Commit 49918a752b739041c7afb205f7158e61c0874267

Authored by pbrook
1 parent f16a0db3

* Use function pointers for symbol lookup (currently for elf32 and elf64,

could be expanded).  This also fixes the bug with mips elf64 symbols
  in current Qemu trunk.

* Use quicksort and binary search for symbol lookup.

* Remove unneeded entries from symbol table.  This reduced a typical table
  size (linux mips kernel) from 1764487 to 11656 entries.

Signed-off-by: Stefan Weil <weil@mail.berlios.de> 



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5510 c046a42c-6fe2-441c-8c8c-71466251a162
@@ -303,33 +303,17 @@ void disas(FILE *out, void *code, unsigned long size) @@ -303,33 +303,17 @@ void disas(FILE *out, void *code, unsigned long size)
303 /* Look up symbol for debugging purpose. Returns "" if unknown. */ 303 /* Look up symbol for debugging purpose. Returns "" if unknown. */
304 const char *lookup_symbol(target_ulong orig_addr) 304 const char *lookup_symbol(target_ulong orig_addr)
305 { 305 {
306 - unsigned int i;  
307 - /* Hack, because we know this is x86. */  
308 - Elf32_Sym *sym; 306 + const char *symbol = "";
309 struct syminfo *s; 307 struct syminfo *s;
310 - target_ulong addr;  
311 308
312 for (s = syminfos; s; s = s->next) { 309 for (s = syminfos; s; s = s->next) {
313 - sym = s->disas_symtab;  
314 - for (i = 0; i < s->disas_num_syms; i++) {  
315 - if (sym[i].st_shndx == SHN_UNDEF  
316 - || sym[i].st_shndx >= SHN_LORESERVE)  
317 - continue;  
318 -  
319 - if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)  
320 - continue;  
321 -  
322 - addr = sym[i].st_value;  
323 -#if defined(TARGET_ARM) || defined (TARGET_MIPS)  
324 - /* The bottom address bit marks a Thumb or MIPS16 symbol. */  
325 - addr &= ~(target_ulong)1;  
326 -#endif  
327 - if (orig_addr >= addr  
328 - && orig_addr < addr + sym[i].st_size)  
329 - return s->disas_strtab + sym[i].st_name;  
330 - } 310 + symbol = s->lookup_symbol(s, orig_addr);
  311 + if (symbol[0] != '\0') {
  312 + break;
  313 + }
331 } 314 }
332 - return ""; 315 +
  316 + return symbol;
333 } 317 }
334 318
335 #if !defined(CONFIG_USER_ONLY) 319 #if !defined(CONFIG_USER_ONLY)
@@ -10,12 +10,24 @@ void monitor_disas(CPUState *env, @@ -10,12 +10,24 @@ void monitor_disas(CPUState *env,
10 /* Look up symbol for debugging purpose. Returns "" if unknown. */ 10 /* Look up symbol for debugging purpose. Returns "" if unknown. */
11 const char *lookup_symbol(target_ulong orig_addr); 11 const char *lookup_symbol(target_ulong orig_addr);
12 12
13 -/* Filled in by elfload.c. Simplistic, but will do for now. */  
14 -extern struct syminfo { 13 +struct syminfo;
  14 +struct elf32_sym;
  15 +struct elf64_sym;
  16 +
  17 +typedef const char *(*lookup_symbol_t)(struct syminfo *s, target_ulong orig_addr);
  18 +
  19 +struct syminfo {
  20 + lookup_symbol_t lookup_symbol;
15 unsigned int disas_num_syms; 21 unsigned int disas_num_syms;
16 - void *disas_symtab; 22 + union {
  23 + struct elf32_sym *elf32;
  24 + struct elf64_sym *elf64;
  25 + } disas_symtab;
17 const char *disas_strtab; 26 const char *disas_strtab;
18 struct syminfo *next; 27 struct syminfo *next;
19 -} *syminfos; 28 +};
  29 +
  30 +/* Filled in by elfload.c. Simplistic, but will do for now. */
  31 +extern struct syminfo *syminfos;
20 32
21 #endif /* _QEMU_DISAS_H */ 33 #endif /* _QEMU_DISAS_H */
elf_ops.h
@@ -60,13 +60,48 @@ static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, @@ -60,13 +60,48 @@ static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
60 return NULL; 60 return NULL;
61 } 61 }
62 62
  63 +static int glue(symfind, SZ)(const void *s0, const void *s1)
  64 +{
  65 + struct elf_sym *key = (struct elf_sym *)s0;
  66 + struct elf_sym *sym = (struct elf_sym *)s1;
  67 + int result = 0;
  68 + if (key->st_value < sym->st_value) {
  69 + result = -1;
  70 + } else if (key->st_value > sym->st_value + sym->st_size) {
  71 + result = 1;
  72 + }
  73 + return result;
  74 +}
  75 +
  76 +static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr)
  77 +{
  78 + struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
  79 + struct elf_sym key;
  80 + struct elf_sym *sym;
  81 +
  82 + key.st_value = orig_addr;
  83 +
  84 + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
  85 + if (sym != 0) {
  86 + return s->disas_strtab + sym->st_name;
  87 + }
  88 +
  89 + return "";
  90 +}
  91 +
  92 +static int glue(symcmp, SZ)(const void *s0, const void *s1)
  93 +{
  94 + struct elf_sym *sym0 = (struct elf_sym *)s0;
  95 + struct elf_sym *sym1 = (struct elf_sym *)s1;
  96 + return (sym0->st_value < sym1->st_value)
  97 + ? -1
  98 + : ((sym0->st_value > sym1->st_value) ? 1 : 0);
  99 +}
  100 +
