예제 #1
0
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);
}
예제 #2
0
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;
}
예제 #5
0
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);
	}
}
예제 #6
0
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);
}