xref: /linux/scripts/gendwarfksyms/gendwarfksyms.c (revision ba6ec09911b805778a2fed6d626bfe77b011a717)
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;
24ab443998SSami Tolvanen /* Print out type strings (i.e. type_map) */
25ab443998SSami Tolvanen int dump_types;
2671378888SSami Tolvanen /* Print out expanded type strings used for symbol versions */
2771378888SSami Tolvanen int dump_versions;
28*936cf61cSSami Tolvanen /* Support kABI stability features */
29*936cf61cSSami Tolvanen int stable;
30ab443998SSami Tolvanen /* Write a symtypes file */
31ab443998SSami Tolvanen int symtypes;
32ab443998SSami Tolvanen static const char *symtypes_file;
33f2856884SSami Tolvanen 
usage(void)34f2856884SSami Tolvanen static void usage(void)
35f2856884SSami Tolvanen {
36f2856884SSami Tolvanen 	fputs("Usage: gendwarfksyms [options] elf-object-file ... < symbol-list\n\n"
37f2856884SSami Tolvanen 	      "Options:\n"
38f2856884SSami Tolvanen 	      "  -d, --debug          Print debugging information\n"
39f2856884SSami Tolvanen 	      "      --dump-dies      Dump DWARF DIE contents\n"
40d2ffdc1cSSami Tolvanen 	      "      --dump-die-map   Print debugging information about die_map changes\n"
41ab443998SSami Tolvanen 	      "      --dump-types     Dump type strings\n"
4271378888SSami Tolvanen 	      "      --dump-versions  Dump expanded type strings used for symbol versions\n"
43*936cf61cSSami Tolvanen 	      "  -s, --stable         Support kABI stability features\n"
44ab443998SSami Tolvanen 	      "  -T, --symtypes file  Write a symtypes file\n"
45f2856884SSami Tolvanen 	      "  -h, --help           Print this message\n"
46f2856884SSami Tolvanen 	      "\n",
47f2856884SSami Tolvanen 	      stderr);
48f2856884SSami Tolvanen }
49f2856884SSami Tolvanen 
process_module(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr base,void * arg)50f2856884SSami Tolvanen static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
51f2856884SSami Tolvanen 			  Dwarf_Addr base, void *arg)
52f2856884SSami Tolvanen {
53f2856884SSami Tolvanen 	Dwarf_Addr dwbias;
54f2856884SSami Tolvanen 	Dwarf_Die cudie;
55f2856884SSami Tolvanen 	Dwarf_CU *cu = NULL;
56f2856884SSami Tolvanen 	Dwarf *dbg;
57ab443998SSami Tolvanen 	FILE *symfile = arg;
58f2856884SSami Tolvanen 	int res;
59f2856884SSami Tolvanen 
60f2856884SSami Tolvanen 	debug("%s", name);
61f2856884SSami Tolvanen 	dbg = dwfl_module_getdwarf(mod, &dwbias);
62f2856884SSami Tolvanen 
630c1c7627SSami Tolvanen 	/*
640c1c7627SSami Tolvanen 	 * Look for exported symbols in each CU, follow the DIE tree, and add
650c1c7627SSami Tolvanen 	 * the entries to die_map.
660c1c7627SSami Tolvanen 	 */
67f2856884SSami Tolvanen 	do {
68f2856884SSami Tolvanen 		res = dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL);
69f2856884SSami Tolvanen 		if (res < 0)
70f2856884SSami Tolvanen 			error("dwarf_get_units failed: no debugging information?");
71f2856884SSami Tolvanen 		if (res == 1)
72f2856884SSami Tolvanen 			break; /* No more units */
73f2856884SSami Tolvanen 
74f2856884SSami Tolvanen 		process_cu(&cudie);
75f2856884SSami Tolvanen 	} while (cu);
76f2856884SSami Tolvanen 
77ab443998SSami Tolvanen 	/*
7871378888SSami Tolvanen 	 * Use die_map to expand type strings, write them to `symfile`, and
7971378888SSami Tolvanen 	 * calculate symbol versions.
80ab443998SSami Tolvanen 	 */
8171378888SSami Tolvanen 	generate_symtypes_and_versions(symfile);
820c1c7627SSami Tolvanen 	die_map_free();
830c1c7627SSami Tolvanen 
84f2856884SSami Tolvanen 	return DWARF_CB_OK;
85f2856884SSami Tolvanen }
86f2856884SSami Tolvanen 
87f2856884SSami Tolvanen static const Dwfl_Callbacks callbacks = {
88f2856884SSami Tolvanen 	.section_address = dwfl_offline_section_address,
89f2856884SSami Tolvanen 	.find_debuginfo = dwfl_standard_find_debuginfo,
90f2856884SSami Tolvanen };
91f2856884SSami Tolvanen 
main(int argc,char ** argv)92f2856884SSami Tolvanen int main(int argc, char **argv)
93f2856884SSami Tolvanen {
94ab443998SSami Tolvanen 	FILE *symfile = NULL;
95f2856884SSami Tolvanen 	unsigned int n;
96f2856884SSami Tolvanen 	int opt;
97f2856884SSami Tolvanen 
98f2856884SSami Tolvanen 	static const struct option opts[] = {
99f2856884SSami Tolvanen 		{ "debug", 0, NULL, 'd' },
100f2856884SSami Tolvanen 		{ "dump-dies", 0, &dump_dies, 1 },
101d2ffdc1cSSami Tolvanen 		{ "dump-die-map", 0, &dump_die_map, 1 },
102ab443998SSami Tolvanen 		{ "dump-types", 0, &dump_types, 1 },
10371378888SSami Tolvanen 		{ "dump-versions", 0, &dump_versions, 1 },
104*936cf61cSSami Tolvanen 		{ "stable", 0, NULL, 's' },
105ab443998SSami Tolvanen 		{ "symtypes", 1, NULL, 'T' },
106f2856884SSami Tolvanen 		{ "help", 0, NULL, 'h' },
107f2856884SSami Tolvanen 		{ 0, 0, NULL, 0 }
108f2856884SSami Tolvanen 	};
109f2856884SSami Tolvanen 
110*936cf61cSSami Tolvanen 	while ((opt = getopt_long(argc, argv, "dsT:h", opts, NULL)) != EOF) {
111f2856884SSami Tolvanen 		switch (opt) {
112f2856884SSami Tolvanen 		case 0:
113f2856884SSami Tolvanen 			break;
114f2856884SSami Tolvanen 		case 'd':
115f2856884SSami Tolvanen 			debug = 1;
116f2856884SSami Tolvanen 			break;
117*936cf61cSSami Tolvanen 		case 's':
118*936cf61cSSami Tolvanen 			stable = 1;
119*936cf61cSSami Tolvanen 			break;
120ab443998SSami Tolvanen 		case 'T':
121ab443998SSami Tolvanen 			symtypes = 1;
122ab443998SSami Tolvanen 			symtypes_file = optarg;
123ab443998SSami Tolvanen 			break;
124f2856884SSami Tolvanen 		case 'h':
125f2856884SSami Tolvanen 			usage();
126f2856884SSami Tolvanen 			return 0;
127f2856884SSami Tolvanen 		default:
128f2856884SSami Tolvanen 			usage();
129f2856884SSami Tolvanen 			return 1;
130f2856884SSami Tolvanen 		}
131f2856884SSami Tolvanen 	}
132f2856884SSami Tolvanen 
133d2ffdc1cSSami Tolvanen 	if (dump_die_map)
134d2ffdc1cSSami Tolvanen 		dump_dies = 1;
135d2ffdc1cSSami Tolvanen 
136f2856884SSami Tolvanen 	if (optind >= argc) {
137f2856884SSami Tolvanen 		usage();
138f2856884SSami Tolvanen 		error("no input files?");
139f2856884SSami Tolvanen 	}
140f2856884SSami Tolvanen 
141f2856884SSami Tolvanen 	symbol_read_exports(stdin);
142f2856884SSami Tolvanen 
143ab443998SSami Tolvanen 	if (symtypes_file) {
144ab443998SSami Tolvanen 		symfile = fopen(symtypes_file, "w");
145ab443998SSami Tolvanen 		if (!symfile)
146ab443998SSami Tolvanen 			error("fopen failed for '%s': %s", symtypes_file,
147ab443998SSami Tolvanen 			      strerror(errno));
148ab443998SSami Tolvanen 	}
149ab443998SSami Tolvanen 
150f2856884SSami Tolvanen 	for (n = optind; n < argc; n++) {
151f2856884SSami Tolvanen 		Dwfl *dwfl;
152f2856884SSami Tolvanen 		int fd;
153f2856884SSami Tolvanen 
154f2856884SSami Tolvanen 		fd = open(argv[n], O_RDONLY);
155f2856884SSami Tolvanen 		if (fd == -1)
156f2856884SSami Tolvanen 			error("open failed for '%s': %s", argv[n],
157f2856884SSami Tolvanen 			      strerror(errno));
158f2856884SSami Tolvanen 
159e982abf4SSami Tolvanen 		symbol_read_symtab(fd);
160*936cf61cSSami Tolvanen 		kabi_read_rules(fd);
161e982abf4SSami Tolvanen 
162f2856884SSami Tolvanen 		dwfl = dwfl_begin(&callbacks);
163f2856884SSami Tolvanen 		if (!dwfl)
164f2856884SSami Tolvanen 			error("dwfl_begin failed for '%s': %s", argv[n],
165f2856884SSami Tolvanen 			      dwarf_errmsg(-1));
166f2856884SSami Tolvanen 
167f2856884SSami Tolvanen 		if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd))
168f2856884SSami Tolvanen 			error("dwfl_report_offline failed for '%s': %s",
169f2856884SSami Tolvanen 			      argv[n], dwarf_errmsg(-1));
170f2856884SSami Tolvanen 
171f2856884SSami Tolvanen 		dwfl_report_end(dwfl, NULL, NULL);
172f2856884SSami Tolvanen 
173ab443998SSami Tolvanen 		if (dwfl_getmodules(dwfl, &process_module, symfile, 0))
174f2856884SSami Tolvanen 			error("dwfl_getmodules failed for '%s'", argv[n]);
175f2856884SSami Tolvanen 
176f2856884SSami Tolvanen 		dwfl_end(dwfl);
177*936cf61cSSami Tolvanen 		kabi_free();
178f2856884SSami Tolvanen 	}
179f2856884SSami Tolvanen 
180ab443998SSami Tolvanen 	if (symfile)
181ab443998SSami Tolvanen 		check(fclose(symfile));
182ab443998SSami Tolvanen 
18371378888SSami Tolvanen 	symbol_print_versions();
184f2856884SSami Tolvanen 	symbol_free();
185f2856884SSami Tolvanen 
186f2856884SSami Tolvanen 	return 0;
187f2856884SSami Tolvanen }
188