Support XCOFF entrypoint and imports via loader ##bin
This commit is contained in:
parent
9996cfeb3d
commit
1a4d6e7fe3
|
@ -89,16 +89,73 @@ static int r_coff_rebase_sym(RBinCoffObj *obj, RBinAddr *addr, struct coff_symbo
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* Try to get a valid entrypoint using the methods outlined in
|
||||
* http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#SEC24 */
|
||||
R_IPI RBinAddr *r_coff_get_entry(RBinCoffObj *obj) {
|
||||
if (obj->xcoff) {
|
||||
/* In XCOFF32, the entrypoint seems to be indirect.
|
||||
At the entrypoint address, we find a pointer in .data,
|
||||
that resolves to the actual entrypoint. */
|
||||
|
||||
static RBinAddr *r_xcoff_get_entry(RBinCoffObj *obj) {
|
||||
/* Scan XCOFF loader symbol table */
|
||||
int ptr_scnum = 0;
|
||||
ut64 ptr_vaddr;
|
||||
if (obj->x_ldsyms) {
|
||||
int i;
|
||||
for (i = 0; i < obj->x_ldhdr.l_nsyms; i++) {
|
||||
if (!strcmp (obj->x_ldsyms[i].l_name, "__start")) {
|
||||
ptr_scnum = obj->x_ldsyms[i].l_scnum;
|
||||
ptr_vaddr = obj->x_ldsyms[i].l_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ptr_scnum) {
|
||||
return NULL;
|
||||
}
|
||||
/* Translate the pointer to a file offset */
|
||||
if (ptr_scnum < 1 || ptr_scnum > obj->hdr.f_nscns) {
|
||||
R_LOG_WARN ("__start l_scnum invalid (%d)", ptr_scnum);
|
||||
return NULL;
|
||||
}
|
||||
ut64 ptr_offset = obj->scn_hdrs[ptr_scnum - 1].s_scnptr + ptr_vaddr - obj->scn_hdrs[ptr_scnum - 1].s_vaddr;
|
||||
|
||||
/* Read the actual entrypoint */
|
||||
ut32 entry_vaddr = r_buf_read_be32_at (obj->b, ptr_offset);
|
||||
if (entry_vaddr == UT32_MAX) {
|
||||
R_LOG_WARN ("__start vaddr invalid (vaddr=%#x off=%#x)", ptr_vaddr, ptr_offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Double check that the entrypoint is in .text */
|
||||
int sntext = obj->x_opt_hdr.o_sntext;
|
||||
if (sntext < 1 || sntext > obj->hdr.f_nscns) {
|
||||
R_LOG_WARN ("o_sntext invalid (%d)", sntext);
|
||||
return NULL;
|
||||
}
|
||||
ut32 text_vaddr = obj->scn_hdrs[sntext - 1].s_vaddr;
|
||||
ut32 text_size = obj->scn_hdrs[sntext - 1].s_size;
|
||||
if (entry_vaddr < text_vaddr || entry_vaddr >= text_vaddr + text_size) {
|
||||
R_LOG_WARN ("*__start OOB (vaddr=%#lx text=%#lx..%#lx)", entry_vaddr, text_vaddr, text_vaddr + text_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RBinAddr *addr = R_NEW0 (RBinAddr);
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
addr->vaddr = entry_vaddr;
|
||||
return addr;
|
||||
}
|
||||
|
||||
/* Try to get a valid entrypoint using the methods outlined in
|
||||
* http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#SEC24 */
|
||||
R_IPI RBinAddr *r_coff_get_entry(RBinCoffObj *obj) {
|
||||
RBinAddr *addr = R_NEW0 (RBinAddr);
|
||||
if (!addr) {
|
||||
return NULL;
|
||||
}
|
||||
/* Special case for XCOFF */
|
||||
if (obj->xcoff) {
|
||||
return r_xcoff_get_entry (obj);
|
||||
}
|
||||
/* Simplest case, the header provides the entrypoint address */
|
||||
if (obj->hdr.f_opthdr) {
|
||||
addr->paddr = obj->opt_hdr.entry;
|
||||
|
@ -188,7 +245,7 @@ static bool r_bin_coff_init_opt_hdr(RBinCoffObj *obj) {
|
|||
static bool r_bin_xcoff_init_opt_hdr(RBinCoffObj *obj) {
|
||||
int ret;
|
||||
ret = r_buf_fread_at (obj->b, sizeof (struct coff_hdr) + sizeof (struct coff_opt_hdr),
|
||||
(ut8 *)&obj->xcoff_opt_hdr, "1I8S4c3I4c2S", 1);
|
||||
(ut8 *)&obj->x_opt_hdr, "1I8S4c3I4c2S", 1);
|
||||
if (ret != sizeof (struct xcoff32_opt_hdr)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -217,6 +274,57 @@ static bool r_bin_coff_init_scn_hdr(RBinCoffObj *obj) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* init_ldhdr reads the XCOFF32 loader header, which is at the beginning of the .loader section */
|
||||
|
||||
static bool r_bin_xcoff_init_ldhdr(RBinCoffObj *obj) {
|
||||
int ret;
|
||||
ut16 loader_idx = obj->x_opt_hdr.o_snloader;
|
||||
if (!loader_idx) {
|
||||
return true;
|
||||
}
|
||||
if (loader_idx > obj->hdr.f_nscns) {
|
||||
R_LOG_WARN ("invalid loader section number (%d > %d)", loader_idx, obj->hdr.f_nscns);
|
||||
return false;
|
||||
}
|
||||
ut64 offset = obj->scn_hdrs[loader_idx-1].s_scnptr; // section numbers start at 1
|
||||
ret = r_buf_fread_at (obj->b, offset, (ut8 *)&obj->x_ldhdr, "8I", 1);
|
||||
if (ret != sizeof (struct xcoff32_ldhdr)) {
|
||||
R_LOG_WARN ("failed to read loader header");
|
||||
return false;
|
||||
}
|
||||
if (obj->x_ldhdr.l_version != 1) {
|
||||
R_LOG_WARN ("unsupported loader version (%u)", obj->x_ldhdr.l_version);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool r_bin_xcoff_init_ldsyms(RBinCoffObj *obj) {
|
||||
int ret;
|
||||
size_t size;
|
||||
ut64 offset = obj->scn_hdrs[obj->x_opt_hdr.o_snloader-1].s_scnptr + sizeof (struct xcoff32_ldhdr);
|
||||
if (!obj->x_ldhdr.l_nsyms) {
|
||||
return true;
|
||||
}
|
||||
if (obj->x_ldhdr.l_nsyms >= 0xffff) { // too much symbols, probably not allocatable
|
||||
R_LOG_DEBUG ("too many loader symbols (%u)", obj->x_ldhdr.l_nsyms);
|
||||
return false;
|
||||
}
|
||||
// USHORT_MAX * 24UL cannot overflow size_t
|
||||
size = obj->x_ldhdr.l_nsyms * sizeof (struct xcoff32_ldsym);
|
||||
obj->x_ldsyms = calloc (1, size);
|
||||
if (!obj->x_ldsyms) {
|
||||
return false;
|
||||
}
|
||||
ret = r_buf_fread_at (obj->b, offset, (ut8 *)obj->x_ldsyms, "8cIS2c2I", obj->x_ldhdr.l_nsyms);
|
||||
if (ret != size) {
|
||||
R_LOG_DEBUG ("failed to read loader symbol table (%lu, %lu)", ret, size);
|
||||
R_FREE (obj->x_ldsyms);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool r_bin_coff_init_symtable(RBinCoffObj *obj) {
|
||||
int ret, size;
|
||||
ut64 offset = obj->hdr.f_symptr;
|
||||
|
@ -290,6 +398,15 @@ static bool r_bin_coff_init(RBinCoffObj *obj, RBuffer *buf, bool verbose) {
|
|||
R_LOG_WARN ("failed to init section VA table");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!r_bin_xcoff_init_ldhdr (obj)) {
|
||||
R_LOG_WARN ("failed to init xcoff loader header");
|
||||
return false;
|
||||
}
|
||||
if (!r_bin_xcoff_init_ldsyms (obj)) {
|
||||
R_LOG_WARN ("failed to init xcoff loader symbol table");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!r_bin_coff_init_symtable (obj)) {
|
||||
R_LOG_WARN ("failed to init symtable");
|
||||
|
@ -304,6 +421,7 @@ R_IPI void r_bin_coff_free(RBinCoffObj *obj) {
|
|||
ht_up_free (obj->imp_ht);
|
||||
free (obj->scn_va);
|
||||
free (obj->scn_hdrs);
|
||||
free (obj->x_ldsyms);
|
||||
free (obj->symbols);
|
||||
r_buf_free (obj->b);
|
||||
free (obj);
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
typedef struct r_bin_coff_obj {
|
||||
struct coff_hdr hdr;
|
||||
struct coff_opt_hdr opt_hdr;
|
||||
struct xcoff32_opt_hdr xcoff_opt_hdr;
|
||||
struct coff_scn_hdr *scn_hdrs;
|
||||
struct coff_symbol *symbols;
|
||||
|
||||
/* XCOFF specific */
|
||||
struct xcoff32_opt_hdr x_opt_hdr;
|
||||
struct xcoff32_ldhdr x_ldhdr;
|
||||
struct xcoff32_ldsym *x_ldsyms;
|
||||
|
||||
ut16 target_id; /* TI COFF specific */
|
||||
|
||||
RBuffer *b;
|
||||
|
|
|
@ -181,6 +181,16 @@
|
|||
#define COFF_SYM_CLASS_WEAK_EXTERNAL 105
|
||||
#define COFF_SYM_CLASS_CLR_TOKEN 107
|
||||
|
||||
/* XCOFF32 loader */
|
||||
#define XCOFF_LDSYM_FLAGS(x) ((x)&0xF8)
|
||||
#define XCOFF_LDSYM_FLAG_EXPORT 0x10
|
||||
#define XCOFF_LDSYM_FLAG_ENTRYPOINT 0x20
|
||||
#define XCOFF_LDSYM_FLAG_IMPORT 0x40
|
||||
|
||||
#define XCOFF_LDSYM_TYPE(x) ((x)&0x07)
|
||||
|
||||
#define XCOFF_LDSYM_CLASS_FUNCTION 0x0a
|
||||
|
||||
/* XCOFF64 auxiliary entry type */
|
||||
#define XCOFF_AUX_EXCEPT 255
|
||||
#define XCOFF_AUX_FCN 254
|
||||
|
@ -460,7 +470,7 @@ struct xcoff64_ldhdr {
|
|||
/* XCOFF32 loader symbol */
|
||||
R_PACKED (
|
||||
struct xcoff32_ldsym {
|
||||
ut8 l_name[8];
|
||||
char l_name[8];
|
||||
ut32 l_value;
|
||||
ut16 l_scnum;
|
||||
ut8 l_smtype;
|
||||
|
|
|
@ -138,6 +138,39 @@ static RBinImport *_fill_bin_import(struct r_bin_coff_obj *bin, int idx) {
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static bool xcoff_is_imported_symbol(struct xcoff32_ldsym *s) {
|
||||
return XCOFF_LDSYM_FLAGS (s->l_smtype) == XCOFF_LDSYM_FLAG_IMPORT;
|
||||
}
|
||||
|
||||
static RBinImport *_xcoff_fill_bin_import(struct r_bin_coff_obj *bin, int idx) {
|
||||
RBinImport *ptr = R_NEW0 (RBinImport);
|
||||
if (!ptr || idx < 0 || idx > bin->x_ldhdr.l_nsyms) {
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
struct xcoff32_ldsym *s = &bin->x_ldsyms[idx];
|
||||
if (!xcoff_is_imported_symbol (s)) {
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (strnlen (s->l_name, 8)) {
|
||||
ptr->name = r_str_ndup (s->l_name, 8);
|
||||
}
|
||||
if (!ptr->name) {
|
||||
free (ptr);
|
||||
return NULL;
|
||||
}
|
||||
switch (s->l_smclas) {
|
||||
case XCOFF_LDSYM_CLASS_FUNCTION:
|
||||
ptr->type = R_BIN_TYPE_FUNC_STR;
|
||||
break;
|
||||
default:
|
||||
ptr->type = R_BIN_TYPE_UNKNOWN_STR;
|
||||
break;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static RList *entries(RBinFile *bf) {
|
||||
struct r_bin_coff_obj *obj = (struct r_bin_coff_obj*)bf->bo->bin_obj;
|
||||
RList *ret;
|
||||
|
@ -199,6 +232,8 @@ static const char *xcoff_section_type_tostring(int i) {
|
|||
return "BSS";
|
||||
case XCOFF_SCN_TYPE_EXCEPT:
|
||||
return "EXCEPT";
|
||||
case XCOFF_SCN_TYPE_LOADER:
|
||||
return "LOADER";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -315,8 +350,17 @@ static RList *imports(RBinFile *bf) {
|
|||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
if (obj->symbols) {
|
||||
int ord = 0;
|
||||
int ord = 0;
|
||||
if (obj->x_ldsyms) {
|
||||
for (i = 0; i < obj->x_ldhdr.l_nsyms; i++) {
|
||||
RBinImport *ptr = _xcoff_fill_bin_import (obj, i);
|
||||
if (ptr) {
|
||||
ptr->ordinal = ord++;
|
||||
r_list_append (ret, ptr);
|
||||
ht_up_insert (obj->imp_ht, (ut64)i, ptr);
|
||||
}
|
||||
}
|
||||
} else if (obj->symbols) {
|
||||
for (i = 0; i < obj->hdr.f_nsyms; i++) {
|
||||
RBinImport *ptr = _fill_bin_import (obj, i);
|
||||
if (ptr) {
|
||||
|
@ -586,9 +630,34 @@ static RBinInfo *info(RBinFile *bf) {
|
|||
struct r_bin_coff_obj *obj = (struct r_bin_coff_obj*)bf->bo->bin_obj;
|
||||
|
||||
ret->file = bf->file? strdup (bf->file): NULL;
|
||||
/* XXX also set bclass or class to xcoff? */
|
||||
ret->rclass = strdup ("coff");
|
||||
ret->bclass = strdup ("coff");
|
||||
ret->type = strdup ("COFF (Executable file)");
|
||||
switch (obj->hdr.f_magic) {
|
||||
case COFF_FILE_MACHINE_ALPHA:
|
||||
case COFF_FILE_MACHINE_POWERPC:
|
||||
case COFF_FILE_MACHINE_R4000:
|
||||
ret->type = strdup ("COFF (Object file)");
|
||||
break;
|
||||
case XCOFF32_FILE_MACHINE_U800WR:
|
||||
case XCOFF32_FILE_MACHINE_U800RO:
|
||||
case XCOFF32_FILE_MACHINE_U800TOC:
|
||||
case XCOFF32_FILE_MACHINE_U802WR:
|
||||
case XCOFF32_FILE_MACHINE_U802RO:
|
||||
ret->type = strdup ("XCOFF32");
|
||||
break;
|
||||
case XCOFF32_FILE_MACHINE_U802TOC:
|
||||
ret->type = strdup ("XCOFF32 (Executable file, RO text, TOC)");
|
||||
break;
|
||||
case XCOFF64_FILE_MACHINE_U803TOC:
|
||||
case XCOFF64_FILE_MACHINE_U803XTOC:
|
||||
case XCOFF64_FILE_MACHINE_U64:
|
||||
ret->type = strdup ("XCOFF64");
|
||||
break;
|
||||
default:
|
||||
ret->type = strdup ("COFF (Executable file)");
|
||||
break;
|
||||
}
|
||||
ret->os = strdup ("any");
|
||||
ret->subsystem = strdup ("any");
|
||||
ret->big_endian = obj->endian;
|
||||
|
|
|
@ -20,12 +20,12 @@ CMDS=iS
|
|||
EXPECT=<<EOF
|
||||
[Sections]
|
||||
|
||||
nth paddr size vaddr vsize perm type name
|
||||
--------------------------------------------------------
|
||||
0 0x00000128 0x3722 0x10000128 0x3722 -r-x TEXT .text-0
|
||||
1 0x0000384a 0x4ba 0x2000084a 0x4ba -rw- DATA .data-1
|
||||
2 0x00000000 0x1c 0x20000d04 0x1c -rw- BSS .bss-2
|
||||
3 0x00003d04 0xc73 0x00000000 0xc73 ---- ---- .loader-3
|
||||
nth paddr size vaddr vsize perm type name
|
||||
----------------------------------------------------------
|
||||
0 0x00000128 0x3722 0x10000128 0x3722 -r-x TEXT .text-0
|
||||
1 0x0000384a 0x4ba 0x2000084a 0x4ba -rw- DATA .data-1
|
||||
2 0x00000000 0x1c 0x20000d04 0x1c -rw- BSS .bss-2
|
||||
3 0x00003d04 0xc73 0x00000000 0xc73 ---- LOADER .loader-3
|
||||
|
||||
EOF
|
||||
RUN
|
||||
|
@ -52,3 +52,73 @@ bl 0x100001f0
|
|||
nop
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=xcoff entrypoint
|
||||
FILE=bins/xcoff/file-xcoff-aix51
|
||||
CMDS=ie
|
||||
EXPECT=<<EOF
|
||||
[Entrypoints]
|
||||
vaddr=0x10000128 paddr=0x00000000 haddr=-1 type=program
|
||||
|
||||
1 entrypoints
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=xcoff imports
|
||||
FILE=bins/xcoff/file-xcoff-aix51
|
||||
CMDS=ii
|
||||
EXPECT=<<EOF
|
||||
[Imports]
|
||||
nth vaddr bind type lib name
|
||||
---------------------------------
|
||||
0 ---------- NONE UNK errno
|
||||
1 ---------- NONE UNK __mulh
|
||||
2 ---------- NONE UNK _iob
|
||||
3 ---------- NONE FUNC exit
|
||||
4 ---------- NONE FUNC free
|
||||
5 ---------- NONE FUNC strlen
|
||||
6 ---------- NONE FUNC fopen64
|
||||
7 ---------- NONE FUNC getenv
|
||||
8 ---------- NONE FUNC atoi
|
||||
9 ---------- NONE FUNC fprintf
|
||||
10 ---------- NONE FUNC strchr
|
||||
11 ---------- NONE FUNC printf
|
||||
12 ---------- NONE FUNC fclose
|
||||
13 ---------- NONE FUNC fflush
|
||||
14 ---------- NONE FUNC __flsbuf
|
||||
15 ---------- NONE FUNC vfprintf
|
||||
16 ---------- NONE FUNC fwrite
|
||||
17 ---------- NONE FUNC strncmp
|
||||
18 ---------- NONE FUNC strrchr
|
||||
19 ---------- NONE FUNC fputc
|
||||
20 ---------- NONE FUNC rewind
|
||||
21 ---------- NONE FUNC fputs
|
||||
22 ---------- NONE FUNC strstr
|
||||
23 ---------- NONE FUNC strerror
|
||||
24 ---------- NONE FUNC wcwidth
|
||||
25 ---------- NONE FUNC mbrtowc
|
||||
26 ---------- NONE UNK __crt0v
|
||||
27 ---------- NONE UNK optind
|
||||
28 ---------- NONE FUNC getline
|
||||
29 ---------- NONE UNK optarg
|
||||
|
||||
EOF
|
||||
RUN
|
||||
|
||||
NAME=xcoff imports 2
|
||||
FILE=bins/xcoff/gcc-ppc32-aix-dwarf2-exec
|
||||
CMDS=ii
|
||||
EXPECT=<<EOF
|
||||
[Imports]
|
||||
nth vaddr bind type lib name
|
||||
---------------------------------
|
||||
0 ---------- NONE UNK errno
|
||||
1 ---------- NONE FUNC calloc
|
||||
2 ---------- NONE FUNC exit
|
||||
3 ---------- NONE FUNC __assert
|
||||
4 ---------- NONE FUNC fflush
|
||||
5 ---------- NONE FUNC puts
|
||||
6 ---------- NONE UNK __crt0v
|
||||
|
||||
EOF
|
||||
RUN
|
||||
|
|
Loading…
Reference in New Issue