Debugger: implement DWARFv5 line-info handling
* add new field for .debug_line_str section * implement reading string and int values tagged with DW_FORM_* * skip new fields addressSize, segmentSelectorSize in line info header * parse directories and file names according to new syntax * enable line-info parsing up to version 5 Change-Id: I1dd7e0d834c73f6d72b7115c7ded9f868be84a3d Reviewed-on: https://review.haiku-os.org/c/haiku/+/6978 Reviewed-by: Rene Gollent <rene@gollent.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
ae2049aa4f
commit
006478bfce
@ -495,6 +495,7 @@ DwarfFile::DwarfFile()
|
||||
fDebugStringSection(NULL),
|
||||
fDebugRangesSection(NULL),
|
||||
fDebugLineSection(NULL),
|
||||
fDebugLineStrSection(NULL),
|
||||
fDebugFrameSection(NULL),
|
||||
fEHFrameSection(NULL),
|
||||
fDebugLocationSection(NULL),
|
||||
@ -526,6 +527,7 @@ DwarfFile::~DwarfFile()
|
||||
debugInfoFile->PutSection(fDebugStringSection);
|
||||
debugInfoFile->PutSection(fDebugRangesSection);
|
||||
debugInfoFile->PutSection(fDebugLineSection);
|
||||
debugInfoFile->PutSection(fDebugLineStrSection);
|
||||
debugInfoFile->PutSection(fDebugFrameSection);
|
||||
fElfFile->PutSection(fEHFrameSection);
|
||||
debugInfoFile->PutSection(fDebugLocationSection);
|
||||
@ -589,6 +591,7 @@ DwarfFile::Load(uint8 addressSize, const BString& externalInfoFilePath)
|
||||
fDebugStringSection = debugInfoFile->GetSection(".debug_str");
|
||||
fDebugRangesSection = debugInfoFile->GetSection(".debug_ranges");
|
||||
fDebugLineSection = debugInfoFile->GetSection(".debug_line");
|
||||
fDebugLineStrSection = debugInfoFile->GetSection(".debug_line_str");
|
||||
fDebugFrameSection = debugInfoFile->GetSection(".debug_frame");
|
||||
|
||||
if (fDebugFrameSection != NULL) {
|
||||
@ -1758,6 +1761,96 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfFile::_ParseLineInfoFormatString(CompilationUnit* unit, DataReader &dataReader,
|
||||
uint64 format, const char*& value)
|
||||
{
|
||||
switch (format) {
|
||||
case DW_FORM_string:
|
||||
value = dataReader.ReadString();
|
||||
break;
|
||||
case DW_FORM_line_strp:
|
||||
{
|
||||
if (fDebugLineStrSection == NULL) {
|
||||
WARNING("Invalid DW_FORM_line_strp: no line_str section!\n");
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
target_addr_t offset = unit->IsDwarf64()
|
||||
? dataReader.Read<uint64>(0)
|
||||
: dataReader.Read<uint32>(0);
|
||||
if (offset > fDebugLineStrSection->Size()) {
|
||||
WARNING("Invalid DW_FORM_line_strp offset: %" B_PRIu64 "\n",
|
||||
offset);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
value = (const char*)fDebugLineStrSection->Data() + offset;
|
||||
break;
|
||||
}
|
||||
case DW_FORM_strp:
|
||||
{
|
||||
if (fDebugStringSection == NULL) {
|
||||
WARNING("Invalid DW_FORM_strp: no string section!\n");
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
target_addr_t offset = unit->IsDwarf64()
|
||||
? dataReader.Read<uint64>(0)
|
||||
: dataReader.Read<uint32>(0);
|
||||
if (offset > fDebugStringSection->Size()) {
|
||||
WARNING("Invalid DW_FORM_strp offset: %" B_PRIu64 "\n",
|
||||
offset);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
value = (const char*)fDebugStringSection->Data() + offset;
|
||||
break;
|
||||
}
|
||||
case DW_FORM_strp_sup:
|
||||
return B_UNSUPPORTED;
|
||||
break;
|
||||
default:
|
||||
WARNING("DwarfFile::_ParseLineInfoFormatString(\"%s\"): unsupported "
|
||||
"field type %" PRIu64 "\n", fName, format);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfFile::_ParseLineInfoFormatUint(CompilationUnit* unit, DataReader &dataReader,
|
||||
uint64 format, uint64 &value)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case DW_FORM_data1:
|
||||
value = dataReader.Read<uint8>(0);
|
||||
break;
|
||||
case DW_FORM_data2:
|
||||
value = dataReader.Read<uint16>(0);
|
||||
break;
|
||||
case DW_FORM_data4:
|
||||
value = dataReader.Read<uint32>(0);
|
||||
break;
|
||||
case DW_FORM_data8:
|
||||
value = dataReader.Read<uint64>(0);
|
||||
break;
|
||||
case DW_FORM_udata:
|
||||
value = dataReader.ReadUnsignedLEB128(0);
|
||||
break;
|
||||
default:
|
||||
WARNING("DwarfFile::_ParseLineInfoFormatUint(\"%s\"): unsupported "
|
||||
"field type %" PRIu64 "\n", fName, format);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
||||
{
|
||||
@ -1779,12 +1872,31 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
||||
// version (uhalf)
|
||||
uint16 version = dataReader.Read<uint16>(0);
|
||||
|
||||
if (version < 2 || version > 4) {
|
||||
if (version < 2 || version > 5) {
|
||||
WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
|
||||
"version %d\n", fName, version);
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
uint8 addressSize = unit->AddressSize();
|
||||
uint8 segmentSelectorSize = 0;
|
||||
|
||||
if (version >= 5) {
|
||||
addressSize = dataReader.Read<uint8>(0);
|
||||
if (addressSize != 4 && addressSize != 8) {
|
||||
WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
|
||||
"addressSize %d\n", fName, addressSize);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
segmentSelectorSize = dataReader.Read<uint8>(0);
|
||||
if (segmentSelectorSize != 0) {
|
||||
WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
|
||||
"segmentSelectorSize %d\n", fName, segmentSelectorSize);
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
// header_length (4/8)
|
||||
uint64 headerLength = dwarf64
|
||||
? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
|
||||
@ -1829,6 +1941,10 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
||||
|
||||
TRACE_LINES(" unitLength: %" B_PRIu64 "\n", unitLength);
|
||||
TRACE_LINES(" version: %u\n", version);
|
||||
if (version >= 5) {
|
||||
TRACE_LINES(" addressSize: %u\n", addressSize);
|
||||
TRACE_LINES(" segmentSelectorSize: %u\n", segmentSelectorSize);
|
||||
}
|
||||
TRACE_LINES(" headerLength: %" B_PRIu64 "\n", headerLength);
|
||||
TRACE_LINES(" minInstructionLength: %u\n", minInstructionLength);
|
||||
if (version >= 4)
|
||||
@ -1838,37 +1954,162 @@ DwarfFile::_ParseLineInfo(CompilationUnit* unit)
|
||||
TRACE_LINES(" lineRange: %u\n", lineRange);
|
||||
TRACE_LINES(" opcodeBase: %u\n", opcodeBase);
|
||||
|
||||
// include directories
|
||||
TRACE_LINES(" include directories:\n");
|
||||
while (const char* directory = dataReader.ReadString()) {
|
||||
if (*directory == '\0')
|
||||
break;
|
||||
TRACE_LINES(" \"%s\"\n", directory);
|
||||
if (version >= 5) {
|
||||
uint8 dirEntryFormatCount = dataReader.Read<uint8>(0);
|
||||
TRACE_LINES(" dirEntryFormatCount: %u\n", dirEntryFormatCount);
|
||||
|
||||
if (!unit->AddDirectory(directory))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
off_t dirEntryFormatOffset = dataReader.Offset();
|
||||
for (unsigned int i = 0; i < dirEntryFormatCount; i++) {
|
||||
TRACE_LINES_ONLY(uint64 content =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 format =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
|
||||
// file names
|
||||
TRACE_LINES(" files:\n");
|
||||
while (const char* file = dataReader.ReadString()) {
|
||||
if (*file == '\0')
|
||||
break;
|
||||
uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 modificationTime =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 fileLength =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES(" content: %" B_PRIu64 "\n", content);
|
||||
TRACE_LINES(" format: %" B_PRIu64 "\n", format);
|
||||
}
|
||||
off_t dirEntryFormatLength = dataReader.Offset() - dirEntryFormatOffset;
|
||||
DataReader dirEntryFormatReader = dataReader.RestrictedReader(-dirEntryFormatLength,
|
||||
dirEntryFormatLength);
|
||||
|
||||
if (dataReader.HasOverflow())
|
||||
return B_BAD_DATA;
|
||||
uint8 dirCount = dataReader.Read<uint8>(0);
|
||||
TRACE_LINES(" dirCount: %u\n", dirCount);
|
||||
|
||||
TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
|
||||
", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
|
||||
fileLength);
|
||||
for (unsigned int i = 0; i < dirCount; i++) {
|
||||
dirEntryFormatReader.SeekAbsolute(0);
|
||||
for (unsigned int j = 0; j < dirEntryFormatCount; j++) {
|
||||
uint64 content = dirEntryFormatReader.ReadUnsignedLEB128(0);
|
||||
uint64 format = dirEntryFormatReader.ReadUnsignedLEB128(0);
|
||||
if (content != DW_LNCT_path) {
|
||||
WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
|
||||
"field in dirs %" PRIu64 "\n", fName, content);
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (!unit->AddFile(file, dirIndex))
|
||||
return B_NO_MEMORY;
|
||||
const char* directory;
|
||||
status_t res = _ParseLineInfoFormatString(unit, dataReader, format, directory);
|
||||
if (res != B_OK)
|
||||
return res;
|
||||
TRACE_LINES(" \"%s\"\n", directory);
|
||||
|
||||
if (!unit->AddDirectory(directory))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
uint8 fileNameEntryFormatCount = dataReader.Read<uint8>(0);
|
||||
TRACE_LINES(" fileNameFormatCount: %u\n", fileNameEntryFormatCount);
|
||||
|
||||
off_t fileNameEntryFormatOffset = dataReader.Offset();
|
||||
for (unsigned int i = 0; i < fileNameEntryFormatCount; i++) {
|
||||
TRACE_LINES_ONLY(uint64 content =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 format =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
|
||||
TRACE_LINES(" content: %" B_PRIu64 "\n", content);
|
||||
TRACE_LINES(" format: %" B_PRIu64 "\n", format);
|
||||
}
|
||||
off_t fileNameEntryFormatLength = dataReader.Offset() - fileNameEntryFormatOffset;
|
||||
DataReader fileNameEntryFormatReader = dataReader.RestrictedReader(-fileNameEntryFormatLength,
|
||||
fileNameEntryFormatLength);
|
||||
|
||||
uint8 fileNameCount = dataReader.Read<uint8>(0);
|
||||
TRACE_LINES(" fileNameCount: %u\n", dirCount);
|
||||
|
||||
for (unsigned int i = 0; i < fileNameCount; i++) {
|
||||
const char* fileName = NULL;
|
||||
uint64 dirIndex = 0xffffffffffffffffull;
|
||||
uint64 modificationTime = 0;
|
||||
uint64 fileLength = 0;
|
||||
|
||||
fileNameEntryFormatReader.SeekAbsolute(0);
|
||||
for (unsigned int j = 0; j < fileNameEntryFormatCount; j++) {
|
||||
|
||||
uint64 content = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
|
||||
uint64 format = fileNameEntryFormatReader.ReadUnsignedLEB128(0);
|
||||
status_t res;
|
||||
switch (content) {
|
||||
case DW_LNCT_path:
|
||||
res = _ParseLineInfoFormatString(unit, dataReader,
|
||||
format, fileName);
|
||||
if (res != B_OK)
|
||||
return res;
|
||||
break;
|
||||
case DW_LNCT_directory_index:
|
||||
res = _ParseLineInfoFormatUint(unit, dataReader,
|
||||
format, dirIndex);
|
||||
if (res != B_OK)
|
||||
return res;
|
||||
break;
|
||||
case DW_LNCT_timestamp:
|
||||
res = _ParseLineInfoFormatUint(unit, dataReader,
|
||||
format, modificationTime);
|
||||
if (res != B_OK)
|
||||
return res;
|
||||
break;
|
||||
case DW_LNCT_size:
|
||||
res = _ParseLineInfoFormatUint(unit, dataReader,
|
||||
format, fileLength);
|
||||
if (res != B_OK)
|
||||
return res;
|
||||
break;
|
||||
case DW_LNCT_MD5:
|
||||
if (format != DW_FORM_data16)
|
||||
return B_BAD_DATA;
|
||||
|
||||
dataReader.Skip(16);
|
||||
break;
|
||||
default:
|
||||
WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported "
|
||||
"field in files %" PRIu64 "\n",
|
||||
fName, content);
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
if ((fileName != NULL) && (dirIndex != 0xffffffffffffffffull)) {
|
||||
TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 "\n",
|
||||
fileName, dirIndex);
|
||||
|
||||
if (!unit->AddFile(fileName, dirIndex))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// include directories
|
||||
TRACE_LINES(" include directories:\n");
|
||||
while (const char* directory = dataReader.ReadString()) {
|
||||
if (*directory == '\0')
|
||||
break;
|
||||
TRACE_LINES(" \"%s\"\n", directory);
|
||||
|
||||
if (!unit->AddDirectory(directory))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
// file names
|
||||
TRACE_LINES(" files:\n");
|
||||
while (const char* file = dataReader.ReadString()) {
|
||||
if (*file == '\0')
|
||||
break;
|
||||
uint64 dirIndex = dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 modificationTime =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
TRACE_LINES_ONLY(uint64 fileLength =)
|
||||
dataReader.ReadUnsignedLEB128(0);
|
||||
|
||||
if (dataReader.HasOverflow())
|
||||
return B_BAD_DATA;
|
||||
|
||||
TRACE_LINES(" \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
|
||||
", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
|
||||
fileLength);
|
||||
|
||||
if (!unit->AddFile(file, dirIndex))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
off_t readerOffset = dataReader.Offset();
|
||||
|
@ -135,6 +135,12 @@ private:
|
||||
DebugInfoEntry* entry,
|
||||
AbbreviationEntry& abbreviationEntry);
|
||||
|
||||
status_t _ParseLineInfoFormatString(CompilationUnit* unit,
|
||||
DataReader &dataReader,
|
||||
uint64 format, const char*& value);
|
||||
status_t _ParseLineInfoFormatUint(CompilationUnit* unit,
|
||||
DataReader &dataReader,
|
||||
uint64 format, uint64 &value);
|
||||
status_t _ParseLineInfo(CompilationUnit* unit);
|
||||
|
||||
status_t _UnwindCallFrame(CompilationUnit* unit,
|
||||
@ -211,6 +217,7 @@ private:
|
||||
ElfSection* fDebugStringSection;
|
||||
ElfSection* fDebugRangesSection;
|
||||
ElfSection* fDebugLineSection;
|
||||
ElfSection* fDebugLineStrSection;
|
||||
ElfSection* fDebugFrameSection;
|
||||
ElfSection* fEHFrameSection;
|
||||
ElfSection* fDebugLocationSection;
|
||||
|
Loading…
Reference in New Issue
Block a user