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:
David Karoly 2023-10-03 10:29:21 +02:00 committed by Rene Gollent
parent ae2049aa4f
commit 006478bfce
2 changed files with 275 additions and 27 deletions

View File

@ -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();

View File

@ -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;