summaryrefslogtreecommitdiff
path: root/scripts/gendwarfksyms/gendwarfksyms.c
blob: 08ae61eb327eac7ee402b2464c1114b749daf0a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// 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?");
	}

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