Passo intermediario, ainda falta um longo caminho
[pspdecompiler.git] / prx.c
blob410df0ceba02f5c4d29e68b6f95330c573496c48
2 #include <stdlib.h>
3 #include <string.h>
5 #include "prx.h"
6 #include "nids.h"
7 #include "utils.h"
9 #define ELF_HEADER_SIZE 52
10 #define ELF_SECTION_HEADER_ENT_SIZE 40
11 #define ELF_PROGRAM_HEADER_ENT_SIZE 32
12 #define ELF_PRX_FLAGS (ELF_FLAGS_MIPS_ARCH2 | ELF_FLAGS_MACH_ALLEGREX | ELF_FLAGS_MACH_ALLEGREX)
13 #define PRX_MODULE_INFO_SIZE 52
15 extern int load_relocs (struct prx *p);
16 extern void free_relocs (struct prx *p);
17 extern void print_relocs (struct prx *p);
19 extern int load_module_info (struct prx *p);
20 extern void free_module_info (struct prx *p);
21 extern void print_module_info (struct prx *p);
24 static const uint8 valid_ident[] = {
25 0x7F, 'E', 'L', 'F',
26 0x01, /* Elf class = ELFCLASS32 */
27 0x01, /* Elf data = ELFDATA2LSB */
28 0x01, /* Version = EV_CURRENT */
29 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* Padding */
32 uint32 read_uint32_le (const uint8 *bytes)
34 uint32 r;
35 r = *bytes++;
36 r |= *bytes++ << 8;
37 r |= *bytes++ << 16;
38 r |= *bytes++ << 24;
39 return r;
42 uint16 read_uint16_le (const uint8 *bytes)
44 uint16 r;
45 r = *bytes++;
46 r |= *bytes++ << 8;
47 return r;
50 void write_uint32_le (uint8 *bytes, uint32 val)
52 bytes[0] = val & 0xFF; val >>= 8;
53 bytes[1] = val & 0xFF; val >>= 8;
54 bytes[2] = val & 0xFF; val >>= 8;
55 bytes[3] = val & 0xFF;
58 int prx_inside_prx (struct prx *p, uint32 offset, uint32 size)
60 if (offset >= p->size || size > p->size ||
61 size > (p->size - offset)) return 0;
62 return 1;
65 int prx_inside_progfile (struct elf_program *program, uint32 vaddr, uint32 size)
67 if (vaddr < program->vaddr || size > program->filesz) return 0;
69 vaddr -= program->vaddr;
70 if (vaddr >= program->filesz || (program->filesz - vaddr) < size) return 0;
71 return 1;
74 int prx_inside_progmem (struct elf_program *program, uint32 vaddr, uint32 size)
76 if (vaddr < program->vaddr || size > program->memsz) return 0;
78 vaddr -= program->vaddr;
79 if (vaddr >= program->memsz || (program->memsz - vaddr) < size) return 0;
80 return 1;
84 int prx_inside_strprogfile (struct elf_program *program, uint32 vaddr)
86 if (vaddr < program->vaddr) return 0;
88 vaddr -= program->vaddr;
89 if (vaddr >= program->filesz) return 0;
91 while (vaddr < program->filesz) {
92 if (!program->data[vaddr]) return 1;
93 vaddr++;
96 return 0;
99 static
100 int check_section_header (struct prx *p, uint32 index)
102 struct elf_section *section = &p->sections[index];
104 switch (section->type) {
105 case SHT_NOBITS:
106 break;
107 case SHT_PRXRELOC:
108 case SHT_STRTAB:
109 case SHT_PROGBITS:
110 case SHT_NULL:
111 if (section->size) {
112 if (!prx_inside_prx (p, section->offset, section->size)) {
113 error (__FILE__ ": section is not inside ELF/PRX (section %d)", index);
114 return 0;
117 break;
118 default:
119 error (__FILE__ ": invalid section type 0x$08X (section %d)", section->type, index);
120 return 0;
123 return 1;
126 static
127 int check_program_header (struct prx *p, uint32 index)
129 struct elf_program *program = &p->programs[index];
130 if (!prx_inside_prx (p, program->offset, program->filesz)) {
131 error (__FILE__ ": program is not inside ELF/PRX (program %d)", index);
132 return 0;
135 if ((index == 0) && program->type != PT_LOAD) {
136 error (__FILE__ ": first program is not of the type LOAD");
137 return 0;
140 switch (program->type) {
141 case PT_LOAD:
142 if (program->filesz > program->memsz) {
143 error (__FILE__ ": program file size grater than than memory size (program %d)", index);
144 return 0;
146 break;
147 case PT_PRXRELOC:
148 case PT_PRXRELOC2:
149 if (program->memsz) {
150 error (__FILE__ ": program type must not loaded (program %d)", index);
151 return 0;
153 break;
154 default:
155 error (__FILE__ ": invalid program type 0x%08X (program %d)", program->type, index);
156 return 0;
159 return 1;
162 static
163 int check_elf_header (struct prx *p)
165 uint32 table_size;
167 if (memcmp (p->ident, valid_ident, sizeof (valid_ident))) {
168 error (__FILE__ ": invalid identification for ELF/PRX");
169 return 0;
172 if (p->type != ELF_PRX_TYPE) {
173 error (__FILE__ ": not a PRX file (0x%04X)", p->type);
174 return 0;
177 if (p->machine != ELF_MACHINE_MIPS) {
178 error (__FILE__ ": machine is not MIPS (0x%04X)", p->machine);
179 return 0;
182 if (p->version != ELF_VERSION_CURRENT) {
183 error (__FILE__ ": version is not EV_CURRENT (0x%08X)", p->version);
184 return 0;
187 if (p->ehsize != ELF_HEADER_SIZE) {
188 error (__FILE__ ": wrong ELF header size (%u)", p->ehsize);
189 return 0;
192 if ((p->flags & ELF_PRX_FLAGS) != ELF_PRX_FLAGS) {
193 error (__FILE__ ": wrong ELF flags (0x%08X)", p->flags);
194 return 0;
197 if (p->phnum && p->phentsize != ELF_PROGRAM_HEADER_ENT_SIZE) {
198 error (__FILE__ ": wrong ELF program header entity size (%u)", p->phentsize);
199 return 0;
202 if (!p->phnum) {
203 error (__FILE__ ": PRX has no programs");
204 return 0;
207 table_size = p->phentsize;
208 table_size *= (uint32) p->phnum;
209 if (!prx_inside_prx (p, p->phoff, table_size)) {
210 error (__FILE__ ": wrong ELF program header table offset/size");
211 return 0;
214 if (p->shnum && p->shentsize != ELF_SECTION_HEADER_ENT_SIZE) {
215 error (__FILE__ ": wrong ELF section header entity size (%u)", p->shentsize);
216 return 0;
219 table_size = p->shentsize;
220 table_size *= (uint32) p->shnum;
221 if (!prx_inside_prx (p, p->shoff, table_size)) {
222 error (__FILE__ ": wrong ELF section header table offset/size");
223 return 0;
226 return 1;
230 static
231 int load_sections (struct prx *p)
233 struct elf_section *sections;
234 uint32 idx;
235 uint32 offset;
237 p->sections = NULL;
238 if (p->shnum == 0) return 1;
240 sections = xmalloc (p->shnum * sizeof (struct elf_section));
241 p->sections = sections;
243 offset = p->shoff;
244 for (idx = 0; idx < p->shnum; idx++) {
246 sections[idx].idxname = read_uint32_le (&p->data[offset]);
247 sections[idx].type = read_uint32_le (&p->data[offset+4]);
248 sections[idx].flags = read_uint32_le (&p->data[offset+8]);
249 sections[idx].addr = read_uint32_le (&p->data[offset+12]);
250 sections[idx].offset = read_uint32_le (&p->data[offset+16]);
251 sections[idx].size = read_uint32_le (&p->data[offset+20]);
252 sections[idx].link = read_uint32_le (&p->data[offset+24]);
253 sections[idx].info = read_uint32_le (&p->data[offset+28]);
254 sections[idx].addralign = read_uint32_le (&p->data[offset+32]);
255 sections[idx].entsize = read_uint32_le (&p->data[offset+36]);
257 sections[idx].data = &p->data[sections[idx].offset];
259 if (!check_section_header (p, idx))
260 return 0;
262 offset += p->shentsize;
265 if (p->shstrndx > 0) {
266 if (sections[p->shstrndx].type == SHT_STRTAB) {
267 char *strings = (char *) sections[p->shstrndx].data;
268 uint32 max_index = sections[p->shstrndx].size;
269 if (max_index > 0) {
271 if (strings[max_index - 1] != '\0') {
272 error (__FILE__ ": string table section not terminated with null byte");
273 return 0;
276 for (idx = 0; idx < p->shnum; idx++) {
277 if (sections[idx].idxname < max_index) {
278 sections[idx].name = &strings[sections[idx].idxname];
279 } else {
280 error (__FILE__ ": invalid section name");
281 return 0;
288 return 1;
291 static
292 int load_programs (struct prx *p)
294 struct elf_program *programs;
295 uint32 idx;
296 uint32 offset;
298 programs = xmalloc (p->phnum * sizeof (struct elf_program));
299 p->programs = programs;
301 offset = p->phoff;
302 for (idx = 0; idx < p->phnum; idx++) {
303 programs[idx].type = read_uint32_le (&p->data[offset]);
304 programs[idx].offset = read_uint32_le (&p->data[offset+4]);
305 programs[idx].vaddr = read_uint32_le (&p->data[offset+8]);
306 programs[idx].paddr = read_uint32_le (&p->data[offset+12]);
307 programs[idx].filesz = read_uint32_le (&p->data[offset+16]);
308 programs[idx].memsz = read_uint32_le (&p->data[offset+20]);
309 programs[idx].flags = read_uint32_le (&p->data[offset+24]);
310 programs[idx].align = read_uint32_le (&p->data[offset+28]);
312 programs[idx].data = &p->data[programs[idx].offset];
314 if (!check_program_header (p, idx))
315 return 0;
317 offset += p->phentsize;
320 return 1;
323 struct prx *prx_load (const char *path)
325 struct prx *p;
326 uint8 *elf_bytes;
327 size_t elf_size;
328 elf_bytes = read_file (path, &elf_size);
330 if (!elf_bytes) return NULL;
332 if (elf_size < ELF_HEADER_SIZE) {
333 error (__FILE__ ": elf size too short");
334 free ((void *) elf_bytes);
335 return NULL;
338 p = xmalloc (sizeof (struct prx));
339 memset (p, 0, sizeof (struct prx));
340 p->size = elf_size;
341 p->data = elf_bytes;
343 memcpy (p->ident, p->data, ELF_HEADER_IDENT);
344 p->type = read_uint16_le (&p->data[ELF_HEADER_IDENT]);
345 p->machine = read_uint16_le (&p->data[ELF_HEADER_IDENT+2]);
347 p->version = read_uint32_le (&p->data[ELF_HEADER_IDENT+4]);
348 p->entry = read_uint32_le (&p->data[ELF_HEADER_IDENT+8]);
349 p->phoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+12]);
350 p->shoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+16]);
351 p->flags = read_uint32_le (&p->data[ELF_HEADER_IDENT+20]);
352 p->ehsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+24]);
353 p->phentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+26]);
354 p->phnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+28]);
355 p->shentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+30]);
356 p->shnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+32]);
357 p->shstrndx = read_uint16_le (&p->data[ELF_HEADER_IDENT+34]);
359 if (!check_elf_header (p)) {
360 prx_free (p);
361 return NULL;
364 if (!load_sections (p)) {
365 prx_free (p);
366 return NULL;
369 if (!load_programs (p)) {
370 prx_free (p);
371 return NULL;
374 if (!load_relocs (p)) {
375 prx_free (p);
376 return NULL;
379 if (!load_module_info (p)) {
380 prx_free (p);
381 return NULL;
384 return p;
387 static
388 void free_sections (struct prx *p)
390 if (p->sections)
391 free (p->sections);
392 p->sections = NULL;
395 static
396 void free_programs (struct prx *p)
398 if (p->programs)
399 free (p->programs);
400 p->programs = NULL;
403 void prx_free (struct prx *p)
405 free_sections (p);
406 free_programs (p);
407 free_relocs (p);
408 free_module_info (p);
409 if (p->data)
410 free ((void *) p->data);
411 p->data = NULL;
412 free (p);
415 static
416 void print_sections (struct prx *p)
418 uint32 idx;
419 struct elf_section *section;
420 const char *type = "";
422 if (!p->shnum) return;
423 report ("\nSection Headers:\n");
424 report (" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
426 for (idx = 0; idx < p->shnum; idx++) {
427 section = &p->sections[idx];
428 switch (section->type) {
429 case SHT_NOBITS: type = "NOBITS"; break;
430 case SHT_PRXRELOC: type = "PRXRELOC"; break;
431 case SHT_STRTAB: type = "STRTAB"; break;
432 case SHT_PROGBITS: type = "PROGBITS"; break;
433 case SHT_NULL: type = "NULL"; break;
435 report (" [%2d] %-28s %-10s %08X %08X %08X %02d %s%s%s %2d %2d %2d\n",
436 idx, section->name, type, section->addr, section->offset, section->size,
437 section->entsize, (section->flags & SHF_ALLOC) ? "A" : " ",
438 (section->flags & SHF_EXECINSTR) ? "X" : " ", (section->flags & SHF_WRITE) ? "W" : " ",
439 section->link, section->info, section->addralign);
443 static
444 void print_programs (struct prx *p)
446 uint32 idx;
447 struct elf_program *program;
448 const char *type = "";
450 if (!p->phnum) return;
451 report ("\nProgram Headers:\n");
452 report (" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n");
454 for (idx = 0; idx < p->phnum; idx++) {
455 program = &p->programs[idx];
456 switch (program->type) {
457 case PT_LOAD: type = "LOAD"; break;
458 case PT_PRXRELOC: type = "REL"; break;
459 case PT_PRXRELOC2: type = "REL2"; break;
462 report (" %-5s 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %s%s%s 0x%02X\n",
463 type, program->offset, program->vaddr, program->paddr, program->filesz,
464 program->memsz, (program->flags & PF_X) ? "X" : " ", (program->flags & PF_R) ? "R" : " ",
465 (program->flags & PF_W) ? "W" : " ", program->align);
469 void prx_print (struct prx *p, int prtrelocs)
471 report ("ELF header:\n");
472 report (" Entry point address: 0x%08X\n", p->entry);
473 report (" Start of program headers: 0x%08X\n", p->phoff);
474 report (" Start of section headers: 0x%08X\n", p->shoff);
475 report (" Number of programs: %8d\n", p->phnum);
476 report (" Number of sections: %8d\n", p->shnum);
478 print_sections (p);
479 print_programs (p);
480 if (prtrelocs)
481 print_relocs (p);
482 print_module_info (p);
484 report ("\n");
487 uint32 prx_translate (struct prx *p, uint32 vaddr)
489 uint32 idx;
490 for (idx = 0; idx < p->phnum; idx++) {
491 struct elf_program *program = &p->programs[idx];
492 if (program->type != PT_LOAD) continue;
493 if (vaddr >= program->vaddr &&
494 (vaddr - program->vaddr) < program->memsz) {
495 vaddr -= program->vaddr;
496 if (vaddr < program->filesz)
497 return vaddr + program->offset;
498 else
499 return 0;
502 return 0;