63 static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) 101 static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
64 { 102 {
65 struct elf_shdr *symtab, *strtab, *shdr_table = NULL; 103 struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
66 struct elf_sym *syms = NULL; 104 struct elf_sym *syms = NULL;
67 -#if (SZ == 64)  
68 - struct elf32_sym *syms32 = NULL;  
69 -#endif  
70 struct syminfo *s; 105 struct syminfo *s;
71 int nsyms, i; 106 int nsyms, i;
72 char *str = NULL; 107 char *str = NULL;
@@ -90,21 +125,32 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) @@ -90,21 +125,32 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
90 goto fail; 125 goto fail;
91 126
92 nsyms = symtab->sh_size / sizeof(struct elf_sym); 127 nsyms = symtab->sh_size / sizeof(struct elf_sym);
93 -#if (SZ == 64)  
94 - syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym));  
95 -#endif  
96 - for (i = 0; i < nsyms; i++) { 128 +
  129 + i = 0;
  130 + while (i < nsyms) {
97 if (must_swab) 131 if (must_swab)
98 glue(bswap_sym, SZ)(&syms[i]); 132 glue(bswap_sym, SZ)(&syms[i]);
99 -#if (SZ == 64)  
100 - syms32[i].st_name = syms[i].st_name;  
101 - syms32[i].st_info = syms[i].st_info;  
102 - syms32[i].st_other = syms[i].st_other;  
103 - syms32[i].st_shndx = syms[i].st_shndx;  
104 - syms32[i].st_value = syms[i].st_value & 0xffffffff;  
105 - syms32[i].st_size = syms[i].st_size & 0xffffffff; 133 + /* We are only interested in function symbols.
  134 + Throw everything else away. */
  135 + if (syms[i].st_shndx == SHN_UNDEF ||
  136 + syms[i].st_shndx >= SHN_LORESERVE ||
  137 + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
  138 + nsyms--;
  139 + if (i < nsyms) {
  140 + syms[i] = syms[nsyms];
  141 + }
  142 + continue;
  143 + }
  144 +#if defined(TARGET_ARM) || defined (TARGET_MIPS)
  145 + /* The bottom address bit marks a Thumb or MIPS16 symbol. */
  146 + syms[i].st_value &= ~(target_ulong)1;
106 #endif 147 #endif
  148 + i++;
107 } 149 }
  150 + syms = qemu_realloc(syms, nsyms * sizeof(*syms));
  151 +
  152 + qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
  153 +
108 /* String table */ 154 /* String table */
109 if (symtab->sh_link >= ehdr->e_shnum) 155 if (symtab->sh_link >= ehdr->e_shnum)
110 goto fail; 156 goto fail;
@@ -112,16 +158,12 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) @@ -112,16 +158,12 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
112 158
113 str = load_at(fd, strtab->sh_offset, strtab->sh_size); 159 str = load_at(fd, strtab->sh_offset, strtab->sh_size);
114 if (!str) 160 if (!str)
115 - goto fail; 161 + goto fail;
116 162
117 /* Commit */ 163 /* Commit */
118 s = qemu_mallocz(sizeof(*s)); 164 s = qemu_mallocz(sizeof(*s));
119 -#if (SZ == 64)  
120 - s->disas_symtab = syms32;  
121 - qemu_free(syms);  
122 -#else  
123 - s->disas_symtab = syms;  
124 -#endif 165 + s->lookup_symbol = glue(lookup_symbol, SZ);
  166 + glue(s->disas_symtab.elf, SZ) = syms;
