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 303 /* Look up symbol for debugging purpose. Returns "" if unknown. */
304 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 307 struct syminfo *s;
310   - target_ulong addr;
311 308  
312 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 319 #if !defined(CONFIG_USER_ONLY)
... ...
... ... @@ -10,12 +10,24 @@ void monitor_disas(CPUState *env,
10 10 /* Look up symbol for debugging purpose. Returns "" if unknown. */
11 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 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 26 const char *disas_strtab;
18 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 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 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 101 static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
64 102 {
65 103 struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
66 104 struct elf_sym *syms = NULL;
67   -#if (SZ == 64)
68   - struct elf32_sym *syms32 = NULL;
69   -#endif
70 105 struct syminfo *s;
71 106 int nsyms, i;
72 107 char *str = NULL;
... ... @@ -90,21 +125,32 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
90 125 goto fail;
91 126  
92 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 131 if (must_swab)
98 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 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 154 /* String table */
109 155 if (symtab->sh_link >= ehdr->e_shnum)
110 156 goto fail;
... ... @@ -112,16 +158,12 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
112 158  
113 159 str = load_at(fd, strtab->sh_offset, strtab->sh_size);
114 160 if (!str)
115   - goto fail;
  161 + goto fail;
116 162  
117 163 /* Commit */
118 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 167 s->disas_num_syms = nsyms;
126 168 s->disas_strtab = str;
127 169 s->next = syminfos;
... ... @@ -129,9 +171,6 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
129 171 qemu_free(shdr_table);
130 172 return 0;
131 173 fail:
132   -#if (SZ == 64)
133   - qemu_free(syms32);
134   -#endif
135 174 qemu_free(syms);
136 175 qemu_free(str);
137 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 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 1032 /* Best attempt to load symbols from this ELF object. */
988 1033 static void load_symbols(struct elfhdr *hdr, int fd)
989 1034 {
990   - unsigned int i;
  1035 + unsigned int i, nsyms;
991 1036 struct elf_shdr sechdr, symtab, strtab;
992 1037 char *strings;
993 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 1041 lseek(fd, hdr->e_shoff, SEEK_SET);
1001 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 1045 #ifdef BSWAP_NEEDED
1005   - bswap_shdr(&sechdr);
  1046 + bswap_shdr(&sechdr);
1006 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 1055 #ifdef BSWAP_NEEDED
1015   - bswap_shdr(&strtab);
  1056 + bswap_shdr(&strtab);
1016 1057 #endif
1017   - goto found;
1018   - }
  1058 + goto found;
  1059 + }
1019 1060 }
1020 1061 return; /* Shouldn't happen... */
1021 1062  
1022 1063 found:
1023 1064 /* Now know where the strtab and symtab are. Snarf them. */
1024 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 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 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 1081 #ifdef BSWAP_NEEDED
1040   - bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
  1082 + bswap_sym(syms + i);
1041 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 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 1104 lseek(fd, strtab.sh_offset, SEEK_SET);
1058 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 1115 s->next = syminfos;
1062 1116 syminfos = s;
1063 1117 }
... ...