diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index fdf4202bfa..900fa59083 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -74,6 +74,9 @@ efi-y := $(shell if [ ! -r $(BASEDIR)/include/xen/compile.h -o \ ifdef CONFIG_XSPLICE all_symbols = --all-symbols +ifdef CONFIG_FAST_SYMBOL_LOOKUP +all_symbols = --all-symbols --sort-by-name +endif else all_symbols = endif diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 692ef51d12..e4f86c2906 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -200,4 +200,16 @@ config XSPLICE If unsure, say Y. +config FAST_SYMBOL_LOOKUP + bool "Fast symbol lookup (bigger binary)" + default y + depends on XSPLICE + ---help--- + When searching for symbol addresses we can use the built-in system + that is optimized for searching symbols using addresses as the key. + However using it for the inverse (find address using the symbol name) + it is slow. This extra data and code (~55kB) speeds up the search. + The only user of this is xSplice. + + If unsure, say Y. endmenu diff --git a/xen/common/symbols-dummy.c b/xen/common/symbols-dummy.c index 5090c3b4d7..044dfd3399 100644 --- a/xen/common/symbols-dummy.c +++ b/xen/common/symbols-dummy.c @@ -5,6 +5,7 @@ #include #include +#include #ifdef SYMBOLS_ORIGIN const unsigned int symbols_offsets[1]; @@ -14,6 +15,10 @@ const unsigned long symbols_addresses[1]; const unsigned int symbols_num_syms; const u8 symbols_names[1]; +#ifdef CONFIG_FAST_SYMBOL_LOOKUP +const struct symbol_offset symbols_sorted_offsets[1]; +#endif + const u8 symbols_token_table[1]; const u16 symbols_token_index[1]; diff --git a/xen/common/symbols.c b/xen/common/symbols.c index e02a2afa86..12765d3f34 100644 --- a/xen/common/symbols.c +++ b/xen/common/symbols.c @@ -31,6 +31,8 @@ extern const unsigned long symbols_addresses[]; extern const unsigned int symbols_num_syms; extern const u8 symbols_names[]; +extern const struct symbol_offset symbols_sorted_offsets[]; + extern const u8 symbols_token_table[]; extern const u16 symbols_token_index[]; @@ -211,14 +213,39 @@ int xensyms_read(uint32_t *symnum, char *type, unsigned long symbols_lookup_by_name(const char *symname) { char name[KSYM_NAME_LEN + 1]; +#ifdef CONFIG_FAST_SYMBOL_LOOKUP + unsigned long low, high; +#else uint32_t symnum = 0; char type; unsigned long addr; int rc; +#endif if ( *symname == '\0' ) return 0; +#ifdef CONFIG_FAST_SYMBOL_LOOKUP + low = 0; + high = symbols_num_syms; + while ( low < high ) + { + unsigned long mid = low + ((high - low) / 2); + const struct symbol_offset *s; + int rc; + + s = &symbols_sorted_offsets[mid]; + (void)symbols_expand_symbol(s->stream, name); + /* Format is: [filename]#. symbols_expand_symbol eats type.*/ + rc = strcmp(symname, name); + if ( rc < 0 ) + high = mid; + else if ( rc > 0 ) + low = mid + 1; + else + return symbols_address(s->addr); + } +#else do { rc = xensyms_read(&symnum, &type, &addr, name); if ( rc ) @@ -229,6 +256,7 @@ unsigned long symbols_lookup_by_name(const char *symname) } while ( name[0] != '\0' ); +#endif return 0; } diff --git a/xen/include/xen/symbols.h b/xen/include/xen/symbols.h index 015fcb46fb..20bbb28ef2 100644 --- a/xen/include/xen/symbols.h +++ b/xen/include/xen/symbols.h @@ -25,4 +25,12 @@ int xensyms_read(uint32_t *symnum, char *type, unsigned long symbols_lookup_by_name(const char *symname); +/* + * A sorted (by symbols) lookup table table to symbols_names (stream) + * and symbols_address (or offset). + */ +struct symbol_offset { + uint32_t stream; /* .. in the compressed stream.*/ + uint32_t addr; /* .. and in the fixed size address array. */ +}; #endif /*_XEN_SYMBOLS_H*/ diff --git a/xen/tools/symbols.c b/xen/tools/symbols.c index 196db742bd..941fbe7c11 100644 --- a/xen/tools/symbols.c +++ b/xen/tools/symbols.c @@ -40,6 +40,10 @@ struct sym_entry { unsigned long long addr; unsigned int len; unsigned char *sym; + char *orig_symbol; + unsigned int addr_idx; + unsigned int stream_offset; + unsigned char type; }; #define SYMBOL_NAME(s) ((char *)(s)->sym + 1) @@ -47,8 +51,10 @@ static struct sym_entry *table; static unsigned int table_size, table_cnt; static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext; static int all_symbols = 0; +static int sort_by_name = 0; static char symbol_prefix_char = '\0'; static enum { fmt_bsd, fmt_sysv } input_format; +static int compare_name(const void *p1, const void *p2); int token_profit[0x10000]; @@ -175,8 +181,11 @@ static int read_symbol(FILE *in, struct sym_entry *s) *sym++ = '#'; } strcpy(sym, str); + if (sort_by_name) { + s->orig_symbol = strdup(SYMBOL_NAME(s)); + s->type = stype; /* As s->sym[0] ends mangled. */ + } s->sym[0] = stype; - rc = 0; skip_tail: @@ -276,6 +285,21 @@ static int expand_symbol(unsigned char *data, int len, char *result) return total; } +/* Sort by original (non mangled) symbol name, then type. */ +static int compare_name_orig(const void *p1, const void *p2) +{ + const struct sym_entry *sym1 = p1; + const struct sym_entry *sym2 = p2; + int rc; + + rc = strcmp(sym1->orig_symbol, sym2->orig_symbol); + + if (!rc) + rc = sym1->type - sym2->type; + + return rc; +} + static void write_src(void) { unsigned int i, k, off; @@ -325,6 +349,7 @@ static void write_src(void) printf(", 0x%02x", table[i].sym[k]); printf("\n"); + table[i].stream_offset = off; off += table[i].len + 1; } printf("\n"); @@ -334,7 +359,6 @@ static void write_src(void) printf("\t.long\t%d\n", markers[i]); printf("\n"); - free(markers); output_label("symbols_token_table"); off = 0; @@ -350,6 +374,25 @@ static void write_src(void) for (i = 0; i < 256; i++) printf("\t.short\t%d\n", best_idx[i]); printf("\n"); + + if (!sort_by_name) { + free(markers); + return; + } + + /* Sorted by original symbol names and type. */ + qsort(table, table_cnt, sizeof(*table), compare_name_orig); + + output_label("symbols_sorted_offsets"); + /* A fixed sized array with two entries: offset in the + * compressed stream (for symbol name), and offset in + * symbols_addresses (or symbols_offset). */ + for (i = 0; i < table_cnt; i++) { + printf("\t.long %u, %u\n", table[i].stream_offset, table[i].addr_idx); + } + printf("\n"); + + free(markers); } @@ -410,6 +453,7 @@ static void compress_symbols(unsigned char *str, int idx) len = table[i].len; p1 = table[i].sym; + table[i].addr_idx = i; /* find the token on the symbol */ p2 = memmem_pvt(p1, len, str, 2); if (!p2) continue; @@ -561,6 +605,8 @@ int main(int argc, char **argv) input_format = fmt_sysv; else if (strcmp(argv[i], "--sort") == 0) unsorted = true; + else if (strcmp(argv[i], "--sort-by-name") == 0) + sort_by_name = 1; else if (strcmp(argv[i], "--warn-dup") == 0) warn_dup = true; else