Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | // 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_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 */ |