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.
This commit is contained in:
Rene Gollent
2015-07-26 14:37:28 -04:00
parent 10bbf8cb8d
commit 9123fde7b9
2 changed files with 77 additions and 9 deletions
+74 -9
View File
@@ -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<TeamExecEvent*>(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<UserBreakpoint> 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<Image> 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<ImageInfoPendingThread> threadDeleter(thread);
locker.Lock();
ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
BReference<ThreadHandler> handlerReference(handler);
if (fTeam->StopOnImageLoad()) {
ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
BReference<ThreadHandler> 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());
}
}
}
}