mirror of https://github.com/torvalds/linux.git
189 lines
4.1 KiB
C
189 lines
4.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2024 Google LLC
|
|
*/
|
|
|
|
#include <fcntl.h>
|
|
#include <getopt.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#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?");
|
|
}
|
|
|
|
if (!symbol_read_exports(stdin))
|
|
return 0;
|
|
|
|
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;
|
|
}
|