From 7cab8329564c7bccca42693808e9445ccfe6e108 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Sun, 8 Dec 2013 17:20:11 -0500 Subject: [PATCH] Debugger: Add support for suspending LoadImageDebugInfoJob. DwarfFile: - Loading is now split into two steps, the first of which simply attempts to verify the presence of debug information. If the latter is referenced externally, but cannot be found on disk, the corresponding file reference is returned. TeamDebugInfo: - Add state parameter to LoadImageDebugInfo(). Use it to preserve where we are in the specific info loading loop if necessary. SpecificTeamDebugInfo: - Add parameter to CreateImageDebugInfo() to allow passing in a state object and adjust implementing subclasses accordingly. DwarfTeamDebugInfo: - Preserve and/or pass down DwarfFile's loading state as needed. DwarfManager: - When attempting to load a DwarfFile, detect the case where external debug information is referenced, but could not be located. If so, preserve the relevant details in the loading state, so the user can be notified and asked to find it accordingly. LoadImageDebugInfoJob: - Keep a state object for the progress of the current loading job. If a particular image fails due to needing user input, suspend ourselves until such input has been provided. --- .../debug_info/DebuggerTeamDebugInfo.cpp | 3 +- .../debug_info/DebuggerTeamDebugInfo.h | 2 + .../debug_info/DwarfTeamDebugInfo.cpp | 25 ++++++-- .../debugger/debug_info/DwarfTeamDebugInfo.h | 2 + .../debug_info/SpecificTeamDebugInfo.h | 4 +- .../debugger/debug_info/TeamDebugInfo.cpp | 16 +++++- src/apps/debugger/debug_info/TeamDebugInfo.h | 3 + src/apps/debugger/dwarf/DwarfFile.cpp | 57 ++++++++++++++----- src/apps/debugger/dwarf/DwarfFile.h | 9 ++- src/apps/debugger/dwarf/DwarfManager.cpp | 45 +++++++++++---- src/apps/debugger/dwarf/DwarfManager.h | 8 ++- src/apps/debugger/jobs/Jobs.h | 5 +- .../debugger/jobs/LoadImageDebugInfoJob.cpp | 11 +++- 13 files changed, 149 insertions(+), 41 deletions(-) diff --git a/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.cpp b/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.cpp index 3c46e5f5df..66195db739 100644 --- a/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.cpp @@ -33,7 +33,8 @@ DebuggerTeamDebugInfo::Init() status_t DebuggerTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo, - LocatableFile* imageFile, SpecificImageDebugInfo*& _imageDebugInfo) + LocatableFile* imageFile, ImageDebugInfoLoadingState& _state, + SpecificImageDebugInfo*& _imageDebugInfo) { DebuggerImageDebugInfo* debuggerInfo = new(std::nothrow) DebuggerImageDebugInfo(imageInfo, diff --git a/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.h b/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.h index d3895c0c1e..37367540d1 100644 --- a/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.h +++ b/src/apps/debugger/debug_info/DebuggerTeamDebugInfo.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 DEBUGGER_TEAM_DEBUG_INFO_H @@ -24,6 +25,7 @@ public: virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo, LocatableFile* imageFile, + ImageDebugInfoLoadingState& _state, SpecificImageDebugInfo*& _imageDebugInfo); private: diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp index 331f0a3b4b..da04aca4d3 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp @@ -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. */ @@ -12,8 +13,10 @@ #include "DebuggerInterface.h" #include "DwarfFile.h" #include "DwarfImageDebugInfo.h" +#include "DwarfImageDebugInfoLoadingState.h" #include "DwarfManager.h" #include "GlobalTypeLookup.h" +#include "ImageDebugInfoLoadingState.h" #include "LocatableFile.h" @@ -58,7 +61,8 @@ DwarfTeamDebugInfo::Init() status_t DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo, - LocatableFile* imageFile, SpecificImageDebugInfo*& _imageDebugInfo) + LocatableFile* imageFile, ImageDebugInfoLoadingState& _state, + SpecificImageDebugInfo*& _imageDebugInfo) { // We only like images whose file we can play with. BString filePath; @@ -66,11 +70,22 @@ DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo, return B_ENTRY_NOT_FOUND; // try to load the DWARF file - DwarfFile* file; - status_t error = fManager->LoadFile(filePath, file); + DwarfImageDebugInfoLoadingState* dwarfState; + if (_state.HasSpecificDebugInfoLoadingState()) { + dwarfState = dynamic_cast( + _state.GetSpecificDebugInfoLoadingState()); + if (dwarfState == NULL) + return B_BAD_VALUE; + } else { + dwarfState = new(std::nothrow) DwarfImageDebugInfoLoadingState(); + if (dwarfState == NULL) + return B_NO_MEMORY; + _state.SetSpecificDebugInfoLoadingState(dwarfState); + } + + status_t error = fManager->LoadFile(filePath, dwarfState->GetFileState()); if (error != B_OK) return error; - BReference fileReference(file, true); error = fManager->FinishLoading(); if (error != B_OK) @@ -79,7 +94,7 @@ DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo, // create the image debug info DwarfImageDebugInfo* debugInfo = new(std::nothrow) DwarfImageDebugInfo( imageInfo, fDebuggerInterface, fArchitecture, fFileManager, - fTypeLookup, fTypeCache, file); + fTypeLookup, fTypeCache, dwarfState->GetFileState().dwarfFile); if (debugInfo == NULL) return B_NO_MEMORY; diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h index 90c243417a..fa2891b925 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.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 DWARF_TEAM_DEBUG_INFO_H @@ -31,6 +32,7 @@ public: virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo, LocatableFile* imageFile, + ImageDebugInfoLoadingState& _state, SpecificImageDebugInfo*& _imageDebugInfo); private: diff --git a/src/apps/debugger/debug_info/SpecificTeamDebugInfo.h b/src/apps/debugger/debug_info/SpecificTeamDebugInfo.h index 1d3a47d103..f9ac7c6a72 100644 --- a/src/apps/debugger/debug_info/SpecificTeamDebugInfo.h +++ b/src/apps/debugger/debug_info/SpecificTeamDebugInfo.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 SPECIFIC_TEAM_DEBUG_INFO_H @@ -8,17 +9,18 @@ #include +class ImageDebugInfoLoadingState; class ImageInfo; class LocatableFile; class SpecificImageDebugInfo; - class SpecificTeamDebugInfo { public: virtual ~SpecificTeamDebugInfo(); virtual status_t CreateImageDebugInfo(const ImageInfo& imageInfo, LocatableFile* imageFile, + ImageDebugInfoLoadingState& _state, SpecificImageDebugInfo*& _imageDebugInfo) = 0; }; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index 700caa4d76..00b174e0fa 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -1,6 +1,6 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2012-2013, Rene Gollent, rene@gollent.com. + * Copyright 2012-2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -24,6 +24,7 @@ #include "Function.h" #include "FunctionID.h" #include "ImageDebugInfo.h" +#include "ImageDebugInfoLoadingState.h" #include "LocatableFile.h" #include "SourceFile.h" #include "SourceLanguage.h" @@ -426,7 +427,8 @@ TeamDebugInfo::GetType(GlobalTypeCache* cache, const BString& name, status_t TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo, - LocatableFile* imageFile, ImageDebugInfo*& _imageDebugInfo) + LocatableFile* imageFile, ImageDebugInfoLoadingState& _state, + ImageDebugInfo*& _imageDebugInfo) { ImageDebugInfo* imageDebugInfo = new(std::nothrow) ImageDebugInfo( imageInfo); @@ -438,15 +440,23 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo, = fSpecificInfos.ItemAt(i); i++) { SpecificImageDebugInfo* specificImageInfo; status_t error = specificTeamInfo->CreateImageDebugInfo(imageInfo, - imageFile, specificImageInfo); + imageFile, _state, specificImageInfo); if (error == B_OK) { if (!imageDebugInfo->AddSpecificInfo(specificImageInfo)) { delete specificImageInfo; return B_NO_MEMORY; } + } else if (_state.UserInputRequired()) { + _state.SetSpecificInfoIndex(i); + return error; } else if (error == B_NO_MEMORY) return error; // fail only when out of memory + + _state.ClearSpecificDebugInfoLoadingState(); + // if we made it this far, then we're done with current specific + // info, and its corresponding state object, if any, is no longer + // needed } status_t error = imageDebugInfo->FinishInit(fDebuggerInterface); diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.h b/src/apps/debugger/debug_info/TeamDebugInfo.h index 06b7fe0399..884a1a36c7 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.h +++ b/src/apps/debugger/debug_info/TeamDebugInfo.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 TEAM_DEBUG_INFO_H @@ -26,6 +27,7 @@ class Function; class FunctionID; class FunctionInstance; class ImageDebugInfo; +class ImageDebugInfoLoadingState; class ImageInfo; class LocatableFile; class SourceCode; @@ -54,6 +56,7 @@ public: status_t LoadImageDebugInfo(const ImageInfo& imageInfo, LocatableFile* imageFile, + ImageDebugInfoLoadingState& state, ImageDebugInfo*& _imageDebugInfo); status_t LoadSourceCode(LocatableFile* file, diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index ad2fd47876..fa38af5af1 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -1,6 +1,6 @@ /* * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2012-2013, Rene Gollent, rene@gollent.com. + * Copyright 2012-2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -504,7 +504,7 @@ DwarfFile::~DwarfFile() status_t -DwarfFile::Load(const char* fileName) +DwarfFile::StartLoading(const char* fileName, BString& _requiredExternalFile) { fName = strdup(fileName); if (fName == NULL) @@ -523,9 +523,21 @@ DwarfFile::Load(const char* fileName) if (error != B_OK) return error; - error = _LocateDebugInfo(); - if (error != B_OK) - return error; + return _LocateDebugInfo(_requiredExternalFile); +} + + +status_t +DwarfFile::Load(const BString& externalInfoFilePath) +{ + status_t error = B_OK; + if (fDebugInfoSection == NULL) { + BString path; + error = _LocateDebugInfo(path, externalInfoFilePath.IsEmpty() + ? NULL : externalInfoFilePath.String()); + if (error != B_OK) + return error; + } ElfFile* debugInfoFile = fAlternateElfFile != NULL ? fAlternateElfFile : fElfFile; @@ -2686,7 +2698,8 @@ DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, status_t -DwarfFile::_LocateDebugInfo() +DwarfFile::_LocateDebugInfo(BString& _requiredExternalFileName, + const char* locatedFilePath) { ElfFile* debugInfoFile = fElfFile; ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink"); @@ -2700,10 +2713,19 @@ DwarfFile::_LocateDebugInfo() // by a 32-bit CRC BString debugPath; - status_t result = _GetDebugInfoPath( - (const char*)debugLinkSection->Data(), debugPath); - if (result != B_OK) - return result; + if (locatedFilePath) + debugPath = locatedFilePath; + else { + status_t result = _GetDebugInfoPath( + (const char*)debugLinkSection->Data(), + _requiredExternalFileName); + if (result != B_OK) + return result; + debugPath = _requiredExternalFileName; + } + + if (fAlternateName != NULL) + free(fAlternateName); fAlternateName = strdup(debugPath.String()); @@ -2715,11 +2737,13 @@ DwarfFile::_LocateDebugInfo() int32 debugCRC = *(int32*)((char*)debugLinkSection->Data() + debugLinkSection->Size() - sizeof(int32)); */ - fAlternateElfFile = new(std::nothrow) ElfFile; - if (fAlternateElfFile == NULL) - return B_NO_MEMORY; + if (fAlternateElfFile == NULL) { + fAlternateElfFile = new(std::nothrow) ElfFile; + if (fAlternateElfFile == NULL) + return B_NO_MEMORY; + } - result = fAlternateElfFile->Init(fAlternateName); + status_t result = fAlternateElfFile->Init(fAlternateName); if (result != B_OK) return result; @@ -2780,6 +2804,11 @@ DwarfFile::_GetDebugInfoPath(const char* debugFileName, if (result == B_OK) { _infoPath = basePath.Path(); return B_OK; + } else { + // if we failed to find a match, then it's up to the user to + // locate it. As such, return the external info file name + // for user interface purposes. + _infoPath.SetTo(debugFileName); } return B_ENTRY_NOT_FOUND; diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index 17dee900c8..b778383c80 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -35,7 +35,9 @@ public: DwarfFile(); ~DwarfFile(); - status_t Load(const char* fileName); + status_t StartLoading(const char* fileName, + BString& _requiredExternalFile); + status_t Load(const BString& externalFilePath); status_t FinishLoading(); const char* Name() const { return fName; } @@ -172,7 +174,10 @@ private: const void*& _expression, off_t& _length) const; - status_t _LocateDebugInfo(); + status_t _LocateDebugInfo( + BString& _requiredExternalFileName, + const char* locatedFilePath = NULL); + status_t _GetDebugInfoPath(const char* fileName, BString& _infoPath) const; diff --git a/src/apps/debugger/dwarf/DwarfManager.cpp b/src/apps/debugger/dwarf/DwarfManager.cpp index b6fb6bfadb..4f033da0c3 100644 --- a/src/apps/debugger/dwarf/DwarfManager.cpp +++ b/src/apps/debugger/dwarf/DwarfManager.cpp @@ -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. */ @@ -11,6 +12,7 @@ #include #include "DwarfFile.h" +#include "DwarfFileLoadingState.h" DwarfManager::DwarfManager() @@ -33,26 +35,49 @@ DwarfManager::Init() status_t -DwarfManager::LoadFile(const char* fileName, DwarfFile*& _file) +DwarfManager::LoadFile(const char* fileName, DwarfFileLoadingState& _state) { AutoLocker locker(this); - DwarfFile* file = new(std::nothrow) DwarfFile; - if (file == NULL) - return B_NO_MEMORY; + DwarfFile* file = _state.dwarfFile; + BReference fileReference; + if (file == NULL) { + file = new(std::nothrow) DwarfFile; + if (file == NULL) + return B_NO_MEMORY; + fileReference.SetTo(file, true); + _state.dwarfFile = file; + } else + fileReference.SetTo(file); - BReference fileReference(file, true); - status_t error = file->Load(fileName); + status_t error; + if (_state.externalInfoFileName.IsEmpty()) { + error = file->StartLoading(fileName, _state.externalInfoFileName); + if (error != B_OK) { + // only preserve state in the failure case if an external + // debug information reference was found, but the corresponding + // file could not be located on disk. + _state.state = _state.externalInfoFileName.IsEmpty() + ? DWARF_FILE_LOADING_STATE_FAILED + : DWARF_FILE_LOADING_STATE_USER_INPUT_NEEDED; + + return error; + } + } + + error = file->Load(_state.locatedExternalInfoPath); if (error != B_OK) { + _state.state = DWARF_FILE_LOADING_STATE_FAILED; return error; } fFiles.Add(file); - fileReference.Detach(); - // we keep the initial reference for ourselves - file->AcquireReference(); - _file = file; + fileReference.Detach(); + // keep a reference for ourselves in the list. + + _state.state = DWARF_FILE_LOADING_STATE_SUCCEEDED; + return B_OK; } diff --git a/src/apps/debugger/dwarf/DwarfManager.h b/src/apps/debugger/dwarf/DwarfManager.h index 8da0755a49..375402fc22 100644 --- a/src/apps/debugger/dwarf/DwarfManager.h +++ b/src/apps/debugger/dwarf/DwarfManager.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 DWARF_MANAGER_H @@ -11,6 +12,7 @@ class DwarfFile; +struct DwarfFileLoadingState; class DwarfManager { @@ -24,8 +26,10 @@ public: void Unlock() { fLock.Unlock(); } status_t LoadFile(const char* fileName, - DwarfFile*& _file); - // returns a reference + DwarfFileLoadingState& _loadingState); + // _loadingState receives a reference + // to the corresponding DwarfFile. + status_t FinishLoading(); private: diff --git a/src/apps/debugger/jobs/Jobs.h b/src/apps/debugger/jobs/Jobs.h index 1cf7a06925..f024bc38a3 100644 --- a/src/apps/debugger/jobs/Jobs.h +++ b/src/apps/debugger/jobs/Jobs.h @@ -1,12 +1,13 @@ /* * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2011, Rene Gollent, rene@gollent.com. + * Copyright 2011-2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #ifndef JOBS_H #define JOBS_H +#include "ImageDebugInfoLoadingState.h" #include "ImageDebugInfoProvider.h" #include "Types.h" #include "Worker.h" @@ -128,6 +129,8 @@ public: private: SimpleJobKey fKey; Image* fImage; + ImageDebugInfoLoadingState + fState; }; diff --git a/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp b/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp index dc1706c29f..418873f5eb 100644 --- a/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp +++ b/src/apps/debugger/jobs/LoadImageDebugInfoJob.cpp @@ -17,7 +17,8 @@ LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image) : fKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO), - fImage(image) + fImage(image), + fState() { fImage->AcquireReference(); } @@ -47,10 +48,16 @@ LoadImageDebugInfoJob::Do() // create the debug info ImageDebugInfo* debugInfo; status_t error = fImage->GetTeam()->DebugInfo()->LoadImageDebugInfo( - imageInfo, fImage->ImageFile(), debugInfo); + imageInfo, fImage->ImageFile(), fState, debugInfo); // set the result locker.Lock(); + + if (fState.UserInputRequired()) { + // TODO: notify the user interface + return WaitForUserInput(); + } + if (error == B_OK) { error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); debugInfo->ReleaseReference();