gctf2023/pwn/flipper/dist/utils/add-debug/dwarf/attrs.cc
2023-11-24 13:11:34 -05:00

264 lines
8.0 KiB
C++

#include "dwarf++.hh"
using namespace std;
DWARFPP_BEGIN_NAMESPACE
#define AT_ANY(name) \
value at_##name(const die &d) \
{ \
return d[DW_AT::name]; \
} \
static_assert(true, "")
#define AT_ADDRESS(name) \
taddr at_##name(const die &d) \
{ \
return d[DW_AT::name].as_address(); \
} \
static_assert(true, "")
#define AT_ENUM(name, type) \
type at_##name(const die &d) \
{ \
return (type)d[DW_AT::name].as_uconstant(); \
} \
static_assert(true, "")
#define AT_FLAG(name) \
bool at_##name(const die &d) \
{ \
return d[DW_AT::name].as_flag(); \
} \
static_assert(true, "")
#define AT_FLAG_(name) \
bool at_##name(const die &d) \
{ \
return d[DW_AT::name##_].as_flag(); \
} \
static_assert(true, "")
#define AT_REFERENCE(name) \
die at_##name(const die &d) \
{ \
return d[DW_AT::name].as_reference(); \
} \
static_assert(true, "")
#define AT_STRING(name) \
string at_##name(const die &d) \
{ \
return d[DW_AT::name].as_string(); \
} \
static_assert(true, "")
#define AT_UDYNAMIC(name) \
uint64_t at_##name(const die &d, expr_context *ctx) \
{ \
return _at_udynamic(DW_AT::name, d, ctx); \
} \
static_assert(true, "")
static uint64_t _at_udynamic(DW_AT attr, const die &d, expr_context *ctx, int depth = 0)
{
// DWARF4 section 2.19
if (depth > 16)
throw format_error("reference depth exceeded for " + to_string(attr));
value v(d[attr]);
switch (v.get_type()) {
case value::type::constant:
case value::type::uconstant:
return v.as_uconstant();
case value::type::reference:
return _at_udynamic(attr, v.as_reference(), ctx, depth + 1);
case value::type::exprloc:
return v.as_exprloc().evaluate(ctx).value;
default:
throw format_error(to_string(attr) + " has unexpected type " +
to_string(v.get_type()));
}
}
//////////////////////////////////////////////////////////////////
// 0x0X
//
AT_REFERENCE(sibling);
// XXX location
AT_STRING(name);
AT_ENUM(ordering, DW_ORD);
AT_UDYNAMIC(byte_size);
AT_UDYNAMIC(bit_offset);
AT_UDYNAMIC(bit_size);
//////////////////////////////////////////////////////////////////
// 0x1X
//
// XXX stmt_list
AT_ADDRESS(low_pc);
taddr
at_high_pc(const die &d)
{
value v(d[DW_AT::high_pc]);
switch (v.get_type()) {
case value::type::address:
return v.as_address();
case value::type::constant:
case value::type::uconstant:
return at_low_pc(d) + v.as_uconstant();
default:
throw format_error(to_string(DW_AT::high_pc) + " has unexpected type " +
to_string(v.get_type()));
}
}
AT_ENUM(language, DW_LANG);
AT_REFERENCE(discr);
AT_ANY(discr_value); // XXX Signed or unsigned
AT_ENUM(visibility, DW_VIS);
AT_REFERENCE(import);
// XXX string_length
AT_REFERENCE(common_reference);
AT_STRING(comp_dir);
AT_ANY(const_value);
AT_REFERENCE(containing_type);
// XXX default_value
//////////////////////////////////////////////////////////////////
// 0x2X
//
DW_INL at_inline(const die &d)
{
// XXX Missing attribute is equivalent to DW_INL_not_inlined
// (DWARF4 section 3.3.8)
return (DW_INL)d[DW_AT::inline_].as_uconstant();
}
AT_FLAG(is_optional);
AT_UDYNAMIC(lower_bound); // XXX Language-based default?
AT_STRING(producer);
AT_FLAG(prototyped);
// XXX return_addr
// XXX start_scope
AT_UDYNAMIC(bit_stride);
AT_UDYNAMIC(upper_bound);
//////////////////////////////////////////////////////////////////
// 0x3X
//
AT_REFERENCE(abstract_origin);
AT_ENUM(accessibility, DW_ACCESS);
// XXX const address_class
AT_FLAG(artificial);
// XXX base_types
AT_ENUM(calling_convention, DW_CC);
AT_UDYNAMIC(count);
expr_result
at_data_member_location(const die &d, expr_context *ctx, taddr base, [[gnu::unused]] taddr pc)
{
value v(d[DW_AT::data_member_location]);
switch (v.get_type()) {
case value::type::constant:
case value::type::uconstant:
return {expr_result::type::address, base + v.as_uconstant(), nullptr, 0};
case value::type::exprloc:
return v.as_exprloc().evaluate(ctx, base);
case value::type::loclist:
// XXX
throw std::runtime_error("not implemented");
default:
throw format_error("DW_AT_data_member_location has unexpected type " +
to_string(v.get_type()));
}
}
// XXX decl_column decl_file decl_line
AT_FLAG(declaration);
// XXX discr_list
AT_ENUM(encoding, DW_ATE);
AT_FLAG(external);
//////////////////////////////////////////////////////////////////
// 0x4X
//
// XXX frame_base
die at_friend(const die &d)
{
return d[DW_AT::friend_].as_reference();
}
AT_ENUM(identifier_case, DW_ID);
// XXX macro_info
AT_REFERENCE(namelist_item);
AT_REFERENCE(priority); // XXX Computed might be useful
// XXX segment
AT_REFERENCE(specification);
// XXX static_link
AT_REFERENCE(type);
// XXX use_location
AT_FLAG(variable_parameter);
// XXX 7.11 The value DW_VIRTUALITY_none is equivalent to the absence
// of the DW_AT_virtuality attribute.
AT_ENUM(virtuality, DW_VIRTUALITY);
// XXX vtable_elem_location
AT_UDYNAMIC(allocated);
AT_UDYNAMIC(associated);
//////////////////////////////////////////////////////////////////
// 0x5X
//
// XXX data_location
AT_UDYNAMIC(byte_stride);
AT_ADDRESS(entry_pc);
AT_FLAG(use_UTF8);
AT_REFERENCE(extension);
rangelist
at_ranges(const die &d)
{
return d[DW_AT::ranges].as_rangelist();
}
// XXX trampoline
// XXX const call_column, call_file, call_line
AT_STRING(description);
// XXX const binary_scale
// XXX const decimal_scale
AT_REFERENCE(small);
// XXX const decimal_sign
// XXX const digit_count
//////////////////////////////////////////////////////////////////
// 0x6X
//
AT_STRING(picture_string);
AT_FLAG_(mutable);
AT_FLAG(threads_scaled);
AT_FLAG_(explicit);
AT_REFERENCE(object_pointer);
AT_ENUM(endianity, DW_END);
AT_FLAG(elemental);
AT_FLAG(pure);
AT_FLAG(recursive);
AT_REFERENCE(signature); // XXX Computed might be useful
AT_FLAG(main_subprogram);
// XXX const data_bit_offset
AT_FLAG(const_expr);
AT_FLAG(enum_class);
AT_STRING(linkage_name);
rangelist
die_pc_range(const die &d)
{
// DWARF4 section 2.17
if (d.has(DW_AT::ranges))
return at_ranges(d);
taddr low = at_low_pc(d);
taddr high = d.has(DW_AT::high_pc) ? at_high_pc(d) : (low + 1);
return rangelist({{low, high}});
}
DWARFPP_END_NAMESPACE