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:
@@ -11,6 +11,9 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
#include "AttributeClasses.h"
|
#include "AttributeClasses.h"
|
||||||
#include "AttributeValue.h"
|
#include "AttributeValue.h"
|
||||||
@@ -27,6 +30,30 @@
|
|||||||
#include "Variant.h"
|
#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
|
// #pragma mark - ExpressionEvaluationContext
|
||||||
|
|
||||||
|
|
||||||
@@ -281,7 +308,9 @@ private:
|
|||||||
DwarfFile::DwarfFile()
|
DwarfFile::DwarfFile()
|
||||||
:
|
:
|
||||||
fName(NULL),
|
fName(NULL),
|
||||||
|
fAlternateName(NULL),
|
||||||
fElfFile(NULL),
|
fElfFile(NULL),
|
||||||
|
fAlternateElfFile(NULL),
|
||||||
fDebugInfoSection(NULL),
|
fDebugInfoSection(NULL),
|
||||||
fDebugAbbrevSection(NULL),
|
fDebugAbbrevSection(NULL),
|
||||||
fDebugStringSection(NULL),
|
fDebugStringSection(NULL),
|
||||||
@@ -305,19 +334,24 @@ DwarfFile::~DwarfFile()
|
|||||||
delete table;
|
delete table;
|
||||||
|
|
||||||
if (fElfFile != NULL) {
|
if (fElfFile != NULL) {
|
||||||
fElfFile->PutSection(fDebugInfoSection);
|
ElfFile* debugInfoFile = fAlternateElfFile != NULL
|
||||||
fElfFile->PutSection(fDebugAbbrevSection);
|
? fAlternateElfFile : fElfFile;
|
||||||
fElfFile->PutSection(fDebugStringSection);
|
|
||||||
fElfFile->PutSection(fDebugRangesSection);
|
debugInfoFile->PutSection(fDebugInfoSection);
|
||||||
fElfFile->PutSection(fDebugLineSection);
|
debugInfoFile->PutSection(fDebugAbbrevSection);
|
||||||
fElfFile->PutSection(fDebugFrameSection);
|
debugInfoFile->PutSection(fDebugStringSection);
|
||||||
|
debugInfoFile->PutSection(fDebugRangesSection);
|
||||||
|
debugInfoFile->PutSection(fDebugLineSection);
|
||||||
|
debugInfoFile->PutSection(fDebugFrameSection);
|
||||||
fElfFile->PutSection(fEHFrameSection);
|
fElfFile->PutSection(fEHFrameSection);
|
||||||
fElfFile->PutSection(fDebugLocationSection);
|
debugInfoFile->PutSection(fDebugLocationSection);
|
||||||
fElfFile->PutSection(fDebugPublicTypesSection);
|
debugInfoFile->PutSection(fDebugPublicTypesSection);
|
||||||
delete fElfFile;
|
delete fElfFile;
|
||||||
|
delete fAlternateElfFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(fName);
|
free(fName);
|
||||||
|
free(fAlternateName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -337,23 +371,24 @@ DwarfFile::Load(const char* fileName)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// get the interesting sections
|
error = _LocateDebugInfo();
|
||||||
fDebugInfoSection = fElfFile->GetSection(".debug_info");
|
if (error != B_OK)
|
||||||
fDebugAbbrevSection = fElfFile->GetSection(".debug_abbrev");
|
return error;
|
||||||
if (fDebugInfoSection == NULL || fDebugAbbrevSection == NULL) {
|
|
||||||
WARNING("DwarfManager::File::Load(\"%s\"): no "
|
ElfFile* debugInfoFile = fAlternateElfFile != NULL
|
||||||
".debug_info or .debug_abbrev.\n", fileName);
|
? fAlternateElfFile : fElfFile;
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// non mandatory sections
|
// non mandatory sections
|
||||||
fDebugStringSection = fElfFile->GetSection(".debug_str");
|
fDebugStringSection = debugInfoFile->GetSection(".debug_str");
|
||||||
fDebugRangesSection = fElfFile->GetSection(".debug_ranges");
|
fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
|
||||||
fDebugLineSection = fElfFile->GetSection(".debug_line");
|
fDebugLineSection = debugInfoFile->GetSection(".debug_line");
|
||||||
fDebugFrameSection = fElfFile->GetSection(".debug_frame");
|
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");
|
fEHFrameSection = fElfFile->GetSection(".eh_frame");
|
||||||
fDebugLocationSection = fElfFile->GetSection(".debug_loc");
|
fDebugLocationSection = debugInfoFile->GetSection(".debug_loc");
|
||||||
fDebugPublicTypesSection = fElfFile->GetSection(".debug_pubtypes");
|
fDebugPublicTypesSection = debugInfoFile->GetSection(".debug_pubtypes");
|
||||||
|
|
||||||
// iterate through the debug info section
|
// iterate through the debug info section
|
||||||
DataReader dataReader(fDebugInfoSection->Data(),
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -150,12 +150,18 @@ private:
|
|||||||
const void*& _expression,
|
const void*& _expression,
|
||||||
off_t& _length) const;
|
off_t& _length) const;
|
||||||
|
|
||||||
|
status_t _LocateDebugInfo();
|
||||||
|
status_t _GetDebugInfoPath(const char* fileName,
|
||||||
|
BString& _infoPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DwarfFile::ExpressionEvaluationContext;
|
friend class DwarfFile::ExpressionEvaluationContext;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* fName;
|
char* fName;
|
||||||
|
char* fAlternateName;
|
||||||
ElfFile* fElfFile;
|
ElfFile* fElfFile;
|
||||||
|
ElfFile* fAlternateElfFile;
|
||||||
ElfSection* fDebugInfoSection;
|
ElfSection* fDebugInfoSection;
|
||||||
ElfSection* fDebugAbbrevSection;
|
ElfSection* fDebugAbbrevSection;
|
||||||
ElfSection* fDebugStringSection;
|
ElfSection* fDebugStringSection;
|
||||||
|
|||||||
Reference in New Issue
Block a user