mirror of
https://github.com/RGBCube/serenity
synced 2025-07-22 21:57:35 +00:00
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.
This commit is contained in:
parent
b750843797
commit
a4f23429aa
3 changed files with 102 additions and 36 deletions
|
@ -163,43 +163,36 @@ NonnullOwnPtrVector<DebugInfo::VariableInfo> DebugInfo::get_variables_in_current
|
||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnPtr<DebugInfo::VariableInfo> DebugInfo::create_variable_info(const Dwarf::DIE& variable_die, const PtraceRegisters& regs) const
|
static Optional<Dwarf::DIE> 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<VariableInfo> variable_info = make<VariableInfo>();
|
|
||||||
|
|
||||||
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);
|
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);
|
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_die = variable_die.get_die_at_offset(type_die_offset.value().data.as_u32);
|
||||||
auto type_name = type_die.get_attribute(Dwarf::Attribute::Name);
|
auto type_name = type_die.get_attribute(Dwarf::Attribute::Name);
|
||||||
if (type_name.has_value()) {
|
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 {
|
} else {
|
||||||
dbg() << "Unnamed DWARF type at offset: " << type_die.offset();
|
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);
|
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);
|
location_info = variable_die.get_attribute(Dwarf::Attribute::MemberLocation);
|
||||||
}
|
|
||||||
|
|
||||||
if (location_info.has_value()) {
|
if (location_info.has_value()) {
|
||||||
if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::UnsignedNumber) {
|
if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::UnsignedNumber) {
|
||||||
variable_info->location_type = 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_u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::DwarfExpression) {
|
if (location_info.value().type == Dwarf::DIE::AttributeValue::Type::DwarfExpression) {
|
||||||
|
@ -208,27 +201,86 @@ OwnPtr<DebugInfo::VariableInfo> DebugInfo::create_variable_info(const Dwarf::DIE
|
||||||
|
|
||||||
if (value.type != Dwarf::Expression::Type::None) {
|
if (value.type != Dwarf::Expression::Type::None) {
|
||||||
ASSERT(value.type == Dwarf::Expression::Type::UnsignedIntetger);
|
ASSERT(value.type == Dwarf::Expression::Type::UnsignedIntetger);
|
||||||
variable_info->location_type = 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_u32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnPtr<DebugInfo::VariableInfo> 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);
|
||||||
|
|
||||||
|
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 {};
|
||||||
|
}
|
||||||
|
|
||||||
type_die.for_each_child([&](const Dwarf::DIE& member) {
|
NonnullOwnPtr<VariableInfo> variable_info = make<VariableInfo>();
|
||||||
|
variable_info->name = variable_die.get_attribute(Dwarf::Attribute::Name).value().data.as_string;
|
||||||
|
|
||||||
|
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<VariableInfo> 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())
|
if (member.is_null())
|
||||||
return;
|
return;
|
||||||
auto member_variable = create_variable_info(member, regs);
|
auto member_variable = create_variable_info(member, regs);
|
||||||
|
|
||||||
ASSERT(member_variable);
|
ASSERT(member_variable);
|
||||||
ASSERT(member_variable->location_type == DebugInfo::VariableInfo::LocationType::Address);
|
|
||||||
|
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);
|
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->location_data.address += variable_info->location_data.address;
|
||||||
member_variable->parent = variable_info.ptr();
|
|
||||||
|
|
||||||
|
member_variable->parent = variable_info.ptr();
|
||||||
variable_info->members.append(member_variable.release_nonnull());
|
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;
|
return variable_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,17 +53,27 @@ public:
|
||||||
enum class LocationType {
|
enum class LocationType {
|
||||||
None,
|
None,
|
||||||
Address,
|
Address,
|
||||||
Regsiter,
|
Register,
|
||||||
};
|
};
|
||||||
String name;
|
String name;
|
||||||
String type;
|
String type_name;
|
||||||
LocationType location_type { LocationType::None };
|
LocationType location_type { LocationType::None };
|
||||||
union {
|
union {
|
||||||
u32 address;
|
u32 address;
|
||||||
} location_data { 0 };
|
} location_data { 0 };
|
||||||
|
|
||||||
|
union {
|
||||||
|
u32 as_u32;
|
||||||
|
u32 as_i32;
|
||||||
|
const char* as_string;
|
||||||
|
} constant_data { 0 };
|
||||||
|
|
||||||
|
Dwarf::EntryTag type_tag;
|
||||||
|
OwnPtr<VariableInfo> type;
|
||||||
NonnullOwnPtrVector<VariableInfo> members;
|
NonnullOwnPtrVector<VariableInfo> members;
|
||||||
VariableInfo* parent { nullptr };
|
VariableInfo* parent { nullptr };
|
||||||
|
|
||||||
|
bool is_enum_type() const { return type && type->type_tag == Dwarf::EntryTag::EnumerationType; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VariablesScope {
|
struct VariablesScope {
|
||||||
|
|
|
@ -40,9 +40,12 @@ struct [[gnu::packed]] CompilationUnitHeader
|
||||||
|
|
||||||
enum class EntryTag : u32 {
|
enum class EntryTag : u32 {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
EnumerationType = 0x4,
|
||||||
FormalParameter = 0x5,
|
FormalParameter = 0x5,
|
||||||
LexicalBlock = 0xb,
|
LexicalBlock = 0xb,
|
||||||
Member = 0xd,
|
Member = 0xd,
|
||||||
|
StructureType = 0x13,
|
||||||
|
Enumerator = 0x28,
|
||||||
SubProgram = 0x2e,
|
SubProgram = 0x2e,
|
||||||
Variable = 0x34,
|
Variable = 0x34,
|
||||||
};
|
};
|
||||||
|
@ -54,6 +57,7 @@ enum class Attribute : u32 {
|
||||||
Name = 0x3,
|
Name = 0x3,
|
||||||
LowPc = 0x11,
|
LowPc = 0x11,
|
||||||
HighPc = 0x12,
|
HighPc = 0x12,
|
||||||
|
ConstValue = 0x1c,
|
||||||
Inline = 0x20,
|
Inline = 0x20,
|
||||||
MemberLocation = 0x38,
|
MemberLocation = 0x38,
|
||||||
Type = 0x49,
|
Type = 0x49,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue