From 006478bfce5d82619a4dab86c8cf54890ea2a525 Mon Sep 17 00:00:00 2001 From: David Karoly Date: Tue, 3 Oct 2023 10:29:21 +0200 Subject: [PATCH] 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 Tested-by: Commit checker robot --- src/kits/debugger/dwarf/DwarfFile.cpp | 295 +++++++++++++++++++++++--- src/kits/debugger/dwarf/DwarfFile.h | 7 + 2 files changed, 275 insertions(+), 27 deletions(-) diff --git a/src/kits/debugger/dwarf/DwarfFile.cpp b/src/kits/debugger/dwarf/DwarfFile.cpp index f07dafacc4..709b3ad1a2 100644 --- a/src/kits/debugger/dwarf/DwarfFile.cpp +++ b/src/kits/debugger/dwarf/DwarfFile.cpp @@ -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(0) + : dataReader.Read(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(0) + : dataReader.Read(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(0); + break; + case DW_FORM_data2: + value = dataReader.Read(0); + break; + case DW_FORM_data4: + value = dataReader.Read(0); + break; + case DW_FORM_data8: + value = dataReader.Read(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(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(0); + if (addressSize != 4 && addressSize != 8) { + WARNING("DwarfFile::_ParseLineInfo(\"%s\"): unsupported " + "addressSize %d\n", fName, addressSize); + return B_BAD_DATA; + } + + segmentSelectorSize = dataReader.Read(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(0) : (uint64)dataReader.Read(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(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(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(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(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(); diff --git a/src/kits/debugger/dwarf/DwarfFile.h b/src/kits/debugger/dwarf/DwarfFile.h index 7d54a4a9ba..e4f4023297 100644 --- a/src/kits/debugger/dwarf/DwarfFile.h +++ b/src/kits/debugger/dwarf/DwarfFile.h @@ -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;