Problemas com os relocs
[pspdecompiler.git] / prx.c
blob008139d7bda8d69bd041b59ee0070a4336385bde
2 #include <stdlib.h>
3 #include <string.h>
5 #include "prx.h"
6 #include "allegrex.h"
7 #include "hash.h"
8 #include "utils.h"
10 #define ELF_HEADER_SIZE 52
11 #define ELF_SECTION_HEADER_ENT_SIZE 40
12 #define ELF_PROGRAM_HEADER_ENT_SIZE 32
13 #define ELF_PRX_FLAGS (ELF_FLAGS_MIPS_ARCH2 | ELF_FLAGS_MACH_ALLEGREX | ELF_FLAGS_MACH_ALLEGREX)
14 #define PRX_MODULE_INFO_SIZE 52
17 static const uint8 valid_ident[] = {
18 0x7F, 'E', 'L', 'F',
19 0x01, /* Elf class = ELFCLASS32 */
20 0x01, /* Elf data = ELFDATA2LSB */
21 0x01, /* Version = EV_CURRENT */
22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* Padding */
25 static
26 uint32 read_uint32_le (const uint8 *bytes)
28 uint32 r;
29 r = *bytes++;
30 r |= *bytes++ << 8;
31 r |= *bytes++ << 16;
32 r |= *bytes++ << 24;
33 return r;
36 static
37 uint16 read_uint16_le (const uint8 *bytes)
39 uint16 r;
40 r = *bytes++;
41 r |= *bytes++ << 8;
42 return r;
45 static
46 int inside_prx (struct prx *p, uint32 offset, uint32 size)
48 if (offset >= p->size || size > p->size ||
49 size > (p->size - offset)) return 0;
50 return 1;
53 static
54 int inside_progfile (struct elf_program *program, uint32 vaddr, uint32 size)
56 if (vaddr < program->vaddr || size > program->filesz) return 0;
58 vaddr -= program->vaddr;
59 if (vaddr >= program->filesz || (program->filesz - vaddr) < size) return 0;
60 return 1;
63 static
64 int inside_progmem (struct elf_program *program, uint32 vaddr, uint32 size)
66 if (vaddr < program->vaddr || size > program->memsz) return 0;
68 vaddr -= program->vaddr;
69 if (vaddr >= program->memsz || (program->memsz - vaddr) < size) return 0;
70 return 1;
74 static
75 int inside_strprogfile (struct elf_program *program, uint32 vaddr)
77 if (vaddr < program->vaddr) return 0;
79 vaddr -= program->vaddr;
80 if (vaddr >= program->filesz) return 0;
82 while (vaddr < program->filesz) {
83 if (!program->data[vaddr]) return 1;
84 vaddr++;
87 return 0;
90 static
91 int check_section_header (struct prx *p, uint32 index)
93 struct elf_section *section = &p->sections[index];
95 switch (section->type) {
96 case SHT_NOBITS:
97 break;
98 case SHT_PRXRELOC:
99 case SHT_STRTAB:
100 case SHT_PROGBITS:
101 case SHT_NULL:
102 if (!inside_prx (p, section->offset, section->size)) {
103 error (__FILE__ ": section is not inside ELF/PRX (section %d)", index);
104 return 0;
106 break;
107 default:
108 error (__FILE__ ": invalid section type 0x$08X (section %d)", section->type, index);
109 return 0;
112 return 1;
115 static
116 int check_program_header (struct prx *p, uint32 index)
118 struct elf_program *program = &p->programs[index];
119 if (!inside_prx (p, program->offset, program->filesz)) {
120 error (__FILE__ ": program is not inside ELF/PRX (program %d)", index);
121 return 0;
124 if ((index == 0) && program->type != PT_LOAD) {
125 error (__FILE__ ": first program is not of the type LOAD");
126 return 0;
129 switch (program->type) {
130 case PT_LOAD:
131 if (program->filesz > program->memsz) {
132 error (__FILE__ ": program file size grater than than memory size (program %d)", index);
133 return 0;
135 break;
136 case PT_PRX:
137 if (program->memsz) {
138 error (__FILE__ ": program type must not loaded (program %d)", index);
139 return 0;
141 break;
142 default:
143 error (__FILE__ ": invalid program type 0x$08X (program %d)", program->type, index);
144 return 0;
147 return 1;
150 static
151 int check_relocs (struct prx *p)
153 struct prx_reloc *r;
154 struct elf_program *offsbase;
155 struct elf_program *addrbase;
156 uint32 index, lasthi = -1, addend;
157 int hiused = TRUE;
160 for (index = 0; index < p->relocnum; index++) {
161 r = &p->relocs[index];
162 if (r->offsbase >= p->phnum) {
163 error (__FILE__ ": invalid offset base for relocation (%d)", r->offsbase);
164 return 0;
167 if (r->addrbase >= p->phnum) {
168 error (__FILE__ ": invalid address base for relocation (%d)", r->offsbase);
169 return 0;
172 offsbase = &p->programs[r->offsbase];
173 addrbase = &p->programs[r->addrbase];
175 r->vaddr = r->offset + offsbase->vaddr;
176 if (!inside_progfile (offsbase, r->vaddr, 4)) {
177 error (__FILE__ ": relocation points to invalid address (0x%08X)", r->vaddr);
178 return 0;
181 addend = read_uint32_le (&offsbase->data[r->offset]);
183 switch (r->type) {
184 case R_MIPS_NONE:
185 break;
186 case R_MIPS_26:
187 r->target = (addrbase->vaddr & 0xF0000000) | ((addend & 0x3FFFFFF) << 2);
188 if (!inside_progfile (addrbase, r->target, 8)) {
189 error (__FILE__ ": mips26 relocation to invalid address at 0x%08X (0x%08X)", r->vaddr, r->target);
190 return 0;
192 break;
193 case R_MIPS_HI16:
194 if (!hiused) {
195 /*error (__FILE__ ": hi16 without a matching lo16 relocation at 0x%08X (now at 0x%08X)",
196 p->relocs[lasthi].vaddr, r->vaddr);
197 return 0; */
199 lasthi = index;
200 hiused = FALSE;
201 r->target = (addend & 0xFFFF) << 16;
202 break;
203 case R_MIPS_LO16:
204 if (lasthi == -1) {
205 error (__FILE__ ": lo16 without matching hi16");
206 return 0;
207 } else {
208 struct prx_reloc *last = &p->relocs[lasthi];
209 enum insn_type itype;
211 hiused = TRUE;
212 itype = allegrex_insn_type (addend);
213 r->target = addend & 0xFFFF;
214 if (/*itype != I_ORI &&*/ (r->target & 0x8000)) {
215 r->target |= ~0xFFFF;
217 r->target += last->target + addrbase->vaddr;
218 if (!inside_progmem (addrbase, r->target, 1)) {
219 error (__FILE__ ": invalid hi16/lo16 reference at 0x%08X (0x%08X) (matching hi: 0x%08X)", r->vaddr, r->target, last->vaddr);
220 return 0;
223 break;
225 case R_MIPS_32:
226 r->target = addend;
227 if (!inside_progmem (addrbase, r->target, 1)) {
228 error (__FILE__ ": invalid mips32 reference at 0x%08X (0x%08X)", r->vaddr, r->target);
229 /*return 0;*/
231 break;
233 case R_MIPS_16:
234 case R_MIPS_REL32:
235 case R_MIPS_GPREL16:
236 case R_MIPS_LITERAL:
237 case R_MIPS_GOT16:
238 case R_MIPS_PC16:
239 case R_MIPS_CALL16:
240 case R_MIPS_GPREL32:
241 error (__FILE__ ": invalid reference type %d", r->type);
242 return 0;
247 return 1;
250 static
251 int check_module_info (struct prx *p)
253 struct prx_modinfo *info = p->modinfo;
254 uint32 vaddr, offset;
256 if (info->name[27]) {
257 error (__FILE__ ": module name is not null terminated\n");
258 return 0;
261 if (info->expvaddr) {
262 if (info->expvaddr > info->expvaddrbtm) {
263 error (__FILE__ ": exports bottom is above top (0x%08X - 0x%08X)", info->expvaddr, info->expvaddrbtm);
264 return 0;
266 if (!inside_progfile (p->programs, info->expvaddr, info->expvaddrbtm - info->expvaddr)) {
267 error (__FILE__ ": exports not inside the first program (0x%08X - 0x%08X)", info->expvaddr, info->expvaddrbtm);
268 return 0;
270 info->numexports = 0;
271 offset = prx_translate (p, info->expvaddr);
272 for (vaddr = info->expvaddr; vaddr < info->expvaddrbtm; info->numexports++) {
273 uint32 size;
274 size = p->data[offset+8];
275 if (size < 4) {
276 error (__FILE__ ": export size less than 4 words: %d", size);
277 return 0;
279 vaddr += size << 2;
280 offset += size << 2;
282 if (vaddr != info->expvaddrbtm) {
283 error (__FILE__ ": invalid exports boundary");
284 return 0;
288 if (info->impvaddr) {
289 if (info->impvaddr > info->impvaddrbtm) {
290 error (__FILE__ ": imports bottom is above top (0x%08X - 0x%08X)", info->impvaddr, info->impvaddrbtm);
291 return 0;
293 if (!inside_progfile (p->programs, info->impvaddr, info->impvaddrbtm - info->impvaddr)) {
294 error (__FILE__ ": imports not inside the first program (0x%08X - 0x%08X)", info->impvaddr, info->impvaddrbtm);
295 return 0;
297 info->numimports = 0;
298 offset = prx_translate (p, info->impvaddr);
299 for (vaddr = info->impvaddr; vaddr < info->impvaddrbtm; info->numimports++) {
300 uint32 size;
301 uint8 nvars;
302 size = p->data[offset+8];
303 nvars = p->data[offset+9];
304 if (size < 5) {
305 error (__FILE__ ": import size less than 5 words: %d", size);
306 return 0;
308 if (nvars && size < 6) {
309 error (__FILE__ ": import size less than 6 words: %d", size);
310 return 0;
312 vaddr += size << 2;
313 offset += size << 2;
315 if (vaddr != info->impvaddrbtm) {
316 error (__FILE__ ": invalid imports boundary");
317 return 0;
320 return 1;
323 static
324 int check_module_import (struct prx *p, uint32 index)
326 struct prx_import *imp = &p->modinfo->imports[index];
328 if (!inside_strprogfile (p->programs, imp->namevaddr)) {
329 error (__FILE__ ": import name not inside first program");
330 return 0;
333 if (!imp->nfuncs && !imp->nvars) {
334 error (__FILE__ ": no functions or variables imported");
335 return 0;
338 if (!inside_progfile (p->programs, imp->funcsvaddr, 8 * imp->nfuncs)) {
339 error (__FILE__ ": functions not inside the first program");
340 return 0;
343 if (!inside_progfile (p->programs, imp->nidsvaddr, 4 * imp->nfuncs)) {
344 error (__FILE__ ": nids not inside the first program");
345 return 0;
348 if (imp->nvars) {
349 if (!inside_progfile (p->programs, imp->varsvaddr, 8 * imp->nvars)) {
350 error (__FILE__ ": variables not inside first program");
351 return 0;
356 return 1;
359 static
360 int check_module_export (struct prx *p, uint32 index)
362 struct prx_export *exp = &p->modinfo->exports[index];
364 if (!inside_strprogfile (p->programs, exp->namevaddr)) {
365 error (__FILE__ ": export name not inside first program");
366 return 0;
369 if (!exp->nfuncs && !exp->nvars) {
370 error (__FILE__ ": no functions or variables exported");
371 return 0;
374 if (!inside_progfile (p->programs, exp->expvaddr, 8 * (exp->nfuncs + exp->nvars))) {
375 error (__FILE__ ": functions and variables not inside the first program");
376 return 0;
379 return 1;
382 static
383 int check_elf_header (struct prx *p)
385 uint32 table_size;
387 if (memcmp (p->ident, valid_ident, sizeof (valid_ident))) {
388 error (__FILE__ ": invalid identification for ELF/PRX");
389 return 0;
392 if (p->type != ELF_PRX_TYPE) {
393 error (__FILE__ ": not a PRX file (0x%04X)", p->type);
394 return 0;
397 if (p->machine != ELF_MACHINE_MIPS) {
398 error (__FILE__ ": machine is not MIPS (0x%04X)", p->machine);
399 return 0;
402 if (p->version != ELF_VERSION_CURRENT) {
403 error (__FILE__ ": version is not EV_CURRENT (0x%08X)", p->version);
404 return 0;
407 if (p->ehsize != ELF_HEADER_SIZE) {
408 error (__FILE__ ": wrong ELF header size (%u)", p->ehsize);
409 return 0;
412 if ((p->flags & ELF_PRX_FLAGS) != ELF_PRX_FLAGS) {
413 error (__FILE__ ": wrong ELF flags (0x%08X)", p->flags);
414 return 0;
417 if (p->phnum && p->phentsize != ELF_PROGRAM_HEADER_ENT_SIZE) {
418 error (__FILE__ ": wrong ELF program header entity size (%u)", p->phentsize);
419 return 0;
422 if (!p->phnum) {
423 error (__FILE__ ": PRX has no programs");
424 return 0;
427 table_size = p->phentsize;
428 table_size *= (uint32) p->phnum;
429 if (!inside_prx (p, p->phoff, table_size)) {
430 error (__FILE__ ": wrong ELF program header table offset/size");
431 return 0;
434 if (p->shnum && p->shentsize != ELF_SECTION_HEADER_ENT_SIZE) {
435 error (__FILE__ ": wrong ELF section header entity size (%u)", p->shentsize);
436 return 0;
439 table_size = p->shentsize;
440 table_size *= (uint32) p->shnum;
441 if (!inside_prx (p, p->shoff, table_size)) {
442 error (__FILE__ ": wrong ELF section header table offset/size");
443 return 0;
446 return 1;
450 static
451 int load_sections (struct prx *p)
453 struct elf_section *sections;
454 uint32 idx;
455 uint32 offset;
457 p->sections = NULL;
458 p->secbyname = hashtable_create (64, &hashtable_hash_string, &hashtable_string_compare);
459 if (p->shnum == 0) return 1;
461 sections = xmalloc (p->shnum * sizeof (struct elf_section));
462 p->sections = sections;
464 offset = p->shoff;
465 for (idx = 0; idx < p->shnum; idx++) {
467 sections[idx].idxname = read_uint32_le (&p->data[offset]);
468 sections[idx].type = read_uint32_le (&p->data[offset+4]);
469 sections[idx].flags = read_uint32_le (&p->data[offset+8]);
470 sections[idx].addr = read_uint32_le (&p->data[offset+12]);
471 sections[idx].offset = read_uint32_le (&p->data[offset+16]);
472 sections[idx].size = read_uint32_le (&p->data[offset+20]);
473 sections[idx].link = read_uint32_le (&p->data[offset+24]);
474 sections[idx].info = read_uint32_le (&p->data[offset+28]);
475 sections[idx].addralign = read_uint32_le (&p->data[offset+32]);
476 sections[idx].entsize = read_uint32_le (&p->data[offset+36]);
478 sections[idx].data = &p->data[sections[idx].offset];
480 if (!check_section_header (p, idx))
481 return 0;
483 offset += p->shentsize;
486 if (p->shstrndx > 0) {
487 if (sections[p->shstrndx].type == SHT_STRTAB) {
488 char *strings = (char *) sections[p->shstrndx].data;
489 uint32 max_index = sections[p->shstrndx].size;
490 if (max_index > 0) {
492 if (strings[max_index - 1] != '\0') {
493 error (__FILE__ ": string table section not terminated with null byte");
494 return 0;
497 for (idx = 0; idx < p->shnum; idx++) {
498 if (sections[idx].idxname < max_index) {
499 sections[idx].name = &strings[sections[idx].idxname];
500 } else {
501 error (__FILE__ ": invalid section name");
502 return 0;
505 for (idx = 0; idx < p->shnum; idx++) {
506 hashtable_insert (p->secbyname, (void *) sections[idx].name, &sections[idx]);
512 return 1;
515 static
516 int load_programs (struct prx *p)
518 struct elf_program *programs;
519 uint32 idx;
520 uint32 offset;
522 programs = xmalloc (p->phnum * sizeof (struct elf_program));
523 p->programs = programs;
525 offset = p->phoff;
526 for (idx = 0; idx < p->phnum; idx++) {
527 programs[idx].type = read_uint32_le (&p->data[offset]);
528 programs[idx].offset = read_uint32_le (&p->data[offset+4]);
529 programs[idx].vaddr = read_uint32_le (&p->data[offset+8]);
530 programs[idx].paddr = read_uint32_le (&p->data[offset+12]);
531 programs[idx].filesz = read_uint32_le (&p->data[offset+16]);
532 programs[idx].memsz = read_uint32_le (&p->data[offset+20]);
533 programs[idx].flags = read_uint32_le (&p->data[offset+24]);
534 programs[idx].align = read_uint32_le (&p->data[offset+28]);
536 programs[idx].data = &p->data[programs[idx].offset];
538 if (!check_program_header (p, idx))
539 return 0;
541 offset += p->phentsize;
544 return 1;
547 static
548 int load_relocs (struct prx *p)
550 uint32 i, count = 0;
551 for (i = 0; i < p->shnum; i++) {
552 struct elf_section *section = &p->sections[i];
553 if (section->type == SHT_PRXRELOC) {
554 count += section->size >> 3;
557 p->relocs = NULL;
558 if (!count) return 1;
560 p->relocnum = count;
561 p->relocs = (struct prx_reloc *) xmalloc (count * sizeof (struct prx_reloc));
563 count = 0;
564 for (i = 0; i < p->shnum; i++) {
565 struct elf_section *section = &p->sections[i];
566 if (section->type == SHT_PRXRELOC) {
567 uint32 j, secsize;
568 uint32 offset;
569 offset = section->offset;
570 secsize = section->size >> 3;
571 for (j = 0; j < secsize; j++) {
572 p->relocs[count].offset = read_uint32_le (&p->data[offset]);
573 p->relocs[count].type = p->data[offset + 4];
574 p->relocs[count].offsbase = p->data[offset + 5];
575 p->relocs[count].addrbase = p->data[offset + 6];
576 p->relocs[count].extra = p->data[offset + 7];
578 count++;
579 offset += 8;
584 if (!check_relocs (p)) return 0;
586 return 1;
589 static
590 int load_module_import (struct prx *p, struct prx_import *imp)
592 uint32 i, offset;
593 if (imp->nfuncs) {
594 imp->funcs = (struct prx_function *) xmalloc (imp->nfuncs * sizeof (struct prx_function));
595 offset = prx_translate (p, imp->nidsvaddr);
596 for (i = 0; i < imp->nfuncs; i++) {
597 struct prx_function *f = &imp->funcs[i];
598 f->nid = read_uint32_le (&p->data[offset + 4 * i]);
599 f->vaddr = imp->funcsvaddr + 8 * i;
600 f->name = NULL;
604 if (imp->nvars) {
605 imp->vars = (struct prx_variable *) xmalloc (imp->nvars * sizeof (struct prx_variable));
606 offset = prx_translate (p, imp->varsvaddr);
607 for (i = 0; i < imp->nvars; i++) {
608 struct prx_variable *v = &imp->vars[i];
609 v->nid = read_uint32_le (&p->data[offset + 8 * i + 4]);
610 v->vaddr = read_uint32_le (&p->data[offset + 8 * i]);
611 v->name = NULL;
614 return 1;
617 static
618 int load_module_imports (struct prx *p)
620 uint32 i = 0, offset;
621 struct prx_modinfo *info = p->modinfo;
622 if (!info->impvaddr) return 1;
624 info->imports = (struct prx_import *) xmalloc (info->numimports * sizeof (struct prx_import));
625 memset (info->imports, 0, info->numimports * sizeof (struct prx_import));
627 offset = prx_translate (p, info->impvaddr);
628 for (i = 0; i < info->numimports; i++) {
629 struct prx_import *imp = &info->imports[i];
630 imp->namevaddr = read_uint32_le (&p->data[offset]);
631 imp->flags = read_uint32_le (&p->data[offset+4]);
632 imp->size = p->data[offset+8];
633 imp->nvars = p->data[offset+9];
634 imp->nfuncs = read_uint16_le (&p->data[offset+10]);
635 imp->nidsvaddr = read_uint32_le (&p->data[offset+12]);
636 imp->funcsvaddr = read_uint32_le (&p->data[offset+16]);
637 if (imp->nvars) imp->varsvaddr = read_uint32_le (&p->data[offset+20]);
639 if (!check_module_import (p, i)) return 0;
641 if (imp->namevaddr)
642 imp->name = (const char *) &p->data[prx_translate (p, imp->namevaddr)];
643 else
644 imp->name = NULL;
646 if (!load_module_import (p, imp)) return 0;
647 offset += imp->size << 2;
649 return 1;
652 static
653 const char *resolve_syslib_nid (uint32 nid)
655 switch (nid) {
656 case 0xd3744be0: return "module_bootstart";
657 case 0x2f064fa6: return "module_reboot_before";
658 case 0xadf12745: return "module_reboot_phase";
659 case 0xd632acdb: return "module_start";
660 case 0xcee8593c: return "module_stop";
661 case 0xf01d73a7: return "module_info";
662 case 0x0f7c276c: return "module_start_thread_parameter";
663 case 0xcf0cc697: return "module_stop_thread_parameter";
665 return NULL;
668 static
669 int load_module_export (struct prx *p, struct prx_export *exp)
671 uint32 i, offset, disp;
672 offset = prx_translate (p, exp->expvaddr);
673 disp = 4 * (exp->nfuncs + exp->nvars);
674 if (exp->nfuncs) {
675 exp->funcs = (struct prx_function *) xmalloc (exp->nfuncs * sizeof (struct prx_function));
676 for (i = 0; i < exp->nfuncs; i++) {
677 struct prx_function *f = &exp->funcs[i];
678 f->vaddr = read_uint32_le (&p->data[offset + disp]);
679 f->nid = read_uint32_le (&p->data[offset]);
680 f->name = NULL;
681 offset += 4;
682 if (exp->namevaddr == 0) {
683 f->name = resolve_syslib_nid (f->nid);
688 if (exp->nvars) {
689 exp->vars = (struct prx_variable *) xmalloc (exp->nvars * sizeof (struct prx_variable));
690 for (i = 0; i < exp->nvars; i++) {
691 struct prx_variable *v = &exp->vars[i];
692 v->vaddr = read_uint32_le (&p->data[offset + disp]);
693 v->nid = read_uint32_le (&p->data[offset]);
694 v->name = NULL;
695 offset += 4;
696 if (exp->namevaddr == 0) {
697 v->name = resolve_syslib_nid (v->nid);
701 return 1;
704 static
705 int load_module_exports (struct prx *p)
707 uint32 i = 0, offset;
708 struct prx_modinfo *info = p->modinfo;
709 if (!info->expvaddr) return 1;
711 info->exports = (struct prx_export *) xmalloc (info->numexports * sizeof (struct prx_export));
712 memset (info->exports, 0, info->numexports * sizeof (struct prx_export));
714 offset = prx_translate (p, info->expvaddr);
715 for (i = 0; i < info->numexports; i++) {
716 struct prx_export *exp = &info->exports[i];
717 exp->namevaddr = read_uint32_le (&p->data[offset]);
718 exp->flags = read_uint32_le (&p->data[offset+4]);
719 exp->size = p->data[offset+8];
720 exp->nvars = p->data[offset+9];
721 exp->nfuncs = read_uint16_le (&p->data[offset+10]);
722 exp->expvaddr = read_uint32_le (&p->data[offset+12]);
724 if (!check_module_export (p, i)) return 0;
726 if (exp->namevaddr)
727 exp->name = (const char *) &p->data[prx_translate (p, exp->namevaddr)];
728 else
729 exp->name = "syslib";
731 if (!load_module_export (p, exp)) return 0;
732 offset += exp->size << 2;
734 return 1;
737 static
738 int load_module_info (struct prx *p)
740 struct prx_modinfo *info;
741 uint32 offset;
742 p->modinfo = NULL;
743 if (p->phnum > 0)
744 offset = p->programs[0].paddr & 0x7FFFFFFF;
745 else {
746 error (__FILE__ ": can't find module info for PRX");
747 return 0;
750 info = (struct prx_modinfo *) xmalloc (sizeof (struct prx_modinfo));
751 p->modinfo = info;
753 info->attributes = read_uint16_le (&p->data[offset]);
754 info->version = read_uint16_le (&p->data[offset+2]);
755 info->name = (const char *) &p->data[offset+4];
756 info->gp = read_uint32_le (&p->data[offset+32]);
757 info->expvaddr = read_uint32_le (&p->data[offset+36]);
758 info->expvaddrbtm = read_uint32_le (&p->data[offset+40]);
759 info->impvaddr = read_uint32_le (&p->data[offset+44]);
760 info->impvaddrbtm = read_uint32_le (&p->data[offset+48]);
762 info->imports = NULL;
763 info->exports = NULL;
765 if (!check_module_info (p)) return 0;
767 if (!load_module_imports (p)) return 0;
768 if (!load_module_exports (p)) return 0;
770 return 1;
774 struct prx *prx_load (const char *path)
776 struct prx *p;
777 uint8 *elf_bytes;
778 size_t elf_size;
779 elf_bytes = read_file (path, &elf_size);
781 if (!elf_bytes) return NULL;
783 if (elf_size < ELF_HEADER_SIZE) {
784 error (__FILE__ ": elf size too short");
785 free ((void *) elf_bytes);
786 return NULL;
789 p = xmalloc (sizeof (struct prx));
790 memset (p, 0, sizeof (struct prx));
791 p->size = elf_size;
792 p->data = elf_bytes;
794 memcpy (p->ident, p->data, ELF_HEADER_IDENT);
795 p->type = read_uint16_le (&p->data[ELF_HEADER_IDENT]);
796 p->machine = read_uint16_le (&p->data[ELF_HEADER_IDENT+2]);
798 p->version = read_uint32_le (&p->data[ELF_HEADER_IDENT+4]);
799 p->entry = read_uint32_le (&p->data[ELF_HEADER_IDENT+8]);
800 p->phoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+12]);
801 p->shoff = read_uint32_le (&p->data[ELF_HEADER_IDENT+16]);
802 p->flags = read_uint32_le (&p->data[ELF_HEADER_IDENT+20]);
803 p->ehsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+24]);
804 p->phentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+26]);
805 p->phnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+28]);
806 p->shentsize = read_uint16_le (&p->data[ELF_HEADER_IDENT+30]);
807 p->shnum = read_uint16_le (&p->data[ELF_HEADER_IDENT+32]);
808 p->shstrndx = read_uint16_le (&p->data[ELF_HEADER_IDENT+34]);
810 if (!check_elf_header (p)) {
811 prx_free (p);
812 return NULL;
815 if (!load_sections (p)) {
816 prx_free (p);
817 return NULL;
820 if (!load_programs (p)) {
821 prx_free (p);
822 return NULL;
825 if (!load_relocs (p)) {
826 prx_free (p);
827 return NULL;
830 if (!load_module_info (p)) {
831 prx_free (p);
832 return NULL;
835 return p;
838 static
839 void free_sections (struct prx *p)
841 if (p->sections)
842 free (p->sections);
843 p->sections = NULL;
844 if (p->secbyname)
845 hashtable_free (p->secbyname, NULL, NULL);
846 p->secbyname = NULL;
849 static
850 void free_programs (struct prx *p)
852 if (p->programs)
853 free (p->programs);
854 p->programs = NULL;
857 static
858 void free_relocs (struct prx *p)
860 if (p->relocs)
861 free (p->relocs);
862 p->relocs = NULL;
865 static
866 void free_module_import (struct prx_import *imp)
868 if (imp->funcs) free (imp->funcs);
869 if (imp->vars) free (imp->vars);
870 imp->funcs = NULL;
871 imp->vars = NULL;
874 static
875 void free_module_imports (struct prx *p)
877 if (!p->modinfo) return;
878 if (p->modinfo->imports) {
879 uint32 i;
880 for (i = 0; i < p->modinfo->numimports; i++)
881 free_module_import (&p->modinfo->imports[i]);
882 free (p->modinfo->imports);
884 p->modinfo->imports = NULL;
887 static
888 void free_module_export (struct prx_export *exp)
890 if (exp->funcs) free (exp->funcs);
891 if (exp->vars) free (exp->vars);
892 exp->funcs = NULL;
893 exp->vars = NULL;
896 static
897 void free_module_exports (struct prx *p)
899 if (!p->modinfo) return;
900 if (p->modinfo->exports) {
901 uint32 i;
902 for (i = 0; i < p->modinfo->numexports; i++)
903 free_module_export (&p->modinfo->exports[i]);
904 free (p->modinfo->exports);
906 p->modinfo->imports = NULL;
909 static
910 void free_module_info (struct prx *p)
912 free_module_imports (p);
913 free_module_exports (p);
914 if (p->modinfo)
915 free (p->modinfo);
916 p->modinfo = NULL;
919 void prx_free (struct prx *p)
921 free_sections (p);
922 free_programs (p);
923 free_relocs (p);
924 free_module_info (p);
925 if (p->data)
926 free ((void *) p->data);
927 p->data = NULL;
928 free (p);
931 static
932 void print_sections (struct prx *p)
934 uint32 idx;
935 struct elf_section *section;
936 const char *type = "";
938 if (!p->shnum) return;
939 report ("\nSection Headers:\n");
940 report (" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
942 for (idx = 0; idx < p->shnum; idx++) {
943 section = &p->sections[idx];
944 switch (section->type) {
945 case SHT_NOBITS: type = "NOBITS"; break;
946 case SHT_PRXRELOC: type = "PRXRELOC"; break;
947 case SHT_STRTAB: type = "STRTAB"; break;
948 case SHT_PROGBITS: type = "PROGBITS"; break;
949 case SHT_NULL: type = "NULL"; break;
951 report (" [%2d] %-28s %-10s %08X %08X %08X %02d %s%s%s %2d %2d %2d\n",
952 idx, section->name, type, section->addr, section->offset, section->size,
953 section->entsize, (section->flags & SHF_ALLOC) ? "A" : " ",
954 (section->flags & SHF_EXECINSTR) ? "X" : " ", (section->flags & SHF_WRITE) ? "W" : " ",
955 section->link, section->info, section->addralign);
959 static
960 void print_programs (struct prx *p)
962 uint32 idx;
963 struct elf_program *program;
964 const char *type = "";
966 if (!p->phnum) return;
967 report ("\nProgram Headers:\n");
968 report (" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n");
970 for (idx = 0; idx < p->phnum; idx++) {
971 program = &p->programs[idx];
972 switch (program->type) {
973 case PT_LOAD: type = "LOAD"; break;
974 case PT_PRX: type = "PRX"; break;
977 report (" %-5s 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %s%s%s 0x%02X\n",
978 type, program->offset, program->vaddr, program->paddr, program->filesz,
979 program->memsz, (program->flags & PF_X) ? "X" : " ", (program->flags & PF_R) ? "R" : " ",
980 (program->flags & PF_W) ? "W" : " ", program->align);
984 static
985 void print_module_imports (struct prx *p)
987 uint32 idx, i;
988 struct prx_modinfo *info = p->modinfo;
989 report ("\nImports:\n");
990 for (idx = 0; idx < info->numimports; idx++) {
991 struct prx_import *imp = &info->imports[idx];
992 report (" %s\n", imp->name);
994 report (" Flags: 0x%08X\n", imp->flags);
995 report (" Size: %6d\n", imp->size);
996 report (" Num Variables: %6d\n", imp->nvars);
997 report (" Num Functions: %6d\n", imp->nfuncs);
998 report (" Nids: 0x%08X\n", imp->nidsvaddr);
999 report (" Functions: 0x%08X\n", imp->funcsvaddr);
1001 for (i = 0; i < imp->nfuncs; i++) {
1002 struct prx_function *f = &imp->funcs[i];
1003 report (" NID: 0x%08X VADDR: 0x%08X", f->nid, f->vaddr);
1004 if (f->name)
1005 report (" NAME: %s", f->name);
1006 report ("\n");
1008 if (imp->nvars) {
1009 report (" Variables: 0x%08X\n", imp->varsvaddr);
1010 for (i = 0; i < imp->nvars; i++) {
1011 struct prx_variable *v = &imp->vars[i];
1012 report (" NID: 0x%08X VADDR: 0x%08X", v->nid, v->vaddr);
1013 if (v->name)
1014 report (" NAME: %s", v->name);
1015 report ("\n");
1019 report ("\n");
1023 static
1024 void print_module_exports (struct prx *p)
1026 uint32 idx, i;
1027 struct prx_modinfo *info = p->modinfo;
1028 report ("\nExports:\n");
1029 for (idx = 0; idx < info->numexports; idx++) {
1030 struct prx_export *exp = &info->exports[idx];
1031 report (" %s\n", exp->name);
1033 report (" Flags: 0x%08X\n", exp->flags);
1034 report (" Size: %6d\n", exp->size);
1035 report (" Num Variables: %6d\n", exp->nvars);
1036 report (" Num Functions: %6d\n", exp->nfuncs);
1037 report (" Exports: 0x%08X\n", exp->expvaddr);
1038 if (exp->nfuncs) {
1039 report (" Functions:\n");
1040 for (i = 0; i < exp->nfuncs; i++) {
1041 struct prx_function *f = &exp->funcs[i];
1042 report (" NID: 0x%08X VADDR: 0x%08X", f->nid, f->vaddr);
1043 if (f->name)
1044 report (" NAME: %s", f->name);
1045 report ("\n");
1048 if (exp->nvars) {
1049 report (" Variables:\n");
1050 for (i = 0; i < exp->nvars; i++) {
1051 struct prx_variable *v = &exp->vars[i];
1052 report (" NID: 0x%08X VADDR: 0x%08X", v->nid, v->vaddr);
1053 if (v->name)
1054 report (" NAME: %s", v->name);
1055 report ("\n");
1058 report ("\n");
1062 static
1063 void print_module_info (struct prx *p)
1065 struct prx_modinfo *info = p->modinfo;
1066 if (!info) return;
1068 report ("\nModule info:\n");
1069 report (" Name: %31s\n", info->name);
1070 report (" Attributes: 0x%04X\n", info->attributes);
1071 report (" Version: 0x%04X\n", info->version);
1072 report (" GP: 0x%08X\n", info->gp);
1073 report (" Library entry: 0x%08X\n", info->expvaddr);
1074 report (" Library entry bottom: 0x%08X\n", info->expvaddrbtm);
1075 report (" Library stubs: 0x%08X\n", info->impvaddr);
1076 report (" Library stubs bottom: 0x%08X\n", info->impvaddrbtm);
1078 print_module_imports (p);
1079 print_module_exports (p);
1082 void prx_print (struct prx *p)
1084 report ("ELF header:\n");
1085 report (" Entry point address: 0x%08X\n", p->entry);
1086 report (" Start of program headers: 0x%08X\n", p->phoff);
1087 report (" Start of section headers: 0x%08X\n", p->shoff);
1088 report (" Number of programs: %8d\n", p->phnum);
1089 report (" Number of sections: %8d\n", p->shnum);
1091 print_sections (p);
1092 print_programs (p);
1093 print_module_info (p);
1095 report ("\n");
1098 void prx_resolve_nids (struct prx *p, struct nidstable *nids)
1100 uint32 i, j;
1101 const char *name;
1102 struct prx_modinfo *info = p->modinfo;
1103 for (i = 0; i < info->numimports; i++) {
1104 struct prx_import *imp = &info->imports[i];
1105 for (j = 0; j < imp->nfuncs; j++) {
1106 struct prx_function *f = &imp->funcs[j];
1107 name = nids_find (nids, imp->name, f->nid);
1108 if (name) f->name = name;
1110 for (j = 0; j < imp->nvars; j++) {
1111 struct prx_variable *v = &imp->vars[j];
1112 name = nids_find (nids, imp->name, v->nid);
1113 if (name) v->name = name;
1116 for (i = 0; i < info->numexports; i++) {
1117 struct prx_export *exp = &info->exports[i];
1118 for (j = 0; j < exp->nfuncs; j++) {
1119 struct prx_function *f = &exp->funcs[j];
1120 name = nids_find (nids, exp->name, f->nid);
1121 if (name) f->name = name;
1123 for (j = 0; j < exp->nvars; j++) {
1124 struct prx_variable *v = &exp->vars[j];
1125 name = nids_find (nids, exp->name, v->nid);
1126 if (name) v->name = name;
1131 uint32 prx_translate (struct prx *p, uint32 vaddr)
1133 uint32 idx;
1134 for (idx = 0; idx < p->phnum; idx++) {
1135 struct elf_program *program = &p->programs[idx];
1136 if (program->type != PT_LOAD) continue;
1137 if (vaddr >= program->vaddr &&
1138 (vaddr - program->vaddr) < program->memsz) {
1139 vaddr -= program->vaddr;
1140 if (vaddr < program->filesz)
1141 return vaddr + program->offset;
1142 else
1143 return 0;
1146 return 0;