unplugged-system/frameworks/libs/binary_translation/tools/nogrod/dwarf_abbrev.cc

1047 lines
42 KiB
C++

/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dwarf_abbrev.h"
#include <map>
#include <memory>
#include <vector>
#include "berberis/base/stringprintf.h"
#include "dwarf_constants.h"
namespace nogrod {
namespace {
using berberis::StringPrintf;
class DwarfClasses {
public:
DwarfClasses() { classes_[0] = {}; }
DwarfClasses(std::initializer_list<const DwarfClass*> classes) {
classes_[0] = std::vector(classes);
}
DwarfClasses(
std::initializer_list<std::map<uint16_t, std::vector<const DwarfClass*>>::value_type> classes)
: classes_(classes) {}
[[nodiscard]] const std::vector<const DwarfClass*>* get(uint16_t version) const {
auto candidate = classes_.find(version);
if (candidate != classes_.end()) {
return &candidate->second;
}
for (auto it = classes_.begin(), end = classes_.end(); it != end; ++it) {
if (it->first <= version) {
candidate = it;
} else {
break;
}
}
return candidate != classes_.end() ? &candidate->second : nullptr;
}
private:
// classes for every version
std::map<uint16_t, std::vector<const DwarfClass*>> classes_;
};
struct AbbrevDescriptor {
uint32_t code;
DwarfClasses classes;
const char* name;
};
// clang-format makes this part unreadable so we disable it.
// clang-format off
const AbbrevDescriptor kFormDescriptors[] = {
{ 0x00, { }, "null"},
{ 0x01, { DwarfClass::kAddress }, "DW_FORM_addr" },
{ 0x02, { }, "Reserved 0x02" },
{ 0x03, { DwarfClass::kBlock }, "DW_FORM_block2" },
{ 0x04, { DwarfClass::kBlock }, "DW_FORM_block4" },
{ 0x05, { DwarfClass::kConstant }, "DW_FORM_data2" },
{ 0x06, { DwarfClass::kConstant }, "DW_FORM_data4" },
{ 0x07, { DwarfClass::kConstant }, "DW_FORM_data8" },
{ 0x08, { DwarfClass::kString }, "DW_FORM_string" },
{ 0x09, { DwarfClass::kBlock }, "DW_FORM_block" },
{ 0x0a, { DwarfClass::kBlock }, "DW_FORM_block4" },
{ 0x0b, { DwarfClass::kConstant }, "DW_FORM_data1" },
{ 0x0c, { DwarfClass::kFlag }, "DW_FORM_flag" },
{ 0x0d, { DwarfClass::kConstant }, "DW_FORM_sdata" },
{ 0x0e, { DwarfClass::kString }, "DW_FORM_strp" },
{ 0x0f, { DwarfClass::kConstant }, "DW_FORM_udata" },
{ 0x10, { DwarfClass::kReference }, "DW_FORM_ref_addr" },
{ 0x11, { DwarfClass::kReference }, "DW_FORM_ref1" },
{ 0x12, { DwarfClass::kReference }, "DW_FORM_ref2" },
{ 0x13, { DwarfClass::kReference }, "DW_FORM_ref4" },
{ 0x14, { DwarfClass::kReference }, "DW_FORM_ref8" },
{ 0x15, { DwarfClass::kReference }, "DW_FORM_ref_udata" },
{ 0x16, {}, "DW_FORM_indirect" }, // TODO(dimitry): DwarfClass::kIndirect?
{ 0x17, { DwarfClass::kAddrptr,
DwarfClass::kLineptr,
//DwarfClass::kLoclist,
DwarfClass::kLoclistsptr,
DwarfClass::kMacptr,
//DwarfClass::kRnglist,
DwarfClass::kRnglistsptr,
DwarfClass::kStroffsetsptr,
}, "DW_FORM_sec_offset"},
{ 0x18, { DwarfClass::kExprloc }, "DW_FORM_exprloc" },
{ 0x19, { DwarfClass::kFlag }, "DW_FORM_flag_present" },
{ 0x1a, { DwarfClass::kString }, "DW_FORM_strx" },
{ 0x1b, { DwarfClass::kAddress }, "DW_FORM_addrx" },
{ 0x1c, { DwarfClass::kReference }, "DW_FORM_ref_sup4" },
{ 0x1d, { DwarfClass::kString }, "DW_FORM_strp_sup" },
{ 0x1e, { DwarfClass::kConstant }, "DW_FORM_data16" },
{ 0x1f, { DwarfClass::kString }, "DW_FORM_line_strp" },
{ 0x20, { DwarfClass::kReference }, "DW_FORM_ref_sig8" },
{ 0x21, { DwarfClass::kConstant }, "DW_FORM_implicit_const" },
{ 0x22, { DwarfClass::kLoclist }, "DW_FORM_loclistx" },
{ 0x23, { DwarfClass::kRnglist }, "DW_FORM_rnglistx" },
{ 0x24, { DwarfClass::kReference }, "DW_FORM_ref_sup8" },
{ 0x25, { DwarfClass::kString }, "DW_FORM_strx1" },
{ 0x26, { DwarfClass::kString }, "DW_FORM_strx2" },
{ 0x27, { DwarfClass::kString }, "DW_FORM_strx3" },
{ 0x28, { DwarfClass::kString }, "DW_FORM_strx4" },
{ 0x29, { DwarfClass::kAddress }, "DW_FORM_addrx1" },
{ 0x2a, { DwarfClass::kAddress }, "DW_FORM_addrx2" },
{ 0x2b, { DwarfClass::kAddress }, "DW_FORM_addrx3" },
{ 0x2c, { DwarfClass::kAddress }, "DW_FORM_addrx4" },
};
const AbbrevDescriptor kNameDescriptors[] = {
{ 0x00, { }, "null" },
{ 0x01, { { 2, { DwarfClass::kReference } } }, "DW_AT_sibling" },
{ 0x02, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, DwarfClass::kLoclist } },
}, "DW_AT_location" },
{ 0x03, { { 2, { DwarfClass::kString } } }, "DW_AT_name" },
{ 0x04, { }, "Reserved 0x04" },
{ 0x05, { }, "Reserved 0x05" },
{ 0x06, { }, "Reserved 0x06" },
{ 0x07, { }, "Reserved 0x07" },
{ 0x08, { }, "Reserved 0x08" },
{ 0x09, { { 2, { DwarfClass::kConstant } } }, "DW_AT_ordering" },
{ 0x0a, { }, "Reserved 0x0a" },
{ 0x0b, {
{ 2, { DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock,
DwarfClass::kConstant,
DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant,
DwarfClass::kExprloc,
DwarfClass::kReference } },
}, "DW_AT_byte_size" },
{ 0x0c, {
{ 2, { DwarfClass::kConstant } },
{ 3, { DwarfClass::kConstant,
DwarfClass::kBlock,
DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant,
DwarfClass::kExprloc,
DwarfClass::kReference } },
}, "DW_AT_bit_offset" }, // Removed in dwarf5??
{ 0x0d, {
{ 2, { DwarfClass::kConstant } },
{ 3, { DwarfClass::kConstant,
DwarfClass::kBlock,
DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant,
DwarfClass::kExprloc,
DwarfClass::kReference } },
}, "DW_AT_bit_size" },
{ 0x0e, { }, "Reserved 0x0e" },
{ 0x0f, { }, "Reserved 0x0f" },
{ 0x10, {
{ 2, { DwarfClass::kConstant } },
{ 3, { DwarfClass::kLineptr } },
}, "DW_AT_stmt_list" },
{ 0x11, { { 2, { DwarfClass::kAddress } } }, "DW_AT_low_pc" },
{ 0x12, {
{ 2, { DwarfClass::kAddress } },
{ 4, { DwarfClass::kAddress, DwarfClass::kConstant } },
}, "DW_AT_high_pc" },
{ 0x13, { { 2, { DwarfClass::kConstant } } }, "DW_AT_language" },
{ 0x14, { }, "Reserved 0x14" },
{ 0x15, { { 2, { DwarfClass::kReference } } }, "DW_AT_discr" },
{ 0x16, { { 2, { DwarfClass::kConstant } } }, "DW_AT_discr_value" },
{ 0x17, { { 2, { DwarfClass::kConstant } } }, "DW_AT_visibility" },
{ 0x18, { { 2, { DwarfClass::kReference } } }, "DW_AT_import" },
{ 0x19, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc/*, DwarfClass::kLoclist */, DwarfClass::kReference } },
}, "DW_AT_string_length" },
{ 0x1a, { { 2, { DwarfClass::kReference } } }, "DW_AT_common_reference" },
{ 0x1b, { { 2, { DwarfClass::kString } } }, "DW_AT_comp_dir" },
{ 0x1c, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kString } }
}, "DW_AT_const_value" },
{ 0x1d, { { 2, { DwarfClass::kReference } } }, "DW_AT_containing_type" },
{ 0x1e, {
{ 2, { DwarfClass::kReference } },
{ 5, { DwarfClass::kConstant,
DwarfClass::kReference,
DwarfClass::kFlag } }
}, "DW_AT_default_value" },
{ 0x1f, { }, "Reserved 0x1f" },
{ 0x20, { { 2, { DwarfClass::kConstant } } }, "DW_AT_inline" },
{ 0x21, { { 2, { DwarfClass::kFlag } } }, "DW_AT_is_optional" },
{ 0x22, {
{ 2, { DwarfClass::kConstant, DwarfClass::kReference } },
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_lower_bound" },
{ 0x23, { }, "Reserved 0x23" },
{ 0x24, { }, "Reserved 0x24" },
{ 0x25, { { 2, { DwarfClass::kString } } }, "DW_AT_producer" },
{ 0x26, { }, "Reserved 0x26" },
{ 0x27, { { 2, { DwarfClass::kFlag } } }, "DW_AT_prototyped" },
{ 0x28, { }, "Reserved 0x28" },
{ 0x29, { }, "Reserved 0x29" },
{ 0x2a, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } }
}, "DW_AT_return_addr" },
{ 0x2b, { }, "Reserved 0x2b" },
{ 0x2c, {
{ 2, { DwarfClass::kConstant } },
{ 4, { DwarfClass::kConstant, DwarfClass::kRnglistsptr } },
{ 5, { DwarfClass::kConstant, /* DwarfClass::kRnglist */ } }
}, "DW_AT_start_scope" },
{ 0x2d, { }, "Reserved 0x2d" },
{ 0x2e, {
{ 2, { DwarfClass::kConstant } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_bit_stride" }, // called "DW_AT_stride_size" in dwarf2
{ 0x2f, {
{ 2, { DwarfClass::kConstant, DwarfClass::kReference } },
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_upper_bound" },
{ 0x30, { }, "Reserved 0x30" },
{ 0x31, { { 2, { DwarfClass::kReference } } }, "DW_AT_abstract_origin" },
{ 0x32, { { 2, { DwarfClass::kConstant } } }, "DW_AT_accessibility" },
{ 0x33, { { 2, { DwarfClass::kConstant } } }, "DW_AT_address_class" },
{ 0x34, { { 2, { DwarfClass::kFlag } } }, "DW_AT_artificial" },
{ 0x35, { { 2, { DwarfClass::kReference } } }, "DW_AT_base_types" },
{ 0x36, { { 2, { DwarfClass::kConstant } } }, "DW_AT_calling_convention" },
{ 0x37, {
{ 2, { DwarfClass::kConstant, DwarfClass::kReference } },
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_count" },
{ 0x38, {
{ 2, { DwarfClass::kBlock, DwarfClass::kReference } },
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kConstant, DwarfClass::kExprloc /*, DwarfClass::kLoclist */ } },
}, "DW_AT_data_member_location" },
{ 0x39, { { 2, { DwarfClass::kConstant } } }, "DW_AT_decl_column" },
{ 0x3a, { { 2, { DwarfClass::kConstant } } }, "DW_AT_decl_file" },
{ 0x3b, { { 2, { DwarfClass::kConstant } } }, "DW_AT_decl_line" },
{ 0x3c, { { 2, { DwarfClass::kFlag } } }, "DW_AT_declaration" },
{ 0x3d, { { 2, { DwarfClass::kBlock } } }, "DW_AT_discr_list" },
{ 0x3e, { { 2, { DwarfClass::kConstant } } }, "DW_AT_encoding" },
{ 0x3f, { { 2, { DwarfClass::kFlag } } }, "DW_AT_external" },
{ 0x40, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } },
}, "DW_AT_frame_base" },
{ 0x41, { { 2, { DwarfClass::kReference } } }, "DW_AT_friend" },
{ 0x42, { { 2, { DwarfClass::kConstant } } }, "DW_AT_identifier_case" },
{ 0x43, {
{ 2, { DwarfClass::kConstant } },
{ 3, { DwarfClass::kMacptr } },
}, "DW_AT_macro_info" }, // Removed in dwarf5??
{ 0x44, {
{ 2, { DwarfClass::kBlock } },
{ 4, { DwarfClass::kReference } },
}, "DW_AT_namelist_item" },
{ 0x45, { { 2, { DwarfClass::kReference } } }, "DW_AT_priority" },
{ 0x46, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } },
}, "DW_AT_segment" },
{ 0x47, { { 2, { DwarfClass::kReference } } }, "DW_AT_specification" },
{ 0x48, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } },
}, "DW_AT_static_link" },
{ 0x49, { { 2, { DwarfClass::kReference } } }, "DW_AT_type" },
{ 0x4a, {
{ 2, { DwarfClass::kBlock, DwarfClass::kConstant } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } },
}, "DW_AT_use_location" },
{ 0x4b, { { 2, { DwarfClass::kFlag } } }, "DW_AT_variable_parameter" },
{ 0x4c, { { 2, { DwarfClass::kConstant } } }, "DW_AT_virtuality" },
{ 0x4d, {
{ 2, { DwarfClass::kBlock, DwarfClass::kReference } },
{ 3, { DwarfClass::kBlock, DwarfClass::kLoclistsptr } },
{ 4, { DwarfClass::kExprloc, DwarfClass::kLoclistsptr } },
{ 5, { DwarfClass::kExprloc, /* DwarfClass::kLoclist */ } },
}, "DW_AT_vtable_elem_location" },
// Dwarf 3
{ 0x4e, {
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_allocated" },
{ 0x4f, {
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_associated" },
{ 0x50, {
{ 3, { DwarfClass::kBlock } },
{ 4, { DwarfClass::kExprloc } },
}, "DW_AT_data_location" },
{ 0x51, {
{ 3, { DwarfClass::kBlock, DwarfClass::kConstant, DwarfClass::kReference } },
{ 4, { DwarfClass::kConstant, DwarfClass::kExprloc, DwarfClass::kReference } },
}, "DW_AT_byte_stride" },
{ 0x52, {
{ 3, { DwarfClass::kAddress } },
{ 5, { DwarfClass::kAddress, DwarfClass::kConstant } },
}, "DW_AT_entry_pc" },
{ 0x53, { { 3, { DwarfClass::kFlag } } }, "DW_AT_use_UTF8" },
{ 0x54, { { 3, { DwarfClass::kReference } } }, "DW_AT_extension" },
{ 0x55, {
{ 2, { DwarfClass::kConstant } }, // not in spec, but clang uses this in dwarf2??
{ 3, { DwarfClass::kRnglistsptr } },
{ 5, { DwarfClass::kRnglist } },
}, "DW_AT_ranges" },
{ 0x56, {
{ 3, { DwarfClass::kAddress,
DwarfClass::kFlag,
DwarfClass::kReference,
DwarfClass::kString } },
}, "DW_AT_trampoline" },
{ 0x57, { { 3, { DwarfClass::kConstant } } }, "DW_AT_call_column" },
{ 0x58, { { 3, { DwarfClass::kConstant } } }, "DW_AT_call_file" },
{ 0x59, { { 3, { DwarfClass::kConstant } } }, "DW_AT_call_line" },
{ 0x5a, { { 3, { DwarfClass::kString } } }, "DW_AT_description" },
{ 0x5b, { { 3, { DwarfClass::kConstant } } }, "DW_AT_binary_scale" },
{ 0x5c, { { 3, { DwarfClass::kConstant } } }, "DW_AT_decimal_scale" },
{ 0x5d, { { 3, { DwarfClass::kReference } } }, "DW_AT_small" },
{ 0x5e, { { 3, { DwarfClass::kConstant } } }, "DW_AT_decimal_sign" },
{ 0x5f, { { 3, { DwarfClass::kConstant } } }, "DW_AT_digit_count" },
{ 0x60, { { 3, { DwarfClass::kString } } }, "DW_AT_picture_string" },
{ 0x61, { { 3, { DwarfClass::kFlag } } }, "DW_AT_mutable" },
{ 0x62, { { 3, { DwarfClass::kFlag } } }, "DW_AT_thread_scaled" },
{ 0x63, { { 3, { DwarfClass::kFlag } } }, "DW_AT_explicit" },
{ 0x64, { { 3, { DwarfClass::kReference } } }, "DW_AT_object_pointer" },
{ 0x65, { { 3, { DwarfClass::kConstant } } }, "DW_AT_endianity" },
{ 0x66, { { 3, { DwarfClass::kFlag } } }, "DW_AT_elemental" },
{ 0x67, { { 3, { DwarfClass::kFlag } } }, "DW_AT_pure" },
{ 0x68, { { 3, { DwarfClass::kFlag } } }, "DW_AT_recursive" },
// Dwarf 4
{ 0x69, { { 4, { DwarfClass::kReference } } }, "DW_AT_signature" },
{ 0x6a, { { 4, { DwarfClass::kFlag } } }, "DW_AT_main_subprogram" },
{ 0x6b, { { 4, { DwarfClass::kConstant } } }, "DW_AT_data_bit_offset" },
{ 0x6c, { { 4, { DwarfClass::kFlag } } }, "DW_AT_const_expr" },
{ 0x6d, { { 4, { DwarfClass::kFlag } } }, "DW_AT_enum_class" },
{ 0x6e, { { 4, { DwarfClass::kString } } }, "DW_AT_linkage_name" },
// Dwarf 5
{ 0x6f, { { 5, { DwarfClass::kConstant } } }, "DW_AT_string_length_bit_size" },
{ 0x70, { { 5, { DwarfClass::kConstant } } }, "DW_AT_string_length_byte_size" },
{ 0x71, { { 5, { DwarfClass::kConstant, DwarfClass::kExprloc } } }, "DW_AT_rank" },
{ 0x72, { { 5, { DwarfClass::kStroffsetsptr } } }, "DW_AT_str_offset_base" },
{ 0x73, { { 5, { DwarfClass::kAddrptr } } }, "DW_AT_addr_base" },
{ 0x74, { { 5, { DwarfClass::kRnglistsptr } } }, "DW_AT_rnglists_base" },
{ 0x75, { }, "Unused 0x75" },
{ 0x76, { { 5, { DwarfClass::kString } } }, "DW_AT_dwo_name" },
// The following are dwarf 5 by spec but clang still injects it to dwarf4
{ 0x77, { { 4, { DwarfClass::kFlag } } }, "DW_AT_reference" },
{ 0x78, { { 4, { DwarfClass::kFlag } } }, "DW_AT_rvalue_reference" },
{ 0x79, { { 5, { DwarfClass::kMacptr } } }, "DW_AT_macros" },
{ 0x7a, { { 5, { DwarfClass::kFlag } } }, "DW_AT_call_all_calls" },
{ 0x7b, { { 5, { DwarfClass::kFlag } } }, "DW_AT_call_all_source_calls" },
{ 0x7c, { { 5, { DwarfClass::kFlag } } }, "DW_AT_call_all_tail_calls" },
{ 0x7d, { { 5, { DwarfClass::kAddress } } }, "DW_AT_call_return_pc" },
{ 0x7e, { { 5, { DwarfClass::kExprloc } } }, "DW_AT_call_value" },
// kReference is not allowed for DW_AT_call_origin by DWARF5 standard, but it is used by clang
{ 0x7f, { { 5, { DwarfClass::kExprloc, DwarfClass::kReference } } }, "DW_AT_call_origin" },
{ 0x80, { { 5, { DwarfClass::kReference } } }, "DW_AT_call_parameter" },
{ 0x81, { { 5, { DwarfClass::kAddress } } }, "DW_AT_call_pc" },
{ 0x82, { { 5, { DwarfClass::kFlag } } }, "DW_AT_call_tail_call" },
{ 0x83, { { 5, { DwarfClass::kExprloc } } }, "DW_AT_call_target" },
{ 0x84, { { 5, { DwarfClass::kExprloc } } }, "DW_AT_call_target_clobbered" },
{ 0x85, { { 5, { DwarfClass::kExprloc } } }, "DW_AT_call_data_location" },
{ 0x86, { { 5, { DwarfClass::kExprloc } } }, "DW_AT_call_data_value" },
// Apparently clang uses these in dwarf4 CUs
{ 0x87, { { 4, { DwarfClass::kFlag } } }, "DW_AT_noreturn" },
{ 0x88, { { 4, { DwarfClass::kConstant } } }, "DW_AT_alignment" },
{ 0x89, { { 4, { DwarfClass::kFlag } } }, "DW_AT_export_symbols" },
{ 0x8a, { { 5, { DwarfClass::kFlag } } }, "DW_AT_deleted" },
{ 0x8b, { { 5, { DwarfClass::kConstant } } }, "DW_AT_defaulted" },
{ 0x8c, { { 5, { DwarfClass::kLoclistsptr } } }, "DW_AT_loclists_base" },
};
// clang-format on
static_assert(sizeof(kFormDescriptors) / sizeof(AbbrevDescriptor) == (DW_FORM_MAX_VALUE + 1), "");
static_assert(sizeof(kNameDescriptors) / sizeof(AbbrevDescriptor) == (DW_AT_MAX_VALUE + 1), "");
const AbbrevDescriptor kAtGnuVector = {0x2107, {DwarfClass::kFlag}, "DW_AT_GNU_vector"};
const AbbrevDescriptor kAtGnuTemplateName = {0x2110,
{DwarfClass::kString},
"DW_AT_GNU_template_name"};
const AbbrevDescriptor kAtGnuCallSiteValue = {0x2111,
{DwarfClass::kExprloc},
"DW_AT_GNU_call_site_value"};
const AbbrevDescriptor kAtGnuCallSiteTarget = {0x2113,
{DwarfClass::kExprloc},
"DW_AT_GNU_call_site_target"};
const AbbrevDescriptor kAtGnuTailCall = {0x2115, {DwarfClass::kFlag}, "DW_AT_GNU_tail_call"};
const AbbrevDescriptor kAtGnuAllTailCallSites = {0x2116,
{DwarfClass::kFlag},
"DW_AT_GNU_all_tail_call_sites"};
const AbbrevDescriptor kAtGnuAllCallSites = {0x2117,
{DwarfClass::kFlag},
"DW_AT_GNU_all_call_sites"};
const AbbrevDescriptor kAtGnuPubnamesDescriptor = {0x2134,
{DwarfClass::kFlag},
"DW_AT_GNU_pubnames"};
const AbbrevDescriptor kAtGnuDiscriminator = {0x2136,
{DwarfClass::kConstant},
"DW_AT_GNU_discriminator"};
const AbbrevDescriptor kAtGnuLocviews = {0x2137, {DwarfClass::kLoclistsptr}, "DW_AT_GNU_locviews"};
const AbbrevDescriptor kAtGnuEntryView = {0x2138, {DwarfClass::kConstant}, "DW_AT_GNU_entry_view"};
const AbbrevDescriptor* GetNameDescriptor(uint32_t name) {
switch (name) {
case DW_AT_GNU_vector:
return &kAtGnuVector;
case DW_AT_GNU_template_name:
return &kAtGnuTemplateName;
case DW_AT_GNU_call_site_value:
return &kAtGnuCallSiteValue;
case DW_AT_GNU_call_site_target:
return &kAtGnuCallSiteTarget;
case DW_AT_GNU_tail_call:
return &kAtGnuTailCall;
case DW_AT_GNU_all_tail_call_sites:
return &kAtGnuAllTailCallSites;
case DW_AT_GNU_all_call_sites:
return &kAtGnuAllCallSites;
case DW_AT_GNU_pubnames:
return &kAtGnuPubnamesDescriptor;
case DW_AT_GNU_discriminator:
return &kAtGnuDiscriminator;
case DW_AT_GNU_locviews:
return &kAtGnuLocviews;
case DW_AT_GNU_entry_view:
return &kAtGnuEntryView;
}
if (name > DW_AT_MAX_VALUE) {
return nullptr;
}
return kNameDescriptors + name;
}
std::string NameToString(uint32_t name) {
auto descriptor = GetNameDescriptor(name);
if (descriptor == nullptr) {
return StringPrintf("unknown-0x%x", name);
}
return descriptor->name;
}
std::string FormToString(uint32_t form) {
if (form >= DW_FORM_MAX_VALUE) {
return StringPrintf("unknown-0x%x", form);
}
return kFormDescriptors[form].name;
}
class DwarfClassAddress : public DwarfClass {
public:
DwarfClassAddress() : DwarfClass("address") {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader* cu,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint64_t address;
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
if (form == DW_FORM_addr) {
uint8_t address_size = cu->address_size();
if (address_size != 4 && address_size != 8) {
*error_msg = StringPrintf("Invalid address size %d (expected 4 or 8)", address_size);
return nullptr;
}
address = address_size == 4 ? bs->ReadUint32() : bs->ReadUint64();
} else if (form == DW_FORM_addrx || form == DW_FORM_addrx1 || form == DW_FORM_addrx2 ||
form == DW_FORM_addrx3 || form == DW_FORM_addrx4) {
address = bs->ReadLeb128();
} else {
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
return std::unique_ptr<DwarfAttribute>(new DwarfAttributeValue<uint64_t>(name, address));
}
};
class DwarfClassBlock : public DwarfClass {
public:
DwarfClassBlock() : DwarfClass("block") {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader*,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint64_t size = 0;
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
switch (form) {
case DW_FORM_block1:
size = bs->ReadUint8();
break;
case DW_FORM_block2:
size = bs->ReadUint16();
break;
case DW_FORM_block4:
size = bs->ReadUint32();
break;
case DW_FORM_block:
size = bs->ReadLeb128();
break;
default:
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
std::vector<uint8_t> data = bs->ReadBytes(size);
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<std::vector<uint8_t>>(name, std::move(data)));
}
};
class DwarfClassConstant : public DwarfClass {
public:
DwarfClassConstant() : DwarfClass("constant") {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader*,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint64_t size = 0;
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
if (form == DW_FORM_implicit_const) {
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<int64_t>(name, abbrev_attr->value()));
}
if (form == DW_FORM_sdata) {
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<int64_t>(name, bs->ReadSleb128()));
}
if (form == DW_FORM_udata) {
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<uint64_t>(name, bs->ReadLeb128()));
}
switch (form) {
case DW_FORM_data1:
size = 1;
break;
case DW_FORM_data2:
size = 2;
break;
case DW_FORM_data4:
size = 4;
break;
case DW_FORM_data8:
size = 8;
break;
case DW_FORM_data16:
size = 16;
break;
default:
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
std::vector<uint8_t> data = bs->ReadBytes(size);
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<std::vector<uint8_t>>(name, std::move(data)));
}
};
class DwarfClassExprloc : public DwarfClass {
public:
DwarfClassExprloc() : DwarfClass("exprloc") {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader*,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
if (form != DW_FORM_exprloc) {
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
uint64_t length = bs->ReadLeb128();
return std::unique_ptr<DwarfAttribute>(
new DwarfAttributeValue<std::vector<uint8_t>>(name, bs->ReadBytes(length)));
}
};
class DwarfClassFlag : public DwarfClass {
public:
DwarfClassFlag() : DwarfClass("flag") {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader*,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
bool value;
if (form == DW_FORM_flag_present) {
value = true;
} else if (form == DW_FORM_flag) {
value = bs->ReadUint8();
} else {
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
return std::unique_ptr<DwarfAttribute>(new DwarfAttributeValue<bool>(name, value));
}
};
// Use this implementation for classes where we are not interested in the value
// This one reads offset and puts it into attribute list. It does not read the
// actual value from the corresponding target segment.
class DwarfClassBaseptr : public DwarfClass {
public:
explicit DwarfClassBaseptr(const char* name) : DwarfClass(name) {}
virtual std::unique_ptr<DwarfAttribute> ReadAttribute(const DwarfCompilationUnitHeader* cu,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
if (form == DW_FORM_sec_offset) {
uint64_t offset = cu->is_dwarf64() ? bs->ReadUint64() : bs->ReadUint32();
return std::make_unique<DwarfAttributeValue<uint64_t>>(name, offset);
}
if (form == DW_FORM_rnglistx || form == DW_FORM_loclistx) {
return std::make_unique<DwarfAttributeValue<uint64_t>>(name, bs->ReadLeb128());
}
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
};
class DwarfClassReference : public DwarfClass {
public:
DwarfClassReference() : DwarfClass("reference") {}
[[nodiscard]] std::unique_ptr<DwarfAttribute> ReadAttribute(
const DwarfCompilationUnitHeader* cu,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
uint64_t offset = 0;
switch (form) {
case DW_FORM_ref1:
offset = cu->unit_offset() + bs->ReadUint8();
break;
case DW_FORM_ref2:
offset = cu->unit_offset() + bs->ReadUint16();
break;
case DW_FORM_ref4:
offset = cu->unit_offset() + bs->ReadUint32();
break;
case DW_FORM_ref8:
offset = cu->unit_offset() + bs->ReadUint64();
break;
case DW_FORM_ref_udata:
offset = cu->unit_offset() + bs->ReadLeb128();
break;
case DW_FORM_ref_addr:
offset = cu->is_dwarf64() ? bs->ReadUint64() : bs->ReadUint32();
break;
// TODO(dimitry): DW_FORM_ref_sig8?
default:
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
return std::unique_ptr<DwarfAttribute>(new DwarfAttributeValue<uint64_t>(name, offset));
}
};
class DwarfClassString : public DwarfClass {
public:
DwarfClassString() : DwarfClass("string") {}
[[nodiscard]] std::unique_ptr<DwarfAttribute> ReadAttribute(
const DwarfCompilationUnitHeader* cu,
const DwarfAbbrevAttribute* abbrev_attr,
DwarfContext* context,
std::string* error_msg) const override {
ByteInputStream* bs = context->info_stream();
uint32_t form = abbrev_attr->form();
uint32_t name = abbrev_attr->name();
switch (form) {
case DW_FORM_string:
// This form should be deprecated...
return std::make_unique<DwarfAttributeValue<std::string>>(name, bs->ReadString());
case DW_FORM_strp: {
uint64_t offset = cu->is_dwarf64() ? bs->ReadUint64() : bs->ReadUint32();
std::string value = context->debug_str_table()->GetString(offset);
return std::make_unique<DwarfAttributeValue<std::string>>(name, value);
}
case DW_FORM_strx:
return std::make_unique<DwarfStrXAttribute>(name, bs->ReadLeb128());
case DW_FORM_strx1:
return std::make_unique<DwarfStrXAttribute>(name, bs->ReadUint8());
case DW_FORM_strx2:
return std::make_unique<DwarfStrXAttribute>(name, bs->ReadUint16());
case DW_FORM_strx3:
return std::make_unique<DwarfStrXAttribute>(name, bs->ReadUint24());
case DW_FORM_strx4:
return std::make_unique<DwarfStrXAttribute>(name, bs->ReadUint32());
default:
// We do not support supplemental object files and debug_line_str (DW_FORM_line_strp) atm.
*error_msg = StringPrintf("%s:%d:%s: Unsupported form %s for class: %s",
__FILE__,
__LINE__,
__FUNCTION__,
FormToString(form).c_str(),
NameToString(name).c_str());
return nullptr;
}
}
};
const DwarfClass* FindDwarfClass(uint16_t version,
uint32_t name,
uint32_t form,
std::string* error_msg) {
if (form > DW_FORM_MAX_VALUE) {
*error_msg = StringPrintf("Invalid abbrev attribute form: 0x%x", form);
return nullptr;
}
auto name_descriptor = GetNameDescriptor(name);
if (name_descriptor == nullptr) {
*error_msg = StringPrintf("Invalid abbrev attribute name: 0x%x", name);
return nullptr;
}
auto name_classes = name_descriptor->classes.get(version);
if (name_classes == nullptr) {
*error_msg = StringPrintf(
"failed to lookup classes for %s (0x%x) version=%d", name_descriptor->name, name, version);
return nullptr;
}
auto& form_descriptor = kFormDescriptors[form];
auto form_classes = form_descriptor.classes.get(version);
if (form_classes == nullptr) {
*error_msg = StringPrintf(
"failed to lookup classes for %s (0x%x) version=%d", form_descriptor.name, form, version);
return nullptr;
}
// Check if the class identified by form actually in the list of classes
// supported by name
const DwarfClass* result = nullptr;
for (auto form_class : *form_classes) {
for (auto name_class : *name_classes) {
if (name_class == form_class) { // found valid combination
if (result != nullptr) {
*error_msg = StringPrintf(
"Incompatible combination of form %s(%x) and name %s(%x): "
"Found more than one intersection of classes (%s and %s)",
form_descriptor.name,
form,
name_descriptor->name,
name,
result->name(),
name_class->name());
return nullptr;
}
result = name_class;
}
}
}
if (result == nullptr) {
*error_msg = StringPrintf("form %s (0x%x) is not applicable to the name %s (0x%x) version=%d.",
form_descriptor.name,
form,
name_descriptor->name,
name,
version);
}
return result;
}
DwarfClassAddress g_class_address;
DwarfClassBaseptr g_class_addrptr("addrptr");
DwarfClassBlock g_class_block;
DwarfClassConstant g_class_constant;
DwarfClassExprloc g_class_exprloc;
DwarfClassFlag g_class_flag;
DwarfClassBaseptr g_class_lineptr("lineptr");
DwarfClassBaseptr g_class_loclist("loclist");
DwarfClassBaseptr g_class_loclistptr("loclistptr");
DwarfClassBaseptr g_class_macptr("macptr");
DwarfClassReference g_class_reference;
DwarfClassBaseptr g_class_rnglist("rnglist");
DwarfClassBaseptr g_class_rnglistptr("rnglistptr");
DwarfClassString g_class_string;
DwarfClassBaseptr g_class_stroffsetsptr("rnglistptr");
} // namespace
const DwarfClass* DwarfClass::kAddress = &g_class_address;
const DwarfClass* DwarfClass::kAddrptr = &g_class_addrptr;
const DwarfClass* DwarfClass::kBlock = &g_class_block;
const DwarfClass* DwarfClass::kConstant = &g_class_constant;
const DwarfClass* DwarfClass::kFlag = &g_class_flag;
const DwarfClass* DwarfClass::kExprloc = &g_class_exprloc;
const DwarfClass* DwarfClass::kLineptr = &g_class_lineptr;
const DwarfClass* DwarfClass::kLoclist = &g_class_loclist;
const DwarfClass* DwarfClass::kLoclistsptr = &g_class_loclistptr;
const DwarfClass* DwarfClass::kMacptr = &g_class_macptr;
const DwarfClass* DwarfClass::kReference = &g_class_reference;
const DwarfClass* DwarfClass::kRnglist = &g_class_rnglist;
const DwarfClass* DwarfClass::kRnglistsptr = &g_class_rnglistptr;
const DwarfClass* DwarfClass::kString = &g_class_string;
const DwarfClass* DwarfClass::kStroffsetsptr = &g_class_stroffsetsptr;
DwarfClass::DwarfClass(const char* name) : name_{name} {}
const char* DwarfClass::name() const {
return name_;
}
DwarfAttribute::DwarfAttribute(uint32_t name) : name_(name) {}
template <typename T>
std::optional<std::string> DwarfAttributeValue<T>::StringValue() const {
return {};
}
template <typename T>
std::optional<uint64_t> DwarfAttributeValue<T>::Uint64Value() const {
return {};
}
template <typename T>
std::optional<bool> DwarfAttributeValue<T>::BoolValue() const {
return {};
}
template <typename T>
void DwarfAttributeValue<T>::Resolve(DwarfContext* /*context*/) {}
template <>
std::optional<std::string> DwarfAttributeValue<std::string>::StringValue() const {
return value_;
}
template <>
std::optional<uint64_t> DwarfAttributeValue<uint64_t>::Uint64Value() const {
return value_;
}
template <>
std::optional<uint64_t> DwarfAttributeValue<std::vector<uint8_t>>::Uint64Value() const {
CHECK(value_.size() <= sizeof(uint64_t));
uint64_t result = 0;
memcpy(&result, value_.data(), value_.size());
return result;
}
template <>
std::optional<bool> DwarfAttributeValue<bool>::BoolValue() const {
return value_;
}
std::optional<std::string> DwarfStrXAttribute::StringValue() const {
// At this point we expect the string to exist.
CHECK(string_.has_value());
return string_.value();
}
void DwarfStrXAttribute::Resolve(DwarfContext* context) {
CHECK(context->str_offsets_base().has_value());
CHECK(context->string_offset_table().has_value());
uint64_t string_offset = context->string_offset_table().value().GetStringOffset(
context->str_offsets_base().value(), index_);
string_.emplace(context->debug_str_table()->GetString(string_offset));
}
std::unique_ptr<const DwarfAbbrevAttribute> DwarfAbbrevAttribute::CreateAbbrevAttribute(
uint16_t version,
uint32_t name,
uint32_t form,
int64_t value,
std::string* error_msg) {
// TODO(dimitry): support DW_FORM_indirect, might require some refactoring of DwarfClass
if (form == DW_FORM_indirect) {
*error_msg = "DW_FORM_indirect is not yet supported.";
return nullptr;
}
const DwarfClass* dwarf_class = FindDwarfClass(version, name, form, error_msg);
if (dwarf_class == nullptr) {
return nullptr;
}
return std::make_unique<DwarfAbbrevAttribute>(name, form, value, dwarf_class);
}
DwarfCompilationUnitHeader::DwarfCompilationUnitHeader(uint64_t unit_offset,
uint64_t unit_length,
uint16_t version,
uint64_t abbrev_offset,
uint8_t address_size,
bool is_dwarf64)
: unit_offset_(unit_offset),
unit_length_(unit_length),
version_(version),
abbrev_offset_(abbrev_offset),
address_size_(address_size),
is_dwarf64_(is_dwarf64) {}
DwarfAbbrev::DwarfAbbrev() : code_(0), tag_(0), has_children_(false) {}
DwarfAbbrev::DwarfAbbrev(uint64_t code, uint64_t tag, bool has_children)
: code_(code), tag_(tag), has_children_(has_children) {}
void DwarfAbbrev::AddAttribute(std::unique_ptr<const DwarfAbbrevAttribute>&& abbrev_attribute) {
attributes_.push_back(std::move(abbrev_attribute));
}
DwarfAbbrevAttribute::DwarfAbbrevAttribute()
: name_{0}, form_{0}, value_{0}, dwarf_class_{nullptr} {}
DwarfAbbrevAttribute::DwarfAbbrevAttribute(uint32_t name,
uint32_t form,
int64_t value,
const DwarfClass* dwarf_class)
: name_(name), form_(form), value_(value), dwarf_class_(dwarf_class) {}
} // namespace nogrod