projects/linux·blob master · refs

215 lines · 4.7 KiB

1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * DWARF debug information handling code. Copied from probe-finder.c.
4 *
5 * Written by Masami Hiramatsu <[email protected]>
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_SUPPORT
23#include <elfutils/debuginfod.h>
24#endif
25
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 bool fd_consumed = false;
46
47 fd = open(path, O_RDONLY);
48 if (fd < 0)
49 return fd;
50
51 dbg->dwfl = dwfl_begin(&offline_callbacks);
52 if (!dbg->dwfl)
53 goto error;
54
55 dwfl_report_begin(dbg->dwfl);
56 dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
57 if (!dbg->mod)
58 goto error;
59 fd_consumed = true;
60
61 dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
62 if (!dbg->dbg)
63 goto error;
64
65 dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);
66
67 if (dwfl_report_end(dbg->dwfl, NULL, NULL) != 0)
68 goto error;
69
70 return 0;
71error:
72 if (dbg->dwfl)
73 dwfl_end(dbg->dwfl);
74 if (!fd_consumed)
75 close(fd);
76 memset(dbg, 0, sizeof(*dbg));
77
78 return -ENOENT;
79}
80
81static struct debuginfo *__debuginfo__new(const char *path)
82{
83 struct debuginfo *dbg = zalloc(sizeof(*dbg));
84 if (!dbg)
85 return NULL;
86
87 if (debuginfo__init_offline_dwarf(dbg, path) < 0)
88 zfree(&dbg);
89 if (dbg)
90 pr_debug("Open Debuginfo file: %s\n", path);
91 return dbg;
92}
93
94struct debuginfo *debuginfo__new(const char *path)
95{
96 static const enum dso_binary_type distro_dwarf_types[] = {
97 DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
98 DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
99 DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
100 DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
101 DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
102 DSO_BINARY_TYPE__NOT_FOUND,
103 };
104 const enum dso_binary_type *type;
105 char buf[PATH_MAX], nil = '\0';
106 struct dso *dso;
107 struct debuginfo *dinfo = NULL;
108 struct build_id bid = { .size = 0};
109
110 /* Try to open distro debuginfo files */
111 dso = dso__new(path);
112 if (!dso)
113 goto out;
114
115 /*
116 * Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO. Don't block
117 * incase the path isn't for a regular file.
118 */
119 assert(!dso__has_build_id(dso));
120 if (filename__read_build_id(path, &bid) > 0)
121 dso__set_build_id(dso, &bid);
122
123 for (type = distro_dwarf_types;
124 !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
125 type++) {
126 if (dso__read_binary_type_filename(dso, *type, &nil,
127 buf, PATH_MAX) < 0)
128 continue;
129 dinfo = __debuginfo__new(buf);
130 }
131 dso__put(dso);
132
133out:
134 if (dinfo)
135 return dinfo;
136
137 /* if failed to open all distro debuginfo, open given binary */
138 symbol__join_symfs(buf, path);
139 return __debuginfo__new(buf);
140}
141
142void debuginfo__delete(struct debuginfo *dbg)
143{
144 if (dbg) {
145 if (dbg->dwfl)
146 dwfl_end(dbg->dwfl);
147 free(dbg);
148 }
149}
150
151/* For the kernel module, we need a special code to get a DIE */
152int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
153 bool adjust_offset)
154{
155 int n, i;
156 Elf32_Word shndx;
157 Elf_Scn *scn;
158 Elf *elf;
159 GElf_Shdr mem, *shdr;
160 const char *p;
161
162 elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
163 if (!elf)
164 return -EINVAL;
165
166 /* Get the number of relocations */
167 n = dwfl_module_relocations(dbg->mod);
168 if (n < 0)
169 return -ENOENT;
170 /* Search the relocation related .text section */
171 for (i = 0; i < n; i++) {
172 p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
173 if (p && strcmp(p, ".text") == 0) {
174 /* OK, get the section header */
175 scn = elf_getscn(elf, shndx);
176 if (!scn)
177 return -ENOENT;
178 shdr = gelf_getshdr(scn, &mem);
179 if (!shdr)
180 return -ENOENT;
181 *offs = shdr->sh_addr;
182 if (adjust_offset)
183 *offs -= shdr->sh_offset;
184 }
185 }
186 return 0;
187}
188
189#ifdef HAVE_DEBUGINFOD_SUPPORT
190int get_source_from_debuginfod(const char *raw_path,
191 const char *sbuild_id, char **new_path)
192{
193 debuginfod_client *c = debuginfod_begin();
194 const char *p = raw_path;
195 int fd;
196
197 if (!c)
198 return -ENOMEM;
199
200 fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
201 0, p, new_path);
202 pr_debug("Search %s from debuginfod -> %d\n", p, fd);
203 if (fd >= 0)
204 close(fd);
205 debuginfod_end(c);
206 if (fd < 0) {
207 pr_debug("Failed to find %s in debuginfod (%s)\n",
208 raw_path, sbuild_id);
209 return -ENOENT;
210 }
211 pr_debug("Got a source %s\n", *new_path);
212
213 return 0;
214}
215#endif /* HAVE_DEBUGINFOD_SUPPORT */