Debugger: Finish handling of missing debug information.

Add a listener interface for LoadImageDebugInfoJob that allows it to request
user assistance based on its current state. Adjust callers to pass in said
listener accordingly.

Implement the aforementioned listener interface in TeamDebugger, and use the
loading state handler roster to find the appropriate handler / handle the request.

This implements most of what's needed for #10138, the main piece still missing
is for the dwarf handler to detect whether the image in question comes from a package,
and if so, to offer to install the corresponding debug information package rather than
locating the file manually, assuming such a package exists.
This commit is contained in:
Rene Gollent
2014-06-15 11:03:24 -04:00
parent 331511009c
commit d44d8207a8
7 changed files with 133 additions and 21 deletions
+53 -5
View File
@@ -32,12 +32,16 @@
#include "Function.h" #include "Function.h"
#include "FunctionID.h" #include "FunctionID.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "ImageDebugInfoLoadingState.h"
#include "ImageDebugLoadingStateHandler.h"
#include "ImageDebugLoadingStateHandlerRoster.h"
#include "Jobs.h" #include "Jobs.h"
#include "LocatableFile.h" #include "LocatableFile.h"
#include "MessageCodes.h" #include "MessageCodes.h"
#include "SettingsManager.h" #include "SettingsManager.h"
#include "SourceCode.h" #include "SourceCode.h"
#include "SpecificImageDebugInfo.h" #include "SpecificImageDebugInfo.h"
#include "SpecificImageDebugInfoLoadingState.h"
#include "StackFrame.h" #include "StackFrame.h"
#include "StackFrameValues.h" #include "StackFrameValues.h"
#include "Statement.h" #include "Statement.h"
@@ -463,8 +467,7 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, int argc,
return error; return error;
ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
fWorker, fDebuggerInterface, fWorker, fDebuggerInterface, this, fBreakpointManager);
fBreakpointManager);
if (handler == NULL) if (handler == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -787,6 +790,20 @@ TeamDebugger::MessageReceived(BMessage* message)
break; break;
} }
case MSG_DEBUG_INFO_NEEDS_USER_INPUT:
{
Job* job;
ImageDebugInfoLoadingState* state;
if (message->FindPointer("job", (void**)&job) != B_OK)
break;
if (message->FindPointer("state", (void**)&state) != B_OK)
break;
_HandleDebugInfoJobUserInput(state);
fWorker->ResumeJob(job);
break;
}
default: default:
BLooper::MessageReceived(message); BLooper::MessageReceived(message);
break; break;
@@ -848,7 +865,7 @@ TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
void void
TeamDebugger::ImageDebugInfoRequested(Image* image) TeamDebugger::ImageDebugInfoRequested(Image* image)
{ {
LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image); LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
} }
@@ -1121,6 +1138,20 @@ TeamDebugger::JobAborted(Job* job)
} }
void
TeamDebugger::ImageDebugInfoJobNeedsUserInput(Job* job,
ImageDebugInfoLoadingState* state)
{
TRACE_JOBS("TeamDebugger::DebugInfoJobNeedsUserInput(%p, %p)\n",
job, state);
BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
message.AddPointer("job", job);
message.AddPointer("state", state);
PostMessage(&message);
}
void void
TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event) TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
{ {
@@ -1405,8 +1436,7 @@ TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
fTeam->AddThread(info, &thread); fTeam->AddThread(info, &thread);
ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
fWorker, fDebuggerInterface, fWorker, fDebuggerInterface, this, fBreakpointManager);
fBreakpointManager);
if (handler != NULL) { if (handler != NULL) {
fThreadHandlers.Insert(handler); fThreadHandlers.Insert(handler);
handler->Init(); handler->Init();
@@ -1909,6 +1939,24 @@ TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
} }
void
TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
{
SpecificImageDebugInfoLoadingState* specificState
= state->GetSpecificDebugInfoLoadingState();
ImageDebugLoadingStateHandler* handler;
if (ImageDebugLoadingStateHandlerRoster::Default()
->FindStateHandler(specificState, handler) != B_OK) {
TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
"Failed to find appropriate information handler, aborting.");
return;
}
handler->HandleState(specificState, fUserInterface);
}
ThreadHandler* ThreadHandler*
TeamDebugger::_GetThreadHandler(thread_id threadID) TeamDebugger::_GetThreadHandler(thread_id threadID)
{ {
+10 -2
View File
@@ -1,6 +1,6 @@
/* /*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2013, Rene Gollent, rene@gollent.com. * Copyright 2013-2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef TEAM_DEBUGGER_H #ifndef TEAM_DEBUGGER_H
@@ -13,6 +13,7 @@
#include <debug_support.h> #include <debug_support.h>
#include "DebugEvent.h" #include "DebugEvent.h"
#include "Jobs.h"
#include "Team.h" #include "Team.h"
#include "TeamSettings.h" #include "TeamSettings.h"
#include "ThreadHandler.h" #include "ThreadHandler.h"
@@ -30,7 +31,8 @@ class WatchpointManager;
class TeamDebugger : public BLooper, private UserInterfaceListener, class TeamDebugger : public BLooper, private UserInterfaceListener,
private JobListener, private Team::Listener { private JobListener, private ImageDebugInfoJobListener,
private Team::Listener {
public: public:
class Listener; class Listener;
@@ -110,6 +112,9 @@ private:
virtual void JobFailed(Job* job); virtual void JobFailed(Job* job);
virtual void JobAborted(Job* job); virtual void JobAborted(Job* job);
virtual void ImageDebugInfoJobNeedsUserInput(Job* job,
ImageDebugInfoLoadingState* state);
// Team::Listener // Team::Listener
virtual void ThreadStateChanged( virtual void ThreadStateChanged(
const ::Team::ThreadEvent& event); const ::Team::ThreadEvent& event);
@@ -178,6 +183,9 @@ private:
status_t _HandleSetArguments(int argc, status_t _HandleSetArguments(int argc,
const char* const* argv); const char* const* argv);
void _HandleDebugInfoJobUserInput(
ImageDebugInfoLoadingState* state);
ThreadHandler* _GetThreadHandler(thread_id threadID); ThreadHandler* _GetThreadHandler(thread_id threadID);
status_t _AddImage(const ImageInfo& imageInfo, status_t _AddImage(const ImageInfo& imageInfo,
@@ -1,6 +1,6 @@
/* /*
* Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2010-2013, Rene Gollent, rene@gollent.com. * Copyright 2010-2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -44,11 +44,13 @@ enum {
ThreadHandler::ThreadHandler(Thread* thread, Worker* worker, ThreadHandler::ThreadHandler(Thread* thread, Worker* worker,
DebuggerInterface* debuggerInterface, DebuggerInterface* debuggerInterface,
ImageDebugInfoJobListener* listener,
BreakpointManager* breakpointManager) BreakpointManager* breakpointManager)
: :
fThread(thread), fThread(thread),
fWorker(worker), fWorker(worker),
fDebuggerInterface(debuggerInterface), fDebuggerInterface(debuggerInterface),
fDebugInfoJobListener(listener),
fBreakpointManager(breakpointManager), fBreakpointManager(breakpointManager),
fStepMode(STEP_NONE), fStepMode(STEP_NONE),
fStepStatement(NULL), fStepStatement(NULL),
@@ -376,7 +378,8 @@ ThreadHandler::HandleCpuStateChanged()
if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) { if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) {
fWorker->ScheduleJob( fWorker->ScheduleJob(
new(std::nothrow) GetStackTraceJob(fDebuggerInterface, new(std::nothrow) GetStackTraceJob(fDebuggerInterface,
fDebuggerInterface->GetArchitecture(), fThread)); fDebugInfoJobListener, fDebuggerInterface->GetArchitecture(),
fThread));
} }
} }
@@ -1,5 +1,6 @@
/* /*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2014, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef THREAD_HANDLER_H #ifndef THREAD_HANDLER_H
@@ -17,6 +18,7 @@
class BreakpointManager; class BreakpointManager;
class DebuggerInterface; class DebuggerInterface;
class ImageDebugInfoJobListener;
class StackFrame; class StackFrame;
class Statement; class Statement;
class Worker; class Worker;
@@ -27,6 +29,7 @@ class ThreadHandler : public BReferenceable, private ImageDebugInfoProvider,
public: public:
ThreadHandler(Thread* thread, Worker* worker, ThreadHandler(Thread* thread, Worker* worker,
DebuggerInterface* debuggerInterface, DebuggerInterface* debuggerInterface,
ImageDebugInfoJobListener* listener,
BreakpointManager* breakpointManager); BreakpointManager* breakpointManager);
~ThreadHandler(); ~ThreadHandler();
@@ -103,6 +106,7 @@ private:
Thread* fThread; Thread* fThread;
Worker* fWorker; Worker* fWorker;
DebuggerInterface* fDebuggerInterface; DebuggerInterface* fDebuggerInterface;
ImageDebugInfoJobListener* fDebugInfoJobListener;
BreakpointManager* fBreakpointManager; BreakpointManager* fBreakpointManager;
uint32 fStepMode; uint32 fStepMode;
Statement* fStepStatement; Statement* fStepStatement;
+4 -2
View File
@@ -18,10 +18,12 @@
GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface, GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface,
Architecture* architecture, Thread* thread) ImageDebugInfoJobListener* listener, Architecture* architecture,
Thread* thread)
: :
fKey(thread, JOB_TYPE_GET_STACK_TRACE), fKey(thread, JOB_TYPE_GET_STACK_TRACE),
fDebuggerInterface(debuggerInterface), fDebuggerInterface(debuggerInterface),
fDebugInfoJobListener(listener),
fArchitecture(architecture), fArchitecture(architecture),
fThread(thread) fThread(thread)
{ {
@@ -82,7 +84,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
// schedule a job, if not loaded // schedule a job, if not loaded
ImageDebugInfo* info; ImageDebugInfo* info;
status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(GetWorker(), status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(GetWorker(),
image, &info); image, fDebugInfoJobListener, &info);
if (error != B_OK) if (error != B_OK)
return error; return error;
+20 -1
View File
@@ -83,10 +83,19 @@ private:
}; };
class ImageDebugInfoJobListener {
public:
virtual ~ImageDebugInfoJobListener();
virtual void ImageDebugInfoJobNeedsUserInput(Job* job,
ImageDebugInfoLoadingState* state);
};
class GetStackTraceJob : public Job, private ImageDebugInfoProvider { class GetStackTraceJob : public Job, private ImageDebugInfoProvider {
public: public:
GetStackTraceJob( GetStackTraceJob(
DebuggerInterface* debuggerInterface, DebuggerInterface* debuggerInterface,
ImageDebugInfoJobListener* listener,
Architecture* architecture, Thread* thread); Architecture* architecture, Thread* thread);
virtual ~GetStackTraceJob(); virtual ~GetStackTraceJob();
@@ -101,6 +110,7 @@ private:
private: private:
SimpleJobKey fKey; SimpleJobKey fKey;
DebuggerInterface* fDebuggerInterface; DebuggerInterface* fDebuggerInterface;
ImageDebugInfoJobListener* fDebugInfoJobListener;
Architecture* fArchitecture; Architecture* fArchitecture;
Thread* fThread; Thread* fThread;
CpuState* fCpuState; CpuState* fCpuState;
@@ -109,7 +119,8 @@ private:
class LoadImageDebugInfoJob : public Job { class LoadImageDebugInfoJob : public Job {
public: public:
LoadImageDebugInfoJob(Image* image); LoadImageDebugInfoJob(Image* image,
ImageDebugInfoJobListener* listener);
virtual ~LoadImageDebugInfoJob(); virtual ~LoadImageDebugInfoJob();
virtual const JobKey& Key() const; virtual const JobKey& Key() const;
@@ -117,6 +128,7 @@ public:
static status_t ScheduleIfNecessary(Worker* worker, static status_t ScheduleIfNecessary(Worker* worker,
Image* image, Image* image,
ImageDebugInfoJobListener* listener,
ImageDebugInfo** _imageDebugInfo = NULL); ImageDebugInfo** _imageDebugInfo = NULL);
// If already loaded returns a // If already loaded returns a
// reference, if desired. If not loaded // reference, if desired. If not loaded
@@ -125,12 +137,19 @@ public:
// if scheduling the job failed, or the // if scheduling the job failed, or the
// debug info already failed to load // debug info already failed to load
// earlier. // earlier.
private:
void NotifyUserInputListener();
private:
typedef BObjectList<ImageDebugInfoJobListener> ListenerList;
private: private:
SimpleJobKey fKey; SimpleJobKey fKey;
Image* fImage; Image* fImage;
ImageDebugInfoLoadingState ImageDebugInfoLoadingState
fState; fState;
ImageDebugInfoJobListener* fListener;
}; };
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012, Rene Gollent, rene@gollent.com. * Copyright 2012-2014, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -14,11 +14,31 @@
#include "Team.h" #include "Team.h"
LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image) // #pragma mark - ImageDebugInfoJobListener
ImageDebugInfoJobListener::~ImageDebugInfoJobListener()
{
}
void
ImageDebugInfoJobListener::ImageDebugInfoJobNeedsUserInput(Job* job,
ImageDebugInfoLoadingState* state)
{
}
// #pragma mark - LoadImageDebugInfoJob
LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image,
ImageDebugInfoJobListener* listener)
: :
fKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO), fKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO),
fImage(image), fImage(image),
fState() fState(),
fListener(listener)
{ {
fImage->AcquireReference(); fImage->AcquireReference();
} }
@@ -54,11 +74,9 @@ LoadImageDebugInfoJob::Do()
locker.Lock(); locker.Lock();
if (fState.UserInputRequired()) { if (fState.UserInputRequired()) {
// TODO: notify the user interface NotifyUserInputListener();
return WaitForUserInput(); return WaitForUserInput();
} } else if (error == B_OK) {
if (error == B_OK) {
error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
debugInfo->ReleaseReference(); debugInfo->ReleaseReference();
} else } else
@@ -70,7 +88,7 @@ LoadImageDebugInfoJob::Do()
/*static*/ status_t /*static*/ status_t
LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image, LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
ImageDebugInfo** _imageDebugInfo) ImageDebugInfoJobListener* listener, ImageDebugInfo** _imageDebugInfo)
{ {
AutoLocker<Team> teamLocker(image->GetTeam()); AutoLocker<Team> teamLocker(image->GetTeam());
@@ -95,7 +113,8 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
return B_ERROR; return B_ERROR;
// schedule a job // schedule a job
LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(image); LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(image,
listener);
if (job == NULL) if (job == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -111,3 +130,12 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
*_imageDebugInfo = NULL; *_imageDebugInfo = NULL;
return B_OK; return B_OK;
} }
void
LoadImageDebugInfoJob::NotifyUserInputListener()
{
if (fListener != NULL)
fListener->ImageDebugInfoJobNeedsUserInput(this, &fState);
}