/* radare - LGPL - Copyright 2012-2016 - pancake, Fedor Sakharov */ #define D0 if(1) #define D1 if(1) #include #define DWARF_DUMP 0 #if DWARF_DUMP #define DBGFD stdout #else #define DBGFD NULL #endif #include #include #include #define STANDARD_OPERAND_COUNT_DWARF2 9 #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) static const char *dwarf_tag_name_encodings[] = { [DW_TAG_array_type] = "DW_TAG_array_type", [DW_TAG_class_type] = "DW_TAG_class_type", [DW_TAG_entry_point] = "DW_TAG_entry_point", [DW_TAG_enumeration_type] = "DW_TAG_enumeration_type", [DW_TAG_formal_parameter] = "DW_TAG_formal_parameter", [DW_TAG_imported_declaration] = "DW_TAG_imported_declaration", [DW_TAG_label] = "DW_TAG_label", [DW_TAG_lexical_block] = "DW_TAG_lexical_block", [DW_TAG_member] = "DW_TAG_member", [DW_TAG_pointer_type] = "DW_TAG_pointer_type", [DW_TAG_reference_type] = "DW_TAG_reference_type", [DW_TAG_compile_unit] = "DW_TAG_compile_unit", [DW_TAG_string_type] = "DW_TAG_string_type", [DW_TAG_structure_type] = "DW_TAG_structure_type", [DW_TAG_subroutine_type] = "DW_TAG_subroutine_type", [DW_TAG_typedef] = "DW_TAG_typedef", [DW_TAG_union_type] = "DW_TAG_union_type", [DW_TAG_unspecified_parameters] = "DW_TAG_unspecified_parameters", [DW_TAG_variant] = "DW_TAG_variant", [DW_TAG_common_block] = "DW_TAG_common_block", [DW_TAG_common_inclusion] = "DW_TAG_common_inclusion", [DW_TAG_inheritance] = "DW_TAG_inheritance", [DW_TAG_inlined_subroutine] = "DW_TAG_inlined_subroutine", [DW_TAG_module] = "DW_TAG_module", [DW_TAG_ptr_to_member_type] = "DW_TAG_ptr_to_member_type", [DW_TAG_set_type] = "DW_TAG_set_type", [DW_TAG_subrange_type] = "DW_TAG_subrange_type", [DW_TAG_with_stmt] = "DW_TAG_with_stmt", [DW_TAG_access_declaration] = "DW_TAG_access_declaration", [DW_TAG_base_type] = "DW_TAG_base_type", [DW_TAG_catch_block] = "DW_TAG_catch_block", [DW_TAG_const_type] = "DW_TAG_const_type", [DW_TAG_constant] = "DW_TAG_constant", [DW_TAG_enumerator] = "DW_TAG_enumerator", [DW_TAG_file_type] = "DW_TAG_file_type", [DW_TAG_friend] = "DW_TAG_friend", [DW_TAG_namelist] = "DW_TAG_namelist", [DW_TAG_namelist_item] = "DW_TAG_namelist_item", [DW_TAG_packed_type] = "DW_TAG_packed_type", [DW_TAG_subprogram] = "DW_TAG_subprogram", [DW_TAG_template_type_param] = "DW_TAG_template_type_param", [DW_TAG_template_value_param] = "DW_TAG_template_value_param", [DW_TAG_template_alias] = "DW_TAG_template_alias", [DW_TAG_thrown_type] = "DW_TAG_thrown_type", [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" }; static const char *dwarf_attr_encodings[] = { [DW_AT_sibling] = "DW_AT_siblings", [DW_AT_location] = "DW_AT_location", [DW_AT_name] = "DW_AT_name", [DW_AT_ordering] = "DW_AT_ordering", [DW_AT_byte_size] = "DW_AT_byte_size", [DW_AT_bit_size] = "DW_AT_bit_size", [DW_AT_stmt_list] = "DW_AT_stmt_list", [DW_AT_low_pc] = "DW_AT_low_pc", [DW_AT_high_pc] = "DW_AT_high_pc", [DW_AT_language] = "DW_AT_language", [DW_AT_discr] = "DW_AT_discr", [DW_AT_discr_value] = "DW_AT_discr_value", [DW_AT_visibility] = "DW_AT_visibility", [DW_AT_import] = "DW_AT_import", [DW_AT_string_length] = "DW_AT_string_length", [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_default_value] = "DW_AT_default_value", [DW_AT_inline] = "DW_AT_inline", [DW_AT_is_optional] = "DW_AT_is_optional", [DW_AT_lower_bound] = "DW_AT_lower_bound", [DW_AT_producer] = "DW_AT_producer", [DW_AT_prototyped] = "DW_AT_prototyped", [DW_AT_return_addr] = "DW_AT_return_addr", [DW_AT_start_scope] = "DW_AT_start_scope", [DW_AT_stride_size] = "DW_AT_stride_size", [DW_AT_upper_bound] = "DW_AT_upper_bound", [DW_AT_abstract_origin] = "DW_AT_abstract_origin", [DW_AT_accessibility] = "DW_AT_accessibility", [DW_AT_address_class] = "DW_AT_address_class", [DW_AT_artificial] = "DW_AT_artificial", [DW_AT_base_types] = "DW_AT_base_types", [DW_AT_calling_convention] = "DW_AT_calling_convention", [DW_AT_count] = "DW_AT_count", [DW_AT_data_member_location] = "DW_AT_data_member_location", [DW_AT_decl_column] = "DW_AT_decl_column", [DW_AT_decl_file] = "DW_AT_decl_file", [DW_AT_decl_line] = "DW_AT_decl_line", [DW_AT_declaration] = "DW_AT_declaration", [DW_AT_discr_list] = "DW_AT_discr_list", [DW_AT_encoding] = "DW_AT_encoding", [DW_AT_external] = "DW_AT_external", [DW_AT_frame_base] = "DW_AT_frame_base", [DW_AT_friend] = "DW_AT_friend", [DW_AT_identifier_case] = "DW_AT_identifier_case", [DW_AT_macro_info] = "DW_AT_macro_info", [DW_AT_namelist_item] = "DW_AT_namelist_item", [DW_AT_priority] = "DW_AT_priority", [DW_AT_segment] = "DW_AT_segment", [DW_AT_specification] = "DW_AT_specification", [DW_AT_static_link] = "DW_AT_static_link", [DW_AT_type] = "DW_AT_type", [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" }; static const char *dwarf_attr_form_encodings[] = { [DW_FORM_addr] = "DW_FORM_addr", [DW_FORM_block2] = "DW_FORM_block2", [DW_FORM_block4] = "DW_FORM_block4", [DW_FORM_data2] = "DW_FORM_data2", [DW_FORM_data4] = "DW_FORM_data4", [DW_FORM_data8] = "DW_FORM_data8", [DW_FORM_string] = "DW_FORM_string", [DW_FORM_block] = "DW_FORM_block", [DW_FORM_block1] = "DW_FORM_block1", [DW_FORM_data1] = "DW_FORM_data1", [DW_FORM_flag] = "DW_FORM_flag", [DW_FORM_sdata] = "DW_FORM_sdata", [DW_FORM_strp] = "DW_FORM_strp", [DW_FORM_udata] = "DW_FORM_udata", [DW_FORM_ref_addr] = "DW_FORM_ref_addr", [DW_FORM_ref1] = "DW_FORM_ref1", [DW_FORM_ref2] = "DW_FORM_ref2", [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" }; static const char *dwarf_langs[] = { [DW_LANG_C89] = "C89", [DW_LANG_C] = "C", [DW_LANG_Ada83] = "Ada83", [DW_LANG_C_plus_plus] = "C++", [DW_LANG_Cobol74] = "Cobol74", [DW_LANG_Cobol85] = "Cobol85", [DW_LANG_Fortran77] = "Fortran77", [DW_LANG_Fortran90] = "Fortran90", [DW_LANG_Pascal83] = "Pascal83", [DW_LANG_Modula2] = "Modula2", [DW_LANG_Java] = "Java", [DW_LANG_C99] = "C99", [DW_LANG_Ada95] = "Ada95", [DW_LANG_Fortran95] = "Fortran95", [DW_LANG_PLI] = "PLI", [DW_LANG_ObjC] = "ObjC", [DW_LANG_ObjC_plus_plus] = "ObjC_plus_plus", [DW_LANG_UPC] = "UPC", [DW_LANG_D] = "D", [DW_LANG_Python] = "Python", [DW_LANG_Rust] = "Rust", [DW_LANG_C11] = "C11", [DW_LANG_Swift] = "Swift", [DW_LANG_Julia] = "Julia", [DW_LANG_Dylan] = "Dylan", [DW_LANG_C_plus_plus_14] = "C++14", [DW_LANG_Fortran03] = "Fortran03", [DW_LANG_Fortran08] = "Fortran08" }; static int add_sdb_include_dir(Sdb *s, const char *incl, int idx) { if (!s || !incl) return false; return sdb_array_set (s, "includedirs", idx, incl, 0); } static const ut8 *r_bin_dwarf_parse_lnp_header ( RBinFile *bf, const ut8 *buf, const ut8 *buf_end, RBinDwarfLNPHeader *hdr, FILE *f, int mode) { int i; Sdb *s; size_t count; const ut8 *tmp_buf = NULL; if (!hdr || !bf || !buf) return NULL; hdr->unit_length.part1 = READ (buf, ut32); if (hdr->unit_length.part1 == DWARF_INIT_LEN_64) { hdr->unit_length.part2 = READ (buf, ut32); } s = sdb_new (NULL, NULL, 0); hdr->version = READ (buf, ut16); if (hdr->unit_length.part1 == DWARF_INIT_LEN_64) { hdr->header_length = READ (buf, ut64); } else { hdr->header_length = READ (buf, ut32); } if (buf_end-buf < 8) { sdb_free (s); return NULL; } hdr->min_inst_len = READ (buf, ut8); //hdr->max_ops_per_inst = READ (buf, ut8); hdr->file_names = NULL; hdr->default_is_stmt = READ (buf, ut8); hdr->line_base = READ (buf, char); hdr->line_range = READ (buf, ut8); hdr->opcode_base = READ (buf, ut8); if (f) { fprintf(f, "DWARF LINE HEADER\n"); fprintf(f, " total_length: %d\n", hdr->unit_length.part1); fprintf(f, " version: %d\n", hdr->version); fprintf(f, " header_length: : %"PFMT64d"\n", hdr->header_length); fprintf(f, " mininstlen: %d\n", hdr->min_inst_len); fprintf(f, " 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); } if (hdr->opcode_base>0) { hdr->std_opcode_lengths = calloc(sizeof(ut8), hdr->opcode_base); for (i = 1; i <= hdr->opcode_base - 1; i++) { if (buf+2>buf_end) break; hdr->std_opcode_lengths[i] = READ (buf, ut8); if (f) { fprintf(f, " op %d %d\n", i, hdr->std_opcode_lengths[i]); } } } else { hdr->std_opcode_lengths = NULL; } i = 0; while (buf+1 < buf_end) { int maxlen = R_MIN ((size_t)(buf_end-buf)-1, 0xfff); int len = r_str_nlen ((const char*)buf, maxlen); char *str = r_str_ndup ((const char *)buf, len); if (len<1 || len >= 0xfff) { buf += 1; free (str); break; } if (*str != '/' && *str != '.') { // no more paths in here free (str); break; } if (f) { fprintf (f, "INCLUDEDIR (%s)\n", str); } add_sdb_include_dir (s, str, i); free (str); i++; buf += len + 1; } tmp_buf = buf; count = 0; for (i = 0; i < 2; i++) { while (buf+1=buf_end) { buf = NULL; goto beach; } buf = r_uleb128 (buf, buf_end-buf, &id_idx); if (buf>=buf_end) { buf = NULL; goto beach; } buf = r_uleb128 (buf, buf_end-buf, &mod_time); if (buf>=buf_end) { buf = NULL; goto beach; } buf = r_uleb128 (buf, buf_end-buf, &file_len); if (buf>=buf_end) { buf = NULL; goto beach; } if (i) { char *include_dir = NULL, *comp_dir = NULL; char *allocated_id = NULL; if (id_idx > 0) { include_dir = sdb_array_get (s, "includedirs", id_idx - 1, 0); if (include_dir && include_dir[0] != '/') { comp_dir = sdb_get (bf->sdb_addrinfo, "DW_AT_comp_dir", 0); if (comp_dir) { allocated_id = calloc (1, strlen (comp_dir) + strlen (include_dir) + 8); snprintf (allocated_id, strlen (comp_dir) + strlen (include_dir) + 8, "%s/%s/", comp_dir, include_dir); include_dir = allocated_id; } } } else { include_dir = sdb_get (bf->sdb_addrinfo, "DW_AT_comp_dir", 0); if (!include_dir) include_dir = "./"; } namelen = len + (include_dir?strlen (include_dir):0) + 8; if (hdr->file_names) { hdr->file_names[count].name = calloc (sizeof(char), namelen); snprintf (hdr->file_names[count].name, namelen - 1, "%s/%s", include_dir? include_dir : "", filename); hdr->file_names[count].name[namelen - 1] = '\0'; free (allocated_id); hdr->file_names[count].id_idx = id_idx; hdr->file_names[count].mod_time = mod_time; hdr->file_names[count].file_len = file_len; } } count++; if (f && i) { fprintf (f, "FILE (%s)\n", filename); fprintf (f, "| dir idx %"PFMT64d"\n", id_idx); fprintf (f, "| lastmod %"PFMT64d"\n", mod_time); fprintf (f, "| filelen %"PFMT64d"\n", file_len); } } if (i == 0) { if (count>0) { hdr->file_names = calloc(sizeof(file_entry), count); } else { hdr->file_names = NULL; } hdr->file_names_count = count; buf = tmp_buf; count = 0; } } beach: sdb_free (s); return buf; } static inline void add_sdb_addrline(Sdb *s, ut64 addr, const char *file, ut64 line, FILE *f, int mode) { const char *p; char *fileline; char offset[64]; char *offset_ptr; if (!s || !file) return; p = r_str_rchr (file, NULL, '/'); if (p) { p++; } else { p = file; } // includedirs and properly check full paths switch (mode) { case 1: case 'r': case '*': if (!f) { f = stdout; } fprintf (f, "CL %s:%d 0x%08"PFMT64x"\n", p, (int)line, addr); break; } #if 0 /* THIS IS TOO SLOW */ if (r_file_exists (file)) { p = file; } #else p = file; #endif fileline = r_str_newf ("%s|%"PFMT64d, p, line); offset_ptr = sdb_itoa (addr, offset, 16); sdb_add (s, offset_ptr, fileline, 0); sdb_add (s, fileline, offset_ptr, 0); free (fileline); } static const ut8* r_bin_dwarf_parse_ext_opcode(const RBin *a, const ut8 *obuf, size_t len, const RBinDwarfLNPHeader *hdr, RBinDwarfSMRegisters *regs, FILE *f, int mode) { // XXX - list is an unused parameter. const ut8 *buf; const ut8 *buf_end; ut8 opcode; ut64 addr; buf = obuf; st64 op_len; RBinFile *binfile = a ? a->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; if (!binfile || !obuf || !hdr || !regs) return NULL; buf = r_leb128 (buf, &op_len); buf_end = buf+len; opcode = *buf++; if (f) { fprintf (f, "Extended opcode %d: ", opcode); } switch (opcode) { case DW_LNE_end_sequence: regs->end_sequence = DWARF_TRUE; if (binfile && binfile->sdb_addrinfo && hdr->file_names) { 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); } } if (f) { fprintf(f, "End of Sequence\n"); } break; case DW_LNE_set_address: if (addr_size == 8) { addr = READ (buf, ut64); } else { addr = READ (buf, ut32); } regs->address = addr; if (f) { fprintf(f, "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); } buf += (strlen (filename) + 1); ut64 dir_idx; if (buf+1 < buf_end) buf = r_uleb128 (buf, ST32_MAX, &dir_idx); break; case DW_LNE_set_discriminator: buf = r_uleb128(buf, ST32_MAX, &addr); if (f) { fprintf(f, "set Discriminator to %"PFMT64d"\n", addr); } regs->discriminator = addr; break; default: if (f) { fprintf(f, "Unexpeced opcode %d\n", opcode); } break; } return buf; } static const ut8* r_bin_dwarf_parse_spec_opcode( const RBin *a, const ut8 *obuf, size_t len, const RBinDwarfLNPHeader *hdr, RBinDwarfSMRegisters *regs, ut8 opcode, FILE *f, int mode) { // XXX - list is not used const ut8 *buf = obuf; ut8 adj_opcode = 0; ut64 advance_adr; RBinFile *binfile = a ? a->cur : NULL; if (!obuf || !hdr || !regs) { return NULL; } adj_opcode = opcode - hdr->opcode_base; if (!hdr->line_range) { // line line-range information. move away return NULL; } advance_adr = adj_opcode / hdr->line_range; regs->address += advance_adr; regs->line += hdr->line_base + (adj_opcode % hdr->line_range); if (f) { fprintf (f, "Special opcode %d: ", adj_opcode); fprintf (f, "advance Address by %"PFMT64d" to %"PFMT64x" and Line by %d to %"PFMT64d"\n", advance_adr, regs->address, hdr->line_base + (adj_opcode % hdr->line_range), regs->line); } if (binfile && binfile->sdb_addrinfo && hdr->file_names) { int idx = regs->file -1; 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->basic_block = DWARF_FALSE; regs->prologue_end = DWARF_FALSE; regs->epilogue_begin = DWARF_FALSE; regs->discriminator = 0; return buf; } static const ut8* r_bin_dwarf_parse_std_opcode( const RBin *a, const ut8 *obuf, size_t len, const RBinDwarfLNPHeader *hdr, RBinDwarfSMRegisters *regs, ut8 opcode, FILE *f, int mode) { const ut8* buf = obuf; const ut8* buf_end = obuf + len; ut64 addr = 0LL; st64 sbuf; ut8 adj_opcode; ut64 op_advance; ut16 operand; RBinFile *binfile = a ? a->cur : NULL; if (!binfile || !hdr || !regs || !obuf) { return NULL; } switch (opcode) { case DW_LNS_copy: if (f) { fprintf (f, "Copy\n"); } if (binfile && binfile->sdb_addrinfo && hdr->file_names) { 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); } } regs->basic_block = DWARF_FALSE; break; case DW_LNS_advance_pc: buf = r_uleb128 (buf, ST32_MAX, &addr); regs->address += addr * hdr->min_inst_len; if (f) { fprintf (f, "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, &sbuf); regs->line += sbuf; if (f) { fprintf(f, "Advance line by %"PFMT64d", to %"PFMT64d"\n", sbuf, regs->line); } break; case DW_LNS_set_file: buf = r_uleb128 (buf, ST32_MAX, &addr); if (f) { fprintf(f, "Set file to %"PFMT64d"\n", addr); } regs->file = addr; break; case DW_LNS_set_column: buf = r_uleb128(buf, ST32_MAX, &addr); if (f) { fprintf(f, "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); } break; case DW_LNS_set_basic_block: if (f) { fprintf(f, "set_basic_block\n"); } regs->basic_block = DWARF_TRUE; break; case DW_LNS_const_add_pc: adj_opcode = 255 - hdr->opcode_base; if (hdr->line_range > 0) { op_advance = adj_opcode / hdr->line_range; } else { op_advance = 0; } regs->address += op_advance; if (f) { fprintf(f, "Advance PC by constant %"PFMT64d" to 0x%"PFMT64x"\n", op_advance, regs->address); } break; case DW_LNS_fixed_advance_pc: operand = READ (buf, ut16); regs->address += operand; if (f) { fprintf(f,"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"); } break; case DW_LNS_set_epilogue_begin: regs->epilogue_begin = ~0; if (f) { fprintf(f, "set_epilogue_begin\n"); } break; case DW_LNS_set_isa: buf = r_uleb128 (buf, ST32_MAX, &addr); regs->isa = addr; if (f) { fprintf(f, "set_isa\n"); } break; default: if (f) { fprintf(f, "Unexpected opcode\n"); } break; } return buf; } static const ut8* r_bin_dwarf_parse_opcodes(const RBin *a, const ut8 *obuf, size_t len, const RBinDwarfLNPHeader *hdr, RBinDwarfSMRegisters *regs, FILE *f, int mode) { const ut8 *buf, *buf_end; ut8 opcode, ext_opcode; if (!a || !obuf || len < 8) { return NULL; } buf = obuf; buf_end = obuf + len; while (buf && buf + 1 < buf_end) { opcode = *buf++; len--; if (!opcode) { ext_opcode = *buf; buf = r_bin_dwarf_parse_ext_opcode (a, buf, len, hdr, regs, f, mode); if (ext_opcode == DW_LNE_end_sequence) { break; } } else if (opcode >= hdr->opcode_base) { buf = r_bin_dwarf_parse_spec_opcode (a, buf, len, hdr, regs, opcode, f, mode); } else { buf = r_bin_dwarf_parse_std_opcode (a, buf, len, hdr, regs, opcode, f, mode); } len = (int)(buf_end - buf); } return buf; } static void r_bin_dwarf_set_regs_default (const RBinDwarfLNPHeader *hdr, RBinDwarfSMRegisters *regs) { regs->address = 0; regs->file = 1; regs->line = 1; regs->column = 0; regs->is_stmt = hdr->default_is_stmt; regs->basic_block = DWARF_FALSE; regs->end_sequence = DWARF_FALSE; } R_API int r_bin_dwarf_parse_line_raw2(const RBin *a, const ut8 *obuf, size_t len, int mode) { RBinDwarfLNPHeader hdr = {{0}}; const ut8 *buf = NULL, *buf_tmp = NULL, *buf_end = NULL; RBinDwarfSMRegisters regs; int tmplen; FILE *f = NULL; RBinFile *binfile = a ? a->cur : NULL; if (!binfile || !obuf) { return false; } if (mode == R_CORE_BIN_PRINT) { f = stdout; } buf = obuf; buf_end = obuf + len; while (buf + 1 < buf_end) { buf_tmp = buf; buf = r_bin_dwarf_parse_lnp_header (a->cur, buf, buf_end, &hdr, f, mode); if (!buf) { return false; } r_bin_dwarf_set_regs_default (&hdr, ®s); tmplen = (int)(buf_end - buf); tmplen = R_MIN (tmplen, 4 + hdr.unit_length.part1); if (tmplen < 1) { break; } if (!r_bin_dwarf_parse_opcodes (a, buf, tmplen, &hdr, ®s, f, mode)) { break; } buf = buf_tmp + tmplen; len = (int)(buf_end - buf); } return true; } #define READ_BUF(x,y) if (idx+sizeof(y)>=len) { return false;} \ x=*(y*)buf; idx+=sizeof(y);buf+=sizeof(y) R_API int r_bin_dwarf_parse_aranges_raw(const ut8 *obuf, int len, FILE *f) { ut32 length, offset; ut16 version; ut32 debug_info_offset; ut8 address_size, segment_size; const ut8 *buf = obuf; int idx = 0; if (!buf || len< 4) { return false; } READ_BUF (length, ut32); if (f) { printf("parse_aranges\n"); printf("length 0x%x\n", length); } if (idx+12>=len) return false; READ_BUF (version, ut16); if (f) printf("Version %d\n", version); READ_BUF (debug_info_offset, ut32); if (f) fprintf(f, "Debug info offset %d\n", debug_info_offset); READ_BUF (address_size, ut8); if (f) fprintf(f, "address size %d\n", (int)address_size); READ_BUF (segment_size, ut8); if (f) fprintf(f, "segment size %d\n", (int)segment_size); offset = segment_size + address_size * 2; if (offset) { ut64 n = (((ut64) (size_t)buf / offset) + 1) * offset - ((ut64)(size_t)buf); if (idx+n>=len) return false; buf += n; idx += n; } while ((buf - obuf) < len) { ut64 adr, length; if ((idx+8)>=len) break; READ_BUF (adr, ut64); READ_BUF (length, ut64); if (f) printf("length 0x%"PFMT64x" address 0x%"PFMT64x"\n", length, adr); } return 0; } static int r_bin_dwarf_init_debug_info(RBinDwarfDebugInfo *inf) { if (!inf) return -1; inf->comp_units = calloc (sizeof(RBinDwarfCompUnit), DEBUG_INFO_CAPACITY); // XXX - should we be using error codes? if (!inf->comp_units) return -ENOMEM; inf->capacity = DEBUG_INFO_CAPACITY; inf->length = 0; return true; } static int r_bin_dwarf_init_die(RBinDwarfDIE *die) { if (!die) return -EINVAL; die->attr_values = calloc (sizeof (RBinDwarfAttrValue), 8); if (!die->attr_values) { return -ENOMEM; } die->capacity = 8; die->length = 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; } die->attr_values = tmp; die->capacity *= 2; return 0; } static int r_bin_dwarf_init_comp_unit(RBinDwarfCompUnit *cu) { if (!cu) { return -EINVAL; } cu->dies = calloc (sizeof (RBinDwarfDIE), COMP_UNIT_CAPACITY); if (!cu->dies) { return -ENOMEM; } cu->capacity = COMP_UNIT_CAPACITY; cu->length = 0; return 0; } static int r_bin_dwarf_expand_cu(RBinDwarfCompUnit *cu) { RBinDwarfDIE *tmp; if (!cu || cu->capacity == 0 || cu->capacity != cu->length) return -EINVAL; tmp = (RBinDwarfDIE*)realloc(cu->dies, cu->capacity * 2 * sizeof(RBinDwarfDIE)); if (!tmp) return -ENOMEM; cu->dies = tmp; cu->capacity *= 2; return 0; } static int r_bin_dwarf_init_abbrev_decl(RBinDwarfAbbrevDecl *ad) { if (!ad) return -EINVAL; ad->specs = calloc(sizeof(RBinDwarfAttrSpec), ABBREV_DECL_CAP); if (!ad->specs) return -ENOMEM; ad->capacity = ABBREV_DECL_CAP; ad->length = 0; return 0; } static int r_bin_dwarf_expand_abbrev_decl(RBinDwarfAbbrevDecl *ad) { RBinDwarfAttrSpec *tmp; if (!ad || ad->capacity==0 || ad->capacity != ad->length) return -EINVAL; tmp = (RBinDwarfAttrSpec*)realloc(ad->specs, ad->capacity * 2 * sizeof(RBinDwarfAttrSpec)); if (!tmp) return -ENOMEM; ad->specs = tmp; ad->capacity *= 2; return 0; } static int r_bin_dwarf_init_debug_abbrev(RBinDwarfDebugAbbrev *da) { if (!da) return -EINVAL; da->decls = calloc (sizeof (RBinDwarfAbbrevDecl), DEBUG_ABBREV_CAP); if (!da->decls) { return -ENOMEM; } da->capacity = DEBUG_ABBREV_CAP; da->length = 0; return 0; } static int r_bin_dwarf_expand_debug_abbrev(RBinDwarfDebugAbbrev *da) { RBinDwarfAbbrevDecl *tmp; if (!da || da->capacity == 0 || da->capacity != da->length) return -EINVAL; tmp = (RBinDwarfAbbrevDecl*)realloc (da->decls, da->capacity * 2 * sizeof (RBinDwarfAbbrevDecl)); if (!tmp) return -ENOMEM; da->decls = tmp; da->capacity *= 2; return 0; } static void dump_r_bin_dwarf_debug_abbrev(FILE *f, RBinDwarfDebugAbbrev *da) { size_t i, j; ut64 attr_name, attr_form; if (!f || !da) return; for (i = 0; i < da->length; i++) { int declstag = da->decls[i].tag; fprintf(f, "Abbreviation Code %"PFMT64d" ", da->decls[i].code); if (declstag>=0 && declstag < DW_TAG_LAST) fprintf(f, "Tag %s ", dwarf_tag_name_encodings[declstag]); fprintf(f, "[%s]\n", da->decls[i].has_children ? "has children" : "no children"); fprintf(f, "Offset 0x%"PFMT64x"\n", da->decls[i].offset); 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", dwarf_attr_encodings[attr_name], dwarf_attr_form_encodings[attr_form]); } } } } R_API void r_bin_dwarf_free_debug_abbrev(RBinDwarfDebugAbbrev *da) { size_t i; if (!da) return; for (i = 0; i < da->length; i++) { R_FREE (da->decls[i].specs); } R_FREE (da->decls); } static void r_bin_dwarf_free_attr_value(RBinDwarfAttrValue *val) { if (!val) return; switch (val->form) { case DW_FORM_strp: case DW_FORM_string: R_FREE (val->encoding.str_struct.string); break; case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: R_FREE (val->encoding.block.data); break; default: break; }; } static void r_bin_dwarf_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]); } R_FREE (die->attr_values); } static void r_bin_dwarf_free_comp_unit (RBinDwarfCompUnit *cu) { size_t i; if (!cu) return; for (i = 0; i < cu->length; i++) { r_bin_dwarf_free_die (&cu->dies[i]); } R_FREE (cu->dies); } static 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]); } R_FREE (inf->comp_units); } static void r_bin_dwarf_dump_attr_value(const RBinDwarfAttrValue *val, FILE *f) { size_t i; if (!val || !f) return; switch (val->form) { case DW_FORM_addr: fprintf(f, "0x%"PFMT64x"", val->encoding.address); break; 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]); } 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]); } break; case DW_FORM_strp: fprintf (f, "(indirect string, offset: 0x%"PFMT64x"): ", val->encoding.str_struct.offset); case DW_FORM_string: if (val->encoding.str_struct.string) { fprintf (f, "%s", val->encoding.str_struct.string); } else { fprintf (f, "No string found"); } break; case DW_FORM_flag: fprintf (f, "%u", val->encoding.flag); break; case DW_FORM_sdata: fprintf (f, "%"PFMT64d"", val->encoding.sdata); break; case DW_FORM_udata: fprintf (f, "%"PFMT64u"", val->encoding.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); break; default: fprintf (f, "Unknown attr value form %"PFMT64d"\n", val->form); }; } static void r_bin_dwarf_dump_debug_info(FILE *f, const RBinDwarfDebugInfo *inf) { size_t i, j, k; 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); 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); 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]); } else { fprintf(f, "(Unknown abbrev tag)\n"); } if (!dies[j].abbrev_code) continue; values = dies[j].attr_values; for (k = 0; k < dies[j].length; k++) { if (!values[k].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]); } else { fprintf(f, " TODO\t"); } r_bin_dwarf_dump_attr_value (&values[k], f); fprintf(f, "\n"); } } } } static const ut8 *r_bin_dwarf_parse_attr_value(const ut8 *obuf, int obuf_len, RBinDwarfAttrSpec *spec, 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 (value && spec) { value->form = spec->attr_form; value->name = spec->attr_name; value->encoding.block.data = NULL; value->encoding.str_struct.string = NULL; } if (!spec || !value || !hdr || !obuf || obuf_len < 0) { return NULL; } switch (spec->attr_form) { case DW_FORM_addr: switch (hdr->pointer_size) { case 1: value->encoding.address = READ (buf, ut8); break; case 2: value->encoding.address = READ (buf, ut16); break; case 4: value->encoding.address = READ (buf, ut32); break; case 8: value->encoding.address = READ (buf, ut64); break; default: eprintf("DWARF: Unexpected pointer size: %u\n", (unsigned)hdr->pointer_size); return NULL; } break; case DW_FORM_block2: value->encoding.block.length = READ (buf, ut16); 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); } } break; case DW_FORM_block4: value->encoding.block.length = READ (buf, ut32); 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->encoding.block.data = data; } break; case DW_FORM_data2: value->encoding.data = READ (buf, ut16); break; case DW_FORM_data4: value->encoding.data = READ (buf, ut32); break; case DW_FORM_data8: value->encoding.data = READ (buf, ut64); 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); if (!buf) { return NULL; } 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); } break; case DW_FORM_block1: value->encoding.block.length = READ (buf, ut8); value->encoding.block.data = calloc (sizeof (ut8), value->encoding.block.length + 1); for (j = 0; j < value->encoding.block.length; j++) { value->encoding.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, &value->encoding.sdata); break; case DW_FORM_strp: value->encoding.str_struct.offset = READ (buf, ut32); 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)); } else { value->encoding.str_struct.string = NULL; } break; case DW_FORM_udata: buf = r_uleb128 (buf, buf_end - buf, &value->encoding.data); break; case DW_FORM_ref_addr: value->encoding.reference = READ (buf, ut64); // addr size of machine break; case DW_FORM_ref1: value->encoding.reference = READ (buf, ut8); break; case DW_FORM_ref2: value->encoding.reference = READ (buf, ut16); break; case DW_FORM_ref4: value->encoding.reference = READ (buf, ut32); break; case DW_FORM_ref8: value->encoding.reference = READ (buf, ut64); break; case DW_FORM_data1: value->encoding.data = READ (buf, ut8); break; default: return buf; } 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; size_t 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 = r_uleb128 (buf, buf_end - buf, &abbr_code); if (abbr_code > da->length || !buf) { return NULL; } r_bin_dwarf_init_die (&cu->dies[cu->length]); if (!abbr_code) { cu->dies[cu->length].abbrev_code = 0; cu->length++; buf++; continue; } cu->dies[cu->length].abbrev_code = abbr_code; cu->dies[cu->length].tag = da->decls[abbr_code - 1].tag; abbr_code += offset; if (da->capacity < abbr_code) { 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; } 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) { // ut64 comp_dir = (ut64)(size_t)cu->dies[cu->length].attr_values[i].encoding.str_struct.string; // sdb_num_add (s, "DW_AT_comp_dir", comp_dir, 0); sdb_set (s, "DW_AT_comp_dir", cu->dies[cu->length].attr_values[i].encoding.str_struct.string, 0); } cu->dies[cu->length].length++; } cu->length++; } return buf; } R_API int r_bin_dwarf_parse_info_raw(Sdb *s, 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 curr_unit = 0, k, offset = 0; RBinDwarfDebugInfo *inf = NULL, di; inf = &di; if (!da || !s || !obuf) return false; r_bin_dwarf_init_debug_info (inf); while (buf < buf_end) { if (inf->length >= inf->capacity) break; r_bin_dwarf_init_comp_unit (&inf->comp_units[curr_unit]); inf->comp_units[curr_unit].offset = buf - obuf; inf->comp_units[curr_unit].hdr.length = READ (buf, ut32); inf->comp_units[curr_unit].hdr.version = READ (buf, ut16); 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); return -1; } if (inf->comp_units[curr_unit].hdr.length > len) { return -1; } inf->comp_units[curr_unit].hdr.abbrev_offset = READ (buf, ut32); 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; break; } } buf = r_bin_dwarf_parse_comp_unit(s, buf, &inf->comp_units[curr_unit], da, offset, debug_str, debug_str_len); if (!buf) { r_bin_dwarf_free_debug_info (inf); return false; } curr_unit++; } if (mode == R_CORE_BIN_PRINT) { r_bin_dwarf_dump_debug_info (NULL, inf); } r_bin_dwarf_free_debug_info (inf); return true; } static RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev_raw(const ut8 *obuf, size_t len, int mode) { const ut8 *buf = obuf, *buf_end = obuf + len; ut64 tmp, spec1, spec2, offset; ut8 has_children; RBinDwarfAbbrevDecl *tmpdecl; RBinDwarfDebugAbbrev *da = NULL; // XXX - Set a suitable value here. if (!obuf || len < 3) return da; da = R_NEW0(RBinDwarfDebugAbbrev); r_bin_dwarf_init_debug_abbrev (da); while (buf && buf+1 < buf_end) { offset = buf - obuf; buf = r_uleb128 (buf, (size_t)(buf_end-buf), &tmp); if (!buf || !tmp) continue; if (da->length == da->capacity) r_bin_dwarf_expand_debug_abbrev(da); tmpdecl = &da->decls[da->length]; r_bin_dwarf_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; has_children = READ (buf, ut8); tmpdecl->has_children = has_children; do { if (tmpdecl->length == tmpdecl->capacity) r_bin_dwarf_expand_abbrev_decl(tmpdecl); buf = r_uleb128(buf, (size_t)(buf_end-buf), &spec1); 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); da->length++; } if (mode == R_CORE_BIN_PRINT) dump_r_bin_dwarf_debug_abbrev(stdout, da); return da; } RBinSection *getsection(RBin *a, const char *sn) { RListIter *iter; RBinSection *section = NULL; RBinFile *binfile = a ? a->cur: NULL; RBinObject *o = binfile ? binfile->o : NULL; if ( o && o->sections) { r_list_foreach (o->sections, iter, section) { if (strstr (section->name, sn)) { return section; } } } 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; RBinSection *debug_str; RBinSection *section = getsection (a, "debug_info"); RBinFile *binfile = a ? a->cur: NULL; if (binfile && section) { debug_str = getsection (a, "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 (!ret) { free (debug_str_buf); return false; } } len = section->size; if (len > (UT32_MAX >> 1) || len < 1) { free (debug_str_buf); return false; } buf = calloc (1, len); ret = r_buf_read_at (binfile->buf, section->paddr, buf, len); if (!ret) { free (debug_str_buf); free (buf); return false; } 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); free (buf); return ret; } return false; } static RBinDwarfRow *r_bin_dwarf_row_new (ut64 addr, const char *file, int line, int col) { RBinDwarfRow *row = R_NEW0 (RBinDwarfRow); if (!row) return NULL; row->file = strdup (file); row->address = addr; row->line = line; row->column = 0; return row; } static void r_bin_dwarf_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) { ut8 *buf; RList *list = NULL; int len, ret; RBinSection *section = getsection (a, "debug_line"); RBinFile *binfile = a ? a->cur: NULL; if (binfile && section) { len = section->size; if (len < 1) { return NULL; } buf = calloc (1, len + 1); if (!buf) { return NULL; } ret = r_buf_read_at (binfile->buf, section->paddr, buf, len); if (ret != len) { free (buf); return NULL; } list = r_list_new (); // always return empty list wtf if (!list) { free (buf); return NULL; } list->free = r_bin_dwarf_row_free; r_bin_dwarf_parse_line_raw2 (a, buf, len, mode); // k bin/cur/addrinfo/* SdbListIter *iter; SdbKv *kv; SdbList *ls = sdb_foreach_list (binfile->sdb_addrinfo, false); ls_foreach (ls, iter, kv) { if (!strncmp (kv->key, "0x", 2)) { ut64 addr; RBinDwarfRow *row; int line; char *file = strdup (kv->value); if (!file) { free (buf); ls_free (ls); return NULL; } char *tok = strchr (file, '|'); if (tok) { *tok++ = 0; line = atoi (tok); addr = r_num_math (NULL, kv->key); row = r_bin_dwarf_row_new (addr, file, line, 0); r_list_append (list, row); } free (file); } } ls_free (ls); free (buf); } return list; } R_API RList *r_bin_dwarf_parse_aranges(RBin *a, int mode) { ut8 *buf; int ret; size_t len; RBinSection *section = getsection (a, "debug_aranges"); RBinFile *binfile = a ? a->cur: NULL; if (binfile && section) { len = section->size; if (len < 1 || len > ST32_MAX) { return NULL; } buf = calloc (1, len); ret = r_buf_read_at (binfile->buf, section->paddr, buf, len); if (!ret) { free (buf); return NULL; } if (mode == R_CORE_BIN_PRINT) { r_bin_dwarf_parse_aranges_raw (buf, len, stdout); } else { r_bin_dwarf_parse_aranges_raw (buf, len, DBGFD); } free (buf); } return NULL; } R_API RBinDwarfDebugAbbrev *r_bin_dwarf_parse_abbrev(RBin *a, int mode) { ut8 *buf; size_t len; RBinSection *section = getsection (a, "debug_abbrev"); RBinDwarfDebugAbbrev *da = NULL; RBinFile *binfile = a ? a->cur: NULL; if (!section || !binfile) return NULL; if (section->size > binfile->size) { return NULL; } 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); free (buf); return da; }