205 lines · 4.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * DWARF debug information handling code.  Copied from probe-finder.c. * * Written by Masami Hiramatsu <mhiramat@redhat.com> */ #include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <linux/zalloc.h> #include "build-id.h"#include "dso.h"#include "debug.h"#include "debuginfo.h"#include "symbol.h" #ifdef HAVE_DEBUGINFOD_SUPPORT#include <elfutils/debuginfod.h>#endif /* Dwarf FL wrappers */static char *debuginfo_path;	/* Currently dummy */ static const Dwfl_Callbacks offline_callbacks = {	.find_debuginfo = dwfl_standard_find_debuginfo,	.debuginfo_path = &debuginfo_path, 	.section_address = dwfl_offline_section_address, 	/* We use this table for core files too.  */	.find_elf = dwfl_build_id_find_elf,}; /* Get a Dwarf from offline image */static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,					 const char *path){	GElf_Addr dummy;	int fd; 	fd = open(path, O_RDONLY);	if (fd < 0)		return fd; 	dbg->dwfl = dwfl_begin(&offline_callbacks);	if (!dbg->dwfl)		goto error; 	dwfl_report_begin(dbg->dwfl);	dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);	if (!dbg->mod)		goto error; 	dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);	if (!dbg->dbg)		goto error; 	dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); 	dwfl_report_end(dbg->dwfl, NULL, NULL); 	return 0;error:	if (dbg->dwfl)		dwfl_end(dbg->dwfl);	else		close(fd);	memset(dbg, 0, sizeof(*dbg)); 	return -ENOENT;} static struct debuginfo *__debuginfo__new(const char *path){	struct debuginfo *dbg = zalloc(sizeof(*dbg));	if (!dbg)		return NULL; 	if (debuginfo__init_offline_dwarf(dbg, path) < 0)		zfree(&dbg);	if (dbg)		pr_debug("Open Debuginfo file: %s\n", path);	return dbg;} enum dso_binary_type distro_dwarf_types[] = {	DSO_BINARY_TYPE__FEDORA_DEBUGINFO,	DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,	DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,	DSO_BINARY_TYPE__BUILDID_DEBUGINFO,	DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,	DSO_BINARY_TYPE__NOT_FOUND,}; struct debuginfo *debuginfo__new(const char *path){	enum dso_binary_type *type;	char buf[PATH_MAX], nil = '\0';	struct dso *dso;	struct debuginfo *dinfo = NULL;	struct build_id bid; 	/* Try to open distro debuginfo files */	dso = dso__new(path);	if (!dso)		goto out; 	/* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */	if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0)		dso__set_build_id(dso, &bid); 	for (type = distro_dwarf_types;	     !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;	     type++) {		if (dso__read_binary_type_filename(dso, *type, &nil,						   buf, PATH_MAX) < 0)			continue;		dinfo = __debuginfo__new(buf);	}	dso__put(dso); out:	/* if failed to open all distro debuginfo, open given binary */	return dinfo ? : __debuginfo__new(path);} void debuginfo__delete(struct debuginfo *dbg){	if (dbg) {		if (dbg->dwfl)			dwfl_end(dbg->dwfl);		free(dbg);	}} /* For the kernel module, we need a special code to get a DIE */int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,				bool adjust_offset){	int n, i;	Elf32_Word shndx;	Elf_Scn *scn;	Elf *elf;	GElf_Shdr mem, *shdr;	const char *p; 	elf = dwfl_module_getelf(dbg->mod, &dbg->bias);	if (!elf)		return -EINVAL; 	/* Get the number of relocations */	n = dwfl_module_relocations(dbg->mod);	if (n < 0)		return -ENOENT;	/* Search the relocation related .text section */	for (i = 0; i < n; i++) {		p = dwfl_module_relocation_info(dbg->mod, i, &shndx);		if (strcmp(p, ".text") == 0) {			/* OK, get the section header */			scn = elf_getscn(elf, shndx);			if (!scn)				return -ENOENT;			shdr = gelf_getshdr(scn, &mem);			if (!shdr)				return -ENOENT;			*offs = shdr->sh_addr;			if (adjust_offset)				*offs -= shdr->sh_offset;		}	}	return 0;} #ifdef HAVE_DEBUGINFOD_SUPPORTint get_source_from_debuginfod(const char *raw_path,			       const char *sbuild_id, char **new_path){	debuginfod_client *c = debuginfod_begin();	const char *p = raw_path;	int fd; 	if (!c)		return -ENOMEM; 	fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,				0, p, new_path);	pr_debug("Search %s from debuginfod -> %d\n", p, fd);	if (fd >= 0)		close(fd);	debuginfod_end(c);	if (fd < 0) {		pr_debug("Failed to find %s in debuginfod (%s)\n",			raw_path, sbuild_id);		return -ENOENT;	}	pr_debug("Got a source %s\n", *new_path); 	return 0;}#endif /* HAVE_DEBUGINFOD_SUPPORT */