]> Git Repo - J-linux.git/blob - tools/perf/util/debuginfo.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / perf / util / debuginfo.c
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 */
27 static char *debuginfo_path;    /* Currently dummy */
28
29 static 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 */
40 static 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;
68 error:
69         if (dbg->dwfl)
70                 dwfl_end(dbg->dwfl);
71         else
72                 close(fd);
73         memset(dbg, 0, sizeof(*dbg));
74
75         return -ENOENT;
76 }
77
78 static 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
91 enum 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
100 struct 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
127 out:
128         /* if failed to open all distro debuginfo, open given binary */
129         return dinfo ? : __debuginfo__new(path);
130 }
131
132 void 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 */
142 int 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_SUPPORT
180 int 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 */
This page took 0.033924 seconds and 4 git commands to generate.