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

gendwarfksyms: Add symbol versioning



Calculate symbol versions from the fully expanded type strings in
type_map, and output the versions in a genksyms-compatible format.

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 ab443998
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8,4 +8,4 @@ gendwarfksyms-objs += dwarf.o
gendwarfksyms-objs += symbols.o
gendwarfksyms-objs += types.o

HOSTLDLIBS_gendwarfksyms := -ldw -lelf
HOSTLDLIBS_gendwarfksyms := -ldw -lelf -lz
+23 −2
Original line number Diff line number Diff line
@@ -740,12 +740,33 @@ static int process_type(struct state *state, struct die *parent, Dwarf_Die *die)
/*
 * Exported symbol processing
 */
static struct die *get_symbol_cache(struct state *state, Dwarf_Die *die)
{
	struct die *cache;

	cache = die_map_get(die, DIE_SYMBOL);

	if (cache->state != DIE_INCOMPLETE)
		return NULL; /* We already processed a symbol for this DIE */

	cache->tag = dwarf_tag(die);
	return cache;
}

static void process_symbol(struct state *state, Dwarf_Die *die,
			   die_callback_t process_func)
{
	struct die *cache;

	symbol_set_die(state->sym, die);

	cache = get_symbol_cache(state, die);
	if (!cache)
		return;

	debug("%s", state->sym->name);
	check(process_func(state, NULL, die));
	state->sym->state = SYMBOL_MAPPED;
	check(process_func(state, cache, die));
	cache->state = DIE_SYMBOL;
	if (dump_dies)
		fputs("\n", stderr);
}
+8 −2
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ int dump_dies;
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;
/* Write a symtypes file */
int symtypes;
static const char *symtypes_file;
@@ -35,6 +37,7 @@ static void usage(void)
	      "      --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"
	      "  -T, --symtypes file  Write a symtypes file\n"
	      "  -h, --help           Print this message\n"
	      "\n",
@@ -69,9 +72,10 @@ static int process_module(Dwfl_Module *mod, void **userdata, const char *name,
	} while (cu);

	/*
	 * Use die_map to expand type strings and write them to `symfile`.
	 * Use die_map to expand type strings, write them to `symfile`, and
	 * calculate symbol versions.
	 */
	generate_symtypes(symfile);
	generate_symtypes_and_versions(symfile);
	die_map_free();

	return DWARF_CB_OK;
@@ -93,6 +97,7 @@ int main(int argc, char **argv)
		{ "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 },
		{ "symtypes", 1, NULL, 'T' },
		{ "help", 0, NULL, 'h' },
		{ 0, 0, NULL, 0 }
@@ -166,6 +171,7 @@ int main(int argc, char **argv)
	if (symfile)
		check(fclose(symfile));

	symbol_print_versions();
	symbol_free();

	return 0;
+11 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ extern int debug;
extern int dump_dies;
extern int dump_die_map;
extern int dump_types;
extern int dump_versions;
extern int symtypes;

/*
@@ -95,6 +96,7 @@ static inline unsigned int addr_hash(uintptr_t addr)
enum symbol_state {
	SYMBOL_UNPROCESSED,
	SYMBOL_MAPPED,
	SYMBOL_PROCESSED
};

struct symbol_addr {
@@ -109,6 +111,7 @@ struct symbol {
	struct hlist_node name_hash;
	enum symbol_state state;
	uintptr_t die_addr;
	unsigned long crc;
};

typedef void (*symbol_callback_t)(struct symbol *, void *arg);
@@ -116,6 +119,10 @@ typedef void (*symbol_callback_t)(struct symbol *, void *arg);
void symbol_read_exports(FILE *file);
void symbol_read_symtab(int fd);
struct symbol *symbol_get(const char *name);
void symbol_set_die(struct symbol *sym, Dwarf_Die *die);
void symbol_set_crc(struct symbol *sym, unsigned long crc);
void symbol_for_each(symbol_callback_t func, void *arg);
void symbol_print_versions(void);
void symbol_free(void);

/*
@@ -126,7 +133,8 @@ enum die_state {
	DIE_INCOMPLETE,
	DIE_UNEXPANDED,
	DIE_COMPLETE,
	DIE_LAST = DIE_COMPLETE
	DIE_SYMBOL,
	DIE_LAST = DIE_SYMBOL
};

enum die_fragment_type {
@@ -156,6 +164,7 @@ static inline const char *die_state_name(enum die_state state)
	CASE_CONST_TO_STR(DIE_INCOMPLETE)
	CASE_CONST_TO_STR(DIE_UNEXPANDED)
	CASE_CONST_TO_STR(DIE_COMPLETE)
	CASE_CONST_TO_STR(DIE_SYMBOL)
	}

	error("unexpected die_state: %d", state);
@@ -252,6 +261,6 @@ void process_cu(Dwarf_Die *cudie);
 * types.c
 */

void generate_symtypes(FILE *file);
void generate_symtypes_and_versions(FILE *file);

#endif /* __GENDWARFKSYMS_H */
+53 −0
Original line number Diff line number Diff line
@@ -66,6 +66,36 @@ static unsigned int for_each(const char *name, symbol_callback_t func,
	return 0;
}

static void set_crc(struct symbol *sym, void *data)
{
	unsigned long *crc = data;

	if (sym->state == SYMBOL_PROCESSED && sym->crc != *crc)
		warn("overriding version for symbol %s (crc %lx vs. %lx)",
		     sym->name, sym->crc, *crc);

	sym->state = SYMBOL_PROCESSED;
	sym->crc = *crc;
}

void symbol_set_crc(struct symbol *sym, unsigned long crc)
{
	if (for_each(sym->name, set_crc, &crc) == 0)
		error("no matching symbols: '%s'", sym->name);
}

static void set_die(struct symbol *sym, void *data)
{
	sym->die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
	sym->state = SYMBOL_MAPPED;
}

void symbol_set_die(struct symbol *sym, Dwarf_Die *die)
{
	if (for_each(sym->name, set_die, die) == 0)
		error("no matching symbols: '%s'", sym->name);
}

static bool is_exported(const char *name)
{
	return for_each(name, NULL, NULL) > 0;
@@ -120,6 +150,16 @@ struct symbol *symbol_get(const char *name)
	return sym;
}

void symbol_for_each(symbol_callback_t func, void *arg)
{
	struct hlist_node *tmp;
	struct symbol *sym;

	hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
		func(sym, arg);
	}
}

typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym,
				      Elf32_Word xndx, void *arg);

@@ -246,6 +286,19 @@ void symbol_read_symtab(int fd)
	elf_for_each_global(fd, elf_set_symbol_addr, NULL);
}

void symbol_print_versions(void)
{
	struct hlist_node *tmp;
	struct symbol *sym;

	hash_for_each_safe(symbol_names, sym, tmp, name_hash) {
		if (sym->state != SYMBOL_PROCESSED)
			warn("no information for symbol %s", sym->name);

		printf("#SYMVER %s 0x%08lx\n", sym->name, sym->crc);
	}
}

void symbol_free(void)
{
	struct hlist_node *tmp;
Loading