/* Return DW_DLV_OK, ERROR, or NO_ENTRY. */ static int handle_debug_info(Dwarf_Debug dbg, int *errval) { Dwarf_Unsigned nxtoff = 1; Dwarf_Unsigned hdr_length; Dwarf_Half version_stamp; Dwarf_Unsigned abbrev_offset; Dwarf_Half addr_size; Dwarf_Error err; int terminate_now = 0; int res = 0; Dwarf_Die sibdie; int sibres; int nres = DW_DLV_OK; for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, &abbrev_offset, &addr_size, &nxtoff, &err); terminate_now == 0 && nres == DW_DLV_OK; nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, &abbrev_offset, &addr_size, &nxtoff, &err) ) { Dwarf_Die curdie = 0; /* try to get the compilation unit die */ sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err); if (sibres == DW_DLV_OK) { res = do_this_die_and_dealloc(dbg, sibdie, errval); switch (res) { case DW_DLV_OK: break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: return DW_DLV_ERROR; } } else if (sibres == DW_DLV_ERROR) { *errval = (int) dwarf_errno(err); return DW_DLV_ERROR; } else { /* NO ENTRY! */ /* impossible? */ } } if (nres == DW_DLV_ERROR) { int localerr = (int) dwarf_errno(err); *errval = localerr; return DW_DLV_ERROR; } return DW_DLV_OK; }
int _dwarf_get_string_from_tied(Dwarf_Debug dbg, Dwarf_Unsigned offset, char **return_str, Dwarf_Error*error) { Dwarf_Debug tieddbg = 0; Dwarf_Small *secend = 0; Dwarf_Small *secbegin = 0; Dwarf_Small *strbegin = 0; int res = DW_DLV_ERROR; Dwarf_Error localerror = 0; /* Attach errors to dbg, not tieddbg. */ tieddbg = dbg->de_tied_data.td_tied_object; if (!tieddbg) { _dwarf_error(dbg, error, DW_DLE_NO_TIED_FILE_AVAILABLE); return DW_DLV_ERROR; } /* The 'offset' into .debug_str is set. */ res = _dwarf_load_section(tieddbg, &tieddbg->de_debug_str,&localerror); if (res == DW_DLV_ERROR) { Dwarf_Unsigned lerrno = dwarf_errno(localerror); dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR); _dwarf_error(dbg,error,lerrno); return res; } else if (res == DW_DLV_NO_ENTRY) { return res; } if (offset >= tieddbg->de_debug_str.dss_size) { /* Badly damaged DWARF here. */ _dwarf_error(dbg, error, DW_DLE_NO_TIED_STRING_AVAILABLE); return (DW_DLV_ERROR); } secbegin = tieddbg->de_debug_str.dss_data; strbegin= tieddbg->de_debug_str.dss_data + offset; secend = tieddbg->de_debug_str.dss_data + tieddbg->de_debug_str.dss_size; /* Ensure the offset lies within the .debug_str */ if (offset >= tieddbg->de_debug_str.dss_size) { _dwarf_error(dbg, error, DW_DLE_NO_TIED_STRING_AVAILABLE); return (DW_DLV_ERROR); } res= _dwarf_check_string_valid(tieddbg,secbegin,strbegin, secend, &localerror); if (res == DW_DLV_ERROR) { Dwarf_Unsigned lerrno = dwarf_errno(localerror); dwarf_dealloc(tieddbg,localerror,DW_DLA_ERROR); _dwarf_error(dbg,error,lerrno); return res; } else if (res == DW_DLV_NO_ENTRY) { return res; } *return_str = (char *) (tieddbg->de_debug_str.dss_data + offset); return DW_DLV_OK; }
/* Often errs and errt point to the same Dwarf_Error, So exercise care. All the arguments MUST be non-null.*/ void _dwarf_error_mv_s_to_t(Dwarf_Debug dbgs,Dwarf_Error *errs, Dwarf_Debug dbgt,Dwarf_Error *errt) { if (!errt || !errs) { return; } if (!dbgs || !dbgt) { return; } if(dbgs == dbgt) { if(errs != errt) { Dwarf_Error ers = *errs; *errs = 0; *errt = ers; } } else { /* Do not stomp on the system errno variable if there is one! */ int mydw_errno = dwarf_errno(*errs); dwarf_dealloc(dbgs,*errs, DW_DLA_ERROR); *errs = 0; _dwarf_error(dbgt,errt, mydw_errno); } }
static int handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval) { int retval = DW_DLV_OK; int res; Dwarf_Error err; Dwarf_Addr *addrlist; Dwarf_Off *offsetlist; Dwarf_Unsigned count; Dwarf_Unsigned i; res = _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist, &count, &err); if (res == DW_DLV_OK) { for (i = 0; i < count; i++) { cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]); } dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); } else if (res == DW_DLV_NO_ENTRY) { retval = res; } else { *errval = (int) dwarf_errno(err); retval = DW_DLV_ERROR; } return retval; }
static int handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval) { int retval = DW_DLV_OK; Dwarf_Error err; Dwarf_Addr *aranges; Dwarf_Signed count; int indx; Dwarf_Off *offsets; retval = _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count, &err); if (retval == DW_DLV_OK) { if (count == 0) { retval = DW_DLV_NO_ENTRY; } else { for (indx = 0; indx < count; indx++) { cb_func(DW_SECTION_ARANGES, offsets[indx], aranges[indx]); } } dwarf_dealloc(dbg, aranges, DW_DLA_ADDR); dwarf_dealloc(dbg, offsets, DW_DLA_ADDR); } else if (retval == DW_DLV_NO_ENTRY) { ; /* do nothing */ } else { *errval = (int) dwarf_errno(err); retval = DW_DLV_ERROR; } return retval; }
int main (int argc, char *argv[]) { assert (argc >= 3); const char *name = argv[1]; ptrdiff_t cuoff = strtol (argv[2], NULL, 0); bool new_style = argc > 3; int fd = open (name, O_RDONLY); Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); Dwarf_Die cudie_mem, *cudie = dwarf_offdie (dbg, cuoff, &cudie_mem); for (ptrdiff_t off = new_style ? DWARF_GETMACROS_START : 0; (off = dwarf_getmacros (cudie, mac, dbg, off)); ) if (off == -1) { puts (dwarf_errmsg (dwarf_errno ())); break; } dwarf_end (dbg); return 0; }
static void include (Dwarf *dbg, Dwarf_Off macoff, ptrdiff_t token) { while ((token = dwarf_getmacros_off (dbg, macoff, mac, dbg, token)) != 0) if (token == -1) { puts (dwarf_errmsg (dwarf_errno ())); break; } }
static int reloc_incomplete(Dwarf_Error err) { int e = dwarf_errno(err); if( e == DW_DLE_RELOC_MISMATCH_INDEX || e == DW_DLE_RELOC_MISMATCH_RELOC_INDEX || e == DW_DLE_RELOC_MISMATCH_STRTAB_INDEX || e == DW_DLE_RELOC_SECTION_MISMATCH || e == DW_DLE_RELOC_SECTION_MISSING_INDEX || e == DW_DLE_RELOC_SECTION_LENGTH_ODD || e == DW_DLE_RELOC_SECTION_PTR_NULL || e == DW_DLE_RELOC_SECTION_MALLOC_FAIL || e == DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD ) { return 1; } return 0; }
void _dwarf_error_mv_s_to_t(Dwarf_Debug dbgs,Dwarf_Error *errs, Dwarf_Debug dbgt,Dwarf_Error *errt) { if(dbgs == dbgt) { if(errs != errt) { Dwarf_Error ers = *errs; *errs = 0; *errt = ers; } } else { int errno = dwarf_errno(*errs); dwarf_dealloc(dbgs,*errs, DW_DLA_ERROR); *errs = 0; _dwarf_error(dbgt,errt, errno); } }
void deal_with_name_offset_err(Dwarf_Debug dbg, char *err_loc, char *name, Dwarf_Unsigned die_off, int nres, Dwarf_Error err) { if (nres == DW_DLV_ERROR) { Dwarf_Unsigned myerr = dwarf_errno(err); if (myerr == DW_DLE_OFFSET_BAD) { printf("Error: bad offset %s, %s %" DW_PR_DUu " (0x%08" DW_PR_DUx ")\n", err_loc, name, die_off, die_off); } print_error(dbg, err_loc, nres, err); } }
static void __dead2 _dwarf_err(const char *fn, unsigned ln, const char *func, int ex, int error, const char *fmt, ...) { va_list ap; printf("%s:%u: %s: ", fn, ln, func); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); /* * Bizarrely, this clears the global DWARF error, breaking * dwarf_errmsg(-1): */ if (error == -1) error = dwarf_errno(); printf(": %s(%d)\n", dwarf_errmsg(error), error); exit(ex); }
static int mac (Dwarf_Macro *macro, void *dbg) { static int level = 0; unsigned int opcode; dwarf_macro_opcode (macro, &opcode); switch (opcode) { case DW_MACRO_GNU_transparent_include: { Dwarf_Attribute at; int r = dwarf_macro_param (macro, 0, &at); assert (r == 0); Dwarf_Word w; r = dwarf_formudata (&at, &w); assert (r == 0); printf ("%*sinclude %#" PRIx64 "\n", level, "", w); ++level; include (dbg, w, DWARF_GETMACROS_START); --level; printf ("%*s/include\n", level, ""); break; } case DW_MACRO_GNU_start_file: { Dwarf_Files *files; size_t nfiles; if (dwarf_macro_getsrcfiles (dbg, macro, &files, &nfiles) < 0) printf ("dwarf_macro_getsrcfiles: %s\n", dwarf_errmsg (dwarf_errno ())); Dwarf_Word w = 0; dwarf_macro_param2 (macro, &w, NULL); const char *name = dwarf_filesrc (files, (size_t) w, NULL, NULL); printf ("%*sfile %s\n", level, "", name); ++level; break; } case DW_MACRO_GNU_end_file: { --level; printf ("%*s/file\n", level, ""); break; } case DW_MACINFO_define: case DW_MACRO_GNU_define_indirect: { const char *value; dwarf_macro_param2 (macro, NULL, &value); printf ("%*s%s\n", level, "", value); break; } case DW_MACINFO_undef: case DW_MACRO_GNU_undef_indirect: break; default: { size_t paramcnt; dwarf_macro_getparamcnt (macro, ¶mcnt); printf ("%*sopcode %u with %zd arguments\n", level, "", opcode, paramcnt); break; } } return DWARF_CB_ABORT; }
/* Return DW_DLV_OK, or DW_DLV_ERROR Handle the addrs in a single die. */ static int process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval) { Dwarf_Error err; Dwarf_Half i; Dwarf_Half newattrnum; int res; int tres; Dwarf_Half ltag; Dwarf_Off doff; int doffres = dwarf_dieoffset(newdie, &doff, &err); if (doffres != DW_DLV_OK) { if (doffres == DW_DLV_ERROR) { *errval = (int) dwarf_errno(err); } return doffres; } tres = dwarf_tag(newdie, <ag, &err); if (tres != DW_DLV_OK) { return tres; } if (DW_TAG_compile_unit == ltag) { /* because of the way the dwarf_line code works, we ** do lines only per compile unit. ** This may turn out to be wrong if we have lines ** left unconnected to a CU. ** of course such lines will not, at present, be ** used by gnome ** This is not ideal as coded due to the dwarf_line.c issue. */ int lres; lres = handle_debug_line(dbg, newdie, send_addr_note, errval); if (lres == DW_DLV_ERROR) { return lres; } } for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) { int resattr; Dwarf_Bool hasattr; newattrnum = might_have_addr[i]; err = 0; resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); if (DW_DLV_OK == resattr) { if (hasattr) { res = handle_attr_addr(dbg, newdie, newattrnum, &err); if (res != DW_DLV_OK) { *errval = (int) dwarf_errno(err); return DW_DLV_ERROR; } } } else { if (resattr == DW_DLV_ERROR) { *errval = (int) dwarf_errno(err); return resattr; } } } for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) { int resattr; Dwarf_Bool hasattr; newattrnum = might_have_locdesc[i]; err = 0; resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); if (DW_DLV_OK == resattr) { if (hasattr) { res = handle_attr_locdesc(dbg, newdie, newattrnum, &err); if (res != DW_DLV_OK) { *errval = (int) dwarf_errno(err); return DW_DLV_ERROR; } } } else { if (resattr == DW_DLV_ERROR) { *errval = (int) dwarf_errno(err); return resattr; } } } return DW_DLV_OK; }
/* Handle siblings as a list, Do children by recursing. Effectively this is walking the tree preorder. This dealloc's any die passed to it, so the caller should not do that dealloc. It seems more logical to have the one causing the alloc to do the dealloc, but that way this routine became a mess. */ static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval) { Dwarf_Die prevdie = 0; Dwarf_Die newdie = die; Dwarf_Error err = 0; int res = 0; int sibres = DW_DLV_OK; int tres = DW_DLV_OK; Dwarf_Die sibdie; while (sibres == DW_DLV_OK) { Dwarf_Die ch_die; res = process_this_die_attrs(dbg, newdie, errval); switch (res) { case DW_DLV_OK: break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: if (prevdie) { dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); prevdie = 0; } return DW_DLV_ERROR; } tres = dwarf_child(newdie, &ch_die, &err); if (tres == DW_DLV_OK) { res = do_this_die_and_dealloc(dbg, ch_die, errval); switch (res) { case DW_DLV_OK: break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: if (prevdie) { dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); prevdie = 0; } return DW_DLV_ERROR; } } else if (tres == DW_DLV_ERROR) { /* An error! */ *errval = (int) dwarf_errno(err); if (prevdie) { dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); prevdie = 0; } dwarf_dealloc(dbg, err, DW_DLA_ERROR); return DW_DLV_ERROR; } /* else was NO ENTRY */ prevdie = newdie; sibdie = 0; sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err); if (prevdie) { dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); prevdie = 0; } newdie = sibdie; } if (sibres == DW_DLV_NO_ENTRY) { return DW_DLV_OK; } /* error. */ *errval = (int) dwarf_errno(err); if (prevdie) { dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); prevdie = 0; } dwarf_dealloc(dbg, err, DW_DLA_ERROR); return DW_DLV_ERROR; }
int _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr, Dwarf_addr_callback_func cb_func, int *dwerr) { Dwarf_Error err = 0; Dwarf_Debug dbg = 0; int res = 0; int errval = 0; int sections_found = 0; res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0, /* errarg */ 0, &dbg, &err); if (res == DW_DLV_ERROR) { int errv = (int) dwarf_errno(err); return errv; } if (res == DW_DLV_NO_ENTRY) { return res; } send_addr_note = cb_func; res = handle_debug_info(dbg, &errval); switch (res) { case DW_DLV_OK: ++sections_found; break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: dwarf_finish(dbg, &err); *dwerr = errval; return res; } res = handle_debug_aranges(dbg, cb_func, &errval); switch (res) { case DW_DLV_OK: ++sections_found; break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: dwarf_finish(dbg, &err); *dwerr = errval; return res; } res = handle_debug_frame(dbg, cb_func, &errval); switch (res) { case DW_DLV_OK: ++sections_found; break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: dwarf_finish(dbg, &err); *dwerr = errval; return res; } res = handle_debug_loc(); /* does nothing */ switch (res) { case DW_DLV_OK: ++sections_found; break; case DW_DLV_NO_ENTRY: break; default: case DW_DLV_ERROR: /* IMPOSSIBLE : handle_debug_loc cannot return this */ dwarf_finish(dbg, &err); *dwerr = errval; return res; } *dwerr = 0; res = dwarf_finish(dbg, &err); if (res == DW_DLV_ERROR) { *dwerr = (int) dwarf_errno(err); return DW_DLV_ERROR; } if (sections_found == 0) { return DW_DLV_NO_ENTRY; } return DW_DLV_OK; }
/* Use a Dwarf_Obj_Access_Interface to kick things off. All other init routines eventually use this one. The returned Dwarf_Debug contains a copy of *obj the callers copy of *obj may be freed whenever the caller wishes. */ int dwarf_object_init(Dwarf_Obj_Access_Interface* obj, Dwarf_Handler errhand, Dwarf_Ptr errarg, Dwarf_Debug* ret_dbg, Dwarf_Error* error) { Dwarf_Debug dbg = 0; int setup_result = DW_DLV_OK; dbg = _dwarf_get_debug(); if (dbg == NULL) { DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR); } dbg->de_errhand = errhand; dbg->de_errarg = errarg; dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE; dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM; #ifdef HAVE_OLD_FRAME_CFA_COL /* DW_FRAME_CFA_COL is really only suitable for old libdwarf frame interfaces and its value of 0 there is only usable where (as in MIPS) register 0 has no value other than 0 so we can use the frame table column 0 for the CFA value (and rely on client software to know when 'register 0' is the cfa and when to just use a value 0 for register 0). */ dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL; #else dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL3; #endif dbg->de_frame_same_value_number = DW_FRAME_SAME_VAL; dbg->de_frame_undefined_value_number = DW_FRAME_UNDEFINED_VAL; dbg->de_obj_file = obj; setup_result = _dwarf_setup(dbg, error); if (setup_result == DW_DLV_OK) { int fission_result = load_debugfission_tables(dbg,error); /* In most cases we get setup_result == DW_DLV_NO_ENTRY here as having debugfission (.dwp objects) is fairly rare. */ if (fission_result == DW_DLV_ERROR) { /* Something is very wrong. */ setup_result = fission_result; } } if (setup_result != DW_DLV_OK) { int freeresult = 0; /* We cannot use any _dwarf_setup() error here as we are freeing dbg, making that error (setup as part of dbg) stale. Hence we have to make a new error without a dbg. But error might be NULL and the init call error-handler function might be set. */ int myerr = 0; if ( (setup_result == DW_DLV_ERROR) && error ) { /* Preserve our _dwarf_setup error number, but this does not apply if error NULL. */ myerr = dwarf_errno(*error); /* deallocate the soon-stale error pointer. */ dwarf_dealloc(dbg,*error,DW_DLA_ERROR); *error = 0; } /* The status we want to return here is of _dwarf_setup, not of the _dwarf_free_all_of_one_debug(dbg) call. So use a local status variable for the free. */ freeresult = _dwarf_free_all_of_one_debug(dbg); dbg = 0; /* DW_DLV_NO_ENTRY not possible in freeresult */ if (freeresult == DW_DLV_ERROR) { /* Use the _dwarf_setup error number. If error is NULL the following will issue a message on stderr and abort(), as without dbg there is no error-handler function. */ _dwarf_error(NULL,error,DW_DLE_DBG_ALLOC); return DW_DLV_ERROR; } if (setup_result == DW_DLV_ERROR) { /* Use the _dwarf_setup error number. If error is NULL the following will issue a message on stderr and abort(), as without dbg there is no error-handler function. */ _dwarf_error(NULL,error,myerr); } return setup_result; } dwarf_harmless_init(&dbg->de_harmless_errors, DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE); *ret_dbg = dbg; return DW_DLV_OK; }
int main(int argc, char **argv) { Dwarf_Off off, lastoff; Dwarf *dw; size_t hdr_size; int cufd, error; argv0 = argv[0]; if (argc < 3) usage(); structname = argv[1]; binary = argv[2]; elf_version(EV_CURRENT); cufd = open(binary, O_RDONLY); if (cufd == -1) err(EX_USAGE, "open"); dw = dwarf_begin(cufd, DWARF_C_READ); if (dw == NULL) { error = dwarf_errno(); if (error == DWARF_E_NO_REGFILE) errx(EX_USAGE, "%s: Not a regular file", binary); dwarf_err_errno(EX_DATAERR, error, "dwarf_begin"); } get_elf_pointer_size(dw); /* XXX worry about .debug_types sections later. */ lastoff = off = 0; while (dwarf_nextcu(dw, off, &off, &hdr_size, NULL, NULL, NULL) == 0) { Dwarf_Die cu_die, die; int x; if (dwarf_offdie(dw, lastoff + hdr_size, &cu_die) == NULL) continue; lastoff = off; /* * A CU may be empty because e.g. an empty (or fully #if0'd) * file is compiled. */ if (dwarf_child(&cu_die, &die)) continue; /* Loop through all DIEs in the CU. */ do { if (isstruct(dwarf_tag(&die)) && dwarf_haschildren(&die) && dwarf_diename(&die) && strcmp(dwarf_diename(&die), structname) == 0) { structprobe(dw, &die); goto out; } } while ((x = dwarf_siblingof(&die, &die)) == 0); if (x == -1) dwarf_err(EX_DATAERR, "dwarf_siblingof"); } out: if (dwarf_end(dw)) dwarf_err(EX_SOFTWARE, "dwarf_end"); return (EX_OK); }
/* Here a DW_DLV_NO_ENTRY return means the macro operator is not a def/undef operator. */ int dwarf_get_macro_defundef(Dwarf_Macro_Context macro_context, Dwarf_Unsigned op_number, Dwarf_Unsigned * line_number, Dwarf_Unsigned * index, Dwarf_Unsigned * offset, Dwarf_Half * forms_count, const char ** macro_string, Dwarf_Error *error) { Dwarf_Debug dbg = 0; Dwarf_Small *mdata = 0; int res = 0; Dwarf_Small *startptr = 0; Dwarf_Small *endptr = 0; Dwarf_Half lformscount = 0; struct Dwarf_Macro_Operator_s *curop = 0; unsigned macop = 0; if (!macro_context || macro_context->mc_sentinel != 0xada) { if(macro_context) { dbg = macro_context->mc_dbg; } _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_HEADER_POINTER); return DW_DLV_ERROR; } dbg = macro_context->mc_dbg; if (op_number >= macro_context->mc_macro_ops_count) { _dwarf_error(dbg, error,DW_DLE_BAD_MACRO_INDEX); return DW_DLV_ERROR; } curop = macro_context->mc_ops + op_number; macop = curop->mo_opcode; startptr = macro_context->mc_macro_header; endptr = startptr + macro_context->mc_total_length; mdata = curop->mo_data; lformscount = curop->mo_form->mf_formcount; if (lformscount != 2) { /*_dwarf_error(dbg, error,DW_DLE_MACRO_OPCODE_FORM_BAD);*/ return DW_DLV_NO_ENTRY; } switch(macop){ case DW_MACRO_define: case DW_MACRO_undef: { Dwarf_Unsigned linenum = 0; Dwarf_Word uleblen = 0; const char * content = 0; linenum = _dwarf_decode_u_leb128(mdata, &uleblen); mdata += uleblen; content = (const char *)mdata; res = _dwarf_check_string_valid(dbg, startptr,mdata, endptr, error); if(res != DW_DLV_OK) { return res; } *line_number = linenum; *index = 0; *offset = 0; *forms_count = lformscount; *macro_string = content; } return DW_DLV_OK; case DW_MACRO_define_strp: case DW_MACRO_undef_strp: { Dwarf_Unsigned linenum = 0; Dwarf_Word uleblen = 0; Dwarf_Unsigned stringoffset = 0; Dwarf_Small form1 = curop->mo_form->mf_formbytes[1]; char * localstr = 0; linenum = _dwarf_decode_u_leb128(mdata, &uleblen); mdata += uleblen; READ_UNALIGNED(dbg,stringoffset,Dwarf_Unsigned, mdata,macro_context->mc_offset_size); mdata += macro_context->mc_offset_size; res = _dwarf_extract_local_debug_str_string_given_offset(dbg, form1, stringoffset, &localstr, error); *index = 0; *line_number = linenum; *offset = stringoffset; *forms_count = lformscount; if (res == DW_DLV_ERROR) { return res; *macro_string = "<Error: getting local .debug_str>"; } else if (res == DW_DLV_NO_ENTRY) { *macro_string = "<Error: NO_ENTRY on .debug_string (strp)>"; } else { *macro_string = (const char *)localstr; } } return DW_DLV_OK; case DW_MACRO_define_strx: case DW_MACRO_undef_strx: { Dwarf_Unsigned linenum = 0; Dwarf_Word uleblen = 0; Dwarf_Unsigned stringindex = 0; Dwarf_Unsigned offsettostr= 0; int res = 0; Dwarf_Small form1 = curop->mo_form->mf_formbytes[1]; linenum = _dwarf_decode_u_leb128(mdata, &uleblen); mdata += uleblen; *line_number = linenum; stringindex = _dwarf_decode_u_leb128(mdata, &uleblen); /* leave mdata uchanged for call below */ *index = stringindex; *forms_count = lformscount; /* FIXME */ /* Redoes the index-getting. Gets offset. */ res = _dwarf_extract_string_offset_via_str_offsets(dbg, mdata, DW_AT_macros, /*arbitrary, unused by called routine. */ form1, macro_context->mc_cu_context, &offsettostr, error); if (res == DW_DLV_ERROR) { return res; } if (res == DW_DLV_OK) { *index = stringindex; *offset = offsettostr; char *localstr = 0; res = _dwarf_extract_local_debug_str_string_given_offset(dbg, form1, offsettostr, &localstr, error); if(res == DW_DLV_ERROR) { return res; } else if (res == DW_DLV_NO_ENTRY){ *macro_string = "<:No string available>"; } else { *macro_string = (const char *)localstr; /* All is ok. */ } } else { *index = stringindex; *offset = 0; *macro_string = "<.debug_str_offsets not available>"; } } return DW_DLV_OK; case DW_MACRO_define_sup: case DW_MACRO_undef_sup: { Dwarf_Unsigned linenum = 0; Dwarf_Word uleblen = 0; Dwarf_Unsigned supoffset = 0; char *localstring = 0; int res = 0; linenum = _dwarf_decode_u_leb128(mdata, &uleblen); mdata += uleblen; READ_UNALIGNED(dbg,supoffset,Dwarf_Unsigned, mdata,macro_context->mc_offset_size); mdata += macro_context->mc_offset_size; *line_number = linenum; *index = 0; *offset = supoffset; *forms_count = lformscount; res = _dwarf_get_string_from_tied(dbg, supoffset, &localstring, error); if (res != DW_DLV_OK) { if (res == DW_DLV_ERROR) { if(dwarf_errno(*error) == DW_DLE_NO_TIED_FILE_AVAILABLE) { *macro_string = (char *)"<DW_FORM_str_sup-no-tied_file>"; } else { *macro_string = (char *)"<Error: DW_FORM_str_sup-got-error>"; } dwarf_dealloc(dbg,*error,DW_DLA_ERROR); } else { *macro_string = "<DW_FORM_str_sup-no-entry>"; } } else { *macro_string = (const char *)localstring; } return DW_DLV_OK; } } return DW_DLV_NO_ENTRY; }
/* Contrary to pre-2005 documentation, The string pointer returned thru return_str must never have dwarf_dealloc() applied to it. Documentation fixed July 2005. */ int dwarf_formstring(Dwarf_Attribute attr, char **return_str, Dwarf_Error * error) { Dwarf_CU_Context cu_context = 0; Dwarf_Debug dbg = 0; Dwarf_Unsigned offset = 0; int res = DW_DLV_ERROR; Dwarf_Small *secdataptr = 0; Dwarf_Small *secend = 0; Dwarf_Unsigned secdatalen = 0; Dwarf_Small *infoptr = attr->ar_debug_ptr; res = get_attr_dbg(&dbg,&cu_context,attr,error); if (res != DW_DLV_OK) { return res; } if (cu_context->cc_is_info) { secdataptr = (Dwarf_Small *)dbg->de_debug_info.dss_data; secdatalen = dbg->de_debug_info.dss_size; } else { secdataptr = (Dwarf_Small *)dbg->de_debug_types.dss_data; secdatalen = dbg->de_debug_types.dss_size; } switch(attr->ar_attribute_form) { case DW_FORM_string: { Dwarf_Small *begin = attr->ar_debug_ptr; Dwarf_Small *contextend = secdataptr + cu_context->cc_debug_offset + cu_context->cc_length + cu_context->cc_length_size + cu_context->cc_extension_size; secend = secdataptr + secdatalen; if (contextend < secend) { secend = contextend; } res= _dwarf_check_string_valid(dbg,secdataptr,begin, secend,error); if (res != DW_DLV_OK) { return res; } *return_str = (char *) (begin); return DW_DLV_OK; } case DW_FORM_GNU_strp_alt: case DW_FORM_strp_sup: { Dwarf_Error alterr = 0; /* See dwarfstd.org issue 120604.1 This is the offset in the .debug_str section of another object file. The 'tied' file notion should apply. It is not clear whether both a supplementary and a split object might be needed at the same time (hence two 'tied' files simultaneously). */ Dwarf_Off soffset = 0; res = dwarf_global_formref(attr, &soffset,error); if (res != DW_DLV_OK) { return res; } res = _dwarf_get_string_from_tied(dbg, soffset, return_str, &alterr); if (res == DW_DLV_ERROR) { if (dwarf_errno(alterr) == DW_DLE_NO_TIED_FILE_AVAILABLE) { dwarf_dealloc(dbg,alterr,DW_DLA_ERROR); if( attr->ar_attribute_form == DW_FORM_GNU_strp_alt) { *return_str = (char *)"<DW_FORM_GNU_strp_alt-no-tied-file>"; } else { *return_str = (char *)"<DW_FORM_strp_sup-no-tied-file>"; } return DW_DLV_OK; } if (error) { *error = alterr; } return res; } if (res == DW_DLV_NO_ENTRY) { if( attr->ar_attribute_form == DW_FORM_GNU_strp_alt) { *return_str = (char *)"<DW_FORM_GNU_strp_alt-no-tied-file>"; }else { *return_str = (char *)"<DW_FORM_strp_sup-no-tied-file>"; } } return res; } case DW_FORM_GNU_str_index: case DW_FORM_strx: { Dwarf_Unsigned offsettostr= 0; res = _dwarf_extract_string_offset_via_str_offsets(dbg, infoptr, attr->ar_attribute, attr->ar_attribute_form, cu_context, &offsettostr, error); if (res != DW_DLV_OK) { return res; } offset = offsettostr; break; } case DW_FORM_strp: case DW_FORM_line_strp:{ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, infoptr, cu_context->cc_length_size); break; } default: _dwarf_error(dbg, error, DW_DLE_STRING_FORM_IMPROPER); return DW_DLV_ERROR; } /* Now we have offset so read the string from debug_str or debug_line_str. */ res = _dwarf_extract_local_debug_str_string_given_offset(dbg, attr->ar_attribute_form, offset, return_str, error); return res; }