264 lines
8.0 KiB
C++
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
|