diff --git a/Libraries/LibDebug/DebugInfo.cpp b/Libraries/LibDebug/DebugInfo.cpp index 93dbcf11f22..4bff5b88434 100644 --- a/Libraries/LibDebug/DebugInfo.cpp +++ b/Libraries/LibDebug/DebugInfo.cpp @@ -163,43 +163,36 @@ NonnullOwnPtrVector DebugInfo::get_variables_in_current return variables; } -OwnPtr DebugInfo::create_variable_info(const Dwarf::DIE& variable_die, const PtraceRegisters& regs) const +static Optional parse_variable_type_die(const Dwarf::DIE& variable_die, DebugInfo::VariableInfo& variable_info) { - ASSERT(variable_die.tag() == Dwarf::EntryTag::Variable - || variable_die.tag() == Dwarf::EntryTag::Member - || variable_die.tag() == Dwarf::EntryTag::FormalParameter); - - if (variable_die.tag() == Dwarf::EntryTag::FormalParameter - && !variable_die.get_attribute(Dwarf::Attribute::Name).has_value()) { - // We don't want to display info for unused paramters - return {}; - } - - NonnullOwnPtr variable_info = make(); - - variable_info->name = variable_die.get_attribute(Dwarf::Attribute::Name).value().data.as_string; auto type_die_offset = variable_die.get_attribute(Dwarf::Attribute::Type); - ASSERT(type_die_offset.has_value()); + if (!type_die_offset.has_value()) + return {}; + ASSERT(type_die_offset.value().type == Dwarf::DIE::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); if (type_name.has_value()) { - variable_info->type = type_name.value().data.as_string; + variable_info.type_name = type_name.value().data.as_string; } else { dbg() << "Unnamed DWARF type at offset: " << type_die.offset(); - variable_info->name = "[Unnamed Type]"; + variable_info.name = "[Unnamed Type]"; } + return type_die; +} + +static void parse_variable_location(const Dwarf::DIE& variable_die, DebugInfo::VariableInfo& variable_info, const PtraceRegisters& regs) +{ auto location_info = variable_die.get_attribute(Dwarf::Attribute::Location); - if (!location_info.has_value()) { + if (!location_info.has_value()) location_info = variable_die.get_attribute(Dwarf::Attribute::MemberLocation); - } if (location_info.has_value()) { if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::UnsignedNumber) { - variable_info->location_type = VariableInfo::LocationType::Address; - variable_info->location_data.address = location_info.value().data.as_u32; + variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; + variable_info.location_data.address = location_info.value().data.as_u32; } if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::DwarfExpression) { @@ -208,26 +201,85 @@ OwnPtr DebugInfo::create_variable_info(const Dwarf::DIE if (value.type != Dwarf::Expression::Type::None) { ASSERT(value.type == Dwarf::Expression::Type::UnsignedIntetger); - variable_info->location_type = VariableInfo::LocationType::Address; - variable_info->location_data.address = value.data.as_u32; + variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; + variable_info.location_data.address = value.data.as_u32; } } } +} - type_die.for_each_child([&](const Dwarf::DIE& member) { - if (member.is_null()) - return; - auto member_variable = create_variable_info(member, regs); +OwnPtr DebugInfo::create_variable_info(const Dwarf::DIE& variable_die, const PtraceRegisters& regs) const +{ + ASSERT(variable_die.tag() == Dwarf::EntryTag::Variable + || variable_die.tag() == Dwarf::EntryTag::Member + || variable_die.tag() == Dwarf::EntryTag::FormalParameter + || variable_die.tag() == Dwarf::EntryTag::EnumerationType + || variable_die.tag() == Dwarf::EntryTag::Enumerator + || variable_die.tag() == Dwarf::EntryTag::StructureType); - ASSERT(member_variable); - ASSERT(member_variable->location_type == DebugInfo::VariableInfo::LocationType::Address); - ASSERT(variable_info->location_type == DebugInfo::VariableInfo::LocationType::Address); + if (variable_die.tag() == Dwarf::EntryTag::FormalParameter + && !variable_die.get_attribute(Dwarf::Attribute::Name).has_value()) { + // We don't want to display info for unused paramters + return {}; + } - member_variable->location_data.address += variable_info->location_data.address; - member_variable->parent = variable_info.ptr(); + NonnullOwnPtr variable_info = make(); + variable_info->name = variable_die.get_attribute(Dwarf::Attribute::Name).value().data.as_string; - variable_info->members.append(member_variable.release_nonnull()); - }); + auto type_die = parse_variable_type_die(variable_die, *variable_info); + + if (variable_die.tag() == Dwarf::EntryTag::Enumerator) { + auto constant = variable_die.get_attribute(Dwarf::Attribute::ConstValue); + ASSERT(constant.has_value()); + switch (constant.value().type) { + case Dwarf::DIE::AttributeValue::Type::UnsignedNumber: + variable_info->constant_data.as_u32 = constant.value().data.as_u32; + break; + case Dwarf::DIE::AttributeValue::Type::SignedNumber: + variable_info->constant_data.as_i32 = constant.value().data.as_i32; + break; + case Dwarf::DIE::AttributeValue::Type::String: + variable_info->constant_data.as_string = constant.value().data.as_string; + break; + default: + ASSERT_NOT_REACHED(); + } + } else { + parse_variable_location(variable_die, *variable_info, regs); + } + + if (type_die.has_value()) { + OwnPtr type_info; + if (type_die.value().tag() == Dwarf::EntryTag::EnumerationType || type_die.value().tag() == Dwarf::EntryTag::StructureType) { + type_info = create_variable_info(type_die.value(), regs); + } + + type_die.value().for_each_child([&](const Dwarf::DIE& member) { + if (member.is_null()) + return; + auto member_variable = create_variable_info(member, regs); + + ASSERT(member_variable); + + if (type_die.value().tag() == Dwarf::EntryTag::EnumerationType) { + member_variable->parent = type_info.ptr(); + type_info->members.append(member_variable.release_nonnull()); + } else { + ASSERT(variable_info->location_type == DebugInfo::VariableInfo::LocationType::Address); + + if (member_variable->location_type == DebugInfo::VariableInfo::LocationType::Address) + member_variable->location_data.address += variable_info->location_data.address; + + member_variable->parent = variable_info.ptr(); + variable_info->members.append(member_variable.release_nonnull()); + } + }); + + if (type_info) { + variable_info->type = move(type_info); + variable_info->type->type_tag = type_die.value().tag(); + } + } return variable_info; } diff --git a/Libraries/LibDebug/DebugInfo.h b/Libraries/LibDebug/DebugInfo.h index de73a8aa384..d73582c7fbd 100644 --- a/Libraries/LibDebug/DebugInfo.h +++ b/Libraries/LibDebug/DebugInfo.h @@ -53,17 +53,27 @@ public: enum class LocationType { None, Address, - Regsiter, + Register, }; String name; - String type; + String type_name; LocationType location_type { LocationType::None }; union { u32 address; } location_data { 0 }; + union { + u32 as_u32; + u32 as_i32; + const char* as_string; + } constant_data { 0 }; + + Dwarf::EntryTag type_tag; + OwnPtr type; NonnullOwnPtrVector members; VariableInfo* parent { nullptr }; + + bool is_enum_type() const { return type && type->type_tag == Dwarf::EntryTag::EnumerationType; } }; struct VariablesScope { diff --git a/Libraries/LibDebug/Dwarf/DwarfTypes.h b/Libraries/LibDebug/Dwarf/DwarfTypes.h index 84f09b6fad2..e3f601ab4e5 100644 --- a/Libraries/LibDebug/Dwarf/DwarfTypes.h +++ b/Libraries/LibDebug/Dwarf/DwarfTypes.h @@ -40,9 +40,12 @@ struct [[gnu::packed]] CompilationUnitHeader enum class EntryTag : u32 { None = 0, + EnumerationType = 0x4, FormalParameter = 0x5, LexicalBlock = 0xb, Member = 0xd, + StructureType = 0x13, + Enumerator = 0x28, SubProgram = 0x2e, Variable = 0x34, }; @@ -54,6 +57,7 @@ enum class Attribute : u32 { Name = 0x3, LowPc = 0x11, HighPc = 0x12, + ConstValue = 0x1c, Inline = 0x20, MemberLocation = 0x38, Type = 0x49,