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