18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_type);			/* Object file type */
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_machine);		/* Architecture */
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&ehdr->e_version);		/* Object file version */
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&ehdr->e_entry);		/* Entry point virtual address */
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&ehdr->e_phoff);		/* Program header table file offset */
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&ehdr->e_shoff);		/* Section header table file offset */
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&ehdr->e_flags);		/* Processor-specific flags */
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_ehsize);		/* ELF header size in bytes */
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_phentsize);		/* Program header table entry size */
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_phnum);		/* Program header table entry count */
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_shentsize);		/* Section header table entry size */
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_shnum);		/* Section header table entry count */
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&ehdr->e_shstrndx);		/* Section header string table index */
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&phdr->p_type);			/* Segment type */
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_offset);		/* Segment file offset */
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_vaddr);		/* Segment virtual address */
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_paddr);		/* Segment physical address */
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_filesz);		/* Segment size in file */
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_memsz);		/* Segment size in memory */
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&phdr->p_flags);		/* Segment flags */
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&phdr->p_align);		/* Segment alignment */
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&shdr->sh_name);
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&shdr->sh_type);
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_flags);
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_addr);
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_offset);
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_size);
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&shdr->sh_link);
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&shdr->sh_info);
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_addralign);
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&shdr->sh_entsize);
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void glue(bswap_sym, SZ)(struct elf_sym *sym)
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap32s(&sym->st_name);
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&sym->st_value);
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswapSZs(&sym->st_size);
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bswap16s(&sym->st_shndx);
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                               int n, int type)
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i=0;i<n;i++) {
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (shdr_table[i].sh_type == type)
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return shdr_table + i;
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return NULL;
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int glue(symfind, SZ)(const void *s0, const void *s1)
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *key = (struct elf_sym *)s0;
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *sym = (struct elf_sym *)s1;
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int result = 0;
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (key->st_value < sym->st_value) {
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        result = -1;
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (key->st_value > sym->st_value + sym->st_size) {
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        result = 1;
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return result;
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char *glue(lookup_symbol, SZ)(struct syminfo *s, target_ulong orig_addr)
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym key;
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *sym;
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    key.st_value = orig_addr;
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sym != 0) {
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return s->disas_strtab + sym->st_name;
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return "";
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int glue(symcmp, SZ)(const void *s0, const void *s1)
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *sym0 = (struct elf_sym *)s0;
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct elf_sym *sym1 = (struct elf_sym *)s1;
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return (sym0->st_value < sym1->st_value)
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ? -1
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab)
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct elf_sym *syms = NULL;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct syminfo *s;
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int nsyms, i;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    char *str = NULL;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    shdr_table = load_at(fd, ehdr->e_shoff,
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                         sizeof(struct elf_shdr) * ehdr->e_shnum);
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!shdr_table)
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (must_swab) {
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < ehdr->e_shnum; i++) {
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            glue(bswap_shdr, SZ)(shdr_table + i);
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!symtab)
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!syms)
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    nsyms = symtab->sh_size / sizeof(struct elf_sym);
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    i = 0;
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (i < nsyms) {
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (must_swab)
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            glue(bswap_sym, SZ)(&syms[i]);
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* We are only interested in function symbols.
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           Throw everything else away.  */
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (syms[i].st_shndx == SHN_UNDEF ||
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                syms[i].st_shndx >= SHN_LORESERVE ||
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            nsyms--;
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (i < nsyms) {
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                syms[i] = syms[nsyms];
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(TARGET_ARM) || defined (TARGET_MIPS)
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syms[i].st_value &= ~(target_ulong)1;
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        i++;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    syms = qemu_realloc(syms, nsyms * sizeof(*syms));
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* String table */
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (symtab->sh_link >= ehdr->e_shnum)
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    strtab = &shdr_table[symtab->sh_link];
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!str)
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Commit */
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s = qemu_mallocz(sizeof(*s));
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->lookup_symbol = glue(lookup_symbol, SZ);
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    glue(s->disas_symtab.elf, SZ) = syms;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->disas_num_syms = nsyms;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->disas_strtab = str;
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->next = syminfos;
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    syminfos = s;
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(shdr_table);
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail:
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(syms);
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(str);
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(shdr_table);
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return -1;
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int glue(load_elf, SZ)(int fd, int64_t address_offset,
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              int must_swab, uint64_t *pentry,
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              uint64_t *lowaddr, uint64_t *highaddr)
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct elfhdr ehdr;
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct elf_phdr *phdr = NULL, *ph;
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int size, i, total_size;
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    elf_word mem_size;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint64_t addr, low = (uint64_t)-1, high = 0;
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t *data = NULL;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (must_swab) {
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        glue(bswap_ehdr, SZ)(&ehdr);
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch (ELF_MACHINE) {
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case EM_PPC64:
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (EM_PPC64 != ehdr.e_machine)
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (EM_PPC != ehdr.e_machine)
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    goto fail;
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case EM_X86_64:
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (EM_X86_64 != ehdr.e_machine)
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (EM_386 != ehdr.e_machine)
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    goto fail;
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        default:
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (ELF_MACHINE != ehdr.e_machine)
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto fail;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (pentry)
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   	*pentry = (uint64_t)(elf_sword)ehdr.e_entry;
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    glue(load_symbols, SZ)(&ehdr, fd, must_swab);
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    size = ehdr.e_phnum * sizeof(phdr[0]);
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    lseek(fd, ehdr.e_phoff, SEEK_SET);
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    phdr = qemu_mallocz(size);
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!phdr)
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (read(fd, phdr, size) != size)
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto fail;
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (must_swab) {
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for(i = 0; i < ehdr.e_phnum; i++) {
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ph = &phdr[i];
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            glue(bswap_phdr, SZ)(ph);
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    total_size = 0;
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < ehdr.e_phnum; i++) {
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        ph = &phdr[i];
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (ph->p_type == PT_LOAD) {
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mem_size = ph->p_memsz;
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* XXX: avoid allocating */
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            data = qemu_mallocz(mem_size);
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ph->p_filesz > 0) {
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto fail;
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    goto fail;
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* address_offset is hack for kernel images that are
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner               linked at the wrong physical address.  */
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            addr = ph->p_paddr + address_offset;
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            cpu_physical_memory_write_rom(addr, data, mem_size);
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            total_size += mem_size;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (addr < low)
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                low = addr;
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((addr + mem_size) > high)
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                high = addr + mem_size;
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            qemu_free(data);
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            data = NULL;
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(phdr);
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (lowaddr)
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *lowaddr = (uint64_t)(elf_sword)low;
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (highaddr)
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *highaddr = (uint64_t)(elf_sword)high;
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return total_size;
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project fail:
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(data);
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(phdr);
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return -1;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
272