hrev44428 adds 1 changeset to branch 'master' old head: 200dec066fdd9d18e8e93232a6e55e9f5ba3df30 new head: 224f75100b15ee71dce0b0e551efd40236ca8b54 ---------------------------------------------------------------------------- 224f751: Implement support for separate debug info files. - When loading an image, we now check if it has a .gnu_debuglink section. If so, we try to load the linked file for our symbolic debugging information. The file is searched for with the following rules: 1) If self-contained app, app image is looked for in ./debug while library/add-on images are looked for in ../debug/. 2) If the image in question is in one of the global locations (/boot/{common,system,home/config}/{lib,add-ons}), we search in develop/debug for the corresponding global dir. Implements #8135. [ Rene Gollent <anevilyak@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev44428 Commit: 224f75100b15ee71dce0b0e551efd40236ca8b54 URL: http://cgit.haiku-os.org/haiku/commit/?id=224f751 Author: Rene Gollent <anevilyak@xxxxxxxxx> Date: Sun Jul 29 11:07:04 2012 UTC Ticket: https://dev.haiku-os.org/ticket/8135 ---------------------------------------------------------------------------- 2 files changed, 167 insertions(+), 22 deletions(-) src/apps/debugger/dwarf/DwarfFile.cpp | 183 +++++++++++++++++++++++++---- src/apps/debugger/dwarf/DwarfFile.h | 6 + ---------------------------------------------------------------------------- diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index f95d18e..636b1fa 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -11,6 +11,9 @@ #include <new> #include <AutoDeleter.h> +#include <Entry.h> +#include <FindDirectory.h> +#include <Path.h> #include "AttributeClasses.h" #include "AttributeValue.h" @@ -27,6 +30,30 @@ #include "Variant.h" +// #pragma mark - AutoSectionPutter + + +class AutoSectionPutter { +public: + AutoSectionPutter(ElfFile* elfFile, ElfSection* elfSection) + : + fElfFile(elfFile), + fElfSection(elfSection) + { + } + + ~AutoSectionPutter() + { + if (fElfSection != NULL) + fElfFile->PutSection(fElfSection); + } + +private: + ElfFile* fElfFile; + ElfSection* fElfSection; +}; + + // #pragma mark - ExpressionEvaluationContext @@ -281,7 +308,9 @@ private: DwarfFile::DwarfFile() : fName(NULL), + fAlternateName(NULL), fElfFile(NULL), + fAlternateElfFile(NULL), fDebugInfoSection(NULL), fDebugAbbrevSection(NULL), fDebugStringSection(NULL), @@ -305,19 +334,24 @@ DwarfFile::~DwarfFile() delete table; if (fElfFile != NULL) { - fElfFile->PutSection(fDebugInfoSection); - fElfFile->PutSection(fDebugAbbrevSection); - fElfFile->PutSection(fDebugStringSection); - fElfFile->PutSection(fDebugRangesSection); - fElfFile->PutSection(fDebugLineSection); - fElfFile->PutSection(fDebugFrameSection); + ElfFile* debugInfoFile = fAlternateElfFile != NULL + ? fAlternateElfFile : fElfFile; + + debugInfoFile->PutSection(fDebugInfoSection); + debugInfoFile->PutSection(fDebugAbbrevSection); + debugInfoFile->PutSection(fDebugStringSection); + debugInfoFile->PutSection(fDebugRangesSection); + debugInfoFile->PutSection(fDebugLineSection); + debugInfoFile->PutSection(fDebugFrameSection); fElfFile->PutSection(fEHFrameSection); - fElfFile->PutSection(fDebugLocationSection); - fElfFile->PutSection(fDebugPublicTypesSection); + debugInfoFile->PutSection(fDebugLocationSection); + debugInfoFile->PutSection(fDebugPublicTypesSection); delete fElfFile; + delete fAlternateElfFile; } free(fName); + free(fAlternateName); } @@ -337,23 +371,24 @@ DwarfFile::Load(const char* fileName) if (error != B_OK) return error; - // get the interesting sections - fDebugInfoSection = fElfFile->GetSection(".debug_info"); - fDebugAbbrevSection = fElfFile->GetSection(".debug_abbrev"); - if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) { - WARNING("DwarfManager::File::Load(\"%s\"): no " - ".debug_info or .debug_abbrev.\n", fileName); - return B_ERROR; - } + error = _LocateDebugInfo(); + if (error != B_OK) + return error; + + ElfFile* debugInfoFile = fAlternateElfFile != NULL + ? fAlternateElfFile : fElfFile; // non mandatory sections - fDebugStringSection = fElfFile->GetSection(".debug_str"); - fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); - fDebugLineSection = fElfFile->GetSection(".debug_line"); - fDebugFrameSection = fElfFile->GetSection(".debug_frame"); + fDebugStringSection = debugInfoFile->GetSection(".debug_str"); + fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges"); + fDebugLineSection = debugInfoFile->GetSection(".debug_line"); + fDebugFrameSection = debugInfoFile->GetSection(".debug_frame"); + // .eh_frame doesn't appear to get copied into separate debug + // info files properly, therefore always use it off the main + // executable image fEHFrameSection = fElfFile->GetSection(".eh_frame"); - fDebugLocationSection = fElfFile->GetSection(".debug_loc"); - fDebugPublicTypesSection = fElfFile->GetSection(".debug_pubtypes"); + fDebugLocationSection = debugInfoFile->GetSection(".debug_loc"); + fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes"); // iterate through the debug info section DataReader dataReader(fDebugInfoSection->Data(), @@ -2224,3 +2259,107 @@ DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, } } } + + +status_t +DwarfFile::_LocateDebugInfo() +{ + ElfFile* debugInfoFile = fElfFile; + ElfSection* debugLinkSection = fElfFile->GetSection(".gnu_debuglink"); + if (debugLinkSection != NULL) { + AutoSectionPutter putter(fElfFile, debugLinkSection); + + // the file specifies a debug link, look at its target instead + // for debug information. + // Format: null-terminated filename, as many 0 padding bytes as + // needed to reach the next 32-bit address boundary, followed + // by a 32-bit CRC + + BString debugPath; + status_t result = _GetDebugInfoPath( + (const char*)debugLinkSection->Data(), debugPath); + if (result != B_OK) + return result; + + fAlternateName = strdup(debugPath.String()); + + if (fAlternateName == NULL) + return B_NO_MEMORY; + +/* + // TODO: validate CRC + int32 debugCRC = *(int32*)((char*)debugLinkSection->Data() + + debugLinkSection->Size() - sizeof(int32)); +*/ + fAlternateElfFile = new(std::nothrow) ElfFile; + if (fAlternateElfFile == NULL) + return B_NO_MEMORY; + + result = fAlternateElfFile->Init(fAlternateName); + if (result != B_OK) + return result; + + debugInfoFile = fAlternateElfFile; + } + + // get the interesting sections + fDebugInfoSection = debugInfoFile->GetSection(".debug_info"); + fDebugAbbrevSection = debugInfoFile->GetSection(".debug_abbrev"); + if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) { + WARNING("DwarfManager::File::Load(\"%s\"): no " + ".debug_info or .debug_abbrev.\n", fName); + return B_ERROR; + } + + return B_OK; +} + + +status_t +DwarfFile::_GetDebugInfoPath(const char* debugFileName, BString& _infoPath) +{ + const directory_which dirLocations[] = { B_USER_CONFIG_DIRECTORY, + B_COMMON_DIRECTORY, B_SYSTEM_DIRECTORY }; + + // first, see if we have a relative match to our local directory + BPath basePath; + status_t result = basePath.SetTo(fName); + if (result != B_OK) + return result; + basePath.GetParent(&basePath); + if (strcmp(basePath.Leaf(), "lib") == 0 || strcmp(basePath.Leaf(), + "add-ons") == 0) { + _infoPath.SetToFormat("%s/../debug/%s", basePath.Path(), + debugFileName); + } else + _infoPath.SetToFormat("%s/debug/%s", basePath.Path(), debugFileName); + + BEntry entry(_infoPath.String()); + result = entry.InitCheck(); + if (result != B_OK && result != B_ENTRY_NOT_FOUND) + return result; + if (entry.Exists()) + return B_OK; + + // See if our image is in any of the system locations. + // if so, look for its debug info in the corresponding location. + for (uint16 i = 0; i < sizeof(dirLocations) / sizeof(directory_which); + i++) { + result = find_directory(dirLocations[i], &basePath); + if (result != B_OK) + return result; + + if (strncmp(fName, basePath.Path(), strlen(basePath.Path())) == 0) { + _infoPath.SetToFormat("%s/develop/debug/%s", basePath.Path(), + debugFileName); + entry.SetTo(_infoPath.String()); + result = entry.InitCheck(); + if (result != B_OK && result != B_ENTRY_NOT_FOUND) + return result; + return entry.Exists() ? B_OK : B_ENTRY_NOT_FOUND; + } + } + + return B_ENTRY_NOT_FOUND; +} + diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index b7d53b8..ba08a08 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -150,12 +150,18 @@ private: const void*& _expression, off_t& _length) const; + status_t _LocateDebugInfo(); + status_t _GetDebugInfoPath(const char* fileName, + BString& _infoPath); + private: friend class DwarfFile::ExpressionEvaluationContext; private: char* fName; + char* fAlternateName; ElfFile* fElfFile; + ElfFile* fAlternateElfFile; ElfSection* fDebugInfoSection; ElfSection* fDebugAbbrevSection; ElfSection* fDebugStringSection;