Commit cc7d131d authored by tqcq's avatar tqcq
Browse files

feat add dispatcher

parent 7807eecc
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
cmake_minimum_required(VERSION 3.10)
project(
  elf
  VERSION 0.3.0
  LANGUAGES C CXX)

add_library(
  dwarf STATIC
  dwarf/abbrev.cc
  dwarf/attrs.cc
  dwarf/cursor.cc
  dwarf/die.cc
  dwarf/dwarf.cc
  dwarf/elf.cc
  dwarf/expr.cc
  dwarf/line.cc
  dwarf/rangelist.cc
  dwarf/value.cc
  dwarf/to_string.cc)
target_include_directories(dwarf PUBLIC dwarf/)

add_library(elf STATIC elf/elf.cc elf/to_string.cc elf/mmap_loader.cc)
target_include_directories(elf PUBLIC elf/)
target_link_libraries(elf PUBLIC dwarf)
+14 −0
Original line number Diff line number Diff line
all:
	$(MAKE) -C elf
	$(MAKE) -C dwarf

install:
	$(MAKE) -C elf install
	$(MAKE) -C dwarf install

clean:
	$(MAKE) -C elf clean
	$(MAKE) -C dwarf clean

check:
	cd test && ./test.sh
+7 −0
Original line number Diff line number Diff line
*.o
to_string.cc
libdwarf++.a
libdwarf++.so
libdwarf++.so.*
libdwarf++.pc
/doc/
+176 −0
Original line number Diff line number Diff line
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

#include "internal.hh"

using namespace std;

DWARFPP_BEGIN_NAMESPACE

static value::type
resolve_type(DW_AT name, DW_FORM form)
{
        switch (form) {
        case DW_FORM::addr:
                return value::type::address;

        case DW_FORM::block:
        case DW_FORM::block1:
        case DW_FORM::block2:
        case DW_FORM::block4:
                // Prior to DWARF 4, exprlocs didn't have their own
                // form and were represented as blocks.
                // XXX Should this be predicated on version?
                switch (name) {
                case DW_AT::location:
                case DW_AT::byte_size:
                case DW_AT::bit_offset:
                case DW_AT::bit_size:
                case DW_AT::string_length:
                case DW_AT::lower_bound:
                case DW_AT::return_addr:
                case DW_AT::bit_stride:
                case DW_AT::upper_bound:
                case DW_AT::count:
                case DW_AT::data_member_location:
                case DW_AT::frame_base:
                case DW_AT::segment:
                case DW_AT::static_link:
                case DW_AT::use_location:
                case DW_AT::vtable_elem_location:
                case DW_AT::allocated:
                case DW_AT::associated:
                case DW_AT::data_location:
                case DW_AT::byte_stride:
                        return value::type::exprloc;
                default:
                        return value::type::block;
                }

        case DW_FORM::data4:
        case DW_FORM::data8:
                // Prior to DWARF 4, section offsets didn't have their
                // own form and were represented as data4 or data8.
                // DWARF 3 clarified that types that accepted both
                // constants and section offsets were to treat data4
                // and data8 as section offsets and other constant
                // forms as constants.
                // XXX Should this be predicated on version?
                switch (name) {
                case DW_AT::location:
                case DW_AT::stmt_list:
                case DW_AT::string_length:
                case DW_AT::return_addr:
                case DW_AT::start_scope:
                case DW_AT::data_member_location:
                case DW_AT::frame_base:
                case DW_AT::macro_info:
                case DW_AT::segment:
                case DW_AT::static_link:
                case DW_AT::use_location:
                case DW_AT::vtable_elem_location:
                case DW_AT::ranges:
                        goto sec_offset;
                default:
                        // Fall through
                        break;
                }
        case DW_FORM::data1:
        case DW_FORM::data2:
                return value::type::constant;
        case DW_FORM::udata:
                return value::type::uconstant;
        case DW_FORM::sdata:
                return value::type::sconstant;

        case DW_FORM::exprloc:
                return value::type::exprloc;

        case DW_FORM::flag:
        case DW_FORM::flag_present:
                return value::type::flag;

        case DW_FORM::ref1:
        case DW_FORM::ref2:
        case DW_FORM::ref4:
        case DW_FORM::ref8:
        case DW_FORM::ref_addr:
        case DW_FORM::ref_sig8:
        case DW_FORM::ref_udata:
                return value::type::reference;

        case DW_FORM::string:
        case DW_FORM::strp:
                return value::type::string;

        case DW_FORM::indirect:
                // There's nothing meaningful we can do
                return value::type::invalid;

        case DW_FORM::sec_offset:
        sec_offset:
                // The type of this form depends on the attribute
                switch (name) {
                case DW_AT::stmt_list:
                        return value::type::line;

                case DW_AT::location:
                case DW_AT::string_length:
                case DW_AT::return_addr:
                case DW_AT::data_member_location:
                case DW_AT::frame_base:
                case DW_AT::segment:
                case DW_AT::static_link:
                case DW_AT::use_location:
                case DW_AT::vtable_elem_location:
                        return value::type::loclist;

                case DW_AT::macro_info:
                        return value::type::mac;

                case DW_AT::start_scope:
                case DW_AT::ranges:
                        return value::type::rangelist;

                case DW_AT::lo_user...DW_AT::hi_user:
                        //HACK: ignore vendor extensions
                        return value::type::invalid;

                default:
                        throw format_error("DW_FORM_sec_offset not expected for attribute " +
                                           to_string(name));
                }
        }
        throw format_error("unknown attribute form " + to_string(form));
}

attribute_spec::attribute_spec(DW_AT name, DW_FORM form)
        : name(name), form(form), type(resolve_type(name, form))
{
}

bool
abbrev_entry::read(cursor *cur)
{
        attributes.clear();

        // Section 7.5.3
        code = cur->uleb128();
        if (!code)
                return false;

        tag = (DW_TAG)cur->uleb128();
        children = cur->fixed<DW_CHILDREN>() == DW_CHILDREN::yes;
        while (1) {
                DW_AT name = (DW_AT)cur->uleb128();
                DW_FORM form = (DW_FORM)cur->uleb128();
                if (name == (DW_AT)0 && form == (DW_FORM)0)
                        break;
                attributes.push_back(attribute_spec(name, form));
        }
        attributes.shrink_to_fit();
        return true;
}

DWARFPP_END_NAMESPACE
+267 −0
Original line number Diff line number Diff line
// Copyright (c) 2013 Austin T. Clements. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.

#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, 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()};
        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
Loading