static Dwarf_Off die_attr_ref(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name) { Dwarf_Off off; if (dwarf_attrval_unsigned(die, name, &off, &dw->dw_err) != DWARF_E_NONE) { terminate("die %llu: failed to get ref: %s\n", die_off(dw, die), dwarf_errmsg(&dw->dw_err)); } return (off); }
static int die_unsigned(dwarf_t *dw, Dwarf_Die die, Dwarf_Half name, Dwarf_Unsigned *valp, int req) { *valp = 0; if (dwarf_attrval_unsigned(die, name, valp, &dw->dw_err) != DWARF_E_NONE) { if (req) terminate("die %llu: failed to get unsigned: %s\n", die_off(dw, die), dwarf_errmsg(&dw->dw_err)); return (0); } return (1); }
bool FLinuxCrashContext::GetInfoForAddress(void * Address, const char **OutFunctionNamePtr, const char **OutSourceFilePtr, int *OutLineNumberPtr) { if (DebugInfo == NULL) { return false; } Dwarf_Die Die; Dwarf_Unsigned Addr = reinterpret_cast< Dwarf_Unsigned >( Address ), LineNumber = 0; const char * SrcFile = NULL; checkAtCompileTime(sizeof(Dwarf_Unsigned) >= sizeof(Address), _Dwarf_Unsigned_type_should_be_long_enough_to_represent_pointers_Check_libdwarf_bitness); int ReturnCode = DW_DLV_OK; Dwarf_Error ErrorInfo; bool bExitHeaderLoop = false; int32 MaxCompileUnitsAllowed = 16 * 1024 * 1024; // safeguard to make sure we never get into an infinite loop const int32 kMaxBufferLinesAllowed = 16 * 1024 * 1024; // safeguard to prevent too long line loop for(;;) { if (--MaxCompileUnitsAllowed <= 0) { fprintf(stderr, "Breaking out from what seems to be an infinite loop during DWARF parsing (too many compile units).\n"); ReturnCode = DW_DLE_DIE_NO_CU_CONTEXT; // invalidate break; } if (bExitHeaderLoop) break; ReturnCode = dwarf_next_cu_header(DebugInfo, NULL, NULL, NULL, NULL, NULL, &ErrorInfo); if (ReturnCode != DW_DLV_OK) break; Die = NULL; while(dwarf_siblingof(DebugInfo, Die, &Die, &ErrorInfo) == DW_DLV_OK) { Dwarf_Half Tag; if (dwarf_tag(Die, &Tag, &ErrorInfo) != DW_DLV_OK) { bExitHeaderLoop = true; break; } if (Tag == DW_TAG_compile_unit) { break; } } if (Die == NULL) { break; } // check if address is inside this CU Dwarf_Unsigned LowerPC, HigherPC; if (!dwarf_attrval_unsigned(Die, DW_AT_low_pc, &LowerPC, &ErrorInfo) && !dwarf_attrval_unsigned(Die, DW_AT_high_pc, &HigherPC, &ErrorInfo)) { if (Addr < LowerPC || Addr >= HigherPC) { continue; } } Dwarf_Line * LineBuf; Dwarf_Signed NumLines = kMaxBufferLinesAllowed; if (dwarf_srclines(Die, &LineBuf, &NumLines, &ErrorInfo) != DW_DLV_OK) { // could not get line info for some reason break; } if (NumLines >= kMaxBufferLinesAllowed) { fprintf(stderr, "Number of lines associated with a DIE looks unreasonable (%ld), early quitting.\n", NumLines); ReturnCode = DW_DLE_DIE_NO_CU_CONTEXT; // invalidate break; } // look which line is that Dwarf_Addr LineAddress, PrevLineAddress = ~0ULL; Dwarf_Unsigned PrevLineNumber = 0; const char * PrevSrcFile = NULL; char * SrcFileTemp = NULL; for (int Idx = 0; Idx < NumLines; ++Idx) { if (dwarf_lineaddr(LineBuf[Idx], &LineAddress, &ErrorInfo) != 0 || dwarf_lineno(LineBuf[Idx], &LineNumber, &ErrorInfo) != 0) { bExitHeaderLoop = true; break; } if (!dwarf_linesrc(LineBuf[Idx], &SrcFileTemp, &ErrorInfo)) { SrcFile = SrcFileTemp; } // check if we hit the exact line if (Addr == LineAddress) { bExitHeaderLoop = true; break; } else if (PrevLineAddress < Addr && Addr < LineAddress) { LineNumber = PrevLineNumber; SrcFile = PrevSrcFile; bExitHeaderLoop = true; break; } PrevLineAddress = LineAddress; PrevLineNumber = LineNumber; PrevSrcFile = SrcFile; } } const char * FunctionName = NULL; if (ReturnCode == DW_DLV_OK) { FindFunctionNameInDIEAndChildren(DebugInfo, Die, Addr, &FunctionName); } if (OutFunctionNamePtr != NULL && FunctionName != NULL) { *OutFunctionNamePtr = FunctionName; } if (OutSourceFilePtr != NULL && SrcFile != NULL) { *OutSourceFilePtr = SrcFile; if (OutLineNumberPtr != NULL) { *OutLineNumberPtr = LineNumber; } } // Resets internal CU pointer, so next time we get here it begins from the start while (ReturnCode != DW_DLV_NO_ENTRY) { if (ReturnCode == DW_DLV_ERROR) break; ReturnCode = dwarf_next_cu_header(DebugInfo, NULL, NULL, NULL, NULL, NULL, &ErrorInfo); } // if we weren't able to find a function name, don't trust the source file either return FunctionName != NULL; }
/** * 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 translate(Dwarf_Debug dbg, const char* addrstr) { Dwarf_Die die, ret_die; Dwarf_Line *lbuf; Dwarf_Error de; Dwarf_Half tag; Dwarf_Unsigned lopc, hipc, addr, lineno, plineno; Dwarf_Signed lcount; Dwarf_Addr lineaddr, plineaddr; char *funcname; char *file, *file0, *pfile; char demangled[1024]; int i, ret; addr = strtoull(addrstr, NULL, 16); addr += section_base; lineno = 0; file = unknown; die = NULL; lbuf = NULL; lcount = 0; while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de)) == DW_DLV_OK) { die = NULL; while (dwarf_siblingof(dbg, die, &ret_die, &de) == DW_DLV_OK) { if (die != NULL) dwarf_dealloc(dbg, die, DW_DLA_DIE); die = ret_die; if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) { warnx("dwarf_tag failed: %s", dwarf_errmsg(de)); goto next_cu; } /* XXX: What about DW_TAG_partial_unit? */ if (tag == DW_TAG_compile_unit) break; } if (ret_die == NULL) { warnx("could not find DW_TAG_compile_unit die"); goto next_cu; } if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) && !dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) { /* * Check if the address falls into the PC range of * this CU. */ if (handle_high_pc(die, lopc, &hipc) != DW_DLV_OK) goto next_cu; if (addr < lopc || addr >= hipc) goto next_cu; } switch (dwarf_srclines(die, &lbuf, &lcount, &de)) { case DW_DLV_OK: break; case DW_DLV_NO_ENTRY: /* If a CU lacks debug info, just skip it. */ goto next_cu; default: warnx("dwarf_srclines: %s", dwarf_errmsg(de)); goto out; } plineaddr = ~0ULL; plineno = 0; pfile = unknown; for (i = 0; i < lcount; i++) { if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) { warnx("dwarf_lineaddr: %s", dwarf_errmsg(de)); goto out; } if (dwarf_lineno(lbuf[i], &lineno, &de)) { warnx("dwarf_lineno: %s", dwarf_errmsg(de)); goto out; } if (dwarf_linesrc(lbuf[i], &file0, &de)) { warnx("dwarf_linesrc: %s", dwarf_errmsg(de)); } else file = file0; if (addr == lineaddr) goto out; else if (addr < lineaddr && addr > plineaddr) { lineno = plineno; file = pfile; goto out; } plineaddr = lineaddr; plineno = lineno; pfile = file; } next_cu: if (die != NULL) { dwarf_dealloc(dbg, die, DW_DLA_DIE); die = NULL; } } out: funcname = NULL; if (ret == DW_DLV_OK && func) { search_func(dbg, die, addr, &funcname); die = NULL; } if (func) { if (funcname == NULL) if ((funcname = strdup(unknown)) == NULL) err(EXIT_FAILURE, "strdup"); if (demangle && !elftc_demangle(funcname, demangled, sizeof(demangled), 0)) printf("%s\n", demangled); else printf("%s\n", funcname); free(funcname); } (void) printf("%s:%ju\n", base ? basename(file) : file, lineno); if (die != NULL) dwarf_dealloc(dbg, die, DW_DLA_DIE); /* * Reset internal CU pointer, so we will start from the first CU * next round. */ while (ret != DW_DLV_NO_ENTRY) { if (ret == DW_DLV_ERROR) errx(EXIT_FAILURE, "dwarf_next_cu_header: %s", dwarf_errmsg(de)); ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL, &de); } }
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); }