From 914624a921373e53d29a7c72c430354a85a3f288 Mon Sep 17 00:00:00 2001 From: HoundThe Date: Fri, 19 Jun 2020 13:25:59 +0200 Subject: [PATCH] DWARF .debug_info parsing fix and improvement (#17007) * Get .debug_info working for DWARF 2, 3 * Fill up missing information in abbrev string table * Add 64bit dwarf option into debug_info * Add DWARF4 and DWARF5 forms * Add unit tests * added basic test Co-authored-by: Riccardo Schirone --- libr/bin/dbginfo.c | 12 +- libr/bin/dwarf.c | 1530 +++++++++++++++++++++------------- libr/core/cbin.c | 6 +- libr/include/r_bin_dwarf.h | 958 +++++++++++---------- test/db/cmd/cmd_flags | 2 +- test/db/cmd/cmd_i | 1 + test/db/cmd/dwarf | 4 +- test/db/cmd/lea_intel | 12 +- test/db/formats/mangling/bin | 2 +- test/unit/meson.build | 1 + test/unit/test_dwarf.c | 157 ++-- test/unit/test_dwarf_info.c | 335 ++++++++ 12 files changed, 1923 insertions(+), 1097 deletions(-) create mode 100644 test/unit/test_dwarf_info.c diff --git a/libr/bin/dbginfo.c b/libr/bin/dbginfo.c index c6d8ca844c..ae35161557 100644 --- a/libr/bin/dbginfo.c +++ b/libr/bin/dbginfo.c @@ -78,7 +78,17 @@ R_API char *r_bin_addr2text(RBin *bin, ut64 addr, int origin) { // TODO: this is slow. must use a cached pool of mapped files and line:off entries out = r_file_slurp_line (file, line, 0); if (!out) { - return r_str_newf ("%s:%d", file, line); + if (origin > 1) { + file_nopath = file; + } else { + file_nopath = strrchr (file, '/'); + if (file_nopath) { + file_nopath++; + } else { + file_nopath = file; + } + } + return r_str_newf ("%s:%d", file_nopath? file_nopath: "", line); } out2 = malloc ((strlen (file) + 64 + strlen (out)) * sizeof (char)); if (origin > 1) { diff --git a/libr/bin/dwarf.c b/libr/bin/dwarf.c index 768ea5487b..7fc859162c 100644 --- a/libr/bin/dwarf.c +++ b/libr/bin/dwarf.c @@ -21,13 +21,24 @@ #define STANDARD_OPERAND_COUNT_DWARF3 12 #define R_BIN_DWARF_INFO 1 -#define READ(x,y) (((x) + sizeof (y) < buf_end)? *((y*)(x)): 0); (x) += sizeof (y) -#define READ8(x) (((x) + sizeof (ut8) < buf_end)? ((ut8*)x)[0]: 0); (x) += sizeof (ut8) -#define READ16(x) (((x) + sizeof (ut16) < buf_end)? r_read_ble16(x,0): 0); (x) += sizeof (ut16) -#define READ32(x) (((x) + sizeof (ut32) < buf_end)? r_read_ble32(x,0): 0); (x) += sizeof (ut32) -#define READ64(x) (((x) + sizeof (ut64) < buf_end)? r_read_ble64(x,0): 0); (x) += sizeof (ut64) +#define READ(x, y) \ + (((x) + sizeof (y) < buf_end) ? *((y *)(x)) : 0); \ + (x) += sizeof (y) +#define READ8(x) \ + (((x) + sizeof (ut8) < buf_end) ? ((ut8 *)x)[0] : 0); \ + (x) += sizeof (ut8) +#define READ16(x) \ + (((x) + sizeof (ut16) < buf_end) ? r_read_ble16 (x, 0) : 0); \ + (x) += sizeof (ut16) +#define READ32(x) \ + (((x) + sizeof (ut32) < buf_end) ? r_read_ble32 (x, 0) : 0); \ + (x) += sizeof (ut32) +#define READ64(x) \ + (((x) + sizeof (ut64) < buf_end) ? r_read_ble64 (x, 0) : 0); \ + (x) += sizeof (ut64) static const char *dwarf_tag_name_encodings[] = { + [DW_TAG_null_entry] = "DW_TAG_null_entry", [DW_TAG_array_type] = "DW_TAG_array_type", [DW_TAG_class_type] = "DW_TAG_class_type", [DW_TAG_entry_point] = "DW_TAG_entry_point", @@ -75,7 +86,22 @@ static const char *dwarf_tag_name_encodings[] = { [DW_TAG_try_block] = "DW_TAG_try_block", [DW_TAG_variant_part] = "DW_TAG_variant_part", [DW_TAG_variable] = "DW_TAG_variable", - [DW_TAG_volatile_type] = "DW_TAG_volatile_type" + [DW_TAG_volatile_type] = "DW_TAG_volatile_type", + [DW_TAG_dwarf_procedure] = "DW_TAG_dwarf_procedure", + [DW_TAG_restrict_type] = "DW_TAG_restrict_type", + [DW_TAG_interface_type] = "DW_TAG_interface_type", + [DW_TAG_namespace] = "DW_TAG_namespace", + [DW_TAG_imported_module] = "DW_TAG_imported_module", + [DW_TAG_unspecified_type] = "DW_TAG_unspecified_type", + [DW_TAG_partial_unit] = "DW_TAG_partial_unit", + [DW_TAG_imported_unit] = "DW_TAG_imported_unit", + [DW_TAG_mutable_type] = "DW_TAG_mutable_type", + [DW_TAG_condition] = "DW_TAG_condition", + [DW_TAG_shared_type] = "DW_TAG_shared_type", + [DW_TAG_type_unit] = "DW_TAG_type_unit", + [DW_TAG_rvalue_reference_type] = "DW_TAG_rvalue_reference_type", + [DW_TAG_template_alias] = "DW_TAG_template_alias", + [DW_TAG_LAST] = "DW_TAG_LAST", }; static const char *dwarf_attr_encodings[] = { @@ -97,7 +123,7 @@ static const char *dwarf_attr_encodings[] = { [DW_AT_common_reference] = "DW_AT_common_reference", [DW_AT_comp_dir] = "DW_AT_comp_dir", [DW_AT_const_value] = "DW_AT_const_value", - [DW_AT_containing_type] = "DW_AT_containig_type", + [DW_AT_containing_type] = "DW_AT_containing_type", [DW_AT_default_value] = "DW_AT_default_value", [DW_AT_inline] = "DW_AT_inline", [DW_AT_is_optional] = "DW_AT_is_optional", @@ -136,7 +162,73 @@ static const char *dwarf_attr_encodings[] = { [DW_AT_use_location] = "DW_AT_use_location", [DW_AT_variable_parameter] = "DW_AT_variable_parameter", [DW_AT_virtuality] = "DW_AT_virtuality", - [DW_AT_vtable_elem_location] = "DW_AT_vtable_elem_location" + [DW_AT_vtable_elem_location] = "DW_AT_vtable_elem_location", + [DW_AT_allocated] = "DW_AT_allocated", + [DW_AT_associated] = "DW_AT_associated", + [DW_AT_data_location] = "DW_AT_data_location", + [DW_AT_byte_stride] = "DW_AT_byte_stride", + [DW_AT_entry_pc] = "DW_AT_entry_pc", + [DW_AT_use_UTF8] = "DW_AT_use_UTF8", + [DW_AT_extension] = "DW_AT_extension", + [DW_AT_ranges] = "DW_AT_ranges", + [DW_AT_trampoline] = "DW_AT_trampoline", + [DW_AT_call_column] = "DW_AT_call_column", + [DW_AT_call_file] = "DW_AT_call_file", + [DW_AT_call_line] = "DW_AT_call_line", + [DW_AT_description] = "DW_AT_description", + [DW_AT_binary_scale] = "DW_AT_binary_scale", + [DW_AT_decimal_scale] = "DW_AT_decimal_scale", + [DW_AT_small] = "DW_AT_small", + [DW_AT_decimal_sign] = "DW_AT_decimal_sign", + [DW_AT_digit_count] = "DW_AT_digit_count", + [DW_AT_picture_string] = "DW_AT_picture_string", + [DW_AT_mutable] = "DW_AT_mutable", + [DW_AT_threads_scaled] = "DW_AT_threads_scaled", + [DW_AT_explicit] = "DW_AT_explicit", + [DW_AT_object_pointer] = "DW_AT_object_pointer", + [DW_AT_endianity] = "DW_AT_endianity", + [DW_AT_elemental] = "DW_AT_elemental", + [DW_AT_pure] = "DW_AT_pure", + [DW_AT_recursive] = "DW_AT_recursive", + [DW_AT_signature] = "DW_AT_signature", + [DW_AT_main_subprogram] = "DW_AT_main_subprogram", + [DW_AT_data_big_offset] = "DW_AT_data_big_offset", + [DW_AT_const_expr] = "DW_AT_const_expr", + [DW_AT_enum_class] = "DW_AT_enum_class", + [DW_AT_linkage_name] = "DW_AT_linkage_name", + [DW_AT_string_length_bit_size] = "DW_AT_string_length_bit_size", + [DW_AT_string_length_byte_size] = "DW_AT_string_length_byte_size", + [DW_AT_rank] = "DW_AT_rank", + [DW_AT_str_offsets_base] = "DW_AT_str_offsets_base", + [DW_AT_addr_base] = "DW_AT_addr_base", + [DW_AT_rnglists_base] = "DW_AT_rnglists_base", + [DW_AT_dwo_name] = "DW_AT_dwo_name", + [DW_AT_reference] = "DW_AT_reference", + [DW_AT_rvalue_reference] = "DW_AT_rvalue_reference", + [DW_AT_macros] = "DW_AT_macros", + [DW_AT_call_all_calls] = "DW_AT_call_all_calls", + [DW_AT_call_all_source_calls] = "DW_AT_call_all_source_calls", + [DW_AT_call_all_tail_calls] = "DW_AT_call_all_tail_calls", + [DW_AT_call_return_pc] = "DW_AT_call_return_pc", + [DW_AT_call_value] = "DW_AT_call_value", + [DW_AT_call_origin] = "DW_AT_call_origin", + [DW_AT_call_parameter] = "DW_AT_call_parameter", + [DW_AT_call_pc] = "DW_AT_call_pc", + [DW_AT_call_tail_call] = "DW_AT_call_tail_call", + [DW_AT_call_target] = "DW_AT_call_target", + [DW_AT_call_target_clobbered] = "DW_AT_call_target_clobbered", + [DW_AT_call_data_location] = "DW_AT_call_data_location", + [DW_AT_call_data_value] = "DW_AT_call_data_value", + [DW_AT_noreturn] = "DW_AT_noreturn", + [DW_AT_alignment] = "DW_AT_alignment", + [DW_AT_export_symbols] = "DW_AT_export_symbols", + [DW_AT_deleted] = "DW_AT_deleted", + [DW_AT_defaulted] = "DW_AT_defaulted", + [DW_AT_loclists_base] = "DW_AT_loclists_base", + + [DW_AT_lo_user] = "DW_AT_lo_user", + [DW_AT_GNU_all_tail_call_sites] = "DW_AT_GNU_all_tail_call_sites", + [DW_AT_hi_user] = "DW_AT_hi_user", }; static const char *dwarf_attr_form_encodings[] = { @@ -160,7 +252,29 @@ static const char *dwarf_attr_form_encodings[] = { [DW_FORM_ref4] = "DW_FORM_ref4", [DW_FORM_ref8] = "DW_FORM_ref8", [DW_FORM_ref_udata] = "DW_FORM_ref_udata", - [DW_FORM_indirect] = "DW_FORM_indirect" + [DW_FORM_indirect] = "DW_FORM_indirect", + [DW_FORM_sec_offset] = "DW_FORM_sec_offset", + [DW_FORM_exprloc] = "DW_FORM_exprloc", + [DW_FORM_flag_present] = "DW_FORM_flag_present", + [DW_FORM_strx] = "DW_FORM_strx", + [DW_FORM_addrx] = "DW_FORM_addrx", + [DW_FORM_ref_sup4] = "DW_FORM_ref_sup4", + [DW_FORM_strp_sup] = "DW_FORM_strp_sup", + [DW_FORM_data16] = "DW_FORM_data16", + [DW_FORM_line_ptr] = "DW_FORM_line_ptr", + [DW_FORM_ref_sig8] = "DW_FORM_ref_sig8", + [DW_FORM_implicit_const] = "DW_FORM_implicit_const", + [DW_FORM_loclistx] = "DW_FORM_loclistx", + [DW_FORM_rnglistx] = "DW_FORM_rnglistx", + [DW_FORM_ref_sup8] = "DW_FORM_ref_sup8", + [DW_FORM_strx1] = "DW_FORM_strx1", + [DW_FORM_strx2] = "DW_FORM_strx2", + [DW_FORM_strx3] = "DW_FORM_strx3", + [DW_FORM_strx4] = "DW_FORM_strx4", + [DW_FORM_addrx1] = "DW_FORM_addrx1", + [DW_FORM_addrx2] = "DW_FORM_addrx2", + [DW_FORM_addrx3] = "DW_FORM_addrx3", + [DW_FORM_addrx4] = "DW_FORM_addrx4", }; static const char *dwarf_langs[] = { @@ -194,6 +308,66 @@ static const char *dwarf_langs[] = { [DW_LANG_Fortran08] = "Fortran08" }; +static const char *dwarf_unit_types[] = { + [DW_UT_compile] = "DW_UT_compile", + [DW_UT_type] = "DW_UT_type", + [DW_UT_partial] = "DW_UT_partial", + [DW_UT_skeleton] = "DW_UT_skeleton", + [DW_UT_split_compile] = "DW_UT_split_compile", + [DW_UT_split_type] = "DW_UT_split_type", + [DW_UT_lo_user] = "DW_UT_lo_user", + [DW_UT_hi_user] = "DW_UT_hi_user", +}; + +static int abbrev_cmp(const void *a, const void *b) { + const RBinDwarfAbbrevDecl *first = a; + const RBinDwarfAbbrevDecl *second = b; + + if (first->offset > second->offset) { + return 1; + } else if (first->offset < second->offset) { + return -1; + } else { + return 0; + } +} + +static inline bool is_printable_attr(ut64 attr_code) { + return (attr_code >= DW_AT_sibling && attr_code <= DW_AT_loclists_base) || + attr_code == DW_AT_GNU_all_tail_call_sites; +} + +static inline bool is_printable_form(ut64 form_code) { + return form_code >= DW_FORM_addr && form_code <= DW_FORM_addrx4; +} + +static inline bool is_printable_tag(ut64 attr_code) { + return attr_code <= DW_TAG_LAST; +} + +static inline bool is_printable_unit_type(ut64 unit_type) { + return unit_type > 0 && unit_type <= DW_UT_split_type; +} + +/** + * @brief Reads 64/32 bit unsigned based on format + * + * @param is_64bit Format of the comp unit + * @param buf Pointer to the buffer to read from, to update after read + * @param buf_end To check the boundary + * @return ut64 Read value + */ +static ut64 dwarf_read_piece(bool is_64bit, const ut8 **buf, const ut8 *buf_end) { + ut64 result; + if (is_64bit) { + result = READ64 (*buf); + } else { + result = READ32 (*buf); + } + return result; +} + + static int add_sdb_include_dir(Sdb *s, const char *incl, int idx) { if (!s || !incl) { return false; @@ -201,7 +375,7 @@ static int add_sdb_include_dir(Sdb *s, const char *incl, int idx) { return sdb_array_set (s, "includedirs", idx, incl, 0); } -static void r_bin_dwarf_header_fini(RBinDwarfLineHeader *hdr) { +static void line_header_fini(RBinDwarfLineHeader *hdr) { if (hdr) { size_t i; @@ -215,13 +389,13 @@ static void r_bin_dwarf_header_fini(RBinDwarfLineHeader *hdr) { } // Parses source file header of DWARF version <= 4 static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const ut8 *buf_end, - RBinDwarfLineHeader *hdr, FILE *f, Sdb *sdb, int mode) { + RBinDwarfLineHeader *hdr, Sdb *sdb, int mode, PrintfCallback print) { int i = 0; size_t count; const ut8 *tmp_buf = NULL; - if (f) { - fprintf (f, " The Directory Table:\n"); + if (mode == R_MODE_PRINT) { + print (" The Directory Table:\n"); } while (buf + 1 < buf_end) { size_t maxlen = R_MIN ((size_t) (buf_end - buf) - 1, 0xfff); @@ -232,8 +406,8 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u free (str); break; } - if (f) { - fprintf (f, " %d %s\n", i + 1, str); + if (mode == R_MODE_PRINT) { + print (" %d %s\n", i + 1, str); } add_sdb_include_dir (sdb, str, i); free (str); @@ -243,10 +417,10 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u tmp_buf = buf; count = 0; - if (f) { - fprintf (f, "\n"); - fprintf (f, " The File Name Table:\n"); - fprintf (f, " Entry Dir Time Size Name\n"); + if (mode == R_MODE_PRINT) { + print ("\n"); + print (" The File Name Table:\n"); + print (" Entry Dir Time Size Name\n"); } int entry_index = 1; // used for printing information @@ -255,7 +429,7 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u const char *filename = (const char *)buf; size_t maxlen = R_MIN ((size_t) (buf_end - buf - 1), 0xfff); ut64 id_idx, mod_time, file_len; - size_t namelen, len = r_str_nlen (filename, maxlen); + size_t len = r_str_nlen (filename, maxlen); if (!len) { buf++; @@ -299,8 +473,6 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u } } - namelen = len + (include_dir ? strlen (include_dir) : 0) + 8; - if (hdr->file_names) { hdr->file_names[count].name = r_str_newf("%s/%s", include_dir ? include_dir : "", filename); hdr->file_names[count].id_idx = id_idx; @@ -311,8 +483,8 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u free (pinclude_dir); } count++; - if (f && i) { - fprintf (f, " %d %" PFMT64d " %" PFMT64d " %" PFMT64d " %s\n", entry_index++, id_idx, mod_time, file_len, filename); + if (mode == R_MODE_PRINT && i) { + print (" %d %" PFMT64d " %" PFMT64d " %" PFMT64d " %s\n", entry_index++, id_idx, mod_time, file_len, filename); } } if (i == 0) { @@ -326,8 +498,8 @@ static const ut8 *parse_line_header_source(RBinFile *bf, const ut8 *buf, const u count = 0; } } - if (f) { - fprintf (f, "\n"); + if (mode == R_MODE_PRINT) { + print ("\n"); } beach: @@ -340,7 +512,7 @@ beach: // I'll complete this function after completing debug_info parsing and merging // for the meanwhile I am skipping the space. static const ut8 *parse_line_header_source_dwarf5(RBinFile *bf, const ut8 *buf, const ut8 *buf_end, - RBinDwarfLineHeader *hdr, FILE *f, Sdb *sdb, int mode) { + RBinDwarfLineHeader *hdr, Sdb *sdb, int mode) { // int i = 0; // size_t count; // const ut8 *tmp_buf = NULL; @@ -364,7 +536,7 @@ static const ut8 *parse_line_header_source_dwarf5(RBinFile *bf, const ut8 *buf, static const ut8 *parse_line_header ( RBinFile *bf, const ut8 *buf, const ut8 *buf_end, - RBinDwarfLineHeader *hdr, FILE *f, int mode) { + RBinDwarfLineHeader *hdr, int mode, PrintfCallback print) { r_return_val_if_fail(hdr && bf && buf, NULL); @@ -383,12 +555,9 @@ static const ut8 *parse_line_header ( hdr->segment_selector_size = READ8 (buf); } - if (hdr->is_64bit) { - hdr->header_length = READ64 (buf); - } else { - hdr->header_length = READ32 (buf); - } - ut8 *tmp_buf = buf; // So I can skip parsing DWARF 5 headres for now + hdr->header_length = dwarf_read_piece(hdr->is_64bit, &buf, buf_end); + + const ut8 *tmp_buf = buf; // So I can skip parsing DWARF 5 headers for now if (buf_end - buf < 8) { return NULL; @@ -404,25 +573,24 @@ static const ut8 *parse_line_header ( hdr->file_names = NULL; - if (f) { - fprintf (f, " Header information:\n"); - fprintf (f, " Length: %" PFMT64u "\n", hdr->unit_length); - fprintf (f, " DWARF Version: %d\n", hdr->version); - fprintf (f, " Header Length: %" PFMT64d "\n", hdr->header_length); - fprintf (f, " Minimum Instruction Length: %d\n", hdr->min_inst_len); - fprintf (f, " Maximum Operations per Instruction: %d\n", hdr->max_ops_per_inst); - fprintf (f, " Initial value of 'is_stmt': %d\n", hdr->default_is_stmt); - fprintf (f, " Line Base: %d\n", hdr->line_base); - fprintf (f, " Line Range: %d\n", hdr->line_range); - fprintf (f, " Opcode Base: %d\n", hdr->opcode_base); - fprintf (f, "\n"); + if (mode == R_MODE_PRINT) { + print (" Header information:\n"); + print (" Length: %" PFMT64u "\n", hdr->unit_length); + print (" DWARF Version: %d\n", hdr->version); + print (" Header Length: %" PFMT64d "\n", hdr->header_length); + print (" Minimum Instruction Length: %d\n", hdr->min_inst_len); + print (" Maximum Operations per Instruction: %d\n", hdr->max_ops_per_inst); + print (" Initial value of 'is_stmt': %d\n", hdr->default_is_stmt); + print (" Line Base: %d\n", hdr->line_base); + print (" Line Range: %d\n", hdr->line_range); + print (" Opcode Base: %d\n\n", hdr->opcode_base); } if (hdr->opcode_base > 0) { hdr->std_opcode_lengths = calloc (sizeof (ut8), hdr->opcode_base); - if (f) { - fprintf (f, " Opcodes:\n"); + if (mode == R_MODE_PRINT) { + print (" Opcodes:\n"); } size_t i; for (i = 1; i < hdr->opcode_base; i++) { @@ -430,12 +598,12 @@ static const ut8 *parse_line_header ( break; } hdr->std_opcode_lengths[i] = READ (buf, ut8); - if (f) { - fprintf (f, " Opcode %zu has %d arg\n", i, hdr->std_opcode_lengths[i]); + if (mode == R_MODE_PRINT) { + print (" Opcode %d has %d arg\n", i, hdr->std_opcode_lengths[i]); } } - if (f) { - fprintf (f, "\n"); + if (mode == R_MODE_PRINT) { + print ("\n"); } } else { hdr->std_opcode_lengths = NULL; @@ -453,15 +621,15 @@ static const ut8 *parse_line_header ( } if (hdr->version <= 4) { - buf = parse_line_header_source (bf, buf, buf_end, hdr, f, sdb, mode); + buf = parse_line_header_source (bf, buf, buf_end, hdr, sdb, mode, print); } else { // because Version 5 source files are very different - buf = parse_line_header_source_dwarf5 (bf, buf, buf_end, hdr, f, sdb, mode); + buf = parse_line_header_source_dwarf5 (bf, buf, buf_end, hdr, sdb, mode); } return buf; } -static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, FILE *f, int mode) { +static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, int mode, PrintfCallback print) { const char *p; char *fileline; char offset[64]; @@ -481,10 +649,7 @@ static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 li case 1: case 'r': case '*': - if (!f) { - f = stdout; - } - fprintf (f, "CL %s:%d 0x%08"PFMT64x"\n", p, (int)line, addr); + print ("CL %s:%d 0x%08"PFMT64x"\n", p, (int)line, addr); break; } #if 0 @@ -502,17 +667,18 @@ static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 li free (fileline); } -static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, +static const ut8 *parse_ext_opcode(const RBin *bin, const ut8 *obuf, size_t len, const RBinDwarfLineHeader *hdr, - RBinDwarfSMRegisters *regs, FILE *f, int mode) { + RBinDwarfSMRegisters *regs, int mode) { // XXX - list is an unused parameter. + PrintfCallback print = bin->cb_printf; const ut8 *buf; const ut8 *buf_end; ut8 opcode; ut64 addr; buf = obuf; st64 op_len; - RBinFile *binfile = a ? a->cur : NULL; + RBinFile *binfile = bin ? bin->cur : NULL; RBinObject *o = binfile ? binfile->o : NULL; ut32 addr_size = o && o->info && o->info->bits ? o->info->bits / 8 : 4; const char *filename; @@ -529,9 +695,8 @@ static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, opcode = *buf++; - // TODO - Maybe add offset to the print later? - if (f) { - fprintf (f, " Extended opcode %d: ", opcode); + if (mode == R_MODE_PRINT) { + print (" Extended opcode %d: ", opcode); } switch (opcode) { @@ -542,12 +707,12 @@ static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, int fnidx = regs->file - 1; if (fnidx >= 0 && fnidx < hdr->file_names_count) { add_sdb_addrline(binfile->sdb_addrinfo, regs->address, - hdr->file_names[fnidx].name, regs->line, f, mode); + hdr->file_names[fnidx].name, regs->line, mode, print); } } - if (f) { - fprintf (f, "End of Sequence\n"); + if (mode == R_MODE_PRINT) { + print ("End of Sequence\n"); } break; case DW_LNE_set_address: @@ -557,16 +722,16 @@ static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, addr = READ32 (buf); } regs->address = addr; - if (f) { - fprintf (f, "set Address to 0x%"PFMT64x"\n", addr); + if (mode == R_MODE_PRINT) { + print ("set Address to 0x%"PFMT64x"\n", addr); } break; case DW_LNE_define_file: filename = (const char*)buf; - if (f) { - fprintf (f, "define_file\n"); - fprintf (f, "filename %s\n", filename); + if (mode == R_MODE_PRINT) { + print ("define_file\n"); + print ("filename %s\n", filename); } buf += (strlen (filename) + 1); @@ -584,14 +749,14 @@ static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, break; case DW_LNE_set_discriminator: buf = r_uleb128 (buf, buf_end - buf, &addr); - if (f) { - fprintf (f, "set Discriminator to %"PFMT64d"\n", addr); + if (mode == R_MODE_PRINT) { + print ("set Discriminator to %"PFMT64d"\n", addr); } regs->discriminator = addr; break; default: - if (f) { - fprintf (f, "Unexpected ext opcode %d\n", opcode); + if (mode == R_MODE_PRINT) { + print ("Unexpected ext opcode %d\n", opcode); buf = NULL; } break; @@ -600,16 +765,17 @@ static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, return buf; } -static const ut8* r_bin_dwarf_parse_spec_opcode( - const RBin *a, const ut8 *obuf, size_t len, +static const ut8* parse_spec_opcode( + const RBin *bin, const ut8 *obuf, size_t len, const RBinDwarfLineHeader *hdr, RBinDwarfSMRegisters *regs, - ut8 opcode, FILE *f, int mode) { - // XXX - list is not used + ut8 opcode, int mode) { + + PrintfCallback print = bin->cb_printf; const ut8 *buf = obuf; ut8 adj_opcode = 0; ut64 advance_adr; - RBinFile *binfile = a ? a->cur : NULL; + RBinFile *binfile = bin ? bin->cur : NULL; if (!obuf || !hdr || !regs) { return NULL; @@ -624,9 +790,9 @@ static const ut8* r_bin_dwarf_parse_spec_opcode( regs->address += advance_adr; int line_increment = hdr->line_base + (adj_opcode % hdr->line_range); regs->line += line_increment; - if (f) { - fprintf (f, " Special opcode %d: ", adj_opcode); - fprintf (f, "advance Address by %"PFMT64d" to 0x%"PFMT64x" and Line by %d to %"PFMT64d"\n", + if (mode == R_MODE_PRINT) { + print (" Special opcode %d: ", adj_opcode); + print ("advance Address by %"PFMT64d" to 0x%"PFMT64x" and Line by %d to %"PFMT64d"\n", advance_adr, regs->address, line_increment, regs->line); } if (binfile && binfile->sdb_addrinfo && hdr->file_names) { @@ -634,7 +800,7 @@ static const ut8* r_bin_dwarf_parse_spec_opcode( if (idx >= 0 && idx < hdr->file_names_count) { add_sdb_addrline (binfile->sdb_addrinfo, regs->address, hdr->file_names[idx].name, - regs->line, f, mode); + regs->line, mode, print); } } regs->basic_block = DWARF_FALSE; @@ -645,10 +811,12 @@ static const ut8* r_bin_dwarf_parse_spec_opcode( return buf; } -static const ut8* r_bin_dwarf_parse_std_opcode( - const RBin *a, const ut8 *obuf, size_t len, +static const ut8* parse_std_opcode( + const RBin *bin, const ut8 *obuf, size_t len, const RBinDwarfLineHeader *hdr, RBinDwarfSMRegisters *regs, - ut8 opcode, FILE *f, int mode) { + ut8 opcode, int mode) { + + PrintfCallback print = bin->cb_printf; const ut8* buf = obuf; const ut8* buf_end = obuf + len; ut64 addr = 0LL; @@ -656,19 +824,19 @@ static const ut8* r_bin_dwarf_parse_std_opcode( ut8 adj_opcode; ut64 op_advance; ut16 operand; - RBinFile *binfile = a ? a->cur : NULL; + RBinFile *binfile = bin ? bin->cur : NULL; if (!binfile || !hdr || !regs || !obuf) { return NULL; } - if (f) { - fprintf (f, " "); // formatting + if (mode == R_MODE_PRINT) { + print (" "); // formatting } switch (opcode) { case DW_LNS_copy: - if (f) { - fprintf (f, "Copy\n"); + if (mode == R_MODE_PRINT) { + print ("Copy\n"); } if (binfile && binfile->sdb_addrinfo && hdr->file_names) { int fnidx = regs->file - 1; @@ -676,7 +844,7 @@ static const ut8* r_bin_dwarf_parse_std_opcode( add_sdb_addrline (binfile->sdb_addrinfo, regs->address, hdr->file_names[fnidx].name, - regs->line, f, mode); + regs->line, mode, print); } } regs->basic_block = DWARF_FALSE; @@ -684,41 +852,41 @@ static const ut8* r_bin_dwarf_parse_std_opcode( case DW_LNS_advance_pc: buf = r_uleb128 (buf, buf_end - buf, &addr); regs->address += addr * hdr->min_inst_len; - if (f) { - fprintf (f, "Advance PC by %"PFMT64d" to 0x%"PFMT64x"\n", + if (mode == R_MODE_PRINT) { + print ("Advance PC by %"PFMT64d" to 0x%"PFMT64x"\n", addr * hdr->min_inst_len, regs->address); } break; case DW_LNS_advance_line: buf = r_leb128(buf, buf_end - buf, &sbuf); regs->line += sbuf; - if (f) { - fprintf (f, "Advance line by %"PFMT64d", to %"PFMT64d"\n", sbuf, regs->line); + if (mode == R_MODE_PRINT) { + print ("Advance line by %"PFMT64d", to %"PFMT64d"\n", sbuf, regs->line); } break; case DW_LNS_set_file: buf = r_uleb128 (buf, buf_end - buf, &addr); - if (f) { - fprintf (f, "Set file to %"PFMT64d"\n", addr); + if (mode == R_MODE_PRINT) { + print ("Set file to %"PFMT64d"\n", addr); } regs->file = addr; break; case DW_LNS_set_column: buf = r_uleb128 (buf, buf_end - buf, &addr); - if (f) { - fprintf (f, "Set column to %"PFMT64d"\n", addr); + if (mode == R_MODE_PRINT) { + print ("Set column to %"PFMT64d"\n", addr); } regs->column = addr; break; case DW_LNS_negate_stmt: regs->is_stmt = regs->is_stmt ? DWARF_FALSE : DWARF_TRUE; - if (f) { - fprintf (f, "Set is_stmt to %d\n", regs->is_stmt); + if (mode == R_MODE_PRINT) { + print ("Set is_stmt to %d\n", regs->is_stmt); } break; case DW_LNS_set_basic_block: - if (f) { - fprintf (f, "set_basic_block\n"); + if (mode == R_MODE_PRINT) { + print ("set_basic_block\n"); } regs->basic_block = DWARF_TRUE; break; @@ -730,47 +898,47 @@ static const ut8* r_bin_dwarf_parse_std_opcode( op_advance = 0; } regs->address += op_advance; - if (f) { - fprintf (f, "Advance PC by constant %"PFMT64d" to 0x%"PFMT64x"\n", + if (mode == R_MODE_PRINT) { + print ("Advance PC by constant %"PFMT64d" to 0x%"PFMT64x"\n", op_advance, regs->address); } break; case DW_LNS_fixed_advance_pc: operand = READ16 (buf); regs->address += operand; - if (f) { - fprintf (f,"Fixed advance pc to %"PFMT64d"\n", regs->address); + if (mode == R_MODE_PRINT) { + print ("Fixed advance pc to %"PFMT64d"\n", regs->address); } break; case DW_LNS_set_prologue_end: regs->prologue_end = ~0; - if (f) { - fprintf (f, "set_prologue_end\n"); + if (mode == R_MODE_PRINT) { + print ("set_prologue_end\n"); } break; case DW_LNS_set_epilogue_begin: regs->epilogue_begin = ~0; - if (f) { - fprintf (f, "set_epilogue_begin\n"); + if (mode == R_MODE_PRINT) { + print ("set_epilogue_begin\n"); } break; case DW_LNS_set_isa: buf = r_uleb128 (buf, buf_end - buf, &addr); regs->isa = addr; - if (f) { - fprintf (f, "set_isa\n"); + if (mode == R_MODE_PRINT) { + print ("set_isa\n"); } break; default: - if (f) { - fprintf (f, "Unexpected std opcode %d\n", opcode); + if (mode == R_MODE_PRINT) { + print ("Unexpected std opcode %d\n", opcode); } break; } return buf; } -static void r_bin_dwarf_set_regs_default(const RBinDwarfLineHeader *hdr, RBinDwarfSMRegisters *regs) { +static void set_regs_default(const RBinDwarfLineHeader *hdr, RBinDwarfSMRegisters *regs) { regs->address = 0; regs->file = 1; regs->line = 1; @@ -783,13 +951,14 @@ static void r_bin_dwarf_set_regs_default(const RBinDwarfLineHeader *hdr, RBinDwa regs->isa = 0; } -static size_t r_bin_dwarf_parse_opcodes(const RBin *a, const ut8 *obuf, +// Passing bin should be unnecessary (after we stop printing inside bin_dwarf) +static size_t parse_opcodes(const RBin *bin, const ut8 *obuf, size_t len, const RBinDwarfLineHeader *hdr, - RBinDwarfSMRegisters *regs, FILE *f, int mode) { + RBinDwarfSMRegisters *regs, int mode) { const ut8 *buf, *buf_end; ut8 opcode, ext_opcode; - if (!a || !obuf || len < 8) { + if (!bin || !obuf || len < 8) { return 0; } buf = obuf; @@ -800,34 +969,33 @@ static size_t r_bin_dwarf_parse_opcodes(const RBin *a, const ut8 *obuf, len--; if (!opcode) { ext_opcode = *buf; - buf = r_bin_dwarf_parse_ext_opcode (a, buf, len, hdr, regs, f, mode); + buf = parse_ext_opcode (bin, buf, len, hdr, regs, mode); if (!buf || ext_opcode == DW_LNE_end_sequence) { - r_bin_dwarf_set_regs_default (hdr, regs); // end_sequence should reset regs to default + set_regs_default (hdr, regs); // end_sequence should reset regs to default break; } } else if (opcode >= hdr->opcode_base) { - buf = r_bin_dwarf_parse_spec_opcode (a, buf, len, hdr, regs, opcode, f, mode); + buf = parse_spec_opcode (bin, buf, len, hdr, regs, opcode, mode); } else { - buf = r_bin_dwarf_parse_std_opcode (a, buf, len, hdr, regs, opcode, f, mode); + buf = parse_std_opcode (bin, buf, len, hdr, regs, opcode, mode); } - len = (int)(buf_end - buf); + len = (size_t)(buf_end - buf); } - if (f) { - fprintf (f, "\n"); // formatting of the output + if (mode == R_MODE_PRINT) { + bin->cb_printf ("\n"); // formatting of the output } return (size_t) (buf - obuf); // number of bytes we've moved by } static int parse_line_raw(const RBin *a, const ut8 *obuf, ut64 len, int mode) { + RBinFile *binfile = a ? a->cur : NULL; - if (!binfile || !obuf) { - return false; - } - FILE *f = NULL; + r_return_val_if_fail(binfile && obuf, false); + PrintfCallback print = a->cb_printf; + if (mode == R_MODE_PRINT) { - f = stdout; - fprintf (f, "Raw dump of debug contents of section .debug_line:\n\n"); + print ("Raw dump of debug contents of section .debug_line:\n\n"); } const ut8 *buf = obuf; const ut8 *buf_end = obuf + len; @@ -845,18 +1013,18 @@ static int parse_line_raw(const RBin *a, const ut8 *obuf, buf_size = buf_end - buf; tmpbuf = buf; - buf = parse_line_header (a->cur, buf, buf_end, &hdr, f, mode); + buf = parse_line_header (a->cur, buf, buf_end, &hdr, mode, print); if (!buf) { return false; } - if (f) { - fprintf (f, " Line Number Statements:\n"); + if (mode == R_MODE_PRINT) { + print (" Line Number Statements:\n"); } bytes_read = buf - tmpbuf; RBinDwarfSMRegisters regs; - r_bin_dwarf_set_regs_default (&hdr, ®s); + set_regs_default (&hdr, ®s); // If there is more bytes in the buffer than size of the header // It means that there has to be another header/comp.unit @@ -866,25 +1034,25 @@ static int parse_line_raw(const RBin *a, const ut8 *obuf, } // this deals with a case that there is compilation unit with any line information if (buf_size == bytes_read) { - if (f) { - fprintf (f, " Line table is present, but no lines present\n"); + if (mode == R_MODE_PRINT) { + print (" Line table is present, but no lines present\n"); } - r_bin_dwarf_header_fini (&hdr); + line_header_fini (&hdr); continue; } if (buf_size > (buf_end - buf) + bytes_read || buf > buf_end) { - r_bin_dwarf_header_fini (&hdr); + line_header_fini (&hdr); return false; } // we read the whole compilation unit (that might be composed of more sequences) do { // reads one whole sequence - size_t tmp_read = r_bin_dwarf_parse_opcodes (a, buf, buf_size, &hdr, ®s, f, mode); + size_t tmp_read = parse_opcodes (a, buf, buf_size, &hdr, ®s, mode); bytes_read += tmp_read; buf += tmp_read; // Move in the buffer forward } while (bytes_read < buf_size); - r_bin_dwarf_header_fini (&hdr); + line_header_fini (&hdr); } return true; } @@ -899,7 +1067,7 @@ static int parse_line_raw(const RBin *a, const ut8 *obuf, #define READ_BUF16(x) if (idx+sizeof(ut16)>=len) { return false;} \ (x)=r_read_ble16(buf, 0); idx+=sizeof(ut16);buf+=sizeof(ut16) -R_API int r_bin_dwarf_parse_aranges_raw(const ut8 *obuf, int len, FILE *f) { +static int parse_aranges_raw(const ut8 *obuf, int len, int mode, PrintfCallback print) { ut32 length, offset; ut16 version; ut32 debug_info_offset; @@ -912,9 +1080,9 @@ R_API int r_bin_dwarf_parse_aranges_raw(const ut8 *obuf, int len, FILE *f) { } READ_BUF32 (length); - if (f) { - printf("parse_aranges\n"); - printf("length 0x%x\n", length); + if (mode == R_MODE_PRINT) { + print ("parse_aranges\n"); + print ("length 0x%x\n", length); } if (idx + 12 >= len) { @@ -922,23 +1090,23 @@ R_API int r_bin_dwarf_parse_aranges_raw(const ut8 *obuf, int len, FILE *f) { } READ_BUF16 (version); - if (f) { - printf("Version %d\n", version); + if (mode == R_MODE_PRINT) { + print("Version %d\n", version); } READ_BUF32 (debug_info_offset); - if (f) { - fprintf (f, "Debug info offset %d\n", debug_info_offset); + if (mode == R_MODE_PRINT) { + print ("Debug info offset %d\n", debug_info_offset); } READ_BUF (address_size, ut8); - if (f) { - fprintf (f, "address size %d\n", (int)address_size); + if (mode == R_MODE_PRINT) { + print ("address size %d\n", (int)address_size); } READ_BUF (segment_size, ut8); - if (f) { - fprintf (f, "segment size %d\n", (int)segment_size); + if (mode == R_MODE_PRINT) { + print ("segment size %d\n", (int)segment_size); } offset = segment_size + address_size * 2; @@ -959,15 +1127,15 @@ R_API int r_bin_dwarf_parse_aranges_raw(const ut8 *obuf, int len, FILE *f) { } READ_BUF64 (adr); READ_BUF64 (length); - if (f) { - printf ("length 0x%" PFMT64x " address 0x%" PFMT64x "\n", length, adr); + if (mode == R_MODE_PRINT) { + print ("length 0x%" PFMT64x " address 0x%" PFMT64x "\n", length, adr); } } return 0; } -static int r_bin_dwarf_init_debug_info(RBinDwarfDebugInfo *inf) { +static int init_debug_info(RBinDwarfDebugInfo *inf) { if (!inf) { return -1; } @@ -979,118 +1147,99 @@ static int r_bin_dwarf_init_debug_info(RBinDwarfDebugInfo *inf) { } inf->capacity = DEBUG_INFO_CAPACITY; - inf->length = 0; + inf->count = 0; return true; } -static int r_bin_dwarf_init_die(RBinDwarfDIE *die) { +static int init_die(RBinDwarfDie *die, ut64 abbr_code, ut64 attr_count) { if (!die) { - return -EINVAL; + return -1; } - die->attr_values = calloc (sizeof (RBinDwarfAttrValue), 8); + die->attr_values = calloc (sizeof (RBinDwarfAttrValue), attr_count); if (!die->attr_values) { - return -ENOMEM; + return -1; } - die->capacity = 8; - die->length = 0; + die->abbrev_code = abbr_code; + die->capacity = attr_count; + die->count = 0; return 0; } -static int r_bin_dwarf_expand_die(RBinDwarfDIE* die) { - RBinDwarfAttrValue *tmp = NULL; - if (!die || die->capacity == 0) { - return -EINVAL; - } - if (die->capacity != die->length) { - return -EINVAL; - } - tmp = (RBinDwarfAttrValue*)realloc (die->attr_values, - die->capacity * 2 * sizeof (RBinDwarfAttrValue)); - if (!tmp) { - return -ENOMEM; - } - memset ((ut8*)tmp + die->capacity * sizeof (RBinDwarfAttrValue), - 0, die->capacity * sizeof (RBinDwarfAttrValue)); - die->attr_values = tmp; - die->capacity *= 2; - return 0; -} - -static int r_bin_dwarf_init_comp_unit(RBinDwarfCompUnit *cu) { +static int init_comp_unit(RBinDwarfCompUnit *cu) { if (!cu) { return -EINVAL; } - cu->dies = calloc (sizeof (RBinDwarfDIE), COMP_UNIT_CAPACITY); + cu->dies = calloc (sizeof (RBinDwarfDie), COMP_UNIT_CAPACITY); if (!cu->dies) { return -ENOMEM; } cu->capacity = COMP_UNIT_CAPACITY; - cu->length = 0; + cu->count = 0; return 0; } -static int r_bin_dwarf_expand_cu(RBinDwarfCompUnit *cu) { - RBinDwarfDIE *tmp; +static int expand_cu(RBinDwarfCompUnit *cu) { + RBinDwarfDie *tmp; - if (!cu || cu->capacity == 0 || cu->capacity != cu->length) { + if (!cu || cu->capacity == 0 || cu->capacity != cu->count) { return -EINVAL; } - tmp = (RBinDwarfDIE*)realloc(cu->dies, - cu->capacity * 2 * sizeof(RBinDwarfDIE)); + tmp = (RBinDwarfDie *)realloc (cu->dies, + cu->capacity * 2 * sizeof (RBinDwarfDie)); if (!tmp) { return -ENOMEM; } - memset ((ut8*)tmp + cu->capacity * sizeof (RBinDwarfDIE), - 0, cu->capacity * sizeof (RBinDwarfDIE)); + memset ((ut8 *)tmp + cu->capacity * sizeof (RBinDwarfDie), + 0, cu->capacity * sizeof (RBinDwarfDie)); cu->dies = tmp; cu->capacity *= 2; return 0; } -static int r_bin_dwarf_init_abbrev_decl(RBinDwarfAbbrevDecl *ad) { +static int init_abbrev_decl(RBinDwarfAbbrevDecl *ad) { if (!ad) { return -EINVAL; } - ad->specs = calloc (sizeof( RBinDwarfAttrSpec), ABBREV_DECL_CAP); + ad->defs = calloc (sizeof (RBinDwarfAttrDef), ABBREV_DECL_CAP); - if (!ad->specs) { + if (!ad->defs) { return -ENOMEM; } ad->capacity = ABBREV_DECL_CAP; - ad->length = 0; + ad->count = 0; return 0; } -static int r_bin_dwarf_expand_abbrev_decl(RBinDwarfAbbrevDecl *ad) { - RBinDwarfAttrSpec *tmp; +static int expand_abbrev_decl(RBinDwarfAbbrevDecl *ad) { + RBinDwarfAttrDef *tmp; - if (!ad || !ad->capacity || ad->capacity != ad->length) { + if (!ad || !ad->capacity || ad->capacity != ad->count) { return -EINVAL; } - tmp = (RBinDwarfAttrSpec*)realloc (ad->specs, - ad->capacity * 2 * sizeof (RBinDwarfAttrSpec)); + tmp = (RBinDwarfAttrDef *)realloc (ad->defs, + ad->capacity * 2 * sizeof (RBinDwarfAttrDef)); if (!tmp) { return -ENOMEM; } // Set the area in the buffer past the length to 0 - memset ((ut8*)tmp + ad->capacity * sizeof (RBinDwarfAttrSpec), - 0, ad->capacity * sizeof (RBinDwarfAttrSpec)); - ad->specs = tmp; + memset ((ut8 *)tmp + ad->capacity * sizeof (RBinDwarfAttrDef), + 0, ad->capacity * sizeof (RBinDwarfAttrDef)); + ad->defs = tmp; ad->capacity *= 2; return 0; } -static int r_bin_dwarf_init_debug_abbrev(RBinDwarfDebugAbbrev *da) { +static int init_debug_abbrev(RBinDwarfDebugAbbrev *da) { if (!da) { return -EINVAL; } @@ -1099,26 +1248,26 @@ static int r_bin_dwarf_init_debug_abbrev(RBinDwarfDebugAbbrev *da) { return -ENOMEM; } da->capacity = DEBUG_ABBREV_CAP; - da->length = 0; + da->count = 0; return 0; } -static int r_bin_dwarf_expand_debug_abbrev(RBinDwarfDebugAbbrev *da) { +static int expand_debug_abbrev(RBinDwarfDebugAbbrev *da) { RBinDwarfAbbrevDecl *tmp; - if (!da || da->capacity == 0 || da->capacity != da->length) { + if (!da || da->capacity == 0 || da->capacity != da->count) { return -EINVAL; } - tmp = (RBinDwarfAbbrevDecl*)realloc (da->decls, - da->capacity * 2 * sizeof (RBinDwarfAbbrevDecl)); + tmp = (RBinDwarfAbbrevDecl *)realloc (da->decls, + da->capacity * 2 * sizeof (RBinDwarfAbbrevDecl)); if (!tmp) { return -ENOMEM; } - memset ((ut8*)tmp + da->capacity * sizeof (RBinDwarfAbbrevDecl), - 0, da->capacity * sizeof (RBinDwarfAbbrevDecl)); + memset ((ut8 *)tmp + da->capacity * sizeof (RBinDwarfAbbrevDecl), + 0, da->capacity * sizeof (RBinDwarfAbbrevDecl)); da->decls = tmp; da->capacity *= 2; @@ -1126,31 +1275,29 @@ static int r_bin_dwarf_expand_debug_abbrev(RBinDwarfDebugAbbrev *da) { return 0; } -static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) { +static void print_abbrev_section(RBinDwarfDebugAbbrev *da, PrintfCallback print) { size_t i, j; ut64 attr_name, attr_form; - if (!f || !da) { + if (!da) { return; } - for (i = 0; i < da->length; i++) { + for (i = 0; i < da->count; i++) { int declstag = da->decls[i].tag; - fprintf (f, "Abbreviation Code %"PFMT64d" ", da->decls[i].code); + print (" %-4"PFMT64d" ", da->decls[i].code); if (declstag>=0 && declstag < DW_TAG_LAST) { - fprintf (f, "Tag %s ", dwarf_tag_name_encodings[declstag]); + print (" %-25s ", dwarf_tag_name_encodings[declstag]); } - fprintf (f, "[%s]\n", da->decls[i].has_children ? + print ("[%s]", da->decls[i].has_children ? "has children" : "no children"); - fprintf (f, "Offset 0x%"PFMT64x"\n", da->decls[i].offset); + print (" (0x%"PFMT64x")\n", da->decls[i].offset); - if (da->decls[i].specs) { - for (j = 0; j < da->decls[i].length; j++) { - attr_name = da->decls[i].specs[j].attr_name; - attr_form = da->decls[i].specs[j].attr_form; - if (attr_name && attr_form && - attr_name <= DW_AT_vtable_elem_location && - attr_form <= DW_FORM_indirect) { - fprintf (f, " %s %s\n", + if (da->decls[i].defs) { + for (j = 0; j < da->decls[i].count; j++) { + attr_name = da->decls[i].defs[j].attr_name; + attr_form = da->decls[i].defs[j].attr_form; + if (is_printable_attr(attr_name) && is_printable_form(attr_form)) { + print (" %-30s %-30s\n", dwarf_attr_encodings[attr_name], dwarf_attr_form_encodings[attr_form]); } @@ -1164,153 +1311,187 @@ R_API void r_bin_dwarf_free_debug_abbrev(RBinDwarfDebugAbbrev *da) { if (!da) { return; } - for (i = 0; i < da->length; i++) { - R_FREE (da->decls[i].specs); + for (i = 0; i < da->count; i++) { + R_FREE (da->decls[i].defs); } R_FREE (da->decls); + free (da); } -static void r_bin_dwarf_free_attr_value(RBinDwarfAttrValue *val) { +static void free_attr_value(RBinDwarfAttrValue *val) { // TODO adjust to new forms, now we're leaking if (!val) { return; } - switch (val->form) { + switch (val->attr_form) { case DW_FORM_strp: case DW_FORM_string: - R_FREE (val->encoding.str_struct.string); + R_FREE (val->string.content); break; + case DW_FORM_exprloc: case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: - R_FREE (val->encoding.block.data); + R_FREE (val->block.data); break; default: break; }; } -static void r_bin_dwarf_free_die(RBinDwarfDIE *die) { +static void free_die(RBinDwarfDie *die) { size_t i; if (!die) { return; } - for (i = 0; i < die->length; i++) { - r_bin_dwarf_free_attr_value (&die->attr_values[i]); + for (i = 0; i < die->count; i++) { + free_attr_value (&die->attr_values[i]); } R_FREE (die->attr_values); } -static void r_bin_dwarf_free_comp_unit(RBinDwarfCompUnit *cu) { +static void free_comp_unit(RBinDwarfCompUnit *cu) { size_t i; if (!cu) { return; } - for (i = 0; i < cu->length; i++) { + for (i = 0; i < cu->count; i++) { if (cu->dies) { - r_bin_dwarf_free_die (&cu->dies[i]); + free_die (&cu->dies[i]); } } R_FREE (cu->dies); } -static void r_bin_dwarf_free_debug_info(RBinDwarfDebugInfo *inf) { +R_API void r_bin_dwarf_free_debug_info(RBinDwarfDebugInfo *inf) { size_t i; if (!inf) { return; } - for (i = 0; i < inf->length; i++) { - r_bin_dwarf_free_comp_unit (&inf->comp_units[i]); + for (i = 0; i < inf->count; i++) { + free_comp_unit (&inf->comp_units[i]); } R_FREE (inf->comp_units); + free(inf); } -static void r_bin_dwarf_dump_attr_value(const RBinDwarfAttrValue *val, FILE *f) { +static void print_attr_value(const RBinDwarfAttrValue *val, PrintfCallback print) { size_t i; - if (!val || !f) { - return; - } - switch (val->form) { - case DW_FORM_addr: - fprintf (f, "0x%"PFMT64x"", val->encoding.address); - break; + r_return_if_fail(val); + + switch (val->attr_form) { case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: - fprintf (f, "%"PFMT64u" byte block:", val->encoding.block.length); - for (i = 0; i < val->encoding.block.length; i++) { - fprintf (f, "%02x", val->encoding.block.data[i]); + case DW_FORM_exprloc: + print ("%"PFMT64u" byte block:", val->block.length); + for (i = 0; i < val->block.length; i++) { + print (" 0x%02x", val->block.data[i]); } break; case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: - fprintf (f, "%"PFMT64u"", val->encoding.data); - if (val->name == DW_AT_language) { - fprintf (f, " (%s)", dwarf_langs[val->encoding.data]); + case DW_FORM_data16: + print ("%"PFMT64u"", val->data); + if (val->attr_name == DW_AT_language) { + print (" (%s)", dwarf_langs[val->data]); } break; case DW_FORM_strp: - fprintf (f, "(indirect string, offset: 0x%"PFMT64x"): ", - val->encoding.str_struct.offset); + print ("(indirect string, offset: 0x%"PFMT64x"): ", + val->string.offset); case DW_FORM_string: - if (val->encoding.str_struct.string) { - fprintf (f, "%s", val->encoding.str_struct.string); + if (val->string.content) { + print ("%s", val->string.content); } else { - fprintf (f, "No string found"); + print ("No string found"); } break; case DW_FORM_flag: - fprintf (f, "%u", val->encoding.flag); + print ("%u", val->flag); break; case DW_FORM_sdata: - fprintf (f, "%"PFMT64d"", val->encoding.sdata); + print ("%"PFMT64d"", val->sdata); break; case DW_FORM_udata: - fprintf (f, "%"PFMT64u"", val->encoding.data); + print ("%"PFMT64u"", val->data); break; case DW_FORM_ref_addr: - fprintf (f, "<0x%"PFMT64x">", val->encoding.reference); - break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: - fprintf (f, "<0x%"PFMT64x">", val->encoding.reference); + case DW_FORM_ref_sig8: + case DW_FORM_ref_udata: + case DW_FORM_ref_sup4: + case DW_FORM_ref_sup8: + case DW_FORM_sec_offset: + print ("<0x%"PFMT64x">", val->reference); + break; + case DW_FORM_flag_present: + print ("1"); + break; + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + case DW_FORM_line_ptr: + case DW_FORM_strp_sup: + print ("(indirect string, offset: 0x%"PFMT64x"): ", + val->string.offset); + break; + case DW_FORM_addr: + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + print ("0x%"PFMT64x"", val->address); + break; + case DW_FORM_implicit_const: + print ("0x%"PFMT64d"", val->sdata); break; default: - fprintf (f, "Unknown attr value form %"PFMT64d"\n", val->form); + print ("Unknown attr value form %"PFMT64d"\n", val->attr_form); + break; }; } -static void r_bin_dwarf_dump_debug_info(FILE *f, const RBinDwarfDebugInfo *inf) { +static void print_debug_info(const RBinDwarfDebugInfo *inf, PrintfCallback print) { size_t i, j, k; - RBinDwarfDIE *dies; + RBinDwarfDie *dies; RBinDwarfAttrValue *values; - if (!inf || !f) { - return; - } - for (i = 0; i < inf->length; i++) { - fprintf (f, " Compilation Unit @ offset 0x%"PFMT64x":\n", inf->comp_units [i].offset); - fprintf (f, " Length: 0x%x\n", inf->comp_units [i].hdr.length); - fprintf (f, " Version: %d\n", inf->comp_units [i].hdr.version); - fprintf (f, " Abbrev Offset: 0x%x\n", inf->comp_units [i].hdr.abbrev_offset); - fprintf (f, " Pointer Size: %d\n", inf->comp_units [i].hdr.pointer_size); + r_return_if_fail(inf); + + for (i = 0; i < inf->count; i++) { + print ("\n"); + print (" Compilation Unit @ offset 0x%" PFMT64x ":\n", inf->comp_units[i].offset); + print (" Length: 0x%" PFMT64x "\n", inf->comp_units[i].hdr.length); + print (" Version: %d\n", inf->comp_units[i].hdr.version); + print (" Abbrev Offset: 0x%" PFMT64x "\n", inf->comp_units[i].hdr.abbrev_offset); + print (" Pointer Size: %d\n", inf->comp_units[i].hdr.address_size); + if (is_printable_unit_type(inf->comp_units[i].hdr.unit_type)) { + print (" Unit Type: %s\n", dwarf_unit_types[inf->comp_units[i].hdr.unit_type]); + } + print ("\n"); dies = inf->comp_units[i].dies; - for (j = 0; j < inf->comp_units[i].length; j++) { - fprintf (f, " Abbrev Number: %"PFMT64u" ", dies[j].abbrev_code); + for (j = 0; j < inf->comp_units[i].count; j++) { + print (" Abbrev Number: %-4" PFMT64u " ", dies[j].abbrev_code); - if (dies[j].tag && dies[j].tag <= DW_TAG_volatile_type && - dwarf_tag_name_encodings[dies[j].tag]) { - fprintf (f, "(%s)\n", dwarf_tag_name_encodings[dies[j].tag]); + if (is_printable_tag (dies[j].tag)) { + print ("(%s)\n", dwarf_tag_name_encodings[dies[j].tag]); } else { - fprintf (f, "(Unknown abbrev tag)\n"); + print ("(Unknown abbrev tag)\n"); } if (!dies[j].abbrev_code) { @@ -1318,322 +1499,520 @@ static void r_bin_dwarf_dump_debug_info(FILE *f, const RBinDwarfDebugInfo *inf) } values = dies[j].attr_values; - for (k = 0; k < dies[j].length; k++) { - if (!values[k].name) { + for (k = 0; k < dies[j].count; k++) { + if (!values[k].attr_name) { continue; } - - if (values[k].name < DW_AT_vtable_elem_location && - dwarf_attr_encodings[values[k].name]) { - fprintf (f, " %-18s : ", dwarf_attr_encodings[values[k].name]); + if (is_printable_attr (values[k].attr_name)) { + print (" %-25s : ", dwarf_attr_encodings[values[k].attr_name]); } else { - fprintf (f, " TODO\t"); + print (" AT_UNKWN [0x%-3" PFMT64x "]\t : ", values[k].attr_name); } - r_bin_dwarf_dump_attr_value (&values[k], f); - fprintf (f, "\n"); + print_attr_value (&values[k], print); + print ("\n"); } } } } - -static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len, - RBinDwarfAttrSpec *spec, RBinDwarfAttrValue *value, +/** + * This function is quite incomplete and requires lot of work + * With parsing various new FORM values + * @brief Parses attribute value based on its definition + * and stores it into `value` + * + * @param obuf + * @param obuf_len Buffer max capacity + * @param def Attribute definition + * @param value Parsed value storage + * @param hdr Current unit header + * @param debug_str Ptr to string section start + * @param debug_str_len Length of the string section + * @return const ut8* Updated buffer + */ +static const ut8 *parse_attr_value(const ut8 *obuf, int obuf_len, + RBinDwarfAttrDef *def, RBinDwarfAttrValue *value, const RBinDwarfCompUnitHdr *hdr, const ut8 *debug_str, size_t debug_str_len) { + const ut8 *buf = obuf; const ut8 *buf_end = obuf + obuf_len; size_t j; - if (!spec || !value || !hdr || !obuf || obuf_len < 1) { - return NULL; - } + r_return_val_if_fail(def && value && hdr && obuf && obuf_len >= 1, NULL); - value->form = spec->attr_form; - value->name = spec->attr_name; - value->encoding.block.data = NULL; - value->encoding.str_struct.string = NULL; - value->encoding.str_struct.offset = 0; + value->attr_form = def->attr_form; + value->attr_name = def->attr_name; + value->block.data = NULL; + value->string.content = NULL; + value->string.offset = 0; - switch (spec->attr_form) { + switch (def->attr_form) { case DW_FORM_addr: - switch (hdr->pointer_size) { + switch (hdr->address_size) { case 1: - value->encoding.address = READ8 (buf); + value->address = READ8 (buf); break; case 2: - value->encoding.address = READ16 (buf); + value->address = READ16 (buf); break; case 4: - value->encoding.address = READ32 (buf); + value->address = READ32 (buf); break; case 8: - value->encoding.address = READ64 (buf); + value->address = READ64 (buf); break; default: - eprintf ("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size); + eprintf ("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->address_size); return NULL; } break; + case DW_FORM_data1: + value->data = READ8 (buf); + break; + case DW_FORM_data2: + value->data = READ16 (buf); + break; + case DW_FORM_data4: + value->data = READ32 (buf); + break; + case DW_FORM_data8: + value->data = READ64 (buf); + break; + case DW_FORM_data16: // TODO Fix this, right now I just read the data, but I need to make storage for it + value->data = READ64 (buf); + value->data = READ64 (buf); + break; + case DW_FORM_sdata: + buf = r_leb128 (buf, buf_end - buf, &value->sdata); + break; + case DW_FORM_udata: + buf = r_uleb128 (buf, buf_end - buf, &value->data); + break; + case DW_FORM_string: + value->string.content = *buf ? strdup ((const char *)buf) : NULL; + buf += (strlen ((const char *)buf) + 1); + break; + case DW_FORM_block1: + value->block.length = READ8 (buf); + value->block.data = calloc (sizeof (ut8), value->block.length + 1); + if (!value->block.data) { + return NULL; + } + if (value->block.data) { + for (j = 0; j < value->block.length; j++) { + value->block.data[j] = READ (buf, ut8); + } + } + break; case DW_FORM_block2: - value->encoding.block.length = READ16 (buf); - if (value->encoding.block.length > 0) { - value->encoding.block.data = calloc (sizeof(ut8), value->encoding.block.length); - for (j = 0; j < value->encoding.block.length; j++) { - value->encoding.block.data[j] = READ (buf, ut8); + value->block.length = READ16 (buf); + if (value->block.length > 0) { + value->block.data = calloc (sizeof (ut8), value->block.length); + if (!value->block.data) { + return NULL; + } + for (j = 0; j < value->block.length; j++) { + value->block.data[j] = READ (buf, ut8); } } break; case DW_FORM_block4: - value->encoding.block.length = READ32 (buf); - if (value->encoding.block.length > 0) { - ut8 *data = calloc (sizeof (ut8), value->encoding.block.length); - if (data) { - for (j = 0; j < value->encoding.block.length; j++) { - data[j] = READ (buf, ut8); - } + value->block.length = READ32 (buf); + if (value->block.length > 0) { + ut8 *data = calloc (sizeof (ut8), value->block.length); + if (!data) { + return NULL; } - value->encoding.block.data = data; + for (j = 0; j < value->block.length; j++) { + data[j] = READ (buf, ut8); + } + value->block.data = data; } break; - case DW_FORM_data2: - value->encoding.data = READ16 (buf); - break; - case DW_FORM_data4: - value->encoding.data = READ32 (buf); - break; - case DW_FORM_data8: - value->encoding.data = READ64 (buf); - break; - case DW_FORM_string: - value->encoding.str_struct.string = *buf? strdup ((const char*)buf) : NULL; - buf += (strlen ((const char*)buf) + 1); - break; - case DW_FORM_block: - buf = r_uleb128 (buf, buf_end - buf, &value->encoding.block.length); + case DW_FORM_block: // variable length ULEB128 + buf = r_uleb128 (buf, buf_end - buf, &value->block.length); if (!buf || buf >= buf_end) { return NULL; } - value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length); - if (value->encoding.block.data) { - for (j = 0; j < value->encoding.block.length; j++) { - value->encoding.block.data[j] = READ (buf, ut8); - } - } - break; - case DW_FORM_block1: - value->encoding.block.length = READ (buf, ut8); - value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length + 1); - if (value->encoding.block.data) { - for (j = 0; j < value->encoding.block.length; j++) { - value->encoding.block.data[j] = READ (buf, ut8); + value->block.data = calloc (sizeof (ut8), value->block.length); + if (value->block.data) { + for (j = 0; j < value->block.length; j++) { + value->block.data[j] = READ (buf, ut8); } } break; case DW_FORM_flag: - value->encoding.flag = READ (buf, ut8); - break; - case DW_FORM_sdata: - buf = r_leb128 (buf, buf_end - buf, &value->encoding.sdata); + value->flag = READ (buf, ut8); break; + // offset in .debug_str case DW_FORM_strp: - value->encoding.str_struct.offset = READ32 (buf); - if (debug_str && value->encoding.str_struct.offset < debug_str_len) { - value->encoding.str_struct.string = strdup ( - (const char *)(debug_str + - value->encoding.str_struct.offset)); + value->string.offset = dwarf_read_piece(hdr->is_64bit, &buf, buf_end); + if (debug_str && value->string.offset < debug_str_len) { + value->string.content = + strdup ((const char *)(debug_str + value->string.offset)); } else { - value->encoding.str_struct.string = NULL; - } - break; - case DW_FORM_udata: - { - ut64 ndata = 0; - const ut8 *data = (const ut8*)&ndata; - buf = r_uleb128 (buf, R_MIN (sizeof (data), (size_t)(buf_end - buf)), &ndata); - memcpy (&value->encoding.data, data, sizeof (value->encoding.data)); - value->encoding.str_struct.string = NULL; + value->string.content = NULL; } break; + // offset in .debug_info case DW_FORM_ref_addr: - value->encoding.reference = READ64 (buf); // addr size of machine + value->reference = dwarf_read_piece(hdr->is_64bit, &buf, buf_end); break; + // This type of reference is an offset from the first byte of the compilation + // header for the compilation unit containing the reference case DW_FORM_ref1: - value->encoding.reference = READ8 (buf); + value->reference = hdr->unit_offset + READ8 (buf); break; case DW_FORM_ref2: - value->encoding.reference = READ16 (buf); + value->reference = hdr->unit_offset + READ16 (buf); break; case DW_FORM_ref4: - value->encoding.reference = READ32 (buf); + value->reference = hdr->unit_offset + READ32 (buf); break; case DW_FORM_ref8: - value->encoding.reference = READ64 (buf); + value->reference = hdr->unit_offset + READ64 (buf); break; - case DW_FORM_data1: - value->encoding.data = READ8 (buf); + case DW_FORM_ref_udata: + // uleb128 is enough to fit into ut64? + buf = r_uleb128 (buf, buf_end - buf, &value->reference); + value->reference += hdr->unit_offset; + break; + // offset in a section other than .debug_info or .debug_str + case DW_FORM_sec_offset: + value->reference = dwarf_read_piece(hdr->is_64bit, &buf, buf_end); + break; + case DW_FORM_exprloc: + buf = r_uleb128 (buf, buf_end - buf, &value->block.length); + if (!buf || buf >= buf_end) { + return NULL; + } + value->block.data = calloc (sizeof (ut8), value->block.length); + if (!value->block.data) { + return NULL; + } + if (value->block.data) { + for (j = 0; j < value->block.length; j++) { + value->block.data[j] = READ (buf, ut8); + } + } + break; + // this means that the flag is present, nothing is read + case DW_FORM_flag_present: + value->flag = true; + break; + case DW_FORM_ref_sig8: + value->reference = READ64 (buf); + break; + // offset into .debug_line_str section, can't parse the section now, so we just skip + case DW_FORM_strx: + buf = r_uleb128 (buf, buf_end - buf, &value->string.offset); + break; + case DW_FORM_strx1: + value->string.offset = READ8 (buf); + break; + case DW_FORM_strx2: + value->string.offset = READ16 (buf); + break; + case DW_FORM_strx3: // TODO Add 3 byte int read + buf += 3; + break; + case DW_FORM_strx4: + value->string.offset = READ32 (buf); + break; + case DW_FORM_implicit_const: + value->sdata = def->special; + break; + /* addrx* forms : The index is relative to the value of the + DW_AT_addr_base attribute of the associated compilation unit. + index into an array of addresses in the .debug_addr section.*/ + case DW_FORM_addrx: + buf = r_uleb128 (buf, buf_end - buf, &value->address); + break; + case DW_FORM_addrx1: + value->address = READ8 (buf); + break; + case DW_FORM_addrx2: + value->address = READ16 (buf); + break; + case DW_FORM_addrx3: + // I need to add 3byte endianess free read here TODO + buf += 3; + break; + case DW_FORM_addrx4: + value->address = READ32 (buf); + break; + case DW_FORM_line_ptr: // offset in a section .debug_line_str + case DW_FORM_strp_sup: // offset in a section .debug_line_str + value->string.offset = dwarf_read_piece(hdr->is_64bit, &buf, buf_end); + break; + // offset in the supplementary object file + case DW_FORM_ref_sup4: + value->reference = READ32 (buf); + break; + case DW_FORM_ref_sup8: + value->reference = READ64 (buf); + break; + // An index into the .debug_loclists + case DW_FORM_loclistx: + // An index into the .debug_rnglists + case DW_FORM_rnglistx: + buf = r_uleb128 (buf, buf_end - buf, &value->address); break; default: - eprintf ("Unknown DW_FORM 0x%02"PFMT64x"\n", spec->attr_form); - value->encoding.data = 0; + eprintf ("Unknown DW_FORM 0x%02" PFMT64x "\n", def->attr_form); + value->data = 0; return NULL; } return buf; } -static const ut8 *r_bin_dwarf_parse_comp_unit(Sdb *s, const ut8 *obuf, - RBinDwarfCompUnit *cu, const RBinDwarfDebugAbbrev *da, - size_t offset, const ut8 *debug_str, size_t debug_str_len) { - const ut8 *buf = obuf, *buf_end = obuf + (cu->hdr.length - 7); - ut64 abbr_code; +/** + * @brief + * + * @param buf Start of the DIE data + * @param buf_end + * @param abbrev Abbreviation of the DIE + * @param hdr Unit header + * @param die DIE to store the parsed info into + * @param debug_str Ptr to string section start + * @param debug_str_len Length of the string section + * @param sdb + * @return const ut8* Updated buffer + */ +static const ut8 *parse_die(const ut8 *buf, const ut8 *buf_end, RBinDwarfAbbrevDecl *abbrev, + RBinDwarfCompUnitHdr *hdr, RBinDwarfDie *die, const ut8 *debug_str, size_t debug_str_len, Sdb *sdb) { size_t i; + for (i = 0; i < abbrev->count - 1; i++) { + memset (&die->attr_values[i], 0, sizeof (die->attr_values[i])); - if (cu->hdr.length > debug_str_len) { - //avoid oob read - return NULL; - } - while (buf && buf < buf_end && buf >= obuf) { - if (cu->length && cu->capacity == cu->length) { - r_bin_dwarf_expand_cu (cu); + buf = parse_attr_value (buf, buf_end - buf, &abbrev->defs[i], + &die->attr_values[i], hdr, debug_str, debug_str_len); + + RBinDwarfAttrValue *attribute = &die->attr_values[i]; + + bool is_valid_string_form = (attribute->attr_form == DW_FORM_strp || + attribute->attr_form == DW_FORM_string) && + attribute->string.content; + // TODO does this have a purpose anymore? + // Or atleast it needs to rework becase there will be + // more comp units -> more comp dirs and only the last one will be kept + if (attribute->attr_name == DW_AT_comp_dir && is_valid_string_form) { + const char *name = attribute->string.content; + sdb_set (sdb, "DW_AT_comp_dir", name, 0); } + die->count++; + } + + return buf; +} + +/** + * @brief Reads throught comp_unit buffer and parses all its DIEntries + * + * @param sdb + * @param buf_start Start of the compilation unit data + * @param unit Unit to store the newly parsed information + * @param abbrevs Parsed abbrev section info of *all* abbreviations + * @param first_abbr_idx index for first abbrev of the current comp unit in abbrev array + * @param debug_str Ptr to string section start + * @param debug_str_len Length of the string section + * + * @return const ut8* Update buffer + */ +static const ut8 *parse_comp_unit(Sdb *sdb, const ut8 *buf_start, + RBinDwarfCompUnit *unit, const RBinDwarfDebugAbbrev *abbrevs, + size_t first_abbr_idx, const ut8 *debug_str, size_t debug_str_len) { + + const ut8 *buf = buf_start; + const ut8 *buf_end = buf_start + unit->hdr.length - unit->hdr.header_size; + + while (buf && buf < buf_end && buf >= buf_start) { + if (unit->count && unit->capacity == unit->count) { + expand_cu (unit); + } + RBinDwarfDie *die = &unit->dies[unit->count]; + // DIE starts with ULEB128 with the abbreviation code + ut64 abbr_code; buf = r_uleb128 (buf, buf_end - buf, &abbr_code); - if (abbr_code > da->length || !buf || buf >= buf_end) { + + if (abbr_code > abbrevs->count || !buf) { // something invalid return NULL; } - r_bin_dwarf_init_die (&cu->dies[cu->length]); + if (buf >= buf_end) { + unit->count++; // we wanna store this entry too, usually the last one is null_entry + return buf; // return the buffer to parse next compilation units + } + // there can be "null" entries that have abbr_code == 0 if (!abbr_code) { - cu->dies[cu->length].abbrev_code = 0; - cu->length++; - buf++; + unit->count++; continue; } + ut64 abbr_idx = first_abbr_idx + abbr_code; - cu->dies[cu->length].abbrev_code = abbr_code; - cu->dies[cu->length].tag = da->decls[abbr_code - 1].tag; - abbr_code += offset; + if (abbrevs->count < abbr_idx) { + return NULL; + } + RBinDwarfAbbrevDecl *abbrev = &abbrevs->decls[abbr_idx - 1]; - if (da->capacity < abbr_code) { + if (init_die (die, abbr_code, abbrev->count)) { + return NULL; // error + } + die->tag = abbrev->tag; + + buf = parse_die (buf, buf_end, abbrev, &unit->hdr, die, debug_str, debug_str_len, sdb); + if (!buf) { return NULL; } - for (i = 0; i < da->decls[abbr_code - 1].length; i++) { - if (cu->dies[cu->length].length == cu->dies[cu->length].capacity) { - r_bin_dwarf_expand_die (&cu->dies[cu->length]); - } - if (i >= cu->dies[cu->length].capacity || i >= da->decls[abbr_code - 1].capacity) { - eprintf ("Warning: malformed dwarf attribute capacity doesn't match length\n"); - break; - } - memset (&cu->dies[cu->length].attr_values[i], 0, sizeof (cu->dies[cu->length].attr_values[i])); - buf = r_bin_dwarf_parse_attr_value (buf, buf_end - buf, - &da->decls[abbr_code - 1].specs[i], - &cu->dies[cu->length].attr_values[i], - &cu->hdr, debug_str, debug_str_len); - if (cu->dies[cu->length].attr_values[i].name == DW_AT_comp_dir) { - const char *name = cu->dies[cu->length].attr_values[i].encoding.str_struct.string; - if ((size_t)name > 1024) { // solve some null derefs - sdb_set (s, "DW_AT_comp_dir", name, 0); - } else { - eprintf ("Invalid string pointer at %p\n", name); - } - } - cu->dies[cu->length].length++; - } - cu->length++; + unit->count++; } return buf; } -R_API int r_bin_dwarf_parse_info_raw(Sdb *s, RBinDwarfDebugAbbrev *da, +/** + * @brief Reads all information about compilation unit header + * + * @param buf Start of the buffer + * @param buf_end Upper bound of the buffer + * @param unit Unit to read information into + * @return ut8* Advanced position in a buffer + */ +static const ut8 *info_comp_unit_read_hdr(const ut8 *buf, const ut8 *buf_end, RBinDwarfCompUnitHdr *hdr) { + // 32-bit vs 64-bit dwarf formats + // http://www.dwarfstd.org/doc/Dwarf3.pdf section 7.4 + hdr->length = READ32 (buf); + if (hdr->length == (ut32)DWARF_INIT_LEN_64) { // then its 64bit + hdr->length = READ64 (buf); + hdr->is_64bit = true; + } + const ut8 *tmp = buf; // to calculate header size + hdr->version = READ16 (buf); + if (hdr->version == 5) { + hdr->unit_type = READ8 (buf); + hdr->address_size = READ8 (buf); + hdr->abbrev_offset = dwarf_read_piece (hdr->is_64bit, &buf, buf_end); + + if (hdr->unit_type == DW_UT_skeleton || hdr->unit_type == DW_UT_split_compile) { + hdr->dwo_id = READ8 (buf); + } else if (hdr->unit_type == DW_UT_type || hdr->unit_type == DW_UT_split_type) { + hdr->type_sig = READ64 (buf); + hdr->type_offset = dwarf_read_piece (hdr->is_64bit, &buf, buf_end); + } + } else { + hdr->abbrev_offset = dwarf_read_piece (hdr->is_64bit, &buf, buf_end); + hdr->address_size = READ8 (buf); + } + hdr->header_size = buf - tmp; // header size excluding length field + return buf; +} +static int expand_info(RBinDwarfDebugInfo *info) { + r_return_val_if_fail (info && info->capacity == info->count, -1); + + RBinDwarfCompUnit *tmp = realloc (info->comp_units, + info->capacity * 2 * sizeof (RBinDwarfCompUnit)); + if (!tmp) { + return -1; + } + + memset ((ut8 *)tmp + info->capacity * sizeof (RBinDwarfCompUnit), + 0, info->capacity * sizeof (RBinDwarfCompUnit)); + + info->comp_units = tmp; + info->capacity *= 2; + + return 0; +} + +/** + * @brief Parses whole .debug_info section + * + * @param sdb Sdb to store line related information into + * @param da Parsed Abbreviations + * @param obuf .debug_info section buffer start + * @param len length of the section buffer + * @param debug_str start of the .debug_str section + * @param debug_str_len length of the debug_str section + * @param mode + * @return R_API* parse_info_raw Parsed information + */ +static RBinDwarfDebugInfo *parse_info_raw(Sdb *sdb, RBinDwarfDebugAbbrev *da, const ut8 *obuf, size_t len, - const ut8 *debug_str, size_t debug_str_len, int mode) { - const ut8 *buf = obuf, *buf_end = obuf + len; - size_t k, offset = 0; - int curr_unit = 0; - RBinDwarfDebugInfo di = {0}; - RBinDwarfDebugInfo *inf = &di; - bool ret = true; + const ut8 *debug_str, size_t debug_str_len) { - if (!da || !s || !obuf) { - return false; - } + r_return_val_if_fail (da && sdb && obuf, false); - if (r_bin_dwarf_init_debug_info (inf) < 0) { - ret = false; - goto out; + const ut8 *buf = obuf; + const ut8 *buf_end = obuf + len; + + RBinDwarfDebugInfo *info = R_NEW0 (RBinDwarfDebugInfo); + if (!info) { + return NULL; } + if (init_debug_info (info) < 0) { + goto cleanup; + } + int unit_idx = 0; + while (buf < buf_end) { - if (inf->length >= inf->capacity) { - break; - } - - if (r_bin_dwarf_init_comp_unit (&inf->comp_units[curr_unit]) < 0) { - ret = false; - curr_unit--; - goto out_debug_info; - } - - inf->comp_units[curr_unit].offset = buf - obuf; - inf->comp_units[curr_unit].hdr.pointer_size = 0; - inf->comp_units[curr_unit].hdr.abbrev_offset = 0; - inf->comp_units[curr_unit].hdr.length = READ32 (buf); - inf->comp_units[curr_unit].hdr.version = READ16 (buf); - - if (inf->comp_units[curr_unit].hdr.version != 2) { -// eprintf ("DWARF: version %d is not yet supported.\n", -// inf->comp_units[curr_unit].hdr.version); - ret = false; - goto out_debug_info; - } - if (inf->comp_units[curr_unit].hdr.length > len) { - ret = false; - goto out_debug_info; - } - - inf->comp_units[curr_unit].hdr.abbrev_offset = READ32 (buf); - inf->comp_units[curr_unit].hdr.pointer_size = READ (buf, ut8); - inf->length++; - - /* Linear search FIXME */ - if (da->decls->length >= da->capacity) { - eprintf ("WARNING: malformed dwarf have not enough buckets for decls.\n"); - } - const int k_max = R_MIN (da->capacity, da->decls->length); - for (k = 0; k < k_max; k++) { - if (da->decls[k].offset == - inf->comp_units[curr_unit].hdr.abbrev_offset) { - offset = k; + if (info->count >= info->capacity) { + if (expand_info (info)) { break; } } - buf = r_bin_dwarf_parse_comp_unit (s, buf, &inf->comp_units[curr_unit], - da, offset, debug_str, debug_str_len); + RBinDwarfCompUnit *unit = &info->comp_units[unit_idx]; + if (init_comp_unit (unit) < 0) { + unit_idx--; + goto cleanup; + } + info->count++; - if (!buf) { - ret = false; - goto out_debug_info; + unit->offset = buf - obuf; + // small redundancy, because it was easiest solution at a time + unit->hdr.unit_offset = buf - obuf; + + buf = info_comp_unit_read_hdr (buf, buf_end, &unit->hdr); + + if (unit->hdr.length > len) { + goto cleanup; } - curr_unit++; + if (da->decls->count >= da->capacity) { + eprintf ("WARNING: malformed dwarf have not enough buckets for decls.\n"); + } + r_warn_if_fail (da->count <= da->capacity); + + // find abbrev start for current comp unit + // we could also do naive, ((char *)da->decls) + abbrev_offset? + RBinDwarfAbbrevDecl key = { .offset = unit->hdr.abbrev_offset }; + RBinDwarfAbbrevDecl *abbrev_start = bsearch (&key, da->decls, da->count, sizeof (key), abbrev_cmp); + if (!abbrev_start) { + goto cleanup; + } + // They point to the same array object, so should be def. behaviour + size_t first_abbr_idx = abbrev_start - da->decls; + + buf = parse_comp_unit (sdb, buf, unit, da, first_abbr_idx, debug_str, debug_str_len); + + if (!buf) { + goto cleanup; + } + + unit_idx++; } - if (mode == R_MODE_PRINT) { - r_bin_dwarf_dump_debug_info (NULL, inf); - } + return info; -out_debug_info: - for (; curr_unit >= 0; curr_unit--) { - r_bin_dwarf_free_comp_unit (&inf->comp_units[curr_unit]); - } - r_bin_dwarf_free_debug_info (inf); -out: - return ret; +cleanup: + r_bin_dwarf_free_debug_info (info); + return NULL; } -static RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev_raw(const ut8 *obuf, size_t len, int mode) { +static RBinDwarfDebugAbbrev *parse_abbrev_raw(const ut8 *obuf, size_t len) { const ut8 *buf = obuf, *buf_end = obuf + len; - ut64 tmp, spec1, spec2, offset; + ut64 tmp, attr_code, attr_form, offset; + st64 special; ut8 has_children; RBinDwarfAbbrevDecl *tmpdecl; @@ -1643,7 +2022,7 @@ static RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev_raw(const ut8 *obuf, size_ } RBinDwarfDebugAbbrev *da = R_NEW0 (RBinDwarfDebugAbbrev); - r_bin_dwarf_init_debug_abbrev (da); + init_debug_abbrev (da); while (buf && buf+1 < buf_end) { offset = buf - obuf; @@ -1651,16 +2030,16 @@ static RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev_raw(const ut8 *obuf, size_ if (!buf || !tmp || buf >= buf_end) { continue; } - if (da->length == da->capacity) { - r_bin_dwarf_expand_debug_abbrev(da); + if (da->count == da->capacity) { + expand_debug_abbrev(da); } - tmpdecl = &da->decls[da->length]; - r_bin_dwarf_init_abbrev_decl (tmpdecl); + tmpdecl = &da->decls[da->count]; + init_abbrev_decl (tmpdecl); tmpdecl->code = tmp; buf = r_uleb128 (buf, (size_t)(buf_end-buf), &tmp); tmpdecl->tag = tmp; - + tmpdecl->offset = offset; if (buf >= buf_end) { break; @@ -1668,24 +2047,25 @@ static RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev_raw(const ut8 *obuf, size_ has_children = READ (buf, ut8); tmpdecl->has_children = has_children; do { - if (tmpdecl->length == tmpdecl->capacity) { - r_bin_dwarf_expand_abbrev_decl (tmpdecl); + if (tmpdecl->count == tmpdecl->capacity) { + expand_abbrev_decl (tmpdecl); } - buf = r_uleb128 (buf, (size_t)(buf_end - buf), &spec1); + buf = r_uleb128 (buf, (size_t)(buf_end - buf), &attr_code); if (buf >= buf_end) { break; } - buf = r_uleb128 (buf, (size_t)(buf_end - buf), &spec2); - tmpdecl->specs[tmpdecl->length].attr_name = spec1; - tmpdecl->specs[tmpdecl->length].attr_form = spec2; - tmpdecl->length++; - } while (spec1 && spec2); + buf = r_uleb128 (buf, (size_t)(buf_end - buf), &attr_form); + // http://www.dwarfstd.org/doc/DWARF5.pdf#page=225 + if (attr_form == DW_FORM_implicit_const) { + buf = r_leb128 (buf, (size_t)(buf_end - buf), &special); + tmpdecl->defs[tmpdecl->count].special = special; + } + tmpdecl->defs[tmpdecl->count].attr_name = attr_code; + tmpdecl->defs[tmpdecl->count].attr_form = attr_form; + tmpdecl->count++; + } while (attr_code && attr_form); - da->length++; - } - - if (mode == R_MODE_PRINT) { - dump_r_bin_dwarf_debug_abbrev (stdout, da); + da->count++; } return da; } @@ -1706,51 +2086,68 @@ RBinSection *getsection(RBin *a, const char *sn) { return NULL; } -R_API int r_bin_dwarf_parse_info(RBinDwarfDebugAbbrev *da, RBin *a, int mode) { - ut8 *buf, *debug_str_buf = 0; - int len, debug_str_len = 0, ret; +/** + * @brief Prepares sections and parses .debug_info + * + * @param da Parsed abbreviations + * @param a + * @param mode + * @return RBinDwarfDebugInfo* Parsed information + */ +R_API RBinDwarfDebugInfo *r_bin_dwarf_parse_info(RBinDwarfDebugAbbrev *da, RBin *bin, int mode) { + RBinDwarfDebugInfo *info = NULL; RBinSection *debug_str; - RBinSection *section = getsection (a, "debug_info"); - RBinFile *binfile = a ? a->cur: NULL; + RBinSection *section = getsection (bin, "debug_info"); + RBinFile *binfile = bin ? bin->cur : NULL; + + ut64 debug_str_len; + ut8 *debug_str_buf = NULL; if (binfile && section) { - debug_str = getsection (a, "debug_str"); + debug_str = getsection (bin, "debug_str"); if (debug_str) { debug_str_len = debug_str->size; debug_str_buf = calloc (1, debug_str_len + 1); - ret = r_buf_read_at (binfile->buf, debug_str->paddr, - debug_str_buf, debug_str_len); + if (!debug_str_buf) { + goto cleanup; + } + st64 ret = r_buf_read_at (binfile->buf, debug_str->paddr, + debug_str_buf, debug_str_len); if (!ret) { - free (debug_str_buf); - return false; + goto cleanup; } } - len = section->size; + ut64 len = section->size; + // what is this checking for? if (len > (UT32_MAX >> 1) || len < 1) { - free (debug_str_buf); - return false; + goto cleanup; } - buf = calloc (1, len); + ut8 *buf = calloc (1, len); if (!buf) { - free (debug_str_buf); - return false; + goto cleanup; } if (!r_buf_read_at (binfile->buf, section->paddr, buf, len)) { - free (debug_str_buf); free (buf); - return false; + goto cleanup; } - ret = r_bin_dwarf_parse_info_raw (binfile->sdb_addrinfo, da, buf, len, - debug_str_buf, debug_str_len, mode); - R_FREE (debug_str_buf); + info = parse_info_raw (binfile->sdb_addrinfo, da, buf, len, + debug_str_buf, debug_str_len); + + if (mode == R_MODE_PRINT && info) { + print_debug_info (info, bin->cb_printf); + } + + free (debug_str_buf); free (buf); - return ret; + return info; } - return false; +cleanup: + free (debug_str_buf); + return NULL; } -static RBinDwarfRow *r_bin_dwarf_row_new(ut64 addr, const char *file, int line, int col) { +static RBinDwarfRow *row_new(ut64 addr, const char *file, int line, int col) { RBinDwarfRow *row = R_NEW0 (RBinDwarfRow); if (!row) { return NULL; @@ -1762,18 +2159,18 @@ static RBinDwarfRow *r_bin_dwarf_row_new(ut64 addr, const char *file, int line, return row; } -static void r_bin_dwarf_row_free(void *p) { +static void row_free(void *p) { RBinDwarfRow *row = (RBinDwarfRow*)p; free (row->file); free (row); } -R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode) { +R_API RList *r_bin_dwarf_parse_line(RBin *bin, int mode) { ut8 *buf; RList *list = NULL; int len, ret; - RBinSection *section = getsection (a, "debug_line"); - RBinFile *binfile = a ? a->cur: NULL; + RBinSection *section = getsection (bin, "debug_line"); + RBinFile *binfile = bin ? bin->cur: NULL; if (binfile && section) { len = section->size; if (len < 1) { @@ -1788,13 +2185,13 @@ R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode) { free (buf); return NULL; } - list = r_list_newf (r_bin_dwarf_row_free); // always return empty list wtf + list = r_list_newf (row_free); // always return empty list wtf if (!list) { free (buf); return NULL; } // Actually parse the section - parse_line_raw (a, buf, len, mode); + parse_line_raw (bin, buf, len, mode); // k bin/cur/addrinfo/* SdbListIter *iter; SdbKv *kv; @@ -1817,7 +2214,7 @@ R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode) { *tok++ = 0; line = atoi (tok); addr = r_num_math (NULL, sdbkv_key (kv)); - row = r_bin_dwarf_row_new (addr, file, line, 0); + row = row_new (addr, file, line, 0); r_list_append (list, row); } free (file); @@ -1829,12 +2226,12 @@ R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode) { return list; } -R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode) { +R_API RList *r_bin_dwarf_parse_aranges(RBin *bin, int mode) { ut8 *buf; int ret; size_t len; - RBinSection *section = getsection (a, "debug_aranges"); - RBinFile *binfile = a ? a->cur: NULL; + RBinSection *section = getsection (bin, "debug_aranges"); + RBinFile *binfile = bin ? bin->cur: NULL; if (binfile && section) { len = section->size; @@ -1847,22 +2244,19 @@ R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode) { free (buf); return NULL; } - if (mode == R_MODE_PRINT) { - r_bin_dwarf_parse_aranges_raw (buf, len, stdout); - } else { - r_bin_dwarf_parse_aranges_raw (buf, len, DBGFD); - } + parse_aranges_raw (buf, len, mode, bin->cb_printf); + free (buf); } return NULL; } -R_API RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev(RBin *a, int mode) { +R_API RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev(RBin *bin, int mode) { ut8 *buf; size_t len; - RBinSection *section = getsection (a, "debug_abbrev"); + RBinSection *section = getsection (bin, "debug_abbrev"); RBinDwarfDebugAbbrev *da = NULL; - RBinFile *binfile = a ? a->cur: NULL; + RBinFile *binfile = bin ? bin->cur: NULL; if (!section || !binfile) { return NULL; } @@ -1872,7 +2266,11 @@ R_API RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev(RBin *a, int mode) { len = section->size; buf = calloc (1,len); r_buf_read_at (binfile->buf, section->paddr, buf, len); - da = r_bin_dwarf_parse_abbrev_raw (buf, len, mode); + da = parse_abbrev_raw (buf, len); + + if (mode == R_MODE_PRINT && da) { + print_abbrev_section (da, bin->cb_printf); + } free (buf); return da; } diff --git a/libr/core/cbin.c b/libr/core/cbin.c index 783182f16b..f5b2a0b5dc 100644 --- a/libr/core/cbin.c +++ b/libr/core/cbin.c @@ -896,11 +896,13 @@ static int bin_dwarf(RCore *core, int mode) { // TODO: complete and speed-up support for dwarf RBinDwarfDebugAbbrev *da = NULL; da = r_bin_dwarf_parse_abbrev (core->bin, mode); - r_bin_dwarf_parse_info (da, core->bin, mode); + RBinDwarfDebugInfo *info = r_bin_dwarf_parse_info (da, core->bin, mode); + // dig types out of into and then free + r_bin_dwarf_free_debug_info (info); + r_bin_dwarf_parse_aranges (core->bin, mode); list = ownlist = r_bin_dwarf_parse_line (core->bin, mode); r_bin_dwarf_free_debug_abbrev (da); - free (da); } if (!list) { return false; diff --git a/libr/include/r_bin_dwarf.h b/libr/include/r_bin_dwarf.h index 68148ab340..b29bb5fa4b 100644 --- a/libr/include/r_bin_dwarf.h +++ b/libr/include/r_bin_dwarf.h @@ -28,8 +28,8 @@ extern "C" { #define DW_LNE_set_address 0x02 #define DW_LNE_define_file 0x03 #define DW_LNE_set_discriminator 0x04 /* DWARF4 */ -#define DW_LNE_lo_user 0x80 -#define DW_LNE_hi_user 0xff +#define DW_LNE_lo_user 0x80 +#define DW_LNE_hi_user 0xff /* HP extensions. */ #define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */ @@ -47,6 +47,7 @@ extern "C" { #define DW_LNE_hi_user 0xff /* DWARF3 */ /* debug_info tags */ +#define DW_TAG_null_entry 0x00 #define DW_TAG_array_type 0x01 #define DW_TAG_class_type 0x02 #define DW_TAG_entry_point 0x03 @@ -110,7 +111,7 @@ extern "C" { #define DW_TAG_partial_unit 0x3c /* DWARF3 */ #define DW_TAG_imported_unit 0x3d /* DWARF3 */ /* Do not use DW_TAG_mutable_type */ -#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */ +#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */ #define DW_TAG_condition 0x3f /* DWARF3f */ #define DW_TAG_shared_type 0x40 /* DWARF3f */ #define DW_TAG_type_unit 0x41 /* DWARF4 */ @@ -118,423 +119,492 @@ extern "C" { #define DW_TAG_template_alias 0x43 /* DWARF4 */ #define DW_TAG_LAST 0x44 // correct ? -#define DW_TAG_lo_user 0x4080 -#define DW_TAG_hi_user 0xffff +/* <_lo_user ; _hi_user> Interval is reserved for vendor extensions */ +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff -#define DW_CHILDREN_no 0x00 -#define DW_CHILDREN_yes 0x01 +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 -#define DW_AT_sibling 0x01 -#define DW_AT_location 0x02 -#define DW_AT_name 0x03 -#define DW_AT_ordering 0x09 -#define DW_AT_byte_size 0x0b -#define DW_AT_bit_offset 0x0c -#define DW_AT_bit_size 0x0d -#define DW_AT_stmt_list 0x10 -#define DW_AT_low_pc 0x11 -#define DW_AT_high_pc 0x12 -#define DW_AT_language 0x13 -#define DW_AT_discr 0x15 -#define DW_AT_discr_value 0x16 -#define DW_AT_visibility 0x17 -#define DW_AT_import 0x18 -#define DW_AT_string_length 0x19 -#define DW_AT_common_reference 0x1a -#define DW_AT_comp_dir 0x1b -#define DW_AT_const_value 0x1c -#define DW_AT_containing_type 0x1d -#define DW_AT_default_value 0x1e -#define DW_AT_inline 0x20 -#define DW_AT_is_optional 0x21 -#define DW_AT_lower_bound 0x22 -#define DW_AT_producer 0x25 -#define DW_AT_prototyped 0x27 -#define DW_AT_return_addr 0x2a -#define DW_AT_start_scope 0x2c -#define DW_AT_stride_size 0x2e -#define DW_AT_upper_bound 0x2f -#define DW_AT_abstract_origin 0x31 -#define DW_AT_accessibility 0x32 -#define DW_AT_address_class 0x33 -#define DW_AT_artificial 0x34 -#define DW_AT_base_types 0x35 -#define DW_AT_calling_convention 0x36 -#define DW_AT_count 0x37 -#define DW_AT_data_member_location 0x38 -#define DW_AT_decl_column 0x39 -#define DW_AT_decl_file 0x3a -#define DW_AT_decl_line 0x3b -#define DW_AT_declaration 0x3c -#define DW_AT_discr_list 0x3d -#define DW_AT_encoding 0x3e -#define DW_AT_external 0x3f -#define DW_AT_frame_base 0x40 -#define DW_AT_friend 0x41 -#define DW_AT_identifier_case 0x42 -#define DW_AT_macro_info 0x43 -#define DW_AT_namelist_item 0x44 -#define DW_AT_priority 0x45 -#define DW_AT_segment 0x46 -#define DW_AT_specification 0x47 -#define DW_AT_static_link 0x48 -#define DW_AT_type 0x49 -#define DW_AT_use_location 0x4a -#define DW_AT_variable_parameter 0x4b -#define DW_AT_virtuality 0x4c -#define DW_AT_vtable_elem_location 0x4d -#define DW_AT_allocated 0x4e -#define DW_AT_associated 0x4f -#define DW_AT_data_location 0x50 -#define DW_AT_byte_stride 0x51 -#define DW_AT_entry_pc 0x52 -#define DW_AT_use_UTF8 0x53 -#define DW_AT_extension 0x54 -#define DW_AT_ranges 0x55 -#define DW_AT_trampoline 0x56 -#define DW_AT_call_column 0x57 -#define DW_AT_call_file 0x58 -#define DW_AT_call_line 0x59 -#define DW_AT_description 0x5a -#define DW_AT_binary_scale 0x5b -#define DW_AT_decimal_scale 0x5c -#define DW_AT_small 0x5d -#define DW_AT_decimal_sign 0x5e -#define DW_AT_digit_count 0x5f -#define DW_AT_picture_string 0x60 -#define DW_AT_mutable 0x61 -#define DW_AT_threads_scaled 0x62 -#define DW_AT_explicit 0x63 -#define DW_AT_object_pointer 0x64 -#define DW_AT_endianity 0x65 -#define DW_AT_elemental 0x66 -#define DW_AT_pure 0x67 -#define DW_AT_recursive 0x68 -#define DW_AT_signature 0x69 -#define DW_AT_main_subprogram 0x6a -#define DW_AT_data_big_offset 0x6b -#define DW_AT_const_expr 0x6c -#define DW_AT_enum_class 0x6d -#define DW_AT_linkage_name 0x6e -#define DW_AT_lo_user 0x2000 -#define DW_AT_hi_user 0x3fff +#define DW_AT_sibling 0x01 +#define DW_AT_location 0x02 +#define DW_AT_name 0x03 +#define DW_AT_ordering 0x09 +#define DW_AT_byte_size 0x0b +#define DW_AT_bit_offset 0x0c +#define DW_AT_bit_size 0x0d +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_discr 0x15 +#define DW_AT_discr_value 0x16 +#define DW_AT_visibility 0x17 +#define DW_AT_import 0x18 +#define DW_AT_string_length 0x19 +#define DW_AT_common_reference 0x1a +#define DW_AT_comp_dir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_default_value 0x1e +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_return_addr 0x2a +#define DW_AT_start_scope 0x2c +#define DW_AT_stride_size 0x2e +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_address_class 0x33 +#define DW_AT_artificial 0x34 +#define DW_AT_base_types 0x35 +#define DW_AT_calling_convention 0x36 +#define DW_AT_count 0x37 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_column 0x39 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_discr_list 0x3d +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_friend 0x41 +#define DW_AT_identifier_case 0x42 +#define DW_AT_macro_info 0x43 +#define DW_AT_namelist_item 0x44 +#define DW_AT_priority 0x45 +#define DW_AT_segment 0x46 +#define DW_AT_specification 0x47 +#define DW_AT_static_link 0x48 +#define DW_AT_type 0x49 +#define DW_AT_use_location 0x4a +#define DW_AT_variable_parameter 0x4b +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d +#define DW_AT_allocated 0x4e // DWARF 3 additions start +#define DW_AT_associated 0x4f +#define DW_AT_data_location 0x50 +#define DW_AT_byte_stride 0x51 +#define DW_AT_entry_pc 0x52 +#define DW_AT_use_UTF8 0x53 +#define DW_AT_extension 0x54 +#define DW_AT_ranges 0x55 +#define DW_AT_trampoline 0x56 +#define DW_AT_call_column 0x57 +#define DW_AT_call_file 0x58 +#define DW_AT_call_line 0x59 +#define DW_AT_description 0x5a +#define DW_AT_binary_scale 0x5b +#define DW_AT_decimal_scale 0x5c +#define DW_AT_small 0x5d +#define DW_AT_decimal_sign 0x5e +#define DW_AT_digit_count 0x5f +#define DW_AT_picture_string 0x60 +#define DW_AT_mutable 0x61 +#define DW_AT_threads_scaled 0x62 +#define DW_AT_explicit 0x63 +#define DW_AT_object_pointer 0x64 +#define DW_AT_endianity 0x65 +#define DW_AT_elemental 0x66 +#define DW_AT_pure 0x67 +#define DW_AT_recursive 0x68 // DWARF 3 additions end +#define DW_AT_signature 0x69 +#define DW_AT_main_subprogram 0x6a +#define DW_AT_data_big_offset 0x6b +#define DW_AT_const_expr 0x6c +#define DW_AT_enum_class 0x6d +#define DW_AT_linkage_name 0x6e -#define DW_FORM_addr 0x01 -#define DW_FORM_block2 0x03 -#define DW_FORM_block4 0x04 -#define DW_FORM_data2 0x05 -#define DW_FORM_data4 0x06 -#define DW_FORM_data8 0x07 -#define DW_FORM_string 0x08 -#define DW_FORM_block 0x09 -#define DW_FORM_block1 0x0a -#define DW_FORM_data1 0x0b -#define DW_FORM_flag 0x0c -#define DW_FORM_sdata 0x0d -#define DW_FORM_strp 0x0e -#define DW_FORM_udata 0x0f -#define DW_FORM_ref_addr 0x10 -#define DW_FORM_ref1 0x11 -#define DW_FORM_ref2 0x12 -#define DW_FORM_ref4 0x13 -#define DW_FORM_ref8 0x14 -#define DW_FORM_ref_udata 0x15 -#define DW_FORM_indirect 0x16 -#define DW_FORM_sec_offset 0x17 -#define DW_FORM_exprloc 0x18 -#define DW_FORM_flag_present 0x19 -#define DW_FORM_ref_sig8 0x20 +#define DW_AT_string_length_bit_size 0x6f +#define DW_AT_string_length_byte_size 0x70 +#define DW_AT_rank 0x71 +#define DW_AT_str_offsets_base 0x72 +#define DW_AT_addr_base 0x73 +#define DW_AT_rnglists_base 0x74 +// #define Reserved 0x75 Unused +#define DW_AT_dwo_name 0x76 +#define DW_AT_reference 0x77 +#define DW_AT_rvalue_reference 0x78 +#define DW_AT_macros 0x79 +#define DW_AT_call_all_calls 0x7a +#define DW_AT_call_all_source_calls 0x7b +#define DW_AT_call_all_tail_calls 0x7c +#define DW_AT_call_return_pc 0x7d +#define DW_AT_call_value 0x7e +#define DW_AT_call_origin 0x7f +#define DW_AT_call_parameter 0x80 +#define DW_AT_call_pc 0x81 +#define DW_AT_call_tail_call 0x82 +#define DW_AT_call_target 0x83 +#define DW_AT_call_target_clobbered 0x84 +#define DW_AT_call_data_location 0x85 +#define DW_AT_call_data_value 0x86 +#define DW_AT_noreturn 0x87 +#define DW_AT_alignment 0x88 +#define DW_AT_export_symbols 0x89 +#define DW_AT_deleted 0x8a +#define DW_AT_defaulted 0x8b +#define DW_AT_loclists_base 0x8c -#define DW_OP_addr 0x03 -#define DW_OP_deref 0x06 -#define DW_OP_const1u 0x08 -#define DW_OP_const1s 0x09 -#define DW_OP_const2u 0x0a -#define DW_OP_const2s 0x0b -#define DW_OP_const4u 0x0c -#define DW_OP_const4s 0x0d -#define DW_OP_const8u 0x0e -#define DW_OP_const8s 0x0f -#define DW_OP_constu 0x10 -#define DW_OP_consts 0x11 -#define DW_OP_dup 0x12 -#define DW_OP_drop 0x13 -#define DW_OP_over 0x14 -#define DW_OP_pick 0x15 -#define DW_OP_swap 0x16 -#define DW_OP_rot 0x17 -#define DW_OP_xderef 0x18 -#define DW_OP_abs 0x19 -#define DW_OP_and 0x1a -#define DW_OP_div 0x1b -#define DW_OP_minus 0x1c -#define DW_OP_mod 0x1d -#define DW_OP_mul 0x1e -#define DW_OP_neg 0x1f -#define DW_OP_not 0x20 -#define DW_OP_or 0x21 -#define DW_OP_plus 0x22 -#define DW_OP_plus_uconst 0x23 -#define DW_OP_shl 0x24 -#define DW_OP_shr 0x25 -#define DW_OP_shra 0x26 -#define DW_OP_xor 0x27 -#define DW_OP_skip 0x2f -#define DW_OP_bra 0x28 -#define DW_OP_eq 0x29 -#define DW_OP_ge 0x2a -#define DW_OP_gt 0x2b -#define DW_OP_le 0x2c -#define DW_OP_lt 0x2d -#define DW_OP_ne 0x2e -#define DW_OP_lit0 0x30 -#define DW_OP_lit1 0x31 -#define DW_OP_lit2 0x32 -#define DW_OP_lit3 0x33 -#define DW_OP_lit4 0x34 -#define DW_OP_lit5 0x35 -#define DW_OP_lit6 0x36 -#define DW_OP_lit7 0x37 -#define DW_OP_lit8 0x38 -#define DW_OP_lit9 0x39 -#define DW_OP_lit10 0x3a -#define DW_OP_lit11 0x3b -#define DW_OP_lit12 0x3c -#define DW_OP_lit13 0x3d -#define DW_OP_lit14 0x3e -#define DW_OP_lit15 0x3f -#define DW_OP_lit16 0x40 -#define DW_OP_lit17 0x41 -#define DW_OP_lit18 0x42 -#define DW_OP_lit19 0x43 -#define DW_OP_lit20 0x44 -#define DW_OP_lit21 0x45 -#define DW_OP_lit22 0x46 -#define DW_OP_lit23 0x47 -#define DW_OP_lit24 0x48 -#define DW_OP_lit25 0x49 -#define DW_OP_lit26 0x4a -#define DW_OP_lit27 0x4b -#define DW_OP_lit28 0x4c -#define DW_OP_lit29 0x4d -#define DW_OP_lit30 0x4e -#define DW_OP_lit31 0x4f -#define DW_OP_reg0 0x50 -#define DW_OP_reg1 0x51 -#define DW_OP_reg2 0x52 -#define DW_OP_reg3 0x53 -#define DW_OP_reg4 0x54 -#define DW_OP_reg5 0x55 -#define DW_OP_reg6 0x56 -#define DW_OP_reg7 0x57 -#define DW_OP_reg8 0x58 -#define DW_OP_reg9 0x59 -#define DW_OP_reg10 0x5a -#define DW_OP_reg11 0x5b -#define DW_OP_reg12 0x5c -#define DW_OP_reg13 0x5d -#define DW_OP_reg14 0x5e -#define DW_OP_reg15 0x5f -#define DW_OP_reg16 0x60 -#define DW_OP_reg17 0x61 -#define DW_OP_reg18 0x62 -#define DW_OP_reg19 0x63 -#define DW_OP_reg20 0x64 -#define DW_OP_reg21 0x65 -#define DW_OP_reg22 0x66 -#define DW_OP_reg23 0x67 -#define DW_OP_reg24 0x68 -#define DW_OP_reg25 0x69 -#define DW_OP_reg26 0x6a -#define DW_OP_reg27 0x6b -#define DW_OP_reg28 0x6c -#define DW_OP_reg29 0x6d -#define DW_OP_reg30 0x6e -#define DW_OP_reg31 0x6f -#define DW_OP_breg0 0x70 -#define DW_OP_breg1 0x71 -#define DW_OP_breg2 0x72 -#define DW_OP_breg3 0x73 -#define DW_OP_breg4 0x74 -#define DW_OP_breg5 0x75 -#define DW_OP_breg6 0x76 -#define DW_OP_breg7 0x77 -#define DW_OP_breg8 0x78 -#define DW_OP_breg9 0x79 -#define DW_OP_breg10 0x7a -#define DW_OP_breg11 0x7b -#define DW_OP_breg12 0x7c -#define DW_OP_breg13 0x7d -#define DW_OP_breg14 0x7e -#define DW_OP_breg15 0x7f -#define DW_OP_breg16 0x80 -#define DW_OP_breg17 0x81 -#define DW_OP_breg18 0x82 -#define DW_OP_breg19 0x83 -#define DW_OP_breg20 0x84 -#define DW_OP_breg21 0x85 -#define DW_OP_breg22 0x86 -#define DW_OP_breg23 0x87 -#define DW_OP_breg24 0x88 -#define DW_OP_breg25 0x89 -#define DW_OP_breg26 0x8a -#define DW_OP_breg27 0x8b -#define DW_OP_breg28 0x8c -#define DW_OP_breg29 0x8d -#define DW_OP_breg30 0x8e -#define DW_OP_breg31 0x8f -#define DW_OP_regx 0x90 -#define DW_OP_fbreg 0x91 -#define DW_OP_bregx 0x92 -#define DW_OP_piece 0x93 -#define DW_OP_deref_size 0x94 -#define DW_OP_xderef_size 0x95 -#define DW_OP_nop 0x96 -#define DW_OP_push_object_address 0x97 -#define DW_OP_call2 0x98 -#define DW_OP_call4 0x99 -#define DW_OP_call_ref 0x9a -#define DW_OP_form_tls_address 0x9b -#define DW_OP_call_frame_cfa 0x9c -#define DW_OP_bit_piece 0x9d -#define DW_OP_implicit_value 0x9e -#define DW_OP_stack_value 0x9f -#define DW_OP_lo_user 0xe0 -#define DW_OP_hi_user 0xff +/* <_lo_user ; _hi_user> Interval is reserved for vendor extensions */ +#define DW_AT_lo_user 0x2000 +// extensions: +#define DW_AT_GNU_all_tail_call_sites 0x2116 + +#define DW_AT_hi_user 0x3fff + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 +#define DW_FORM_data4 0x06 +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 +#define DW_FORM_sec_offset 0x17 // DWARF 4 new attribute for section offset +#define DW_FORM_exprloc 0x18 +#define DW_FORM_flag_present 0x19 +#define DW_FORM_strx 0x1a +#define DW_FORM_addrx 0x1b +#define DW_FORM_ref_sup4 0x1c +#define DW_FORM_strp_sup 0x1d +#define DW_FORM_data16 0x1e +#define DW_FORM_line_ptr 0x1f +#define DW_FORM_ref_sig8 0x20 +#define DW_FORM_implicit_const 0x21 +#define DW_FORM_loclistx 0x22 +#define DW_FORM_rnglistx 0x23 +#define DW_FORM_ref_sup8 0x24 +#define DW_FORM_strx1 0x25 +#define DW_FORM_strx2 0x26 +#define DW_FORM_strx3 0x27 +#define DW_FORM_strx4 0x28 +#define DW_FORM_addrx1 0x29 +#define DW_FORM_addrx2 0x2a +#define DW_FORM_addrx3 0x2b +#define DW_FORM_addrx4 0x2c + +#define DW_OP_addr 0x03 +#define DW_OP_deref 0x06 +#define DW_OP_const1u 0x08 +#define DW_OP_const1s 0x09 +#define DW_OP_const2u 0x0a +#define DW_OP_const2s 0x0b +#define DW_OP_const4u 0x0c +#define DW_OP_const4s 0x0d +#define DW_OP_const8u 0x0e +#define DW_OP_const8s 0x0f +#define DW_OP_constu 0x10 +#define DW_OP_consts 0x11 +#define DW_OP_dup 0x12 +#define DW_OP_drop 0x13 +#define DW_OP_over 0x14 +#define DW_OP_pick 0x15 +#define DW_OP_swap 0x16 +#define DW_OP_rot 0x17 +#define DW_OP_xderef 0x18 +#define DW_OP_abs 0x19 +#define DW_OP_and 0x1a +#define DW_OP_div 0x1b +#define DW_OP_minus 0x1c +#define DW_OP_mod 0x1d +#define DW_OP_mul 0x1e +#define DW_OP_neg 0x1f +#define DW_OP_not 0x20 +#define DW_OP_or 0x21 +#define DW_OP_plus 0x22 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_shl 0x24 +#define DW_OP_shr 0x25 +#define DW_OP_shra 0x26 +#define DW_OP_xor 0x27 +#define DW_OP_skip 0x2f +#define DW_OP_bra 0x28 +#define DW_OP_eq 0x29 +#define DW_OP_ge 0x2a +#define DW_OP_gt 0x2b +#define DW_OP_le 0x2c +#define DW_OP_lt 0x2d +#define DW_OP_ne 0x2e +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 +#define DW_OP_lit2 0x32 +#define DW_OP_lit3 0x33 +#define DW_OP_lit4 0x34 +#define DW_OP_lit5 0x35 +#define DW_OP_lit6 0x36 +#define DW_OP_lit7 0x37 +#define DW_OP_lit8 0x38 +#define DW_OP_lit9 0x39 +#define DW_OP_lit10 0x3a +#define DW_OP_lit11 0x3b +#define DW_OP_lit12 0x3c +#define DW_OP_lit13 0x3d +#define DW_OP_lit14 0x3e +#define DW_OP_lit15 0x3f +#define DW_OP_lit16 0x40 +#define DW_OP_lit17 0x41 +#define DW_OP_lit18 0x42 +#define DW_OP_lit19 0x43 +#define DW_OP_lit20 0x44 +#define DW_OP_lit21 0x45 +#define DW_OP_lit22 0x46 +#define DW_OP_lit23 0x47 +#define DW_OP_lit24 0x48 +#define DW_OP_lit25 0x49 +#define DW_OP_lit26 0x4a +#define DW_OP_lit27 0x4b +#define DW_OP_lit28 0x4c +#define DW_OP_lit29 0x4d +#define DW_OP_lit30 0x4e +#define DW_OP_lit31 0x4f +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_reg16 0x60 +#define DW_OP_reg17 0x61 +#define DW_OP_reg18 0x62 +#define DW_OP_reg19 0x63 +#define DW_OP_reg20 0x64 +#define DW_OP_reg21 0x65 +#define DW_OP_reg22 0x66 +#define DW_OP_reg23 0x67 +#define DW_OP_reg24 0x68 +#define DW_OP_reg25 0x69 +#define DW_OP_reg26 0x6a +#define DW_OP_reg27 0x6b +#define DW_OP_reg28 0x6c +#define DW_OP_reg29 0x6d +#define DW_OP_reg30 0x6e +#define DW_OP_reg31 0x6f +#define DW_OP_breg0 0x70 +#define DW_OP_breg1 0x71 +#define DW_OP_breg2 0x72 +#define DW_OP_breg3 0x73 +#define DW_OP_breg4 0x74 +#define DW_OP_breg5 0x75 +#define DW_OP_breg6 0x76 +#define DW_OP_breg7 0x77 +#define DW_OP_breg8 0x78 +#define DW_OP_breg9 0x79 +#define DW_OP_breg10 0x7a +#define DW_OP_breg11 0x7b +#define DW_OP_breg12 0x7c +#define DW_OP_breg13 0x7d +#define DW_OP_breg14 0x7e +#define DW_OP_breg15 0x7f +#define DW_OP_breg16 0x80 +#define DW_OP_breg17 0x81 +#define DW_OP_breg18 0x82 +#define DW_OP_breg19 0x83 +#define DW_OP_breg20 0x84 +#define DW_OP_breg21 0x85 +#define DW_OP_breg22 0x86 +#define DW_OP_breg23 0x87 +#define DW_OP_breg24 0x88 +#define DW_OP_breg25 0x89 +#define DW_OP_breg26 0x8a +#define DW_OP_breg27 0x8b +#define DW_OP_breg28 0x8c +#define DW_OP_breg29 0x8d +#define DW_OP_breg30 0x8e +#define DW_OP_breg31 0x8f +#define DW_OP_regx 0x90 +#define DW_OP_fbreg 0x91 +#define DW_OP_bregx 0x92 +#define DW_OP_piece 0x93 +#define DW_OP_deref_size 0x94 +#define DW_OP_xderef_size 0x95 +#define DW_OP_nop 0x96 +#define DW_OP_push_object_address 0x97 +#define DW_OP_call2 0x98 +#define DW_OP_call4 0x99 +#define DW_OP_call_ref 0x9a +#define DW_OP_form_tls_address 0x9b +#define DW_OP_call_frame_cfa 0x9c +#define DW_OP_bit_piece 0x9d +#define DW_OP_implicit_value 0x9e +#define DW_OP_stack_value 0x9f + +/* <_lo_user ; _hi_user> Interval is reserved for vendor extensions */ +#define DW_OP_lo_user 0xe0 +#define DW_OP_hi_user 0xff -#define DW_ATE_address 0x01 -#define DW_ATE_boolean 0x02 -#define DW_ATE_complex_float 0x03 -#define DW_ATE_float 0x04 -#define DW_ATE_signed 0x05 -#define DW_ATE_signed_char 0x06 -#define DW_ATE_unsigned 0x07 -#define DW_ATE_unsigned_char 0x08 -#define DW_ATE_imaginary_float 0x09 -#define DW_ATE_packed_decimal 0x0a -#define DW_ATE_numeric_string 0x0b -#define DW_ATE_edited 0x0c -#define DW_ATE_signed_fixed 0x0d -#define DW_ATE_unsigned_fixed 0x0e -#define DW_ATE_decimal_float 0x0f -#define DW_ATE_UTF 0x10 -#define DW_ATE_lo_user 0x80 -#define DW_ATE_hi_user 0xff +#define DW_ATE_address 0x01 +#define DW_ATE_boolean 0x02 +#define DW_ATE_complex_float 0x03 +#define DW_ATE_float 0x04 +#define DW_ATE_signed 0x05 +#define DW_ATE_signed_char 0x06 +#define DW_ATE_unsigned 0x07 +#define DW_ATE_unsigned_char 0x08 +#define DW_ATE_imaginary_float 0x09 +#define DW_ATE_packed_decimal 0x0a +#define DW_ATE_numeric_string 0x0b +#define DW_ATE_edited 0x0c +#define DW_ATE_signed_fixed 0x0d +#define DW_ATE_unsigned_fixed 0x0e +#define DW_ATE_decimal_float 0x0f +#define DW_ATE_UTF 0x10 -#define DW_DS_unsigned 0x01 -#define DW_DS_leading_overpunch 0x02 -#define DW_DS_trailing_overpunch 0x03 -#define DW_DS_leading_separate 0x04 -#define DW_DS_trailing_separate 0x05 +/* <_lo_user ; _hi_user> Interval is reserved for vendor extensions */ +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff -#define DW_END_default 0x00 -#define DW_END_big 0x01 -#define DW_END_little 0x02 -#define DW_END_lo_user 0x40 -#define DW_END_hi_user 0xff +#define DW_DS_unsigned 0x01 +#define DW_DS_leading_overpunch 0x02 +#define DW_DS_trailing_overpunch 0x03 +#define DW_DS_leading_separate 0x04 +#define DW_DS_trailing_separate 0x05 -#define DW_ACCESS_public 0x01 -#define DW_ACCESS_protected 0x02 -#define DW_ACCESS_private 0x03 +#define DW_END_default 0x00 +#define DW_END_big 0x01 +#define DW_END_little 0x02 -#define DW_VIS_local 0x01 -#define DW_VIS_exported 0x02 -#define DW_VIS_qualified 0x03 +/* <_lo_user ; _hi_user> Interval is reserved for vendor extensions */ +#define DW_END_lo_user 0x40 +#define DW_END_hi_user 0xff -#define DW_VIRTUALITY_none 0x00 -#define DW_VIRTUALITY_virtual 0x01 -#define DW_VIRTUALITY_pure_virtual 0x02 +#define DW_ACCESS_public 0x01 +#define DW_ACCESS_protected 0x02 +#define DW_ACCESS_private 0x03 -#define DW_LANG_C89 0x0001 -#define DW_LANG_C 0x0002 -#define DW_LANG_Ada83 0x0003 -#define DW_LANG_C_plus_plus 0x0004 -#define DW_LANG_Cobol74 0x0005 -#define DW_LANG_Cobol85 0x0006 -#define DW_LANG_Fortran77 0x0007 -#define DW_LANG_Fortran90 0x0008 -#define DW_LANG_Pascal83 0x0009 -#define DW_LANG_Modula2 0x000a -#define DW_LANG_Java 0x000b -#define DW_LANG_C99 0x000c -#define DW_LANG_Ada95 0x000d -#define DW_LANG_Fortran95 0x000e -#define DW_LANG_PLI 0x000f -#define DW_LANG_ObjC 0x0010 -#define DW_LANG_ObjC_plus_plus 0x0011 -#define DW_LANG_UPC 0x0012 -#define DW_LANG_D 0x0013 -#define DW_LANG_Python 0x0014 -#define DW_LANG_Rust 0x001c -#define DW_LANG_C11 0x001d -#define DW_LANG_Swift 0x001e -#define DW_LANG_Julia 0x001f -#define DW_LANG_Dylan 0x0020 -#define DW_LANG_C_plus_plus_14 0x0021 -#define DW_LANG_Fortran03 0x0022 -#define DW_LANG_Fortran08 0x0023 -#define DW_LANG_lo_user 0x8000 -#define DW_LANG_hi_user 0xffff +#define DW_VIS_local 0x01 +#define DW_VIS_exported 0x02 +#define DW_VIS_qualified 0x03 +#define DW_VIRTUALITY_none 0x00 +#define DW_VIRTUALITY_virtual 0x01 +#define DW_VIRTUALITY_pure_virtual 0x02 -#define DW_ID_case_sensitive 0x00 -#define DW_ID_up_case 0x01 -#define DW_ID_down_case 0x02 -#define DW_ID_case_insensitive 0x03 +#define DW_LANG_C89 0x0001 +#define DW_LANG_C 0x0002 +#define DW_LANG_Ada83 0x0003 +#define DW_LANG_C_plus_plus 0x0004 +#define DW_LANG_Cobol74 0x0005 +#define DW_LANG_Cobol85 0x0006 +#define DW_LANG_Fortran77 0x0007 +#define DW_LANG_Fortran90 0x0008 +#define DW_LANG_Pascal83 0x0009 +#define DW_LANG_Modula2 0x000a +#define DW_LANG_Java 0x000b +#define DW_LANG_C99 0x000c +#define DW_LANG_Ada95 0x000d +#define DW_LANG_Fortran95 0x000e +#define DW_LANG_PLI 0x000f +#define DW_LANG_ObjC 0x0010 +#define DW_LANG_ObjC_plus_plus 0x0011 +#define DW_LANG_UPC 0x0012 +#define DW_LANG_D 0x0013 +#define DW_LANG_Python 0x0014 +#define DW_LANG_Rust 0x001c +#define DW_LANG_C11 0x001d +#define DW_LANG_Swift 0x001e +#define DW_LANG_Julia 0x001f +#define DW_LANG_Dylan 0x0020 +#define DW_LANG_C_plus_plus_14 0x0021 +#define DW_LANG_Fortran03 0x0022 +#define DW_LANG_Fortran08 0x0023 +#define DW_LANG_lo_user 0x8000 +#define DW_LANG_hi_user 0xffff -#define DW_CC_normal 0x01 -#define DW_CC_program 0x02 -#define DW_CC_nocall 0x03 -#define DW_CC_lo_user 0x40 -#define DW_CC_hi_user 0xff +#define DW_ID_case_sensitive 0x00 +#define DW_ID_up_case 0x01 +#define DW_ID_down_case 0x02 +#define DW_ID_case_insensitive 0x03 -#define DW_INL_not_inlined 0x00 -#define DW_INL_inlined 0x01 -#define DW_INL_declared_not_inlined 0x02 -#define DW_INL_declared_inlined 0x03 +#define DW_CC_normal 0x01 +#define DW_CC_program 0x02 +#define DW_CC_nocall 0x03 +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff -#define DW_ORD_row_major 0x00 -#define DW_ORD_col_major 0x01 +#define DW_INL_not_inlined 0x00 +#define DW_INL_inlined 0x01 +#define DW_INL_declared_not_inlined 0x02 +#define DW_INL_declared_inlined 0x03 -#define DW_DSC_label 0x00 -#define DW_DSC_range 0x01 +#define DW_ORD_row_major 0x00 +#define DW_ORD_col_major 0x01 -#define DW_MACINFO_define 0x01 -#define DW_MACINFO_undef 0x02 -#define DW_MACINFO_start_file 0x03 -#define DW_MACINFO_end_file 0x04 -#define DW_MACINFO_vendor_ext 0xff +#define DW_DSC_label 0x00 +#define DW_DSC_range 0x01 -#define DW_CFA_advance_loc 0x40 -#define DW_CFA_offset 0x80 -#define DW_CFA_restore 0xc0 +#define DW_MACINFO_define 0x01 +#define DW_MACINFO_undef 0x02 +#define DW_MACINFO_start_file 0x03 +#define DW_MACINFO_end_file 0x04 +#define DW_MACINFO_vendor_ext 0xff -#define DW_CFA_nop 0x00 -#define DW_CFA_set_loc 0x01 -#define DW_CFA_advance_loc1 0x02 -#define DW_CFA_advance_loc2 0x03 -#define DW_CFA_advance_loc4 0x04 -#define DW_CFA_offse_extended 0x05 -#define DW_CFA_restore_extended 0x06 -#define DW_CFA_undefined 0x07 -#define DW_CFA_same_value 0x08 -#define DW_CFA_register 0x09 -#define DW_CFA_remember_state 0x0a -#define DW_CFA_restore_state 0x0b -#define DW_CFA_def_cfa 0x0c -#define DW_CFA_def_cfa_register 0x0d -#define DW_CFA_def_cfa_offset 0x0e -#define DW_CFA_def_cfa_expression 0x0f -#define DW_CFA_expression 0x10 -#define DW_CFA_offset_extended_sf 0x11 -#define DW_CFA_def_cfa_sf 0x12 -#define DW_CFA_def_cfa_offset_sf 0x13 -#define DW_CFA_val_offset 0x14 -#define DW_CFA_val_offset_sf 0x15 -#define DW_CFA_val_expression 0x16 -#define DW_CFA_lo_user 0x1c -#define DW_CFA_hi_user 0x3f +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 + +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offse_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_CFA_offset_extended_sf 0x11 +#define DW_CFA_def_cfa_sf 0x12 +#define DW_CFA_def_cfa_offset_sf 0x13 +#define DW_CFA_val_offset 0x14 +#define DW_CFA_val_offset_sf 0x15 +#define DW_CFA_val_expression 0x16 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_UT_compile 0x01 +#define DW_UT_type 0x02 +#define DW_UT_partial 0x03 +#define DW_UT_skeleton 0x04 +#define DW_UT_split_compile 0x05 +#define DW_UT_split_type 0x06 +#define DW_UT_lo_user 0x80 +#define DW_UT_hi_user 0xff typedef struct { ut32 total_length; @@ -548,7 +618,6 @@ typedef struct { ut32 oplentable[12]; const char **incdirs; const char *file[128]; - //RBinDwarfInfoHeader } RBinDwarfInfoHeader; #define R_BIN_DWARF_INFO_HEADER_FILE_LENGTH(x) (sizeof (x->file)/sizeof(*(x->file))) @@ -575,13 +644,6 @@ typedef union { ut64 offset64; } section_offset; -typedef struct { - ut64 unit_length; - ut16 version; - section_offset debug_abbrev_offset; - ut8 address_size; -} RBinDwarfCompilationUnitHeader; - typedef struct { ut64 unit_length; ut16 version; @@ -602,60 +664,72 @@ typedef struct { typedef struct { ut64 attr_name; ut64 attr_form; -} RBinDwarfAttrSpec; + st64 special; // Used for values coded directly into abbrev +} RBinDwarfAttrDef; typedef struct { ut64 length; ut8 *data; } RBinDwarfBlock; -typedef union { - ut64 address; - RBinDwarfBlock block; - ut64 constant; - ut8 flag; - ut64 data; - st64 sdata; - ut64 reference; - struct { - char *string; - ut64 offset; - } str_struct; -} RBinDwarfAttrEnc; - typedef struct { - ut64 name; - ut64 form; - RBinDwarfAttrEnc encoding; + ut64 attr_name; + ut64 attr_form; + union { + ut64 address; + RBinDwarfBlock block; + ut64 constant; + ut8 flag; + ut64 data; + st64 sdata; + ut64 reference; + // ut64 offset; // I'll use it for all the new offset forms in DWARF 5 + struct { + const char *content; + ut64 offset; + } string; + }; } RBinDwarfAttrValue; typedef struct { - ut32 length; - ut16 version; - ut32 abbrev_offset; - ut8 pointer_size; + // A 4-byte (or 8 byte for 64bit dwarf) unsigned length of the .debug_info contribution + // for that compilation unit, not including the length field itself. + ut64 length; + ut16 version; + // A 4-byte unsigned offset into the .debug_abbrev section. + ut64 abbrev_offset; + // A 1 - byte size of an address on the target architecture.If the system uses + // segmented addressing, this value represents the size of the offset portion of an address. + ut8 address_size; + ut8 unit_type; // DWARF 5 addition + ut8 dwo_id; // DWARF 5 addition + ut64 type_sig; // DWARF 5 addition + ut64 type_offset; // DWARF 5 addition + ut64 header_size; // excluding length field + ut64 unit_offset; + bool is_64bit; } RBinDwarfCompUnitHdr; typedef struct { ut64 tag; ut64 abbrev_code; - size_t length; + size_t count; size_t capacity; RBinDwarfAttrValue *attr_values; -} RBinDwarfDIE; +} RBinDwarfDie; typedef struct { RBinDwarfCompUnitHdr hdr; ut64 offset; - size_t length; + size_t count; size_t capacity; - RBinDwarfDIE *dies; + RBinDwarfDie *dies; } RBinDwarfCompUnit; #define COMP_UNIT_CAPACITY 8 #define DEBUG_INFO_CAPACITY 8 typedef struct { - size_t length; + size_t count; size_t capacity; RBinDwarfCompUnit *comp_units; } RBinDwarfDebugInfo; @@ -667,15 +741,15 @@ typedef struct { ut64 tag; ut64 offset; ut8 has_children; - size_t length; + size_t count; size_t capacity; - RBinDwarfAttrSpec *specs; + RBinDwarfAttrDef *defs; } RBinDwarfAbbrevDecl; #define DEBUG_ABBREV_CAP 32 typedef struct { - size_t length; + size_t count; size_t capacity; RBinDwarfAbbrevDecl *decls; } RBinDwarfDebugAbbrev; @@ -727,11 +801,13 @@ typedef struct { typedef struct r_bin_t RBin; // forward declaration so I can keep the functions in this interface -R_API void r_bin_dwarf_free_debug_abbrev(RBinDwarfDebugAbbrev *da); -R_API int r_bin_dwarf_parse_info(RBinDwarfDebugAbbrev *da, RBin *a, int mode); -R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode); -R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode); R_API RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev(RBin *a, int mode); +R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode); +R_API RBinDwarfDebugInfo *r_bin_dwarf_parse_info(RBinDwarfDebugAbbrev *da, RBin *a, int mode); +R_API RList *r_bin_dwarf_parse_line(RBin *a, int mode); + +R_API void r_bin_dwarf_free_debug_info(RBinDwarfDebugInfo *inf); +R_API void r_bin_dwarf_free_debug_abbrev(RBinDwarfDebugAbbrev *da); #ifdef __cplusplus } diff --git a/test/db/cmd/cmd_flags b/test/db/cmd/cmd_flags index 96dc6b8ad3..c7daaa9624 100644 --- a/test/db/cmd/cmd_flags +++ b/test/db/cmd/cmd_flags @@ -431,7 +431,7 @@ pd 1 EOF EXPECT=<decls[i].tag, expected_tag, "Incorrect abbreviation tag") -#define check_abbrev_length(expected_length) \ - mu_assert_eq (da->decls[i].length, expected_length, "Incorrect abbreviation length") +#define check_abbrev_count(expected_count) \ + mu_assert_eq (da->decls[i].count, expected_count, "Incorrect abbreviation count") #define check_abbrev_children(expected_children) \ mu_assert_eq (da->decls[i].has_children, expected_children, "Incorrect children flag") #define check_abbrev_attr_name(expected_name) \ - mu_assert_eq (da->decls[i].specs[j].attr_name, expected_name, "Incorrect children flag"); + mu_assert_eq (da->decls[i].defs[j].attr_name, expected_name, "Incorrect children flag"); #define check_abbrev_attr_form(expected_form) \ - mu_assert_eq (da->decls[i].specs[j].attr_form, expected_form, "Incorrect children flag"); + mu_assert_eq (da->decls[i].defs[j].attr_form, expected_form, "Incorrect children flag"); /** * @brief Comparator to sort list of line statements by address(collection of DwarfRows) @@ -57,7 +57,7 @@ bool test_dwarf3_c_basic(void) { // this should work for dwarf2 aswell // static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) // which prints out all the abbreviation da = r_bin_dwarf_parse_abbrev (bin, MODE); - mu_assert_eq (da->length, 7, "Incorrect number of abbreviation"); + mu_assert_eq (da->count, 7, "Incorrect number of abbreviation"); // order matters // I nest scopes to make it more readable, (hopefully) @@ -65,7 +65,7 @@ bool test_dwarf3_c_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_compile_unit); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); { int j = 0; check_abbrev_attr_name (DW_AT_producer); @@ -93,45 +93,43 @@ bool test_dwarf3_c_basic(void) { // this should work for dwarf2 aswell i++; check_abbrev_tag (DW_TAG_variable); { - check_abbrev_length (8); + check_abbrev_count (8); check_abbrev_children (false); } i++; check_abbrev_tag (DW_TAG_base_type); { - check_abbrev_length (4); + check_abbrev_count (4); check_abbrev_children (false); } i++; check_abbrev_tag (DW_TAG_subprogram); { - check_abbrev_length (12); + check_abbrev_count (12); check_abbrev_children (true); } i++; check_abbrev_tag (DW_TAG_variable); { - check_abbrev_length (7); + check_abbrev_count (7); check_abbrev_children (false); } i++; check_abbrev_tag (DW_TAG_subprogram); { - check_abbrev_length (10); + check_abbrev_count (10); check_abbrev_children (true); } i++; check_abbrev_tag (DW_TAG_variable); { - check_abbrev_length (6); + check_abbrev_count (6); check_abbrev_children (false); } i++; - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 8, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 8, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -155,6 +153,9 @@ bool test_dwarf3_c_basic(void) { // this should work for dwarf2 aswell mu_assert_eq (row->address, test_addresses[i++], "Line number statement address doesn't match"); } + r_list_free (line_list); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); r_io_free (io); mu_end; } @@ -183,7 +184,7 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell // static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) // which prints out all the abbreviation da = r_bin_dwarf_parse_abbrev (bin, MODE); - mu_assert ("Incorrect number of abbreviation", da->length == 32); + mu_assert ("Incorrect number of abbreviation", da->count == 32); // order matters // I nest scopes to make it more readable, (hopefully) @@ -191,7 +192,7 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_compile_unit); { check_abbrev_children (true); - check_abbrev_length (9); + check_abbrev_count (9); { /** * Everything commented out is something that is missing from being printed by `id` Radare @@ -229,7 +230,7 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_structure_type); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); { /** * Everything commented out is something that is missing from being printed by `id` Radare @@ -264,31 +265,31 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); } i++; check_abbrev_tag (DW_TAG_formal_parameter); { check_abbrev_children (false); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_formal_parameter); { check_abbrev_children (false); - check_abbrev_length (2); + check_abbrev_count (2); } i++; check_abbrev_tag (DW_TAG_member); { check_abbrev_children (false); - check_abbrev_length (5); + check_abbrev_count (5); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (10); + check_abbrev_count (10); } i++; @@ -296,7 +297,7 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (12); + check_abbrev_count (12); { int j = 0; check_abbrev_attr_name (DW_AT_external); @@ -337,155 +338,153 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (13); + check_abbrev_count (13); } i++; check_abbrev_tag (DW_TAG_const_type); { check_abbrev_children (false); - check_abbrev_length (2); + check_abbrev_count (2); } i++; check_abbrev_tag (DW_TAG_pointer_type); { check_abbrev_children (false); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_reference_type); { check_abbrev_children (false); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_subroutine_type); { check_abbrev_children (true); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_unspecified_parameters); { check_abbrev_children (false); - check_abbrev_length (1); + check_abbrev_count (1); } i++; check_abbrev_tag (DW_TAG_base_type); { check_abbrev_children (false); - check_abbrev_length (4); + check_abbrev_count (4); } i++; check_abbrev_tag (DW_TAG_pointer_type); { check_abbrev_children (false); - check_abbrev_length (4); + check_abbrev_count (4); } i++; check_abbrev_tag (DW_TAG_structure_type); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); } i++; check_abbrev_tag (DW_TAG_inheritance); { check_abbrev_children (false); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (10); + check_abbrev_count (10); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (13); + check_abbrev_count (13); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (12); + check_abbrev_count (12); } i++; check_abbrev_tag (DW_TAG_variable); { check_abbrev_children (false); - check_abbrev_length (7); + check_abbrev_count (7); } i++; check_abbrev_tag (DW_TAG_variable); { check_abbrev_children (false); - check_abbrev_length (7); + check_abbrev_count (7); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); } i++; check_abbrev_tag (DW_TAG_formal_parameter); { check_abbrev_children (false); - check_abbrev_length (5); + check_abbrev_count (5); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (5); + check_abbrev_count (5); } i++; check_abbrev_tag (DW_TAG_formal_parameter); { check_abbrev_children (false); - check_abbrev_length (4); + check_abbrev_count (4); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (9); + check_abbrev_count (9); } i++; check_abbrev_tag (DW_TAG_formal_parameter); { check_abbrev_children (false); - check_abbrev_length (3); + check_abbrev_count (3); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (9); + check_abbrev_count (9); } i++; check_abbrev_tag (DW_TAG_subprogram); { check_abbrev_children (true); - check_abbrev_length (8); + check_abbrev_count (8); } // r_bin_dwarf_parse_info (da, core->bin, mode); Information not stored anywhere, not testable now? // r_bin_dwarf_parse_aranges (core->bin, MODE); Information not stored anywhere, not testable now? - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 60, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 60, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -563,6 +562,9 @@ bool test_dwarf3_cpp_basic(void) { // this should work for dwarf2 aswell mu_assert_eq (row->address, test_addresses[i++], "Line number statement address doesn't match"); } + r_list_free (line_list); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); r_io_free (io); mu_end; } @@ -580,23 +582,21 @@ bool test_dwarf3_cpp_many_comp_units(void) { // static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) // which prints out all the abbreviation da = r_bin_dwarf_parse_abbrev (bin, MODE); - mu_assert_eq (da->length, 58, "Incorrect number of abbreviation"); + mu_assert_eq (da->count, 58, "Incorrect number of abbreviation"); int i = 18; check_abbrev_tag (DW_TAG_formal_parameter); - check_abbrev_length (5); + check_abbrev_count (5); check_abbrev_children (false); check_abbrev_code (19); i = 41; check_abbrev_tag (DW_TAG_inheritance); - check_abbrev_length (3); + check_abbrev_count (3); check_abbrev_children (false); check_abbrev_code (18); - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 64, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 64, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -678,6 +678,9 @@ bool test_dwarf3_cpp_many_comp_units(void) { mu_assert_eq (row->address, test_addresses[i++], "Line number statement address doesn't match"); } + r_list_free (line_list); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); r_io_free (io); mu_end; } @@ -697,12 +700,10 @@ bool test_dwarf_cpp_empty_line_info(void) { // this should work for dwarf2 aswel // which prints out all the abbreviation da = r_bin_dwarf_parse_abbrev (bin, MODE); // not ignoring null entries -> 755 abbrevs - mu_assert_eq (da->length, 731, "Incorrect number of abbreviation"); + mu_assert_eq (da->count, 731, "Incorrect number of abbreviation"); - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 771, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 771, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -744,6 +745,8 @@ bool test_dwarf_cpp_empty_line_info(void) { // this should work for dwarf2 aswel break; } + r_list_free (line_list); + r_bin_dwarf_free_debug_abbrev (da); r_io_free (io); mu_end; } @@ -762,24 +765,22 @@ bool test_dwarf2_cpp_many_comp_units(void) { // static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) // which prints out all the abbreviation da = r_bin_dwarf_parse_abbrev (bin, MODE); - mu_assert_eq (da->length, 58, "Incorrect number of abbreviation"); + mu_assert_eq (da->count, 58, "Incorrect number of abbreviation"); int i = 18; check_abbrev_tag (DW_TAG_formal_parameter); - check_abbrev_length (5); + check_abbrev_count (5); check_abbrev_children (false); check_abbrev_code (19); i = 41; check_abbrev_tag (DW_TAG_inheritance); - check_abbrev_length (4); + check_abbrev_count (4); check_abbrev_children (false); check_abbrev_code (18); - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 64, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 64, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -859,6 +860,9 @@ bool test_dwarf2_cpp_many_comp_units(void) { } // add line information check + r_list_free (line_list); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); r_io_free (io); mu_end; } @@ -872,13 +876,10 @@ bool test_dwarf4_cpp_many_comp_units(void) { bool res = r_bin_open (bin, "bins/elf/dwarf4_many_comp_units.elf", &opt); mu_assert ("couldn't open file", res); - RBinDwarfDebugAbbrev *da = NULL; // TODO add abbrev checks - RList *line_list = NULL; - - line_list = r_bin_dwarf_parse_line (bin, MODE); - mu_assert_eq (line_list->length, 75, "Amount of line information parse doesn't match"); + RList *line_list = r_bin_dwarf_parse_line (bin, MODE); + mu_assert_eq (r_list_length (line_list), 75, "Amount of line information parse doesn't match"); RBinDwarfRow *row; RListIter *iter; @@ -968,6 +969,8 @@ bool test_dwarf4_cpp_many_comp_units(void) { mu_assert_eq (row->address, test_addresses[i++], "Line number statement address doesn't match"); } + r_list_free (line_list); + r_bin_free (bin); r_io_free (io); mu_end; } diff --git a/test/unit/test_dwarf_info.c b/test/unit/test_dwarf_info.c new file mode 100644 index 0000000000..6ac0d21b61 --- /dev/null +++ b/test/unit/test_dwarf_info.c @@ -0,0 +1,335 @@ +#include +#include "minunit.h" +#include +#include + +#define MODE 2 + + +#define check_attr_string(attr_idx, expect_string) \ + mu_assert_streq (cu.dies[i].attr_values[attr_idx].string.content, expect_string, "Wrong string attribute information") + +#define check_attr_name(attr_idx, expect_name) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].attr_name, expect_name, "Wrong attribute name") + +#define check_attr_address(attr_idx, expect_addr) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].address, expect_addr, "Wrong attribute name") + +#define check_attr_form(attr_idx, expect_form) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].attr_form, expect_form, "Wrong attribute name") + +#define check_attr_data(attr_idx, expect_data) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].data, expect_data, "Wrong attribute data") + +#define check_attr_block_length(attr_idx, expect_len) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].block.length, expect_len, "Wrong attribute block length") + +#define check_attr_block_data(attr_idx, data_idx, expect_data) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].block.data[data_idx], expect_data, "Wrong attribute block data") + +#define check_attr_reference(attr_idx, expect_ref) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].reference, expect_ref, "Wrong attribute reference") + +#define check_attr_flag(attr_idx, expect_flag) \ + mu_assert_eq (cu.dies[i].attr_values[attr_idx].flag, expect_flag, "Wrong attribute flag") + +#define check_die_abbr_code(expect_code) \ + mu_assert_eq (cu.dies[i].abbrev_code, expect_code, "Wrong abbrev code") + +#define check_die_length(len) \ + mu_assert_eq (cu.dies[i].count, len, "Wrong DIE length information") + +#define check_die_tag(tg) \ + mu_assert_eq (cu.dies[i].tag, tg, "Wrong DIE tag") + +#define check_basic_unit_header(vers, len, is64bit, addr_size, abbr_offset) \ + do { \ + mu_assert_eq (hdr.version, vers, "Wrong header version information"); \ + mu_assert_eq (hdr.length, len, "Wrong header length information"); \ + mu_assert_eq (hdr.is_64bit, is64bit, "Wrong header is_64bit information"); \ + mu_assert_eq (hdr.address_size, addr_size, "Wrong header address_size information"); \ + mu_assert_eq (hdr.abbrev_offset, abbr_offset, "Wrong header abbrev_offset information"); \ + } while (0) + +bool test_dwarf3_c(void) { + RBin *bin = r_bin_new (); + RIO *io = r_io_new (); + r_io_bind (io, &bin->iob); + + RBinOptions opt = { 0 }; + bool res = r_bin_open (bin, "bins/elf/dwarf3_c.elf", &opt); + mu_assert ("dwarf3_c.elf binary could not be opened", res); + + RBinDwarfDebugAbbrev *da = r_bin_dwarf_parse_abbrev (bin, MODE); + mu_assert_eq (da->count, 7, "Incorrect number of abbreviation"); + RBinDwarfDebugInfo *info = r_bin_dwarf_parse_info (da, bin, MODE); + mu_assert_eq (info->count, 1, "Incorrect number of info compilation units"); + + // check header + RBinDwarfCompUnit cu = info->comp_units[0]; + RBinDwarfCompUnitHdr hdr = cu.hdr; + + check_basic_unit_header (3, 0xa9, false, 8, 0x0); + + mu_assert_eq (cu.count, 11, "Wrong attribute information"); + mu_assert_eq (cu.offset, 0x0, "Wrong attribute information"); + // check some of the attributes + int i = 0; + check_die_abbr_code (1); + + check_die_length (7); + check_die_tag (DW_TAG_compile_unit); + + check_attr_name (0, DW_AT_producer); + check_attr_string (2, "main.c"); + i++; + check_die_abbr_code (2); + i++; + check_die_abbr_code (3); + i++; + check_die_abbr_code (4); + i++; + check_die_abbr_code (5); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (6); + i++; + check_die_abbr_code (7); + + check_attr_string (0, "b"); + check_attr_data (3, 15); + + i++; + check_die_abbr_code (7); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (0); + + r_bin_dwarf_free_debug_info (info); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); + r_io_free (io); + mu_end; +} + +bool test_dwarf4_cpp_multiple_modules(void) { + RBin *bin = r_bin_new (); + RIO *io = r_io_new (); + r_io_bind (io, &bin->iob); + + RBinOptions opt = { 0 }; + bool res = r_bin_open (bin, "bins/elf/dwarf4_many_comp_units.elf", &opt); + mu_assert ("dwarf4_many_comp_units.elf binary could not be opened", res); + + RBinDwarfDebugAbbrev *da = r_bin_dwarf_parse_abbrev (bin, MODE); + mu_assert_eq (da->count, 37, "Incorrect number of abbreviation"); + RBinDwarfDebugInfo *info = r_bin_dwarf_parse_info (da, bin, MODE); + mu_assert_notnull (info, "Failed parsing of debug_info"); + mu_assert_eq (info->count, 2, "Incorrect number of info compilation units"); + + // check header + RBinDwarfCompUnit cu = info->comp_units[0]; + RBinDwarfCompUnitHdr hdr = cu.hdr; + check_basic_unit_header (4, 0x2c0, false, 8, 0x0); + + // check some of the attributes + mu_assert_eq (cu.count, 73, "Wrong attribute information"); + mu_assert_eq (cu.offset, 0x0, "Wrong attribute information"); + + int i = 0; + check_die_abbr_code (1); + check_die_length (7); + check_die_tag (DW_TAG_compile_unit); + + check_attr_name (0, DW_AT_producer); + check_attr_string (2, "../main.cpp"); + check_attr_name (6, DW_AT_ranges); + check_attr_reference (6, 0x0); + + i++; + check_die_abbr_code (2); + i++; + check_die_abbr_code (3); + i++; + check_die_abbr_code (3); + i++; + check_die_abbr_code (3); + i++; + check_die_abbr_code (0); + i++; + // i == 6 + check_die_abbr_code (4); + check_attr_reference (0, 0x6e); + check_attr_data (1, 4); + check_attr_string (2, "Bird"); + check_attr_data (3, 8); + check_attr_data (4, 1); + check_attr_data (5, 9); + i++; + check_die_abbr_code (5); + check_die_tag (DW_TAG_member); + check_attr_string (0, "_vptr$Bird"); + check_attr_reference (1, 0xc5); + check_attr_data (2, 0); + check_attr_data (3, true); + + i++; + check_die_abbr_code (6); + i++; + check_die_abbr_code (7); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (8); + i++; + check_die_abbr_code (7); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (9); + check_die_tag (DW_TAG_subprogram); + check_die_length (10); + check_attr_string (0, "_ZN4Bird3flyEv"); + check_attr_string (1, "fly"); + check_attr_data (2, 1); + check_attr_data (3, 12); + check_attr_reference (4, 0xd8); + check_attr_name (6, DW_AT_vtable_elem_location); + check_attr_form (7, DW_FORM_flag_present); + check_attr_flag (7, true); + check_attr_name (8, DW_AT_external); + check_attr_flag (8, true); + check_attr_name (9, DW_AT_containing_type); + check_attr_reference (9, 0x6e); + i++; + check_die_abbr_code (7); + mu_assert_eq (cu.dies[i].abbrev_code, 7, "Wrong attribute information"); + i++; + check_die_abbr_code (0); + mu_assert_eq (cu.dies[i].abbrev_code, 0, "Wrong attribute information"); + i++; + check_die_abbr_code (0); + mu_assert_eq (cu.dies[i].abbrev_code, 0, "Wrong attribute information"); + i++; + check_die_abbr_code (10); + mu_assert_eq (cu.dies[i].abbrev_code, 10, "Wrong attribute information"); + i++; + check_die_abbr_code (11); + mu_assert_eq (cu.dies[i].abbrev_code, 11, "Wrong attribute information"); + i++; + check_die_abbr_code (12); + mu_assert_eq (cu.dies[i].abbrev_code, 12, "Wrong attribute information"); + i++; + check_die_abbr_code (13); + check_die_tag (DW_TAG_base_type); + check_die_length (3); + i++; + check_die_abbr_code (10); + i++; + check_die_abbr_code (14); + i++; + check_die_abbr_code (15); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (4); + i = 66; + check_die_abbr_code (18); + check_die_length (5); + check_attr_reference (3, 0x2a7); + i++; + check_die_abbr_code (15); + check_die_length (4); + check_attr_block_length (0, 2); + check_attr_block_data (0, 0, 0x91); + check_attr_block_data (0, 1, 0x78); + check_attr_string (1, "this"); + check_attr_reference (2, 0x2be); + check_attr_flag (3, true); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (10); + i++; + check_die_abbr_code (10); + check_die_tag (DW_TAG_pointer_type); + i++; + check_die_abbr_code (10); + i++; + check_die_abbr_code (0); + i++; + + cu = info->comp_units[1]; + hdr = cu.hdr; + check_basic_unit_header (4, 0x192, false, 8, 0xfd); + + // check some of the attributes + mu_assert_eq (cu.count, 42, "Wrong attribute information"); + mu_assert_eq (cu.offset, 0x2c4, "Wrong attribute information"); + + i = 0; + check_die_abbr_code (1); + check_die_length (7); + check_die_tag (DW_TAG_compile_unit); + check_attr_name (0, DW_AT_producer); + check_attr_string (0, "clang version 10.0.0-4ubuntu1 "); + check_attr_data (1, 33); + check_attr_string (2, "../mammal.cpp"); + check_attr_address (5, 0x0); + check_attr_form (5, DW_FORM_addr); + check_attr_name (6, DW_AT_ranges); + check_attr_reference (6, 0xb0); + i++; + check_die_abbr_code (2); + i++; + check_die_abbr_code (3); + i++; + check_die_abbr_code (4); + i++; + check_die_abbr_code (5); + i++; + check_die_abbr_code (0); + i++; + check_die_abbr_code (6); + i++; + check_die_abbr_code (5); + i++; + check_die_abbr_code (0); + i = 35; + check_die_abbr_code (8); + check_die_tag (DW_TAG_pointer_type); + check_die_length (1); + check_attr_form (0, DW_FORM_ref4); + check_attr_reference (0, 0x407); + i++; + check_die_abbr_code (19); + check_die_tag (DW_TAG_subprogram); + check_die_length (5); + check_attr_name (2, DW_AT_frame_base); + check_attr_block_length (2, 1); + check_attr_block_data (2, 0, 0x56); + check_attr_reference (3, 0x442); + check_attr_reference (4, 0x410); + i=40; + check_die_abbr_code (8); + i++; + check_die_abbr_code (0); + + r_bin_dwarf_free_debug_info (info); + r_bin_dwarf_free_debug_abbrev (da); + r_bin_free (bin); + r_io_free (io); + mu_end; +} + +bool all_tests() { + mu_run_test (test_dwarf3_c); + mu_run_test (test_dwarf4_cpp_multiple_modules); + return tests_passed != tests_run; +} + +int main(int argc, char **argv) { + return all_tests (); +}