gendwarfksyms.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2024 Google LLC
  4. */
  5. #include <fcntl.h>
  6. #include <getopt.h>
  7. #include <errno.h>
  8. #include <stdarg.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include "gendwarfksyms.h"
  12. /*
  13. * Options
  14. */
  15. /* Print debugging information to stderr */
  16. int debug;
  17. /* Dump DIE contents */
  18. int dump_dies;
  19. /* Print debugging information about die_map changes */
  20. int dump_die_map;
  21. /* Print out type strings (i.e. type_map) */
  22. int dump_types;
  23. /* Print out expanded type strings used for symbol versions */
  24. int dump_versions;
  25. /* Support kABI stability features */
  26. int stable;
  27. /* Write a symtypes file */
  28. int symtypes;
  29. static const char *symtypes_file;
  30. static void usage(void)
  31. {
  32. fputs("Usage: gendwarfksyms [options] elf-object-file ... < symbol-list\n\n"
  33. "Options:\n"
  34. " -d, --debug Print debugging information\n"
  35. " --dump-dies Dump DWARF DIE contents\n"
  36. " --dump-die-map Print debugging information about die_map changes\n"
  37. " --dump-types Dump type strings\n"
  38. " --dump-versions Dump expanded type strings used for symbol versions\n"
  39. " -s, --stable Support kABI stability features\n"
  40. " -T, --symtypes file Write a symtypes file\n"
  41. " -h, --help Print this message\n"
  42. "\n",
  43. stderr);
  44. }
  45. static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
  46. Dwarf_Addr base, void *arg)
  47. {
  48. Dwarf_Addr dwbias;
  49. Dwarf_Die cudie;
  50. Dwarf_CU *cu = NULL;
  51. Dwarf *dbg;
  52. FILE *symfile = arg;
  53. int res;
  54. debug("%s", name);
  55. dbg = dwfl_module_getdwarf(mod, &dwbias);
  56. /*
  57. * Look for exported symbols in each CU, follow the DIE tree, and add
  58. * the entries to die_map.
  59. */
  60. do {
  61. res = dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL);
  62. if (res < 0)
  63. error("dwarf_get_units failed: no debugging information?");
  64. if (res == 1)
  65. break; /* No more units */
  66. process_cu(&cudie);
  67. } while (cu);
  68. /*
  69. * Use die_map to expand type strings, write them to `symfile`, and
  70. * calculate symbol versions.
  71. */
  72. generate_symtypes_and_versions(symfile);
  73. die_map_free();
  74. return DWARF_CB_OK;
  75. }
  76. static const Dwfl_Callbacks callbacks = {
  77. .section_address = dwfl_offline_section_address,
  78. .find_debuginfo = dwfl_standard_find_debuginfo,
  79. };
  80. int main(int argc, char **argv)
  81. {
  82. FILE *symfile = NULL;
  83. unsigned int n;
  84. int opt;
  85. static const struct option opts[] = {
  86. { "debug", 0, NULL, 'd' },
  87. { "dump-dies", 0, &dump_dies, 1 },
  88. { "dump-die-map", 0, &dump_die_map, 1 },
  89. { "dump-types", 0, &dump_types, 1 },
  90. { "dump-versions", 0, &dump_versions, 1 },
  91. { "stable", 0, NULL, 's' },
  92. { "symtypes", 1, NULL, 'T' },
  93. { "help", 0, NULL, 'h' },
  94. { 0, 0, NULL, 0 }
  95. };
  96. while ((opt = getopt_long(argc, argv, "dsT:h", opts, NULL)) != EOF) {
  97. switch (opt) {
  98. case 0:
  99. break;
  100. case 'd':
  101. debug = 1;
  102. break;
  103. case 's':
  104. stable = 1;
  105. break;
  106. case 'T':
  107. symtypes = 1;
  108. symtypes_file = optarg;
  109. break;
  110. case 'h':
  111. usage();
  112. return 0;
  113. default:
  114. usage();
  115. return 1;
  116. }
  117. }
  118. if (dump_die_map)
  119. dump_dies = 1;
  120. if (optind >= argc) {
  121. usage();
  122. error("no input files?");
  123. }
  124. if (!symbol_read_exports(stdin))
  125. return 0;
  126. if (symtypes_file) {
  127. symfile = fopen(symtypes_file, "w");
  128. if (!symfile)
  129. error("fopen failed for '%s': %s", symtypes_file,
  130. strerror(errno));
  131. }
  132. for (n = optind; n < argc; n++) {
  133. Dwfl *dwfl;
  134. int fd;
  135. fd = open(argv[n], O_RDONLY);
  136. if (fd == -1)
  137. error("open failed for '%s': %s", argv[n],
  138. strerror(errno));
  139. symbol_read_symtab(fd);
  140. kabi_read_rules(fd);
  141. dwfl = dwfl_begin(&callbacks);
  142. if (!dwfl)
  143. error("dwfl_begin failed for '%s': %s", argv[n],
  144. dwarf_errmsg(-1));
  145. if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd))
  146. error("dwfl_report_offline failed for '%s': %s",
  147. argv[n], dwarf_errmsg(-1));
  148. dwfl_report_end(dwfl, NULL, NULL);
  149. if (dwfl_getmodules(dwfl, &process_module, symfile, 0))
  150. error("dwfl_getmodules failed for '%s'", argv[n]);
  151. dwfl_end(dwfl);
  152. kabi_free();
  153. }
  154. if (symfile)
  155. check(fclose(symfile));
  156. symbol_print_versions();
  157. symbol_free();
  158. return 0;
  159. }