]>
Commit | Line | Data |
---|---|---|
5fe141fd FB |
1 | static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr) |
2 | { | |
3 | bswap16s(&ehdr->e_type); /* Object file type */ | |
4 | bswap16s(&ehdr->e_machine); /* Architecture */ | |
5 | bswap32s(&ehdr->e_version); /* Object file version */ | |
6 | bswapSZs(&ehdr->e_entry); /* Entry point virtual address */ | |
7 | bswapSZs(&ehdr->e_phoff); /* Program header table file offset */ | |
8 | bswapSZs(&ehdr->e_shoff); /* Section header table file offset */ | |
9 | bswap32s(&ehdr->e_flags); /* Processor-specific flags */ | |
10 | bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ | |
11 | bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ | |
12 | bswap16s(&ehdr->e_phnum); /* Program header table entry count */ | |
13 | bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ | |
14 | bswap16s(&ehdr->e_shnum); /* Section header table entry count */ | |
15 | bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ | |
16 | } | |
17 | ||
18 | static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr) | |
19 | { | |
20 | bswap32s(&phdr->p_type); /* Segment type */ | |
21 | bswapSZs(&phdr->p_offset); /* Segment file offset */ | |
22 | bswapSZs(&phdr->p_vaddr); /* Segment virtual address */ | |
23 | bswapSZs(&phdr->p_paddr); /* Segment physical address */ | |
24 | bswapSZs(&phdr->p_filesz); /* Segment size in file */ | |
25 | bswapSZs(&phdr->p_memsz); /* Segment size in memory */ | |
26 | bswap32s(&phdr->p_flags); /* Segment flags */ | |
27 | bswapSZs(&phdr->p_align); /* Segment alignment */ | |
28 | } | |
29 | ||
30 | static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr) | |
31 | { | |
32 | bswap32s(&shdr->sh_name); | |
33 | bswap32s(&shdr->sh_type); | |
34 | bswapSZs(&shdr->sh_flags); | |
35 | bswapSZs(&shdr->sh_addr); | |
36 | bswapSZs(&shdr->sh_offset); | |
37 | bswapSZs(&shdr->sh_size); | |
38 | bswap32s(&shdr->sh_link); | |
39 | bswap32s(&shdr->sh_info); | |
40 | bswapSZs(&shdr->sh_addralign); | |
41 | bswapSZs(&shdr->sh_entsize); | |
42 | } | |
43 | ||
44 | static void glue(bswap_sym, SZ)(struct elf_sym *sym) | |
45 | { | |
46 | bswap32s(&sym->st_name); | |
47 | bswapSZs(&sym->st_value); | |
48 | bswapSZs(&sym->st_size); | |
49 | bswap16s(&sym->st_shndx); | |
50 | } | |
51 | ||
5fafdf24 | 52 | static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, |
5fe141fd FB |
53 | int n, int type) |
54 | { | |
55 | int i; | |
56 | for(i=0;i<n;i++) { | |
57 | if (shdr_table[i].sh_type == type) | |
58 | return shdr_table + i; | |
59 | } | |
60 | return NULL; | |
61 | } | |
62 | ||
63 | static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) | |
64 | { | |
65 | struct elf_shdr *symtab, *strtab, *shdr_table = NULL; | |
66 | struct elf_sym *syms = NULL; | |
67 | #if (SZ == 64) | |
68 | struct elf32_sym *syms32 = NULL; | |
69 | #endif | |
70 | struct syminfo *s; | |
71 | int nsyms, i; | |
72 | char *str = NULL; | |
73 | ||
5fafdf24 | 74 | shdr_table = load_at(fd, ehdr->e_shoff, |
5fe141fd FB |
75 | sizeof(struct elf_shdr) * ehdr->e_shnum); |
76 | if (!shdr_table) | |
77 | return -1; | |
3b46e624 | 78 | |
5fe141fd FB |
79 | if (must_swab) { |
80 | for (i = 0; i < ehdr->e_shnum; i++) { | |
81 | glue(bswap_shdr, SZ)(shdr_table + i); | |
82 | } | |
83 | } | |
3b46e624 | 84 | |
5fe141fd FB |
85 | symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); |
86 | if (!symtab) | |
87 | goto fail; | |
88 | syms = load_at(fd, symtab->sh_offset, symtab->sh_size); | |
89 | if (!syms) | |
90 | goto fail; | |
91 | ||
92 | 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++) { | |
97 | if (must_swab) | |
98 | 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; | |
106 | #endif | |
107 | } | |
108 | /* String table */ | |
109 | if (symtab->sh_link >= ehdr->e_shnum) | |
110 | goto fail; | |
111 | strtab = &shdr_table[symtab->sh_link]; | |
112 | ||
113 | str = load_at(fd, strtab->sh_offset, strtab->sh_size); | |
114 | if (!str) | |
115 | goto fail; | |
116 | ||
117 | /* Commit */ | |
118 | 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 | |
125 | s->disas_num_syms = nsyms; | |
126 | s->disas_strtab = str; | |
127 | s->next = syminfos; | |
128 | syminfos = s; | |
129 | qemu_free(shdr_table); | |
130 | return 0; | |
131 | fail: | |
132 | #if (SZ == 64) | |
133 | qemu_free(syms32); | |
134 | #endif | |
135 | qemu_free(syms); | |
136 | qemu_free(str); | |
137 | qemu_free(shdr_table); | |
138 | return -1; | |
139 | } | |
140 | ||
9ee3c029 | 141 | int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend, |
74287114 TS |
142 | int must_swab, uint64_t *pentry, |
143 | uint64_t *lowaddr, uint64_t *highaddr) | |
5fe141fd FB |
144 | { |
145 | struct elfhdr ehdr; | |
146 | struct elf_phdr *phdr = NULL, *ph; | |
147 | int size, i, total_size; | |
9437454a | 148 | elf_word mem_size; |
eb296a0a | 149 | uint64_t addr, low = 0, high = 0; |
9ee3c029 | 150 | uint8_t *data = NULL; |
5fe141fd FB |
151 | |
152 | if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) | |
153 | goto fail; | |
154 | if (must_swab) { | |
155 | glue(bswap_ehdr, SZ)(&ehdr); | |
156 | } | |
157 | ||
9042c0e2 TS |
158 | if (ELF_MACHINE != ehdr.e_machine) |
159 | goto fail; | |
160 | ||
9ee3c029 FB |
161 | if (pentry) |
162 | *pentry = (uint64_t)ehdr.e_entry; | |
163 | ||
5fe141fd FB |
164 | glue(load_symbols, SZ)(&ehdr, fd, must_swab); |
165 | ||
166 | size = ehdr.e_phnum * sizeof(phdr[0]); | |
167 | lseek(fd, ehdr.e_phoff, SEEK_SET); | |
168 | phdr = qemu_mallocz(size); | |
169 | if (!phdr) | |
170 | goto fail; | |
171 | if (read(fd, phdr, size) != size) | |
04d4b0c3 | 172 | goto fail; |
5fe141fd FB |
173 | if (must_swab) { |
174 | for(i = 0; i < ehdr.e_phnum; i++) { | |
175 | ph = &phdr[i]; | |
176 | glue(bswap_phdr, SZ)(ph); | |
177 | } | |
178 | } | |
3b46e624 | 179 | |
5fe141fd FB |
180 | total_size = 0; |
181 | for(i = 0; i < ehdr.e_phnum; i++) { | |
182 | ph = &phdr[i]; | |
183 | if (ph->p_type == PT_LOAD) { | |
184 | mem_size = ph->p_memsz; | |
185 | /* XXX: avoid allocating */ | |
186 | data = qemu_mallocz(mem_size); | |
187 | if (ph->p_filesz > 0) { | |
9ee3c029 | 188 | if (lseek(fd, ph->p_offset, SEEK_SET) < 0) |
04d4b0c3 | 189 | goto fail; |
5fe141fd | 190 | if (read(fd, data, ph->p_filesz) != ph->p_filesz) |
04d4b0c3 | 191 | goto fail; |
5fe141fd FB |
192 | } |
193 | addr = ph->p_vaddr + virt_to_phys_addend; | |
194 | ||
195 | cpu_physical_memory_write_rom(addr, data, mem_size); | |
196 | ||
197 | total_size += mem_size; | |
74287114 TS |
198 | if (!low || addr < low) |
199 | low = addr; | |
200 | if (!high || (addr + mem_size) > high) | |
201 | high = addr + mem_size; | |
5fe141fd FB |
202 | |
203 | qemu_free(data); | |
9ee3c029 | 204 | data = NULL; |
5fe141fd FB |
205 | } |
206 | } | |
3aee288b | 207 | qemu_free(phdr); |
74287114 TS |
208 | if (lowaddr) |
209 | *lowaddr = (uint64_t)low; | |
210 | if (highaddr) | |
211 | *highaddr = (uint64_t)high; | |
5fe141fd | 212 | return total_size; |
04d4b0c3 | 213 | fail: |
9ee3c029 | 214 | qemu_free(data); |
5fe141fd FB |
215 | qemu_free(phdr); |
216 | return -1; | |
217 | } |