From a4f23429aaf88a419d6cf4278f2ef49f1ff75ca1 Mon Sep 17 00:00:00 2001 From: FalseHonesty Date: Sun, 31 May 2020 22:48:09 -0400 Subject: [PATCH] LibDebug: Add support for enum value types Additionally, we will parse and expose the types of variables if they are complex, like Enums or Structs. Variables of an enum type are special in that they do not store all the members of said enum in their own VariableInfo like Structs do, rather, all of the values are stored in the VariableInfo for the Enum. --- Libraries/LibDebug/DebugInfo.cpp | 120 ++++++++++++++++++-------- Libraries/LibDebug/DebugInfo.h | 14 ++- Libraries/LibDebug/Dwarf/DwarfTypes.h | 4 + 3 files changed, 102 insertions(+), 36 deletions(-) diff --git a/Libraries/LibDebug/DebugInfo.cpp b/Libraries/LibDebug/DebugInfo.cpp index 93dbcf11f2..4bff5b8843 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 de73a8aa38..d73582c7fb 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 84f09b6fad..e3f601ab4e 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,