// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2024 Google LLC */ #include #include #include #include #include #include #include "gendwarfksyms.h" /* * Options */ /* Print debugging information to stderr */ int debug; /* Dump DIE contents */ int dump_dies; /* Print debugging information about die_map changes */ int dump_die_map; /* Print out type strings (i.e. type_map) */ int dump_types; /* Print out expanded type strings used for symbol versions */ int dump_versions; /* Support kABI stability features */ int stable; /* Write a symtypes file */ int symtypes; static const char *symtypes_file; static void usage(void) { fputs("Usage: gendwarfksyms [options] elf-object-file ... < symbol-list\n\n" "Options:\n" " -d, --debug Print debugging information\n" " --dump-dies Dump DWARF DIE contents\n" " --dump-die-map Print debugging information about die_map changes\n" " --dump-types Dump type strings\n" " --dump-versions Dump expanded type strings used for symbol versions\n" " -s, --stable Support kABI stability features\n" " -T, --symtypes file Write a symtypes file\n" " -h, --help Print this message\n" "\n", stderr); } static int process_module(Dwfl_Module *mod, void **userdata, const char *name, Dwarf_Addr base, void *arg) { Dwarf_Addr dwbias; Dwarf_Die cudie; Dwarf_CU *cu = NULL; Dwarf *dbg; FILE *symfile = arg; int res; debug("%s", name); dbg = dwfl_module_getdwarf(mod, &dwbias); /* * Look for exported symbols in each CU, follow the DIE tree, and add * the entries to die_map. */ do { res = dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL); if (res < 0) error("dwarf_get_units failed: no debugging information?"); if (res == 1) break; /* No more units */ process_cu(&cudie); } while (cu); /* * Use die_map to expand type strings, write them to `symfile`, and * calculate symbol versions. */ generate_symtypes_and_versions(symfile); die_map_free(); return DWARF_CB_OK; } static const Dwfl_Callbacks callbacks = { .section_address = dwfl_offline_section_address, .find_debuginfo = dwfl_standard_find_debuginfo, }; int main(int argc, char **argv) { FILE *symfile = NULL; unsigned int n; int opt; static const struct option opts[] = { { "debug", 0, NULL, 'd' }, { "dump-dies", 0, &dump_dies, 1 }, { "dump-die-map", 0, &dump_die_map, 1 }, { "dump-types", 0, &dump_types, 1 }, { "dump-versions", 0, &dump_versions, 1 }, { "stable", 0, NULL, 's' }, { "symtypes", 1, NULL, 'T' }, { "help", 0, NULL, 'h' }, { 0, 0, NULL, 0 } }; while ((opt = getopt_long(argc, argv, "dsT:h", opts, NULL)) != EOF) { switch (opt) { case 0: break; case 'd': debug = 1; break; case 's': stable = 1; break; case 'T': symtypes = 1; symtypes_file = optarg; break; case 'h': usage(); return 0; default: usage(); return 1; } } if (dump_die_map) dump_dies = 1; if (optind >= argc) { usage(); error("no input files?"); } symbol_read_exports(stdin); if (symtypes_file) { symfile = fopen(symtypes_file, "w"); if (!symfile) error("fopen failed for '%s': %s", symtypes_file, strerror(errno)); } for (n = optind; n < argc; n++) { Dwfl *dwfl; int fd; fd = open(argv[n], O_RDONLY); if (fd == -1) error("open failed for '%s': %s", argv[n], strerror(errno)); symbol_read_symtab(fd); kabi_read_rules(fd); dwfl = dwfl_begin(&callbacks); if (!dwfl) error("dwfl_begin failed for '%s': %s", argv[n], dwarf_errmsg(-1)); if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd)) error("dwfl_report_offline failed for '%s': %s", argv[n], dwarf_errmsg(-1)); dwfl_report_end(dwfl, NULL, NULL); if (dwfl_getmodules(dwfl, &process_module, symfile, 0)) error("dwfl_getmodules failed for '%s'", argv[n]); dwfl_end(dwfl); kabi_free(); } if (symfile) check(fclose(symfile)); symbol_print_versions(); symbol_free(); return 0; }