767 lines
21 KiB
C++
767 lines
21 KiB
C++
/*
|
|
* Interactive disassembler (IDA).
|
|
* Copyright (c) 1990-98 by Ilfak Guilfanov.
|
|
* ALL RIGHTS RESERVED.
|
|
* E-mail: ig@datarescue.com
|
|
* FIDO: 2:5020/209
|
|
*
|
|
* PEF Loader
|
|
* ----------
|
|
*
|
|
*/
|
|
|
|
#include "../idaldr.h"
|
|
#include <typeinf.hpp>
|
|
#include "pef.hpp"
|
|
#include "../coff/syms.h"
|
|
#include "../../module/ppc/notify_codes.hpp"
|
|
#include "common.cpp"
|
|
|
|
static ea_t toc_ea;
|
|
static netnode toc;
|
|
//----------------------------------------------------------------------
|
|
static const char *get_sec_share_name(uint8 share, char *buf, size_t bufsize)
|
|
{
|
|
switch ( share )
|
|
{
|
|
case PEF_SH_PROCESS: return "Shared within process";
|
|
case PEF_SH_GLOBAL : return "Shared between all processes";
|
|
case PEF_SH_PROTECT: return "Shared between all processes but protected";
|
|
default:
|
|
qsnprintf(buf, bufsize, "Unknown code %d", share);
|
|
return buf;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void process_vector(uint32 ea, const char *name)
|
|
{
|
|
op_plain_offset(ea, 0, 0);
|
|
op_plain_offset(ea+4, 0, 0);
|
|
uint32 mintoc = get_dword(ea+4);
|
|
if ( segtype(mintoc) == SEG_DATA && mintoc < toc_ea )
|
|
{
|
|
toc_ea = mintoc;
|
|
ppc_module_t::set_toc(toc_ea);
|
|
}
|
|
set_name(ea, name, SN_IDBENC);
|
|
char buf[MAXSTR];
|
|
qsnprintf(buf, sizeof(buf), ".%s", name);
|
|
uint32 code = get_dword(ea);
|
|
add_entry(code, code, buf, true, AEF_IDBENC);
|
|
make_name_auto(code);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void process_symbol_class(uint32 ea, uchar sclass, const char *name)
|
|
{
|
|
switch ( sclass )
|
|
{
|
|
case kPEFCodeSymbol:
|
|
case kPEFGlueSymbol:
|
|
add_entry(ea, ea, name, true, AEF_IDBENC);
|
|
break;
|
|
case kPEFTVectSymbol:
|
|
process_vector(ea, name);
|
|
break;
|
|
case kPEFTOCSymbol:
|
|
if ( segtype(ea) == SEG_DATA && ea < toc_ea )
|
|
{
|
|
toc_ea = ea;
|
|
ppc_module_t::set_toc(toc_ea);
|
|
}
|
|
toc.charset_ea(ea, XMC_TD+1, 1);
|
|
/* fall thru */
|
|
case kPEFDataSymbol:
|
|
set_name(ea, name, SN_IDBENC);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void fixup(uint32 ea, uint32 delta, int extdef)
|
|
{
|
|
fixup_data_t fd(FIXUP_OFF32);
|
|
if ( extdef )
|
|
fd.set_extdef();
|
|
segment_t *s = getseg(delta);
|
|
fd.displacement = get_dword(ea);
|
|
if ( s == NULL )
|
|
{
|
|
fd.off = delta;
|
|
}
|
|
else
|
|
{
|
|
fd.sel = s->sel;
|
|
fd.off = delta - get_segm_base(s);
|
|
}
|
|
fd.set(ea);
|
|
uint32 target = get_dword(ea) + delta;
|
|
put_dword(ea, target);
|
|
op_plain_offset(ea, 0, 0);
|
|
//cmd.ea = ea; ua_add_dref(0, target, dr_O); cmd.ea = BADADDR;
|
|
if ( target != toc_ea
|
|
&& !has_name(get_flags(ea))
|
|
&& has_name(get_flags(target)) )
|
|
{
|
|
qstring buf;
|
|
if ( get_name(&buf, target) > 0 )
|
|
{
|
|
buf.insert("TC_");
|
|
force_name(ea, buf.begin());
|
|
make_name_auto(ea);
|
|
}
|
|
}
|
|
// toc.charset_ea(ea, XMC_TC+1, 1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static NORETURN void bad_loader_data(void)
|
|
{
|
|
loader_failure("Bad loader data");
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static NORETURN void bad_reloc_data(void)
|
|
{
|
|
loader_failure("Bad relocation info");
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
inline bool good_string(const char *begin, const uchar *end, const char *p)
|
|
{
|
|
if ( p >= begin )
|
|
{
|
|
while ( p < (const char *)end )
|
|
{
|
|
if ( *p == '\0' )
|
|
return true;
|
|
++p;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
static void process_loader_data(bytevec_t &ldrdata, const qvector<pef_section_t> &sec)
|
|
{
|
|
pef_loader_data_t pd;
|
|
elderr_t errcode = extract_loader_data(&pd, ldrdata, sec);
|
|
if ( errcode != ELDERR_OK )
|
|
bad_loader_data();
|
|
|
|
pef_loader_t &pl = pd.pl;
|
|
if ( pl.totalImportedSymbolCount != 0 )
|
|
{
|
|
uint32 size = pl.totalImportedSymbolCount*4;
|
|
ea_t undef = free_chunk(inf_get_max_ea(), size, -0xF);
|
|
ea_t end = undef + size;
|
|
set_selector(sec.size()+1, 0);
|
|
if ( !add_segm(sec.size()+1, undef, end, "IMPORT", "XTRN") )
|
|
loader_failure();
|
|
|
|
for ( int i=0; i < pl.importLibraryCount; i++ )
|
|
{
|
|
const pef_library_t &pil = pd.pil[i];
|
|
ea_t ea = undef + 4 * pil.firstImportedSymbol;
|
|
const char *libname = pd.stable + pil.nameOffset;
|
|
if ( !good_string(pd.stable, ldrdata.end(), libname) )
|
|
bad_loader_data();
|
|
add_extra_cmt(ea, true, "Imports from library %s", libname);
|
|
if ( (pil.options & PEF_LIB_WEAK) != 0 )
|
|
add_extra_cmt(ea, true, "Library is weak");
|
|
}
|
|
|
|
inf_set_specsegs(inf_is_64bit() ? 8 : 4);
|
|
for ( int i=0; i < pl.totalImportedSymbolCount; i++ )
|
|
{
|
|
uint32 sym = mflong(pd.impsym[i]);
|
|
uchar sclass = uchar(sym >> 24);
|
|
ea_t ea = undef + 4*i;
|
|
const char *iname = get_impsym_name(pd.stable, ldrdata.end(), pd.impsym, i);
|
|
if ( iname == NULL )
|
|
bad_loader_data();
|
|
set_name(ea, iname, SN_IDBENC);
|
|
if ( (sclass & kPEFWeak) != 0 )
|
|
make_name_weak(ea);
|
|
create_dword(ea, 4);
|
|
put_dword(ea, 0);
|
|
pd.impsym[i] = (uint32)ea;
|
|
}
|
|
}
|
|
|
|
if ( pl.mainSection != -1 )
|
|
{
|
|
uint32 ea = sec[pl.mainSection].defaultAddress + pl.mainOffset;
|
|
toc_ea = sec[1].defaultAddress + get_dword(ea+4);
|
|
ppc_module_t::set_toc(toc_ea);
|
|
}
|
|
else if ( pl.initSection != -1 )
|
|
{
|
|
uint32 ea = sec[pl.initSection].defaultAddress + pl.initOffset;
|
|
toc_ea = sec[1].defaultAddress + get_dword(ea+4);
|
|
ppc_module_t::set_toc(toc_ea);
|
|
}
|
|
|
|
if ( qgetenv("IDA_NORELOC") )
|
|
goto EXPORTS;
|
|
|
|
msg("Processing relocation information... ");
|
|
for ( int i=0; i < pl.relocSectionCount; i++ )
|
|
{
|
|
const pef_reloc_header_t &prh = pd.prh[i];
|
|
int sidx = prh.sectionIndex;
|
|
if ( sidx >= sec.size() )
|
|
bad_reloc_data();
|
|
uint32 sea = sec[sidx].defaultAddress;
|
|
const uint16 *ptr = pd.relptr + prh.firstRelocOffset;
|
|
if ( !inside(ldrdata, ptr, prh.relocCount, sizeof(*ptr)) )
|
|
bad_reloc_data();
|
|
uint32 reladdr = sea;
|
|
uint32 import = 0;
|
|
uint32 code = sec.size() > 0 ? sec[0].defaultAddress : 0;
|
|
uint32 data = sec.size() > 1 ? sec[1].defaultAddress : 0;
|
|
int32 repeat = -1;
|
|
for ( int j=0; j < prh.relocCount; )
|
|
{
|
|
uint16 insn = mfshort(ptr[j++]);
|
|
uint16 cnt = insn & 0x1FF;
|
|
switch ( insn >> 9 )
|
|
{
|
|
default: // kPEFRelocBySectDWithSkip= 0x00,/* binary: 00xxxxx */
|
|
if ( (insn & 0xC000) == 0 )
|
|
{
|
|
int skipCount = (insn >> 6) & 0xFF;
|
|
int relocCount = insn & 0x3F;
|
|
reladdr += skipCount * 4;
|
|
while ( relocCount > 0 )
|
|
{
|
|
relocCount--;
|
|
fixup(reladdr, data, 0);
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
}
|
|
bad_reloc_data();
|
|
|
|
case kPEFRelocBySectC: // = 0x20, /* binary: 0100000 */
|
|
cnt++;
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, code, 0);
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocBySectD:
|
|
cnt++;
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, data, 0);
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocTVector12:
|
|
cnt++;
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, code, 0);
|
|
reladdr += 4;
|
|
fixup(reladdr, data, 0);
|
|
reladdr += 4;
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocTVector8:
|
|
cnt++;
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, code, 0);
|
|
reladdr += 4;
|
|
fixup(reladdr, data, 0);
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocVTable8:
|
|
cnt++;
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, data, 0);
|
|
reladdr += 4;
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocImportRun:
|
|
cnt++;
|
|
if ( import+cnt > pl.totalImportedSymbolCount )
|
|
bad_reloc_data();
|
|
while ( cnt > 0 )
|
|
{
|
|
cnt--;
|
|
fixup(reladdr, pd.impsym[import], 1);
|
|
import++;
|
|
reladdr += 4;
|
|
}
|
|
break;
|
|
case kPEFRelocSmByImport:
|
|
if ( cnt >= pl.totalImportedSymbolCount )
|
|
bad_reloc_data();
|
|
fixup(reladdr, pd.impsym[cnt], 1);
|
|
reladdr += 4;
|
|
import = cnt + 1;
|
|
break;
|
|
case kPEFRelocSmSetSectC:
|
|
if ( cnt >= sec.size() )
|
|
bad_reloc_data();
|
|
code = sec[cnt].defaultAddress;
|
|
break;
|
|
case kPEFRelocSmSetSectD:
|
|
if ( cnt >= sec.size() )
|
|
bad_reloc_data();
|
|
data = sec[cnt].defaultAddress;
|
|
break;
|
|
case kPEFRelocSmBySection:
|
|
if ( cnt >= sec.size() )
|
|
bad_reloc_data();
|
|
fixup(reladdr, sec[cnt].defaultAddress, 0);
|
|
reladdr += 4;
|
|
break;
|
|
|
|
case kPEFRelocIncrPosition: /* binary: 1000xxx */
|
|
case kPEFRelocIncrPosition+1:
|
|
case kPEFRelocIncrPosition+2:
|
|
case kPEFRelocIncrPosition+3:
|
|
case kPEFRelocIncrPosition+4:
|
|
case kPEFRelocIncrPosition+5:
|
|
case kPEFRelocIncrPosition+6:
|
|
case kPEFRelocIncrPosition+7:
|
|
reladdr += (insn & 0x0FFF)+1;
|
|
break;
|
|
|
|
case kPEFRelocSmRepeat: /* binary: 1001xxx */
|
|
case kPEFRelocSmRepeat+1:
|
|
case kPEFRelocSmRepeat+2:
|
|
case kPEFRelocSmRepeat+3:
|
|
case kPEFRelocSmRepeat+4:
|
|
case kPEFRelocSmRepeat+5:
|
|
case kPEFRelocSmRepeat+6:
|
|
case kPEFRelocSmRepeat+7:
|
|
if ( repeat == -1 )
|
|
repeat = (insn & 0xFF)+1;
|
|
repeat--;
|
|
if ( repeat != -1 )
|
|
j -= ((insn>>8) & 15)+1 + 1;
|
|
break;
|
|
|
|
case kPEFRelocSetPosition: /* binary: 101000x */
|
|
case kPEFRelocSetPosition+1:
|
|
{
|
|
ushort next = mfshort(ptr[j++]);
|
|
uint32 offset = next | (uint32(insn & 0x3FF) << 16);
|
|
reladdr = sea + offset;
|
|
}
|
|
break;
|
|
|
|
case kPEFRelocLgByImport: /* binary: 101001x */
|
|
case kPEFRelocLgByImport+1:
|
|
{
|
|
ushort next = mfshort(ptr[j++]);
|
|
uint32 index = next | (uint32(insn & 0x3FF) << 16);
|
|
if ( index >= pl.totalImportedSymbolCount )
|
|
bad_reloc_data();
|
|
fixup(reladdr, pd.impsym[index], 1);
|
|
reladdr += 4;
|
|
import = index + 1;
|
|
}
|
|
break;
|
|
|
|
case kPEFRelocLgRepeat: /* binary: 101100x */
|
|
case kPEFRelocLgRepeat+1:
|
|
{
|
|
ushort next = mfshort(ptr[j++]);
|
|
if ( repeat == -1 )
|
|
repeat = next | (uint32(insn & 0x3F) << 16);
|
|
repeat--;
|
|
if ( repeat != -1 )
|
|
j -= ((insn >> 6) & 15) + 1 + 2;
|
|
}
|
|
break;
|
|
|
|
case kPEFRelocLgSetOrBySection: /* binary: 101101x */
|
|
case kPEFRelocLgSetOrBySection+1:
|
|
{
|
|
ushort next = mfshort(ptr[j++]);
|
|
uint32 index = next | (uint32(insn & 0x3F) << 16);
|
|
if ( index >= sec.size() )
|
|
bad_reloc_data();
|
|
int subcode = (insn >> 6) & 15;
|
|
switch ( subcode )
|
|
{
|
|
case 0:
|
|
fixup(reladdr, sec[index].defaultAddress, 0);
|
|
reladdr += 4;
|
|
break;
|
|
case 1:
|
|
code = sec[index].defaultAddress;
|
|
break;
|
|
case 2:
|
|
data = sec[index].defaultAddress;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXPORTS:
|
|
for ( int i=0; i < pl.exportedSymbolCount; i++ )
|
|
{
|
|
const pef_export_t &pe = pd.pe[i];
|
|
uchar sclass = uchar(pe.classAndName >> 24);
|
|
char name[MAXSTR];
|
|
uint32 ea;
|
|
switch ( pe.sectionIndex )
|
|
{
|
|
case -3:
|
|
{
|
|
uint symidx = pe.symbolValue;
|
|
if ( symidx >= pl.totalImportedSymbolCount )
|
|
bad_reloc_data();
|
|
ea = pd.impsym[symidx];
|
|
}
|
|
break;
|
|
case -2: // absolute symbol
|
|
ask_for_feedback("Absolute symbols are not implemented");
|
|
continue;
|
|
default:
|
|
{
|
|
uint secidx = pe.sectionIndex;
|
|
if ( secidx >= sec.size() )
|
|
bad_reloc_data();
|
|
ea = sec[secidx].defaultAddress + pe.symbolValue;
|
|
}
|
|
break;
|
|
}
|
|
if ( !get_expsym_name(pd.stable, pd.keytable, pd.pe, i, ldrdata.end(), name, sizeof(name)) )
|
|
bad_loader_data();
|
|
process_symbol_class(ea, sclass & 0xF, name);
|
|
}
|
|
msg("done.\n");
|
|
|
|
if ( pl.mainSection >= 0 && pl.mainSection < sec.size() )
|
|
{
|
|
uint32 ea = sec[pl.mainSection].defaultAddress + pl.mainOffset;
|
|
process_vector(ea, "start");
|
|
inf_set_start_cs(0);
|
|
inf_set_start_ip(get_dword(ea));
|
|
}
|
|
if ( pl.initSection >= 0 && pl.initSection < sec.size() )
|
|
{
|
|
uint32 ea = sec[pl.initSection].defaultAddress + pl.initOffset;
|
|
process_vector(ea, "INIT_VECTOR");
|
|
}
|
|
if ( pl.termSection >= 0 && pl.termSection < sec.size() )
|
|
{
|
|
uint32 ea = sec[pl.termSection].defaultAddress + pl.termOffset;
|
|
process_vector(ea, "TERM_VECTOR");
|
|
}
|
|
|
|
if ( toc_ea != BADADDR )
|
|
set_name(toc_ea, "TOC");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static NORETURN void bad_packed_data(void)
|
|
{
|
|
loader_failure("Illegal compressed data");
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static uint32 read_number(const uchar *&packed, const uchar *end)
|
|
{
|
|
uint32 arg = 0;
|
|
for ( int i=0; ; i++ )
|
|
{
|
|
if ( packed >= end )
|
|
bad_packed_data();
|
|
uchar b = *packed++;
|
|
arg <<= 7;
|
|
arg |= (b & 0x7F);
|
|
if ( (b & 0x80) == 0 )
|
|
break;
|
|
if ( i > 4 )
|
|
bad_packed_data();
|
|
}
|
|
return arg;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static void unpack_section(
|
|
const bytevec_t &packedvec,
|
|
ea_t start,
|
|
uint32 usize)
|
|
{
|
|
bytevec_t unpacked;
|
|
const uchar *packed = packedvec.begin();
|
|
const uchar *pckend = packedvec.begin() + packedvec.size();
|
|
while ( packed < pckend )
|
|
{
|
|
uchar code = *packed++;
|
|
uint32 arg = code & 0x1F;
|
|
if ( arg == 0 )
|
|
arg = read_number(packed, pckend);
|
|
switch ( code >> 5 )
|
|
{
|
|
case 0: // Zero
|
|
unpacked.growfill(arg);
|
|
break;
|
|
|
|
case 1: // blockCopy
|
|
{
|
|
const uchar *end = packed + arg;
|
|
if ( end < packed || end > pckend )
|
|
bad_packed_data();
|
|
unpacked.append(packed, arg);
|
|
packed += arg;
|
|
}
|
|
break;
|
|
|
|
case 2: // repeatedBlock
|
|
{
|
|
int32 repeat = read_number(packed, pckend) + 1;
|
|
const uchar *end = packed + arg;
|
|
if ( end < packed || end > pckend )
|
|
bad_packed_data();
|
|
while ( --repeat >= 0 )
|
|
unpacked.append(packed, arg);
|
|
packed += arg;
|
|
}
|
|
break;
|
|
|
|
case 3: // interleaveRepeatBlockWithBlockCopy
|
|
{
|
|
int32 commonSize = arg;
|
|
int32 customSize = read_number(packed, pckend);
|
|
int32 repeatCount = read_number(packed, pckend);
|
|
const uchar *common = packed;
|
|
packed += commonSize;
|
|
if ( packed < common || packed > pckend )
|
|
bad_packed_data();
|
|
while ( --repeatCount >= 0 )
|
|
{
|
|
const uchar *end = packed + customSize;
|
|
if ( end < packed || end > pckend )
|
|
bad_packed_data();
|
|
unpacked.append(common, commonSize);
|
|
unpacked.append(packed, customSize);
|
|
packed += customSize;
|
|
}
|
|
unpacked.append(common, commonSize);
|
|
}
|
|
break;
|
|
|
|
case 4: // interleaveRepeatBlockWithZero
|
|
{
|
|
int32 commonSize = arg;
|
|
int32 customSize = read_number(packed, pckend);
|
|
int32 repeatCount = read_number(packed, pckend);
|
|
while ( --repeatCount >= 0 )
|
|
{
|
|
const uchar *end = packed + customSize;
|
|
if ( end < packed || end > pckend )
|
|
bad_packed_data();
|
|
unpacked.growfill(commonSize);
|
|
unpacked.append(packed, customSize);
|
|
packed += customSize;
|
|
}
|
|
unpacked.growfill(commonSize);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
bad_packed_data();
|
|
}
|
|
}
|
|
if ( unpacked.size() < usize )
|
|
unpacked.growfill(usize-unpacked.size());
|
|
if ( unpacked.size() != usize )
|
|
bad_packed_data();
|
|
mem2base(unpacked.begin(), start, start+unpacked.size(), FILEREG_NOTPATCHABLE);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static void load_section(
|
|
int i,
|
|
linput_t *li,
|
|
pef_section_t &ps,
|
|
const char *sname,
|
|
const char *classname,
|
|
int is_packed)
|
|
{
|
|
uint32 size = ps.totalSize;
|
|
ea_t base = ps.defaultAddress ? ps.defaultAddress : to_ea(inf_get_baseaddr(), 0);
|
|
ea_t start = free_chunk(base, size, 1-(1 << ps.alignment));
|
|
ea_t end = start + size;
|
|
if ( is_packed )
|
|
{
|
|
bytevec_t packed;
|
|
packed.resize(ps.packedSize);
|
|
qlseek(li, ps.containerOffset);
|
|
lread(li, packed.begin(), packed.size());
|
|
unpack_section(packed, start, ps.unpackedSize);
|
|
}
|
|
else
|
|
{
|
|
file2base(li, ps.containerOffset,
|
|
start, start+ps.unpackedSize, FILEREG_PATCHABLE);
|
|
}
|
|
set_selector(i+1, 0);
|
|
if ( !add_segm(i+1, start, end, sname, classname, ADDSEG_SPARSE) )
|
|
loader_failure();
|
|
ps.defaultAddress = start;
|
|
if ( start < inf_get_lowoff() )
|
|
inf_set_lowoff(start);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// load file into the database.
|
|
//
|
|
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
|
|
{
|
|
pef_t pef;
|
|
toc_ea = BADADDR;
|
|
toc.create("$ toc");
|
|
qlseek(li, 0);
|
|
lread(li, &pef, sizeof(pef_t));
|
|
swap_pef(pef);
|
|
|
|
const char *proc = get_pef_processor(pef);
|
|
if ( proc != NULL )
|
|
{
|
|
set_processor_type(proc, SETPROC_LOADER);
|
|
if ( PH.id == PLFM_PPC )
|
|
{
|
|
// Mac OS Runtime Architecture for the PowerPC is very similar to AIX
|
|
set_abi_name("aix");
|
|
}
|
|
}
|
|
|
|
// read section headers
|
|
qvector<pef_section_t> sec;
|
|
if ( pef.sectionCount != 0 )
|
|
{
|
|
sec.resize(pef.sectionCount);
|
|
lread(li, sec.begin(), sec.size()*sizeof(pef_section_t));
|
|
}
|
|
|
|
// swap section headers and find the loader section
|
|
pef_section_t *loader = NULL;
|
|
for ( int i=0; i < sec.size(); i++ )
|
|
{
|
|
swap_pef_section(sec[i]);
|
|
if ( sec[i].sectionKind == PEF_SEC_LOADER )
|
|
loader = &sec[i];
|
|
}
|
|
|
|
int32 snames_table = sizeof(pef_t) + sizeof(pef_section_t)*sec.size();
|
|
for ( int i=0; i < sec.size(); i++ )
|
|
{
|
|
char buf[MAXSTR];
|
|
char *secname = get_string(li, snames_table, sec[i].nameOffset, buf, sizeof(buf));
|
|
switch ( sec[i].sectionKind )
|
|
{
|
|
case PEF_SEC_PDATA : // Pattern initialized data segment
|
|
load_section(i, li, sec[i], secname, CLASS_DATA, 1);
|
|
break;
|
|
case PEF_SEC_CODE : // Code segment
|
|
case PEF_SEC_EDATA : // Executable data segment
|
|
load_section(i, li, sec[i], secname, CLASS_CODE, 0);
|
|
break;
|
|
case PEF_SEC_DATA: // Unpacked data segment
|
|
load_section(i, li, sec[i], secname,
|
|
sec[i].unpackedSize != 0 ? CLASS_DATA : CLASS_BSS, 0);
|
|
break;
|
|
case PEF_SEC_CONST: // Read only data
|
|
load_section(i, li, sec[i], secname, CLASS_CONST, 0);
|
|
break;
|
|
case PEF_SEC_LOADER: // Loader section
|
|
case PEF_SEC_DEBUG : // Reserved for future use
|
|
case PEF_SEC_EXCEPT: // Reserved for future use
|
|
case PEF_SEC_TRACEB: // Reserved for future use
|
|
continue;
|
|
default:
|
|
ask_for_feedback("Unknown section type");
|
|
continue;
|
|
}
|
|
if ( i == 0 )
|
|
create_filename_cmt();
|
|
add_extra_cmt(sec[i].defaultAddress, true, "Segment share type: %s\n",
|
|
get_sec_share_name(sec[i].shareKind, buf, sizeof(buf)));
|
|
}
|
|
if ( loader != NULL )
|
|
{
|
|
bytevec_t ldrdata;
|
|
ldrdata.resize(loader->packedSize);
|
|
qlseek(li, loader->containerOffset);
|
|
lread(li, ldrdata.begin(), ldrdata.size());
|
|
process_loader_data(ldrdata, sec);
|
|
}
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// check input file format. if recognized, then return 1
|
|
// and fill 'fileformatname'.
|
|
// otherwise return 0
|
|
//
|
|
static int idaapi accept_file(
|
|
qstring *fileformatname,
|
|
qstring *processor,
|
|
linput_t *li,
|
|
const char *)
|
|
{
|
|
const char *proc = get_pef_processor(li);
|
|
if ( proc == NULL )
|
|
return 0;
|
|
|
|
*fileformatname = "PEF (Mac OS or Be OS executable)";
|
|
*processor = proc;
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
//
|
|
// LOADER DESCRIPTION BLOCK
|
|
//
|
|
//----------------------------------------------------------------------
|
|
loader_t LDSC =
|
|
{
|
|
IDP_INTERFACE_VERSION,
|
|
0, // loader flags
|
|
//
|
|
// check input file format. if recognized, then return 1
|
|
// and fill 'fileformatname'.
|
|
// otherwise return 0
|
|
//
|
|
accept_file,
|
|
//
|
|
// load file into the database.
|
|
//
|
|
load_file,
|
|
//
|
|
// create output file from the database.
|
|
// this function may be absent.
|
|
//
|
|
NULL,
|
|
// take care of a moved segment (fix up relocations, for example)
|
|
NULL,
|
|
NULL,
|
|
};
|