summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2021-10-09 17:38:26 +0200
committerLinus Groh <mail@linusgroh.de>2021-10-17 17:09:58 +0100
commitac53569bd11d1425d5ff77bd0b8a22d26222a7ca (patch)
treeb833ffe53c62287651002f2a6977725c2149f1b4
parent8e5b70a0ba752a4efe9e00bb17691945bfa97911 (diff)
downloadserenity-ac53569bd11d1425d5ff77bd0b8a22d26222a7ca.zip
LibDebug: Support `addrx*`, `strx*` and `rnglistx` forms
These forms were introduced in DWARF5, and have a fair deal of advantages over the more traditional encodings: they reduce the size of the binary and the number of relocations. GCC does not emit these with `-g1` by default, but Clang does at all debug levels.
-rw-r--r--Userland/Libraries/LibDebug/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp49
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/AttributeValue.h4
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp66
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h18
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp74
-rw-r--r--Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h4
7 files changed, 213 insertions, 3 deletions
diff --git a/Userland/Libraries/LibDebug/CMakeLists.txt b/Userland/Libraries/LibDebug/CMakeLists.txt
index e03bc1f625..f823a550d5 100644
--- a/Userland/Libraries/LibDebug/CMakeLists.txt
+++ b/Userland/Libraries/LibDebug/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SOURCES
DebugSession.cpp
Dwarf/AbbreviationsMap.cpp
Dwarf/AddressRanges.cpp
+ Dwarf/AttributeValue.cpp
Dwarf/CompilationUnit.cpp
Dwarf/DIE.cpp
Dwarf/DwarfInfo.cpp
diff --git a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp
new file mode 100644
index 0000000000..c81809f04f
--- /dev/null
+++ b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2021, Daniel Bertalan <dani@danielbertalan.dev>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "AttributeValue.h"
+#include "CompilationUnit.h"
+
+namespace Debug::Dwarf {
+
+FlatPtr AttributeValue::as_addr() const
+{
+ switch (m_form) {
+ case AttributeDataForm::Addr:
+ return m_data.as_addr;
+ case AttributeDataForm::AddrX:
+ case AttributeDataForm::AddrX1:
+ case AttributeDataForm::AddrX2:
+ case AttributeDataForm::AddrX3:
+ case AttributeDataForm::AddrX4: {
+ auto index = m_data.as_unsigned;
+ return m_compilation_unit->get_address(index);
+ }
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+
+char const* AttributeValue::as_string() const
+{
+ switch (m_form) {
+ case AttributeDataForm::String:
+ case AttributeDataForm::StringPointer:
+ case AttributeDataForm::LineStrP:
+ return m_data.as_string;
+ case AttributeDataForm::StrX:
+ case AttributeDataForm::StrX1:
+ case AttributeDataForm::StrX2:
+ case AttributeDataForm::StrX3:
+ case AttributeDataForm::StrX4: {
+ auto index = m_data.as_unsigned;
+ return m_compilation_unit->get_string(index);
+ }
+ default:
+ VERIFY_NOT_REACHED();
+ }
+}
+}
diff --git a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h
index c6cd967384..9343328abf 100644
--- a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h
+++ b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h
@@ -33,10 +33,10 @@ public:
Type type() const { return m_type; }
AttributeDataForm form() const { return m_form; }
- FlatPtr as_addr() const { return m_data.as_addr; }
+ FlatPtr as_addr() const;
u64 as_unsigned() const { return m_data.as_unsigned; }
i64 as_signed() const { return m_data.as_signed; }
- const char* as_string() const { return m_data.as_string; }
+ const char* as_string() const;
bool as_bool() const { return m_data.as_bool; }
ReadonlyBytes as_raw_bytes() const { return m_data.as_raw_bytes; }
diff --git a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp
index e7cf1de168..d8b0343d76 100644
--- a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp
+++ b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp
@@ -44,4 +44,70 @@ Optional<FlatPtr> CompilationUnit::base_address() const
return m_cached_base_address;
}
+u64 CompilationUnit::address_table_base() const
+{
+ if (m_has_cached_address_table_base)
+ return m_cached_address_table_base;
+
+ auto die = root_die();
+ auto res = die.get_attribute(Attribute::AddrBase);
+ if (res.has_value()) {
+ VERIFY(res->form() == AttributeDataForm::SecOffset);
+ m_cached_address_table_base = res->as_unsigned();
+ }
+ m_has_cached_address_table_base = true;
+ return m_cached_address_table_base;
+}
+
+u64 CompilationUnit::string_offsets_base() const
+{
+ if (m_has_cached_string_offsets_base)
+ return m_cached_string_offsets_base;
+
+ auto die = root_die();
+ auto res = die.get_attribute(Attribute::StrOffsetsBase);
+ if (res.has_value()) {
+ VERIFY(res->form() == AttributeDataForm::SecOffset);
+ m_cached_string_offsets_base = res->as_unsigned();
+ }
+ m_has_cached_string_offsets_base = true;
+ return m_cached_string_offsets_base;
+}
+
+u64 CompilationUnit::range_lists_base() const
+{
+ if (m_has_cached_range_lists_base)
+ return m_cached_range_lists_base;
+
+ auto die = root_die();
+ auto res = die.get_attribute(Attribute::RngListsBase);
+ if (res.has_value()) {
+ VERIFY(res->form() == AttributeDataForm::SecOffset);
+ m_cached_range_lists_base = res->as_unsigned();
+ }
+ m_has_cached_range_lists_base = true;
+ return m_cached_range_lists_base;
+}
+
+FlatPtr CompilationUnit::get_address(size_t index) const
+{
+ auto base = address_table_base();
+ auto debug_addr_data = dwarf_info().debug_addr_data();
+ VERIFY(base < debug_addr_data.size());
+ auto addresses = reinterpret_cast<FlatPtr const*>(debug_addr_data.offset(base));
+ VERIFY(base + index * sizeof(FlatPtr) < debug_addr_data.size());
+ return addresses[index];
+}
+
+char const* CompilationUnit::get_string(size_t index) const
+{
+ auto base = string_offsets_base();
+ auto debug_str_offsets_data = dwarf_info().debug_str_offsets_data();
+ VERIFY(base < debug_str_offsets_data.size());
+ // FIXME: This assumes DWARF32
+ auto offsets = reinterpret_cast<u32 const*>(debug_str_offsets_data.offset(base));
+ VERIFY(base + index * sizeof(u32) < debug_str_offsets_data.size());
+ auto offset = offsets[index];
+ return reinterpret_cast<char const*>(dwarf_info().debug_strings_data().offset(offset));
+}
}
diff --git a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h
index c860d1237a..483148e061 100644
--- a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h
+++ b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h
@@ -31,19 +31,35 @@ public:
DIE root_die() const;
DIE get_die_at_offset(u32 offset) const;
+ FlatPtr get_address(size_t index) const;
+ char const* get_string(size_t index) const;
+
DwarfInfo const& dwarf_info() const { return m_dwarf_info; }
AbbreviationsMap const& abbreviations_map() const { return m_abbreviations; }
LineProgram const& line_program() const { return *m_line_program; }
Optional<FlatPtr> base_address() const;
+ // DW_AT_addr_base
+ u64 address_table_base() const;
+ // DW_AT_str_offsets_base
+ u64 string_offsets_base() const;
+ // DW_AT_rnglists_base
+ u64 range_lists_base() const;
+
private:
DwarfInfo const& m_dwarf_info;
u32 m_offset { 0 };
CompilationUnitHeader m_header;
AbbreviationsMap m_abbreviations;
NonnullOwnPtr<LineProgram> m_line_program;
- mutable bool m_has_cached_base_address { false };
+ mutable bool m_has_cached_base_address : 1 { false };
+ mutable bool m_has_cached_address_table_base : 1 { false };
+ mutable bool m_has_cached_string_offsets_base : 1 { false };
+ mutable bool m_has_cached_range_lists_base : 1 { false };
mutable Optional<FlatPtr> m_cached_base_address;
+ mutable u64 m_cached_address_table_base { 0 };
+ mutable u64 m_cached_string_offsets_base { 0 };
+ mutable u64 m_cached_range_lists_base { 0 };
};
}
diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp
index 3f6ae36dd4..fbda566720 100644
--- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp
+++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp
@@ -23,6 +23,8 @@ DwarfInfo::DwarfInfo(ELF::Image const& elf)
m_debug_line_data = section_data(".debug_line"sv);
m_debug_line_strings_data = section_data(".debug_line_str"sv);
m_debug_range_lists_data = section_data(".debug_rnglists"sv);
+ m_debug_str_offsets_data = section_data(".debug_str_offsets"sv);
+ m_debug_addr_data = section_data(".debug_addr"sv);
populate_compilation_units();
}
@@ -230,6 +232,78 @@ AttributeValue DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t im
value.m_data.as_signed = implicit_const_value;
break;
}
+ case AttributeDataForm::StrX1: {
+ u8 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::String;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::StrX2: {
+ u16 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::String;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::StrX4: {
+ u32 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::String;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::StrX: {
+ size_t index;
+ debug_info_stream.read_LEB128_unsigned(index);
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::String;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::AddrX1: {
+ u8 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::Address;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::AddrX2: {
+ u16 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::Address;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::AddrX4: {
+ u32 index;
+ debug_info_stream >> index;
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::Address;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::AddrX: {
+ size_t index;
+ debug_info_stream.read_LEB128_unsigned(index);
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::Address;
+ value.m_data.as_unsigned = index;
+ break;
+ }
+ case AttributeDataForm::RngListX: {
+ size_t index;
+ debug_info_stream.read_LEB128_unsigned(index);
+ VERIFY(!debug_info_stream.has_any_error());
+ value.m_type = AttributeValue::Type::UnsignedNumber;
+ value.m_data.as_unsigned = index;
+ break;
+ }
default:
dbgln("Unimplemented AttributeDataForm: {}", (u32)form);
VERIFY_NOT_REACHED();
diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h
index 24f7e9a2d3..70c63452cc 100644
--- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h
+++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h
@@ -31,6 +31,8 @@ public:
ReadonlyBytes debug_strings_data() const { return m_debug_strings_data; }
ReadonlyBytes debug_line_strings_data() const { return m_debug_line_strings_data; }
ReadonlyBytes debug_range_lists_data() const { return m_debug_range_lists_data; }
+ ReadonlyBytes debug_str_offsets_data() const { return m_debug_str_offsets_data; }
+ ReadonlyBytes debug_addr_data() const { return m_debug_addr_data; }
template<typename Callback>
void for_each_compilation_unit(Callback) const;
@@ -60,6 +62,8 @@ private:
ReadonlyBytes m_debug_line_data;
ReadonlyBytes m_debug_line_strings_data;
ReadonlyBytes m_debug_range_lists_data;
+ ReadonlyBytes m_debug_str_offsets_data;
+ ReadonlyBytes m_debug_addr_data;
NonnullOwnPtrVector<Dwarf::CompilationUnit> m_compilation_units;