From a45b5ccd969443aef7a4afce8bd43d512ca74b1a Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 19 Jun 2021 12:12:52 +0300 Subject: [PATCH] LibDebug: Add DebugInfo::get_source_position_with_inlines This function returns the source position of a given address in the program. If that address exists in an inline chain, then it also returns the source positions that are in the chain. --- Userland/Libraries/LibDebug/DebugInfo.cpp | 75 ++++++++++++++++++++++- Userland/Libraries/LibDebug/DebugInfo.h | 11 +++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibDebug/DebugInfo.cpp b/Userland/Libraries/LibDebug/DebugInfo.cpp index cf11542d1b0..3600ef22645 100644 --- a/Userland/Libraries/LibDebug/DebugInfo.cpp +++ b/Userland/Libraries/LibDebug/DebugInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Itamar S. + * Copyright (c) 2020-2021, Itamar S. * * SPDX-License-Identifier: BSD-2-Clause */ @@ -380,4 +380,77 @@ DebugInfo::SourcePosition DebugInfo::SourcePosition::from_line_info(const Dwarf: return { line.file, line.line, { line.address } }; } +DebugInfo::SourcePositionWithInlines DebugInfo::get_source_position_with_inlines(u32 address) const +{ + // If the address is in an "inline chain", this is the inner-most inlined position. + auto inner_source_position = get_source_position(address); + + auto die = m_dwarf_info.get_die_at_address(address); + if (!die.has_value() || die->tag() == Dwarf::EntryTag::SubroutineType) { + // Inline chain is empty + return SourcePositionWithInlines { inner_source_position, {} }; + } + + Vector inline_chain; + + auto insert_to_chain = [&](const Dwarf::DIE& die) { + auto caller_source_path = get_source_path_of_inline(die); + auto caller_line = get_line_of_inline(die); + + if (!caller_source_path.has_value() || !caller_line.has_value()) { + return; + } + + inline_chain.append({ String::formatted("{}/{}", caller_source_path->directory, caller_source_path->filename), caller_line.value() }); + }; + + while (die->tag() == Dwarf::EntryTag::InlinedSubroutine) { + insert_to_chain(*die); + + if (!die->parent_offset().has_value()) { + break; + } + + auto parent = die->compilation_unit().dwarf_info().get_cached_die_at_offset(die->parent_offset().value()); + if (!parent.has_value()) { + break; + } + die = *parent; + } + + return SourcePositionWithInlines { inner_source_position, inline_chain }; +} + +Optional DebugInfo::get_source_path_of_inline(const Dwarf::DIE& die) const +{ + auto caller_file = die.get_attribute(Dwarf::Attribute::CallFile); + if (caller_file.has_value()) { + u32 file_index = 0; + + if (caller_file->type == Dwarf::AttributeValue::Type::UnsignedNumber) { + file_index = caller_file->data.as_u32; + } else if (caller_file->type == Dwarf::AttributeValue::Type::SignedNumber) { + // For some reason, the file_index is sometimes stored as a signed number. + VERIFY(caller_file->data.as_i32 >= 0); + file_index = (u32)caller_file->data.as_i32; + } else { + return {}; + } + + return die.compilation_unit().line_program().get_directory_and_file(file_index); + } + return {}; +} + +Optional DebugInfo::get_line_of_inline(const Dwarf::DIE& die) const +{ + auto caller_line = die.get_attribute(Dwarf::Attribute::CallLine); + if (!caller_line.has_value()) + return {}; + + if (caller_line->type != Dwarf::AttributeValue::Type::UnsignedNumber) + return {}; + return caller_line.value().data.as_u32; +} + } diff --git a/Userland/Libraries/LibDebug/DebugInfo.h b/Userland/Libraries/LibDebug/DebugInfo.h index 3922729b4a6..2d774539a83 100644 --- a/Userland/Libraries/LibDebug/DebugInfo.h +++ b/Userland/Libraries/LibDebug/DebugInfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Itamar S. + * Copyright (c) 2020-2021, Itamar S. * * SPDX-License-Identifier: BSD-2-Clause */ @@ -95,6 +95,12 @@ public: Optional get_source_position(u32 address) const; + struct SourcePositionWithInlines { + Optional source_position; + Vector inline_chain; + }; + SourcePositionWithInlines get_source_position_with_inlines(u32 address) const; + struct SourcePositionAndAddress { String file; size_t line; @@ -115,6 +121,9 @@ private: static bool is_variable_tag_supported(const Dwarf::EntryTag& tag); void add_type_info_to_variable(const Dwarf::DIE& type_die, const PtraceRegisters& regs, DebugInfo::VariableInfo* parent_variable) const; + Optional get_source_path_of_inline(const Dwarf::DIE&) const; + Optional get_line_of_inline(const Dwarf::DIE&) const; + NonnullOwnPtr m_elf; String m_source_root; FlatPtr m_base_address { 0 };