vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debugger / controllers / TeamDebugger.cpp
blob49f152e90cbb48d47ae1b04d7318eb6840b49d99
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 */
8 #include "controllers/TeamDebugger.h"
10 #include <stdarg.h>
11 #include <stdio.h>
13 #include <new>
15 #include <Entry.h>
16 #include <InterfaceDefs.h>
17 #include <Message.h>
18 #include <StringList.h>
20 #include <AutoDeleter.h>
21 #include <AutoLocker.h>
23 #include "debug_utils.h"
24 #include "syscall_numbers.h"
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"
68 // #pragma mark - ImageHandler
71 struct TeamDebugger::ImageHandler : public BReferenceable,
72 private LocatableFile::Listener {
73 public:
74 ImageHandler(TeamDebugger* teamDebugger, Image* image)
76 fTeamDebugger(teamDebugger),
77 fImage(image)
79 fImage->AcquireReference();
80 if (fImage->ImageFile() != NULL)
81 fImage->ImageFile()->AddListener(this);
84 ~ImageHandler()
86 if (fImage->ImageFile() != NULL)
87 fImage->ImageFile()->RemoveListener(this);
88 fImage->ReleaseReference();
91 Image* GetImage() const
93 return fImage;
96 image_id ImageID() const
98 return fImage->ID();
101 private:
102 // LocatableFile::Listener
103 virtual void LocatableFileChanged(LocatableFile* file)
105 BMessage message(MSG_IMAGE_FILE_CHANGED);
106 message.AddInt32("image", fImage->ID());
107 fTeamDebugger->PostMessage(&message);
110 private:
111 TeamDebugger* fTeamDebugger;
112 Image* fImage;
114 public:
115 ImageHandler* fNext;
119 // #pragma mark - ImageHandlerHashDefinition
122 struct TeamDebugger::ImageHandlerHashDefinition {
123 typedef image_id KeyType;
124 typedef ImageHandler ValueType;
126 size_t HashKey(image_id key) const
128 return (size_t)key;
131 size_t Hash(const ImageHandler* value) const
133 return HashKey(value->ImageID());
136 bool Compare(image_id key, const ImageHandler* value) const
138 return value->ImageID() == key;
141 ImageHandler*& GetLink(ImageHandler* value) const
143 return value->fNext;
148 // #pragma mark - ImageInfoPendingThread
151 struct TeamDebugger::ImageInfoPendingThread {
152 public:
153 ImageInfoPendingThread(image_id image, thread_id thread)
155 fImage(image),
156 fThread(thread)
160 ~ImageInfoPendingThread()
164 image_id ImageID() const
166 return fImage;
169 thread_id ThreadID() const
171 return fThread;
174 private:
175 image_id fImage;
176 thread_id fThread;
178 public:
179 ImageInfoPendingThread* fNext;
183 // #pragma mark - ImageHandlerHashDefinition
186 struct TeamDebugger::ImageInfoPendingThreadHashDefinition {
187 typedef image_id KeyType;
188 typedef ImageInfoPendingThread ValueType;
190 size_t HashKey(image_id key) const
192 return (size_t)key;
195 size_t Hash(const ImageInfoPendingThread* value) const
197 return HashKey(value->ImageID());
200 bool Compare(image_id key, const ImageInfoPendingThread* value) const
202 return value->ImageID() == key;
205 ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const
207 return value->fNext;
212 // #pragma mark - TeamDebugger
215 TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
216 SettingsManager* settingsManager)
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)
241 fUserInterface->AcquireReference();
245 TeamDebugger::~TeamDebugger()
247 if (fTeam != NULL)
248 _SaveSettings();
250 AutoLocker<BLooper> locker(this);
252 fTerminating = true;
254 if (fDebuggerInterface != NULL) {
255 fDebuggerInterface->Close(fKillTeamOnQuit);
256 fDebuggerInterface->ReleaseReference();
259 if (fWorker != NULL)
260 fWorker->ShutDown();
262 locker.Unlock();
264 if (fDebugEventListener >= 0)
265 wait_for_thread(fDebugEventListener, NULL);
267 // terminate UI
268 if (fUserInterface != NULL) {
269 fUserInterface->Terminate();
270 fUserInterface->ReleaseReference();
273 ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
274 while (threadHandler != NULL) {
275 ThreadHandler* next = threadHandler->fNext;
276 threadHandler->ReleaseReference();
277 threadHandler = next;
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;
289 delete fImageHandlers;
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;
300 if (fReportGenerator != NULL) {
301 fReportGenerator->Lock();
302 fReportGenerator->Quit();
305 delete fWorker;
307 delete fImageInfoPendingThreads;
309 delete fBreakpointManager;
310 delete fWatchpointManager;
311 delete fMemoryBlockManager;
312 delete fTeam;
313 delete fFileManager;
315 for (int i = 0; i < fCommandLineArgc; i++) {
316 if (fCommandLineArgv[i] != NULL)
317 free(const_cast<char*>(fCommandLineArgv[i]));
320 delete [] fCommandLineArgv;
322 fListener->TeamDebuggerQuit(this);
326 status_t
327 TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
328 const char* const* argv, bool stopInMain)
330 bool targetIsLocal = true;
331 // TODO: Support non-local targets!
333 // the first thing we want to do when running
334 PostMessage(MSG_LOAD_SETTINGS);
336 status_t error = _HandleSetArguments(argc, argv);
337 if (error != B_OK)
338 return error;
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;
348 fDebuggerInterface = interface;
349 fDebuggerInterface->AcquireReference();
350 fTeamID = interface->TeamID();
351 fIsPostMortem = interface->IsPostMortem();
354 // create file manager
355 fFileManager = new(std::nothrow) FileManager;
356 if (fFileManager == NULL)
357 return B_NO_MEMORY;
359 error = fFileManager->Init(targetIsLocal);
360 if (error != B_OK)
361 return error;
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);
371 error = teamDebugInfo->Init();
372 if (error != B_OK)
373 return error;
375 // check whether the team exists at all
376 TeamInfo teamInfo;
377 error = fDebuggerInterface->GetTeamInfo(teamInfo);
378 if (error != B_OK)
379 return error;
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;
388 error = fTeam->Init();
389 if (error != B_OK)
390 return error;
391 fTeam->SetName(teamInfo.Arguments());
392 // TODO: Set a better name!
394 fTeam->AddListener(this);
396 // init thread handler table
397 error = fThreadHandlers.Init();
398 if (error != B_OK)
399 return error;
401 // create image handler table
402 fImageHandlers = new(std::nothrow) ImageHandlerTable;
403 if (fImageHandlers == NULL)
404 return B_NO_MEMORY;
406 error = fImageHandlers->Init();
407 if (error != B_OK)
408 return error;
410 fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable;
411 if (fImageInfoPendingThreads == NULL)
412 return B_NO_MEMORY;
414 // create our worker
415 fWorker = new(std::nothrow) Worker;
416 if (fWorker == NULL)
417 return B_NO_MEMORY;
419 error = fWorker->Init();
420 if (error != B_OK)
421 return error;
423 // create the breakpoint manager
424 fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
425 fDebuggerInterface);
426 if (fBreakpointManager == NULL)
427 return B_NO_MEMORY;
429 error = fBreakpointManager->Init();
430 if (error != B_OK)
431 return error;
433 // create the watchpoint manager
434 fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam,
435 fDebuggerInterface);
436 if (fWatchpointManager == NULL)
437 return B_NO_MEMORY;
439 error = fWatchpointManager->Init();
440 if (error != B_OK)
441 return error;
443 // create the memory block manager
444 fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
445 if (fMemoryBlockManager == NULL)
446 return B_NO_MEMORY;
448 error = fMemoryBlockManager->Init();
449 if (error != B_OK)
450 return error;
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;
458 error = fReportGenerator->Init();
459 if (error != B_OK)
460 return error;
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);
468 // get the initial state of the team
469 AutoLocker< ::Team> teamLocker(fTeam);
471 ThreadHandler* mainThreadHandler = NULL;
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;
481 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
482 fWorker, fDebuggerInterface, this, fBreakpointManager);
483 if (handler == NULL)
484 return B_NO_MEMORY;
486 fThreadHandlers.Insert(handler);
488 if (thread->IsMainThread())
489 mainThreadHandler = handler;
491 handler->Init();
495 Image* appImage = NULL;
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;
507 ImageDebugInfoRequested(image);
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;
521 resume_thread(fDebugEventListener);
524 // run looper
525 thread_id looperThread = Run();
526 if (looperThread < 0)
527 return looperThread;
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;
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());
546 } else {
547 debug_thread(threadID);
548 // TODO: Superfluous, if the thread is already stopped.
552 fListener->TeamDebuggerStarted(this);
554 return B_OK;
558 void
559 TeamDebugger::Activate()
561 fUserInterface->Show();
565 void
566 TeamDebugger::MessageReceived(BMessage* message)
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:
576 int32 threadID;
577 target_addr_t address;
578 if (message->FindInt32("thread", &threadID) != B_OK)
579 break;
581 if (message->FindUInt64("address", &address) != B_OK)
582 address = 0;
584 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
585 handler->HandleThreadAction(message->what, address);
586 handler->ReleaseReference();
588 break;
591 case MSG_SET_BREAKPOINT:
592 case MSG_CLEAR_BREAKPOINT:
594 UserBreakpoint* breakpoint = NULL;
595 BReference<UserBreakpoint> breakpointReference;
596 uint64 address = 0;
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;
604 if (message->what == MSG_SET_BREAKPOINT) {
605 bool enabled;
606 if (message->FindBool("enabled", &enabled) != B_OK)
607 enabled = true;
609 bool hidden;
610 if (message->FindBool("hidden", &hidden) != B_OK)
611 hidden = false;
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);
624 break;
627 case MSG_SET_BREAKPOINT_CONDITION:
629 UserBreakpoint* breakpoint = NULL;
630 BReference<UserBreakpoint> breakpointReference;
631 if (message->FindPointer("breakpoint", (void**)&breakpoint)
632 != B_OK) {
633 break;
636 breakpointReference.SetTo(breakpoint, true);
638 const char* condition;
639 if (message->FindString("condition", &condition) != B_OK)
640 break;
642 AutoLocker< ::Team> teamLocker(fTeam);
643 breakpoint->SetCondition(condition);
644 fTeam->NotifyUserBreakpointChanged(breakpoint);
646 break;
649 case MSG_CLEAR_BREAKPOINT_CONDITION:
651 UserBreakpoint* breakpoint = NULL;
652 BReference<UserBreakpoint> breakpointReference;
653 if (message->FindPointer("breakpoint", (void**)&breakpoint)
654 != B_OK)
655 break;
657 breakpointReference.SetTo(breakpoint, true);
659 AutoLocker< ::Team> teamLocker(fTeam);
660 breakpoint->SetCondition(NULL);
661 fTeam->NotifyUserBreakpointChanged(breakpoint);
663 break;
666 case MSG_STOP_ON_IMAGE_LOAD:
668 bool enabled;
669 bool useNames;
670 if (message->FindBool("enabled", &enabled) != B_OK)
671 break;
673 if (message->FindBool("useNames", &useNames) != B_OK)
674 break;
676 AutoLocker< ::Team> teamLocker(fTeam);
677 fTeam->SetStopOnImageLoad(enabled, useNames);
678 break;
681 case MSG_ADD_STOP_IMAGE_NAME:
683 BString imageName;
684 if (message->FindString("name", &imageName) != B_OK)
685 break;
687 AutoLocker< ::Team> teamLocker(fTeam);
688 fTeam->AddStopImageName(imageName);
689 break;
692 case MSG_REMOVE_STOP_IMAGE_NAME:
694 BString imageName;
695 if (message->FindString("name", &imageName) != B_OK)
696 break;
698 AutoLocker< ::Team> teamLocker(fTeam);
699 fTeam->RemoveStopImageName(imageName);
700 break;
703 case MSG_SET_DEFAULT_SIGNAL_DISPOSITION:
705 int32 disposition;
706 if (message->FindInt32("disposition", &disposition) != B_OK)
707 break;
709 AutoLocker< ::Team> teamLocker(fTeam);
710 fTeam->SetDefaultSignalDisposition(disposition);
711 break;
714 case MSG_SET_CUSTOM_SIGNAL_DISPOSITION:
716 int32 signal;
717 int32 disposition;
718 if (message->FindInt32("signal", &signal) != B_OK
719 || message->FindInt32("disposition", &disposition) != B_OK) {
720 break;
723 AutoLocker< ::Team> teamLocker(fTeam);
724 fTeam->SetCustomSignalDisposition(signal, disposition);
725 break;
728 case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION:
730 int32 signal;
731 if (message->FindInt32("signal", &signal) != B_OK)
732 break;
734 AutoLocker< ::Team> teamLocker(fTeam);
735 fTeam->RemoveCustomSignalDisposition(signal);
736 break;
739 case MSG_SET_WATCHPOINT:
740 case MSG_CLEAR_WATCHPOINT:
742 Watchpoint* watchpoint = NULL;
743 BReference<Watchpoint> watchpointReference;
744 uint64 address = 0;
745 uint32 type = 0;
746 int32 length = 0;
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;
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;
761 bool enabled;
762 if (message->FindBool("enabled", &enabled) != B_OK)
763 enabled = true;
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);
776 break;
779 case MSG_INSPECT_ADDRESS:
781 TeamMemoryBlock::Listener* listener;
782 if (message->FindPointer("listener",
783 reinterpret_cast<void **>(&listener)) != B_OK) {
784 break;
787 target_addr_t address;
788 if (message->FindUInt64("address",
789 &address) == B_OK) {
790 _HandleInspectAddress(address, listener);
792 break;
795 case MSG_WRITE_TARGET_MEMORY:
797 target_addr_t address;
798 if (message->FindUInt64("address", &address) != B_OK)
799 break;
801 void* data;
802 if (message->FindPointer("data", &data) != B_OK)
803 break;
805 target_size_t size;
806 if (message->FindUInt64("size", &size) != B_OK)
807 break;
809 _HandleWriteMemory(address, data, size);
810 break;
813 case MSG_EVALUATE_EXPRESSION:
815 SourceLanguage* language;
816 if (message->FindPointer("language",
817 reinterpret_cast<void**>(&language)) != B_OK) {
818 break;
821 // ExpressionEvaluationRequested() acquires a reference
822 // to both the language and the expression info on our behalf.
823 BReference<SourceLanguage> reference(language, true);
825 ExpressionInfo* info;
826 if (message->FindPointer("info",
827 reinterpret_cast<void**>(&info)) != B_OK) {
828 break;
831 BReference<ExpressionInfo> infoReference(info, true);
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;
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;
849 _HandleEvaluateExpression(language, info, frame, thread);
850 break;
853 case MSG_GENERATE_DEBUG_REPORT:
855 fReportGenerator->PostMessage(message);
856 break;
859 case MSG_WRITE_CORE_FILE:
861 entry_ref ref;
862 if (message->FindRef("target", &ref) != B_OK)
863 break;
865 _HandleWriteCoreFile(ref);
866 break;
869 case MSG_THREAD_STATE_CHANGED:
871 int32 threadID;
872 if (message->FindInt32("thread", &threadID) != B_OK)
873 break;
875 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
876 handler->HandleThreadStateChanged();
877 handler->ReleaseReference();
879 break;
881 case MSG_THREAD_CPU_STATE_CHANGED:
883 int32 threadID;
884 if (message->FindInt32("thread", &threadID) != B_OK)
885 break;
887 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
888 handler->HandleCpuStateChanged();
889 handler->ReleaseReference();
891 break;
893 case MSG_THREAD_STACK_TRACE_CHANGED:
895 int32 threadID;
896 if (message->FindInt32("thread", &threadID) != B_OK)
897 break;
899 if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
900 handler->HandleStackTraceChanged();
901 handler->ReleaseReference();
903 break;
906 case MSG_IMAGE_DEBUG_INFO_CHANGED:
908 int32 imageID;
909 if (message->FindInt32("image", &imageID) != B_OK)
910 break;
912 _HandleImageDebugInfoChanged(imageID);
913 break;
916 case MSG_IMAGE_FILE_CHANGED:
918 int32 imageID;
919 if (message->FindInt32("image", &imageID) != B_OK)
920 break;
922 _HandleImageFileChanged(imageID);
923 break;
926 case MSG_DEBUGGER_EVENT:
928 DebugEvent* event;
929 if (message->FindPointer("event", (void**)&event) != B_OK)
930 break;
932 _HandleDebuggerMessage(event);
933 delete event;
934 break;
937 case MSG_LOAD_SETTINGS:
938 _LoadSettings();
939 Activate();
940 break;
942 case MSG_TEAM_RESTART_REQUESTED:
944 if (fCommandLineArgc == 0)
945 break;
947 _SaveSettings();
948 fListener->TeamDebuggerRestartRequested(this);
949 break;
952 case MSG_DEBUG_INFO_NEEDS_USER_INPUT:
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;
961 _HandleDebugInfoJobUserInput(state);
962 fWorker->ResumeJob(job);
963 break;
966 default:
967 BLooper::MessageReceived(message);
968 break;
973 void
974 TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
975 const char* locatedPath)
977 AutoLocker<FileManager> locker(fFileManager);
978 fFileManager->SourceEntryLocated(sourcePath, locatedPath);
982 void
983 TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile)
985 AutoLocker< ::Team> locker(fTeam);
987 fTeam->DebugInfo()->ClearSourceCode(sourceFile);
991 void
992 TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
993 bool forceDisassembly)
995 Function* function = functionInstance->GetFunction();
997 // mark loading
998 AutoLocker< ::Team> locker(fTeam);
1000 if (forceDisassembly && functionInstance->SourceCodeState()
1001 != FUNCTION_SOURCE_NOT_LOADED) {
1002 return;
1003 } else if (!forceDisassembly && function->SourceCodeState()
1004 == FUNCTION_SOURCE_LOADED) {
1005 return;
1008 functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1010 bool loadForFunction = false;
1011 if (!forceDisassembly && (function->SourceCodeState()
1012 == FUNCTION_SOURCE_NOT_LOADED
1013 || function->SourceCodeState() == FUNCTION_SOURCE_SUPPRESSED)) {
1014 loadForFunction = true;
1015 function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
1018 locker.Unlock();
1020 // schedule the job
1021 if (fWorker->ScheduleJob(
1022 new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
1023 fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
1024 loadForFunction),
1025 this) != B_OK) {
1026 // scheduling failed -- mark unavailable
1027 locker.Lock();
1028 function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
1029 locker.Unlock();
1034 void
1035 TeamDebugger::ImageDebugInfoRequested(Image* image)
1037 LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
1041 void
1042 TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
1043 ValueNodeContainer* container, ValueNode* valueNode)
1045 AutoLocker<ValueNodeContainer> containerLocker(container);
1046 if (valueNode->Container() != container)
1047 return;
1049 // check whether a job is already in progress
1050 AutoLocker<Worker> workerLocker(fWorker);
1051 SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
1052 if (fWorker->GetJob(jobKey) != NULL)
1053 return;
1054 workerLocker.Unlock();
1056 // schedule the job
1057 status_t error = fWorker->ScheduleJob(
1058 new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
1059 fDebuggerInterface->GetArchitecture(), cpuState,
1060 fTeam->GetTeamTypeInformation(), container, valueNode), this);
1061 if (error != B_OK) {
1062 // scheduling failed -- set the value to invalid
1063 valueNode->SetLocationAndValue(NULL, NULL, error);
1067 void
1068 TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
1069 Value* newValue)
1071 // schedule the job
1072 status_t error = fWorker->ScheduleJob(
1073 new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface,
1074 fDebuggerInterface->GetArchitecture(), state,
1075 fTeam->GetTeamTypeInformation(), node, newValue), this);
1076 if (error != B_OK) {
1077 BString message;
1078 message.SetToFormat("Request to write new value for variable %s "
1079 "failed: %s.\n", node->Name().String(), strerror(error));
1080 fUserInterface->NotifyUser("Error", message.String(),
1081 USER_NOTIFICATION_ERROR);
1086 void
1087 TeamDebugger::ThreadActionRequested(thread_id threadID,
1088 uint32 action, target_addr_t address)
1090 BMessage message(action);
1091 message.AddInt32("thread", threadID);
1092 message.AddUInt64("address", address);
1093 PostMessage(&message);
1097 void
1098 TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled,
1099 bool hidden)
1101 BMessage message(MSG_SET_BREAKPOINT);
1102 message.AddUInt64("address", (uint64)address);
1103 message.AddBool("enabled", enabled);
1104 message.AddBool("hidden", hidden);
1105 PostMessage(&message);
1109 void
1110 TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
1111 bool enabled)
1113 BMessage message(MSG_SET_BREAKPOINT);
1114 BReference<UserBreakpoint> breakpointReference(breakpoint);
1115 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1116 && message.AddBool("enabled", enabled) == B_OK
1117 && PostMessage(&message) == B_OK) {
1118 breakpointReference.Detach();
1123 void
1124 TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
1125 const char* condition)
1127 BMessage message(MSG_SET_BREAKPOINT_CONDITION);
1128 BReference<UserBreakpoint> breakpointReference(breakpoint);
1129 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1130 && message.AddString("condition", condition) == B_OK
1131 && PostMessage(&message) == B_OK) {
1132 breakpointReference.Detach();
1137 void
1138 TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
1140 BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
1141 BReference<UserBreakpoint> breakpointReference(breakpoint);
1142 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1143 && PostMessage(&message) == B_OK) {
1144 breakpointReference.Detach();
1149 void
1150 TeamDebugger::ClearBreakpointRequested(target_addr_t address)
1152 BMessage message(MSG_CLEAR_BREAKPOINT);
1153 message.AddUInt64("address", (uint64)address);
1154 PostMessage(&message);
1158 void
1159 TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames)
1161 BMessage message(MSG_STOP_ON_IMAGE_LOAD);
1162 message.AddBool("enabled", enabled);
1163 message.AddBool("useNames", useImageNames);
1164 PostMessage(&message);
1168 void
1169 TeamDebugger::AddStopImageNameRequested(const char* name)
1171 BMessage message(MSG_ADD_STOP_IMAGE_NAME);
1172 message.AddString("name", name);
1173 PostMessage(&message);
1177 void
1178 TeamDebugger::RemoveStopImageNameRequested(const char* name)
1180 BMessage message(MSG_REMOVE_STOP_IMAGE_NAME);
1181 message.AddString("name", name);
1182 PostMessage(&message);
1186 void
1187 TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition)
1189 BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION);
1190 message.AddInt32("disposition", disposition);
1191 PostMessage(&message);
1195 void
1196 TeamDebugger::SetCustomSignalDispositionRequested(int32 signal,
1197 int32 disposition)
1199 BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION);
1200 message.AddInt32("signal", signal);
1201 message.AddInt32("disposition", disposition);
1202 PostMessage(&message);
1206 void
1207 TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal)
1209 BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION);
1210 message.AddInt32("signal", signal);
1211 PostMessage(&message);
1215 void
1216 TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
1218 BMessage message(MSG_CLEAR_BREAKPOINT);
1219 BReference<UserBreakpoint> breakpointReference(breakpoint);
1220 if (message.AddPointer("breakpoint", breakpoint) == B_OK
1221 && PostMessage(&message) == B_OK) {
1222 breakpointReference.Detach();
1227 void
1228 TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
1229 int32 length, bool enabled)
1231 BMessage message(MSG_SET_WATCHPOINT);
1232 message.AddUInt64("address", (uint64)address);
1233 message.AddUInt32("type", type);
1234 message.AddInt32("length", length);
1235 message.AddBool("enabled", enabled);
1236 PostMessage(&message);
1240 void
1241 TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
1242 bool enabled)
1244 BMessage message(MSG_SET_WATCHPOINT);
1245 BReference<Watchpoint> watchpointReference(watchpoint);
1246 if (message.AddPointer("watchpoint", watchpoint) == B_OK
1247 && message.AddBool("enabled", enabled) == B_OK
1248 && PostMessage(&message) == B_OK) {
1249 watchpointReference.Detach();
1254 void
1255 TeamDebugger::ClearWatchpointRequested(target_addr_t address)
1257 BMessage message(MSG_CLEAR_WATCHPOINT);
1258 message.AddUInt64("address", (uint64)address);
1259 PostMessage(&message);
1263 void
1264 TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
1266 BMessage message(MSG_CLEAR_WATCHPOINT);
1267 BReference<Watchpoint> watchpointReference(watchpoint);
1268 if (message.AddPointer("watchpoint", watchpoint) == B_OK
1269 && PostMessage(&message) == B_OK) {
1270 watchpointReference.Detach();
1275 void
1276 TeamDebugger::InspectRequested(target_addr_t address,
1277 TeamMemoryBlock::Listener *listener)
1279 BMessage message(MSG_INSPECT_ADDRESS);
1280 message.AddUInt64("address", address);
1281 message.AddPointer("listener", listener);
1282 PostMessage(&message);
1286 void
1287 TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data,
1288 target_size_t size)
1290 BMessage message(MSG_WRITE_TARGET_MEMORY);
1291 message.AddUInt64("address", address);
1292 message.AddPointer("data", data);
1293 message.AddUInt64("size", size);
1294 PostMessage(&message);
1298 void
1299 TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
1300 ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
1302 BMessage message(MSG_EVALUATE_EXPRESSION);
1303 message.AddPointer("language", language);
1304 message.AddPointer("info", info);
1305 if (frame != NULL)
1306 message.AddPointer("frame", frame);
1307 if (thread != NULL)
1308 message.AddPointer("thread", thread);
1310 BReference<SourceLanguage> languageReference(language);
1311 BReference<ExpressionInfo> infoReference(info);
1312 if (PostMessage(&message) == B_OK) {
1313 languageReference.Detach();
1314 infoReference.Detach();
1319 void
1320 TeamDebugger::DebugReportRequested(entry_ref* targetPath)
1322 BMessage message(MSG_GENERATE_DEBUG_REPORT);
1323 message.AddRef("target", targetPath);
1324 PostMessage(&message);
1328 void
1329 TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
1331 BMessage message(MSG_WRITE_CORE_FILE);
1332 message.AddRef("target", targetPath);
1333 PostMessage(&message);
1337 void
1338 TeamDebugger::TeamRestartRequested()
1340 PostMessage(MSG_TEAM_RESTART_REQUESTED);
1344 bool
1345 TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
1347 bool askUser = false;
1348 switch (quitOption) {
1349 case QUIT_OPTION_ASK_USER:
1350 askUser = true;
1351 break;
1353 case QUIT_OPTION_ASK_KILL_TEAM:
1354 fKillTeamOnQuit = true;
1355 break;
1357 case QUIT_OPTION_ASK_RESUME_TEAM:
1358 break;
1361 if (askUser) {
1362 AutoLocker< ::Team> locker(fTeam);
1363 BString name(fTeam->Name());
1364 locker.Unlock();
1366 BString message;
1367 message << "What shall be done about the debugged team '";
1368 message << name;
1369 message << "'?";
1371 name.Remove(0, name.FindLast('/') + 1);
1373 BString killLabel("Kill ");
1374 killLabel << name;
1376 BString resumeLabel("Resume ");
1377 resumeLabel << name;
1379 int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
1380 message, killLabel, "Cancel", resumeLabel);
1382 switch (choice) {
1383 case 0:
1384 fKillTeamOnQuit = true;
1385 break;
1386 case 1:
1387 case -1:
1388 return false;
1389 case 2:
1390 // Detach from the team and resume and stopped threads.
1391 break;
1395 PostMessage(B_QUIT_REQUESTED);
1397 return true;
1401 void
1402 TeamDebugger::JobStarted(Job* job)
1404 BString description(job->GetDescription());
1405 if (!description.IsEmpty()) {
1406 description.Append(B_UTF8_ELLIPSIS);
1407 fUserInterface->NotifyBackgroundWorkStatus(description.String());
1412 void
1413 TeamDebugger::JobDone(Job* job)
1415 TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
1416 _ResetUserBackgroundStatusIfNeeded();
1420 void
1421 TeamDebugger::JobWaitingForInput(Job* job)
1423 LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);
1425 if (infoJob == NULL)
1426 return;
1428 BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
1429 message.AddPointer("job", infoJob);
1430 message.AddPointer("state", infoJob->GetLoadingState());
1431 PostMessage(&message);
1435 void
1436 TeamDebugger::JobFailed(Job* job)
1438 TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
1439 // TODO: notify user
1440 _ResetUserBackgroundStatusIfNeeded();
1444 void
1445 TeamDebugger::JobAborted(Job* job)
1447 TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
1448 // TODO: For a stack frame source loader thread we should reset the
1449 // loading state! Asynchronously due to locking order.
1450 _ResetUserBackgroundStatusIfNeeded();
1454 void
1455 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
1457 BMessage message(MSG_THREAD_STATE_CHANGED);
1458 message.AddInt32("thread", event.GetThread()->ID());
1459 PostMessage(&message);
1463 void
1464 TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
1466 BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
1467 message.AddInt32("thread", event.GetThread()->ID());
1468 PostMessage(&message);
1472 void
1473 TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
1475 BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
1476 message.AddInt32("thread", event.GetThread()->ID());
1477 PostMessage(&message);
1481 void
1482 TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event)
1484 BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
1485 message.AddInt32("image", event.GetImage()->ID());
1486 PostMessage(&message);
1490 /*static*/ status_t
1491 TeamDebugger::_DebugEventListenerEntry(void* data)
1493 return ((TeamDebugger*)data)->_DebugEventListener();
1497 status_t
1498 TeamDebugger::_DebugEventListener()
1500 while (!fTerminating) {
1501 // get the next event
1502 DebugEvent* event;
1503 status_t error = fDebuggerInterface->GetNextDebugEvent(event);
1504 if (error != B_OK)
1505 break;
1506 // TODO: Error handling!
1508 if (event->Team() != fTeamID) {
1509 TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
1510 "from team %" B_PRId32 "!\n", fTeamID, event->Team());
1511 continue;
1514 BMessage message(MSG_DEBUGGER_EVENT);
1515 if (message.AddPointer("event", event) != B_OK
1516 || PostMessage(&message) != B_OK) {
1517 // TODO: Continue thread if necessary!
1518 delete event;
1522 return B_OK;
1526 void
1527 TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
1529 TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
1530 event->EventType());
1532 bool handled = false;
1534 ThreadHandler* handler = _GetThreadHandler(event->Thread());
1535 BReference<ThreadHandler> handlerReference(handler, true);
1537 switch (event->EventType()) {
1538 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
1539 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
1540 B_PRId32 "\n", event->Thread());
1542 if (handler != NULL) {
1543 handled = handler->HandleThreadDebugged(
1544 dynamic_cast<ThreadDebuggedEvent*>(event));
1546 break;
1547 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
1548 TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
1549 "\n", event->Thread());
1551 if (handler != NULL) {
1552 handled = handler->HandleDebuggerCall(
1553 dynamic_cast<DebuggerCallEvent*>(event));
1555 break;
1556 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
1557 TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
1558 "\n", event->Thread());
1560 if (handler != NULL) {
1561 handled = handler->HandleBreakpointHit(
1562 dynamic_cast<BreakpointHitEvent*>(event));
1564 break;
1565 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
1566 TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
1567 "\n", event->Thread());
1569 if (handler != NULL) {
1570 handled = handler->HandleWatchpointHit(
1571 dynamic_cast<WatchpointHitEvent*>(event));
1573 break;
1574 case B_DEBUGGER_MESSAGE_SINGLE_STEP:
1575 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
1576 "\n", event->Thread());
1578 if (handler != NULL) {
1579 handled = handler->HandleSingleStep(
1580 dynamic_cast<SingleStepEvent*>(event));
1582 break;
1583 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
1584 TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
1585 B_PRId32 "\n", event->Thread());
1587 if (handler != NULL) {
1588 handled = handler->HandleExceptionOccurred(
1589 dynamic_cast<ExceptionOccurredEvent*>(event));
1591 break;
1592 // case B_DEBUGGER_MESSAGE_TEAM_CREATED:
1593 //printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
1594 // break;
1595 case B_DEBUGGER_MESSAGE_TEAM_DELETED:
1597 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
1598 "\n", event->Team());
1599 TeamDeletedEvent* teamEvent
1600 = dynamic_cast<TeamDeletedEvent*>(event);
1601 handled = _HandleTeamDeleted(teamEvent);
1602 break;
1604 case B_DEBUGGER_MESSAGE_TEAM_EXEC:
1606 TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
1607 event->Team());
1609 TeamExecEvent* teamEvent
1610 = dynamic_cast<TeamExecEvent*>(event);
1611 _PrepareForTeamExec(teamEvent);
1612 break;
1614 case B_DEBUGGER_MESSAGE_THREAD_CREATED:
1616 ThreadCreatedEvent* threadEvent
1617 = dynamic_cast<ThreadCreatedEvent*>(event);
1618 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
1619 "\n", threadEvent->NewThread());
1620 handled = _HandleThreadCreated(threadEvent);
1621 break;
1623 case DEBUGGER_MESSAGE_THREAD_RENAMED:
1625 ThreadRenamedEvent* threadEvent
1626 = dynamic_cast<ThreadRenamedEvent*>(event);
1627 TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
1628 " (\"%s\")\n",
1629 threadEvent->RenamedThread(), threadEvent->NewName());
1630 handled = _HandleThreadRenamed(threadEvent);
1631 break;
1633 case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
1635 ThreadPriorityChangedEvent* threadEvent
1636 = dynamic_cast<ThreadPriorityChangedEvent*>(event);
1637 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
1638 " %" B_PRId32 "\n", threadEvent->ChangedThread());
1639 handled = _HandleThreadPriorityChanged(threadEvent);
1640 break;
1642 case B_DEBUGGER_MESSAGE_THREAD_DELETED:
1643 TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
1644 "\n", event->Thread());
1645 handled = _HandleThreadDeleted(
1646 dynamic_cast<ThreadDeletedEvent*>(event));
1647 break;
1648 case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
1650 ImageCreatedEvent* imageEvent
1651 = dynamic_cast<ImageCreatedEvent*>(event);
1652 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
1653 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1654 imageEvent->GetImageInfo().ImageID());
1655 handled = _HandleImageCreated(imageEvent);
1656 break;
1658 case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
1660 ImageDeletedEvent* imageEvent
1661 = dynamic_cast<ImageDeletedEvent*>(event);
1662 TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
1663 "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
1664 imageEvent->GetImageInfo().ImageID());
1665 handled = _HandleImageDeleted(imageEvent);
1666 break;
1668 case B_DEBUGGER_MESSAGE_POST_SYSCALL:
1670 PostSyscallEvent* postSyscallEvent
1671 = dynamic_cast<PostSyscallEvent*>(event);
1672 TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %"
1673 B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall());
1674 handled = _HandlePostSyscall(postSyscallEvent);
1676 // if a thread was blocked in a syscall when we requested to
1677 // stop it for debugging, then that request will interrupt
1678 // said call, and the post syscall event will be all we get
1679 // in response. Consequently, we need to treat this case as
1680 // equivalent to having received a thread debugged event.
1681 AutoLocker< ::Team> teamLocker(fTeam);
1682 ::Thread* thread = fTeam->ThreadByID(event->Thread());
1683 if (handler != NULL && thread != NULL
1684 && thread->StopRequestPending()) {
1685 handled = handler->HandleThreadDebugged(NULL);
1687 break;
1689 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
1691 TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %"
1692 B_PRId32 "\n", event->Thread());
1694 if (handler != NULL) {
1695 handled = handler->HandleSignalReceived(
1696 dynamic_cast<SignalReceivedEvent*>(event));
1698 break;
1700 case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
1701 case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
1702 case B_DEBUGGER_MESSAGE_HANDED_OVER:
1703 // not interested
1704 break;
1705 default:
1706 WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
1707 "%" B_PRId32 "\n", fTeamID, event->EventType());
1708 break;
1711 if (!handled && event->ThreadStopped())
1712 fDebuggerInterface->ContinueThread(event->Thread());
1716 bool
1717 TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event)
1719 char message[64];
1720 fDebuggerInterface->Close(false);
1722 snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ",
1723 event->Team());
1725 int32 result = fUserInterface->SynchronouslyAskUser("Team terminated",
1726 message, "Do nothing", "Quit", fCommandLineArgc != 0
1727 ? "Restart team" : NULL);
1729 switch (result) {
1730 case 1:
1731 case -1:
1733 PostMessage(B_QUIT_REQUESTED);
1734 break;
1736 case 2:
1738 _SaveSettings();
1739 fListener->TeamDebuggerRestartRequested(this);
1740 break;
1742 default:
1743 break;
1746 return true;
1750 bool
1751 TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
1753 AutoLocker< ::Team> locker(fTeam);
1755 ThreadInfo info;
1756 status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
1757 info);
1758 if (error == B_OK) {
1759 ::Thread* thread;
1760 fTeam->AddThread(info, &thread);
1762 ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
1763 fWorker, fDebuggerInterface, this, fBreakpointManager);
1764 if (handler != NULL) {
1765 fThreadHandlers.Insert(handler);
1766 handler->Init();
1770 return false;
1774 bool
1775 TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
1777 AutoLocker< ::Team> locker(fTeam);
1779 ::Thread* thread = fTeam->ThreadByID(event->RenamedThread());
1781 if (thread != NULL)
1782 thread->SetName(event->NewName());
1784 return false;
1788 bool
1789 TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
1791 // TODO: implement once we actually track thread priorities
1793 return false;
1797 bool
1798 TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
1800 AutoLocker< ::Team> locker(fTeam);
1801 if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
1802 fThreadHandlers.Remove(handler);
1803 handler->ReleaseReference();
1805 fTeam->RemoveThread(event->Thread());
1806 return false;
1810 bool
1811 TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
1813 AutoLocker< ::Team> locker(fTeam);
1814 _AddImage(event->GetImageInfo());
1816 ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
1817 event->GetImageInfo().ImageID(), event->Thread());
1818 if (info == NULL)
1819 return false;
1821 fImageInfoPendingThreads->Insert(info);
1822 return true;
1826 bool
1827 TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
1829 AutoLocker< ::Team> locker(fTeam);
1830 fTeam->RemoveImage(event->GetImageInfo().ImageID());
1832 ImageHandler* imageHandler = fImageHandlers->Lookup(
1833 event->GetImageInfo().ImageID());
1834 if (imageHandler == NULL)
1835 return false;
1837 fImageHandlers->Remove(imageHandler);
1838 BReference<ImageHandler> imageHandlerReference(imageHandler, true);
1839 locker.Unlock();
1841 // remove breakpoints in the image
1842 fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());
1844 return false;
1848 bool
1849 TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event)
1851 const SyscallInfo& info = event->GetSyscallInfo();
1853 switch (info.Syscall()) {
1854 case SYSCALL_WRITE:
1856 if ((ssize_t)info.ReturnValue() <= 0)
1857 break;
1859 int32 fd;
1860 target_addr_t address;
1861 size_t size;
1862 // TODO: decoding the syscall arguments should probably be
1863 // factored out into an Architecture method of its own, since
1864 // there's no guarantee the target architecture has the same
1865 // endianness as the host. This could re-use the syscall
1866 // argument parser that strace uses, though that would need to
1867 // be adapted to handle the aforementioned endian differences.
1868 // This works for x86{-64} for now though.
1869 if (fTeam->GetArchitecture()->AddressSize() == 4) {
1870 const uint32* args = (const uint32*)info.Arguments();
1871 fd = args[0];
1872 address = args[3];
1873 size = args[4];
1874 } else {
1875 const uint64* args = (const uint64*)info.Arguments();
1876 fd = args[0];
1877 address = args[2];
1878 size = args[3];
1881 if (fd == 1 || fd == 2) {
1882 BString data;
1884 ssize_t result = fDebuggerInterface->ReadMemoryString(
1885 address, size, data);
1886 if (result >= 0)
1887 fTeam->NotifyConsoleOutputReceived(fd, data);
1889 break;
1891 case SYSCALL_WRITEV:
1893 // TODO: handle
1895 default:
1896 break;
1899 return false;
1903 void
1904 TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event)
1906 // NB: must be called with team lock held.
1908 _SaveSettings();
1910 // when notified of exec, we need to clear out data related
1911 // to the old team.
1912 const ImageList& images = fTeam->Images();
1914 for (ImageList::ConstIterator it = images.GetIterator();
1915 Image* image = it.Next();) {
1916 fBreakpointManager->RemoveImageBreakpoints(image);
1919 BObjectList<UserBreakpoint> breakpointsToRemove(20, false);
1920 const UserBreakpointList& breakpoints = fTeam->UserBreakpoints();
1921 for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator();
1922 UserBreakpoint* breakpoint = it.Next();) {
1923 breakpointsToRemove.AddItem(breakpoint);
1924 breakpoint->AcquireReference();
1927 for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) {
1928 UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i);
1929 fTeam->RemoveUserBreakpoint(breakpoint);
1930 fTeam->NotifyUserBreakpointChanged(breakpoint);
1931 breakpoint->ReleaseReference();
1934 fTeam->ClearImages();
1935 fTeam->ClearSignalDispositionMappings();
1936 fExecPending = true;
1940 void
1941 TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID)
1943 // get the image (via the image handler)
1944 AutoLocker< ::Team> locker(fTeam);
1945 ImageHandler* imageHandler = fImageHandlers->Lookup(imageID);
1946 if (imageHandler == NULL)
1947 return;
1949 Image* image = imageHandler->GetImage();
1950 BReference<Image> imageReference(image);
1951 image_debug_info_state state = image->ImageDebugInfoState();
1953 bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE
1954 && state != IMAGE_DEBUG_INFO_LOADING;
1955 // this needs to be done first so that breakpoints are loaded.
1956 // otherwise, UpdateImageBreakpoints() won't find the appropriate
1957 // UserBreakpoints to create/install instances for.
1958 if (handlePostExecSetup) {
1959 fTeam->SetName(image->Name());
1960 _LoadSettings();
1961 fExecPending = false;
1964 locker.Unlock();
1966 if (state == IMAGE_DEBUG_INFO_LOADED
1967 || state == IMAGE_DEBUG_INFO_UNAVAILABLE) {
1969 // update breakpoints in the image
1970 fBreakpointManager->UpdateImageBreakpoints(image);
1972 ImageInfoPendingThread* thread = fImageInfoPendingThreads
1973 ->Lookup(imageID);
1974 if (thread != NULL) {
1975 fImageInfoPendingThreads->Remove(thread);
1976 ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread);
1977 locker.Lock();
1978 ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
1979 BReference<ThreadHandler> handlerReference(handler, true);
1980 if (fTeam->StopOnImageLoad()) {
1982 bool stop = true;
1983 const BString& imageName = image->Name();
1984 // only match on the image filename itself
1985 const char* rawImageName = imageName.String()
1986 + imageName.FindLast('/') + 1;
1987 if (fTeam->StopImageNameListEnabled()) {
1988 const BStringList& nameList = fTeam->StopImageNames();
1989 stop = nameList.HasString(rawImageName);
1992 if (stop && handler != NULL) {
1993 BString stopReason;
1994 stopReason.SetToFormat("Image '%s' loaded.",
1995 rawImageName);
1996 locker.Unlock();
1998 if (handler->HandleThreadDebugged(NULL, stopReason))
1999 return;
2000 } else
2001 locker.Unlock();
2002 } else if (handlePostExecSetup) {
2003 // in the case of an exec(), we can't stop in main() until
2004 // the new app image has been loaded, so we know where to
2005 // set the main breakpoint at.
2006 SymbolInfo symbolInfo;
2007 if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(),
2008 "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) {
2009 handler->SetBreakpointAndRun(symbolInfo.Address());
2011 } else {
2012 locker.Unlock();
2013 fDebuggerInterface->ContinueThread(thread->ThreadID());
2020 void
2021 TeamDebugger::_HandleImageFileChanged(image_id imageID)
2023 TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
2024 imageID);
2025 // TODO: Reload the debug info!
2029 void
2030 TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled,
2031 bool hidden)
2033 TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
2034 ", %d, %d)\n", address, enabled, hidden);
2036 // check whether there already is a breakpoint
2037 AutoLocker< ::Team> locker(fTeam);
2039 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2040 UserBreakpoint* userBreakpoint = NULL;
2041 if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
2042 userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2043 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2045 if (userBreakpoint == NULL) {
2046 TRACE_CONTROL(" no breakpoint yet\n");
2048 // get the function at the address
2049 Image* image = fTeam->ImageByAddress(address);
2051 TRACE_CONTROL(" image: %p\n", image);
2053 if (image == NULL)
2054 return;
2055 ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
2057 TRACE_CONTROL(" image debug info: %p\n", imageDebugInfo);
2059 if (imageDebugInfo == NULL)
2060 return;
2061 // TODO: Handle this case by loading the debug info, if possible!
2062 FunctionInstance* functionInstance
2063 = imageDebugInfo->FunctionAtAddress(address);
2065 TRACE_CONTROL(" function instance: %p\n", functionInstance);
2067 if (functionInstance == NULL)
2068 return;
2069 Function* function = functionInstance->GetFunction();
2071 TRACE_CONTROL(" function: %p\n", function);
2073 // get the source location for the address
2074 FunctionDebugInfo* functionDebugInfo
2075 = functionInstance->GetFunctionDebugInfo();
2076 SourceLocation sourceLocation;
2077 Statement* breakpointStatement = NULL;
2078 if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
2079 functionDebugInfo, address, breakpointStatement) != B_OK) {
2080 return;
2083 sourceLocation = breakpointStatement->StartSourceLocation();
2084 breakpointStatement->ReleaseReference();
2086 target_addr_t relativeAddress = address - functionInstance->Address();
2088 TRACE_CONTROL(" relative address: %#" B_PRIx64 ", source location: "
2089 "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
2090 sourceLocation.Line(), sourceLocation.Column());
2092 // get function id
2093 FunctionID* functionID = functionInstance->GetFunctionID();
2094 if (functionID == NULL)
2095 return;
2096 BReference<FunctionID> functionIDReference(functionID, true);
2098 // create the user breakpoint
2099 userBreakpoint = new(std::nothrow) UserBreakpoint(
2100 UserBreakpointLocation(functionID, function->SourceFile(),
2101 sourceLocation, relativeAddress));
2102 if (userBreakpoint == NULL)
2103 return;
2104 userBreakpointReference.SetTo(userBreakpoint, true);
2106 userBreakpoint->SetHidden(hidden);
2108 TRACE_CONTROL(" created user breakpoint: %p\n", userBreakpoint);
2110 // iterate through all function instances and create
2111 // UserBreakpointInstances
2112 for (FunctionInstanceList::ConstIterator it
2113 = function->Instances().GetIterator();
2114 FunctionInstance* instance = it.Next();) {
2115 TRACE_CONTROL(" function instance %p: range: %#" B_PRIx64 " - %#"
2116 B_PRIx64 "\n", instance, instance->Address(),
2117 instance->Address() + instance->Size());
2119 // get the breakpoint address for the instance
2120 target_addr_t instanceAddress = 0;
2121 if (instance == functionInstance) {
2122 instanceAddress = address;
2123 } else if (functionInstance->SourceFile() != NULL) {
2124 // We have a source file, so get the address for the source
2125 // location.
2126 Statement* statement = NULL;
2127 functionDebugInfo = instance->GetFunctionDebugInfo();
2128 functionDebugInfo->GetSpecificImageDebugInfo()
2129 ->GetStatementAtSourceLocation(functionDebugInfo,
2130 sourceLocation, statement);
2131 if (statement != NULL) {
2132 instanceAddress = statement->CoveringAddressRange().Start();
2133 // TODO: What about BreakpointAllowed()?
2134 statement->ReleaseReference();
2138 TRACE_CONTROL(" breakpoint address using source info: %" B_PRIx64
2139 "\n", instanceAddress);
2141 if (instanceAddress == 0) {
2142 // No source file (or we failed getting the statement), so try
2143 // to use the same relative address.
2144 if (relativeAddress > instance->Size())
2145 continue;
2146 instanceAddress = instance->Address() + relativeAddress;
2149 TRACE_CONTROL(" final breakpoint address: %" B_PRIx64 "\n",
2150 instanceAddress);
2152 UserBreakpointInstance* breakpointInstance = new(std::nothrow)
2153 UserBreakpointInstance(userBreakpoint, instanceAddress);
2154 if (breakpointInstance == NULL
2155 || !userBreakpoint->AddInstance(breakpointInstance)) {
2156 delete breakpointInstance;
2157 return;
2160 TRACE_CONTROL(" breakpoint instance: %p\n", breakpointInstance);
2164 locker.Unlock();
2166 _HandleSetUserBreakpoint(userBreakpoint, enabled);
2170 void
2171 TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
2173 status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
2174 enabled);
2175 if (error != B_OK) {
2176 _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
2177 strerror(error));
2182 void
2183 TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
2185 TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
2186 address);
2188 AutoLocker< ::Team> locker(fTeam);
2190 Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
2191 if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
2192 return;
2193 UserBreakpoint* userBreakpoint
2194 = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
2195 BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);
2197 locker.Unlock();
2199 _HandleClearUserBreakpoint(userBreakpoint);
2203 void
2204 TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
2206 fBreakpointManager->UninstallUserBreakpoint(breakpoint);
2210 void
2211 TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
2212 int32 length, bool enabled)
2214 Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
2215 length);
2217 if (watchpoint == NULL)
2218 return;
2219 BReference<Watchpoint> watchpointRef(watchpoint, true);
2221 _HandleSetWatchpoint(watchpoint, enabled);
2225 void
2226 TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
2228 status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
2229 enabled);
2230 if (error != B_OK) {
2231 _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
2232 strerror(error));
2237 void
2238 TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
2240 TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
2241 address);
2243 AutoLocker< ::Team> locker(fTeam);
2245 Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
2246 if (watchpoint == NULL)
2247 return;
2248 BReference<Watchpoint> watchpointReference(watchpoint);
2250 locker.Unlock();
2252 _HandleClearWatchpoint(watchpoint);
2256 void
2257 TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
2259 fWatchpointManager->UninstallWatchpoint(watchpoint);
2263 void
2264 TeamDebugger::_HandleInspectAddress(target_addr_t address,
2265 TeamMemoryBlock::Listener* listener)
2267 TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
2268 address, listener);
2270 TeamMemoryBlock* memoryBlock = fMemoryBlockManager
2271 ->GetMemoryBlock(address);
2273 if (memoryBlock == NULL) {
2274 _NotifyUser("Inspect Address", "Failed to allocate memory block");
2275 return;
2278 if (!memoryBlock->IsValid()) {
2279 AutoLocker< ::Team> teamLocker(fTeam);
2281 if (!memoryBlock->HasListener(listener))
2282 memoryBlock->AddListener(listener);
2284 TeamMemory* memory = fTeam->GetTeamMemory();
2285 // schedule the job
2286 status_t result;
2287 if ((result = fWorker->ScheduleJob(
2288 new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
2289 memoryBlock),
2290 this)) != B_OK) {
2292 memoryBlock->NotifyDataRetrieved(result);
2293 memoryBlock->ReleaseReference();
2295 _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
2296 strerror(result));
2298 } else
2299 memoryBlock->NotifyDataRetrieved();
2304 void
2305 TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data,
2306 target_size_t size)
2308 TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, "
2309 "%" B_PRIu64 ")\n", address, data, size);
2311 AutoLocker< ::Team> teamLocker(fTeam);
2312 TeamMemory* memory = fTeam->GetTeamMemory();
2313 // schedule the job
2314 status_t result;
2315 if ((result = fWorker->ScheduleJob(
2316 new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size),
2317 this)) != B_OK) {
2318 _NotifyUser("Write Memory", "Failed to write memory data: %s",
2319 strerror(result));
2324 void
2325 TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
2326 ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
2328 status_t result = fWorker->ScheduleJob(
2329 new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
2330 language, info, frame, thread));
2331 if (result != B_OK) {
2332 _NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
2333 strerror(result));
2338 void
2339 TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
2341 status_t result = fWorker->ScheduleJob(
2342 new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
2343 targetPath));
2344 if (result != B_OK) {
2345 _NotifyUser("Write Core File", "Failed to write core file: %s",
2346 strerror(result));
2351 status_t
2352 TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
2354 fCommandLineArgc = argc;
2355 fCommandLineArgv = new(std::nothrow) const char*[argc];
2356 if (fCommandLineArgv == NULL)
2357 return B_NO_MEMORY;
2359 memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc);
2361 for (int i = 0; i < argc; i++) {
2362 fCommandLineArgv[i] = strdup(argv[i]);
2363 if (fCommandLineArgv[i] == NULL)
2364 return B_NO_MEMORY;
2367 return B_OK;
2371 void
2372 TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
2374 SpecificImageDebugInfoLoadingState* specificState
2375 = state->GetSpecificDebugInfoLoadingState();
2377 ImageDebugLoadingStateHandler* handler;
2378 if (ImageDebugLoadingStateHandlerRoster::Default()
2379 ->FindStateHandler(specificState, handler) != B_OK) {
2380 TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
2381 "Failed to find appropriate information handler, aborting.");
2382 return;
2385 handler->HandleState(specificState, fUserInterface);
2389 ThreadHandler*
2390 TeamDebugger::_GetThreadHandler(thread_id threadID)
2392 AutoLocker< ::Team> locker(fTeam);
2394 ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
2395 if (handler != NULL)
2396 handler->AcquireReference();
2397 return handler;
2401 status_t
2402 TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
2404 LocatableFile* file = NULL;
2405 if (strchr(imageInfo.Name(), '/') != NULL)
2406 file = fFileManager->GetTargetFile(imageInfo.Name());
2407 BReference<LocatableFile> imageFileReference(file, true);
2409 Image* image;
2410 status_t error = fTeam->AddImage(imageInfo, file, &image);
2411 if (error != B_OK)
2412 return error;
2414 ImageDebugInfoRequested(image);
2416 ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
2417 if (imageHandler != NULL)
2418 fImageHandlers->Insert(imageHandler);
2420 if (_image != NULL)
2421 *_image = image;
2423 return B_OK;
2427 void
2428 TeamDebugger::_LoadSettings()
2430 // get the team name
2431 AutoLocker< ::Team> locker(fTeam);
2432 BString teamName = fTeam->Name();
2433 locker.Unlock();
2435 // load the settings
2436 if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
2437 return;
2439 // create the saved breakpoints
2440 for (int32 i = 0; const BreakpointSetting* breakpointSetting
2441 = fTeamSettings.BreakpointAt(i); i++) {
2442 if (breakpointSetting->GetFunctionID() == NULL)
2443 continue;
2445 // get the source file, if any
2446 LocatableFile* sourceFile = NULL;
2447 if (breakpointSetting->SourceFile().Length() > 0) {
2448 sourceFile = fFileManager->GetSourceFile(
2449 breakpointSetting->SourceFile());
2450 if (sourceFile == NULL)
2451 continue;
2453 BReference<LocatableFile> sourceFileReference(sourceFile, true);
2455 // create the breakpoint
2456 UserBreakpointLocation location(breakpointSetting->GetFunctionID(),
2457 sourceFile, breakpointSetting->GetSourceLocation(),
2458 breakpointSetting->RelativeAddress());
2460 UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location);
2461 if (breakpoint == NULL)
2462 return;
2463 BReference<UserBreakpoint> breakpointReference(breakpoint, true);
2465 breakpoint->SetHidden(breakpointSetting->IsHidden());
2466 breakpoint->SetCondition(breakpointSetting->Condition());
2468 // install it
2469 fBreakpointManager->InstallUserBreakpoint(breakpoint,
2470 breakpointSetting->IsEnabled());
2473 fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings());
2475 const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
2476 fUserInterface->ID());
2477 if (uiSettings != NULL)
2478 fUserInterface->LoadSettings(uiSettings);
2480 const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings();
2481 if (signalSettings != NULL) {
2482 fTeam->SetDefaultSignalDisposition(
2483 signalSettings->DefaultSignalDisposition());
2485 int32 signal;
2486 int32 disposition;
2487 for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions();
2488 i++) {
2489 if (signalSettings->GetCustomSignalDispositionAt(i, signal,
2490 disposition) == B_OK) {
2491 fTeam->SetCustomSignalDisposition(signal, disposition);
2498 void
2499 TeamDebugger::_SaveSettings()
2501 // get the settings
2502 AutoLocker< ::Team> locker(fTeam);
2503 TeamSettings settings;
2504 if (settings.SetTo(fTeam) != B_OK)
2505 return;
2507 TeamUiSettings* uiSettings = NULL;
2508 if (fUserInterface->SaveSettings(uiSettings) != B_OK)
2509 return;
2510 if (uiSettings != NULL)
2511 settings.AddUiSettings(uiSettings);
2513 // preserve the UI settings from our cached copy.
2514 for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
2515 const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
2516 if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
2517 TeamUiSettings* clonedSettings = oldUiSettings->Clone();
2518 if (clonedSettings != NULL)
2519 settings.AddUiSettings(clonedSettings);
2523 fFileManager->SaveLocationMappings(settings.FileManagerSettings());
2524 locker.Unlock();
2526 // save the settings
2527 fSettingsManager->SaveTeamSettings(settings);
2531 void
2532 TeamDebugger::_NotifyUser(const char* title, const char* text,...)
2534 // print the message
2535 char buffer[1024];
2536 va_list args;
2537 va_start(args, text);
2538 vsnprintf(buffer, sizeof(buffer), text, args);
2539 va_end(args);
2541 // notify the user
2542 fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
2546 void
2547 TeamDebugger::_ResetUserBackgroundStatusIfNeeded()
2549 if (!fWorker->HasPendingJobs())
2550 fUserInterface->NotifyBackgroundWorkStatus("Ready.");
2554 // #pragma mark - Listener
2557 TeamDebugger::Listener::~Listener()