From: Petr Machata Date: Tue, 5 Oct 2010 18:33:03 +0000 (+0200) Subject: dwarflint: Revamping dwarf tables X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=958aa412cfee06aa6bbbc110c18e2c2cc369fc0b;p=thirdparty%2Felfutils.git dwarflint: Revamping dwarf tables - forms are now objects. The idea being they know how big they are, how to relocate them, perhaps they might know how to extract value from stream. The goal here is to concetrate all the form-related knowledge to a sigle place. It now passes the suite, but is not really done yet. --- diff --git a/dwarflint/check_debug_info.cc b/dwarflint/check_debug_info.cc index 13f2bedc2..86b6d5a91 100644 --- a/dwarflint/check_debug_info.cc +++ b/dwarflint/check_debug_info.cc @@ -687,7 +687,6 @@ namespace rel_require, // require a relocation rel_nonzero, // require a relocation if value != 0 } relocate = rel_no; - size_t width = 0; /* Point to variable that you want to copy relocated value to. */ @@ -733,7 +732,7 @@ namespace wr_error (where) << "location attribute with invalid (indirect) form \"" << pri::form (form) << "\"." << std::endl; - }; + } } /* Setup rangeptr or lineptr checking. */ else @@ -798,11 +797,92 @@ namespace } } - /* Load attribute value and setup per-form checking. */ + /* Width extraction. */ + size_t width = -1; + switch (form) + { + case DW_FORM_ref_udata: + width = 0; + break; + + case DW_FORM_block1: + case DW_FORM_ref1: + width = 1; + break; + + case DW_FORM_block2: + case DW_FORM_ref2: + width = 2; + break; + + case DW_FORM_data4: + case DW_FORM_block4: + case DW_FORM_ref4: + width = 4; + break; + + case DW_FORM_data8: + case DW_FORM_ref8: + width = 8; + break; + + case DW_FORM_strp: + case DW_FORM_sec_offset: + width = cu->head->offset_size; + break; + + case DW_FORM_ref_addr: + if (cu->head->version >= 3) + width = cu->head->offset_size; + else + width = cu->head->address_size; + break; + + case DW_FORM_addr: + width = cu->head->address_size; + break; + } + + /* Setup per-form checking & relocation. */ switch (form) { case DW_FORM_strp: value_check_cb = check_strp; + case DW_FORM_sec_offset: + relocate = rel_require; + break; + + case DW_FORM_ref_addr: + value_check_cb = check_die_ref_global; + case DW_FORM_addr: + /* In non-rel files, neither addr, nor ref_addr /need/ + a relocation. */ + relocate = rel_nonzero; + break; + + case DW_FORM_ref_udata: + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + value_check_cb = check_die_ref_local; + break; + + case DW_FORM_data4: + if (check_someptr) + relocate = rel_require; + break; + + case DW_FORM_data8: + if (check_someptr) + relocate = rel_require; + break; + } + + /* Load attribute value. */ + switch (form) + { + case DW_FORM_strp: case DW_FORM_sec_offset: if (!read_ctx_read_offset (ctx, cu->head->offset_size == 8, &value)) @@ -813,9 +893,6 @@ namespace << pri::attr (it->name) << '.' << std::endl; return -1; } - - relocate = rel_require; - width = cu->head->offset_size; break; case DW_FORM_string: @@ -824,23 +901,13 @@ namespace break; case DW_FORM_ref_addr: - value_check_cb = check_die_ref_global; - width = cu->head->offset_size; - - if (cu->head->version == 2) - case DW_FORM_addr: - width = cu->head->address_size; - + case DW_FORM_addr: + assert (width != (size_t)-1); if (!read_ctx_read_offset (ctx, width == 8, &value)) goto cant_read; - - /* In non-rel files, neither addr, nor ref_addr /need/ - a relocation. */ - relocate = rel_nonzero; break; case DW_FORM_ref_udata: - value_check_cb = check_die_ref_local; case DW_FORM_udata: if (!checked_read_uleb128 (ctx, &value, &where, "attribute value")) @@ -852,7 +919,6 @@ namespace break; case DW_FORM_ref1: - value_check_cb = check_die_ref_local; case DW_FORM_flag: case DW_FORM_data1: if (!read_ctx_read_var (ctx, 1, &value)) @@ -860,34 +926,19 @@ namespace break; case DW_FORM_ref2: - value_check_cb = check_die_ref_local; case DW_FORM_data2: if (!read_ctx_read_var (ctx, 2, &value)) goto cant_read; break; case DW_FORM_data4: - if (check_someptr) - { - relocate = rel_require; - width = 4; - } - if (false) case DW_FORM_ref4: - value_check_cb = check_die_ref_local; if (!read_ctx_read_var (ctx, 4, &value)) goto cant_read; break; case DW_FORM_data8: - if (check_someptr) - { - relocate = rel_require; - width = 8; - } - if (false) - case DW_FORM_ref8: - value_check_cb = check_die_ref_local; + case DW_FORM_ref8: if (!read_ctx_read_8ubyte (ctx, &value)) goto cant_read; break; @@ -903,23 +954,14 @@ namespace } case DW_FORM_block: + case DW_FORM_block1: + case DW_FORM_block2: + case DW_FORM_block4: { uint64_t length; - - if (false) - case DW_FORM_block1: - width = 1; - - if (false) - case DW_FORM_block2: - width = 2; - - if (false) - case DW_FORM_block4: - width = 4; - if (width == 0) { + assert (form == DW_FORM_block); if (!checked_read_uleb128 (ctx, &length, &where, "attribute value")) return -1; diff --git a/dwarflint/tables.cc b/dwarflint/tables.cc index a44f2a61e..65891158a 100644 --- a/dwarflint/tables.cc +++ b/dwarflint/tables.cc @@ -28,8 +28,9 @@ // a version in its own. #include "tables.hh" -#include "../libdw/dwarf.h" +#include "check_debug_info.hh" +#include "../libdw/dwarf.h" #include #include #include @@ -67,77 +68,152 @@ namespace #undef ADD return s; } +} + +class x_form +{ +public: + virtual int name () const = 0; + virtual dw_class_set const &classes () const = 0; + virtual dwarf_version::form_width_t + width (struct cu const *cu = NULL) const = 0; + virtual ~x_form () {} +}; + +namespace { struct dwarf_row { int val; dw_class_set classes; }; - class form_table + class x_form_table { - typedef std::set
_form_set_t; - typedef std::map _form_map_t; + typedef std::map _forms_map_t; + _forms_map_t const _m_forms; - static _form_map_t init_class_forms (dwarf_row const forms[], - form_table const *parent) + static _forms_map_t build_forms (x_form const *const *forms) { - _form_map_t class_forms; + _forms_map_t ret; + for (x_form const *const *it = forms; *it != NULL; ++it) + ret[(*it)->name ()] = *it; + return ret; + } - if (parent != NULL) - { - std::set overriden_forms; - for (size_t i = 0; forms[i].val != 0; ++i) - overriden_forms.insert (forms[i].val); - - for (_form_map_t::const_iterator it = parent->m_class_forms.begin (); - it != parent->m_class_forms.end (); ++it) - { - std::set new_forms = it->second; - for (_form_set_t::const_iterator ot = overriden_forms.begin (); - ot != overriden_forms.end (); ++ot) - new_forms.erase (*ot); - class_forms.insert (std::make_pair (it->first, new_forms)); - } - } + public: + x_form_table (x_form const *const forms[]) + : _m_forms (build_forms (forms)) + {} - for (size_t i = 0; forms[i].val != 0; ++i) - for (unsigned c = 0; c < forms[i].classes.size (); ++c) - class_forms[static_cast (c)].insert (forms[i].val); + x_form const * + get (int f) const + { + _forms_map_t::const_iterator it = _m_forms.find (f); + if (it != _m_forms.end ()) + return it->second; + else + return NULL; + } - return class_forms; + bool + has_form (int f) const + { + return get (f) != NULL; } + }; - static _form_set_t init_all_forms (_form_map_t const &class_forms) + class basic_form + : public x_form + { + protected: + int _m_name; + dw_class_set _m_classes; + public: + basic_form (int a_name, dw_class_set a_classes) + : _m_name (a_name) + , _m_classes (a_classes) + {} + + int + name () const { - _form_set_t all_forms; - for (_form_map_t::const_iterator it = class_forms.begin (); - it != class_forms.end (); ++it) - all_forms.insert (it->second.begin (), it->second.end ()); - return all_forms; + return _m_name; } - _form_map_t const m_class_forms; - _form_set_t const m_all_forms; + dw_class_set const & + classes () const + { + return _m_classes; + } + }; + + class fixed_form + : public basic_form + { + protected: + dwarf_version::form_width_t _m_width; public: - form_table (dwarf_row const forms[], form_table const *parent = NULL) - : m_class_forms (init_class_forms (forms, parent)) - , m_all_forms (init_all_forms (m_class_forms)) + fixed_form (int a_name, dw_class_set a_classes, + dwarf_version::form_width_t a_width) + : basic_form (a_name, a_classes) + , _m_width (a_width) {} - std::set const &get (dw_class c) const + dwarf_version::form_width_t + width (__attribute__ ((unused)) struct cu const *cu = NULL) const { - _form_map_t::const_iterator it = m_class_forms.find (c); - assert (it != m_class_forms.end ()); - return it->second; + return _m_width; } + }; - std::set const &get_all () const + struct width_off { + static dwarf_version::form_width_t width (struct cu const *cu) { + return static_cast (cu->head->offset_size); + } + }; + + struct width_addr { + static dwarf_version::form_width_t width (struct cu const *cu) { + return static_cast (cu->head->address_size); + } + }; + + template + class selwidth_form + : public basic_form + { + public: + template + selwidth_form (int a_name, Clss... a_classes) + : basic_form (a_name, dw_classes (a_classes...)) + {} + + dwarf_version::form_width_t + width (struct cu const *cu) const { - return m_all_forms; + return Sel::width (cu); } }; + typedef selwidth_form w_off_form; + typedef selwidth_form w_addr_form; + + template + class simple_form + : public fixed_form + { + public: + simple_form (int a_name, dwarf_version::form_width_t a_width) + : fixed_form (a_name, dw_classes (Clss...), a_width) + {} + }; + + typedef simple_form block_form; + typedef simple_form const_form; + typedef simple_form ref_form; + typedef simple_form flag_form; + dwarf_row const dwarf_2_at_table[] = { {DW_AT_sibling, dw_classes (cl_reference)}, {DW_AT_location, dw_classes (cl_block, cl_constant)}, @@ -201,30 +277,35 @@ namespace {0, dw_classes ()} }; - dwarf_row const dwarf_2_form_table_rows[] = { - {DW_FORM_addr, dw_classes (cl_address)}, - {DW_FORM_block2, dw_classes (cl_block)}, - {DW_FORM_block4, dw_classes (cl_block)}, - {DW_FORM_data2, dw_classes (cl_constant)}, - {DW_FORM_data4, dw_classes (cl_constant)}, - {DW_FORM_data8, dw_classes (cl_constant)}, - {DW_FORM_string, dw_classes (cl_string)}, - {DW_FORM_block, dw_classes (cl_block)}, - {DW_FORM_block1, dw_classes (cl_block)}, - {DW_FORM_data1, dw_classes (cl_constant)}, - {DW_FORM_flag, dw_classes (cl_flag)}, - {DW_FORM_sdata, dw_classes (cl_constant)}, - {DW_FORM_strp, dw_classes (cl_string)}, - {DW_FORM_udata, dw_classes (cl_constant)}, - {DW_FORM_ref_addr, dw_classes (cl_reference)}, - {DW_FORM_ref1, dw_classes (cl_reference)}, - {DW_FORM_ref2, dw_classes (cl_reference)}, - {DW_FORM_ref4, dw_classes (cl_reference)}, - {DW_FORM_ref8, dw_classes (cl_reference)}, - {DW_FORM_ref_udata, dw_classes (cl_reference)}, - {0, dw_classes ()} + static x_form const *dwarf_2_forms[] = { + new block_form (DW_FORM_block, dwarf_version::fw_uleb), + new block_form (DW_FORM_block1, dwarf_version::fw_1), + new block_form (DW_FORM_block2, dwarf_version::fw_2), + new block_form (DW_FORM_block4, dwarf_version::fw_4), + + new const_form (DW_FORM_data1, dwarf_version::fw_1), + new const_form (DW_FORM_data2, dwarf_version::fw_2), + new const_form (DW_FORM_data4, dwarf_version::fw_4), + new const_form (DW_FORM_data8, dwarf_version::fw_8), + new const_form (DW_FORM_sdata, dwarf_version::fw_uleb), + new const_form (DW_FORM_udata, dwarf_version::fw_uleb), + + new flag_form (DW_FORM_flag, dwarf_version::fw_1), + + new ref_form (DW_FORM_ref1, dwarf_version::fw_1), + new ref_form (DW_FORM_ref2, dwarf_version::fw_2), + new ref_form (DW_FORM_ref4, dwarf_version::fw_4), + new ref_form (DW_FORM_ref8, dwarf_version::fw_8), + new ref_form (DW_FORM_ref_udata, dwarf_version::fw_uleb), + + new fixed_form (DW_FORM_string, dw_classes (cl_string), + dwarf_version::fw_unknown), + new w_off_form (DW_FORM_strp, cl_string), + new w_addr_form (DW_FORM_addr, cl_address), + new w_addr_form (DW_FORM_ref_addr, cl_reference), + + NULL }; - form_table const dwarf_2_form_table (dwarf_2_form_table_rows); /* Changes from dwarf_2_*_table: */ dwarf_row const dwarf_3_at_table[] = { @@ -278,14 +359,14 @@ namespace {0, dw_classes ()} }; - dwarf_row const dwarf_3_form_table_rows[] = { - {DW_FORM_data4, dw_classes (cl_constant, cl_lineptr, cl_loclistptr, - cl_macptr, cl_rangelistptr)}, - {DW_FORM_data8, dw_classes (cl_constant, cl_lineptr, cl_loclistptr, - cl_macptr, cl_rangelistptr)}, - {0, dw_classes ()} + typedef simple_form dw3_data_form; + x_form const *dwarf_3_forms[] = { + new dw3_data_form (DW_FORM_data4, dwarf_version::fw_4), + new dw3_data_form (DW_FORM_data8, dwarf_version::fw_8), + new w_off_form (DW_FORM_ref_addr, cl_reference), + NULL }; - form_table const dwarf_3_form_table (dwarf_3_form_table_rows, &dwarf_2_form_table); /* Changes from dwarf_3_*_table: */ dwarf_row const dwarf_4_at_table[] = { @@ -319,73 +400,155 @@ namespace {0, dw_classes ()} }; - dwarf_row const dwarf_4_form_table_rows[] = { - {DW_FORM_data4, dw_classes (cl_constant)}, - {DW_FORM_data8, dw_classes (cl_constant)}, - {DW_FORM_sec_offset, dw_classes (cl_lineptr, cl_loclistptr, - cl_macptr, cl_rangelistptr)}, - {DW_FORM_exprloc, dw_classes (cl_exprloc)}, - {DW_FORM_flag_present, dw_classes (cl_flag)}, - {DW_FORM_ref_sig8, dw_classes (cl_reference)}, - {0, dw_classes ()} + x_form const *dwarf_4_forms[] = { + new const_form (DW_FORM_data4, dwarf_version::fw_4), + new const_form (DW_FORM_data8, dwarf_version::fw_8), + new w_off_form (DW_FORM_sec_offset, + cl_lineptr, cl_loclistptr, cl_macptr, cl_rangelistptr), + new simple_form (DW_FORM_exprloc, dwarf_version::fw_uleb), + new flag_form (DW_FORM_flag_present, dwarf_version::fw_0), + new ref_form (DW_FORM_ref_sig8, dwarf_version::fw_8), + NULL }; - form_table const dwarf_4_form_table (dwarf_4_form_table_rows, &dwarf_3_form_table); class std_dwarf : public dwarf_version { - typedef std::map _forms_t; - _forms_t m_forms; - dwarf_version const *m_parent; - form_table const &m_formtab; + typedef std::map _attr_classes; + _attr_classes const _m_attr_classes; + x_form_table const _m_formtab; + dwarf_version const *_m_parent; + + _attr_classes build_attr_classes (dwarf_row const attrtab[]) + { + _attr_classes ret; + for (unsigned i = 0; attrtab[i].val != 0; ++i) + ret[attrtab[i].val] = attrtab[i].classes; + return ret; + } public: - std_dwarf (dwarf_row const attrtab[], form_table const &formtab, + std_dwarf (dwarf_row const attrtab[], + x_form const *const forms[], dwarf_version const *parent = NULL) - : m_parent (parent) - , m_formtab (formtab) + : _m_attr_classes (build_attr_classes (attrtab)) + , _m_formtab (x_form_table (forms)) + , _m_parent (parent) + {} + + form_width_t + form_width (__attribute__ ((unused)) int form, + __attribute__ ((unused)) struct cu const *cu = NULL) const { - for (unsigned i = 0; attrtab[i].val != 0; ++i) - for (unsigned c = 0; c < attrtab[i].classes.size (); ++c) - if (attrtab[i].classes[c]) - m_forms[attrtab[i].val] - = formtab.get (static_cast (c)); - - /* - std::cout << pri::attr (attrtab[i].at) << " {"; - for (std::set ::const_iterator it = forms.begin (); - it != forms.end (); ++it) - std::cout << (it == forms.begin () ? "" : ", ") << pri::form (*it); - std::cout << "}" << std::endl; - */ + assert (!"NIY!"); + } + + x_form const * + get_form (int name) const + { + if (x_form const *form = _m_formtab.get (name)) + return form; + else if (_m_parent != NULL) + return _m_parent->get_form (name); + else + return NULL; } - form_set_t const &allowed_forms () const + bool + form_allowed (form f) const { - return m_formtab.get_all (); + return _m_formtab.has_form (f) + || (_m_parent != NULL && _m_parent->form_allowed (f)); } - form_set_t const &allowed_forms (attr at) const + dw_class_set const & + attr_classes (int at) const { - _forms_t::const_iterator it = m_forms.find (at); - assert (it != m_forms.end () || m_parent != NULL); - if (it != m_forms.end ()) + _attr_classes::const_iterator it = _m_attr_classes.find (at); + if (it != _m_attr_classes.end ()) return it->second; else - return m_parent->allowed_forms (at); + { + assert (_m_parent != NULL); + if (std_dwarf const *std_parent + = dynamic_cast (_m_parent)) // xxx + return std_parent->attr_classes (at); + } + assert (!"Unsupported attribute!"); // xxx but I won't tell you which one } - // Answer forms allowed at DIE with that tag. - form_set_t const &allowed_forms (attr at, - __attribute__ ((unused)) die_tag tag) const + bool + form_allowed (attr at, form f) const { - return allowed_forms (at); + dw_class_set const &at_classes = attr_classes (at); + x_form const *form = this->get_form (f); + assert (form != NULL); + dw_class_set const &form_classes = form->classes (); + return (at_classes & form_classes).any (); + } + }; + + class x_std_dwarf + : public dwarf_version + { + public: + dwarf_version::form_width_t + form_width (int form, struct cu *cu) + { + switch (form) + { + case DW_FORM_flag_present: + return fw_0; + + case DW_FORM_block1: + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + return fw_1; + + case DW_FORM_block2: + case DW_FORM_data2: + case DW_FORM_ref2: + return fw_2; + + case DW_FORM_block4: + case DW_FORM_data4: + case DW_FORM_ref4: + return fw_4; + + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + return fw_8; + + case DW_FORM_addr: + return cu->head->address_size == 8 ? fw_8 : fw_4; + + case DW_FORM_ref_addr: + case DW_FORM_strp: + case DW_FORM_sec_offset: + return cu->head->offset_size == 8 ? fw_8 : fw_4; + + case DW_FORM_block: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_exprloc: + case DW_FORM_indirect: + return fw_uleb; + + case DW_FORM_string: + throw std::runtime_error + ("You shouldn't need the width of DW_FORM_string."); + } + + assert (!"Unhandled form!"); } }; - std_dwarf dwarf2 (dwarf_2_at_table, dwarf_2_form_table); - std_dwarf dwarf3 (dwarf_3_at_table, dwarf_3_form_table, &dwarf2); - std_dwarf dwarf4 (dwarf_4_at_table, dwarf_4_form_table, &dwarf3); + std_dwarf dwarf2 (dwarf_2_at_table, dwarf_2_forms); + std_dwarf dwarf3 (dwarf_3_at_table, dwarf_3_forms, &dwarf2); + std_dwarf dwarf4 (dwarf_4_at_table, dwarf_4_forms, &dwarf3); } dwarf_version const * diff --git a/dwarflint/tables.hh b/dwarflint/tables.hh index 6208b893c..f97866d41 100644 --- a/dwarflint/tables.hh +++ b/dwarflint/tables.hh @@ -28,48 +28,42 @@ #define DWARFLINT_TABLES_HH #include +#include "check_debug_info.ii" -typedef int form; +typedef int form; // xxx get rid of this or something, it collides + // with the x_form stuff. typedef int attr; typedef int die_tag; class locexpr_op {}; +class x_form; // xxx and rename this guy + class dwarf_version { -protected: - typedef std::set form_set_t; - -private: - inline static bool find_form (form_set_t const &s, int f) - { - return s.find (f) != s.end (); - } - public: - // Answer all known forms. - virtual form_set_t const &allowed_forms () const = 0; + enum form_width_t + { + fw_0 = 0, + fw_1 = 1, + fw_2 = 2, + fw_4 = 4, + fw_8 = 8, + fw_uleb, + fw_unknown + }; + // Return width of data stored with given form. CU may be NULL if + // you are sure that the form size doesn't depend on addr_64 or off. + // Forms for which width makes no sense, such as DW_FORM_string, get + // fw_unknown. Unknown forms get an assert. + virtual form_width_t + form_width (int form, struct cu const *cu = NULL) const = 0; - // Answer all forms allowed in theory for this attribute. - virtual form_set_t const &allowed_forms (attr at) const = 0; +public: + virtual bool form_allowed (form f) const = 0; - // Answer forms allowed for this attribute at DIE with that tag. - virtual form_set_t const &allowed_forms (attr at, die_tag tag) const = 0; + virtual x_form const *get_form (int name) const = 0; -public: - bool form_allowed (form f) const - { - return find_form (allowed_forms (), f); - } - - bool form_allowed (attr at, form f) const - { - return find_form (allowed_forms (at), f); - } - - bool form_allowed (attr at, form f, die_tag tag) const - { - return find_form (allowed_forms (at, tag), f); - } + virtual bool form_allowed (attr at, form f) const = 0; int check_sibling_form (int form) const;