Ainda faltam muitas mudancas
[pspdecompiler.git] / prx.c
blob65dc18e8dd03d8191269e879200f55bbb1f5de0a
1 /**
2 * Author: Humberto Naves (hsnaves@gmail.com)
3 */
5 #include <stdlib.h>
6 #include <string.h>
8 #include "prx.h"
9 #include "nids.h"
10 #include "utils.h"
12 #define ELF_HEADER_SIZE 52
13 #define ELF_SECTION_HEADER_ENT_SIZE 40
14 #define ELF_PROGRAM_HEADER_ENT_SIZE 32
15 #define ELF_PRX_FLAGS (ELF_FLAGS_MIPS_ARCH2 | ELF_FLAGS_MACH_ALLEGREX | ELF_FLAGS_MACH_ALLEGREX)
16 #define PRX_MODULE_INFO_SIZE 52
18 extern int load_relocs (struct prx *p);
19 extern void free_relocs (struct prx *p);
20 extern void print_relocs (struct prx *p);
22 extern int load_module_info (struct prx *p);
23 extern void free_module_info (struct prx *p);
24 extern void print_module_info (struct prx *p);
27 static const uint8 valid_ident[] = {
28 0x7F, 'E', 'L', 'F',
29 0x01, /* Elf class = ELFCLASS32 */
30 0x01, /* Elf data = ELFDATA2LSB */
31 0x01, /* Version = EV_CURRENT */
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* Padding */
35 uint32 read_uint32_le (const uint8 *bytes)
37 uint32 r;
38 r = *bytes++;
39 r |= *bytes++ << 8;
40 r |= *bytes++ << 16;
41 r |= *bytes++ << 24;
42 return r;
45 uint16 read_uint16_le (const uint8 *bytes)
47 uint16 r;
48 r = *bytes++;
49 r |= *bytes++ << 8;
50 return r;
53 void write_uint32_le (uint8 *bytes, uint32 val)
55 bytes[0] = val & 0xFF; val >>= 8;
56 bytes[1] = val & 0xFF; val >>= 8;
57 bytes[2] = val & 0xFF; val >>= 8;
58 bytes[3] = val & 0xFF;
61 int prx_inside_prx (struct prx *p, uint32 offset, uint32 size)
63 if (offset >= p->size || size > p->size ||
64 size > (p->size - offset)) return 0;
65 return 1;
68 int prx_inside_progfile (struct elf_program *program, uint32 vaddr, uint32 size)
70 if (vaddr < program->vaddr || size > program->filesz) return 0;
72 vaddr -= program->vaddr;
73 if (vaddr >= program->filesz || (program->filesz - vaddr) < size) return 0;
74 return 1;
77 int prx_inside_progmem (struct elf_program *program, uint32 vaddr, uint32 size)
79 if (vaddr < program->vaddr || size > program->memsz) return 0;
81 vaddr -= program->vaddr;
82 if (vaddr >= program->memsz || (program->memsz - vaddr) < size) return 0;
83 return 1;
87 int prx_inside_strprogfile (struct elf_program *program, uint32 vaddr)
89 if (vaddr < program->vaddr) return 0;
91 vaddr -= program->vaddr;
92 if (vaddr >= program->filesz) return 0;
94 while (vaddr < program->filesz) {
95 if (!program->data[vaddr]) return 1;
96 vaddr++;
99 return 0;
102 static
103 int check_section_header (struct prx *p, uint32 index)
105 struct elf_section *section = &p->sections[index];
107 switch (section->type) {
108 case SHT_NOBITS:
109 break;
110 case SHT_PRXRELOC:
111 case SHT_STRTAB:
112 case SHT_PROGBITS:
113 case SHT_NULL:
114 if (section->size) {
115 if (!prx_inside_prx (p, section->offset, section->size)) {
116 error (__FILE__ ": section is not inside ELF/PRX (section %d)", index);
117 return 0;
120 break;
121 default:
122 error (__FILE__ ": invalid section type 0x$08X (section %d)", section->type, index);
123 return 0;
126 return 1;
129 static
130 int check_program_header (struct prx *p, uint32 index)
132 struct elf_program *program = &p->programs[index];
133 if (!prx_inside_prx (p, program->offset, program->filesz)) {
134 error (__FILE__ ": program is not inside ELF/PRX (program %d)", index);
135 return 0;
138 if ((index == 0) && program->type != PT_LOAD) {
139 error (__FILE__ ": first program is not of the type LOAD");
140 return 0;
143 switch (program->type) {
144 case PT_LOAD:
145 if (program->filesz > program->memsz) {
146 error (__FILE__ ": program file size grater than than memory size (program %d)", index);
147 return 0;
149 break;
150 case PT_PRXRELOC:
151 case PT_PRXRELOC2:
152 if (program->memsz) {
153 error (__FILE__ ": program type must not loaded (program %d)", index);
154 return 0;
156 break;
157 default:
158 error (__FILE__ ": invalid program type 0x%08X (program %d)", program->type, index);
159 return 0;
162 return 1;
165 static
166 int check_elf_header (struct prx *p)
168 uint32 table_size;
170 if (memcmp (p->ident, valid_ident, sizeof (valid_ident))) {
171 error (__FILE__ ": invalid identification for ELF/PRX");
172 return 0;
175 if (p->type != ELF_PRX_TYPE) {
176 error (__FILE__ ": not a PRX file (0x%04X)", p->type);
177 return 0;
180 if (p->machine != ELF_MACHINE_MIPS) {
181 error (__FILE__ ": machine is not MIPS (0x%04X)", p->machine);
182 return 0;
185 if (p->version != ELF_VERSION_CURRENT) {
186 error (__FILE__ ": version is not EV_CURRENT (0x%08X)", p->version);
187 return 0;
190 if (p->ehsize != ELF_HEADER_SIZE) {
191 error (__FILE__ ": wrong ELF header size (%u)", p->ehsize);
192 return 0;
195 if ((p->flags & ELF_PRX_FLAGS) != ELF_PRX_FLAGS) {
196 error (__FILE__ ": wrong ELF flags (0x%08X)", p->flags);
197 return 0;
200 if (p->phnum && p->phentsize != ELF_PROGRAM_HEADER_ENT_SIZE) {
201 error (__FILE__ ": wrong ELF program header entity size (%u)", p->phentsize);
202 return 0;
205 if (!p->phnum) {
206 error (__FILE__ ": PRX has no programs");
207 return 0;
210 table_size = p->phentsize;
211 table_size *= (uint32) p->phnum;
212 if (!prx_inside_prx (p, p->phoff, table_size)) {
213 error (__FILE__ ": wrong ELF program header table offset/size");
214 return 0;
217 if (p->shnum && p->shentsize != ELF_SECTION_HEADER_ENT_SIZE) {
218 error (__FILE__ ": wrong ELF section header entity size (%u)", p->shentsize);
219 return 0;
222 table_size = p->shentsize;
223 table_size *= (uint32) p->shnum;
224 if (!prx_inside_prx (p, p->shoff, table_size)) {
225 error (__FILE__ ": wrong ELF section header table offset/size");
226 return 0;
229 return 1;
233 static
234 int load_sections (struct prx *p)
236 struct elf_section *sections;
237 uint32 idx;
238 uint32 offset;
240 p->sections = NULL;
241 if (p->shnum == 0) return 1;
243 sections = xmalloc (p->shnum * sizeof (struct elf_section));
244 p->sections = sections;
246 offset = p->shoff;
247 for (idx = 0; idx < p->shnum; idx++) {
249 sections[idx].idxname = read_uint32_le (&p->data[offset]);
250 sections[idx].type = read_uint32_le (&p->data[offset+4]);
251 sections[idx].flags = read_uint32_le (&p->data[offset+8]);
252 sections[idx].addr = read_uint32_le (&p->data[offset+12]);
253 sections[idx].offset = read_uint32_le (&p->data[offset+16]);
254 sections[idx].size = read_uint32_le (&p->data[offset+20]);
255 sections[idx].link = read_uint32_le (&p->data[offset+24]);
256 sections[idx].info = read_uint32_le (&p->data[offset+28]);
257 sections[idx].addralign = read_uint32_le (&p->data[offset+32]);
258 sections[idx].entsize = read_uint32_le (&p->data[offset+36]);
260 sections[idx].data = &p->data[sections[idx].offset];
262 if (!check_section_header (p, idx))
263 return 0;
265 offset += p->shentsize;
268 if (p->shstrndx > 0) {
269 if (sections[p->shstrndx].type == SHT_STRTAB) {
270 char *strings = (char *) sections[p->shstrndx].data;
271 uint32 max_index = sections[p->shstrndx].size;
272 if (max_index > 0) {
274 if (strings[max_index - 1] != '\0') {
275 error (__FILE__ ": string table section not terminated with null byte");
276 return 0;
279 for (idx = 0; idx < p->shnum; idx++) {
280 if (sections[idx].idxname < max_index) {
281 sections[idx].name = &strings[sections[idx].idxname];
282 } else {
283 error (__FILE__ ": invalid section name");
284 return 0;
291 return 1;
294 static
295 int load_programs (struct prx *p)
297 struct elf_program *programs;
298 uint32 idx;
299 uint32 offset;
301 programs = xmalloc (p->phnum * sizeof (struct elf_program));
302 p->programs = programs;
304 offset = p->phoff;
305 for (idx = 0; idx < p->phnum; idx++) {
306 programs[idx].type = read_uint32_le (&p->data[offset]);
307 programs[idx].offset = read_uint32_le (&p->data[offset+4]);
308 programs[idx].vaddr = read_uint32_le (&p->data[offset+8]);
309 programs[idx].paddr = read_uint32_le (&p->data[offset+12]);
310 programs[idx].filesz = read_uint32_le (&p->data[offset+16]);
311 programs[idx].memsz = read_uint32_le (&p->data[offset+20]);
312 programs[idx].flags = read_uint32_le (&p->data[offset+24]);
313 programs[idx].align = read_uint32_le (&p->data[offset+28]);
315 programs[idx].data = &p->data[programs[idx].offset];
317 if (!check_program_header (p, idx))
318 return 0;
320 offset += p->phentsize;
323 return 1;
326 struct prx *prx_load (const char *path)
328 struct prx *p;
329 uint8 *elf_bytes;
330 size_t elf_size;
331 elf_bytes = read_file (path, &elf_size);
333 if (!elf_bytes) return NULL;
335 if (elf_size < ELF_HEADER_SIZE) {
336 error (__FILE__ ": elf size too short");
337 free ((void *) elf_bytes);
338 return NULL;
341 p = xmalloc (sizeof (struct prx));
342 memset (p, 0, sizeof (struct prx));
343 p->size = elf_size;
344 p->data = elf_bytes;
346 memcpy (p->ident, p->data, ELF_HEADER_IDENT);
347 p->type = read_uint16_le (&p->data[ELF_HEADER_IDENT]);
348 p->machine = read_uint16_le (&p->data[ELF_HEADER_IDENT+2]);
350 p->version = read_uint32_le (&p->data[ELF_HEADER_IDENT+4]);
351 p->entry = read_uint32_le (&p->data[ELF_HEADER_IDENT+8]);
352 p->phoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+12]);
353 p->shoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+16]);
354 p->flags = read_uint32_le (&p->data[ELF_HEADER_IDENT+20]);
355 p->ehsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+24]);
356 p->phentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+26]);
357 p->phnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+28]);
358 p->shentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+30]);
359 p->shnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+32]);
360 p->shstrndx = read_uint16_le (&p->data[ELF_HEADER_IDENT+34]);
362 if (!check_elf_header (p)) {
363 prx_free (p);
364 return NULL;
367 if (!load_sections (p)) {
368 prx_free (p);
369 return NULL;
372 if (!load_programs (p)) {
373 prx_free (p);
374 return NULL;
377 if (!load_relocs (p)) {
378 prx_free (p);
379 return NULL;
382 if (!load_module_info (p)) {
383 prx_free (p);
384 return NULL;
387 return p;
390 static
391 void free_sections (struct prx *p)
393 if (p->sections)
394 free (p->sections);
395 p->sections = NULL;
398 static
399 void free_programs (struct prx *p)
401 if (p->programs)
402 free (p->programs);
403 p->programs = NULL;
406 void prx_free (struct prx *p)
408 free_sections (p);
409 free_programs (p);
410 free_relocs (p);
411 free_module_info (p);
412 if (p->data)
413 free ((void *) p->data);
414 p->data = NULL;
415 free (p);
418 static
419 void print_sections (struct prx *p)
421 uint32 idx;
422 struct elf_section *section;
423 const char *type = "";
425 if (!p->shnum) return;
426 report ("\nSection Headers:\n");
427 report (" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
429 for (idx = 0; idx < p->shnum; idx++) {
430 section = &p->sections[idx];
431 switch (section->type) {
432 case SHT_NOBITS: type = "NOBITS"; break;
433 case SHT_PRXRELOC: type = "PRXRELOC"; break;
434 case SHT_STRTAB: type = "STRTAB"; break;
435 case SHT_PROGBITS: type = "PROGBITS"; break;
436 case SHT_NULL: type = "NULL"; break;
438 report (" [%2d] %-28s %-10s %08X %08X %08X %02d %s%s%s %2d %2d %2d\n",
439 idx, section->name, type, section->addr, section->offset, section->size,
440 section->entsize, (section->flags & SHF_ALLOC) ? "A" : " ",
441 (section->flags & SHF_EXECINSTR) ? "X" : " ", (section->flags & SHF_WRITE) ? "W" : " ",
442 section->link, section->info, section->addralign);
446 static
447 void print_programs (struct prx *p)
449 uint32 idx;
450 struct elf_program *program;
451 const char *type = "";
453 if (!p->phnum) return;
454 report ("\nProgram Headers:\n");
455 report (" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n");
457 for (idx = 0; idx < p->phnum; idx++) {
458 program = &p->programs[idx];
459 switch (program->type) {
460 case PT_LOAD: type = "LOAD"; break;
461 case PT_PRXRELOC: type = "REL"; break;
462 case PT_PRXRELOC2: type = "REL2"; break;
465 report (" %-5s 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %s%s%s 0x%02X\n",
466 type, program->offset, program->vaddr, program->paddr, program->filesz,
467 program->memsz, (program->flags & PF_X) ? "X" : " ", (program->flags & PF_R) ? "R" : " ",
468 (program->flags & PF_W) ? "W" : " ", program->align);
472 void prx_print (struct prx *p, int prtrelocs)
474 report ("ELF header:\n");
475 report (" Entry point address: 0x%08X\n", p->entry);
476 report (" Start of program headers: 0x%08X\n", p->phoff);
477 report (" Start of section headers: 0x%08X\n", p->shoff);
478 report (" Number of programs: %8d\n", p->phnum);
479 report (" Number of sections: %8d\n", p->shnum);
481 print_sections (p);
482 print_programs (p);
483 if (prtrelocs)
484 print_relocs (p);
485 print_module_info (p);
487 report ("\n");
490 uint32 prx_translate (struct prx *p, uint32 vaddr)
492 uint32 idx;
493 for (idx = 0; idx < p->phnum; idx++) {
494 struct elf_program *program = &p->programs[idx];
495 if (program->type != PT_LOAD) continue;
496 if (vaddr >= program->vaddr &&
497 (vaddr - program->vaddr) < program->memsz) {
498 vaddr -= program->vaddr;
499 if (vaddr < program->filesz)
500 return vaddr + program->offset;
501 else
502 return 0;
505 return 0;