⛏️ index : haiku.git

author David Karoly <karolyd577@gmail.com> 2023-10-03 10:29:21.0 +02:00:00
committer David Karoly <karolyd577@gmail.com> 2023-10-19 16:27:43.0 +00:00:00
commit
fab984f6062749752acb2e6a21e146848e888d1d [patch]
tree
0ec928ff526dbd3164eaba852faaa9165220f053
parent
05e56efe6975c48abca8229473990fddf5321d67
download
fab984f6062749752acb2e6a21e146848e888d1d.tar.gz

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>
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7049
Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>

Diff

 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 f07dafa..709b3ad 100644
--- a/src/kits/debugger/dwarf/DwarfFile.cpp
+++ b/src/kits/debugger/dwarf/DwarfFile.cpp
@@ -495,6 +495,7 @@
	fDebugStringSection(NULL),
	fDebugRangesSection(NULL),
	fDebugLineSection(NULL),
	fDebugLineStrSection(NULL),
	fDebugFrameSection(NULL),
	fEHFrameSection(NULL),
	fDebugLocationSection(NULL),
@@ -526,6 +527,7 @@
		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 @@
	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) {
@@ -1759,6 +1762,96 @@


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)
{
	off_t offset = unit->UnitEntry()->StatementListOffset();
@@ -1779,10 +1872,29 @@
	// 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)
@@ -1829,6 +1941,10 @@

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

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

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

		uint8 dirCount = dataReader.Read<uint8>(0);
		TRACE_LINES("  dirCount:             %u\n", dirCount);

		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->AddDirectory(directory))
			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);

	// 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 (!unit->AddDirectory(directory))
					return B_NO_MEMORY;

		if (dataReader.HasOverflow())
			return B_BAD_DATA;
			}
		}

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

		TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 ", mtime: %" B_PRIu64
			", length: %" B_PRIu64 "\n", file, dirIndex, modificationTime,
			fileLength);
			if ((fileName != NULL) && (dirIndex != 0xffffffffffffffffull)) {
				TRACE_LINES("    \"%s\", dir index: %" B_PRIu64 "\n",
					fileName, dirIndex);

		if (!unit->AddFile(file, dirIndex))
			return B_NO_MEMORY;
				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 7d54a4a..e4f4023 100644
--- a/src/kits/debugger/dwarf/DwarfFile.h
+++ b/src/kits/debugger/dwarf/DwarfFile.h
@@ -135,6 +135,12 @@
									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 @@
			ElfSection*			fDebugStringSection;
			ElfSection*			fDebugRangesSection;
			ElfSection*			fDebugLineSection;
			ElfSection*			fDebugLineStrSection;
			ElfSection*			fDebugFrameSection;
			ElfSection*			fEHFrameSection;
			ElfSection*			fDebugLocationSection;