File Index
Files and directories
Sign in
FILE

debuginfo.c

File preview with syntax highlighting.

linux-6.19.14/tools/perf/util/debuginfo.c 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 <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_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
 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	else
 72		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 = { .size = 0};
107
108	/* Try to open distro debuginfo files */
109	dso = dso__new(path);
110	if (!dso)
111		goto out;
112
113	/*
114	 * Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO. Don't block
115	 * incase the path isn't for a regular file.
116	 */
117	assert(!dso__has_build_id(dso));
118	if (filename__read_build_id(path, &bid) > 0)
119		dso__set_build_id(dso, &bid);
120
121	for (type = distro_dwarf_types;
122	     !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
123	     type++) {
124		if (dso__read_binary_type_filename(dso, *type, &nil,
125						   buf, PATH_MAX) < 0)
126			continue;
127		dinfo = __debuginfo__new(buf);
128	}
129	dso__put(dso);
130
131out:
132	if (dinfo)
133		return dinfo;
134
135	/* if failed to open all distro debuginfo, open given binary */
136	symbol__join_symfs(buf, path);
137	return __debuginfo__new(buf);
138}
139
140void debuginfo__delete(struct debuginfo *dbg)
141{
142	if (dbg) {
143		if (dbg->dwfl)
144			dwfl_end(dbg->dwfl);
145		free(dbg);
146	}
147}
148
149/* For the kernel module, we need a special code to get a DIE */
150int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
151				bool adjust_offset)
152{
153	int n, i;
154	Elf32_Word shndx;
155	Elf_Scn *scn;
156	Elf *elf;
157	GElf_Shdr mem, *shdr;
158	const char *p;
159
160	elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
161	if (!elf)
162		return -EINVAL;
163
164	/* Get the number of relocations */
165	n = dwfl_module_relocations(dbg->mod);
166	if (n < 0)
167		return -ENOENT;
168	/* Search the relocation related .text section */
169	for (i = 0; i < n; i++) {
170		p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
171		if (strcmp(p, ".text") == 0) {
172			/* OK, get the section header */
173			scn = elf_getscn(elf, shndx);
174			if (!scn)
175				return -ENOENT;
176			shdr = gelf_getshdr(scn, &mem);
177			if (!shdr)
178				return -ENOENT;
179			*offs = shdr->sh_addr;
180			if (adjust_offset)
181				*offs -= shdr->sh_offset;
182		}
183	}
184	return 0;
185}
186
187#ifdef HAVE_DEBUGINFOD_SUPPORT
188int get_source_from_debuginfod(const char *raw_path,
189			       const char *sbuild_id, char **new_path)
190{
191	debuginfod_client *c = debuginfod_begin();
192	const char *p = raw_path;
193	int fd;
194
195	if (!c)
196		return -ENOMEM;
197
198	fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
199				0, p, new_path);
200	pr_debug("Search %s from debuginfod -> %d\n", p, fd);
201	if (fd >= 0)
202		close(fd);
203	debuginfod_end(c);
204	if (fd < 0) {
205		pr_debug("Failed to find %s in debuginfod (%s)\n",
206			raw_path, sbuild_id);
207		return -ENOENT;
208	}
209	pr_debug("Got a source %s\n", *new_path);
210
211	return 0;
212}
213#endif /* HAVE_DEBUGINFOD_SUPPORT */
~/ Read-only file preview.