1 /*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2010-2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7 #include "LocalDebuggerInterface.h"
8
9 #include <new>
10
11 #include <stdio.h>
12
13 #include <Locker.h>
14
15 #include <AutoLocker.h>
16 #include <memory_private.h>
17 #include <OS.h>
18 #include <system_info.h>
19 #include <util/DoublyLinkedList.h>
20 #include <util/KMessage.h>
21
22 #include "debug_utils.h"
23
24 #include "ArchitectureX86.h"
25 #include "ArchitectureX8664.h"
26 #include "AreaInfo.h"
27 #include "AutoDeleter.h"
28 #include "CpuState.h"
29 #include "DebugEvent.h"
30 #include "ImageInfo.h"
31 #include "SemaphoreInfo.h"
32 #include "SymbolInfo.h"
33 #include "SystemInfo.h"
34 #include "TeamInfo.h"
35 #include "ThreadInfo.h"
36
37
38 // number of debug contexts the pool does initially create
39 static const int kInitialDebugContextCount = 3;
40
41 // maximum number of debug contexts in the pool
42 static const int kMaxDebugContextCount = 10;
43
44
45 // #pragma mark - LocalDebuggerInterface::DebugContext
46
47 struct LocalDebuggerInterface::DebugContext : debug_context,
48 DoublyLinkedListLinkImpl<DebugContext> {
DebugContextLocalDebuggerInterface::DebugContext49 DebugContext()
50 {
51 team = -1;
52 nub_port = -1;
53 reply_port = -1;
54 }
55
~DebugContextLocalDebuggerInterface::DebugContext56 ~DebugContext()
57 {
58 if (reply_port >= 0)
59 destroy_debug_context(this);
60 }
61
InitLocalDebuggerInterface::DebugContext62 status_t Init(team_id team, port_id nubPort)
63 {
64 return init_debug_context(this, team, nubPort);
65 }
66
CloseLocalDebuggerInterface::DebugContext67 void Close()
68 {
69 if (reply_port >= 0) {
70 destroy_debug_context(this);
71 team = -1;
72 nub_port = -1;
73 reply_port = -1;
74 }
75 }
76 };
77
78 // #pragma mark - LocalDebuggerInterface::DebugContextPool
79
80 struct LocalDebuggerInterface::DebugContextPool {
DebugContextPoolLocalDebuggerInterface::DebugContextPool81 DebugContextPool(team_id team, port_id nubPort)
82 :
83 fLock("debug context pool"),
84 fTeam(team),
85 fNubPort(nubPort),
86 fBlockSem(-1),
87 fContextCount(0),
88 fWaiterCount(0),
89 fClosed(false)
90 {
91 }
92
~DebugContextPoolLocalDebuggerInterface::DebugContextPool93 ~DebugContextPool()
94 {
95 AutoLocker<BLocker> locker(fLock);
96
97 while (DebugContext* context = fFreeContexts.RemoveHead())
98 delete context;
99
100 if (fBlockSem >= 0)
101 delete_sem(fBlockSem);
102 }
103
InitLocalDebuggerInterface::DebugContextPool104 status_t Init()
105 {
106 status_t error = fLock.InitCheck();
107 if (error != B_OK)
108 return error;
109
110 fBlockSem = create_sem(0, "debug context pool block");
111 if (fBlockSem < 0)
112 return fBlockSem;
113
114 for (int i = 0; i < kInitialDebugContextCount; i++) {
115 DebugContext* context;
116 error = _CreateDebugContext(context);
117 if (error != B_OK)
118 return error;
119
120 fFreeContexts.Add(context);
121 }
122
123 return B_OK;
124 }
125
CloseLocalDebuggerInterface::DebugContextPool126 void Close()
127 {
128 AutoLocker<BLocker> locker(fLock);
129 fClosed = true;
130
131 for (DebugContextList::Iterator it = fFreeContexts.GetIterator();
132 DebugContext* context = it.Next();) {
133 context->Close();
134 }
135
136 for (DebugContextList::Iterator it = fUsedContexts.GetIterator();
137 DebugContext* context = it.Next();) {
138 context->Close();
139 }
140 }
141
GetContextLocalDebuggerInterface::DebugContextPool142 DebugContext* GetContext()
143 {
144 AutoLocker<BLocker> locker(fLock);
145 DebugContext* context = fFreeContexts.RemoveHead();
146
147 if (context == NULL) {
148 if (fContextCount >= kMaxDebugContextCount
149 || _CreateDebugContext(context) != B_OK) {
150 // wait for a free context
151 while (context == NULL) {
152 fWaiterCount++;
153 locker.Unlock();
154 while (acquire_sem(fBlockSem) != B_OK);
155 locker.Lock();
156 context = fFreeContexts.RemoveHead();
157 }
158 }
159 }
160
161 fUsedContexts.Add(context);
162
163 return context;
164 }
165
PutContextLocalDebuggerInterface::DebugContextPool166 void PutContext(DebugContext* context)
167 {
168 AutoLocker<BLocker> locker(fLock);
169 fUsedContexts.Remove(context);
170 fFreeContexts.Add(context);
171
172 if (fWaiterCount > 0)
173 release_sem(fBlockSem);
174 }
175
176 private:
177 typedef DoublyLinkedList<DebugContext> DebugContextList;
178
179 private:
_CreateDebugContextLocalDebuggerInterface::DebugContextPool180 status_t _CreateDebugContext(DebugContext*& _context)
181 {
182 DebugContext* context = new(std::nothrow) DebugContext;
183 if (context == NULL)
184 return B_NO_MEMORY;
185
186 if (!fClosed) {
187 status_t error = context->Init(fTeam, fNubPort);
188 if (error != B_OK) {
189 delete context;
190 return error;
191 }
192 }
193
194 fContextCount++;
195
196 _context = context;
197 return B_OK;
198 }
199
200 private:
201 BLocker fLock;
202 team_id fTeam;
203 port_id fNubPort;
204 sem_id fBlockSem;
205 int32 fContextCount;
206 int32 fWaiterCount;
207 DebugContextList fFreeContexts;
208 DebugContextList fUsedContexts;
209 bool fClosed;
210 };
211
212
213 struct LocalDebuggerInterface::DebugContextGetter {
DebugContextGetterLocalDebuggerInterface::DebugContextGetter214 DebugContextGetter(DebugContextPool* pool)
215 :
216 fPool(pool),
217 fContext(pool->GetContext())
218 {
219 }
220
~DebugContextGetterLocalDebuggerInterface::DebugContextGetter221 ~DebugContextGetter()
222 {
223 fPool->PutContext(fContext);
224 }
225
ContextLocalDebuggerInterface::DebugContextGetter226 DebugContext* Context() const
227 {
228 return fContext;
229 }
230
231 private:
232 DebugContextPool* fPool;
233 DebugContext* fContext;
234 };
235
236 // #pragma mark - LocalDebuggerInterface
237
LocalDebuggerInterface(team_id team)238 LocalDebuggerInterface::LocalDebuggerInterface(team_id team)
239 :
240 DebuggerInterface(),
241 fTeamID(team),
242 fDebuggerPort(-1),
243 fNubPort(-1),
244 fDebugContextPool(NULL),
245 fArchitecture(NULL)
246 {
247 }
248
249
~LocalDebuggerInterface()250 LocalDebuggerInterface::~LocalDebuggerInterface()
251 {
252 if (fArchitecture != NULL)
253 fArchitecture->ReleaseReference();
254
255 Close(false);
256
257 delete fDebugContextPool;
258 }
259
260
261 status_t
Init()262 LocalDebuggerInterface::Init()
263 {
264 // create the architecture
265 #if defined(ARCH_x86)
266 fArchitecture = new(std::nothrow) ArchitectureX86(this);
267 #elif defined(ARCH_x86_64)
268 fArchitecture = new(std::nothrow) ArchitectureX8664(this);
269 #else
270 return B_UNSUPPORTED;
271 #endif
272
273 if (fArchitecture == NULL)
274 return B_NO_MEMORY;
275
276 status_t error = fArchitecture->Init();
277 if (error != B_OK)
278 return error;
279
280 // create debugger port
281 char buffer[128];
282 snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debugger", fTeamID);
283 fDebuggerPort = create_port(100, buffer);
284 if (fDebuggerPort < 0)
285 return fDebuggerPort;
286
287 // install as team debugger
288 fNubPort = install_team_debugger(fTeamID, fDebuggerPort);
289 if (fNubPort < 0)
290 return fNubPort;
291
292 error = __start_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES,
293 fDebuggerPort, 0);
294 if (error != B_OK)
295 return error;
296
297 // create debug context pool
298 fDebugContextPool = new(std::nothrow) DebugContextPool(fTeamID, fNubPort);
299 if (fDebugContextPool == NULL)
300 return B_NO_MEMORY;
301
302 error = fDebugContextPool->Init();
303 if (error != B_OK)
304 return error;
305
306 return B_OK;
307 }
308
309
310 void
Close(bool killTeam)311 LocalDebuggerInterface::Close(bool killTeam)
312 {
313 if (killTeam)
314 kill_team(fTeamID);
315 else if (fNubPort >= 0)
316 remove_team_debugger(fTeamID);
317
318 if (fDebuggerPort >= 0) {
319 __stop_watching_system(fTeamID, B_WATCH_SYSTEM_THREAD_PROPERTIES,
320 fDebuggerPort, 0);
321 delete_port(fDebuggerPort);
322 }
323
324 fNubPort = -1;
325 fDebuggerPort = -1;
326 }
327
328
329 bool
Connected() const330 LocalDebuggerInterface::Connected() const
331 {
332 return fNubPort >= 0;
333 }
334
335
336 team_id
TeamID() const337 LocalDebuggerInterface::TeamID() const
338 {
339 return fTeamID;
340 }
341
342
343 Architecture*
GetArchitecture() const344 LocalDebuggerInterface::GetArchitecture() const
345 {
346 return fArchitecture;
347 }
348
349
350 status_t
GetNextDebugEvent(DebugEvent * & _event)351 LocalDebuggerInterface::GetNextDebugEvent(DebugEvent*& _event)
352 {
353 while (true) {
354 char buffer[2048];
355 int32 messageCode;
356 ssize_t size = read_port(fDebuggerPort, &messageCode, buffer,
357 sizeof(buffer));
358 if (size < 0) {
359 if (size == B_INTERRUPTED)
360 continue;
361
362 return size;
363 }
364
365 if (messageCode <= B_DEBUGGER_MESSAGE_HANDED_OVER) {
366 debug_debugger_message_data message;
367 memcpy(&message, buffer, size);
368 if (message.origin.team != fTeamID)
369 continue;
370
371 bool ignore = false;
372 status_t error = _CreateDebugEvent(messageCode, message, ignore,
373 _event);
374 if (error != B_OK)
375 return error;
376
377 if (ignore) {
378 if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
379 error = continue_thread(message.origin.nub_port,
380 message.origin.thread);
381 if (error != B_OK)
382 return error;
383 continue;
384 }
385
386 return B_OK;
387 }
388
389 KMessage message;
390 size = message.SetTo(buffer);
391 if (size != B_OK)
392 return size;
393 return _GetNextSystemWatchEvent(_event, message);
394 }
395
396 return B_OK;
397 }
398
399
400 status_t
SetTeamDebuggingFlags(uint32 flags)401 LocalDebuggerInterface::SetTeamDebuggingFlags(uint32 flags)
402 {
403 return set_team_debugging_flags(fNubPort, flags);
404 }
405
406
407 status_t
ContinueThread(thread_id thread)408 LocalDebuggerInterface::ContinueThread(thread_id thread)
409 {
410 return continue_thread(fNubPort, thread);
411 }
412
413
414 status_t
StopThread(thread_id thread)415 LocalDebuggerInterface::StopThread(thread_id thread)
416 {
417 return debug_thread(thread);
418 }
419
420
421 status_t
SingleStepThread(thread_id thread)422 LocalDebuggerInterface::SingleStepThread(thread_id thread)
423 {
424 debug_nub_continue_thread continueMessage;
425 continueMessage.thread = thread;
426 continueMessage.handle_event = B_THREAD_DEBUG_HANDLE_EVENT;
427 continueMessage.single_step = true;
428
429 return write_port(fNubPort, B_DEBUG_MESSAGE_CONTINUE_THREAD,
430 &continueMessage, sizeof(continueMessage));
431 }
432
433
434 status_t
InstallBreakpoint(target_addr_t address)435 LocalDebuggerInterface::InstallBreakpoint(target_addr_t address)
436 {
437 DebugContextGetter contextGetter(fDebugContextPool);
438
439 debug_nub_set_breakpoint message;
440 message.reply_port = contextGetter.Context()->reply_port;
441 message.address = (void*)(addr_t)address;
442
443 debug_nub_set_breakpoint_reply reply;
444
445 status_t error = send_debug_message(contextGetter.Context(),
446 B_DEBUG_MESSAGE_SET_BREAKPOINT, &message, sizeof(message), &reply,
447 sizeof(reply));
448 return error == B_OK ? reply.error : error;
449 }
450
451
452 status_t
UninstallBreakpoint(target_addr_t address)453 LocalDebuggerInterface::UninstallBreakpoint(target_addr_t address)
454 {
455 debug_nub_clear_breakpoint message;
456 message.address = (void*)(addr_t)address;
457
458 return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_BREAKPOINT,
459 &message, sizeof(message));
460 }
461
462
463 status_t
InstallWatchpoint(target_addr_t address,uint32 type,int32 length)464 LocalDebuggerInterface::InstallWatchpoint(target_addr_t address, uint32 type,
465 int32 length)
466 {
467 DebugContextGetter contextGetter(fDebugContextPool);
468
469 debug_nub_set_watchpoint message;
470 message.reply_port = contextGetter.Context()->reply_port;
471 message.address = (void*)(addr_t)address;
472 message.type = type;
473 message.length = length;
474
475 debug_nub_set_watchpoint_reply reply;
476
477 status_t error = send_debug_message(contextGetter.Context(),
478 B_DEBUG_MESSAGE_SET_WATCHPOINT, &message, sizeof(message), &reply,
479 sizeof(reply));
480 return error == B_OK ? reply.error : error;
481 }
482
483
484 status_t
UninstallWatchpoint(target_addr_t address)485 LocalDebuggerInterface::UninstallWatchpoint(target_addr_t address)
486 {
487 DebugContextGetter contextGetter(fDebugContextPool);
488
489 debug_nub_clear_watchpoint message;
490 message.address = (void*)(addr_t)address;
491
492 return write_port(fNubPort, B_DEBUG_MESSAGE_CLEAR_WATCHPOINT,
493 &message, sizeof(message));
494 }
495
496
497 status_t
GetSystemInfo(SystemInfo & info)498 LocalDebuggerInterface::GetSystemInfo(SystemInfo& info)
499 {
500 system_info sysInfo;
501 status_t result = get_system_info(&sysInfo);
502 if (result != B_OK)
503 return result;
504
505 utsname name;
506 result = uname(&name);
507 if (result != B_OK)
508 return result;
509
510 info.SetTo(fTeamID, sysInfo, name);
511 return B_OK;
512 }
513
514
515 status_t
GetTeamInfo(TeamInfo & info)516 LocalDebuggerInterface::GetTeamInfo(TeamInfo& info)
517 {
518 team_info teamInfo;
519 status_t result = get_team_info(fTeamID, &teamInfo);
520 if (result != B_OK)
521 return result;
522
523 info.SetTo(fTeamID, teamInfo);
524 return B_OK;
525 }
526
527
528 status_t
GetThreadInfos(BObjectList<ThreadInfo> & infos)529 LocalDebuggerInterface::GetThreadInfos(BObjectList<ThreadInfo>& infos)
530 {
531 thread_info threadInfo;
532 int32 cookie = 0;
533 while (get_next_thread_info(fTeamID, &cookie, &threadInfo) == B_OK) {
534 ThreadInfo* info = new(std::nothrow) ThreadInfo(threadInfo.team,
535 threadInfo.thread, threadInfo.name);
536 if (info == NULL || !infos.AddItem(info)) {
537 delete info;
538 return B_NO_MEMORY;
539 }
540 }
541
542 return B_OK;
543 }
544
545
546 status_t
GetImageInfos(BObjectList<ImageInfo> & infos)547 LocalDebuggerInterface::GetImageInfos(BObjectList<ImageInfo>& infos)
548 {
549 // get the team's images
550 image_info imageInfo;
551 int32 cookie = 0;
552 while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) {
553 ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id,
554 imageInfo.name, imageInfo.type, (addr_t)imageInfo.text,
555 imageInfo.text_size, (addr_t)imageInfo.data, imageInfo.data_size);
556 if (info == NULL || !infos.AddItem(info)) {
557 delete info;
558 return B_NO_MEMORY;
559 }
560 }
561
562 return B_OK;
563 }
564
565
566 status_t
GetAreaInfos(BObjectList<AreaInfo> & infos)567 LocalDebuggerInterface::GetAreaInfos(BObjectList<AreaInfo>& infos)
568 {
569 // get the team's areas
570 area_info areaInfo;
571 ssize_t cookie = 0;
572 while (get_next_area_info(fTeamID, &cookie, &areaInfo) == B_OK) {
573 AreaInfo* info = new(std::nothrow) AreaInfo(fTeamID, areaInfo.area,
574 areaInfo.name, (addr_t)areaInfo.address, areaInfo.size,
575 areaInfo.ram_size, areaInfo.lock, areaInfo.protection);
576 if (info == NULL || !infos.AddItem(info)) {
577 delete info;
578 return B_NO_MEMORY;
579 }
580 }
581
582 return B_OK;
583 }
584
585
586 status_t
GetSemaphoreInfos(BObjectList<SemaphoreInfo> & infos)587 LocalDebuggerInterface::GetSemaphoreInfos(BObjectList<SemaphoreInfo>& infos)
588 {
589 // get the team's semaphores
590 sem_info semInfo;
591 int32 cookie = 0;
592 while (get_next_sem_info(fTeamID, &cookie, &semInfo) == B_OK) {
593 SemaphoreInfo* info = new(std::nothrow) SemaphoreInfo(fTeamID,
594 semInfo.sem, semInfo.name, semInfo.count, semInfo.latest_holder);
595 if (info == NULL || !infos.AddItem(info)) {
596 delete info;
597 return B_NO_MEMORY;
598 }
599 }
600
601 return B_OK;
602 }
603
604
605 status_t
GetSymbolInfos(team_id team,image_id image,BObjectList<SymbolInfo> & infos)606 LocalDebuggerInterface::GetSymbolInfos(team_id team, image_id image,
607 BObjectList<SymbolInfo>& infos)
608 {
609 // create a lookup context
610 debug_symbol_lookup_context* lookupContext;
611 status_t error = debug_create_symbol_lookup_context(team, image,
612 &lookupContext);
613 if (error != B_OK)
614 return error;
615
616 // create a symbol iterator
617 debug_symbol_iterator* iterator;
618 error = debug_create_image_symbol_iterator(
619 lookupContext, image, &iterator);
620 if (error != B_OK) {
621 debug_delete_symbol_lookup_context(lookupContext);
622 return error;
623 }
624
625 // get the symbols
626 char name[1024];
627 int32 type;
628 void* address;
629 size_t size;
630 while (debug_next_image_symbol(iterator, name, sizeof(name), &type,
631 &address, &size) == B_OK) {
632 SymbolInfo* info = new(std::nothrow) SymbolInfo(
633 (target_addr_t)(addr_t)address, size, type, name);
634 if (info == NULL)
635 break;
636 if (!infos.AddItem(info)) {
637 delete info;
638 break;
639 }
640 }
641
642 // delete the symbol iterator and lookup context
643 debug_delete_symbol_iterator(iterator);
644 debug_delete_symbol_lookup_context(lookupContext);
645
646 return B_OK;
647 }
648
649
650 status_t
GetSymbolInfo(team_id team,image_id image,const char * name,int32 symbolType,SymbolInfo & info)651 LocalDebuggerInterface::GetSymbolInfo(team_id team, image_id image, const char* name,
652 int32 symbolType, SymbolInfo& info)
653 {
654 // create a lookup context
655 debug_symbol_lookup_context* lookupContext;
656 status_t error = debug_create_symbol_lookup_context(team, image,
657 &lookupContext);
658 if (error != B_OK)
659 return error;
660
661 // try to get the symbol
662 void* foundAddress;
663 size_t foundSize;
664 int32 foundType;
665 error = debug_get_symbol(lookupContext, image, name, symbolType,
666 &foundAddress, &foundSize, &foundType);
667 if (error == B_OK) {
668 info.SetTo((target_addr_t)(addr_t)foundAddress, foundSize, foundType,
669 name);
670 }
671
672 // delete the lookup context
673 debug_delete_symbol_lookup_context(lookupContext);
674
675 return error;
676 }
677
678
679 status_t
GetThreadInfo(thread_id thread,ThreadInfo & info)680 LocalDebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info)
681 {
682 thread_info threadInfo;
683 status_t error = get_thread_info(thread, &threadInfo);
684 if (error != B_OK)
685 return error;
686
687 info.SetTo(threadInfo.team, threadInfo.thread, threadInfo.name);
688 return B_OK;
689 }
690
691
692 status_t
GetCpuState(thread_id thread,CpuState * & _state)693 LocalDebuggerInterface::GetCpuState(thread_id thread, CpuState*& _state)
694 {
695 debug_cpu_state debugState;
696 status_t error = _GetDebugCpuState(thread, debugState);
697 if (error != B_OK)
698 return error;
699 return fArchitecture->CreateCpuState(&debugState, sizeof(debug_cpu_state),
700 _state);
701 }
702
703
704 status_t
SetCpuState(thread_id thread,const CpuState * state)705 LocalDebuggerInterface::SetCpuState(thread_id thread, const CpuState* state)
706 {
707 debug_cpu_state debugState;
708 status_t error = _GetDebugCpuState(thread, debugState);
709 if (error != B_OK)
710 return error;
711
712 DebugContextGetter contextGetter(fDebugContextPool);
713
714 error = state->UpdateDebugState(&debugState, sizeof(debugState));
715 if (error != B_OK)
716 return error;
717
718 debug_nub_set_cpu_state message;
719 message.thread = thread;
720
721 memcpy(&message.cpu_state, &debugState, sizeof(debugState));
722
723 return send_debug_message(contextGetter.Context(),
724 B_DEBUG_MESSAGE_SET_CPU_STATE, &message, sizeof(message), NULL,
725 0);
726 }
727
728
729 status_t
GetCpuFeatures(uint32 & flags)730 LocalDebuggerInterface::GetCpuFeatures(uint32& flags)
731 {
732 return fArchitecture->GetCpuFeatures(flags);
733 }
734
735
736 status_t
WriteCoreFile(const char * path)737 LocalDebuggerInterface::WriteCoreFile(const char* path)
738 {
739 DebugContextGetter contextGetter(fDebugContextPool);
740
741 debug_nub_write_core_file_reply reply;
742
743 debug_nub_write_core_file message;
744 message.reply_port = contextGetter.Context()->reply_port;
745 strlcpy(message.path, path, sizeof(message.path));
746
747 status_t error = send_debug_message(contextGetter.Context(),
748 B_DEBUG_WRITE_CORE_FILE, &message, sizeof(message), &reply,
749 sizeof(reply));
750 if (error == B_OK)
751 error = reply.error;
752
753 return error;
754 }
755
756
757 status_t
GetMemoryProperties(target_addr_t address,uint32 & protection,uint32 & locking)758 LocalDebuggerInterface::GetMemoryProperties(target_addr_t address,
759 uint32& protection, uint32& locking)
760 {
761 return get_memory_properties(fTeamID, (const void *)address,
762 &protection, &locking);
763 }
764
765
766 ssize_t
ReadMemory(target_addr_t address,void * buffer,size_t size)767 LocalDebuggerInterface::ReadMemory(target_addr_t address, void* buffer, size_t size)
768 {
769 DebugContextGetter contextGetter(fDebugContextPool);
770
771 return debug_read_memory(contextGetter.Context(),
772 (const void*)(addr_t)address, buffer, size);
773 }
774
775
776 ssize_t
WriteMemory(target_addr_t address,void * buffer,size_t size)777 LocalDebuggerInterface::WriteMemory(target_addr_t address, void* buffer,
778 size_t size)
779 {
780 DebugContextGetter contextGetter(fDebugContextPool);
781
782 return debug_write_memory(contextGetter.Context(),
783 (const void*)address, buffer, size);
784 }
785
786
787 status_t
_CreateDebugEvent(int32 messageCode,const debug_debugger_message_data & message,bool & _ignore,DebugEvent * & _event)788 LocalDebuggerInterface::_CreateDebugEvent(int32 messageCode,
789 const debug_debugger_message_data& message, bool& _ignore,
790 DebugEvent*& _event)
791 {
792 DebugEvent* event = NULL;
793
794 switch (messageCode) {
795 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
796 event = new(std::nothrow) ThreadDebuggedEvent(message.origin.team,
797 message.origin.thread);
798 break;
799 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
800 event = new(std::nothrow) DebuggerCallEvent(message.origin.team,
801 message.origin.thread,
802 (target_addr_t)message.debugger_call.message);
803 break;
804 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
805 {
806 CpuState* state = NULL;
807 status_t error = fArchitecture->CreateCpuState(
808 &message.breakpoint_hit.cpu_state,
809 sizeof(debug_cpu_state), state);
810 if (error != B_OK)
811 return error;
812
813 event = new(std::nothrow) BreakpointHitEvent(message.origin.team,
814 message.origin.thread, state);
815 state->ReleaseReference();
816 break;
817 }
818 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
819 {
820 CpuState* state = NULL;
821 status_t error = fArchitecture->CreateCpuState(
822 &message.watchpoint_hit.cpu_state,
823 sizeof(debug_cpu_state), state);
824 if (error != B_OK)
825 return error;
826
827 event = new(std::nothrow) WatchpointHitEvent(message.origin.team,
828 message.origin.thread, state);
829 state->ReleaseReference();
830 break;
831 }
832 case B_DEBUGGER_MESSAGE_SINGLE_STEP:
833 {
834 CpuState* state = NULL;
835 status_t error = fArchitecture->CreateCpuState(
836 &message.single_step.cpu_state,
837 sizeof(debug_cpu_state), state);
838 if (error != B_OK)
839 return error;
840
841 event = new(std::nothrow) SingleStepEvent(message.origin.team,
842 message.origin.thread, state);
843 state->ReleaseReference();
844 break;
845 }
846 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
847 event = new(std::nothrow) ExceptionOccurredEvent(
848 message.origin.team, message.origin.thread,
849 message.exception_occurred.exception);
850 break;
851 case B_DEBUGGER_MESSAGE_TEAM_DELETED:
852 if (message.origin.team != fTeamID) {
853 _ignore = true;
854 return B_OK;
855 }
856 event = new(std::nothrow) TeamDeletedEvent(message.origin.team,
857 message.origin.thread);
858 break;
859 case B_DEBUGGER_MESSAGE_TEAM_EXEC:
860 if (message.origin.team != fTeamID) {
861 _ignore = true;
862 return B_OK;
863 }
864 event = new(std::nothrow) TeamExecEvent(message.origin.team,
865 message.origin.thread);
866 break;
867 case B_DEBUGGER_MESSAGE_THREAD_CREATED:
868 event = new(std::nothrow) ThreadCreatedEvent(message.origin.team,
869 message.origin.thread, message.thread_created.new_thread);
870 break;
871 case B_DEBUGGER_MESSAGE_THREAD_DELETED:
872 event = new(std::nothrow) ThreadDeletedEvent(message.origin.team,
873 message.origin.thread);
874 break;
875 case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
876 {
877 const image_info& info = message.image_created.info;
878 event = new(std::nothrow) ImageCreatedEvent(message.origin.team,
879 message.origin.thread,
880 ImageInfo(fTeamID, info.id, info.name, info.type,
881 (addr_t)info.text, info.text_size, (addr_t)info.data,
882 info.data_size));
883 break;
884 }
885 case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
886 {
887 const image_info& info = message.image_deleted.info;
888 event = new(std::nothrow) ImageDeletedEvent(message.origin.team,
889 message.origin.thread,
890 ImageInfo(fTeamID, info.id, info.name, info.type,
891 (addr_t)info.text, info.text_size, (addr_t)info.data,
892 info.data_size));
893 break;
894 }
895 case B_DEBUGGER_MESSAGE_POST_SYSCALL:
896 {
897 event = new(std::nothrow) PostSyscallEvent(message.origin.team,
898 message.origin.thread,
899 SyscallInfo(message.post_syscall.start_time,
900 message.post_syscall.end_time,
901 message.post_syscall.return_value,
902 message.post_syscall.syscall, message.post_syscall.args));
903 break;
904 }
905 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
906 {
907 event = new(std::nothrow) SignalReceivedEvent(message.origin.team,
908 message.origin.thread,
909 SignalInfo(message.signal_received.signal,
910 message.signal_received.handler,
911 message.signal_received.deadly));
912 break;
913 }
914 default:
915 printf("DebuggerInterface for team %" B_PRId32 ": unknown message "
916 "from kernel: %" B_PRId32 "\n", fTeamID, messageCode);
917 // fall through...
918 case B_DEBUGGER_MESSAGE_TEAM_CREATED:
919 case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
920 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
921 case B_DEBUGGER_MESSAGE_HANDED_OVER:
922 _ignore = true;
923 return B_OK;
924 }
925
926 if (event == NULL)
927 return B_NO_MEMORY;
928
929 if (message.origin.thread >= 0 && message.origin.nub_port >= 0)
930 event->SetThreadStopped(true);
931
932 _ignore = false;
933 _event = event;
934
935 return B_OK;
936 }
937
938
939 status_t
_GetNextSystemWatchEvent(DebugEvent * & _event,KMessage & message)940 LocalDebuggerInterface::_GetNextSystemWatchEvent(DebugEvent*& _event,
941 KMessage& message)
942 {
943 status_t error = B_OK;
944 if (message.What() != B_SYSTEM_OBJECT_UPDATE)
945 return B_BAD_DATA;
946
947 int32 opcode = 0;
948 if (message.FindInt32("opcode", &opcode) != B_OK)
949 return B_BAD_DATA;
950
951 DebugEvent* event = NULL;
952 switch (opcode)
953 {
954 case B_THREAD_NAME_CHANGED:
955 {
956 int32 threadID = -1;
957 if (message.FindInt32("thread", &threadID) != B_OK)
958 break;
959
960 thread_info info;
961 error = get_thread_info(threadID, &info);
962 if (error != B_OK)
963 break;
964
965 event = new(std::nothrow) ThreadRenamedEvent(fTeamID,
966 threadID, threadID, info.name);
967 break;
968 }
969
970 default:
971 {
972 error = B_BAD_DATA;
973 break;
974 }
975 }
976
977 if (event != NULL)
978 _event = event;
979
980 return error;
981 }
982
983
984 status_t
_GetDebugCpuState(thread_id thread,debug_cpu_state & _state)985 LocalDebuggerInterface::_GetDebugCpuState(thread_id thread, debug_cpu_state& _state)
986 {
987 DebugContextGetter contextGetter(fDebugContextPool);
988
989 debug_nub_get_cpu_state message;
990 message.reply_port = contextGetter.Context()->reply_port;
991 message.thread = thread;
992
993 debug_nub_get_cpu_state_reply reply;
994
995 status_t error = send_debug_message(contextGetter.Context(),
996 B_DEBUG_MESSAGE_GET_CPU_STATE, &message, sizeof(message), &reply,
997 sizeof(reply));
998 if (error != B_OK)
999 return error;
1000 if (reply.error != B_OK)
1001 return reply.error;
1002
1003 memcpy(&_state, &reply.cpu_state, sizeof(debug_cpu_state));
1004
1005 return B_OK;
1006 }
1007