Commit ab443998 authored by Sami Tolvanen's avatar Sami Tolvanen Committed by Masahiro Yamada
Browse files

gendwarfksyms: Add symtypes output



Add support for producing genksyms-style symtypes files. Process
die_map to find the longest expansions for each type, and use symtypes
references in type definitions. The basic file format is similar to
genksyms, with two notable exceptions:

  1. Type names with spaces (common with Rust) in references are
     wrapped in single quotes. E.g.:

     s#'core::result::Result<u8, core::num::error::ParseIntError>'

  2. The actual type definition is the simple parsed DWARF format we
     output with --dump-dies, not the preprocessed C-style format
     genksyms produces.

Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
Reviewed-by: default avatarPetr Pavlu <petr.pavlu@suse.com>
Signed-off-by: default avatarMasahiro Yamada <masahiroy@kernel.org>
parent d2ffdc1c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,5 +6,6 @@ gendwarfksyms-objs += cache.o
gendwarfksyms-objs += die.o
gendwarfksyms-objs += dwarf.o
gendwarfksyms-objs += symbols.o
gendwarfksyms-objs += types.o

HOSTLDLIBS_gendwarfksyms := -ldw -lelf
+11 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ static inline unsigned int die_hash(uintptr_t addr, enum die_state state)
static void init_die(struct die *cd)
{
	cd->state = DIE_INCOMPLETE;
	cd->mapped = false;
	cd->fqn = NULL;
	cd->tag = -1;
	cd->addr = 0;
@@ -83,6 +84,16 @@ static void reset_die(struct die *cd)
	init_die(cd);
}

void die_map_for_each(die_map_callback_t func, void *arg)
{
	struct hlist_node *tmp;
	struct die *cd;

	hash_for_each_safe(die_map, cd, tmp, hash) {
		func(cd, arg);
	}
}

void die_map_free(void)
{
	struct hlist_node *tmp;
+1 −0
Original line number Diff line number Diff line
@@ -745,6 +745,7 @@ static void process_symbol(struct state *state, Dwarf_Die *die,
{
	debug("%s", state->sym->name);
	check(process_func(state, NULL, die));
	state->sym->state = SYMBOL_MAPPED;
	if (dump_dies)
		fputs("\n", stderr);
}
+31 −2
Original line number Diff line number Diff line
@@ -21,6 +21,11 @@ int debug;
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;
/* Write a symtypes file */
int symtypes;
static const char *symtypes_file;

static void usage(void)
{
@@ -29,6 +34,8 @@ static void usage(void)
	      "  -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"
	      "  -T, --symtypes file  Write a symtypes file\n"
	      "  -h, --help           Print this message\n"
	      "\n",
	      stderr);
@@ -41,6 +48,7 @@ static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
	Dwarf_Die cudie;
	Dwarf_CU *cu = NULL;
	Dwarf *dbg;
	FILE *symfile = arg;
	int res;

	debug("%s", name);
@@ -60,6 +68,10 @@ static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
		process_cu(&cudie);
	} while (cu);

	/*
	 * Use die_map to expand type strings and write them to `symfile`.
	 */
	generate_symtypes(symfile);
	die_map_free();

	return DWARF_CB_OK;
@@ -72,6 +84,7 @@ static const Dwfl_Callbacks callbacks = {

int main(int argc, char **argv)
{
	FILE *symfile = NULL;
	unsigned int n;
	int opt;

@@ -79,17 +92,23 @@ int main(int argc, char **argv)
		{ "debug", 0, NULL, 'd' },
		{ "dump-dies", 0, &dump_dies, 1 },
		{ "dump-die-map", 0, &dump_die_map, 1 },
		{ "dump-types", 0, &dump_types, 1 },
		{ "symtypes", 1, NULL, 'T' },
		{ "help", 0, NULL, 'h' },
		{ 0, 0, NULL, 0 }
	};

	while ((opt = getopt_long(argc, argv, "dh", opts, NULL)) != EOF) {
	while ((opt = getopt_long(argc, argv, "dT:h", opts, NULL)) != EOF) {
		switch (opt) {
		case 0:
			break;
		case 'd':
			debug = 1;
			break;
		case 'T':
			symtypes = 1;
			symtypes_file = optarg;
			break;
		case 'h':
			usage();
			return 0;
@@ -109,6 +128,13 @@ int main(int argc, char **argv)

	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;
@@ -131,12 +157,15 @@ int main(int argc, char **argv)

		dwfl_report_end(dwfl, NULL, NULL);

		if (dwfl_getmodules(dwfl, &process_module, NULL, 0))
		if (dwfl_getmodules(dwfl, &process_module, symfile, 0))
			error("dwfl_getmodules failed for '%s'", argv[n]);

		dwfl_end(dwfl);
	}

	if (symfile)
		check(fclose(symfile));

	symbol_free();

	return 0;
+19 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
extern int debug;
extern int dump_dies;
extern int dump_die_map;
extern int dump_types;
extern int symtypes;

/*
 * Output helpers
@@ -90,6 +92,11 @@ static inline unsigned int addr_hash(uintptr_t addr)
	return hash_ptr((const void *)addr);
}

enum symbol_state {
	SYMBOL_UNPROCESSED,
	SYMBOL_MAPPED,
};

struct symbol_addr {
	uint32_t section;
	Elf64_Addr address;
@@ -100,6 +107,8 @@ struct symbol {
	struct symbol_addr addr;
	struct hlist_node addr_hash;
	struct hlist_node name_hash;
	enum symbol_state state;
	uintptr_t die_addr;
};

typedef void (*symbol_callback_t)(struct symbol *, void *arg);
@@ -154,6 +163,7 @@ static inline const char *die_state_name(enum die_state state)

struct die {
	enum die_state state;
	bool mapped;
	char *fqn;
	int tag;
	uintptr_t addr;
@@ -161,10 +171,13 @@ struct die {
	struct hlist_node hash;
};

typedef void (*die_map_callback_t)(struct die *, void *arg);

int __die_map_get(uintptr_t addr, enum die_state state, struct die **res);
struct die *die_map_get(Dwarf_Die *die, enum die_state state);
void die_map_add_string(struct die *pd, const char *str);
void die_map_add_linebreak(struct die *pd, int linebreak);
void die_map_for_each(die_map_callback_t func, void *arg);
void die_map_add_die(struct die *pd, struct die *child);
void die_map_free(void);

@@ -235,4 +248,10 @@ int process_die_container(struct state *state, struct die *cache,

void process_cu(Dwarf_Die *cudie);

/*
 * types.c
 */

void generate_symtypes(FILE *file);

#endif /* __GENDWARFKSYMS_H */
Loading