/* return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR If err_count_out is non-NULL, this is a special 'check' call. */ static int _dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error, int * err_count_out, int only_line_header) { /* This pointer is used to scan the portion of the .debug_line section for the current cu. */ Dwarf_Small *line_ptr = 0; Dwarf_Small *orig_line_ptr = 0; /* Pointer to a DW_AT_stmt_list attribute in case it exists in the die. */ Dwarf_Attribute stmt_list_attr = 0; /* Pointer to DW_AT_comp_dir attribute in die. */ Dwarf_Attribute comp_dir_attr = 0; /* Pointer to name of compilation directory. */ Dwarf_Small *comp_dir = NULL; /* Offset into .debug_line specified by a DW_AT_stmt_list attribute. */ Dwarf_Unsigned line_offset = 0; Dwarf_Sword i=0; Dwarf_Word u=0; /* These variables are used to decode leb128 numbers. Leb128_num holds the decoded number, and leb128_length is its length in bytes. */ Dwarf_Half attrform = 0; /* In case there are wierd bytes 'after' the line table prologue this lets us print something. This is a gcc compiler bug and we expect the bytes count to be 12. */ Dwarf_Small* bogus_bytes_ptr = 0; Dwarf_Unsigned bogus_bytes_count = 0; Dwarf_Half address_size = 0; Dwarf_Unsigned fission_offset = 0; /* The Dwarf_Debug this die belongs to. */ Dwarf_Debug dbg=0; Dwarf_CU_Context cu_context = 0; Dwarf_Line_Context line_context = 0; int resattr = DW_DLV_ERROR; int lres = DW_DLV_ERROR; int res = DW_DLV_ERROR; Dwarf_Small *line_ptr_actuals = 0; Dwarf_Small *line_ptr_end = 0; Dwarf_Small *section_start = 0; /* ***** BEGIN CODE ***** */ if (error != NULL) { *error = NULL; } CHECK_DIE(die, DW_DLV_ERROR); cu_context = die->di_cu_context; dbg = cu_context->cc_dbg; res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); if (res != DW_DLV_OK) { return res; } if (!dbg->de_debug_line.dss_size) { return (DW_DLV_NO_ENTRY); } address_size = _dwarf_get_address_size(dbg, die); resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error); if (resattr != DW_DLV_OK) { return resattr; } /* The list of relevant FORMs is small. DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset */ lres = dwarf_whatform(stmt_list_attr,&attrform,error); if (lres != DW_DLV_OK) { return lres; } if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 && attrform != DW_FORM_sec_offset ) { _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); return (DW_DLV_ERROR); } lres = dwarf_global_formref(stmt_list_attr, &line_offset, error); if (lres != DW_DLV_OK) { return lres; } if (line_offset >= dbg->de_debug_line.dss_size) { _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD); return (DW_DLV_ERROR); } section_start = dbg->de_debug_line.dss_data; { Dwarf_Unsigned fission_size = 0; int resfis = _dwarf_get_fission_addition_die(die, DW_SECT_LINE, &fission_offset,&fission_size,error); if(resfis != DW_DLV_OK) { return resfis; } } orig_line_ptr = section_start + line_offset + fission_offset; line_ptr = orig_line_ptr; dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR); /* If die has DW_AT_comp_dir attribute, get the string that names the compilation directory. */ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error); if (resattr == DW_DLV_ERROR) { return resattr; } if (resattr == DW_DLV_OK) { int cres = DW_DLV_ERROR; char *cdir = 0; cres = dwarf_formstring(comp_dir_attr, &cdir, error); if (cres == DW_DLV_ERROR) { return cres; } else if (cres == DW_DLV_OK) { comp_dir = (Dwarf_Small *) cdir; } } if (resattr == DW_DLV_OK) { dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR); } line_context = (Dwarf_Line_Context) _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); if (line_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } { Dwarf_Small *newlinep = 0; int dres = _dwarf_read_line_table_header(dbg, cu_context, section_start, line_ptr, dbg->de_debug_line.dss_size, &newlinep, line_context, &bogus_bytes_ptr, &bogus_bytes_count, error, err_count_out); if (dres == DW_DLV_ERROR) { dwarf_srclines_dealloc_b(line_context); return dres; } if (dres == DW_DLV_NO_ENTRY) { dwarf_srclines_dealloc_b(line_context); return dres; } line_ptr_end = line_context->lc_line_ptr_end; line_ptr = newlinep; if (line_context->lc_actuals_table_offset > 0) { line_ptr_actuals = line_context->lc_line_prologue_start + line_context->lc_actuals_table_offset; } } line_context->lc_compilation_directory = comp_dir; if (only_line_header) { /* Just checking for header errors, nothing more here.*/ dwarf_srclines_dealloc_b(line_context); return DW_DLV_OK; } dwarf_printf(dbg, "total line info length %ld bytes," " line offset 0x%" DW_PR_XZEROS DW_PR_DUx " %" DW_PR_DUu "\n", (long) line_context->lc_total_length, line_context->lc_section_offset, line_context->lc_section_offset); if (line_context->lc_version_number <= DW_LINE_VERSION5) { dwarf_printf(dbg, "line table version %d\n",(int) line_context->lc_version_number); } else { dwarf_printf(dbg, "line table version 0x%x\n",(int) line_context->lc_version_number); } dwarf_printf(dbg, "line table length field length %d prologue length %d\n", (int)line_context->lc_length_field_length, (int)line_context->lc_prologue_length); dwarf_printf(dbg, "compilation_directory %s\n", comp_dir ? ((char *) comp_dir) : ""); dwarf_printf(dbg, " min instruction length %d\n", (int) line_context->lc_minimum_instruction_length); if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) { dwarf_printf(dbg, " actuals table offset " "0x%" DW_PR_XZEROS DW_PR_DUx " logicals table offset " "0x%" DW_PR_XZEROS DW_PR_DUx "\n", line_context->lc_actuals_table_offset, line_context->lc_logicals_table_offset); } if (line_context->lc_version_number == DW_LINE_VERSION5) { dwarf_printf(dbg, " segment selector size %d\n", (int) line_context->lc_segment_selector_size); dwarf_printf(dbg, " address size %d\n", (int) line_context->lc_address_size); } dwarf_printf(dbg, " default is stmt %d\n",(int)line_context->lc_default_is_stmt); dwarf_printf(dbg, " line base %d\n",(int)line_context->lc_line_base); dwarf_printf(dbg, " line_range %d\n",(int)line_context->lc_line_range); dwarf_printf(dbg, " opcode base %d\n",(int)line_context->lc_opcode_base); dwarf_printf(dbg, " standard opcode count %d\n",(int)line_context->lc_std_op_count); for (i = 1; i < line_context->lc_opcode_base; i++) { dwarf_printf(dbg, " opcode[%2d] length %d\n", (int) i, (int) line_context->lc_opcode_length_table[i - 1]); } dwarf_printf(dbg, " include directories count %d\n", (int) line_context->lc_include_directories_count); for (u = 0; u < line_context->lc_include_directories_count; ++u) { dwarf_printf(dbg, " include dir[%u] %s\n", (int) u, line_context->lc_include_directories[u]); } dwarf_printf(dbg, " files count %d\n", (int) line_context->lc_file_entry_count); if (line_context->lc_file_entry_count) { Dwarf_File_Entry fe = line_context->lc_file_entries; Dwarf_File_Entry fe2 = fe; unsigned fiu = 0; for (fiu = 0 ; fe2 ; fe2 = fe->fi_next,++fiu ) { Dwarf_Unsigned tlm2 = 0; Dwarf_Unsigned di = 0; Dwarf_Unsigned fl = 0; fe = fe2; tlm2 = fe->fi_time_last_mod; di = fe->fi_dir_index; fl = fe->fi_file_length; dwarf_printf(dbg, " file[%u] %s (file-number: %u) \n", (unsigned) fiu, (char *) fe->fi_file_name, (unsigned)(fiu+1)); dwarf_printf(dbg, " dir index %d\n", (int) di); { time_t tt = (time_t) tlm2; /* ctime supplies newline */ dwarf_printf(dbg, " last time 0x%x %s", (unsigned) tlm2, ctime(&tt)); } dwarf_printf(dbg, " file length %ld 0x%lx\n", (long) fl, (unsigned long) fl); } } if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) { /* Print the subprograms list. */ Dwarf_Unsigned count = line_context->lc_subprogs_count; Dwarf_Unsigned exu = 0; Dwarf_Subprog_Entry sub = line_context->lc_subprogs; dwarf_printf(dbg," subprograms count" " %" DW_PR_DUu "\n",count); if (count > 0) { dwarf_printf(dbg," indx file line name\n"); } for (exu = 0 ; exu < count ; exu++,sub++) { dwarf_printf(dbg," [%2" DW_PR_DUu "] %4" DW_PR_DUu " %4" DW_PR_DUu " %s\n", exu+1, sub->ds_decl_file, sub->ds_decl_line, sub->ds_subprog_name); } } { Dwarf_Unsigned offset = 0; if (bogus_bytes_count > 0) { Dwarf_Unsigned wcount = bogus_bytes_count; Dwarf_Unsigned boffset = bogus_bytes_ptr - section_start; dwarf_printf(dbg, "*** DWARF CHECK: the line table prologue header_length " " is %" DW_PR_DUu " too high, we pretend it is smaller." "Section offset: 0x%" DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ") ***\n", wcount, boffset,boffset); *err_count_out += 1; } offset = line_ptr - section_start; dwarf_printf(dbg, " statement prog offset in section: 0x%" DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ")\n", offset, offset); } { Dwarf_Bool doaddrs = false; Dwarf_Bool dolines = true; _dwarf_print_line_context_record(dbg,line_context); if (!line_ptr_actuals) { /* Normal single level line table. */ Dwarf_Bool is_single_table = true; Dwarf_Bool is_actuals_table = false; print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr, line_ptr_end, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error, err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } } else { Dwarf_Bool is_single_table = false; Dwarf_Bool is_actuals_table = false; if (line_context->lc_version_number != EXPERIMENTAL_LINE_TABLES_VERSION) { dwarf_srclines_dealloc_b(line_context); _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } /* Read Logicals */ print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr, line_ptr_actuals, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error,err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } if (line_context->lc_actuals_table_offset > 0) { is_actuals_table = true; /* Read Actuals */ print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr_actuals, line_ptr_end, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error, err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } } } } dwarf_srclines_dealloc_b(line_context); return DW_DLV_OK; }
int dwarf_get_ranges_a(Dwarf_Debug dbg, Dwarf_Off rangesoffset, Dwarf_Die die, Dwarf_Ranges ** rangesbuf, Dwarf_Signed * listlen, Dwarf_Unsigned * bytecount, Dwarf_Error * error) { Dwarf_Small *rangeptr = 0; Dwarf_Small *beginrangeptr = 0; Dwarf_Small *section_end = 0; unsigned entry_count = 0; struct ranges_entry *base = 0; struct ranges_entry *last = 0; struct ranges_entry *curre = 0; Dwarf_Ranges * ranges_data_out = 0; unsigned copyindex = 0; Dwarf_Half address_size = 0; int res = DW_DLV_ERROR; Dwarf_Unsigned rangebase = 0; Dwarf_Debug localdbg = dbg; Dwarf_Error localerror = 0; if (die &&localdbg->de_tied_data.td_tied_object) { /* ASSERT: localdbg->de_debug_ranges is missing: DW_DLV_NO_ENTRY. So lets not look in dbg. */ Dwarf_CU_Context context = 0; int restied = 0; context = die->di_cu_context; restied = _dwarf_get_ranges_base_attr_from_tied(localdbg, context, &rangebase, error); if (restied == DW_DLV_ERROR ) { if(!error) { return restied; } dwarf_dealloc(localdbg,*error,DW_DLA_ERROR); *error = 0; /* Nothing else to do. Look in original dbg. */ } else if (restied == DW_DLV_NO_ENTRY ) { /* Nothing else to do. Look in original dbg. */ } else { /* Ranges are never in a split dwarf object. In the base object instead. Use the tied_object */ localdbg = dbg->de_tied_data.td_tied_object; } } res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror); if (res == DW_DLV_ERROR) { _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error); return res; } else if (res == DW_DLV_NO_ENTRY) { return res; } if ((rangesoffset +rangebase) >= localdbg->de_debug_ranges.dss_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); return (DW_DLV_ERROR); } address_size = _dwarf_get_address_size(localdbg, die); section_end = localdbg->de_debug_ranges.dss_data + localdbg->de_debug_ranges.dss_size; rangeptr = localdbg->de_debug_ranges.dss_data + rangesoffset+rangebase; beginrangeptr = rangeptr; for (;;) { struct ranges_entry * re = 0; if (rangeptr == section_end) { break; } if (rangeptr > section_end) { free_allocated_ranges(base); _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); return (DW_DLV_ERROR); break; } re = calloc(sizeof(struct ranges_entry),1); if (!re) { free_allocated_ranges(base); _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); return (DW_DLV_ERROR); } if ((rangeptr + (2*address_size)) > section_end) { free(re); free_allocated_ranges(base); _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); return (DW_DLV_ERROR); } entry_count++; res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1, rangeptr, address_size,error,section_end); if (res != DW_DLV_OK) { free(re); free_allocated_ranges(base); return res; } rangeptr += address_size; res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2, rangeptr, address_size,error,section_end); if (res != DW_DLV_OK) { free(re); free_allocated_ranges(base); return res; } rangeptr += address_size; if (!base) { base = re; last = re; } else { last->next = re; last = re; } if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { re->cur.dwr_type = DW_RANGES_END; break; } else if (re->cur.dwr_addr1 == MAX_ADDR) { re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; } else { re->cur.dwr_type = DW_RANGES_ENTRY; } } /* We return ranges on dbg, so use that to allocate. */ ranges_data_out = (Dwarf_Ranges *) _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); if (!ranges_data_out) { /* Error, apply to original, not local dbg. */ free_allocated_ranges(base); _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); return (DW_DLV_ERROR); } curre = base; *rangesbuf = ranges_data_out; *listlen = entry_count; for (copyindex = 0; curre && (copyindex < entry_count); ++copyindex,++ranges_data_out) { *ranges_data_out = curre->cur; curre = curre->next; } /* ASSERT: curre == NULL */ free_allocated_ranges(base); base = 0; /* Callers will often not care about the bytes used. */ if (bytecount) { *bytecount = rangeptr - beginrangeptr; } return DW_DLV_OK; }
int dwarf_get_ranges_a(Dwarf_Debug dbg, Dwarf_Off rangesoffset, Dwarf_Die die, Dwarf_Ranges ** rangesbuf, Dwarf_Signed * listlen, Dwarf_Unsigned * bytecount, Dwarf_Error * error) { Dwarf_Small *rangeptr = 0; Dwarf_Small *beginrangeptr = 0; Dwarf_Small *section_end = 0; unsigned entry_count = 0; struct ranges_entry *base = 0; struct ranges_entry *last = 0; struct ranges_entry *curre = 0; Dwarf_Ranges * ranges_data_out = 0; unsigned copyindex = 0; Dwarf_Half address_size = 0; int res = DW_DLV_ERROR; res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error); if (res != DW_DLV_OK) { return res; } if(rangesoffset >= dbg->de_debug_ranges.dss_size) { _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); return (DW_DLV_ERROR); } address_size = _dwarf_get_address_size(dbg, die); section_end = dbg->de_debug_ranges.dss_data + dbg->de_debug_ranges.dss_size; rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset; beginrangeptr = rangeptr; for(;;) { struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1); if(!re) { _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); return (DW_DLV_ERROR); } if(rangeptr >= section_end) { return (DW_DLV_NO_ENTRY); } if((rangeptr + (2*address_size)) > section_end) { _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD); return (DW_DLV_ERROR); } entry_count++; READ_UNALIGNED(dbg,re->cur.dwr_addr1, Dwarf_Addr, rangeptr, address_size); rangeptr += address_size; READ_UNALIGNED(dbg,re->cur.dwr_addr2 , Dwarf_Addr, rangeptr, address_size); rangeptr += address_size; if(!base) { base = re; last = re; } else { last->next = re; last = re; } if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) { re->cur.dwr_type = DW_RANGES_END; break; } else if ( re->cur.dwr_addr1 == MAX_ADDR) { re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION; } else { re->cur.dwr_type = DW_RANGES_ENTRY; } } ranges_data_out = (Dwarf_Ranges *) _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count); if(!ranges_data_out) { _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM); return (DW_DLV_ERROR); } curre = base; *rangesbuf = ranges_data_out; *listlen = entry_count; for( copyindex = 0; curre && (copyindex < entry_count); ++copyindex,++ranges_data_out) { struct ranges_entry *r = curre; *ranges_data_out = curre->cur; curre = curre->next; free(r); } /* Callers will often not care about the bytes used. */ if(bytecount) { *bytecount = rangeptr - beginrangeptr; } return DW_DLV_OK; }