Revision 3475187d hw/magic-load.c
b/hw/magic-load.c | ||
---|---|---|
56 | 56 |
|
57 | 57 |
#include "elf.h" |
58 | 58 |
|
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 |
} |
|
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) |
|
59 |
#ifndef BSWAP_NEEDED |
|
60 |
#define bswap_ehdr32(e) do { } while (0) |
|
61 |
#define bswap_phdr32(e) do { } while (0) |
|
62 |
#define bswap_shdr32(e) do { } while (0) |
|
63 |
#define bswap_sym32(e) do { } while (0) |
|
64 |
#ifdef TARGET_SPARC64 |
|
65 |
#define bswap_ehdr64(e) do { } while (0) |
|
66 |
#define bswap_phdr64(e) do { } while (0) |
|
67 |
#define bswap_shdr64(e) do { } while (0) |
|
68 |
#define bswap_sym64(e) do { } while (0) |
|
69 |
#endif |
|
115 | 70 |
#endif |
116 | 71 |
|
117 |
static int find_phdr(struct elfhdr *ehdr, int fd, struct elf_phdr *phdr, uint32_t type) |
|
118 |
{ |
|
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; |
|
132 |
} |
|
133 |
return -1; |
|
134 |
} |
|
135 |
|
|
136 |
static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint32_t type) |
|
137 |
{ |
|
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); |
|
151 |
} |
|
152 |
return NULL; |
|
153 |
} |
|
154 |
|
|
155 |
static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab) |
|
156 |
{ |
|
157 |
int retval; |
|
158 |
|
|
159 |
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET); |
|
160 |
if (retval < 0) |
|
161 |
return NULL; |
|
162 |
|
|
163 |
retval = read(fd, shdr, sizeof(*shdr)); |
|
164 |
if (retval < 0) |
|
165 |
return NULL; |
|
166 |
bswap_shdr(shdr); |
|
167 |
if (shdr->sh_type == SHT_STRTAB) |
|
168 |
return qemu_malloc(shdr->sh_size);; |
|
169 |
return NULL; |
|
170 |
} |
|
171 |
|
|
172 |
static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry) |
|
173 |
{ |
|
174 |
int retval; |
|
175 |
retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET); |
|
176 |
if (retval < 0) |
|
177 |
return -1; |
|
178 |
return read(fd, dst, phdr->p_filesz); |
|
179 |
} |
|
180 |
|
|
181 |
static int read_section(int fd, struct elf_shdr *s, void *dst) |
|
182 |
{ |
|
183 |
int retval; |
|
184 |
|
|
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 |
} |
|
193 |
|
|
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 |
} |
|
209 |
|
|
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 |
} |
|
225 |
|
|
226 |
static void load_symbols(struct elfhdr *ehdr, int fd) |
|
227 |
{ |
|
228 |
struct elf_shdr symtab, strtab; |
|
229 |
struct elf_sym *syms; |
|
230 |
struct syminfo *s; |
|
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; |
|
238 |
|
|
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 */ |
|
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; |
|
255 |
return; |
|
256 |
error_freesyms: |
|
257 |
qemu_free(syms); |
|
258 |
return; |
|
259 |
} |
|
72 |
#define SZ 32 |
|
73 |
#define elf_word uint32_t |
|
74 |
#define bswapSZs bswap32s |
|
75 |
#include "elf_ops.h" |
|
76 |
|
|
77 |
#ifdef TARGET_SPARC64 |
|
78 |
#undef elfhdr |
|
79 |
#undef elf_phdr |
|
80 |
#undef elf_shdr |
|
81 |
#undef elf_sym |
|
82 |
#undef elf_note |
|
83 |
#undef elf_word |
|
84 |
#undef bswapSZs |
|
85 |
#undef SZ |
|
86 |
#define elfhdr elf64_hdr |
|
87 |
#define elf_phdr elf64_phdr |
|
88 |
#define elf_note elf64_note |
|
89 |
#define elf_shdr elf64_shdr |
|
90 |
#define elf_sym elf64_sym |
|
91 |
#define elf_word uint64_t |
|
92 |
#define bswapSZs bswap64s |
|
93 |
#define SZ 64 |
|
94 |
#include "elf_ops.h" |
|
95 |
#endif |
|
260 | 96 |
|
261 | 97 |
int load_elf(const char *filename, uint8_t *addr) |
262 | 98 |
{ |
263 |
struct elfhdr ehdr; |
|
264 |
struct elf_phdr phdr; |
|
99 |
struct elf32_hdr ehdr; |
|
265 | 100 |
int retval, fd; |
101 |
Elf32_Half machine; |
|
266 | 102 |
|
267 | 103 |
fd = open(filename, O_RDONLY | O_BINARY); |
268 | 104 |
if (fd < 0) |
... | ... | |
272 | 108 |
if (retval < 0) |
273 | 109 |
goto error; |
274 | 110 |
|
275 |
bswap_ehdr(&ehdr); |
|
276 |
|
|
277 | 111 |
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' |
278 |
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F' |
|
279 |
|| (ehdr.e_machine != EM_SPARC |
|
280 |
&& ehdr.e_machine != EM_SPARC32PLUS)) |
|
112 |
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') |
|
281 | 113 |
goto error; |
114 |
machine = tswap16(ehdr.e_machine); |
|
115 |
if (machine == EM_SPARC || machine == EM_SPARC32PLUS) { |
|
116 |
struct elf32_phdr phdr; |
|
282 | 117 |
|
283 |
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD)) |
|
284 |
goto error; |
|
285 |
retval = read_program(fd, &phdr, addr, ehdr.e_entry); |
|
286 |
if (retval < 0) |
|
287 |
goto error; |
|
118 |
bswap_ehdr32(&ehdr); |
|
288 | 119 |
|
289 |
load_symbols(&ehdr, fd); |
|
120 |
if (find_phdr32(&ehdr, fd, &phdr, PT_LOAD)) |
|
121 |
goto error; |
|
122 |
retval = read_program32(fd, &phdr, addr, ehdr.e_entry); |
|
123 |
if (retval < 0) |
|
124 |
goto error; |
|
125 |
load_symbols32(&ehdr, fd); |
|
126 |
} |
|
127 |
#ifdef TARGET_SPARC64 |
|
128 |
else if (machine == EM_SPARCV9) { |
|
129 |
struct elf64_hdr ehdr64; |
|
130 |
struct elf64_phdr phdr; |
|
131 |
|
|
132 |
lseek(fd, 0, SEEK_SET); |
|
133 |
|
|
134 |
retval = read(fd, &ehdr64, sizeof(ehdr64)); |
|
135 |
if (retval < 0) |
|
136 |
goto error; |
|
137 |
|
|
138 |
bswap_ehdr64(&ehdr64); |
|
139 |
|
|
140 |
if (find_phdr64(&ehdr64, fd, &phdr, PT_LOAD)) |
|
141 |
goto error; |
|
142 |
retval = read_program64(fd, &phdr, addr, ehdr64.e_entry); |
|
143 |
if (retval < 0) |
|
144 |
goto error; |
|
145 |
load_symbols64(&ehdr64, fd); |
|
146 |
} |
|
147 |
#endif |
|
290 | 148 |
|
291 | 149 |
close(fd); |
292 | 150 |
return retval; |
Also available in: Unified diff