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 symbol_read_exports(stdin);
142
143 if (symtypes_file) {
144 symfile = fopen(symtypes_file, "w");
145 if (!symfile)
146 error("fopen failed for '%s': %s", symtypes_file,
147 strerror(errno));
148 }
149
150 for (n = optind; n < argc; n++) {
151 Dwfl *dwfl;
152 int fd;
153
154 fd = open(argv[n], O_RDONLY);
155 if (fd == -1)
156 error("open failed for '%s': %s", argv[n],
157 strerror(errno));
158
159 symbol_read_symtab(fd);
160 kabi_read_rules(fd);
161
162 dwfl = dwfl_begin(&callbacks);
163 if (!dwfl)
164 error("dwfl_begin failed for '%s': %s", argv[n],
165 dwarf_errmsg(-1));
166
167 if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd))
168 error("dwfl_report_offline failed for '%s': %s",
169 argv[n], dwarf_errmsg(-1));
170
171 dwfl_report_end(dwfl, NULL, NULL);
172
173 if (dwfl_getmodules(dwfl, &process_module, symfile, 0))
174 error("dwfl_getmodules failed for '%s'", argv[n]);
175
176 dwfl_end(dwfl);
177 kabi_free();
178 }
179
180 if (symfile)
181 check(fclose(symfile));
182
183 symbol_print_versions();
184 symbol_free();
185
186 return 0;
187 }
188