2 * Author: Humberto Naves (hsnaves@gmail.com)
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
[] = {
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
)
45 uint16
read_uint16_le (const uint8
*bytes
)
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;
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;
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;
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;
103 int check_section_header (struct prx
*p
, uint32 index
)
105 struct elf_section
*section
= &p
->sections
[index
];
107 switch (section
->type
) {
115 if (!prx_inside_prx (p
, section
->offset
, section
->size
)) {
116 error (__FILE__
": section is not inside ELF/PRX (section %d)", index
);
122 error (__FILE__
": invalid section type 0x$08X (section %d)", section
->type
, index
);
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
);
138 if ((index
== 0) && program
->type
!= PT_LOAD
) {
139 error (__FILE__
": first program is not of the type LOAD");
143 switch (program
->type
) {
145 if (program
->filesz
> program
->memsz
) {
146 error (__FILE__
": program file size grater than than memory size (program %d)", index
);
152 if (program
->memsz
) {
153 error (__FILE__
": program type must not loaded (program %d)", index
);
158 error (__FILE__
": invalid program type 0x%08X (program %d)", program
->type
, index
);
166 int check_elf_header (struct prx
*p
)
170 if (memcmp (p
->ident
, valid_ident
, sizeof (valid_ident
))) {
171 error (__FILE__
": invalid identification for ELF/PRX");
175 if (p
->type
!= ELF_PRX_TYPE
) {
176 error (__FILE__
": not a PRX file (0x%04X)", p
->type
);
180 if (p
->machine
!= ELF_MACHINE_MIPS
) {
181 error (__FILE__
": machine is not MIPS (0x%04X)", p
->machine
);
185 if (p
->version
!= ELF_VERSION_CURRENT
) {
186 error (__FILE__
": version is not EV_CURRENT (0x%08X)", p
->version
);
190 if (p
->ehsize
!= ELF_HEADER_SIZE
) {
191 error (__FILE__
": wrong ELF header size (%u)", p
->ehsize
);
195 if ((p
->flags
& ELF_PRX_FLAGS
) != ELF_PRX_FLAGS
) {
196 error (__FILE__
": wrong ELF flags (0x%08X)", p
->flags
);
200 if (p
->phnum
&& p
->phentsize
!= ELF_PROGRAM_HEADER_ENT_SIZE
) {
201 error (__FILE__
": wrong ELF program header entity size (%u)", p
->phentsize
);
206 error (__FILE__
": PRX has no programs");
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");
217 if (p
->shnum
&& p
->shentsize
!= ELF_SECTION_HEADER_ENT_SIZE
) {
218 error (__FILE__
": wrong ELF section header entity size (%u)", p
->shentsize
);
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");
234 int load_sections (struct prx
*p
)
236 struct elf_section
*sections
;
241 if (p
->shnum
== 0) return 1;
243 sections
= xmalloc (p
->shnum
* sizeof (struct elf_section
));
244 p
->sections
= sections
;
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
))
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
;
274 if (strings
[max_index
- 1] != '\0') {
275 error (__FILE__
": string table section not terminated with null byte");
279 for (idx
= 0; idx
< p
->shnum
; idx
++) {
280 if (sections
[idx
].idxname
< max_index
) {
281 sections
[idx
].name
= &strings
[sections
[idx
].idxname
];
283 error (__FILE__
": invalid section name");
295 int load_programs (struct prx
*p
)
297 struct elf_program
*programs
;
301 programs
= xmalloc (p
->phnum
* sizeof (struct elf_program
));
302 p
->programs
= programs
;
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
))
320 offset
+= p
->phentsize
;
326 struct prx
*prx_load (const char *path
)
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
);
341 p
= xmalloc (sizeof (struct prx
));
342 memset (p
, 0, sizeof (struct prx
));
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
)) {
367 if (!load_sections (p
)) {
372 if (!load_programs (p
)) {
377 if (!load_relocs (p
)) {
382 if (!load_module_info (p
)) {
391 void free_sections (struct prx
*p
)
399 void free_programs (struct prx
*p
)
406 void prx_free (struct prx
*p
)
411 free_module_info (p
);
413 free ((void *) p
->data
);
419 void print_sections (struct prx
*p
)
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
);
447 void print_programs (struct prx
*p
)
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
);
485 print_module_info (p
);
490 uint32
prx_translate (struct prx
*p
, uint32 vaddr
)
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
;