]>
Commit | Line | Data |
---|---|---|
420557e8 FB |
1 | #include "vl.h" |
2 | #include "disas.h" | |
e80cfcfc FB |
3 | #include "exec-all.h" |
4 | ||
5 | struct exec | |
6 | { | |
7 | uint32_t a_info; /* Use macros N_MAGIC, etc for access */ | |
8 | uint32_t a_text; /* length of text, in bytes */ | |
9 | uint32_t a_data; /* length of data, in bytes */ | |
10 | uint32_t a_bss; /* length of uninitialized data area, in bytes */ | |
11 | uint32_t a_syms; /* length of symbol table data in file, in bytes */ | |
12 | uint32_t a_entry; /* start address */ | |
13 | uint32_t a_trsize; /* length of relocation info for text, in bytes */ | |
14 | uint32_t a_drsize; /* length of relocation info for data, in bytes */ | |
15 | }; | |
16 | ||
17 | #ifdef BSWAP_NEEDED | |
18 | static void bswap_ahdr(struct exec *e) | |
19 | { | |
20 | bswap32s(&e->a_info); | |
21 | bswap32s(&e->a_text); | |
22 | bswap32s(&e->a_data); | |
23 | bswap32s(&e->a_bss); | |
24 | bswap32s(&e->a_syms); | |
25 | bswap32s(&e->a_entry); | |
26 | bswap32s(&e->a_trsize); | |
27 | bswap32s(&e->a_drsize); | |
28 | } | |
29 | #else | |
30 | #define bswap_ahdr(x) do { } while (0) | |
31 | #endif | |
32 | ||
33 | #define N_MAGIC(exec) ((exec).a_info & 0xffff) | |
34 | #define OMAGIC 0407 | |
35 | #define NMAGIC 0410 | |
36 | #define ZMAGIC 0413 | |
37 | #define QMAGIC 0314 | |
38 | #define _N_HDROFF(x) (1024 - sizeof (struct exec)) | |
39 | #define N_TXTOFF(x) \ | |
40 | (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ | |
41 | (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) | |
42 | #define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0) | |
43 | #define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) | |
44 | #define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1)) | |
45 | ||
46 | #define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) | |
47 | ||
48 | #define N_DATADDR(x) \ | |
49 | (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ | |
50 | : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) | |
51 | ||
420557e8 | 52 | |
420557e8 FB |
53 | #define ELF_CLASS ELFCLASS32 |
54 | #define ELF_DATA ELFDATA2MSB | |
55 | #define ELF_ARCH EM_SPARC | |
56 | ||
57 | #include "elf.h" | |
58 | ||
420557e8 FB |
59 | #ifdef BSWAP_NEEDED |
60 | static void bswap_ehdr(Elf32_Ehdr *ehdr) | |
61 | { | |
62 | bswap16s(&ehdr->e_type); /* Object file type */ | |
63 | bswap16s(&ehdr->e_machine); /* Architecture */ | |
64 | bswap32s(&ehdr->e_version); /* Object file version */ | |
65 | bswap32s(&ehdr->e_entry); /* Entry point virtual address */ | |
66 | bswap32s(&ehdr->e_phoff); /* Program header table file offset */ | |
67 | bswap32s(&ehdr->e_shoff); /* Section header table file offset */ | |
68 | bswap32s(&ehdr->e_flags); /* Processor-specific flags */ | |
69 | bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */ | |
70 | bswap16s(&ehdr->e_phentsize); /* Program header table entry size */ | |
71 | bswap16s(&ehdr->e_phnum); /* Program header table entry count */ | |
72 | bswap16s(&ehdr->e_shentsize); /* Section header table entry size */ | |
73 | bswap16s(&ehdr->e_shnum); /* Section header table entry count */ | |
74 | bswap16s(&ehdr->e_shstrndx); /* Section header string table index */ | |
75 | } | |
76 | ||
77 | static void bswap_phdr(Elf32_Phdr *phdr) | |
78 | { | |
79 | bswap32s(&phdr->p_type); /* Segment type */ | |
80 | bswap32s(&phdr->p_offset); /* Segment file offset */ | |
81 | bswap32s(&phdr->p_vaddr); /* Segment virtual address */ | |
82 | bswap32s(&phdr->p_paddr); /* Segment physical address */ | |
83 | bswap32s(&phdr->p_filesz); /* Segment size in file */ | |
84 | bswap32s(&phdr->p_memsz); /* Segment size in memory */ | |
85 | bswap32s(&phdr->p_flags); /* Segment flags */ | |
86 | bswap32s(&phdr->p_align); /* Segment alignment */ | |
87 | } | |
88 | ||
89 | static void bswap_shdr(Elf32_Shdr *shdr) | |
90 | { | |
91 | bswap32s(&shdr->sh_name); | |
92 | bswap32s(&shdr->sh_type); | |
93 | bswap32s(&shdr->sh_flags); | |
94 | bswap32s(&shdr->sh_addr); | |
95 | bswap32s(&shdr->sh_offset); | |
96 | bswap32s(&shdr->sh_size); | |
97 | bswap32s(&shdr->sh_link); | |
98 | bswap32s(&shdr->sh_info); | |
99 | bswap32s(&shdr->sh_addralign); | |
100 | bswap32s(&shdr->sh_entsize); | |
101 | } | |
102 | ||
103 | static void bswap_sym(Elf32_Sym *sym) | |
104 | { | |
105 | bswap32s(&sym->st_name); | |
106 | bswap32s(&sym->st_value); | |
107 | bswap32s(&sym->st_size); | |
108 | bswap16s(&sym->st_shndx); | |
109 | } | |
8d5f07fa FB |
110 | #else |
111 | #define bswap_ehdr(e) do { } while (0) | |
112 | #define bswap_phdr(e) do { } while (0) | |
113 | #define bswap_shdr(e) do { } while (0) | |
114 | #define bswap_sym(e) do { } while (0) | |
420557e8 FB |
115 | #endif |
116 | ||
8d5f07fa | 117 | static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type) |
420557e8 | 118 | { |
8d5f07fa FB |
119 | int i, retval; |
120 | ||
121 | retval = lseek(fd, ehdr->e_phoff, SEEK_SET); | |
122 | if (retval < 0) | |
123 | return -1; | |
124 | ||
125 | for (i = 0; i < ehdr->e_phnum; i++) { | |
126 | retval = read(fd, phdr, sizeof(*phdr)); | |
127 | if (retval < 0) | |
128 | return -1; | |
129 | bswap_phdr(phdr); | |
130 | if (phdr->p_type == type) | |
131 | return 0; | |
420557e8 | 132 | } |
8d5f07fa | 133 | return -1; |
420557e8 FB |
134 | } |
135 | ||
8d5f07fa | 136 | static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) |
420557e8 | 137 | { |
8d5f07fa FB |
138 | int i, retval; |
139 | ||
140 | retval = lseek(fd, ehdr->e_shoff, SEEK_SET); | |
141 | if (retval < 0) | |
142 | return NULL; | |
143 | ||
144 | for (i = 0; i < ehdr->e_shnum; i++) { | |
145 | retval = read(fd, shdr, sizeof(*shdr)); | |
146 | if (retval < 0) | |
147 | return NULL; | |
148 | bswap_shdr(shdr); | |
149 | if (shdr->sh_type == type) | |
150 | return qemu_malloc(shdr->sh_size); | |
420557e8 | 151 | } |
8d5f07fa FB |
152 | return NULL; |
153 | } | |
420557e8 | 154 | |
e80cfcfc | 155 | static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) |
8d5f07fa FB |
156 | { |
157 | int retval; | |
420557e8 | 158 | |
8d5f07fa FB |
159 | retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); |
160 | if (retval < 0) | |
e80cfcfc | 161 | return NULL; |
8d5f07fa FB |
162 | |
163 | retval = read(fd, shdr, sizeof(*shdr)); | |
164 | if (retval < 0) | |
e80cfcfc | 165 | return NULL; |
8d5f07fa FB |
166 | bswap_shdr(shdr); |
167 | if (shdr->sh_type == SHT_STRTAB) | |
168 | return qemu_malloc(shdr->sh_size);; | |
e80cfcfc | 169 | return NULL; |
420557e8 FB |
170 | } |
171 | ||
e80cfcfc | 172 | static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) |
420557e8 | 173 | { |
420557e8 | 174 | int retval; |
e80cfcfc | 175 | retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); |
8d5f07fa FB |
176 | if (retval < 0) |
177 | return -1; | |
178 | return read(fd, dst, phdr->p_filesz); | |
179 | } | |
420557e8 | 180 | |
8d5f07fa FB |
181 | static int read_section(int fd, struct elf_shdr *s, void *dst) |
182 | { | |
183 | int retval; | |
420557e8 | 184 | |
8d5f07fa FB |
185 | retval = lseek(fd, s->sh_offset, SEEK_SET); |
186 | if (retval < 0) | |
187 | return -1; | |
188 | retval = read(fd, dst, s->sh_size); | |
189 | if (retval < 0) | |
190 | return -1; | |
191 | return 0; | |
192 | } | |
420557e8 | 193 | |
8d5f07fa FB |
194 | static void *process_section(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) |
195 | { | |
196 | void *dst; | |
197 | ||
198 | dst = find_shdr(ehdr, fd, shdr, type); | |
199 | if (!dst) | |
200 | goto error; | |
201 | ||
202 | if (read_section(fd, shdr, dst)) | |
203 | goto error; | |
204 | return dst; | |
205 | error: | |
206 | qemu_free(dst); | |
207 | return NULL; | |
208 | } | |
420557e8 | 209 | |
8d5f07fa FB |
210 | static void *process_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) |
211 | { | |
212 | void *dst; | |
213 | ||
214 | dst = find_strtab(ehdr, fd, shdr, symtab); | |
215 | if (!dst) | |
216 | goto error; | |
217 | ||
218 | if (read_section(fd, shdr, dst)) | |
219 | goto error; | |
220 | return dst; | |
221 | error: | |
222 | qemu_free(dst); | |
223 | return NULL; | |
224 | } | |
420557e8 | 225 | |
8d5f07fa FB |
226 | static void load_symbols(struct elfhdr *ehdr, int fd) |
227 | { | |
228 | struct elf_shdr symtab, strtab; | |
229 | struct elf_sym *syms; | |
e80cfcfc | 230 | struct syminfo *s; |
8d5f07fa FB |
231 | int nsyms, i; |
232 | char *str; | |
233 | ||
234 | /* Symbol table */ | |
235 | syms = process_section(ehdr, fd, &symtab, SHT_SYMTAB); | |
236 | if (!syms) | |
237 | return; | |
420557e8 | 238 | |
8d5f07fa FB |
239 | nsyms = symtab.sh_size / sizeof(struct elf_sym); |
240 | for (i = 0; i < nsyms; i++) | |
241 | bswap_sym(&syms[i]); | |
242 | ||
243 | /* String table */ | |
244 | str = process_strtab(ehdr, fd, &strtab, &symtab); | |
245 | if (!str) | |
246 | goto error_freesyms; | |
247 | ||
248 | /* Commit */ | |
e80cfcfc FB |
249 | s = qemu_mallocz(sizeof(*s)); |
250 | s->disas_symtab = syms; | |
251 | s->disas_num_syms = nsyms; | |
252 | s->disas_strtab = str; | |
253 | s->next = syminfos; | |
254 | syminfos = s; | |
8d5f07fa FB |
255 | return; |
256 | error_freesyms: | |
257 | qemu_free(syms); | |
258 | return; | |
259 | } | |
420557e8 | 260 | |
e80cfcfc | 261 | int load_elf(const char *filename, uint8_t *addr) |
8d5f07fa FB |
262 | { |
263 | struct elfhdr ehdr; | |
264 | struct elf_phdr phdr; | |
265 | int retval, fd; | |
420557e8 | 266 | |
8d5f07fa FB |
267 | fd = open(filename, O_RDONLY | O_BINARY); |
268 | if (fd < 0) | |
269 | goto error; | |
420557e8 | 270 | |
8d5f07fa FB |
271 | retval = read(fd, &ehdr, sizeof(ehdr)); |
272 | if (retval < 0) | |
273 | goto error; | |
420557e8 | 274 | |
8d5f07fa | 275 | bswap_ehdr(&ehdr); |
420557e8 | 276 | |
8d5f07fa FB |
277 | if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' |
278 | || ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' | |
e80cfcfc FB |
279 | || (ehdr.e_machine != EM_SPARC |
280 | && ehdr.e_machine != EM_SPARC32PLUS)) | |
8d5f07fa | 281 | goto error; |
420557e8 | 282 | |
8d5f07fa FB |
283 | if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) |
284 | goto error; | |
e80cfcfc | 285 | retval = read_program(fd, &phdr, addr, ehdr.e_entry); |
8d5f07fa FB |
286 | if (retval < 0) |
287 | goto error; | |
420557e8 | 288 | |
8d5f07fa | 289 | load_symbols(&ehdr, fd); |
420557e8 | 290 | |
8d5f07fa FB |
291 | close(fd); |
292 | return retval; | |
293 | error: | |
294 | close(fd); | |
295 | return -1; | |
420557e8 | 296 | } |
420557e8 | 297 | |
e80cfcfc | 298 | int load_aout(const char *filename, uint8_t *addr) |
420557e8 | 299 | { |
e80cfcfc FB |
300 | int fd, size, ret; |
301 | struct exec e; | |
302 | uint32_t magic; | |
420557e8 FB |
303 | |
304 | fd = open(filename, O_RDONLY | O_BINARY); | |
305 | if (fd < 0) | |
306 | return -1; | |
e80cfcfc FB |
307 | |
308 | size = read(fd, &e, sizeof(e)); | |
420557e8 FB |
309 | if (size < 0) |
310 | goto fail; | |
e80cfcfc FB |
311 | |
312 | bswap_ahdr(&e); | |
313 | ||
314 | magic = N_MAGIC(e); | |
315 | switch (magic) { | |
316 | case ZMAGIC: | |
317 | case QMAGIC: | |
318 | case OMAGIC: | |
319 | lseek(fd, N_TXTOFF(e), SEEK_SET); | |
320 | size = read(fd, addr, e.a_text + e.a_data); | |
321 | if (size < 0) | |
322 | goto fail; | |
323 | break; | |
324 | case NMAGIC: | |
325 | lseek(fd, N_TXTOFF(e), SEEK_SET); | |
326 | size = read(fd, addr, e.a_text); | |
327 | if (size < 0) | |
328 | goto fail; | |
329 | ret = read(fd, addr + N_DATADDR(e), e.a_data); | |
330 | if (ret < 0) | |
331 | goto fail; | |
332 | size += ret; | |
333 | break; | |
334 | default: | |
335 | goto fail; | |
336 | } | |
420557e8 FB |
337 | close(fd); |
338 | return size; | |
339 | fail: | |
340 | close(fd); | |
341 | return -1; | |
342 | } | |
343 |