206 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * DWARF debug information handling code. Copied from probe-finder.c.4 *5 * Written by Masami Hiramatsu <mhiramat@redhat.com>6 */7 8#include <errno.h>9#include <fcntl.h>10#include <stdio.h>11#include <stdlib.h>12#include <string.h>13#include <unistd.h>14#include <linux/zalloc.h>15 16#include "build-id.h"17#include "dso.h"18#include "debug.h"19#include "debuginfo.h"20#include "symbol.h"21 22#ifdef HAVE_DEBUGINFOD_SUPPORT23#include <elfutils/debuginfod.h>24#endif25 26/* Dwarf FL wrappers */27static char *debuginfo_path; /* Currently dummy */28 29static const Dwfl_Callbacks offline_callbacks = {30 .find_debuginfo = dwfl_standard_find_debuginfo,31 .debuginfo_path = &debuginfo_path,32 33 .section_address = dwfl_offline_section_address,34 35 /* We use this table for core files too. */36 .find_elf = dwfl_build_id_find_elf,37};38 39/* Get a Dwarf from offline image */40static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,41 const char *path)42{43 GElf_Addr dummy;44 int fd;45 46 fd = open(path, O_RDONLY);47 if (fd < 0)48 return fd;49 50 dbg->dwfl = dwfl_begin(&offline_callbacks);51 if (!dbg->dwfl)52 goto error;53 54 dwfl_report_begin(dbg->dwfl);55 dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);56 if (!dbg->mod)57 goto error;58 59 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);60 if (!dbg->dbg)61 goto error;62 63 dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);64 65 dwfl_report_end(dbg->dwfl, NULL, NULL);66 67 return 0;68error:69 if (dbg->dwfl)70 dwfl_end(dbg->dwfl);71 else72 close(fd);73 memset(dbg, 0, sizeof(*dbg));74 75 return -ENOENT;76}77 78static struct debuginfo *__debuginfo__new(const char *path)79{80 struct debuginfo *dbg = zalloc(sizeof(*dbg));81 if (!dbg)82 return NULL;83 84 if (debuginfo__init_offline_dwarf(dbg, path) < 0)85 zfree(&dbg);86 if (dbg)87 pr_debug("Open Debuginfo file: %s\n", path);88 return dbg;89}90 91enum dso_binary_type distro_dwarf_types[] = {92 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,93 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,94 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,95 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,96 DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,97 DSO_BINARY_TYPE__NOT_FOUND,98};99 100struct debuginfo *debuginfo__new(const char *path)101{102 enum dso_binary_type *type;103 char buf[PATH_MAX], nil = '\0';104 struct dso *dso;105 struct debuginfo *dinfo = NULL;106 struct build_id bid;107 108 /* Try to open distro debuginfo files */109 dso = dso__new(path);110 if (!dso)111 goto out;112 113 /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */114 if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0)115 dso__set_build_id(dso, &bid);116 117 for (type = distro_dwarf_types;118 !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;119 type++) {120 if (dso__read_binary_type_filename(dso, *type, &nil,121 buf, PATH_MAX) < 0)122 continue;123 dinfo = __debuginfo__new(buf);124 }125 dso__put(dso);126 127out:128 /* if failed to open all distro debuginfo, open given binary */129 return dinfo ? : __debuginfo__new(path);130}131 132void debuginfo__delete(struct debuginfo *dbg)133{134 if (dbg) {135 if (dbg->dwfl)136 dwfl_end(dbg->dwfl);137 free(dbg);138 }139}140 141/* For the kernel module, we need a special code to get a DIE */142int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,143 bool adjust_offset)144{145 int n, i;146 Elf32_Word shndx;147 Elf_Scn *scn;148 Elf *elf;149 GElf_Shdr mem, *shdr;150 const char *p;151 152 elf = dwfl_module_getelf(dbg->mod, &dbg->bias);153 if (!elf)154 return -EINVAL;155 156 /* Get the number of relocations */157 n = dwfl_module_relocations(dbg->mod);158 if (n < 0)159 return -ENOENT;160 /* Search the relocation related .text section */161 for (i = 0; i < n; i++) {162 p = dwfl_module_relocation_info(dbg->mod, i, &shndx);163 if (strcmp(p, ".text") == 0) {164 /* OK, get the section header */165 scn = elf_getscn(elf, shndx);166 if (!scn)167 return -ENOENT;168 shdr = gelf_getshdr(scn, &mem);169 if (!shdr)170 return -ENOENT;171 *offs = shdr->sh_addr;172 if (adjust_offset)173 *offs -= shdr->sh_offset;174 }175 }176 return 0;177}178 179#ifdef HAVE_DEBUGINFOD_SUPPORT180int get_source_from_debuginfod(const char *raw_path,181 const char *sbuild_id, char **new_path)182{183 debuginfod_client *c = debuginfod_begin();184 const char *p = raw_path;185 int fd;186 187 if (!c)188 return -ENOMEM;189 190 fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,191 0, p, new_path);192 pr_debug("Search %s from debuginfod -> %d\n", p, fd);193 if (fd >= 0)194 close(fd);195 debuginfod_end(c);196 if (fd < 0) {197 pr_debug("Failed to find %s in debuginfod (%s)\n",198 raw_path, sbuild_id);199 return -ENOENT;200 }201 pr_debug("Got a source %s\n", *new_path);202 203 return 0;204}205#endif /* HAVE_DEBUGINFOD_SUPPORT */206