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