1 /*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2010-2017, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8 #include "controllers/TeamDebugger.h"
9
10 #include <stdarg.h>
11 #include <stdio.h>
12
13 #include <new>
14
15 #include <Entry.h>
16 #include <InterfaceDefs.h>
17 #include <Message.h>
18 #include <StringList.h>
19
20 #include <AutoDeleter.h>
21 #include <AutoLocker.h>
22
23 #include "debug_utils.h"
24 #include "syscall_numbers.h"
25
26 #include "Architecture.h"
27 #include "BreakpointManager.h"
28 #include "BreakpointSetting.h"
29 #include "CpuState.h"
30 #include "DebugEvent.h"
31 #include "DebuggerInterface.h"
32 #include "DebugReportGenerator.h"
33 #include "ExpressionInfo.h"
34 #include "FileManager.h"
35 #include "Function.h"
36 #include "FunctionID.h"
37 #include "ImageDebugInfo.h"
38 #include "ImageDebugInfoLoadingState.h"
39 #include "ImageDebugLoadingStateHandler.h"
40 #include "ImageDebugLoadingStateHandlerRoster.h"
41 #include "Jobs.h"
42 #include "LocatableFile.h"
43 #include "MessageCodes.h"
44 #include "NoOpSettingsManager.h"
45 #include "SettingsManager.h"
46 #include "SourceCode.h"
47 #include "SourceLanguage.h"
48 #include "SpecificImageDebugInfo.h"
49 #include "SpecificImageDebugInfoLoadingState.h"
50 #include "StackFrame.h"
51 #include "StackFrameValues.h"
52 #include "Statement.h"
53 #include "SymbolInfo.h"
54 #include "TeamDebugInfo.h"
55 #include "TeamInfo.h"
56 #include "TeamMemoryBlock.h"
57 #include "TeamMemoryBlockManager.h"
58 #include "TeamSettings.h"
59 #include "TeamSignalSettings.h"
60 #include "TeamUiSettings.h"
61 #include "Tracing.h"
62 #include "ValueNode.h"
63 #include "ValueNodeContainer.h"
64 #include "Variable.h"
65 #include "WatchpointManager.h"
66
67
68 // #pragma mark - ImageHandler
69
70
71 struct TeamDebugger::ImageHandler : public BReferenceable,
72 private LocatableFile::Listener {
73 public:
ImageHandlerTeamDebugger::ImageHandler74 ImageHandler(TeamDebugger* teamDebugger, Image* image)
75 :
76 fTeamDebugger(teamDebugger),
77 fImage(image)
78 {
79 fImage->AcquireReference();
80 if (fImage->ImageFile() != NULL)
81 fImage->ImageFile()->AddListener(this);
82 }
83
~ImageHandlerTeamDebugger::ImageHandler84 ~ImageHandler()
85 {
86 if (fImage->ImageFile() != NULL)
87 fImage->ImageFile()->RemoveListener(this);
88 fImage->ReleaseReference();
89 }
90
GetImageTeamDebugger::ImageHandler91 Image* GetImage() const
92 {
93 return fImage;
94 }
95
ImageIDTeamDebugger::ImageHandler96 image_id ImageID() const
97 {
98 return fImage->ID();
99 }
100
101 private:
102 // LocatableFile::Listener
LocatableFileChangedTeamDebugger::ImageHandler103 virtual void LocatableFileChanged(LocatableFile* file)
104 {
105 BMessage message(MSG_IMAGE_FILE_CHANGED);
106 message.AddInt32("image", fImage->ID());
107 fTeamDebugger->PostMessage(&message);
108 }
109
110 private:
111 TeamDebugger* fTeamDebugger;
112 Image* fImage;
113
114 public:
115 ImageHandler* fNext;
116 };
117
118
119 // #pragma mark - ImageHandlerHashDefinition
120
121
122 struct TeamDebugger::ImageHandlerHashDefinition {
123 typedef image_id KeyType;
124 typedef ImageHandler ValueType;
125
HashKeyTeamDebugger::ImageHandlerHashDefinition126 size_t HashKey(image_id key) const
127 {
128 return (size_t)key;
129 }
130
HashTeamDebugger::ImageHandlerHashDefinition131 size_t Hash(const ImageHandler* value) const
132 {
133 return HashKey(value->ImageID());
134 }
135
CompareTeamDebugger::ImageHandlerHashDefinition136 bool Compare(image_id key, const ImageHandler* value) const
137 {
138 return value->ImageID() == key;
139 }
140
GetLinkTeamDebugger::ImageHandlerHashDefinition141 ImageHandler*& GetLink(ImageHandler* value) const
142 {
143 return value->fNext;
144 }
145 };
146
147
148 // #pragma mark - ImageInfoPendingThread
149
150
151 struct TeamDebugger::ImageInfoPendingThread {
152 public:
ImageInfoPendingThreadTeamDebugger::ImageInfoPendingThread153 ImageInfoPendingThread(image_id image, thread_id thread)
154 :
155 fImage(image),
156 fThread(thread)
157 {
158 }
159
~ImageInfoPendingThreadTeamDebugger::ImageInfoPendingThread160 ~ImageInfoPendingThread()
161 {
162 }
163
ImageIDTeamDebugger::ImageInfoPendingThread164 image_id ImageID() const
165 {
166 return fImage;
167 }
168
ThreadIDTeamDebugger::ImageInfoPendingThread169 thread_id ThreadID() const
170 {
171 return fThread;
172 }
173
174 private:
175 image_id fImage;
176 thread_id fThread;
177
178 public:
179 ImageInfoPendingThread* fNext;
180 };
181
182
183 // #pragma mark - ImageHandlerHashDefinition
184
185
186 struct TeamDebugger::ImageInfoPendingThreadHashDefinition {
187 typedef image_id KeyType;
188 typedef ImageInfoPendingThread ValueType;
189
HashKeyTeamDebugger::ImageInfoPendingThreadHashDefinition190 size_t HashKey(image_id key) const
191 {
192 return (size_t)key;
193 }
194
HashTeamDebugger::ImageInfoPendingThreadHashDefinition195 size_t Hash(const ImageInfoPendingThread* value) const
196 {
197 return HashKey(value->ImageID());
198 }
199
CompareTeamDebugger::ImageInfoPendingThreadHashDefinition200 bool Compare(image_id key, const ImageInfoPendingThread* value) const
201 {
202 return value->ImageID() == key;
203 }
204
GetLinkTeamDebugger::ImageInfoPendingThreadHashDefinition205 ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const
206 {
207 return value->fNext;
208 }
209 };
210
211
212 // #pragma mark - TeamDebugger
213
214
TeamDebugger(Listener * listener,UserInterface * userInterface,SettingsManager * settingsManager)215 TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
216 SettingsManager* settingsManager)
217 :
218 BLooper("team debugger"),
219 fListener(listener),
220 fSettingsManager(settingsManager),
221 fTeam(NULL),
222 fTeamID(-1),
223 fIsPostMortem(false),
224 fImageHandlers(NULL),
225 fImageInfoPendingThreads(NULL),
226 fDebuggerInterface(NULL),
227 fFileManager(NULL),
228 fWorker(NULL),
229 fBreakpointManager(NULL),
230 fWatchpointManager(NULL),
231 fMemoryBlockManager(NULL),
232 fReportGenerator(NULL),
233 fDebugEventListener(-1),
234 fUserInterface(userInterface),
235 fTerminating(false),
236 fKillTeamOnQuit(false),
237 fCommandLineArgc(0),
238 fCommandLineArgv(NULL),
239 fExecPending(false)
240 {
241 fUserInterface->AcquireReference();
242 }
243
244
~TeamDebugger()245 TeamDebugger::~TeamDebugger()
246 {
247 if (fTeam != NULL)
248 _SaveSettings();
249
250 AutoLocker<BLooper> locker(this);
251
252 fTerminating = true;
253
254 if (fDebuggerInterface != NULL) {
255 fDebuggerInterface->Close(fKillTeamOnQuit);
256 fDebuggerInterface->ReleaseReference();
257 }
258
259 if (fWorker != NULL)
260 fWorker->ShutDown();
261
262 locker.Unlock();
263
264 if (fDebugEventListener >= 0)
265 wait_for_thread(fDebugEventListener, NULL);
266
267 // terminate UI
268 if (fUserInterface != NULL) {
269 fUserInterface->Terminate();
270 fUserInterface->ReleaseReference();
271 }
272
273 ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
274 while (threadHandler != NULL) {
275 ThreadHandler* next = threadHandler->fNext;
276 threadHandler->ReleaseReference();
277 threadHandler = next;
278 }
279
280 if (fImageHandlers != NULL) {
281 ImageHandler* imageHandler = fImageHandlers->Clear(true);
282 while (imageHandler != NULL) {
283 ImageHandler* next = imageHandler->fNext;
284 imageHandler->ReleaseReference();
285 imageHandler = next;
286 }
287 }
288
289 delete fImageHandlers;
290
291 if (fImageInfoPendingThreads != NULL) {
292 ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true);
293 while (thread != NULL) {
294 ImageInfoPendingThread* next = thread->fNext;
295 delete thread;
296 thread = next;
297 }
298 }
299
300 if (fReportGenerator != NULL) {
301 fReportGenerator->Lock();
302 fReportGenerator->Quit();
303 }
304
305 delete fWorker;
306
307 delete fImageInfoPendingThreads;
308
309 delete fBreakpointManager;
310 delete fWatchpointManager;
311 delete fMemoryBlockManager;
312 delete fTeam;
313 delete fFileManager;
314
315 for (int i = 0; i < fCommandLineArgc; i++) {
316 if (fCommandLineArgv[i] != NULL)
317 free(const_cast<char*>(fCommandLineArgv[i]));
318 }
319
320 delete [] fCommandLineArgv;
321
322 fListener->TeamDebuggerQuit(this);
323 }
324
325
326 status_t
Init(DebuggerInterface * interface,thread_id threadID,int argc,const char * const * argv,bool stopInMain)327 TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
328 const char* const* argv, bool stopInMain)
329 {
330 bool targetIsLocal = true;
331 // TODO: Support non-local targets!
332
333 // the first thing we want to do when running
334 PostMessage(MSG_LOAD_SETTINGS);
335
336 status_t error = _HandleSetArguments(argc, argv);
337 if (error != B_OK)
338 return error;
339
340 if (fSettingsManager == NULL) {
341 // if we have not been provided with a settings manager,
342 // simply use the no-op manager by default.
343 fSettingsManager = new(std::nothrow) NoOpSettingsManager;
344 if (fSettingsManager == NULL)
345 return B_NO_MEMORY;
346 }
347
348 fDebuggerInterface = interface;
349 fDebuggerInterface->AcquireReference();
350 fTeamID = interface->TeamID();
351 fIsPostMortem = interface->IsPostMortem();
352
353
354 // create file manager
355 fFileManager = new(std::nothrow) FileManager;
356 if (fFileManager == NULL)
357 return B_NO_MEMORY;
358
359 error = fFileManager->Init(targetIsLocal);
360 if (error != B_OK)
361 return error;
362
363 // create team debug info
364 TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
365 fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
366 fFileManager);
367 if (teamDebugInfo == NULL)
368 return B_NO_MEMORY;
369 BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo, true);
370
371 error = teamDebugInfo->Init();
372 if (error != B_OK)
373 return error;
374
375 // check whether the team exists at all
376 TeamInfo teamInfo;
377 error = fDebuggerInterface->GetTeamInfo(teamInfo);
378 if (error != B_OK)
379 return error;
380
381 // create a team object
382 fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface,
383 fDebuggerInterface->GetArchitecture(), teamDebugInfo,
384 teamDebugInfo);
385 if (fTeam == NULL)
386 return B_NO_MEMORY;
387
388 error = fTeam->Init();
389 if (error != B_OK)
390 return error;
391 fTeam->SetName(teamInfo.Arguments());
392 // TODO: Set a better name!
393
394 fTeam->AddListener(this);
395
396 // init thread handler table
397 error = fThreadHandlers.Init();
398 if (error != B_OK)
399 return error;
400
401 // create image handler table
402 fImageHandlers = new(std::nothrow) ImageHandlerTable;
403 if (fImageHandlers == NULL)
404 return B_NO_MEMORY;
405
406 error = fImageHandlers->Init();
407 if (error != B_OK)
408 return error;
409
410 fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable;
411 if (fImageInfoPendingThreads == NULL)
412 return B_NO_MEMORY;
413
414 // create our worker
415 fWorker = new(std::nothrow) Worker;
416 if (fWorker == NULL)
417 return B_NO_MEMORY;
418
419 error = fWorker->Init();
420 if (error != B_OK)
421 return error;
422
423 // create the breakpoint manager
424 fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
425 fDebuggerInterface);
426 if (fBreakpointManager == NULL)
427 return B_NO_MEMORY;
428
429 error = fBreakpointManager->Init();
430 if (error != B_OK)
431 return error;
432
433 // create the watchpoint manager
434 fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam,
435 fDebuggerInterface);
436 if (fWatchpointManager == NULL)
437 return B_NO_MEMORY;
438
439 error = fWatchpointManager->Init();
440 if (error != B_OK)
441 return error;
442
443 // create the memory block manager
444 fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
445 if (fMemoryBlockManager == NULL)
446 return B_NO_MEMORY;
447
448 error = fMemoryBlockManager->Init();
449 if (error != B_OK)
450 return error;
451
452 // create the debug report generator
453 fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this,
454 fDebuggerInterface);
455 if (fReportGenerator == NULL)
456 return B_NO_MEMORY;
457
458 error = fReportGenerator->Init();
459 if (error != B_OK)
460 return error;
461
462 // set team debugging flags
463 fDebuggerInterface->SetTeamDebuggingFlags(
464 B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES
465 | B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS
466 | B_TEAM_DEBUG_TEAM_CREATION);
467
468 // get the initial state of the team
469 AutoLocker< ::Team> teamLocker(fTeam);
470
471 ThreadHandler* mainThreadHandler = NULL;
472 {
473 BObjectList<ThreadInfo> threadInfos(20, true);
474 status_t error = fDebuggerInterface->GetThreadInfos(threadInfos);
475 for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) {
476 ::Thread* thread;
477 error = fTeam->AddThread(*info, &thread);
478 if (error != B_OK)
479 return error;
480
481 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
482 fWorker, fDebuggerInterface, this, fBreakpointManager);
483 if (handler == NULL)
484 return B_NO_MEMORY;
485
486 fThreadHandlers.Insert(handler);
487
488 if (thread->IsMainThread())
489 mainThreadHandler = handler;
490
491 handler->Init();
492 }
493 }
494
495 Image* appImage = NULL;
496 {
497 BObjectList<ImageInfo> imageInfos(20, true);
498 status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
499 for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
500 Image* image;
501 error = _AddImage(*info, &image);
502 if (error != B_OK)
503 return error;
504 if (image->Type() == B_APP_IMAGE)
505 appImage = image;
506
507 ImageDebugInfoRequested(image);
508 }
509 }
510
511 // create the debug event listener (for live debugging only)
512 if (!fDebuggerInterface->IsPostMortem()) {
513 char buffer[128];
514 snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
515 fTeamID);
516 fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
517 B_NORMAL_PRIORITY, this);
518 if (fDebugEventListener < 0)
519 return fDebugEventListener;
520
521 resume_thread(fDebugEventListener);
522 }
523
524 // run looper
525 thread_id looperThread = Run();
526 if (looperThread < 0)
527 return looperThread;
528
529 // init the UI
530 error = fUserInterface->Init(fTeam, this);
531 if (error != B_OK) {
532 ERROR("Error: Failed to init the UI: %s\n", strerror(error));
533 return error;
534 }
535
536 // if requested, stop the given thread
537 if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) {
538 if (stopInMain) {
539 SymbolInfo symbolInfo;
540 if (appImage != NULL && mainThreadHandler != NULL
541 && fDebuggerInterface->GetSymbolInfo(
542 fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT,
543 symbolInfo) == B_OK) {
544 mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address());
545 }
546 } else {
547 debug_thread(threadID);
548 // TODO: Superfluous, if the thread is already stopped.
549 }
550 }
551
552 fListener->TeamDebuggerStarted(this);
553
554 return B_OK;
555 }
556
557
558 void
Activate()559 TeamDebugger::Activate()
560 {
561 fUserInterface->Show();
562 }
563
564
565 void
MessageReceived(BMessage * message)566 TeamDebugger::MessageReceived(BMessage* message)
567 {
568 switch (message->what) {
569 case MSG_THREAD_RUN:
570 case MSG_THREAD_SET_ADDRESS:
571 case MSG_THREAD_STOP:
572 case MSG_THREAD_STEP_OVER:
573 case MSG_THREAD_STEP_INTO:
574 case MSG_THREAD_STEP_OUT:
575 {
576 int32 threadID;
577 target_addr_t address;
578 if (message->FindInt32("thread", &threadID) != B_OK)
579 break;
580
581 if (message->FindUInt64("address", &address) != B_OK)
582 address = 0;
583
584 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
585 handler->HandleThreadAction(message->what, address);
586 handler->ReleaseReference();
587 }
588 break;
589 }
590
591 case MSG_SET_BREAKPOINT:
592 case MSG_CLEAR_BREAKPOINT:
593 {
594 UserBreakpoint* breakpoint = NULL;
595 BReference<UserBreakpoint> breakpointReference;
596 uint64 address = 0;
597
598 if (message->FindPointer("breakpoint", (void**)&breakpoint)
599 == B_OK) {
600 breakpointReference.SetTo(breakpoint, true);
601 } else if (message->FindUInt64("address", &address) != B_OK)
602 break;
603
604 if (message->what == MSG_SET_BREAKPOINT) {
605 bool enabled;
606 if (message->FindBool("enabled", &enabled) != B_OK)
607 enabled = true;
608
609 bool hidden;
610 if (message->FindBool("hidden", &hidden) != B_OK)
611 hidden = false;
612
613 if (breakpoint != NULL)
614 _HandleSetUserBreakpoint(breakpoint, enabled);
615 else
616 _HandleSetUserBreakpoint(address, enabled, hidden);
617 } else {
618 if (breakpoint != NULL)
619 _HandleClearUserBreakpoint(breakpoint);
620 else
621 _HandleClearUserBreakpoint(address);
622 }
623
624 break;
625 }
626
627 case MSG_SET_BREAKPOINT_CONDITION:
628 {
629 UserBreakpoint* breakpoint = NULL;
630 BReference<UserBreakpoint> breakpointReference;
631 if (message->FindPointer("breakpoint", (void**)&breakpoint)
632 != B_OK) {
633 break;
634 }
635
636 breakpointReference.SetTo(breakpoint, true);
637
638 const char* condition;
639 if (message->FindString("condition", &condition) != B_OK)
640 break;
641
642 AutoLocker< ::Team> teamLocker(fTeam);
643 breakpoint->SetCondition(condition);
644 fTeam->NotifyUserBreakpointChanged(breakpoint);
645
646 break;
647 }
648
649 case MSG_CLEAR_BREAKPOINT_CONDITION:
650 {
651 UserBreakpoint* breakpoint = NULL;
652 BReference<UserBreakpoint> breakpointReference;
653 if (message->FindPointer("breakpoint", (void**)&breakpoint)
654 != B_OK)
655 break;
656
657 breakpointReference.SetTo(breakpoint, true);
658
659 AutoLocker< ::Team> teamLocker(fTeam);
660 breakpoint->SetCondition(NULL);
661 fTeam->NotifyUserBreakpointChanged(breakpoint);
662
663 break;
664 }
665
666 case MSG_STOP_ON_IMAGE_LOAD:
667 {
668 bool enabled;
669 bool useNames;
670 if (message->FindBool("enabled", &enabled) != B_OK)
671 break;
672
673 if (message->FindBool("useNames", &useNames) != B_OK)
674 break;
675
676 AutoLocker< ::Team> teamLocker(fTeam);
677 fTeam->SetStopOnImageLoad(enabled, useNames);
678 break;
679 }
680
681 case MSG_ADD_STOP_IMAGE_NAME:
682 {
683 BString imageName;
684 if (message->FindString("name", &imageName) != B_OK)
685 break;
686
687 AutoLocker< ::Team> teamLocker(fTeam);
688 fTeam->AddStopImageName(imageName);
689 break;
690 }
691
692 case MSG_REMOVE_STOP_IMAGE_NAME:
693 {
694 BString imageName;
695 if (message->FindString("name", &imageName) != B_OK)
696 break;
697
698 AutoLocker< ::Team> teamLocker(fTeam);
699 fTeam->RemoveStopImageName(imageName);
700 break;
701 }
702
703 case MSG_SET_DEFAULT_SIGNAL_DISPOSITION:
704 {
705 int32 disposition;
706 if (message->FindInt32("disposition", &disposition) != B_OK)
707 break;
708
709 AutoLocker< ::Team> teamLocker(fTeam);
710 fTeam->SetDefaultSignalDisposition(disposition);
711 break;
712 }
713
714 case MSG_SET_CUSTOM_SIGNAL_DISPOSITION:
715 {
716 int32 signal;
717 int32 disposition;
718 if (message->FindInt32("signal", &signal) != B_OK
719 || message->FindInt32("disposition", &disposition) != B_OK) {
720 break;
721 }
722
723 AutoLocker< ::Team> teamLocker(fTeam);
724 fTeam->SetCustomSignalDisposition(signal, disposition);
725 break;
726 }
727
728 case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION:
729 {
730 int32 signal;
731 if (message->FindInt32("signal", &signal) != B_OK)
732 break;
733
734 AutoLocker< ::Team> teamLocker(fTeam);
735 fTeam->RemoveCustomSignalDisposition(signal);
736 break;
737 }
738
739 case MSG_SET_WATCHPOINT:
740 case MSG_CLEAR_WATCHPOINT:
741 {
742 Watchpoint* watchpoint = NULL;
743 BReference<Watchpoint> watchpointReference;
744 uint64 address = 0;
745 uint32 type = 0;
746 int32 length = 0;
747
748 if (message->FindPointer("watchpoint", (void**)&watchpoint)
749 == B_OK) {
750 watchpointReference.SetTo(watchpoint, true);
751 } else if (message->FindUInt64("address", &address) != B_OK)
752 break;
753
754 if (message->what == MSG_SET_WATCHPOINT) {
755 if (watchpoint == NULL && (message->FindUInt32("type", &type)
756 != B_OK
757 || message->FindInt32("length", &length) != B_OK)) {
758 break;
759 }
760
761 bool enabled;
762 if (message->FindBool("enabled", &enabled) != B_OK)
763 enabled = true;
764
765 if (watchpoint != NULL)
766 _HandleSetWatchpoint(watchpoint, enabled);
767 else
768 _HandleSetWatchpoint(address, type, length, enabled);
769 } else {
770 if (watchpoint != NULL)
771 _HandleClearWatchpoint(watchpoint);
772 else
773 _HandleClearWatchpoint(address);
774 }
775
776 break;
777 }
778
779 case MSG_INSPECT_ADDRESS:
780 {
781 TeamMemoryBlock::Listener* listener;
782 if (message->FindPointer("listener",
783 reinterpret_cast<void **>(&listener)) != B_OK) {
784 break;
785 }
786
787 target_addr_t address;
788 if (message->FindUInt64("address",
789 &address) == B_OK) {
790 _HandleInspectAddress(address, listener);
791 }
792 break;
793 }
794
795 case MSG_WRITE_TARGET_MEMORY:
796 {
797 target_addr_t address;
798 if (message->FindUInt64("address", &address) != B_OK)
799 break;
800
801 void* data;
802 if (message->FindPointer("data", &data) != B_OK)
803 break;
804
805 target_size_t size;
806 if (message->FindUInt64("size", &size) != B_OK)
807 break;
808
809 _HandleWriteMemory(address, data, size);
810 break;
811 }
812
813 case MSG_EVALUATE_EXPRESSION:
814 {
815 SourceLanguage* language;
816 if (message->FindPointer("language",
817 reinterpret_cast<void**>(&language)) != B_OK) {
818 break;
819 }
820
821 // ExpressionEvaluationRequested() acquires a reference
822 // to both the language and the expression info on our behalf.
823 BReference<SourceLanguage> reference(language, true);
824
825 ExpressionInfo* info;
826 if (message->FindPointer("info",
827 reinterpret_cast<void**>(&info)) != B_OK) {
828 break;
829 }
830
831 BReference<ExpressionInfo> infoReference(info, true);
832
833 StackFrame* frame;
834 if (message->FindPointer("frame",
835 reinterpret_cast<void**>(&frame)) != B_OK) {
836 // the stack frame isn't needed, unless variable
837 // evaluation is desired.
838 frame = NULL;
839 }
840
841 ::Thread* thread;
842 if (message->FindPointer("thread",
843 reinterpret_cast<void**>(&thread)) != B_OK) {
844 // the thread isn't needed, unless variable
845 // evaluation is desired.
846 thread = NULL;
847 }
848
849 _HandleEvaluateExpression(language, info, frame, thread);
850 break;
851 }
852
853 case MSG_GENERATE_DEBUG_REPORT:
854 {
855 fReportGenerator->PostMessage(message);
856 break;
857 }
858
859 case MSG_WRITE_CORE_FILE:
860 {
861 entry_ref ref;
862 if (message->FindRef("target", &ref) != B_OK)
863 break;
864
865 _HandleWriteCoreFile(ref);
866 break;
867 }
868
869 case MSG_THREAD_STATE_CHANGED:
870 {
871 int32 threadID;
872 if (message->FindInt32("thread", &threadID) != B_OK)
873 break;
874
875 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
876 handler->HandleThreadStateChanged();
877 handler->ReleaseReference();
878 }
879 break;
880 }
881 case MSG_THREAD_CPU_STATE_CHANGED:
882 {
883 int32 threadID;
884 if (message->FindInt32("thread", &threadID) != B_OK)
885 break;
886
887 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
888 handler->HandleCpuStateChanged();
889 handler->ReleaseReference();
890 }
891 break;
892 }
893 case MSG_THREAD_STACK_TRACE_CHANGED:
894 {
895 int32 threadID;
896 if (message->FindInt32("thread", &threadID) != B_OK)
897 break;
898
899 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
900 handler->HandleStackTraceChanged();
901 handler->ReleaseReference();
902 }
903 break;
904 }
905
906 case MSG_IMAGE_DEBUG_INFO_CHANGED:
907 {
908 int32 imageID;
909 if (message->FindInt32("image", &imageID) != B_OK)
910 break;
911
912 _HandleImageDebugInfoChanged(imageID);
913 break;
914 }
915
916 case MSG_IMAGE_FILE_CHANGED:
917 {
918 int32 imageID;
919 if (message->FindInt32("image", &imageID) != B_OK)
920 break;
921
922 _HandleImageFileChanged(imageID);
923 break;
924 }
925
926 case MSG_DEBUGGER_EVENT:
927 {
928 DebugEvent* event;
929 if (message->FindPointer("event", (void**)&event) != B_OK)
930 break;
931
932 _HandleDebuggerMessage(event);
933 delete event;
934 break;
935 }
936
937 case MSG_LOAD_SETTINGS:
938 _LoadSettings();
939 Activate();
940 break;
941
942 case MSG_TEAM_RESTART_REQUESTED:
943 {
944 if (fCommandLineArgc == 0)
945 break;
946
947 _SaveSettings();
948 fListener->TeamDebuggerRestartRequested(this);
949 break;
950 }
951
952 case MSG_DEBUG_INFO_NEEDS_USER_INPUT:
953 {
954 Job* job;
955 ImageDebugInfoLoadingState* state;
956 if (message->FindPointer("job", (void**)&job) != B_OK)
957 break;
958 if (message->FindPointer("state", (void**)&state) != B_OK)
959 break;
960
961 _HandleDebugInfoJobUserInput(state);
962 fWorker->ResumeJob(job);
963 break;
964 }
965
966 case MSG_RESET_USER_BACKGROUND_STATUS:
967 {
968 fUserInterface->NotifyBackgroundWorkStatus("Ready.");
969 break;
970 }
971
972 default:
973 BLooper::MessageReceived(message);
974 break;
975 }
976 }
977
978
979 void
SourceEntryLocateRequested(const char * sourcePath,const char * locatedPath)980 TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
981 const char* locatedPath)
982 {
983 AutoLocker<FileManager> locker(fFileManager);
984 fFileManager->SourceEntryLocated(sourcePath, locatedPath);
985 }
986
987
988 void
SourceEntryInvalidateRequested(LocatableFile * sourceFile)989 TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile)
990 {
991 AutoLocker< ::Team> locker(fTeam);
992
993 fTeam->DebugInfo()->ClearSourceCode(sourceFile);
994 }
995
996
997 void
FunctionSourceCodeRequested(FunctionInstance * functionInstance,bool forceDisassembly)998 TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
999 bool forceDisassembly)
1000 {
1001 Function* function = functionInstance->GetFunction();
1002
1003 // mark loading
1004 AutoLocker< ::Team> locker(fTeam);
1005
1006 if (forceDisassembly && functionInstance->SourceCodeState()
1007 != FUNCTION_SOURCE_NOT_LOADED) {
1008 return;
1009 } else if (!forceDisassembly && function->SourceCodeState()
1010 == FUNCTION_SOURCE_LOADED) {
1011 return;
1012 }
1013
1014 functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1015
1016 bool loadForFunction = false;
1017 if (!forceDisassembly && (function->SourceCodeState()
1018 == FUNCTION_SOURCE_NOT_LOADED
1019 || function->SourceCodeState() == FUNCTION_SOURCE_SUPPRESSED)) {
1020 loadForFunction = true;
1021 function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1022 }
1023
1024 locker.Unlock();
1025
1026 // schedule the job
1027 if (fWorker->ScheduleJob(
1028 new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
1029 fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
1030 loadForFunction),
1031 this) != B_OK) {
1032 // scheduling failed -- mark unavailable
1033 locker.Lock();
1034 function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
1035 locker.Unlock();
1036 }
1037 }
1038
1039
1040 void
ImageDebugInfoRequested(Image * image)1041 TeamDebugger::ImageDebugInfoRequested(Image* image)
1042 {
1043 LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
1044 }
1045
1046
1047 void
ValueNodeValueRequested(CpuState * cpuState,ValueNodeContainer * container,ValueNode * valueNode)1048 TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
1049 ValueNodeContainer* container, ValueNode* valueNode)
1050 {
1051 AutoLocker<ValueNodeContainer> containerLocker(container);
1052 if (valueNode->Container() != container)
1053 return;
1054
1055 // check whether a job is already in progress
1056 AutoLocker<Worker> workerLocker(fWorker);
1057 SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
1058 if (fWorker->GetJob(jobKey) != NULL)
1059 return;
1060 workerLocker.Unlock();
1061
1062 // schedule the job
1063 status_t error = fWorker->ScheduleJob(
1064 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
1065 fDebuggerInterface->GetArchitecture(), cpuState,
1066 fTeam->GetTeamTypeInformation(), container, valueNode), this);
1067 if (error != B_OK) {
1068 // scheduling failed -- set the value to invalid
1069 valueNode->SetLocationAndValue(NULL, NULL, error);
1070 }
1071 }
1072
1073 void
ValueNodeWriteRequested(ValueNode * node,CpuState * state,Value * newValue)1074 TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
1075 Value* newValue)
1076 {
1077 // schedule the job
1078 status_t error = fWorker->ScheduleJob(
1079 new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface,
1080 fDebuggerInterface->GetArchitecture(), state,
1081 fTeam->GetTeamTypeInformation(), node, newValue), this);
1082 if (error != B_OK) {
1083 BString message;
1084 message.SetToFormat("Request to write new value for variable %s "
1085 "failed: %s.\n", node->Name().String(), strerror(error));
1086 fUserInterface->NotifyUser("Error", message.String(),
1087 USER_NOTIFICATION_ERROR);
1088 }
1089 }
1090
1091
1092 void
ThreadActionRequested(thread_id threadID,uint32 action,target_addr_t address)1093 TeamDebugger::ThreadActionRequested(thread_id threadID,
1094 uint32 action, target_addr_t address)
1095 {
1096 BMessage message(action);
1097 message.AddInt32("thread", threadID);
1098 message.AddUInt64("address", address);
1099 PostMessage(&message);
1100 }
1101
1102
1103 void
SetBreakpointRequested(target_addr_t address,bool enabled,bool hidden)1104 TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled,
1105 bool hidden)
1106 {
1107 BMessage message(MSG_SET_BREAKPOINT);
1108 message.AddUInt64("address", (uint64)address);
1109 message.AddBool("enabled", enabled);
1110 message.AddBool("hidden", hidden);
1111 PostMessage(&message);
1112 }
1113
1114
1115 void
SetBreakpointEnabledRequested(UserBreakpoint * breakpoint,bool enabled)1116 TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
1117 bool enabled)
1118 {
1119 BMessage message(MSG_SET_BREAKPOINT);
1120 BReference<UserBreakpoint> breakpointReference(breakpoint);
1121 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1122 && message.AddBool("enabled", enabled) == B_OK
1123 && PostMessage(&message) == B_OK) {
1124 breakpointReference.Detach();
1125 }
1126 }
1127
1128
1129 void
SetBreakpointConditionRequested(UserBreakpoint * breakpoint,const char * condition)1130 TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
1131 const char* condition)
1132 {
1133 BMessage message(MSG_SET_BREAKPOINT_CONDITION);
1134 BReference<UserBreakpoint> breakpointReference(breakpoint);
1135 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1136 && message.AddString("condition", condition) == B_OK
1137 && PostMessage(&message) == B_OK) {
1138 breakpointReference.Detach();
1139 }
1140 }
1141
1142
1143 void
ClearBreakpointConditionRequested(UserBreakpoint * breakpoint)1144 TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
1145 {
1146 BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
1147 BReference<UserBreakpoint> breakpointReference(breakpoint);
1148 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1149 && PostMessage(&message) == B_OK) {
1150 breakpointReference.Detach();
1151 }
1152 }
1153
1154
1155 void
ClearBreakpointRequested(target_addr_t address)1156 TeamDebugger::ClearBreakpointRequested(target_addr_t address)
1157 {
1158 BMessage message(MSG_CLEAR_BREAKPOINT);
1159 message.AddUInt64("address", (uint64)address);
1160 PostMessage(&message);
1161 }
1162
1163
1164 void
SetStopOnImageLoadRequested(bool enabled,bool useImageNames)1165 TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames)
1166 {
1167 BMessage message(MSG_STOP_ON_IMAGE_LOAD);
1168 message.AddBool("enabled", enabled);
1169 message.AddBool("useNames", useImageNames);
1170 PostMessage(&message);
1171 }
1172
1173
1174 void
AddStopImageNameRequested(const char * name)1175 TeamDebugger::AddStopImageNameRequested(const char* name)
1176 {
1177 BMessage message(MSG_ADD_STOP_IMAGE_NAME);
1178 message.AddString("name", name);
1179 PostMessage(&message);
1180 }
1181
1182
1183 void
RemoveStopImageNameRequested(const char * name)1184 TeamDebugger::RemoveStopImageNameRequested(const char* name)
1185 {
1186 BMessage message(MSG_REMOVE_STOP_IMAGE_NAME);
1187 message.AddString("name", name);
1188 PostMessage(&message);
1189 }
1190
1191
1192 void
SetDefaultSignalDispositionRequested(int32 disposition)1193 TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition)
1194 {
1195 BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION);
1196 message.AddInt32("disposition", disposition);
1197 PostMessage(&message);
1198 }
1199
1200
1201 void
SetCustomSignalDispositionRequested(int32 signal,int32 disposition)1202 TeamDebugger::SetCustomSignalDispositionRequested(int32 signal,
1203 int32 disposition)
1204 {
1205 BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION);
1206 message.AddInt32("signal", signal);
1207 message.AddInt32("disposition", disposition);
1208 PostMessage(&message);
1209 }
1210
1211
1212 void
RemoveCustomSignalDispositionRequested(int32 signal)1213 TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal)
1214 {
1215 BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION);
1216 message.AddInt32("signal", signal);
1217 PostMessage(&message);
1218 }
1219
1220
1221 void
ClearBreakpointRequested(UserBreakpoint * breakpoint)1222 TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
1223 {
1224 BMessage message(MSG_CLEAR_BREAKPOINT);
1225 BReference<UserBreakpoint> breakpointReference(breakpoint);
1226 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1227 && PostMessage(&message) == B_OK) {
1228 breakpointReference.Detach();
1229 }
1230 }
1231
1232
1233 void
SetWatchpointRequested(target_addr_t address,uint32 type,int32 length,bool enabled)1234 TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
1235 int32 length, bool enabled)
1236 {
1237 BMessage message(MSG_SET_WATCHPOINT);
1238 message.AddUInt64("address", (uint64)address);
1239 message.AddUInt32("type", type);
1240 message.AddInt32("length", length);
1241 message.AddBool("enabled", enabled);
1242 PostMessage(&message);
1243 }
1244
1245
1246 void
SetWatchpointEnabledRequested(Watchpoint * watchpoint,bool enabled)1247 TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
1248 bool enabled)
1249 {
1250 BMessage message(MSG_SET_WATCHPOINT);
1251 BReference<Watchpoint> watchpointReference(watchpoint);
1252 if (message.AddPointer("watchpoint", watchpoint) == B_OK
1253 && message.AddBool("enabled", enabled) == B_OK
1254 && PostMessage(&message) == B_OK) {
1255 watchpointReference.Detach();
1256 }
1257 }
1258
1259
1260 void
ClearWatchpointRequested(target_addr_t address)1261 TeamDebugger::ClearWatchpointRequested(target_addr_t address)
1262 {
1263 BMessage message(MSG_CLEAR_WATCHPOINT);
1264 message.AddUInt64("address", (uint64)address);
1265 PostMessage(&message);
1266 }
1267
1268
1269 void
ClearWatchpointRequested(Watchpoint * watchpoint)1270 TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
1271 {
1272 BMessage message(MSG_CLEAR_WATCHPOINT);
1273 BReference<Watchpoint> watchpointReference(watchpoint);
1274 if (message.AddPointer("watchpoint", watchpoint) == B_OK
1275 && PostMessage(&message) == B_OK) {
1276 watchpointReference.Detach();
1277 }
1278 }
1279
1280
1281 void
InspectRequested(target_addr_t address,TeamMemoryBlock::Listener * listener)1282 TeamDebugger::InspectRequested(target_addr_t address,
1283 TeamMemoryBlock::Listener *listener)
1284 {
1285 BMessage message(MSG_INSPECT_ADDRESS);
1286 message.AddUInt64("address", address);
1287 message.AddPointer("listener", listener);
1288 PostMessage(&message);
1289 }
1290
1291
1292 void
MemoryWriteRequested(target_addr_t address,const void * data,target_size_t size)1293 TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data,
1294 target_size_t size)
1295 {
1296 BMessage message(MSG_WRITE_TARGET_MEMORY);
1297 message.AddUInt64("address", address);
1298 message.AddPointer("data", data);
1299 message.AddUInt64("size", size);
1300 PostMessage(&message);
1301 }
1302
1303
1304 void
ExpressionEvaluationRequested(SourceLanguage * language,ExpressionInfo * info,StackFrame * frame,::Thread * thread)1305 TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
1306 ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
1307 {
1308 BMessage message(MSG_EVALUATE_EXPRESSION);
1309 message.AddPointer("language", language);
1310 message.AddPointer("info", info);
1311 if (frame != NULL)
1312 message.AddPointer("frame", frame);
1313 if (thread != NULL)
1314 message.AddPointer("thread", thread);
1315
1316 BReference<SourceLanguage> languageReference(language);
1317 BReference<ExpressionInfo> infoReference(info);
1318 if (PostMessage(&message) == B_OK) {
1319 languageReference.Detach();
1320 infoReference.Detach();
1321 }
1322 }
1323
1324
1325 void
DebugReportRequested(entry_ref * targetPath)1326 TeamDebugger::DebugReportRequested(entry_ref* targetPath)
1327 {
1328 BMessage message(MSG_GENERATE_DEBUG_REPORT);
1329 message.AddRef("target", targetPath);
1330 PostMessage(&message);
1331 }
1332
1333
1334 void
WriteCoreFileRequested(entry_ref * targetPath)1335 TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
1336 {
1337 BMessage message(MSG_WRITE_CORE_FILE);
1338 message.AddRef("target", targetPath);
1339 PostMessage(&message);
1340 }
1341
1342
1343 void
TeamRestartRequested()1344 TeamDebugger::TeamRestartRequested()
1345 {
1346 PostMessage(MSG_TEAM_RESTART_REQUESTED);
1347 }
1348
1349
1350 bool
UserInterfaceQuitRequested(QuitOption quitOption)1351 TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
1352 {
1353 bool askUser = false;
1354 switch (quitOption) {
1355 case QUIT_OPTION_ASK_USER:
1356 askUser = true;
1357 break;
1358
1359 case QUIT_OPTION_ASK_KILL_TEAM:
1360 fKillTeamOnQuit = true;
1361 break;
1362
1363 case QUIT_OPTION_ASK_RESUME_TEAM:
1364 break;
1365 }
1366
1367 if (askUser) {
1368 AutoLocker< ::Team> locker(fTeam);
1369 BString name(fTeam->Name());
1370 locker.Unlock();
1371
1372 BString message;
1373 message << "What shall be done about the debugged team '";
1374 message << name;
1375 message << "'?";
1376
1377 name.Remove(0, name.FindLast('/') + 1);
1378
1379 BString killLabel("Kill ");
1380 killLabel << name;
1381
1382 BString resumeLabel("Resume ");
1383 resumeLabel << name;
1384
1385 int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
1386 message, killLabel, "Cancel", resumeLabel);
1387
1388 switch (choice) {
1389 case 0:
1390 fKillTeamOnQuit = true;
1391 break;
1392 case 1:
1393 case -1:
1394 return false;
1395 case 2:
1396 // Detach from the team and resume and stopped threads.
1397 break;
1398 }
1399 }
1400
1401 PostMessage(B_QUIT_REQUESTED);
1402
1403 return true;
1404 }
1405
1406
1407 void
JobStarted(Job * job)1408 TeamDebugger::JobStarted(Job* job)
1409 {
1410 BString description(job->GetDescription());
1411 if (!description.IsEmpty()) {
1412 description.Append(B_UTF8_ELLIPSIS);
1413 fUserInterface->NotifyBackgroundWorkStatus(description.String());
1414 }
1415 }
1416
1417
1418 void
JobDone(Job * job)1419 TeamDebugger::JobDone(Job* job)
1420 {
1421 TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
1422 _ResetUserBackgroundStatusIfNeeded();
1423 }
1424
1425
1426 void
JobWaitingForInput(Job * job)1427 TeamDebugger::JobWaitingForInput(Job* job)
1428 {
1429 LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);
1430
1431 if (infoJob == NULL)
1432 return;
1433
1434 BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
1435 message.AddPointer("job", infoJob);
1436 message.AddPointer("state", infoJob->GetLoadingState());
1437 PostMessage(&message);
1438 }
1439
1440
1441 void
JobFailed(Job * job)1442 TeamDebugger::JobFailed(Job* job)
1443 {
1444 TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
1445 // TODO: notify user
1446 _ResetUserBackgroundStatusIfNeeded();
1447 }
1448
1449
1450 void
JobAborted(Job * job)1451 TeamDebugger::JobAborted(Job* job)
1452 {
1453 TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
1454 // TODO: For a stack frame source loader thread we should reset the
1455 // loading state! Asynchronously due to locking order.
1456 _ResetUserBackgroundStatusIfNeeded();
1457 }
1458
1459
1460 void
ThreadStateChanged(const::Team::ThreadEvent & event)1461 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
1462 {
1463 BMessage message(MSG_THREAD_STATE_CHANGED);
1464 message.AddInt32("thread", event.GetThread()->ID());
1465 PostMessage(&message);
1466 }
1467
1468
1469 void
ThreadCpuStateChanged(const::Team::ThreadEvent & event)1470 TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
1471 {
1472 BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1473 message.AddInt32("thread", event.GetThread()->ID());
1474 PostMessage(&message);
1475 }
1476
1477
1478 void
ThreadStackTraceChanged(const::Team::ThreadEvent & event)1479 TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
1480 {
1481 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1482 message.AddInt32("thread", event.GetThread()->ID());
1483 PostMessage(&message);
1484 }
1485
1486
1487 void
ImageDebugInfoChanged(const::Team::ImageEvent & event)1488 TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event)
1489 {
1490 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1491 message.AddInt32("image", event.GetImage()->ID());
1492 PostMessage(&message);
1493 }
1494
1495
1496 /*static*/ status_t
_DebugEventListenerEntry(void * data)1497 TeamDebugger::_DebugEventListenerEntry(void* data)
1498 {
1499 return ((TeamDebugger*)data)->_DebugEventListener();
1500 }
1501
1502
1503 status_t
_DebugEventListener()1504 TeamDebugger::_DebugEventListener()
1505 {
1506 while (!fTerminating) {
1507 // get the next event
1508 DebugEvent* event;
1509 status_t error = fDebuggerInterface->GetNextDebugEvent(event);
1510 if (error != B_OK)
1511 break;
1512 // TODO: Error handling!
1513
1514 if (event->Team() != fTeamID) {
1515 TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
1516 "from team %" B_PRId32 "!\n", fTeamID, event->Team());
1517 continue;
1518 }
1519
1520 BMessage message(MSG_DEBUGGER_EVENT);
1521 if (message.AddPointer("event", event) != B_OK
1522 || PostMessage(&message) != B_OK) {
1523 // TODO: Continue thread if necessary!
1524 delete event;
1525 }
1526 }
1527
1528 return B_OK;
1529 }
1530
1531
1532 void
_HandleDebuggerMessage(DebugEvent * event)1533 TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
1534 {
1535 TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
1536 event->EventType());
1537
1538 bool handled = false;
1539
1540 ThreadHandler* handler = _GetThreadHandler(event->Thread());
1541 BReference<ThreadHandler> handlerReference(handler, true);
1542
1543 switch (event->EventType()) {
1544 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
1545 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
1546 B_PRId32 "\n", event->Thread());
1547
1548 if (handler != NULL) {
1549 handled = handler->HandleThreadDebugged(
1550 dynamic_cast<ThreadDebuggedEvent*>(event));
1551 }
1552 break;
1553 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
1554 TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
1555 "\n", event->Thread());
1556
1557 if (handler != NULL) {
1558 handled = handler->HandleDebuggerCall(
1559 dynamic_cast<DebuggerCallEvent*>(event));
1560 }
1561 break;
1562 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
1563 TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
1564 "\n", event->Thread());
1565
1566 if (handler != NULL) {
1567 handled = handler->HandleBreakpointHit(
1568 dynamic_cast<BreakpointHitEvent*>(event));
1569 }
1570 break;
1571 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
1572 TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
1573 "\n", event->Thread());
1574
1575 if (handler != NULL) {
1576 handled = handler->HandleWatchpointHit(
1577 dynamic_cast<WatchpointHitEvent*>(event));
1578 }
1579 break;
1580 case B_DEBUGGER_MESSAGE_SINGLE_STEP:
1581 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
1582 "\n", event->Thread());
1583
1584 if (handler != NULL) {
1585 handled = handler->HandleSingleStep(
1586 dynamic_cast<SingleStepEvent*>(event));
1587 }
1588 break;
1589 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
1590 TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
1591 B_PRId32 "\n", event->Thread());
1592
1593 if (handler != NULL) {
1594 handled = handler->HandleExceptionOccurred(
1595 dynamic_cast<ExceptionOccurredEvent*>(event));
1596 }
1597 break;
1598 // case B_DEBUGGER_MESSAGE_TEAM_CREATED:
1599 //printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
1600 // break;
1601 case B_DEBUGGER_MESSAGE_TEAM_DELETED:
1602 {
1603 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
1604 "\n", event->Team());
1605 TeamDeletedEvent* teamEvent
1606 = dynamic_cast<TeamDeletedEvent*>(event);
1607 handled = _HandleTeamDeleted(teamEvent);
1608 break;
1609 }
1610 case B_DEBUGGER_MESSAGE_TEAM_EXEC:
1611 {
1612 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
1613 event->Team());
1614
1615 TeamExecEvent* teamEvent
1616 = dynamic_cast<TeamExecEvent*>(event);
1617 _PrepareForTeamExec(teamEvent);
1618 break;
1619 }
1620 case B_DEBUGGER_MESSAGE_THREAD_CREATED:
1621 {
1622 ThreadCreatedEvent* threadEvent
1623 = dynamic_cast<ThreadCreatedEvent*>(event);
1624 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
1625 "\n", threadEvent->NewThread());
1626 handled = _HandleThreadCreated(threadEvent);
1627 break;
1628 }
1629 case DEBUGGER_MESSAGE_THREAD_RENAMED:
1630 {
1631 ThreadRenamedEvent* threadEvent
1632 = dynamic_cast<ThreadRenamedEvent*>(event);
1633 TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
1634 " (\"%s\")\n",
1635 threadEvent->RenamedThread(), threadEvent->NewName());
1636 handled = _HandleThreadRenamed(threadEvent);
1637 break;
1638 }
1639 case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
1640 {
1641 ThreadPriorityChangedEvent* threadEvent
1642 = dynamic_cast<ThreadPriorityChangedEvent*>(event);
1643 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
1644 " %" B_PRId32 "\n", threadEvent->ChangedThread());
1645 handled = _HandleThreadPriorityChanged(threadEvent);
1646 break;
1647 }
1648 case B_DEBUGGER_MESSAGE_THREAD_DELETED:
1649 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
1650 "\n", event->Thread());
1651 handled = _HandleThreadDeleted(
1652 dynamic_cast<ThreadDeletedEvent*>(event));
1653 break;
1654 case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
1655 {
1656 ImageCreatedEvent* imageEvent
1657 = dynamic_cast<ImageCreatedEvent*>(event);
1658 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
1659 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1660 imageEvent->GetImageInfo().ImageID());
1661 handled = _HandleImageCreated(imageEvent);
1662 break;
1663 }
1664 case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
1665 {
1666 ImageDeletedEvent* imageEvent
1667 = dynamic_cast<ImageDeletedEvent*>(event);
1668 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
1669 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1670 imageEvent->GetImageInfo().ImageID());
1671 handled = _HandleImageDeleted(imageEvent);
1672 break;
1673 }
1674 case B_DEBUGGER_MESSAGE_POST_SYSCALL:
1675 {
1676 PostSyscallEvent* postSyscallEvent
1677 = dynamic_cast<PostSyscallEvent*>(event);
1678 TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %"
1679 B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall());
1680 handled = _HandlePostSyscall(postSyscallEvent);
1681
1682 // if a thread was blocked in a syscall when we requested to
1683 // stop it for debugging, then that request will interrupt
1684 // said call, and the post syscall event will be all we get
1685 // in response. Consequently, we need to treat this case as
1686 // equivalent to having received a thread debugged event.
1687 AutoLocker< ::Team> teamLocker(fTeam);
1688 ::Thread* thread = fTeam->ThreadByID(event->Thread());
1689 if (handler != NULL && thread != NULL
1690 && thread->StopRequestPending()) {
1691 handled = handler->HandleThreadDebugged(NULL);
1692 }
1693 break;
1694 }
1695 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
1696 {
1697 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %"
1698 B_PRId32 "\n", event->Thread());
1699
1700 if (handler != NULL) {
1701 handled = handler->HandleSignalReceived(
1702 dynamic_cast<SignalReceivedEvent*>(event));
1703 }
1704 break;
1705 }
1706 case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
1707 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
1708 case B_DEBUGGER_MESSAGE_HANDED_OVER:
1709 // not interested
1710 break;
1711 default:
1712 WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
1713 "%" B_PRId32 "\n", fTeamID, event->EventType());
1714 break;
1715 }
1716
1717 if (!handled && event->ThreadStopped())
1718 fDebuggerInterface->ContinueThread(event->Thread());
1719 }
1720
1721
1722 bool
_HandleTeamDeleted(TeamDeletedEvent * event)1723 TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event)
1724 {
1725 char message[64];
1726 fDebuggerInterface->Close(false);
1727
1728 snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ",
1729 event->Team());
1730
1731 int32 result = fUserInterface->SynchronouslyAskUser("Team terminated",
1732 message, "Do nothing", "Quit", fCommandLineArgc != 0
1733 ? "Restart team" : NULL);
1734
1735 switch (result) {
1736 case 1:
1737 case -1:
1738 {
1739 PostMessage(B_QUIT_REQUESTED);
1740 break;
1741 }
1742 case 2:
1743 {
1744 _SaveSettings();
1745 fListener->TeamDebuggerRestartRequested(this);
1746 break;
1747 }
1748 default:
1749 break;
1750 }
1751
1752 return true;
1753 }
1754
1755
1756 bool
_HandleThreadCreated(ThreadCreatedEvent * event)1757 TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
1758 {
1759 AutoLocker< ::Team> locker(fTeam);
1760
1761 ThreadInfo info;
1762 status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
1763 info);
1764 if (error == B_OK) {
1765 ::Thread* thread;
1766 fTeam->AddThread(info, &thread);
1767
1768 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
1769 fWorker, fDebuggerInterface, this, fBreakpointManager);
1770 if (handler != NULL) {
1771 fThreadHandlers.Insert(handler);
1772 handler->Init();
1773 }
1774 }
1775
1776 return false;
1777 }
1778
1779
1780 bool
_HandleThreadRenamed(ThreadRenamedEvent * event)1781 TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
1782 {
1783 AutoLocker< ::Team> locker(fTeam);
1784
1785 ::Thread* thread = fTeam->ThreadByID(event->RenamedThread());
1786
1787 if (thread != NULL)
1788 thread->SetName(event->NewName());
1789
1790 return false;
1791 }
1792
1793
1794 bool
_HandleThreadPriorityChanged(ThreadPriorityChangedEvent *)1795 TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
1796 {
1797 // TODO: implement once we actually track thread priorities
1798
1799 return false;
1800 }
1801
1802
1803 bool
_HandleThreadDeleted(ThreadDeletedEvent * event)1804 TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
1805 {
1806 AutoLocker< ::Team> locker(fTeam);
1807 if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
1808 fThreadHandlers.Remove(handler);
1809 handler->ReleaseReference();
1810 }
1811 fTeam->RemoveThread(event->Thread());
1812 return false;
1813 }
1814
1815
1816 bool
_HandleImageCreated(ImageCreatedEvent * event)1817 TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
1818 {
1819 AutoLocker< ::Team> locker(fTeam);
1820 _AddImage(event->GetImageInfo());
1821
1822 ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
1823 event->GetImageInfo().ImageID(), event->Thread());
1824 if (info == NULL)
1825 return false;
1826
1827 fImageInfoPendingThreads->Insert(info);
1828 return true;
1829 }
1830
1831
1832 bool
_HandleImageDeleted(ImageDeletedEvent * event)1833 TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
1834 {
1835 AutoLocker< ::Team> locker(fTeam);
1836 fTeam->RemoveImage(event->GetImageInfo().ImageID());
1837
1838 ImageHandler* imageHandler = fImageHandlers->Lookup(
1839 event->GetImageInfo().ImageID());
1840 if (imageHandler == NULL)
1841 return false;
1842
1843 fImageHandlers->Remove(imageHandler);
1844 BReference<ImageHandler> imageHandlerReference(imageHandler, true);
1845 locker.Unlock();
1846
1847 // remove breakpoints in the image
1848 fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());
1849
1850 return false;
1851 }
1852
1853
1854 bool
_HandlePostSyscall(PostSyscallEvent * event)1855 TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event)
1856 {
1857 const SyscallInfo& info = event->GetSyscallInfo();
1858
1859 switch (info.Syscall()) {
1860 case SYSCALL_WRITE:
1861 {
1862 if ((ssize_t)info.ReturnValue() <= 0)
1863 break;
1864
1865 int32 fd;
1866 target_addr_t address;
1867 size_t size;
1868 // TODO: decoding the syscall arguments should probably be
1869 // factored out into an Architecture method of its own, since
1870 // there's no guarantee the target architecture has the same
1871 // endianness as the host. This could re-use the syscall
1872 // argument parser that strace uses, though that would need to
1873 // be adapted to handle the aforementioned endian differences.
1874 // This works for x86{-64} for now though.
1875 if (fTeam->GetArchitecture()->AddressSize() == 4) {
1876 const uint32* args = (const uint32*)info.Arguments();
1877 fd = args[0];
1878 address = args[3];
1879 size = args[4];
1880 } else {
1881 const uint64* args = (const uint64*)info.Arguments();
1882 fd = args[0];
1883 address = args[2];
1884 size = args[3];
1885 }
1886
1887 if (fd == 1 || fd == 2) {
1888 BString data;
1889
1890 ssize_t result = fDebuggerInterface->ReadMemoryString(
1891 address, size, data);
1892 if (result >= 0)
1893 fTeam->NotifyConsoleOutputReceived(fd, data);
1894 }
1895 break;
1896 }
1897 case SYSCALL_WRITEV:
1898 {
1899 // TODO: handle
1900 }
1901 default:
1902 break;
1903 }
1904
1905 return false;
1906 }
1907
1908
1909 void
_PrepareForTeamExec(TeamExecEvent * event)1910 TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event)
1911 {
1912 // NB: must be called with team lock held.
1913
1914 _SaveSettings();
1915
1916 // when notified of exec, we need to clear out data related
1917 // to the old team.
1918 const ImageList& images = fTeam->Images();
1919
1920 for (ImageList::ConstIterator it = images.GetIterator();
1921 Image* image = it.Next();) {
1922 fBreakpointManager->RemoveImageBreakpoints(image);
1923 }
1924
1925 BObjectList<UserBreakpoint> breakpointsToRemove(20, false);
1926 const UserBreakpointList& breakpoints = fTeam->UserBreakpoints();
1927 for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator();
1928 UserBreakpoint* breakpoint = it.Next();) {
1929 breakpointsToRemove.AddItem(breakpoint);
1930 breakpoint->AcquireReference();
1931 }
1932
1933 for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) {
1934 UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i);
1935 fTeam->RemoveUserBreakpoint(breakpoint);
1936 fTeam->NotifyUserBreakpointChanged(breakpoint);
1937 breakpoint->ReleaseReference();
1938 }
1939
1940 fTeam->ClearImages();
1941 fTeam->ClearSignalDispositionMappings();
1942 fExecPending = true;
1943 }
1944
1945
1946 void
_HandleImageDebugInfoChanged(image_id imageID)1947 TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID)
1948 {
1949 // get the image (via the image handler)
1950 AutoLocker< ::Team> locker(fTeam);
1951 ImageHandler* imageHandler = fImageHandlers->Lookup(imageID);
1952 if (imageHandler == NULL)
1953 return;
1954
1955 Image* image = imageHandler->GetImage();
1956 BReference<Image> imageReference(image);
1957 image_debug_info_state state = image->ImageDebugInfoState();
1958
1959 bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE
1960 && state != IMAGE_DEBUG_INFO_LOADING;
1961 // this needs to be done first so that breakpoints are loaded.
1962 // otherwise, UpdateImageBreakpoints() won't find the appropriate
1963 // UserBreakpoints to create/install instances for.
1964 if (handlePostExecSetup) {
1965 fTeam->SetName(image->Name());
1966 _LoadSettings();
1967 fExecPending = false;
1968 }
1969
1970 locker.Unlock();
1971
1972 if (state == IMAGE_DEBUG_INFO_LOADED
1973 || state == IMAGE_DEBUG_INFO_UNAVAILABLE) {
1974
1975 // update breakpoints in the image
1976 fBreakpointManager->UpdateImageBreakpoints(image);
1977
1978 ImageInfoPendingThread* thread = fImageInfoPendingThreads
1979 ->Lookup(imageID);
1980 if (thread != NULL) {
1981 fImageInfoPendingThreads->Remove(thread);
1982 ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread);
1983 locker.Lock();
1984 ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
1985 BReference<ThreadHandler> handlerReference(handler, true);
1986 if (fTeam->StopOnImageLoad()) {
1987
1988 bool stop = true;
1989 const BString& imageName = image->Name();
1990 // only match on the image filename itself
1991 const char* rawImageName = imageName.String()
1992 + imageName.FindLast('/') + 1;
1993 if (fTeam->StopImageNameListEnabled()) {
1994 const BStringList& nameList = fTeam->StopImageNames();
1995 stop = nameList.HasString(rawImageName);
1996 }
1997
1998 if (stop && handler != NULL) {
1999 BString stopReason;
2000 stopReason.SetToFormat("Image '%s' loaded.",
2001 rawImageName);
2002 locker.Unlock();
2003
2004 if (handler->HandleThreadDebugged(NULL, stopReason))
2005 return;
2006 } else
2007 locker.Unlock();
2008 } else if (handlePostExecSetup) {
2009 // in the case of an exec(), we can't stop in main() until
2010 // the new app image has been loaded, so we know where to
2011 // set the main breakpoint at.
2012 SymbolInfo symbolInfo;
2013 if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(),
2014 "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) {
2015 handler->SetBreakpointAndRun(symbolInfo.Address());
2016 }
2017 } else {
2018 locker.Unlock();
2019 fDebuggerInterface->ContinueThread(thread->ThreadID());
2020 }
2021 }
2022 }
2023 }
2024
2025
2026 void
_HandleImageFileChanged(image_id imageID)2027 TeamDebugger::_HandleImageFileChanged(image_id imageID)
2028 {
2029 TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
2030 imageID);
2031 // TODO: Reload the debug info!
2032 }
2033
2034
2035 void
_HandleSetUserBreakpoint(target_addr_t address,bool enabled,bool hidden)2036 TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled,
2037 bool hidden)
2038 {
2039 TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
2040 ", %d, %d)\n", address, enabled, hidden);
2041
2042 // check whether there already is a breakpoint
2043 AutoLocker< ::Team> locker(fTeam);
2044
2045 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2046 UserBreakpoint* userBreakpoint = NULL;
2047 if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
2048 userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2049 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2050
2051 if (userBreakpoint == NULL) {
2052 TRACE_CONTROL(" no breakpoint yet\n");
2053
2054 // get the function at the address
2055 Image* image = fTeam->ImageByAddress(address);
2056
2057 TRACE_CONTROL(" image: %p\n", image);
2058
2059 if (image == NULL)
2060 return;
2061 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
2062
2063 TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo);
2064
2065 if (imageDebugInfo == NULL)
2066 return;
2067 // TODO: Handle this case by loading the debug info, if possible!
2068 FunctionInstance* functionInstance
2069 = imageDebugInfo->FunctionAtAddress(address);
2070
2071 TRACE_CONTROL(" function instance: %p\n", functionInstance);
2072
2073 if (functionInstance == NULL)
2074 return;
2075 Function* function = functionInstance->GetFunction();
2076
2077 TRACE_CONTROL(" function: %p\n", function);
2078
2079 // get the source location for the address
2080 FunctionDebugInfo* functionDebugInfo
2081 = functionInstance->GetFunctionDebugInfo();
2082 SourceLocation sourceLocation;
2083 Statement* breakpointStatement = NULL;
2084 if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
2085 functionDebugInfo, address, breakpointStatement) != B_OK) {
2086 return;
2087 }
2088
2089 sourceLocation = breakpointStatement->StartSourceLocation();
2090 breakpointStatement->ReleaseReference();
2091
2092 target_addr_t relativeAddress = address - functionInstance->Address();
2093
2094 TRACE_CONTROL(" relative address: %#" B_PRIx64 ", source location: "
2095 "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
2096 sourceLocation.Line(), sourceLocation.Column());
2097
2098 // get function id
2099 FunctionID* functionID = functionInstance->GetFunctionID();
2100 if (functionID == NULL)
2101 return;
2102 BReference<FunctionID> functionIDReference(functionID, true);
2103
2104 // create the user breakpoint
2105 userBreakpoint = new(std::nothrow) UserBreakpoint(
2106 UserBreakpointLocation(functionID, function->SourceFile(),
2107 sourceLocation, relativeAddress));
2108 if (userBreakpoint == NULL)
2109 return;
2110 userBreakpointReference.SetTo(userBreakpoint, true);
2111
2112 userBreakpoint->SetHidden(hidden);
2113
2114 TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint);
2115
2116 // iterate through all function instances and create
2117 // UserBreakpointInstances
2118 for (FunctionInstanceList::ConstIterator it
2119 = function->Instances().GetIterator();
2120 FunctionInstance* instance = it.Next();) {
2121 TRACE_CONTROL(" function instance %p: range: %#" B_PRIx64 " - %#"
2122 B_PRIx64 "\n", instance, instance->Address(),
2123 instance->Address() + instance->Size());
2124
2125 // get the breakpoint address for the instance
2126 target_addr_t instanceAddress = 0;
2127 if (instance == functionInstance) {
2128 instanceAddress = address;
2129 } else if (functionInstance->SourceFile() != NULL) {
2130 // We have a source file, so get the address for the source
2131 // location.
2132 Statement* statement = NULL;
2133 functionDebugInfo = instance->GetFunctionDebugInfo();
2134 functionDebugInfo->GetSpecificImageDebugInfo()
2135 ->GetStatementAtSourceLocation(functionDebugInfo,
2136 sourceLocation, statement);
2137 if (statement != NULL) {
2138 instanceAddress = statement->CoveringAddressRange().Start();
2139 // TODO: What about BreakpointAllowed()?
2140 statement->ReleaseReference();
2141 }
2142 }
2143
2144 TRACE_CONTROL(" breakpoint address using source info: %" B_PRIx64
2145 "\n", instanceAddress);
2146
2147 if (instanceAddress == 0) {
2148 // No source file (or we failed getting the statement), so try
2149 // to use the same relative address.
2150 if (relativeAddress > instance->Size())
2151 continue;
2152 instanceAddress = instance->Address() + relativeAddress;
2153 }
2154
2155 TRACE_CONTROL(" final breakpoint address: %" B_PRIx64 "\n",
2156 instanceAddress);
2157
2158 UserBreakpointInstance* breakpointInstance = new(std::nothrow)
2159 UserBreakpointInstance(userBreakpoint, instanceAddress);
2160 if (breakpointInstance == NULL
2161 || !userBreakpoint->AddInstance(breakpointInstance)) {
2162 delete breakpointInstance;
2163 return;
2164 }
2165
2166 TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance);
2167 }
2168 }
2169
2170 locker.Unlock();
2171
2172 _HandleSetUserBreakpoint(userBreakpoint, enabled);
2173 }
2174
2175
2176 void
_HandleSetUserBreakpoint(UserBreakpoint * breakpoint,bool enabled)2177 TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
2178 {
2179 status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
2180 enabled);
2181 if (error != B_OK) {
2182 _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
2183 strerror(error));
2184 }
2185 }
2186
2187
2188 void
_HandleClearUserBreakpoint(target_addr_t address)2189 TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
2190 {
2191 TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
2192 address);
2193
2194 AutoLocker< ::Team> locker(fTeam);
2195
2196 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2197 if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
2198 return;
2199 UserBreakpoint* userBreakpoint
2200 = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2201 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2202
2203 locker.Unlock();
2204
2205 _HandleClearUserBreakpoint(userBreakpoint);
2206 }
2207
2208
2209 void
_HandleClearUserBreakpoint(UserBreakpoint * breakpoint)2210 TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
2211 {
2212 fBreakpointManager->UninstallUserBreakpoint(breakpoint);
2213 }
2214
2215
2216 void
_HandleSetWatchpoint(target_addr_t address,uint32 type,int32 length,bool enabled)2217 TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
2218 int32 length, bool enabled)
2219 {
2220 Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
2221 length);
2222
2223 if (watchpoint == NULL)
2224 return;
2225 BReference<Watchpoint> watchpointRef(watchpoint, true);
2226
2227 _HandleSetWatchpoint(watchpoint, enabled);
2228 }
2229
2230
2231 void
_HandleSetWatchpoint(Watchpoint * watchpoint,bool enabled)2232 TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
2233 {
2234 status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
2235 enabled);
2236 if (error != B_OK) {
2237 _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
2238 strerror(error));
2239 }
2240 }
2241
2242
2243 void
_HandleClearWatchpoint(target_addr_t address)2244 TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
2245 {
2246 TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
2247 address);
2248
2249 AutoLocker< ::Team> locker(fTeam);
2250
2251 Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
2252 if (watchpoint == NULL)
2253 return;
2254 BReference<Watchpoint> watchpointReference(watchpoint);
2255
2256 locker.Unlock();
2257
2258 _HandleClearWatchpoint(watchpoint);
2259 }
2260
2261
2262 void
_HandleClearWatchpoint(Watchpoint * watchpoint)2263 TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
2264 {
2265 fWatchpointManager->UninstallWatchpoint(watchpoint);
2266 }
2267
2268
2269 void
_HandleInspectAddress(target_addr_t address,TeamMemoryBlock::Listener * listener)2270 TeamDebugger::_HandleInspectAddress(target_addr_t address,
2271 TeamMemoryBlock::Listener* listener)
2272 {
2273 TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
2274 address, listener);
2275
2276 TeamMemoryBlock* memoryBlock = fMemoryBlockManager
2277 ->GetMemoryBlock(address);
2278
2279 if (memoryBlock == NULL) {
2280 _NotifyUser("Inspect Address", "Failed to allocate memory block");
2281 return;
2282 }
2283
2284 if (!memoryBlock->IsValid()) {
2285 AutoLocker< ::Team> teamLocker(fTeam);
2286
2287 if (!memoryBlock->HasListener(listener))
2288 memoryBlock->AddListener(listener);
2289
2290 TeamMemory* memory = fTeam->GetTeamMemory();
2291 // schedule the job
2292 status_t result;
2293 if ((result = fWorker->ScheduleJob(
2294 new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
2295 memoryBlock),
2296 this)) != B_OK) {
2297
2298 memoryBlock->NotifyDataRetrieved(result);
2299 memoryBlock->ReleaseReference();
2300
2301 _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
2302 strerror(result));
2303 }
2304 } else
2305 memoryBlock->NotifyDataRetrieved();
2306
2307 }
2308
2309
2310 void
_HandleWriteMemory(target_addr_t address,void * data,target_size_t size)2311 TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data,
2312 target_size_t size)
2313 {
2314 TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, "
2315 "%" B_PRIu64 ")\n", address, data, size);
2316
2317 AutoLocker< ::Team> teamLocker(fTeam);
2318 TeamMemory* memory = fTeam->GetTeamMemory();
2319 // schedule the job
2320 status_t result;
2321 if ((result = fWorker->ScheduleJob(
2322 new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size),
2323 this)) != B_OK) {
2324 _NotifyUser("Write Memory", "Failed to write memory data: %s",
2325 strerror(result));
2326 }
2327 }
2328
2329
2330 void
_HandleEvaluateExpression(SourceLanguage * language,ExpressionInfo * info,StackFrame * frame,::Thread * thread)2331 TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
2332 ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
2333 {
2334 status_t result = fWorker->ScheduleJob(
2335 new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
2336 language, info, frame, thread));
2337 if (result != B_OK) {
2338 _NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
2339 strerror(result));
2340 }
2341 }
2342
2343
2344 void
_HandleWriteCoreFile(const entry_ref & targetPath)2345 TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
2346 {
2347 status_t result = fWorker->ScheduleJob(
2348 new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
2349 targetPath));
2350 if (result != B_OK) {
2351 _NotifyUser("Write Core File", "Failed to write core file: %s",
2352 strerror(result));
2353 }
2354 }
2355
2356
2357 status_t
_HandleSetArguments(int argc,const char * const * argv)2358 TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
2359 {
2360 fCommandLineArgc = argc;
2361 fCommandLineArgv = new(std::nothrow) const char*[argc];
2362 if (fCommandLineArgv == NULL)
2363 return B_NO_MEMORY;
2364
2365 memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc);
2366
2367 for (int i = 0; i < argc; i++) {
2368 fCommandLineArgv[i] = strdup(argv[i]);
2369 if (fCommandLineArgv[i] == NULL)
2370 return B_NO_MEMORY;
2371 }
2372
2373 return B_OK;
2374 }
2375
2376
2377 void
_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState * state)2378 TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
2379 {
2380 SpecificImageDebugInfoLoadingState* specificState
2381 = state->GetSpecificDebugInfoLoadingState();
2382
2383 ImageDebugLoadingStateHandler* handler;
2384 if (ImageDebugLoadingStateHandlerRoster::Default()
2385 ->FindStateHandler(specificState, handler) != B_OK) {
2386 TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
2387 "Failed to find appropriate information handler, aborting.");
2388 return;
2389 }
2390
2391 handler->HandleState(specificState, fUserInterface);
2392 }
2393
2394
2395 ThreadHandler*
_GetThreadHandler(thread_id threadID)2396 TeamDebugger::_GetThreadHandler(thread_id threadID)
2397 {
2398 AutoLocker< ::Team> locker(fTeam);
2399
2400 ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
2401 if (handler != NULL)
2402 handler->AcquireReference();
2403 return handler;
2404 }
2405
2406
2407 status_t
_AddImage(const ImageInfo & imageInfo,Image ** _image)2408 TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
2409 {
2410 LocatableFile* file = NULL;
2411 if (strchr(imageInfo.Name(), '/') != NULL)
2412 file = fFileManager->GetTargetFile(imageInfo.Name());
2413 BReference<LocatableFile> imageFileReference(file, true);
2414
2415 Image* image;
2416 status_t error = fTeam->AddImage(imageInfo, file, &image);
2417 if (error != B_OK)
2418 return error;
2419
2420 ImageDebugInfoRequested(image);
2421
2422 ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
2423 if (imageHandler != NULL)
2424 fImageHandlers->Insert(imageHandler);
2425
2426 if (_image != NULL)
2427 *_image = image;
2428
2429 return B_OK;
2430 }
2431
2432
2433 void
_LoadSettings()2434 TeamDebugger::_LoadSettings()
2435 {
2436 // get the team name
2437 AutoLocker< ::Team> locker(fTeam);
2438 BString teamName = fTeam->Name();
2439 locker.Unlock();
2440
2441 // load the settings
2442 if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
2443 return;
2444
2445 // create the saved breakpoints
2446 for (int32 i = 0; const BreakpointSetting* breakpointSetting
2447 = fTeamSettings.BreakpointAt(i); i++) {
2448 if (breakpointSetting->GetFunctionID() == NULL)
2449 continue;
2450
2451 // get the source file, if any
2452 LocatableFile* sourceFile = NULL;
2453 if (breakpointSetting->SourceFile().Length() > 0) {
2454 sourceFile = fFileManager->GetSourceFile(
2455 breakpointSetting->SourceFile());
2456 if (sourceFile == NULL)
2457 continue;
2458 }
2459 BReference<LocatableFile> sourceFileReference(sourceFile, true);
2460
2461 // create the breakpoint
2462 UserBreakpointLocation location(breakpointSetting->GetFunctionID(),
2463 sourceFile, breakpointSetting->GetSourceLocation(),
2464 breakpointSetting->RelativeAddress());
2465
2466 UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location);
2467 if (breakpoint == NULL)
2468 return;
2469 BReference<UserBreakpoint> breakpointReference(breakpoint, true);
2470
2471 breakpoint->SetHidden(breakpointSetting->IsHidden());
2472 breakpoint->SetCondition(breakpointSetting->Condition());
2473
2474 // install it
2475 fBreakpointManager->InstallUserBreakpoint(breakpoint,
2476 breakpointSetting->IsEnabled());
2477 }
2478
2479 fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings());
2480
2481 const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
2482 fUserInterface->ID());
2483 if (uiSettings != NULL)
2484 fUserInterface->LoadSettings(uiSettings);
2485
2486 const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings();
2487 if (signalSettings != NULL) {
2488 fTeam->SetDefaultSignalDisposition(
2489 signalSettings->DefaultSignalDisposition());
2490
2491 int32 signal;
2492 int32 disposition;
2493 for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions();
2494 i++) {
2495 if (signalSettings->GetCustomSignalDispositionAt(i, signal,
2496 disposition) == B_OK) {
2497 fTeam->SetCustomSignalDisposition(signal, disposition);
2498 }
2499 }
2500 }
2501 }
2502
2503
2504 void
_SaveSettings()2505 TeamDebugger::_SaveSettings()
2506 {
2507 // get the settings
2508 AutoLocker< ::Team> locker(fTeam);
2509 TeamSettings settings;
2510 if (settings.SetTo(fTeam) != B_OK)
2511 return;
2512
2513 TeamUiSettings* uiSettings = NULL;
2514 if (fUserInterface->SaveSettings(uiSettings) != B_OK)
2515 return;
2516 if (uiSettings != NULL)
2517 settings.AddUiSettings(uiSettings);
2518
2519 // preserve the UI settings from our cached copy.
2520 for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
2521 const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
2522 if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
2523 TeamUiSettings* clonedSettings = oldUiSettings->Clone();
2524 if (clonedSettings != NULL)
2525 settings.AddUiSettings(clonedSettings);
2526 }
2527 }
2528
2529 fFileManager->SaveLocationMappings(settings.FileManagerSettings());
2530 locker.Unlock();
2531
2532 // save the settings
2533 fSettingsManager->SaveTeamSettings(settings);
2534 }
2535
2536
2537 void
_NotifyUser(const char * title,const char * text,...)2538 TeamDebugger::_NotifyUser(const char* title, const char* text,...)
2539 {
2540 // print the message
2541 char buffer[1024];
2542 va_list args;
2543 va_start(args, text);
2544 vsnprintf(buffer, sizeof(buffer), text, args);
2545 va_end(args);
2546
2547 // notify the user
2548 fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
2549 }
2550
2551
2552 void
_ResetUserBackgroundStatusIfNeeded()2553 TeamDebugger::_ResetUserBackgroundStatusIfNeeded()
2554 {
2555 if (!fTerminating && !fWorker->HasPendingJobs())
2556 PostMessage(MSG_RESET_USER_BACKGROUND_STATUS);
2557 }
2558
2559
2560 // #pragma mark - Listener
2561
2562
~Listener()2563 TeamDebugger::Listener::~Listener()
2564 {
2565 }
2566