From 9123fde7b9ce627fb4ea6a824fd3151d02b51298 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Sat, 25 Jul 2015 17:18:21 -0400 Subject: [PATCH] Debugger: Implement #9783. TeamDebugger: - When we're notified that the target team has called exec(), take all necessary steps to prepare. These include saving settings for the old team, clearing out breakpoints, resetting signal dispositions, and removing the old team's image list. Also set a flag indicating an exec is pending for later processing. - On image load notification, if the pending flag is set, check if the new image is the app image, and if so update the team's name to the new image, load that respective team's settings, and set a temporary breakpoint in its main() so the user has a chance to perform any additional desired actions before starting execution in the new executable. --- .../debugger/controllers/TeamDebugger.cpp | 83 +++++++++++++++++-- src/apps/debugger/controllers/TeamDebugger.h | 3 + 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index e9d92bbe81..5bea9ee558 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -231,7 +231,8 @@ TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface, fTerminating(false), fKillTeamOnQuit(false), fCommandLineArgc(0), - fCommandLineArgv(NULL) + fCommandLineArgv(NULL), + fExecPending(false) { fUserInterface->AcquireReference(); } @@ -454,7 +455,8 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, int argc, // set team debugging flags fDebuggerInterface->SetTeamDebuggingFlags( B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES - | B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS); + | B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS + | B_TEAM_DEBUG_TEAM_CREATION); // get the initial state of the team AutoLocker< ::Team> teamLocker(fTeam); @@ -1556,10 +1558,15 @@ TeamDebugger::_HandleDebuggerMessage(DebugEvent* event) break; } case B_DEBUGGER_MESSAGE_TEAM_EXEC: + { TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n", event->Team()); - // TODO: Handle! + + TeamExecEvent* teamEvent + = dynamic_cast(event); + _PrepareForTeamExec(teamEvent); break; + } case B_DEBUGGER_MESSAGE_THREAD_CREATED: { ThreadCreatedEvent* threadEvent @@ -1849,6 +1856,43 @@ TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event) } +void +TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event) +{ + // NB: must be called with team lock held. + + _SaveSettings(); + + // when notified of exec, we need to clear out data related + // to the old team. + const ImageList& images = fTeam->Images(); + + for (ImageList::ConstIterator it = images.GetIterator(); + Image* image = it.Next();) { + fBreakpointManager->RemoveImageBreakpoints(image); + } + + BObjectList breakpointsToRemove(20, false); + const UserBreakpointList& breakpoints = fTeam->UserBreakpoints(); + for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator(); + UserBreakpoint* breakpoint = it.Next();) { + breakpointsToRemove.AddItem(breakpoint); + breakpoint->AcquireReference(); + } + + for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) { + UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i); + fTeam->RemoveUserBreakpoint(breakpoint); + fTeam->NotifyUserBreakpointChanged(breakpoint); + breakpoint->ReleaseReference(); + } + + fTeam->ClearImages(); + fTeam->ClearSignalDispositionMappings(); + fExecPending = true; +} + + void TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) { @@ -1860,10 +1904,22 @@ TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) Image* image = imageHandler->GetImage(); BReference imageReference(image); + image_debug_info_state state = image->ImageDebugInfoState(); + + bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE + && state != IMAGE_DEBUG_INFO_LOADING; + + // this needs to be done first so that breakpoints are loaded. + // otherwise, UpdateImageBreakpoints() won't find the appropriate + // UserBreakpoints to create/install instances for. + if (handlePostExecSetup) { + fTeam->SetName(image->Name()); + _LoadSettings(); + fExecPending = false; + } locker.Unlock(); - image_debug_info_state state = image->ImageDebugInfoState(); if (state == IMAGE_DEBUG_INFO_LOADED || state == IMAGE_DEBUG_INFO_UNAVAILABLE) { // update breakpoints in the image @@ -1875,9 +1931,9 @@ TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) fImageInfoPendingThreads->Remove(thread); ObjectDeleter threadDeleter(thread); locker.Lock(); + ThreadHandler* handler = _GetThreadHandler(thread->ThreadID()); + BReference handlerReference(handler); if (fTeam->StopOnImageLoad()) { - ThreadHandler* handler = _GetThreadHandler(thread->ThreadID()); - BReference handlerReference(handler); bool stop = true; const BString& imageName = image->Name(); @@ -1899,10 +1955,19 @@ TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) return; } else locker.Unlock(); - } else + } else if (handlePostExecSetup) { + // in the case of an exec(), we can't stop in main() until + // the new app image has been loaded, so we know where to + // set the main breakpoint at. + SymbolInfo symbolInfo; + if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(), + "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) { + handler->SetBreakpointAndRun(symbolInfo.Address(), false); + } + } else { locker.Unlock(); - - fDebuggerInterface->ContinueThread(thread->ThreadID()); + fDebuggerInterface->ContinueThread(thread->ThreadID()); + } } } } diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index 371a0ed3f5..d69e0f53f0 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -184,6 +184,8 @@ private: bool _HandlePostSyscall( PostSyscallEvent* event); + void _PrepareForTeamExec(TeamExecEvent* event); + void _HandleImageDebugInfoChanged(image_id imageID); void _HandleImageFileChanged(image_id imageID); @@ -259,6 +261,7 @@ private: TeamSettings fTeamSettings; int fCommandLineArgc; const char** fCommandLineArgv; + bool fExecPending; };