| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // 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 = { .size = 0};
- /* Try to open distro debuginfo files */
- dso = dso__new(path);
- if (!dso)
- goto out;
- /*
- * Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO. Don't block
- * incase the path isn't for a regular file.
- */
- assert(!dso__has_build_id(dso));
- if (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 (dinfo)
- return dinfo;
- /* if failed to open all distro debuginfo, open given binary */
- symbol__join_symfs(buf, path);
- return __debuginfo__new(buf);
- }
- 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_SUPPORT
- int 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 */
|