157 lines
4.4 KiB
C
157 lines
4.4 KiB
C
/* radare - LGPL - Copyright 2008-2015 pancake, inisider */
|
|
|
|
#include <r_util.h>
|
|
|
|
#include "coff.h"
|
|
|
|
bool r_coff_supported_arch (const ut8 *buf) {
|
|
ut16 arch = *(ut16*)buf;
|
|
switch (arch) {
|
|
case COFF_FILE_MACHINE_AMD64:
|
|
case COFF_FILE_MACHINE_I386:
|
|
case COFF_FILE_MACHINE_H8300:
|
|
case COFF_FILE_TI_COFF:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int r_coff_is_stripped (struct r_bin_coff_obj *obj) {
|
|
return !!(obj->hdr.f_flags & (COFF_FLAGS_TI_F_RELFLG | \
|
|
COFF_FLAGS_TI_F_LNNO | COFF_FLAGS_TI_F_LSYMS));
|
|
}
|
|
|
|
const char *r_coff_symbol_name (struct r_bin_coff_obj *obj, void *ptr) {
|
|
// XXX: this must be fixed (fuzzy can make it crash)
|
|
#if 0
|
|
union { char name[8]; struct { ut32 zero; ut32 offset; }; } *p = ptr;
|
|
if (!ptr)
|
|
return NULL;
|
|
if (p->zero)
|
|
return p->name;
|
|
|
|
return (char *)obj->b->buf + obj->hdr.f_symptr +
|
|
obj->hdr.f_nsyms * sizeof (struct coff_symbol) + p->offset;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static int r_coff_rebase_sym (struct r_bin_coff_obj *obj, RBinAddr *addr, struct coff_symbol *sym) {
|
|
if (sym->n_scnum<1 || sym->n_scnum > obj->hdr.f_nscns)
|
|
return 0;
|
|
addr->paddr = obj->scn_hdrs[sym->n_scnum - 1].s_scnptr + sym->n_value;
|
|
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 */
|
|
RBinAddr *r_coff_get_entry(struct r_bin_coff_obj *obj) {
|
|
RBinAddr *addr = R_NEW0 (RBinAddr);
|
|
int i;
|
|
if (!addr) return NULL;
|
|
|
|
/* Simplest case, the header provides the entrypoint address */
|
|
if (obj->hdr.f_opthdr) {
|
|
addr->paddr = obj->opt_hdr.entry;
|
|
return addr;
|
|
}
|
|
|
|
/* No help from the header eh? Use the address of the symbols '_start'
|
|
* or 'main' if present */
|
|
if (obj->symbols)
|
|
for (i = 0; i < obj->hdr.f_nsyms; i++) {
|
|
if ((!strcmp (obj->symbols[i].n_name, "_start") ||
|
|
!strcmp (obj->symbols[i].n_name, "start")) &&
|
|
r_coff_rebase_sym (obj, addr, &obj->symbols[i]))
|
|
return addr;
|
|
}
|
|
|
|
if (obj->symbols)
|
|
for (i = 0; i < obj->hdr.f_nsyms; i++) {
|
|
if ((!strcmp (obj->symbols[i].n_name, "_main") ||
|
|
!strcmp (obj->symbols[i].n_name, "main")) &&
|
|
r_coff_rebase_sym (obj, addr, &obj->symbols[i]))
|
|
return addr;
|
|
}
|
|
|
|
/* Still clueless ? Let's just use the address of .text */
|
|
if (obj->scn_hdrs)
|
|
for (i = 0; i < obj->hdr.f_nscns; i++) {
|
|
if (!strcmp (obj->scn_hdrs[i].s_name, ".text")) {
|
|
addr->paddr = obj->scn_hdrs[i].s_scnptr;
|
|
return addr;
|
|
}
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
static int r_bin_coff_init_hdr(struct r_bin_coff_obj *obj) {
|
|
ut16 magic = *(ut16 *)obj->b->buf;
|
|
obj->endian = (magic == COFF_FILE_MACHINE_H8300)?1:0;
|
|
|
|
(void)r_buf_fread_at (obj->b, 0, (ut8 *)&obj->hdr, obj->endian? "2S3I2S": "2s3i2s", 1);
|
|
|
|
if (obj->hdr.f_magic == COFF_FILE_TI_COFF)
|
|
(void)r_buf_fread_at (obj->b, R_BUF_CUR, (ut8 *)&obj->target_id, obj->endian? "S": "s", 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int r_bin_coff_init_opt_hdr(struct r_bin_coff_obj *obj) {
|
|
if (!obj->hdr.f_opthdr)
|
|
return 0;
|
|
(void)r_buf_fread_at (obj->b, obj->hdr.f_opthdr,
|
|
(ut8 *)&obj->opt_hdr, obj->endian? "2S6I": "2s6i", 1);
|
|
return 0;
|
|
}
|
|
|
|
static int r_bin_coff_init_scn_hdr(struct r_bin_coff_obj *obj) {
|
|
ut64 offset = sizeof (struct coff_hdr) + (obj->hdr.f_opthdr * sizeof (struct coff_opt_hdr));
|
|
if (obj->hdr.f_magic == COFF_FILE_TI_COFF)
|
|
offset += 2;
|
|
obj->scn_hdrs = calloc(obj->hdr.f_nscns, sizeof(struct coff_scn_hdr));
|
|
(void)r_buf_fread_at (obj->b, offset, (ut8 *)obj->scn_hdrs,
|
|
obj->endian? "8c6I2S1I": "8c6i2s1i", obj->hdr.f_nscns);
|
|
return 0;
|
|
}
|
|
|
|
static int r_bin_coff_init_symtable(struct r_bin_coff_obj *obj) {
|
|
if (obj->hdr.f_nsyms >= 0xffff) // too much symbols, probably not allocatable
|
|
return 0;
|
|
obj->symbols = calloc (obj->hdr.f_nsyms, sizeof(struct coff_symbol));
|
|
if (obj->symbols == NULL)
|
|
return 0;
|
|
(void)r_buf_fread_at (obj->b, obj->hdr.f_symptr, (ut8 *)obj->symbols,
|
|
obj->endian? "8c1I2S2c": "8c1i2s2c", obj->hdr.f_nsyms);
|
|
return 1;
|
|
}
|
|
|
|
static int r_bin_coff_init(struct r_bin_coff_obj *obj, RBuffer *buf) {
|
|
obj->b = r_buf_new ();
|
|
obj->size = buf->length;
|
|
if (!r_buf_set_bytes (obj->b, buf->buf, obj->size)){
|
|
r_buf_free (obj->b);
|
|
return false;
|
|
}
|
|
r_bin_coff_init_hdr(obj);
|
|
r_bin_coff_init_opt_hdr(obj);
|
|
|
|
r_bin_coff_init_scn_hdr(obj);
|
|
r_bin_coff_init_symtable(obj);
|
|
return true;
|
|
}
|
|
|
|
void r_bin_coff_free(struct r_bin_coff_obj *obj) {
|
|
free (obj->scn_hdrs);
|
|
free (obj->symbols);
|
|
free (obj);
|
|
}
|
|
|
|
struct r_bin_coff_obj* r_bin_coff_new_buf(struct r_buf_t *buf) {
|
|
struct r_bin_coff_obj* bin = R_NEW0 (struct r_bin_coff_obj);
|
|
r_bin_coff_init (bin, buf);
|
|
return bin;
|
|
}
|