125 s->disas_num_syms = nsyms; 167 s->disas_num_syms = nsyms;
126 s->disas_strtab = str; 168 s->disas_strtab = str;
127 s->next = syminfos; 169 s->next = syminfos;
@@ -129,9 +171,6 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) @@ -129,9 +171,6 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
129 qemu_free(shdr_table); 171 qemu_free(shdr_table);
130 return 0; 172 return 0;
131 fail: 173 fail:
132 -#if (SZ == 64)  
133 - qemu_free(syms32);  
134 -#endif  
135 qemu_free(syms); 174 qemu_free(syms);
136 qemu_free(str); 175 qemu_free(str);
137 qemu_free(shdr_table); 176 qemu_free(shdr_table);
linux-user/elfload.c
@@ -984,80 +984,134 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex, @@ -984,80 +984,134 @@ static abi_ulong load_elf_interp(struct elfhdr * interp_elf_ex,
984 return ((abi_ulong) interp_elf_ex->e_entry) + load_addr; 984 return ((abi_ulong) interp_elf_ex->e_entry) + load_addr;
985 } 985 }
986 986
  987 +static int symfind(const void *s0, const void *s1)
  988 +{
  989 + struct elf_sym *key = (struct elf_sym *)s0;
  990 + struct elf_sym *sym = (struct elf_sym *)s1;
  991 + int result = 0;
  992 + if (key->st_value < sym->st_value) {
  993 + result = -1;
  994 + } else if (key->st_value > sym->st_value + sym->st_size) {
  995 + result = 1;
  996 + }
  997 + return result;
  998 +}
  999 +
  1000 +static const char *lookup_symbolxx(struct syminfo *s, target_ulong orig_addr)
  1001 +{
  1002 +#if ELF_CLASS == ELFCLASS32
  1003 + struct elf_sym *syms = s->disas_symtab.elf32;
  1004 +#else
  1005 + struct elf_sym *syms = s->disas_symtab.elf64;
  1006 +#endif
  1007 +
  1008 + // binary search
  1009 + struct elf_sym key;
  1010 + struct elf_sym *sym;
  1011 +
  1012 + key.st_value = orig_addr;
  1013 +
  1014 + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), symfind);
  1015 + if (sym != 0) {
  1016 + return s->disas_strtab + sym->st_name;
  1017 + }
  1018 +
  1019 + return "";
  1020 +}
  1021 +
  1022 +/* FIXME: This should use elf_ops.h */
  1023 +static int symcmp(const void *s0, const void *s1)
  1024 +{
  1025 + struct elf_sym *sym0 = (struct elf_sym *)s0;
  1026 + struct elf_sym *sym1 = (struct elf_sym *)s1;
  1027 + return (sym0->st_value < sym1->st_value)
  1028 + ? -1
  1029 + : ((sym0->st_value > sym1->st_value) ? 1 : 0);
  1030 +}
  1031 +
987 /* Best attempt to load symbols from this ELF object. */ 1032 /* Best attempt to load symbols from this ELF object. */
988 static void load_symbols(struct elfhdr *hdr, int fd) 1033 static void load_symbols(struct elfhdr *hdr, int fd)
989 { 1034 {
990 - unsigned int i; 1035 + unsigned int i, nsyms;
991 struct elf_shdr sechdr, symtab, strtab; 1036 struct elf_shdr sechdr, symtab, strtab;
992 char *strings; 1037 char *strings;
993 struct syminfo *s; 1038 struct syminfo *s;
994 -#if (ELF_CLASS == ELFCLASS64)  
995 - // Disas uses 32 bit symbols  
996 - struct elf32_sym *syms32 = NULL;  
997 - struct elf_sym *sym;  
998 -#endif 1039 + struct elf_sym *syms;
999 1040
1000 lseek(fd, hdr->e_shoff, SEEK_SET); 1041 lseek(fd, hdr->e_shoff, SEEK_SET);
1001 for (i = 0; i < hdr->e_shnum; i++) { 1042 for (i = 0; i < hdr->e_shnum; i++) {
1002 - if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))  
1003 - return; 1043 + if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
  1044 + return;
1004 #ifdef BSWAP_NEEDED 1045 #ifdef BSWAP_NEEDED
1005 - bswap_shdr(&sechdr); 1046 + bswap_shdr(&sechdr);
1006 #endif 1047 #endif
1007 - if (sechdr.sh_type == SHT_SYMTAB) {  
1008 - symtab = sechdr;  
1009 - lseek(fd, hdr->e_shoff  
1010 - + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);  
1011 - if (read(fd, &strtab, sizeof(strtab))  
1012 - != sizeof(strtab))  
1013 - return; 1048 + if (sechdr.sh_type == SHT_SYMTAB) {
  1049 + symtab = sechdr;
  1050 + lseek(fd, hdr->e_shoff
  1051 + + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
  1052 + if (read(fd, &strtab, sizeof(strtab))
  1053 + != sizeof(strtab))
  1054 + return;
1014 #ifdef BSWAP_NEEDED 1055 #ifdef BSWAP_NEEDED
1015 - bswap_shdr(&strtab); 1056 + bswap_shdr(&strtab);
1016 #endif 1057 #endif
1017 - goto found;  
1018 - } 1058 + goto found;
  1059 + }
1019 } 1060 }
1020 return; /* Shouldn't happen... */ 1061 return; /* Shouldn't happen... */
1021 1062
1022 found: 1063 found:
1023 /* Now know where the strtab and symtab are. Snarf them. */ 1064 /* Now know where the strtab and symtab are. Snarf them. */
1024 s = malloc(sizeof(*s)); 1065 s = malloc(sizeof(*s));
1025 - s->disas_symtab = malloc(symtab.sh_size);  
1026 -#if (ELF_CLASS == ELFCLASS64)  
1027 - syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)  
1028 - * sizeof(struct elf32_sym));  
1029 -#endif 1066 + syms = malloc(symtab.sh_size);
  1067 + if (!syms)
  1068 + return;
