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