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 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 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 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