1030 s->disas_strtab = strings = malloc(strtab.sh_size); 1069 s->disas_strtab = strings = malloc(strtab.sh_size);
1031 - if (!s->disas_symtab || !s->disas_strtab)  
1032 - return; 1070 + if (!s->disas_strtab)
  1071 + return;
1033 1072
1034 lseek(fd, symtab.sh_offset, SEEK_SET); 1073 lseek(fd, symtab.sh_offset, SEEK_SET);
1035 - if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)  
1036 - return; 1074 + if (read(fd, syms, symtab.sh_size) != symtab.sh_size)
  1075 + return;
1037 1076
1038 - for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) { 1077 + nsyms = symtab.sh_size / sizeof(struct elf_sym);
  1078 +
  1079 + i = 0;
  1080 + while (i < nsyms) {
1039 #ifdef BSWAP_NEEDED 1081 #ifdef BSWAP_NEEDED
1040 - bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i); 1082 + bswap_sym(syms + i);
1041 #endif 1083 #endif
1042 -#if (ELF_CLASS == ELFCLASS64)  
1043 - sym = s->disas_symtab + sizeof(struct elf_sym)*i;  
1044 - syms32[i].st_name = sym->st_name;  
1045 - syms32[i].st_info = sym->st_info;  
1046 - syms32[i].st_other = sym->st_other;  
1047 - syms32[i].st_shndx = sym->st_shndx;  
1048 - syms32[i].st_value = sym->st_value & 0xffffffff;  
1049 - syms32[i].st_size = sym->st_size & 0xffffffff; 1084 + // Throw away entries which we do not need.
  1085 + if (syms[i].st_shndx == SHN_UNDEF ||
  1086 + syms[i].st_shndx >= SHN_LORESERVE ||
  1087 + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
  1088 + nsyms--;
  1089 + if (i < nsyms) {
  1090 + syms[i] = syms[nsyms];
  1091 + }
  1092 + continue;
  1093 + }
  1094 +#if defined(TARGET_ARM) || defined (TARGET_MIPS)
  1095 + /* The bottom address bit marks a Thumb or MIPS16 symbol. */
  1096 + syms[i].st_value &= ~(target_ulong)1;
1050 #endif 1097 #endif
  1098 + i++;
1051 } 1099 }
  1100 + syms = realloc(syms, nsyms * sizeof(*syms));
  1101 +
  1102 + qsort(syms, nsyms, sizeof(*syms), symcmp);
1052 1103
1053 -#if (ELF_CLASS == ELFCLASS64)  
1054 - free(s->disas_symtab);  
1055 - s->disas_symtab = syms32;  
1056 -#endif  
1057 lseek(fd, strtab.sh_offset, SEEK_SET); 1104 lseek(fd, strtab.sh_offset, SEEK_SET);
1058 if (read(fd, strings, strtab.sh_size) != strtab.sh_size) 1105 if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
1059 - return;  
1060 - s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym); 1106 + return;
  1107 + s->disas_num_syms = nsyms;
  1108 +#if ELF_CLASS == ELFCLASS32
  1109 + s->disas_symtab.elf32 = syms;
  1110 + s->lookup_symbol = lookup_symbolxx;
  1111 +#else
  1112 + s->disas_symtab.elf64 = syms;
  1113 + s->lookup_symbol = lookup_symbolxx;
  1114 +#endif
1061 s->next = syminfos; 1115 s->next = syminfos;
1062 syminfos = s; 1116 syminfos = s;
1063 } 1117 }