00001 static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
00002 {
00003 bswap16s(&ehdr->e_type);
00004 bswap16s(&ehdr->e_machine);
00005 bswap32s(&ehdr->e_version);
00006 bswapSZs(&ehdr->e_entry);
00007 bswapSZs(&ehdr->e_phoff);
00008 bswapSZs(&ehdr->e_shoff);
00009 bswap32s(&ehdr->e_flags);
00010 bswap16s(&ehdr->e_ehsize);
00011 bswap16s(&ehdr->e_phentsize);
00012 bswap16s(&ehdr->e_phnum);
00013 bswap16s(&ehdr->e_shentsize);
00014 bswap16s(&ehdr->e_shnum);
00015 bswap16s(&ehdr->e_shstrndx);
00016 }
00017
00018 static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
00019 {
00020 bswap32s(&phdr->p_type);
00021 bswapSZs(&phdr->p_offset);
00022 bswapSZs(&phdr->p_vaddr);
00023 bswapSZs(&phdr->p_paddr);
00024 bswapSZs(&phdr->p_filesz);
00025 bswapSZs(&phdr->p_memsz);
00026 bswap32s(&phdr->p_flags);
00027 bswapSZs(&phdr->p_align);
00028 }
00029
00030 static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
00031 {
00032 bswap32s(&shdr->sh_name);
00033 bswap32s(&shdr->sh_type);
00034 bswapSZs(&shdr->sh_flags);
00035 bswapSZs(&shdr->sh_addr);
00036 bswapSZs(&shdr->sh_offset);
00037 bswapSZs(&shdr->sh_size);
00038 bswap32s(&shdr->sh_link);
00039 bswap32s(&shdr->sh_info);
00040 bswapSZs(&shdr->sh_addralign);
00041 bswapSZs(&shdr->sh_entsize);
00042 }
00043
00044 static void glue(bswap_sym, SZ)(struct elf_sym *sym)
00045 {
00046 bswap32s(&sym->st_name);
00047 bswapSZs(&sym->st_value);
00048 bswapSZs(&sym->st_size);
00049 bswap16s(&sym->st_shndx);
00050 }
00051
00052 static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
00053 int n, int type)
00054 {
00055 int i;
00056 for(i=0;i<n;i++) {
00057 if (shdr_table[i].sh_type == type)
00058 return shdr_table + i;
00059 }
00060 return NULL;
00061 }
00062
00063 static int glue(symfind, SZ)(const void *s0, const void *s1)
00064 {
00065 struct elf_sym *key = (struct elf_sym *)s0;
00066 struct elf_sym *sym = (struct elf_sym *)s1;
00067 int result = 0;
00068 if (key->st_value < sym->st_value) {
00069 result = -1;
00070 } else if (key->st_value > sym->st_value + sym->st_size) {
00071 result = 1;
00072 }
00073 return result;
00074 }
00075
00076 static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr)
00077 {
00078 struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
00079 struct elf_sym key;
00080 struct elf_sym *sym;
00081
00082 key.st_value = orig_addr;
00083
00084 sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
00085 if (sym != 0) {
00086 return s->disas_strtab + sym->st_name;
00087 }
00088
00089 return "";
00090 }
00091
00092 static int glue(symcmp, SZ)(const void *s0, const void *s1)
00093 {
00094 struct elf_sym *sym0 = (struct elf_sym *)s0;
00095 struct elf_sym *sym1 = (struct elf_sym *)s1;
00096 return (sym0->st_value < sym1->st_value)
00097 ? -1
00098 : ((sym0->st_value > sym1->st_value) ? 1 : 0);
00099 }
00100
00101 static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
00102 {
00103 struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
00104 struct elf_sym *syms = NULL;
00105 struct syminfo *s;
00106 int nsyms, i;
00107 char *str = NULL;
00108
00109 shdr_table = load_at(fd, ehdr->e_shoff,
00110 sizeof(struct elf_shdr) * ehdr->e_shnum);
00111 if (!shdr_table)
00112 return -1;
00113
00114 if (must_swab) {
00115 for (i = 0; i < ehdr->e_shnum; i++) {
00116 glue(bswap_shdr, SZ)(shdr_table + i);
00117 }
00118 }
00119
00120 symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
00121 if (!symtab)
00122 goto fail;
00123 syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
00124 if (!syms)
00125 goto fail;
00126
00127 nsyms = symtab->sh_size / sizeof(struct elf_sym);
00128
00129 i = 0;
00130 while (i < nsyms) {
00131 if (must_swab)
00132 glue(bswap_sym, SZ)(&syms[i]);
00133
00134
00135 if (syms[i].st_shndx == SHN_UNDEF ||
00136 syms[i].st_shndx >= SHN_LORESERVE ||
00137 ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
00138 nsyms--;
00139 if (i < nsyms) {
00140 syms[i] = syms[nsyms];
00141 }
00142 continue;
00143 }
00144 #if defined(TARGET_ARM) || defined (TARGET_MIPS)
00145
00146 syms[i].st_value &= ~(target_ulong)1;
00147 #endif
00148 i++;
00149 }
00150 syms = qemu_realloc(syms, nsyms * sizeof(*syms));
00151
00152 qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
00153
00154
00155 if (symtab->sh_link >= ehdr->e_shnum)
00156 goto fail;
00157 strtab = &shdr_table[symtab->sh_link];
00158
00159 str = load_at(fd, strtab->sh_offset, strtab->sh_size);
00160 if (!str)
00161 goto fail;
00162
00163
00164 s = qemu_mallocz(sizeof(*s));
00165 s->lookup_symbol = glue(lookup_symbol, SZ);
00166 glue(s->disas_symtab.elf, SZ) = syms;
00167 s->disas_num_syms = nsyms;
00168 s->disas_strtab = str;
00169 s->next = syminfos;
00170 syminfos = s;
00171 qemu_free(shdr_table);
00172 return 0;
00173 fail:
00174 qemu_free(syms);
00175 qemu_free(str);
00176 qemu_free(shdr_table);
00177 return -1;
00178 }
00179
00180 static int glue(load_elf, SZ)(int fd, int64_t address_offset,
00181 int must_swab, uint64_t *pentry,
00182 uint64_t *lowaddr, uint64_t *highaddr)
00183 {
00184 struct elfhdr ehdr;
00185 struct elf_phdr *phdr = NULL, *ph;
00186 int size, i, total_size;
00187 elf_word mem_size;
00188 uint64_t addr, low = 0, high = 0;
00189 uint8_t *data = NULL;
00190
00191 if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
00192 goto fail;
00193 if (must_swab) {
00194 glue(bswap_ehdr, SZ)(&ehdr);
00195 }
00196
00197 if (ELF_MACHINE != ehdr.e_machine)
00198 goto fail;
00199
00200 if (pentry)
00201 *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
00202
00203 glue(load_symbols, SZ)(&ehdr, fd, must_swab);
00204
00205 size = ehdr.e_phnum * sizeof(phdr[0]);
00206 lseek(fd, ehdr.e_phoff, SEEK_SET);
00207 phdr = qemu_mallocz(size);
00208 if (!phdr)
00209 goto fail;
00210 if (read(fd, phdr, size) != size)
00211 goto fail;
00212 if (must_swab) {
00213 for(i = 0; i < ehdr.e_phnum; i++) {
00214 ph = &phdr[i];
00215 glue(bswap_phdr, SZ)(ph);
00216 }
00217 }
00218
00219 total_size = 0;
00220 for(i = 0; i < ehdr.e_phnum; i++) {
00221 ph = &phdr[i];
00222 if (ph->p_type == PT_LOAD) {
00223 mem_size = ph->p_memsz;
00224
00225 data = qemu_mallocz(mem_size);
00226 if (ph->p_filesz > 0) {
00227 if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
00228 goto fail;
00229 if (read(fd, data, ph->p_filesz) != ph->p_filesz)
00230 goto fail;
00231 }
00232
00233
00234 addr = ph->p_paddr + address_offset;
00235
00236 cpu_physical_memory_write_rom(addr, data, mem_size);
00237
00238 total_size += mem_size;
00239 if (!low || addr < low)
00240 low = addr;
00241 if (!high || (addr + mem_size) > high)
00242 high = addr + mem_size;
00243
00244 qemu_free(data);
00245 data = NULL;
00246 }
00247 }
00248 qemu_free(phdr);
00249 if (lowaddr)
00250 *lowaddr = (uint64_t)(elf_sword)low;
00251 if (highaddr)
00252 *highaddr = (uint64_t)(elf_sword)high;
00253 return total_size;
00254 fail:
00255 qemu_free(data);
00256 qemu_free(phdr);
00257 return -1;
00258 }