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