mirror of
https://github.com/SerenityOS/serenity
synced 2024-09-06 17:06:31 +00:00
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.
This commit is contained in:
parent
8e5b70a0ba
commit
ac53569bd1
|
@ -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
|
||||
|
|
49
Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp
Normal file
49
Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue