xref: /linux/scripts/gendwarfksyms/gendwarfksyms.c (revision ab4439981f8549b013f4ea0b274b7c77c88ab4bc)
1f2856884SSami Tolvanen // SPDX-License-Identifier: GPL-2.0
2f2856884SSami Tolvanen /*
3f2856884SSami Tolvanen  * Copyright (C) 2024 Google LLC
4f2856884SSami Tolvanen  */
5f2856884SSami Tolvanen 
6f2856884SSami Tolvanen #include <fcntl.h>
7f2856884SSami Tolvanen #include <getopt.h>
8f2856884SSami Tolvanen #include <errno.h>
9f2856884SSami Tolvanen #include <stdarg.h>
10f2856884SSami Tolvanen #include <string.h>
11f2856884SSami Tolvanen #include <unistd.h>
12f2856884SSami Tolvanen #include "gendwarfksyms.h"
13f2856884SSami Tolvanen 
14f2856884SSami Tolvanen /*
15f2856884SSami Tolvanen  * Options
16f2856884SSami Tolvanen  */
17f2856884SSami Tolvanen 
18f2856884SSami Tolvanen /* Print debugging information to stderr */
19f2856884SSami Tolvanen int debug;
20f2856884SSami Tolvanen /* Dump DIE contents */
21f2856884SSami Tolvanen int dump_dies;
22d2ffdc1cSSami Tolvanen /* Print debugging information about die_map changes */
23d2ffdc1cSSami Tolvanen int dump_die_map;
24*ab443998SSami Tolvanen /* Print out type strings (i.e. type_map) */
25*ab443998SSami Tolvanen int dump_types;
26*ab443998SSami Tolvanen /* Write a symtypes file */
27*ab443998SSami Tolvanen int symtypes;
28*ab443998SSami Tolvanen static const char *symtypes_file;
29f2856884SSami Tolvanen 
30f2856884SSami Tolvanen static void usage(void)
31f2856884SSami Tolvanen {
32f2856884SSami Tolvanen 	fputs("Usage: gendwarfksyms [options] elf-object-file ... < symbol-list\n\n"
33f2856884SSami Tolvanen 	      "Options:\n"
34f2856884SSami Tolvanen 	      "  -d, --debug          Print debugging information\n"
35f2856884SSami Tolvanen 	      "      --dump-dies      Dump DWARF DIE contents\n"
36d2ffdc1cSSami Tolvanen 	      "      --dump-die-map   Print debugging information about die_map changes\n"
37*ab443998SSami Tolvanen 	      "      --dump-types     Dump type strings\n"
38*ab443998SSami Tolvanen 	      "  -T, --symtypes file  Write a symtypes file\n"
39f2856884SSami Tolvanen 	      "  -h, --help           Print this message\n"
40f2856884SSami Tolvanen 	      "\n",
41f2856884SSami Tolvanen 	      stderr);
42f2856884SSami Tolvanen }
43f2856884SSami Tolvanen 
44f2856884SSami Tolvanen static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
45f2856884SSami Tolvanen 			  Dwarf_Addr base, void *arg)
46f2856884SSami Tolvanen {
47f2856884SSami Tolvanen 	Dwarf_Addr dwbias;
48f2856884SSami Tolvanen 	Dwarf_Die cudie;
49f2856884SSami Tolvanen 	Dwarf_CU *cu = NULL;
50f2856884SSami Tolvanen 	Dwarf *dbg;
51*ab443998SSami Tolvanen 	FILE *symfile = arg;
52f2856884SSami Tolvanen 	int res;
53f2856884SSami Tolvanen 
54f2856884SSami Tolvanen 	debug("%s", name);
55f2856884SSami Tolvanen 	dbg = dwfl_module_getdwarf(mod, &dwbias);
56f2856884SSami Tolvanen 
570c1c7627SSami Tolvanen 	/*
580c1c7627SSami Tolvanen 	 * Look for exported symbols in each CU, follow the DIE tree, and add
590c1c7627SSami Tolvanen 	 * the entries to die_map.
600c1c7627SSami Tolvanen 	 */
61f2856884SSami Tolvanen 	do {
62f2856884SSami Tolvanen 		res = dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL);
63f2856884SSami Tolvanen 		if (res < 0)
64f2856884SSami Tolvanen 			error("dwarf_get_units failed: no debugging information?");
65f2856884SSami Tolvanen 		if (res == 1)
66f2856884SSami Tolvanen 			break; /* No more units */
67f2856884SSami Tolvanen 
68f2856884SSami Tolvanen 		process_cu(&cudie);
69f2856884SSami Tolvanen 	} while (cu);
70f2856884SSami Tolvanen 
71*ab443998SSami Tolvanen 	/*
72*ab443998SSami Tolvanen 	 * Use die_map to expand type strings and write them to `symfile`.
73*ab443998SSami Tolvanen 	 */
74*ab443998SSami Tolvanen 	generate_symtypes(symfile);
750c1c7627SSami Tolvanen 	die_map_free();
760c1c7627SSami Tolvanen 
77f2856884SSami Tolvanen 	return DWARF_CB_OK;
78f2856884SSami Tolvanen }
79f2856884SSami Tolvanen 
80f2856884SSami Tolvanen static const Dwfl_Callbacks callbacks = {
81f2856884SSami Tolvanen 	.section_address = dwfl_offline_section_address,
82f2856884SSami Tolvanen 	.find_debuginfo = dwfl_standard_find_debuginfo,
83f2856884SSami Tolvanen };
84f2856884SSami Tolvanen 
85f2856884SSami Tolvanen int main(int argc, char **argv)
86f2856884SSami Tolvanen {
87*ab443998SSami Tolvanen 	FILE *symfile = NULL;
88f2856884SSami Tolvanen 	unsigned int n;
89f2856884SSami Tolvanen 	int opt;
90f2856884SSami Tolvanen 
91f2856884SSami Tolvanen 	static const struct option opts[] = {
92f2856884SSami Tolvanen 		{ "debug", 0, NULL, 'd' },
93f2856884SSami Tolvanen 		{ "dump-dies", 0, &dump_dies, 1 },
94d2ffdc1cSSami Tolvanen 		{ "dump-die-map", 0, &dump_die_map, 1 },
95*ab443998SSami Tolvanen 		{ "dump-types", 0, &dump_types, 1 },
96*ab443998SSami Tolvanen 		{ "symtypes", 1, NULL, 'T' },
97f2856884SSami Tolvanen 		{ "help", 0, NULL, 'h' },
98f2856884SSami Tolvanen 		{ 0, 0, NULL, 0 }
99f2856884SSami Tolvanen 	};
100f2856884SSami Tolvanen 
101*ab443998SSami Tolvanen 	while ((opt = getopt_long(argc, argv, "dT:h", opts, NULL)) != EOF) {
102f2856884SSami Tolvanen 		switch (opt) {
103f2856884SSami Tolvanen 		case 0:
104f2856884SSami Tolvanen 			break;
105f2856884SSami Tolvanen 		case 'd':
106f2856884SSami Tolvanen 			debug = 1;
107f2856884SSami Tolvanen 			break;
108*ab443998SSami Tolvanen 		case 'T':
109*ab443998SSami Tolvanen 			symtypes = 1;
110*ab443998SSami Tolvanen 			symtypes_file = optarg;
111*ab443998SSami Tolvanen 			break;
112f2856884SSami Tolvanen 		case 'h':
113f2856884SSami Tolvanen 			usage();
114f2856884SSami Tolvanen 			return 0;
115f2856884SSami Tolvanen 		default:
116f2856884SSami Tolvanen 			usage();
117f2856884SSami Tolvanen 			return 1;
118f2856884SSami Tolvanen 		}
119f2856884SSami Tolvanen 	}
120f2856884SSami Tolvanen 
121d2ffdc1cSSami Tolvanen 	if (dump_die_map)
122d2ffdc1cSSami Tolvanen 		dump_dies = 1;
123d2ffdc1cSSami Tolvanen 
124f2856884SSami Tolvanen 	if (optind >= argc) {
125f2856884SSami Tolvanen 		usage();
126f2856884SSami Tolvanen 		error("no input files?");
127f2856884SSami Tolvanen 	}
128f2856884SSami Tolvanen 
129f2856884SSami Tolvanen 	symbol_read_exports(stdin);
130f2856884SSami Tolvanen 
131*ab443998SSami Tolvanen 	if (symtypes_file) {
132*ab443998SSami Tolvanen 		symfile = fopen(symtypes_file, "w");
133*ab443998SSami Tolvanen 		if (!symfile)
134*ab443998SSami Tolvanen 			error("fopen failed for '%s': %s", symtypes_file,
135*ab443998SSami Tolvanen 			      strerror(errno));
136*ab443998SSami Tolvanen 	}
137*ab443998SSami Tolvanen 
138f2856884SSami Tolvanen 	for (n = optind; n < argc; n++) {
139f2856884SSami Tolvanen 		Dwfl *dwfl;
140f2856884SSami Tolvanen 		int fd;
141f2856884SSami Tolvanen 
142f2856884SSami Tolvanen 		fd = open(argv[n], O_RDONLY);
143f2856884SSami Tolvanen 		if (fd == -1)
144f2856884SSami Tolvanen 			error("open failed for '%s': %s", argv[n],
145f2856884SSami Tolvanen 			      strerror(errno));
146f2856884SSami Tolvanen 
147e982abf4SSami Tolvanen 		symbol_read_symtab(fd);
148e982abf4SSami Tolvanen 
149f2856884SSami Tolvanen 		dwfl = dwfl_begin(&callbacks);
150f2856884SSami Tolvanen 		if (!dwfl)
151f2856884SSami Tolvanen 			error("dwfl_begin failed for '%s': %s", argv[n],
152f2856884SSami Tolvanen 			      dwarf_errmsg(-1));
153f2856884SSami Tolvanen 
154f2856884SSami Tolvanen 		if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd))
155f2856884SSami Tolvanen 			error("dwfl_report_offline failed for '%s': %s",
156f2856884SSami Tolvanen 			      argv[n], dwarf_errmsg(-1));
157f2856884SSami Tolvanen 
158f2856884SSami Tolvanen 		dwfl_report_end(dwfl, NULL, NULL);
159f2856884SSami Tolvanen 
160*ab443998SSami Tolvanen 		if (dwfl_getmodules(dwfl, &process_module, symfile, 0))
161f2856884SSami Tolvanen 			error("dwfl_getmodules failed for '%s'", argv[n]);
162f2856884SSami Tolvanen 
163f2856884SSami Tolvanen 		dwfl_end(dwfl);
164f2856884SSami Tolvanen 	}
165f2856884SSami Tolvanen 
166*ab443998SSami Tolvanen 	if (symfile)
167*ab443998SSami Tolvanen 		check(fclose(symfile));
168*ab443998SSami Tolvanen 
169f2856884SSami Tolvanen 	symbol_free();
170f2856884SSami Tolvanen 
171f2856884SSami Tolvanen 	return 0;
172f2856884SSami Tolvanen }
173