static int die_string(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, char **strp, int req) { const char *str = NULL; if (dwarf_attrval_string(die, name, &str, &dw->dw_err) != DWARF_E_NONE || str == NULL) { if (req) terminate("die %llu: failed to get string: %s\n", die_off(dw, die), dwarf_errmsg(&dw->dw_err)); else *strp = NULL; return (0); } else *strp = xstrdup(str); return (1); }
/** * Finds a function name in DWARF DIE (Debug Information Entry). * For more info on DWARF format, see http://www.dwarfstd.org/Download.php , http://www.ibm.com/developerworks/library/os-debugging/ * * @return true if we need to stop search (i.e. either found it or some error happened) */ bool FindFunctionNameInDIE(Dwarf_Debug DebugInfo, Dwarf_Die Die, Dwarf_Addr Addr, const char **OutFuncName) { Dwarf_Error ErrorInfo; Dwarf_Half Tag; Dwarf_Unsigned LowerPC, HigherPC; char *TempFuncName; int ReturnCode; if (dwarf_tag(Die, &Tag, &ErrorInfo) != DW_DLV_OK || Tag != DW_TAG_subprogram || dwarf_attrval_unsigned(Die, DW_AT_low_pc, &LowerPC, &ErrorInfo) != DW_DLV_OK || dwarf_attrval_unsigned(Die, DW_AT_high_pc, &HigherPC, &ErrorInfo) != DW_DLV_OK || Addr < LowerPC || HigherPC <= Addr ) { return false; } // found it *OutFuncName = NULL; Dwarf_Attribute SubAt; ReturnCode = dwarf_attr(Die, DW_AT_name, &SubAt, &ErrorInfo); if (ReturnCode == DW_DLV_ERROR) { return true; // error, but stop the search } else if (ReturnCode == DW_DLV_OK) { if (dwarf_formstring(SubAt, &TempFuncName, &ErrorInfo)) { *OutFuncName = NULL; } else { *OutFuncName = TempFuncName; } return true; } // DW_AT_Name is not present, look in DW_AT_specification Dwarf_Attribute SpecAt; if (dwarf_attr(Die, DW_AT_specification, &SpecAt, &ErrorInfo)) { // not found, tough luck return false; } Dwarf_Off Offset; if (dwarf_global_formref(SpecAt, &Offset, &ErrorInfo)) { return false; } Dwarf_Die SpecDie; if (dwarf_offdie(DebugInfo, Offset, &SpecDie, &ErrorInfo)) { return false; } if (dwarf_attrval_string(SpecDie, DW_AT_name, OutFuncName, &ErrorInfo)) { *OutFuncName = NULL; } return true; }
static void search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr, char **rlt_func) { Dwarf_Die ret_die, spec_die; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc; Dwarf_Off ref; Dwarf_Attribute sub_at, spec_at; char *func0; const char *func1; int ret; if (*rlt_func != NULL) goto done; if (dwarf_tag(die, &tag, &de)) { warnx("dwarf_tag: %s", dwarf_errmsg(de)); goto cont_search; } if (tag == DW_TAG_subprogram) { if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) || dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) goto cont_search; if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) goto cont_search; if (addr < lopc || addr >= hipc) goto cont_search; /* Found it! */ if ((*rlt_func = strdup(unknown)) == NULL) err(EXIT_FAILURE, "strdup"); ret = dwarf_attr(die, DW_AT_name, &sub_at, &de); if (ret == DW_DLV_ERROR) goto done; if (ret == DW_DLV_OK) { if (dwarf_formstring(sub_at, &func0, &de) == DW_DLV_OK) { free(*rlt_func); if ((*rlt_func = strdup(func0)) == NULL) err(EXIT_FAILURE, "strdup"); } goto done; } /* * If DW_AT_name is not present, but DW_AT_specification is * present, then probably the actual name is in the DIE * referenced by DW_AT_specification. */ if (dwarf_attr(die, DW_AT_specification, &spec_at, &de)) goto done; if (dwarf_global_formref(spec_at, &ref, &de)) goto done; if (dwarf_offdie(dbg, ref, &spec_die, &de)) goto done; if (dwarf_attrval_string(spec_die, DW_AT_name, &func1, &de) == DW_DLV_OK) { free(*rlt_func); if ((*rlt_func = strdup(func1)) == NULL) err(EXIT_FAILURE, "strdup"); } goto done; } cont_search: /* Search children. */ ret = dwarf_child(die, &ret_die, &de); if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_func(dbg, ret_die, addr, rlt_func); /* Search sibling. */ ret = dwarf_siblingof(dbg, die, &ret_die, &de); if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de)); else if (ret == DW_DLV_OK) search_func(dbg, ret_die, addr, rlt_func); done: dwarf_dealloc(dbg, die, DW_DLA_DIE); }