1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-23 16:07:34 +00:00

LibDebug: Implement symbolication for x86_64

This commit is contained in:
Gunnar Beutner 2021-07-13 18:16:36 +02:00 committed by Andreas Kling
parent 567fa4b2f0
commit 2c41e89d08
9 changed files with 33 additions and 43 deletions

View file

@ -35,10 +35,6 @@ ELFObjectInfo const* Backtrace::object_info_for_region(ELF::Core::MemoryRegionIn
return nullptr; return nullptr;
auto image = make<ELF::Image>(file_or_error.value()->bytes()); auto image = make<ELF::Image>(file_or_error.value()->bytes());
#if !ARCH(I386)
// FIXME: Fix LibDebug
return nullptr;
#endif
auto info = make<ELFObjectInfo>(file_or_error.release_value(), make<Debug::DebugInfo>(move(image))); auto info = make<ELFObjectInfo>(file_or_error.release_value(), make<Debug::DebugInfo>(move(image)));
auto* info_ptr = info.ptr(); auto* info_ptr = info.ptr();
m_debug_info_cache.set(path, move(info)); m_debug_info_cache.set(path, move(info));
@ -81,11 +77,11 @@ Backtrace::~Backtrace()
{ {
} }
void Backtrace::add_entry(const Reader& coredump, FlatPtr eip) void Backtrace::add_entry(const Reader& coredump, FlatPtr ip)
{ {
auto* region = coredump.region_containing((FlatPtr)eip); auto* region = coredump.region_containing((FlatPtr)ip);
if (!region) { if (!region) {
m_entries.append({ eip, {}, {}, {} }); m_entries.append({ ip, {}, {}, {} });
return; return;
} }
auto object_name = region->object_name(); auto object_name = region->object_name();
@ -95,15 +91,9 @@ void Backtrace::add_entry(const Reader& coredump, FlatPtr eip)
if (!object_info) if (!object_info)
return; return;
#if ARCH(I386) auto function_name = object_info->debug_info->elf().symbolicate(ip - region->region_start);
auto function_name = object_info->debug_info->elf().symbolicate(eip - region->region_start); auto source_position = object_info->debug_info->get_source_position_with_inlines(ip - region->region_start);
auto source_position = object_info->debug_info->get_source_position_with_inlines(eip - region->region_start); m_entries.append({ ip, object_name, function_name, source_position });
#else
// FIXME: Fix symbolication.
auto function_name = "";
Debug::DebugInfo::SourcePositionWithInlines source_position;
#endif
m_entries.append({ eip, object_name, function_name, source_position });
} }
String Backtrace::Entry::to_string(bool color) const String Backtrace::Entry::to_string(bool color) const

View file

@ -42,7 +42,7 @@ public:
const Vector<Entry> entries() const { return m_entries; } const Vector<Entry> entries() const { return m_entries; }
private: private:
void add_entry(const Reader&, FlatPtr eip); void add_entry(const Reader&, FlatPtr ip);
ELFObjectInfo const* object_info_for_region(ELF::Core::MemoryRegionInfo const&); ELFObjectInfo const* object_info_for_region(ELF::Core::MemoryRegionInfo const&);
ELF::Core::ThreadInfo m_thread_info; ELF::Core::ThreadInfo m_thread_info;

View file

@ -60,9 +60,9 @@ void DebugInfo::parse_scopes_impl(Dwarf::DIE const& die)
dbgln_if(SPAM_DEBUG, "DWARF: Couldn't find attribute LowPc for scope"); dbgln_if(SPAM_DEBUG, "DWARF: Couldn't find attribute LowPc for scope");
return; return;
} }
scope.address_low = child.get_attribute(Dwarf::Attribute::LowPc).value().data.as_u32; scope.address_low = child.get_attribute(Dwarf::Attribute::LowPc).value().data.as_addr;
// The attribute name HighPc is confusing. In this context, it seems to actually be a positive offset from LowPc // The attribute name HighPc is confusing. In this context, it seems to actually be a positive offset from LowPc
scope.address_high = scope.address_low + child.get_attribute(Dwarf::Attribute::HighPc).value().data.as_u32; scope.address_high = scope.address_low + child.get_attribute(Dwarf::Attribute::HighPc).value().data.as_addr;
child.for_each_child([&](Dwarf::DIE const& variable_entry) { child.for_each_child([&](Dwarf::DIE const& variable_entry) {
if (!(variable_entry.tag() == Dwarf::EntryTag::Variable if (!(variable_entry.tag() == Dwarf::EntryTag::Variable
@ -78,7 +78,6 @@ void DebugInfo::parse_scopes_impl(Dwarf::DIE const& die)
void DebugInfo::prepare_lines() void DebugInfo::prepare_lines()
{ {
Vector<Dwarf::LineProgram::LineInfo> all_lines; Vector<Dwarf::LineProgram::LineInfo> all_lines;
m_dwarf_info.for_each_compilation_unit([&all_lines](Dwarf::CompilationUnit const& unit) { m_dwarf_info.for_each_compilation_unit([&all_lines](Dwarf::CompilationUnit const& unit) {
all_lines.extend(unit.line_program().lines()); all_lines.extend(unit.line_program().lines());
@ -115,7 +114,7 @@ void DebugInfo::prepare_lines()
}); });
} }
Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(u32 target_address) const Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(FlatPtr target_address) const
{ {
if (m_sorted_lines.is_empty()) if (m_sorted_lines.is_empty())
return {}; return {};
@ -219,7 +218,7 @@ static void parse_variable_location(Dwarf::DIE const& variable_die, DebugInfo::V
switch (location_info.value().type) { switch (location_info.value().type) {
case Dwarf::AttributeValue::Type::UnsignedNumber: case Dwarf::AttributeValue::Type::UnsignedNumber:
variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address;
variable_info.location_data.address = location_info.value().data.as_u32; variable_info.location_data.address = location_info.value().data.as_addr;
break; break;
case Dwarf::AttributeValue::Type::DwarfExpression: { case Dwarf::AttributeValue::Type::DwarfExpression: {
auto expression_bytes = ReadonlyBytes { location_info.value().data.as_raw_bytes.bytes, location_info.value().data.as_raw_bytes.length }; auto expression_bytes = ReadonlyBytes { location_info.value().data.as_raw_bytes.bytes, location_info.value().data.as_raw_bytes.length };
@ -228,7 +227,7 @@ static void parse_variable_location(Dwarf::DIE const& variable_die, DebugInfo::V
if (value.type != Dwarf::Expression::Type::None) { if (value.type != Dwarf::Expression::Type::None) {
VERIFY(value.type == Dwarf::Expression::Type::UnsignedInteger); VERIFY(value.type == Dwarf::Expression::Type::UnsignedInteger);
variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address;
variable_info.location_data.address = value.data.as_u32; variable_info.location_data.address = value.data.as_addr;
} }
break; break;
} }
@ -349,7 +348,7 @@ bool DebugInfo::is_variable_tag_supported(Dwarf::EntryTag const& tag)
|| tag == Dwarf::EntryTag::ArrayType; || tag == Dwarf::EntryTag::ArrayType;
} }
String DebugInfo::name_of_containing_function(u32 address) const String DebugInfo::name_of_containing_function(FlatPtr address) const
{ {
auto function = get_containing_function(address); auto function = get_containing_function(address);
if (!function.has_value()) if (!function.has_value())
@ -357,7 +356,7 @@ String DebugInfo::name_of_containing_function(u32 address) const
return function.value().name; return function.value().name;
} }
Optional<DebugInfo::VariablesScope> DebugInfo::get_containing_function(u32 address) const Optional<DebugInfo::VariablesScope> DebugInfo::get_containing_function(FlatPtr address) const
{ {
for (const auto& scope : m_scopes) { for (const auto& scope : m_scopes) {
if (!scope.is_function || address < scope.address_low || address >= scope.address_high) if (!scope.is_function || address < scope.address_low || address >= scope.address_high)
@ -386,7 +385,7 @@ DebugInfo::SourcePosition DebugInfo::SourcePosition::from_line_info(Dwarf::LineP
return { line.file, line.line, line.address }; return { line.file, line.line, line.address };
} }
DebugInfo::SourcePositionWithInlines DebugInfo::get_source_position_with_inlines(u32 address) const DebugInfo::SourcePositionWithInlines DebugInfo::get_source_position_with_inlines(FlatPtr address) const
{ {
// If the address is in an "inline chain", this is the inner-most inlined position. // If the address is in an "inline chain", this is the inner-most inlined position.
auto inner_source_position = get_source_position(address); auto inner_source_position = get_source_position(address);

View file

@ -31,7 +31,7 @@ public:
struct SourcePosition { struct SourcePosition {
FlyString file_path; FlyString file_path;
size_t line_number { 0 }; size_t line_number { 0 };
Optional<u32> address_of_first_statement; Optional<FlatPtr> address_of_first_statement;
SourcePosition() SourcePosition()
: SourcePosition(String::empty(), 0) : SourcePosition(String::empty(), 0)
@ -42,7 +42,7 @@ public:
, line_number(line_number) , line_number(line_number)
{ {
} }
SourcePosition(String file_path, size_t line_number, u32 address_of_first_statement) SourcePosition(String file_path, size_t line_number, FlatPtr address_of_first_statement)
: file_path(file_path) : file_path(file_path)
, line_number(line_number) , line_number(line_number)
, address_of_first_statement(address_of_first_statement) , address_of_first_statement(address_of_first_statement)
@ -65,7 +65,7 @@ public:
String type_name; String type_name;
LocationType location_type { LocationType::None }; LocationType location_type { LocationType::None };
union { union {
u32 address; FlatPtr address;
} location_data { 0 }; } location_data { 0 };
union { union {
@ -86,20 +86,20 @@ public:
struct VariablesScope { struct VariablesScope {
bool is_function { false }; bool is_function { false };
String name; String name;
u32 address_low { 0 }; FlatPtr address_low { 0 };
u32 address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope FlatPtr address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope
Vector<Dwarf::DIE> dies_of_variables; Vector<Dwarf::DIE> dies_of_variables;
}; };
NonnullOwnPtrVector<VariableInfo> get_variables_in_current_scope(PtraceRegisters const&) const; NonnullOwnPtrVector<VariableInfo> get_variables_in_current_scope(PtraceRegisters const&) const;
Optional<SourcePosition> get_source_position(u32 address) const; Optional<SourcePosition> get_source_position(FlatPtr address) const;
struct SourcePositionWithInlines { struct SourcePositionWithInlines {
Optional<SourcePosition> source_position; Optional<SourcePosition> source_position;
Vector<SourcePosition> inline_chain; Vector<SourcePosition> inline_chain;
}; };
SourcePositionWithInlines get_source_position_with_inlines(u32 address) const; SourcePositionWithInlines get_source_position_with_inlines(FlatPtr address) const;
struct SourcePositionAndAddress { struct SourcePositionAndAddress {
String file; String file;
@ -109,9 +109,9 @@ public:
Optional<SourcePositionAndAddress> get_address_from_source_position(const String& file, size_t line) const; Optional<SourcePositionAndAddress> get_address_from_source_position(const String& file, size_t line) const;
String name_of_containing_function(u32 address) const; String name_of_containing_function(FlatPtr address) const;
Vector<SourcePosition> source_lines_in_scope(const VariablesScope&) const; Vector<SourcePosition> source_lines_in_scope(const VariablesScope&) const;
Optional<VariablesScope> get_containing_function(u32 address) const; Optional<VariablesScope> get_containing_function(FlatPtr address) const;
private: private:
void prepare_variable_scopes(); void prepare_variable_scopes();

View file

@ -25,6 +25,7 @@ struct AttributeValue {
} type; } type;
union { union {
FlatPtr as_addr;
u32 as_u32; u32 as_u32;
i32 as_i32; i32 as_i32;
u64 as_u64; u64 as_u64;

View file

@ -47,7 +47,7 @@ void DwarfInfo::populate_compilation_units()
debug_info_stream >> compilation_unit_header; debug_info_stream >> compilation_unit_header;
VERIFY(compilation_unit_header.common.version <= 5); VERIFY(compilation_unit_header.common.version <= 5);
VERIFY(compilation_unit_header.address_size() == sizeof(u32)); VERIFY(compilation_unit_header.address_size() == sizeof(FlatPtr));
u32 length_after_header = compilation_unit_header.length() - (compilation_unit_header.header_size() - offsetof(CompilationUnitHeader, common.version)); u32 length_after_header = compilation_unit_header.length() - (compilation_unit_header.header_size() - offsetof(CompilationUnitHeader, common.version));
@ -102,11 +102,11 @@ AttributeValue DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t im
break; break;
} }
case AttributeDataForm::Addr: { case AttributeDataForm::Addr: {
u32 address; FlatPtr address;
debug_info_stream >> address; debug_info_stream >> address;
VERIFY(!debug_info_stream.has_any_error()); VERIFY(!debug_info_stream.has_any_error());
value.type = AttributeValue::Type::UnsignedNumber; value.type = AttributeValue::Type::UnsignedNumber;
value.data.as_u32 = address; value.data.as_addr = address;
break; break;
} }
case AttributeDataForm::SData: { case AttributeDataForm::SData: {
@ -250,7 +250,6 @@ void DwarfInfo::build_cached_dies() const
if (!start.has_value() || !end.has_value()) if (!start.has_value() || !end.has_value())
return {}; return {};
VERIFY(sizeof(FlatPtr) == sizeof(u32));
VERIFY(start->type == Dwarf::AttributeValue::Type::UnsignedNumber); VERIFY(start->type == Dwarf::AttributeValue::Type::UnsignedNumber);
// DW_AT_high_pc attribute can have different meanings depending on the attribute form. // DW_AT_high_pc attribute can have different meanings depending on the attribute form.
@ -258,7 +257,7 @@ void DwarfInfo::build_cached_dies() const
uint32_t range_end = 0; uint32_t range_end = 0;
if (end->form == Dwarf::AttributeDataForm::Addr) if (end->form == Dwarf::AttributeDataForm::Addr)
range_end = end->data.as_u32; range_end = end->data.as_addr;
else else
range_end = start->data.as_u32 + end->data.as_u32; range_end = start->data.as_u32 + end->data.as_u32;

View file

@ -22,6 +22,7 @@ enum class Type {
struct Value { struct Value {
Type type; Type type;
union { union {
FlatPtr as_addr;
u32 as_u32; u32 as_u32;
} data { 0 }; } data { 0 };
}; };

View file

@ -174,7 +174,7 @@ void LineProgram::handle_extended_opcode()
break; break;
} }
default: default:
dbgln_if(DWARF_DEBUG, "offset: {:p}", m_stream.offset()); dbgln("Encountered unknown sub opcode {} at stream offset {:p}", sub_opcode, m_stream.offset());
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
} }

View file

@ -109,7 +109,7 @@ public:
explicit LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream); explicit LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream);
struct LineInfo { struct LineInfo {
u32 address { 0 }; FlatPtr address { 0 };
FlyString file; FlyString file;
size_t line { 0 }; size_t line { 0 };
}; };
@ -176,7 +176,7 @@ private:
Vector<FileEntry> m_source_files; Vector<FileEntry> m_source_files;
// The registers of the "line program" virtual machine // The registers of the "line program" virtual machine
u32 m_address { 0 }; FlatPtr m_address { 0 };
size_t m_line { 0 }; size_t m_line { 0 };
size_t m_file_index { 0 }; size_t m_file_index { 0 };
bool m_is_statement { false }; bool m_is_statement { false };