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:
parent
567fa4b2f0
commit
2c41e89d08
9 changed files with 33 additions and 43 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 };
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue