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.
This commit is contained in:
Rene Gollent
2012-07-29 07:12:49 -04:00
parent 200dec066f
commit 224f75100b
2 changed files with 167 additions and 22 deletions
+161 -22
View File
@@ -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;
}
+6
View File
@@ -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;