From d44d8207a86103afa47f1862c06ff46e46e1cb33 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Fri, 13 Jun 2014 20:25:13 -0400 Subject: [PATCH] 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. --- .../debugger/controllers/TeamDebugger.cpp | 58 +++++++++++++++++-- src/apps/debugger/controllers/TeamDebugger.h | 12 +++- .../debugger/controllers/ThreadHandler.cpp | 7 ++- src/apps/debugger/controllers/ThreadHandler.h | 4 ++ src/apps/debugger/jobs/GetStackTraceJob.cpp | 6 +- src/apps/debugger/jobs/Jobs.h | 21 ++++++- .../debugger/jobs/LoadImageDebugInfoJob.cpp | 46 ++++++++++++--- 7 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/apps/debugger/controllers/TeamDebugger.cpp b/src/apps/debugger/controllers/TeamDebugger.cpp index 5be1681dc2..d084e22f6e 100644 --- a/src/apps/debugger/controllers/TeamDebugger.cpp +++ b/src/apps/debugger/controllers/TeamDebugger.cpp @@ -32,12 +32,16 @@ #include "Function.h" #include "FunctionID.h" #include "ImageDebugInfo.h" +#include "ImageDebugInfoLoadingState.h" +#include "ImageDebugLoadingStateHandler.h" +#include "ImageDebugLoadingStateHandlerRoster.h" #include "Jobs.h" #include "LocatableFile.h" #include "MessageCodes.h" #include "SettingsManager.h" #include "SourceCode.h" #include "SpecificImageDebugInfo.h" +#include "SpecificImageDebugInfoLoadingState.h" #include "StackFrame.h" #include "StackFrameValues.h" #include "Statement.h" @@ -463,8 +467,7 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, int argc, return error; ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, - fWorker, fDebuggerInterface, - fBreakpointManager); + fWorker, fDebuggerInterface, this, fBreakpointManager); if (handler == NULL) return B_NO_MEMORY; @@ -787,6 +790,20 @@ TeamDebugger::MessageReceived(BMessage* message) 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: BLooper::MessageReceived(message); break; @@ -848,7 +865,7 @@ TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance, void 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 TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event) { @@ -1405,8 +1436,7 @@ TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event) fTeam->AddThread(info, &thread); ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread, - fWorker, fDebuggerInterface, - fBreakpointManager); + fWorker, fDebuggerInterface, this, fBreakpointManager); if (handler != NULL) { fThreadHandlers.Insert(handler); 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* TeamDebugger::_GetThreadHandler(thread_id threadID) { diff --git a/src/apps/debugger/controllers/TeamDebugger.h b/src/apps/debugger/controllers/TeamDebugger.h index c91fc583da..46fa880378 100644 --- a/src/apps/debugger/controllers/TeamDebugger.h +++ b/src/apps/debugger/controllers/TeamDebugger.h @@ -1,6 +1,6 @@ /* * 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. */ #ifndef TEAM_DEBUGGER_H @@ -13,6 +13,7 @@ #include #include "DebugEvent.h" +#include "Jobs.h" #include "Team.h" #include "TeamSettings.h" #include "ThreadHandler.h" @@ -30,7 +31,8 @@ class WatchpointManager; class TeamDebugger : public BLooper, private UserInterfaceListener, - private JobListener, private Team::Listener { + private JobListener, private ImageDebugInfoJobListener, + private Team::Listener { public: class Listener; @@ -110,6 +112,9 @@ private: virtual void JobFailed(Job* job); virtual void JobAborted(Job* job); + virtual void ImageDebugInfoJobNeedsUserInput(Job* job, + ImageDebugInfoLoadingState* state); + // Team::Listener virtual void ThreadStateChanged( const ::Team::ThreadEvent& event); @@ -178,6 +183,9 @@ private: status_t _HandleSetArguments(int argc, const char* const* argv); + void _HandleDebugInfoJobUserInput( + ImageDebugInfoLoadingState* state); + ThreadHandler* _GetThreadHandler(thread_id threadID); status_t _AddImage(const ImageInfo& imageInfo, diff --git a/src/apps/debugger/controllers/ThreadHandler.cpp b/src/apps/debugger/controllers/ThreadHandler.cpp index 3a1a02f289..a9653c200b 100644 --- a/src/apps/debugger/controllers/ThreadHandler.cpp +++ b/src/apps/debugger/controllers/ThreadHandler.cpp @@ -1,6 +1,6 @@ /* * 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. */ @@ -44,11 +44,13 @@ enum { ThreadHandler::ThreadHandler(Thread* thread, Worker* worker, DebuggerInterface* debuggerInterface, + ImageDebugInfoJobListener* listener, BreakpointManager* breakpointManager) : fThread(thread), fWorker(worker), fDebuggerInterface(debuggerInterface), + fDebugInfoJobListener(listener), fBreakpointManager(breakpointManager), fStepMode(STEP_NONE), fStepStatement(NULL), @@ -376,7 +378,8 @@ ThreadHandler::HandleCpuStateChanged() if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) { fWorker->ScheduleJob( new(std::nothrow) GetStackTraceJob(fDebuggerInterface, - fDebuggerInterface->GetArchitecture(), fThread)); + fDebugInfoJobListener, fDebuggerInterface->GetArchitecture(), + fThread)); } } diff --git a/src/apps/debugger/controllers/ThreadHandler.h b/src/apps/debugger/controllers/ThreadHandler.h index 3bbff417bb..eb80905d21 100644 --- a/src/apps/debugger/controllers/ThreadHandler.h +++ b/src/apps/debugger/controllers/ThreadHandler.h @@ -1,5 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #ifndef THREAD_HANDLER_H @@ -17,6 +18,7 @@ class BreakpointManager; class DebuggerInterface; +class ImageDebugInfoJobListener; class StackFrame; class Statement; class Worker; @@ -27,6 +29,7 @@ class ThreadHandler : public BReferenceable, private ImageDebugInfoProvider, public: ThreadHandler(Thread* thread, Worker* worker, DebuggerInterface* debuggerInterface, + ImageDebugInfoJobListener* listener, BreakpointManager* breakpointManager); ~ThreadHandler(); @@ -103,6 +106,7 @@ private: Thread* fThread; Worker* fWorker; DebuggerInterface* fDebuggerInterface; + ImageDebugInfoJobListener* fDebugInfoJobListener; BreakpointManager* fBreakpointManager; uint32 fStepMode; Statement* fStepStatement; diff --git a/src/apps/debugger/jobs/GetStackTraceJob.cpp b/src/apps/debugger/jobs/GetStackTraceJob.cpp index 0bc286ea73..d0b28ce167 100644 --- a/src/apps/debugger/jobs/GetStackTraceJob.cpp +++ b/src/apps/debugger/jobs/GetStackTraceJob.cpp @@ -18,10 +18,12 @@ GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface, - Architecture* architecture, Thread* thread) + ImageDebugInfoJobListener* listener, Architecture* architecture, + Thread* thread) : fKey(thread, JOB_TYPE_GET_STACK_TRACE), fDebuggerInterface(debuggerInterface), + fDebugInfoJobListener(listener), fArchitecture(architecture), fThread(thread) { @@ -82,7 +84,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info) // schedule a job, if not loaded ImageDebugInfo* info; status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(GetWorker(), - image, &info); + image, fDebugInfoJobListener, &info); if (error != B_OK) return error; diff --git a/src/apps/debugger/jobs/Jobs.h b/src/apps/debugger/jobs/Jobs.h index f024bc38a3..bc5df71558 100644 --- a/src/apps/debugger/jobs/Jobs.h +++ b/src/apps/debugger/jobs/Jobs.h @@ -83,10 +83,19 @@ private: }; +class ImageDebugInfoJobListener { +public: + virtual ~ImageDebugInfoJobListener(); + virtual void ImageDebugInfoJobNeedsUserInput(Job* job, + ImageDebugInfoLoadingState* state); +}; + + class GetStackTraceJob : public Job, private ImageDebugInfoProvider { public: GetStackTraceJob( DebuggerInterface* debuggerInterface, + ImageDebugInfoJobListener* listener, Architecture* architecture, Thread* thread); virtual ~GetStackTraceJob(); @@ -101,6 +110,7 @@ private: private: SimpleJobKey fKey; DebuggerInterface* fDebuggerInterface; + ImageDebugInfoJobListener* fDebugInfoJobListener; Architecture* fArchitecture; Thread* fThread; CpuState* fCpuState; @@ -109,7 +119,8 @@ private: class LoadImageDebugInfoJob : public Job { public: - LoadImageDebugInfoJob(Image* image); + LoadImageDebugInfoJob(Image* image, + ImageDebugInfoJobListener* listener); virtual ~LoadImageDebugInfoJob(); virtual const JobKey& Key() const; @@ -117,6 +128,7 @@ public: static status_t ScheduleIfNecessary(Worker* worker, Image* image, + ImageDebugInfoJobListener* listener, ImageDebugInfo** _imageDebugInfo = NULL); // If already loaded returns a // reference, if desired. If not loaded @@ -125,12 +137,19 @@ public: // if scheduling the job failed, or the // debug info already failed to load // earlier. +private: + void NotifyUserInputListener(); + +private: + typedef BObjectList ListenerList; + private: SimpleJobKey fKey; Image* fImage; ImageDebugInfoLoadingState fState; + ImageDebugInfoJobListener* fListener; }; diff --git a/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp b/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp index 418873f5eb..600055c0f6 100644 --- a/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp +++ b/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp @@ -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. * Distributed under the terms of the MIT License. */ @@ -14,11 +14,31 @@ #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), fImage(image), - fState() + fState(), + fListener(listener) { fImage->AcquireReference(); } @@ -54,11 +74,9 @@ LoadImageDebugInfoJob::Do() locker.Lock(); if (fState.UserInputRequired()) { - // TODO: notify the user interface + NotifyUserInputListener(); return WaitForUserInput(); - } - - if (error == B_OK) { + } else if (error == B_OK) { error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); debugInfo->ReleaseReference(); } else @@ -70,7 +88,7 @@ LoadImageDebugInfoJob::Do() /*static*/ status_t LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image, - ImageDebugInfo** _imageDebugInfo) + ImageDebugInfoJobListener* listener, ImageDebugInfo** _imageDebugInfo) { AutoLocker teamLocker(image->GetTeam()); @@ -95,7 +113,8 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image, return B_ERROR; // schedule a job - LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(image); + LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(image, + listener); if (job == NULL) return B_NO_MEMORY; @@ -111,3 +130,12 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image, *_imageDebugInfo = NULL; return B_OK; } + + +void +LoadImageDebugInfoJob::NotifyUserInputListener() +{ + if (fListener != NULL) + fListener->ImageDebugInfoJobNeedsUserInput(this, &fState); +} +