diff --git a/Userland/Libraries/LibDebug/DebugInfo.cpp b/Userland/Libraries/LibDebug/DebugInfo.cpp index 07ed3fbe98..43d7c0230c 100644 --- a/Userland/Libraries/LibDebug/DebugInfo.cpp +++ b/Userland/Libraries/LibDebug/DebugInfo.cpp @@ -187,7 +187,7 @@ static Optional parse_variable_type_die(const Dwarf::DIE& variable_d if (!type_die_offset.has_value()) return {}; - VERIFY(type_die_offset.value().type == Dwarf::DIE::AttributeValue::Type::DieReference); + VERIFY(type_die_offset.value().type == Dwarf::AttributeValue::Type::DieReference); auto type_die = variable_die.get_die_at_offset(type_die_offset.value().data.as_u32); auto type_name = type_die.get_attribute(Dwarf::Attribute::Name); @@ -212,11 +212,11 @@ static void parse_variable_location(const Dwarf::DIE& variable_die, DebugInfo::V return; switch (location_info.value().type) { - case Dwarf::DIE::AttributeValue::Type::UnsignedNumber: + case Dwarf::AttributeValue::Type::UnsignedNumber: variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; variable_info.location_data.address = location_info.value().data.as_u32; break; - case Dwarf::DIE::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 value = Dwarf::Expression::evaluate(expression_bytes, regs); @@ -253,13 +253,13 @@ OwnPtr DebugInfo::create_variable_info(const Dwarf::DIE auto constant = variable_die.get_attribute(Dwarf::Attribute::ConstValue); VERIFY(constant.has_value()); switch (constant.value().type) { - case Dwarf::DIE::AttributeValue::Type::UnsignedNumber: + case Dwarf::AttributeValue::Type::UnsignedNumber: variable_info->constant_data.as_u32 = constant.value().data.as_u32; break; - case Dwarf::DIE::AttributeValue::Type::SignedNumber: + case Dwarf::AttributeValue::Type::SignedNumber: variable_info->constant_data.as_i32 = constant.value().data.as_i32; break; - case Dwarf::DIE::AttributeValue::Type::String: + case Dwarf::AttributeValue::Type::String: variable_info->constant_data.as_string = constant.value().data.as_string; break; default: diff --git a/Userland/Libraries/LibDebug/Dwarf/DIE.cpp b/Userland/Libraries/LibDebug/Dwarf/DIE.cpp index f7adf01f78..2e1150c0a7 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DIE.cpp +++ b/Userland/Libraries/LibDebug/Dwarf/DIE.cpp @@ -33,162 +33,13 @@ DIE::DIE(const CompilationUnit& unit, u32 offset) // We iterate the attributes data only to calculate this DIE's size for (auto& attribute_spec : abbreviation_info.value().attribute_specifications) { - get_attribute_value(attribute_spec.form, stream); + m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, stream, &m_compilation_unit); } } m_size = stream.offset() - m_offset; } -DIE::AttributeValue DIE::get_attribute_value(AttributeDataForm form, - InputMemoryStream& debug_info_stream) const -{ - AttributeValue value; - - auto assign_raw_bytes_value = [&](size_t length) { - value.data.as_raw_bytes.length = length; - value.data.as_raw_bytes.bytes = reinterpret_cast(m_compilation_unit.dwarf_info().debug_info_data().data() - + debug_info_stream.offset()); - - debug_info_stream.discard_or_error(length); - }; - - switch (form) { - case AttributeDataForm::StringPointer: { - u32 offset; - debug_info_stream >> offset; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::String; - - auto strings_data = m_compilation_unit.dwarf_info().debug_strings_data(); - value.data.as_string = reinterpret_cast(strings_data.data() + offset); - break; - } - case AttributeDataForm::Data1: { - u8 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::UnsignedNumber; - value.data.as_u32 = data; - break; - } - case AttributeDataForm::Data2: { - u16 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::UnsignedNumber; - value.data.as_u32 = data; - break; - } - case AttributeDataForm::Addr: { - u32 address; - debug_info_stream >> address; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::UnsignedNumber; - value.data.as_u32 = address; - break; - } - case AttributeDataForm::SData: { - ssize_t data; - debug_info_stream.read_LEB128_signed(data); - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::SignedNumber; - value.data.as_i32 = data; - break; - } - case AttributeDataForm::SecOffset: { - u32 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::SecOffset; - value.data.as_u32 = data; - break; - } - case AttributeDataForm::Data4: { - u32 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::UnsignedNumber; - value.data.as_u32 = data; - break; - } - case AttributeDataForm::Data8: { - u64 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::LongUnsignedNumber; - value.data.as_u64 = data; - break; - } - case AttributeDataForm::Ref4: { - u32 data; - debug_info_stream >> data; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::DieReference; - value.data.as_u32 = data + m_compilation_unit.offset(); - break; - } - case AttributeDataForm::FlagPresent: { - value.type = AttributeValue::Type::Boolean; - value.data.as_bool = true; - break; - } - case AttributeDataForm::ExprLoc: { - size_t length; - debug_info_stream.read_LEB128_unsigned(length); - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::DwarfExpression; - assign_raw_bytes_value(length); - break; - } - case AttributeDataForm::String: { - String str; - u32 str_offset = debug_info_stream.offset(); - debug_info_stream >> str; - VERIFY(!debug_info_stream.has_any_error()); - value.type = AttributeValue::Type::String; - value.data.as_string = reinterpret_cast(str_offset + m_compilation_unit.dwarf_info().debug_info_data().data()); - break; - } - case AttributeDataForm::Block1: { - value.type = AttributeValue::Type::RawBytes; - u8 length; - debug_info_stream >> length; - VERIFY(!debug_info_stream.has_any_error()); - assign_raw_bytes_value(length); - break; - } - case AttributeDataForm::Block2: { - value.type = AttributeValue::Type::RawBytes; - u16 length; - debug_info_stream >> length; - VERIFY(!debug_info_stream.has_any_error()); - assign_raw_bytes_value(length); - break; - } - case AttributeDataForm::Block4: { - value.type = AttributeValue::Type::RawBytes; - u32 length; - debug_info_stream >> length; - VERIFY(!debug_info_stream.has_any_error()); - assign_raw_bytes_value(length); - break; - } - case AttributeDataForm::Block: { - value.type = AttributeValue::Type::RawBytes; - size_t length; - debug_info_stream.read_LEB128_unsigned(length); - VERIFY(!debug_info_stream.has_any_error()); - assign_raw_bytes_value(length); - break; - } - default: - dbgln("Unimplemented AttributeDataForm: {}", (u32)form); - VERIFY_NOT_REACHED(); - } - return value; -} - -Optional DIE::get_attribute(const Attribute& attribute) const +Optional DIE::get_attribute(const Attribute& attribute) const { InputMemoryStream stream { m_compilation_unit.dwarf_info().debug_info_data() }; stream.discard_or_error(m_data_offset); @@ -197,7 +48,7 @@ Optional DIE::get_attribute(const Attribute& attribute) con VERIFY(abbreviation_info.has_value()); for (const auto& attribute_spec : abbreviation_info.value().attribute_specifications) { - auto value = get_attribute_value(attribute_spec.form, stream); + auto value = m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, stream, &m_compilation_unit); if (attribute_spec.attribute == attribute) { return value; } diff --git a/Userland/Libraries/LibDebug/Dwarf/DIE.h b/Userland/Libraries/LibDebug/Dwarf/DIE.h index 9018f49507..880d47058a 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DIE.h +++ b/Userland/Libraries/LibDebug/Dwarf/DIE.h @@ -7,6 +7,7 @@ #pragma once #include "CompilationUnit.h" +#include "DwarfInfo.h" #include "DwarfTypes.h" #include #include @@ -22,32 +23,6 @@ class DIE { public: DIE(const CompilationUnit&, u32 offset); - struct AttributeValue { - enum class Type : u8 { - UnsignedNumber, - SignedNumber, - LongUnsignedNumber, - String, - DieReference, // Reference to another DIE in the same compilation unit - Boolean, - DwarfExpression, - SecOffset, - RawBytes, - } type; - - union { - u32 as_u32; - i32 as_i32; - u64 as_u64; - const char* as_string; // points to bytes in the memory mapped elf image - bool as_bool; - struct { - u32 length; - const u8* bytes; // points to bytes in the memory mapped elf image - } as_raw_bytes; - } data {}; - }; - u32 offset() const { return m_offset; } u32 size() const { return m_size; } bool has_children() const { return m_has_children; } @@ -62,9 +37,6 @@ public: DIE get_die_at_offset(u32 offset) const; private: - AttributeValue get_attribute_value(AttributeDataForm form, - InputMemoryStream& debug_info_stream) const; - const CompilationUnit& m_compilation_unit; u32 m_offset { 0 }; u32 m_data_offset { 0 }; diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp index 50858d0598..19d1793099 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp +++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp @@ -48,4 +48,154 @@ void DwarfInfo::populate_compilation_units() } } +AttributeValue DwarfInfo::get_attribute_value(AttributeDataForm form, + InputMemoryStream& debug_info_stream, const CompilationUnit* unit) const +{ + AttributeValue value; + + auto assign_raw_bytes_value = [&](size_t length) { + value.data.as_raw_bytes.length = length; + value.data.as_raw_bytes.bytes = reinterpret_cast(debug_info_data().data() + + debug_info_stream.offset()); + + debug_info_stream.discard_or_error(length); + }; + + switch (form) { + case AttributeDataForm::StringPointer: { + u32 offset; + debug_info_stream >> offset; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::String; + + auto strings_data = debug_strings_data(); + value.data.as_string = reinterpret_cast(strings_data.data() + offset); + break; + } + case AttributeDataForm::Data1: { + u8 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::UnsignedNumber; + value.data.as_u32 = data; + break; + } + case AttributeDataForm::Data2: { + u16 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::UnsignedNumber; + value.data.as_u32 = data; + break; + } + case AttributeDataForm::Addr: { + u32 address; + debug_info_stream >> address; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::UnsignedNumber; + value.data.as_u32 = address; + break; + } + case AttributeDataForm::SData: { + ssize_t data; + debug_info_stream.read_LEB128_signed(data); + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::SignedNumber; + value.data.as_i32 = data; + break; + } + case AttributeDataForm::SecOffset: { + u32 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::SecOffset; + value.data.as_u32 = data; + break; + } + case AttributeDataForm::Data4: { + u32 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::UnsignedNumber; + value.data.as_u32 = data; + break; + } + case AttributeDataForm::Data8: { + u64 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::LongUnsignedNumber; + value.data.as_u64 = data; + break; + } + case AttributeDataForm::Ref4: { + u32 data; + debug_info_stream >> data; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::DieReference; + VERIFY(unit); + value.data.as_u32 = data + unit->offset(); + break; + } + case AttributeDataForm::FlagPresent: { + value.type = AttributeValue::Type::Boolean; + value.data.as_bool = true; + break; + } + case AttributeDataForm::ExprLoc: { + size_t length; + debug_info_stream.read_LEB128_unsigned(length); + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::DwarfExpression; + assign_raw_bytes_value(length); + break; + } + case AttributeDataForm::String: { + String str; + u32 str_offset = debug_info_stream.offset(); + debug_info_stream >> str; + VERIFY(!debug_info_stream.has_any_error()); + value.type = AttributeValue::Type::String; + value.data.as_string = reinterpret_cast(str_offset + debug_info_data().data()); + break; + } + case AttributeDataForm::Block1: { + value.type = AttributeValue::Type::RawBytes; + u8 length; + debug_info_stream >> length; + VERIFY(!debug_info_stream.has_any_error()); + assign_raw_bytes_value(length); + break; + } + case AttributeDataForm::Block2: { + value.type = AttributeValue::Type::RawBytes; + u16 length; + debug_info_stream >> length; + VERIFY(!debug_info_stream.has_any_error()); + assign_raw_bytes_value(length); + break; + } + case AttributeDataForm::Block4: { + value.type = AttributeValue::Type::RawBytes; + u32 length; + debug_info_stream >> length; + VERIFY(!debug_info_stream.has_any_error()); + assign_raw_bytes_value(length); + break; + } + case AttributeDataForm::Block: { + value.type = AttributeValue::Type::RawBytes; + size_t length; + debug_info_stream.read_LEB128_unsigned(length); + VERIFY(!debug_info_stream.has_any_error()); + assign_raw_bytes_value(length); + break; + } + default: + dbgln("Unimplemented AttributeDataForm: {}", (u32)form); + VERIFY_NOT_REACHED(); + } + return value; +} + } diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h index 7f468e1197..8de7c7f603 100644 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h +++ b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h @@ -16,6 +16,32 @@ namespace Debug::Dwarf { +struct AttributeValue { + enum class Type : u8 { + UnsignedNumber, + SignedNumber, + LongUnsignedNumber, + String, + DieReference, // Reference to another DIE in the same compilation unit + Boolean, + DwarfExpression, + SecOffset, + RawBytes, + } type; + + union { + u32 as_u32; + i32 as_i32; + u64 as_u64; + const char* as_string; // points to bytes in the memory mapped elf image + bool as_bool; + struct { + u32 length; + const u8* bytes; // points to bytes in the memory mapped elf image + } as_raw_bytes; + } data {}; +}; + class DwarfInfo { public: explicit DwarfInfo(const ELF::Image&); @@ -27,6 +53,9 @@ public: template void for_each_compilation_unit(Callback) const; + AttributeValue get_attribute_value(AttributeDataForm form, + InputMemoryStream& debug_info_stream, const CompilationUnit* unit = nullptr) const; + private: void populate_compilation_units();