diff options
author | David 'Digit' Turner <digit@google.com> | 2009-09-14 14:32:27 -0700 |
---|---|---|
committer | David 'Digit' Turner <digit@google.com> | 2009-09-14 14:32:27 -0700 |
commit | 5d8f37ad78fc66901af50c762029a501561f3b23 (patch) | |
tree | 206790f8f21000850a98c4f9590a79e779106278 /elf_ops.h | |
parent | cd059b15f2c7df69f4a087bd66900eb172e41d1c (diff) | |
download | external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.zip external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.gz external_qemu-5d8f37ad78fc66901af50c762029a501561f3b23.tar.bz2 |
Merge upstream QEMU 10.0.50 into the Android source tree.
This change integrates many changes from the upstream QEMU sources.
Its main purpose is to enable correct ARMv6 and ARMv7 support to the
Android emulator. Due to the nature of the upstream code base, this
unfortunately also required changes to many other parts of the source.
Note that to ensure easier integrations in the future, some source files
and directories that have heavy Android-specific customization have been
renamed with an -android suffix. The original files are still there for
easier integration tracking, but *never* compiled. For example:
net.c net-android.c
qemu-char.c qemu-char-android.c
slirp/ slirp-android/
etc...
Tested on linux-x86, darwin-x86 and windows host machines.
Diffstat (limited to 'elf_ops.h')
-rw-r--r-- | elf_ops.h | 116 |
1 files changed, 85 insertions, 31 deletions
@@ -60,13 +60,48 @@ static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, return NULL; } +static int glue(symfind, SZ)(const void *s0, const void *s1) +{ + struct elf_sym *key = (struct elf_sym *)s0; + struct elf_sym *sym = (struct elf_sym *)s1; + int result = 0; + if (key->st_value < sym->st_value) { + result = -1; + } else if (key->st_value > sym->st_value + sym->st_size) { + result = 1; + } + return result; +} + +static const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr) +{ + struct elf_sym *syms = glue(s->disas_symtab.elf, SZ); + struct elf_sym key; + struct elf_sym *sym; + + key.st_value = orig_addr; + + sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ)); + if (sym != 0) { + return s->disas_strtab + sym->st_name; + } + + return ""; +} + +static int glue(symcmp, SZ)(const void *s0, const void *s1) +{ + struct elf_sym *sym0 = (struct elf_sym *)s0; + struct elf_sym *sym1 = (struct elf_sym *)s1; + return (sym0->st_value < sym1->st_value) + ? -1 + : ((sym0->st_value > sym1->st_value) ? 1 : 0); +} + static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) { struct elf_shdr *symtab, *strtab, *shdr_table = NULL; struct elf_sym *syms = NULL; -#if (SZ == 64) - struct elf32_sym *syms32 = NULL; -#endif struct syminfo *s; int nsyms, i; char *str = NULL; @@ -90,21 +125,32 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) goto fail; nsyms = symtab->sh_size / sizeof(struct elf_sym); -#if (SZ == 64) - syms32 = qemu_mallocz(nsyms * sizeof(struct elf32_sym)); -#endif - for (i = 0; i < nsyms; i++) { + + i = 0; + while (i < nsyms) { if (must_swab) glue(bswap_sym, SZ)(&syms[i]); -#if (SZ == 64) - syms32[i].st_name = syms[i].st_name; - syms32[i].st_info = syms[i].st_info; - syms32[i].st_other = syms[i].st_other; - syms32[i].st_shndx = syms[i].st_shndx; - syms32[i].st_value = syms[i].st_value & 0xffffffff; - syms32[i].st_size = syms[i].st_size & 0xffffffff; + /* We are only interested in function symbols. + Throw everything else away. */ + if (syms[i].st_shndx == SHN_UNDEF || + syms[i].st_shndx >= SHN_LORESERVE || + ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) { + nsyms--; + if (i < nsyms) { + syms[i] = syms[nsyms]; + } + continue; + } +#if defined(TARGET_ARM) || defined (TARGET_MIPS) + /* The bottom address bit marks a Thumb or MIPS16 symbol. */ + syms[i].st_value &= ~(target_ulong)1; #endif + i++; } + syms = qemu_realloc(syms, nsyms * sizeof(*syms)); + + qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ)); + /* String table */ if (symtab->sh_link >= ehdr->e_shnum) goto fail; @@ -112,16 +158,12 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) str = load_at(fd, strtab->sh_offset, strtab->sh_size); if (!str) - goto fail; + goto fail; /* Commit */ s = qemu_mallocz(sizeof(*s)); -#if (SZ == 64) - s->disas_symtab = syms32; - qemu_free(syms); -#else - s->disas_symtab = syms; -#endif + s->lookup_symbol = glue(lookup_symbol, SZ); + glue(s->disas_symtab.elf, SZ) = syms; s->disas_num_syms = nsyms; s->disas_strtab = str; s->next = syminfos; @@ -129,16 +171,13 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) qemu_free(shdr_table); return 0; fail: -#if (SZ == 64) - qemu_free(syms32); -#endif qemu_free(syms); qemu_free(str); qemu_free(shdr_table); return -1; } -static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, +static int glue(load_elf, SZ)(int fd, int64_t address_offset, int must_swab, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) { @@ -146,7 +185,7 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, struct elf_phdr *phdr = NULL, *ph; int size, i, total_size; elf_word mem_size; - uint64_t addr, low = 0, high = 0; + uint64_t addr, low = (uint64_t)-1, high = 0; uint8_t *data = NULL; if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) @@ -155,8 +194,21 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, glue(bswap_ehdr, SZ)(&ehdr); } - if (ELF_MACHINE != ehdr.e_machine) - goto fail; + switch (ELF_MACHINE) { + case EM_PPC64: + if (EM_PPC64 != ehdr.e_machine) + if (EM_PPC != ehdr.e_machine) + goto fail; + break; + case EM_X86_64: + if (EM_X86_64 != ehdr.e_machine) + if (EM_386 != ehdr.e_machine) + goto fail; + break; + default: + if (ELF_MACHINE != ehdr.e_machine) + goto fail; + } if (pentry) *pentry = (uint64_t)(elf_sword)ehdr.e_entry; @@ -190,14 +242,16 @@ static int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, if (read(fd, data, ph->p_filesz) != ph->p_filesz) goto fail; } - addr = ph->p_vaddr + virt_to_phys_addend; + /* address_offset is hack for kernel images that are + linked at the wrong physical address. */ + addr = ph->p_paddr + address_offset; cpu_physical_memory_write_rom(addr, data, mem_size); total_size += mem_size; - if (!low || addr < low) + if (addr < low) low = addr; - if (!high || (addr + mem_size) > high) + if ((addr + mem_size) > high) high = addr + mem_size; qemu_free(data); |