/* * Interactive disassembler (IDA). * Copyright (c) 1990-98 by Ilfak Guilfanov. * ALL RIGHTS RESERVED. * E-mail: ig@estar.msk.su * FIDO: 2:5020/209 * */ #include "../idaldr.h" #include #include "pilot.hpp" #include "common.cpp" //------------------------------------------------------------------------ static void describe_all(DatabaseHdrType &h) { create_filename_cmt(); add_pgm_cmt("Version : %04X",h.version); add_pgm_cmt("DatabaseType: %4.4s",(char*)&h.type); add_pgm_cmt("\n appl \"%s\", '%4.4s'", h.name, (char*)&h.id); } //------------------------------------------------------------------------ // // Structure of the DATA 0 resource: // // +--------------------------------------------+ // | long: offset of CODE 1 xrefs? |- -+ // +--------------------------------------------+ | // | char[]: Initialized near data (below A5) | | // +--------------------------------------------+ | // | char[]: Uninitialized near data (below A5) | | // +--------------------------------------------+ | // | char[]: Initialized far data (above A5) | | // +--------------------------------------------+ | // | char[]: DATA 0 xrefs | | // +--------------------------------------------+ | // | char[]: CODE 1 xrefs |<--+ // +--------------------------------------------+ // static uchar *apply_relocs(uchar *packed, size_t &packlen, ea_t relocbase, ea_t targetbase, bool code=false) { if ( packlen < 4 ) { BADDATA: warning("Bad packed data"); return NULL; } uint32 nrelocs = swap32(*(uint32*)packed); packed += 4; packlen -= 4; ea_t offset = relocbase; fixup_data_t fd(FIXUP_OFF32); if ( code ) fd.set_sel(getseg(targetbase)); //msg("%d relocations\n", nrelocs); for ( uint i=0; i < nrelocs; i++ ) { if ( packlen < 1 ) goto BADDATA; uchar c = *packed; if ( c&0x80 ) { // signed 8-bit delta offset+=(char)(c<<1); packed++; packlen--; } else if ( c&0x40 ) { if ( packlen < 2 ) goto BADDATA; // 15-bit unsigned(?) delta // comment in PalmOS_Startup.cpp says "unsigned" but they cast it to a signed short... uint32 o1 = swap16(*(ushort*)packed); packed += 2; packlen -= 2; offset += (short)(o1<<2)>>1; } else { if ( packlen < 4 ) goto BADDATA; // direct signed 31-bit offset offset = relocbase+(int32(swap32(*(int32*)packed)<<2)>>1); packed += 4; packlen -= 4; } for ( int j=0; j < 4; j++ ) if ( !is_loaded(offset+j) ) put_byte(offset+j, 0); fd.off = get_dword(offset); if ( code ) { fd.set(offset); auto_make_proc(targetbase+fd.off); if ( get_word(offset-2) == 0x4EF9 ) // jump opcode? auto_make_proc(offset-2); } else { fd.set_base(targetbase); fd.set(offset); } // msg("Relocation %d at %08X: %08X -> %08X\n", i, offset-relocbase, fd.off, targetbase+fd.off); } return packed; } //------------------------------------------------------------------------ // unpack rle data from the buffer packed at file position fpos to ea cea // return new position in the buffer and update cea static uchar *unpack_rle(uchar *packed, size_t &packlen, ea_t &cea, qoff64_t fpos) { const uchar *packed_sav = packed; while ( 1 ) { if ( packlen < 1 ) { BADDATA: warning("Bad packed data"); return NULL; } uchar buf[256]; buf[0] = '\0'; // shutup lint uchar cnt = *packed++; packlen--; if ( cnt == 0 ) break; if ( cnt & 0x80 ) { cnt = (cnt & 0x7F) + 1; if ( packlen < cnt ) goto BADDATA; mem2base(packed, cea, cea+cnt, fpos+(packed-packed_sav)); packed += cnt; packlen -= cnt; cea += cnt; continue; } if ( cnt & 0x40 ) { cnt = (cnt & 0x3F) + 1; memset(buf, 0, cnt); } else if ( cnt & 0x20 ) { if ( packlen < 1 ) goto BADDATA; cnt = (cnt & 0x1F) + 2; memset(buf, *packed++, cnt); packlen--; } else if ( cnt & 0x10 ) { cnt = (cnt & 0x0F) + 1; memset(buf, 0xFF, cnt); } else if ( cnt == 1 ) { if ( packlen < 2 ) goto BADDATA; buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x00; buf[4] = 0xFF; buf[5] = 0xFF; buf[6] = *packed++; buf[7] = *packed++; packlen -= 2; cnt = 8; } else if ( cnt == 2 ) { if ( packlen < 3 ) goto BADDATA; buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x00; buf[4] = 0xFF; buf[5] = *packed++; buf[6] = *packed++; buf[7] = *packed++; cnt = 8; packlen -= 3; } else if ( cnt == 3 ) { if ( packlen < 3 ) goto BADDATA; buf[0] = 0xA9; buf[1] = 0xF0; buf[2] = 0x00; buf[3] = 0x00; buf[4] = *packed++; buf[5] = *packed++; buf[6] = 0x00; buf[7] = *packed++; cnt = 8; packlen -= 3; } else if ( cnt == 4 ) { if ( packlen < 4 ) goto BADDATA; buf[0] = 0xA9; buf[1] = 0xF0; buf[2] = 0x00; buf[3] = *packed++; buf[4] = *packed++; buf[5] = *packed++; buf[6] = 0x00; buf[7] = *packed++; cnt = 8; packlen -= 4; } mem2base(buf, cea, cea+cnt, -1); cea += cnt; } return packed; } //------------------------------------------------------------------------ static size_t unpack_data0000( linput_t *li, qoff64_t fpos, size_t size, ea_t ea, const code0000_t &code0000, ea_t code1ea, ea_t &a5) { if ( size < 4 ) { BADDATA: warning("Bad packed data"); return 0; } bytevec_t packed_buf; packed_buf.resize(size); uchar *packed = packed_buf.begin(); qlseek(li, fpos); lread(li, packed, size); size_t usize = code0000.nBytesAboveA5 + code0000.nBytesBelowA5; // total data size enable_flags(ea, ea+usize, STT_CUR); packed += sizeof(uint32); // skip initializers size size -= sizeof(uint32); a5 = ea+code0000.nBytesBelowA5; ea_t cea; for ( int i=0; i < 3; i++ ) { if ( size < 4 ) goto BADDATA; int32 offset = swap32(*(uint32*)packed); // offset from A5 packed += sizeof(uint32); size -= sizeof(uint32); cea = a5 + offset; if ( cea < ea ) { // can happen when code 0 resource is not present (e.g. prc-tools GLib-type shared libs) if ( i != 0 ) loader_failure("Error while decompressing data 0"); cea = ea; a5 = ea-offset; } if ( size > 0 ) { packed = unpack_rle(packed, size, cea, fpos+(packed-packed_buf.begin())); if ( packed == NULL ) return 0; } if ( usize < cea-ea ) usize = size_t(cea-ea); } if ( a5 > ea + usize - 1 ) { // allocate one extra byte for A5 enable_flags(ea+usize, ea+usize+1, STT_CUR); usize++; } create_byte(a5,1); if ( a5 != ea ) add_pgm_cmt("A5 register does not point to the start of the data segment\n" "The file should not be recompiled using Pila\n"); set_name(a5,"A5BASE",SN_NOCHECK|SN_AUTO); set_cmt(a5,"A5 points here",0); // TODO: find undefined bytes and set them to zero // this is done by Palm OS loader and some programs depend on it // process relocations if ( size > 0 ) { // a5 to a5 // msg("Relocations: data to data\n"); packed = apply_relocs(packed, size, a5, a5); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } if ( size > 0 ) { // a5 to code // msg("Relocations: data to code1\n"); packed = apply_relocs(packed, size, a5, code1ea, true); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } return usize; } //------------------------------------------------------------------------ // CodeWarrior A4 data layout: // // 0..3: 0x00000000 // 4..7: size of "above A4" region // 8..11: size of "below A4" region // 12..N-1: compressed "below A4" data // N..N+3: size of "near above A4" region // N+4..O-1: compressed "near above A4" data // O..O+3: size of "far above A4" region // O+4..P-1: compressed "far above A4" data // then the relocations: // 1) A4 -> A4 // 2) A4 -> A5 // 3) A4 -> code0001 // 4) A5 -> A4 static size_t unpack_data0001(linput_t *li, qoff64_t fpos, size_t size, ea_t ea, ea_t a5, ea_t code1ea, ea_t &a4) { if ( size < 3 * sizeof(uint32) ) { BADDATA: warning("Bad packed data"); return 0; } bytevec_t packed_buf; packed_buf.resize(size); uchar *packed = packed_buf.begin(); qlseek(li, fpos); lread(li, packed, size); packed += sizeof(uint32); // skip the 0 size -= sizeof(uint32); int32 above = swap32(*(int32*)packed); packed += sizeof(int32); size -= sizeof(uint32); int32 below = swap32(*(int32*)packed); packed += sizeof(int32); size -= sizeof(uint32); size_t usize = above - below; // unpacked size if ( below & 1 ) usize++; ea_t cea = ea; a4 = ea-below; if ( below & 1 ) a4++; enable_flags(ea, ea+usize, STT_CUR); create_byte(a4,1); set_name(a4,"A4BASE",SN_NOCHECK|SN_AUTO); set_cmt(a4,"A4 points here",0); // unpack below a4 packed = unpack_rle(packed, size, cea, fpos+(packed-packed_buf.begin())); if ( packed == NULL ) return 0; // unpack near above a4 if ( size < sizeof(int32) ) goto BADDATA; cea = a4 + swap32(*(int32*)packed); packed += sizeof(int32); size -= sizeof(uint32); packed = unpack_rle(packed, size, cea, fpos+(packed-packed_buf.begin())); if ( packed == NULL ) return 0; // unpack far above a4 if ( size < sizeof(int32) ) goto BADDATA; cea = a4 + swap32(*(int32*)packed); packed += sizeof(int32); size -= sizeof(uint32); packed = unpack_rle(packed, size, cea, fpos+(packed-packed_buf.begin())); if ( packed == NULL ) return 0; cea -= ea; if ( usize < cea ) usize = (size_t)cea; // process relocations if ( size > 0 ) { // a4 to a4 // msg("Relocations: a4 to a4\n"); packed = apply_relocs(packed, size, a4, a4); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } if ( size > 0 ) { // a4 to a5 // msg("Relocations: a4 to a5\n"); packed = apply_relocs(packed, size, a4, a5); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } if ( size > 0 ) { // a4 to code1 // msg("Relocations: a4 to code1\n"); packed = apply_relocs(packed, size, a4, code1ea, true); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } if ( size > 0 ) { // a5 to a4 // msg("Relocations: a5 to a4\n"); packed = apply_relocs(packed, size, a5, a4); if ( packed == NULL ) return 0; // packed = (uchar*)__Relocate__((Int8*)packed, 0, 0); } return usize; } //------------------------------------------------------------------------ void fix_jumptables(ea_t ea1, ea_t /*ea2*/, sel_t sel, ea_t a5, ea_t a4) { // msg("Fixing additional code segment at %08X\n",ea1); // from PalmOS_Startup.cpp /* struct SegmentHeader { // the structure of a segment header short jtsoffset; // A5 relative offset of this segments jump table (short version) short jtentries; // number of entries in this segments jump table int32 jtloffset; // A5 relative offset of this segments jump table (long version) int32 xrefoffset; // offset of xref data in this CODE resource char code[]; // the code }; struct JumpTableEntry { // the structure of a jumptable entry short jumpinstruction; // instruction: jmp routine int32 jumpaddress; // absolute or relative address of rountine };*/ short jtsoffset = get_word(ea1); int32 jtloffset = get_dword(ea1+4); if ( jtsoffset != jtloffset ) { // msg("Doesn't look like a CodeWarrior code segment\n"); return; } // find the jumptable ea_t jt_start; if ( a4 != BADADDR && get_word(a4+jtloffset) == 0x4EF9 ) // jmp opcode { jt_start = a4+jtloffset; create_word(ea1,2); create_dword(ea1+4,4); op_offset(ea1, 0, REF_OFF16, BADADDR, a4); op_offset(ea1+4, 0, REF_OFF32, BADADDR, a4); } else if ( get_word(a5+jtloffset) == 0x4EF9 ) // jmp opcode { jt_start = a5+jtloffset; create_word(ea1,2); create_dword(ea1+4,4); op_offset(ea1, 0, REF_OFF16, BADADDR, a5); op_offset(ea1+4, 0, REF_OFF32, BADADDR, a5); } else { // msg("Could not find the jump table!\n"); return; } create_word(ea1+2,2); create_dword(ea1+8,4); op_offset(ea1+8, 0, REF_OFF32, BADADDR, ea1); set_cmt(ea1, "Short jump table offset", 0); set_cmt(ea1+2, "Number of jump table entries", 0); set_cmt(ea1+4, "Long jump table offset", 0); set_cmt(ea1+8, "Offset to xref data", 0); fixup_data_t fd(FIXUP_OFF32); fd.sel = sel; ea_t jt_addr=jt_start; short jtentries = get_word(ea1+2); while ( jtentries-- ) { fd.off = get_dword(jt_addr+2); fd.set(jt_addr+2); // a little heuristic: does the jump point to code? if ( get_word(ea1+fd.off) == 0x4E56 // link a6,x || get_word(ea1+fd.off) == 0x06AF ) // addi.l x, 4(sp) { auto_make_proc(ea1+fd.off); auto_make_proc(jt_addr); } jt_addr+=6; } // TODO: hide the table? // add_hidden_range(jt_start, jt_addr, "Jumptable for segment NNN", "", "", 0); } //------------------------------------------------------------------------ void doCodeOffset(ea_t ea, ea_t base) { create_dword(ea,4); uint32 off = get_dword(ea); op_offset(ea, 0, REF_OFF32, BADADDR, base, off&1); ea_t target = base+off; if ( off&1 )// last bit set: offset to thumb code { target &= (~1); // remove last bit // set_sreg_at_next_code(target,BADADDR,str2reg("T"),1); split_sreg_range(target,str2reg("T"),1,SR_auto,true); } auto_make_proc(target); } //------------------------------------------------------------------------ void fixArmCW(ea_t start_ea, ea_t end_ea) { // check for codewarrior relocation info /* typedef struct PnoHeaderType { 00 UInt32 startupCode[8]; // changes based on the instruction count in startup code 20 UInt32 pnoMain; // offset to ARMletMain routine 24 UInt32 signature; // special PNO signature value 28 UInt32 dataStart; // offset to start of initialized data 2C UInt32 roDataStart; // offset to start of read-only initialized data 30 UInt32 bssStart; // offset to start of uninitialized data 34 UInt32 bssEnd; // offset to end of uninitialized data 38 UInt32 codeRelocsStart; // offset to start of data-to-code relocation list 3C UInt32 codeRelocsEnd; // offset to end of data-to-code relocation list 40 UInt32 dataRelocsStart; // offset to start of data-to-data relocation list 44 UInt32 dataRelocsEnd; // offset to end of data-to-data relocation list 48 UInt32 altEntryCode[8]; // changes based on the instruction count in alternate entry code 68 } PnoHeaderType; */ const char *const comments[] = { "offset to ARMletMain routine", "special PNO signature value", "offset to start of initialized data", "offset to start of read-only initialized data", "offset to start of uninitialized data", "offset to end of uninitialized data", "offset to start of data-to-code relocation list", "offset to end of data-to-code relocation list", "offset to start of data-to-data relocation list", "offset to end of data-to-data relocation list", }; if ( end_ea-start_ea < 0x68 ) return; for ( int i=0x20; i < 0x48; i+=4 ) { create_dword(start_ea+i,4); if ( i == 0x24 ) op_chr(start_ea+i, 0); else op_offset(start_ea+i, 0, REF_OFF32, BADADDR, start_ea); set_cmt(start_ea+i, comments[(i-0x20)/4],0); } auto_make_proc(start_ea); auto_make_proc(start_ea+0x48); doCodeOffset(start_ea+0x20,start_ea); // do relocs ea_t cur = start_ea+get_dword(start_ea+0x38); ea_t end = start_ea+get_dword(start_ea+0x3C); for ( ; cur < end; cur+=4 ) { create_dword(cur,4); op_offset(cur, 0, REF_OFF32, BADADDR, start_ea); doCodeOffset(start_ea+get_dword(cur), start_ea); } cur = start_ea+get_dword(start_ea+0x40); end = start_ea+get_dword(start_ea+0x44); for ( ; cur < end; cur+=4 ) { create_dword(cur,4); op_offset(cur, 0, REF_OFF32, BADADDR, start_ea); ea_t o = start_ea+get_dword(cur); create_dword(o,4); op_offset(o, 0, REF_OFF32, BADADDR, start_ea); } } //------------------------------------------------------------------------ // check for 'cdwr' signature bool isCWseg(linput_t *li, uint32 offset) { qlseek(li, offset + 0x24); uchar sig[4]; qlread(li, sig, 4); return sig[0] == 'r' && sig[1] == 'w' && sig[2] == 'd' && sig[3] == 'c'; } //------------------------------------------------------------------------ void idaapi load_file(linput_t *li, ushort neflags, const char * fileformatname) { int i; bool armCode = strcmp(fileformatname, PRC_ARM) == 0; bool manualMode = (neflags & NEF_MAN) != 0; // don't do any extra processing if set sel_t dgroup = BADSEL; set_processor_type(armCode ? "ARM" : "68K", SETPROC_LOADER); set_target_assembler(armCode ? 0 : 2); // Generic ARM assembler/PalmPilot assembler Pila DatabaseHdrType h; lread(li,&h,sizeof(h)); swap_prc(h); qvector re; re.resize(h.numRecords); lread(li, re.begin(), sizeof(ResourceMapEntry) * h.numRecords); for ( i=0; i < h.numRecords; i++ ) swap_resource_map_entry(re[i]); code0000_t code0000 = { 0, 0 }; if ( !armCode ) { // sortResources(re, h.numRecords); // determine the bss size for ( i=0; i < h.numRecords; i++ ) { if ( re[i].fcType == PILOT_RSC_CODE && re[i].id == 0 ) // code0000 { qlseek(li, re[i].ulOffset); lread(li, &code0000, sizeof(code0000)); swap_code0000(&code0000); break; } } } ea_t a5 = BADADDR, a4 = BADADDR, code1ea = BADADDR; ea_t datastart = BADADDR; // load the segments for ( i=0; i < h.numRecords; i++ ) { // don't load known UI resources when asked not to if ( !(NEF_RSCS & neflags) && isKnownResource(re[i].fcType) ) continue; // skip ARM chunks in 68K mode if ( !armCode && (re[i].fcType == PILOT_RSC_ARMC || re[i].fcType == PILOT_RSC_ARMCL) ) continue; uint64 size; if ( i == (h.numRecords-1) ) size = qlsize(li); else size = re[i+1].ulOffset; if ( size < re[i].ulOffset ) loader_failure("Invalid file structure"); size -= re[i].ulOffset; ea_t ea1 = (inf_get_max_ea() + 0xF) & ~0xF; ea_t ea2 = ea1 + size; char segname[10]; qsnprintf(segname, sizeof(segname), "%4.4s%04X", (char*)&re[i].fcType, re[i].id); const char *sclass = "RSC"; if ( armCode ) { // load only ARM segments in ARM mode if ( re[i].fcType != PILOT_RSC_ARMC && re[i].fcType != PILOT_RSC_ARMCL ) continue; bool bCodeWarrior = isCWseg(li, re[i].ulOffset); ea_t start_ea=ea1; file2base(li, re[i].ulOffset, ea1, ea2, FILEREG_PATCHABLE); int sel = i+1; if ( bCodeWarrior && !manualMode ) { // load all sequential chunks as one segment while ( i < h.numRecords-1 && re[i].fcType == re[i+1].fcType && re[i].id + 1 == re[i+1].id && !isCWseg(li, re[i+1].ulOffset) ) { i++; if ( i == (h.numRecords-1) ) size = qlsize(li); else size = re[i+1].ulOffset; if ( size < re[i].ulOffset ) loader_failure("Invalid file structure"); size -= re[i].ulOffset; ea1 = ea2; // TODO: check if pnoloader.c does alignment ea2 = ea1 + size; file2base(li, re[i].ulOffset, ea1, ea2, FILEREG_PATCHABLE); } } set_selector(sel, start_ea >> 4); if ( !add_segm(sel, start_ea, ea2, segname, CLASS_CODE, ADDSEG_SPARSE) ) loader_failure(); // set DS for the segment to itself set_default_sreg_value(get_segm_by_sel(sel), str2reg("DS"), sel); if ( bCodeWarrior ) fixArmCW(start_ea, ea2); continue; } if ( re[i].fcType == PILOT_RSC_CODE ) { if ( re[i].id == 0 && !manualMode ) continue; // skip code0000 resource sclass = CLASS_CODE; if ( re[i].id == 1 ) { inf_set_start_cs(i + 1); inf_set_start_ip(0); code1ea = ea1; } } else if ( re[i].fcType == PILOT_RSC_LIBR || re[i].fcType == PILOT_RSC_GLIB ) { sclass = CLASS_CODE; if ( re[i].id == 0 ) { inf_set_start_cs(i + 1); inf_set_start_ip(0); code1ea = ea1; } } // check if we need to decompress stuff if ( re[i].fcType == PILOT_RSC_DATA && re[i].id == 0 ) { sclass = CLASS_DATA; dgroup = i + 1; size_t usize = unpack_data0000(li, re[i].ulOffset, size, ea1, code0000, code1ea, a5); ea2 = ea1 + usize; datastart = ea1; } else if ( re[i].fcType == PILOT_RSC_DATA && re[i].id == 1 && !manualMode ) { sclass = CLASS_DATA; size_t usize = unpack_data0001(li, re[i].ulOffset, size, ea1, a5, code1ea, a4); ea2 = ea1 + usize; } else { // otherwise just load it as-is file2base(li, re[i].ulOffset, ea1, ea2, FILEREG_PATCHABLE); } { segment_t s; s.start_ea = ea1; s.end_ea = ea2; s.sel = i+1; s.bitness = 1; // 32bit set_selector(i+1, ea1 >> 4); if ( !add_segm_ex(&s, segname, sclass, ADDSEG_FILLGAP|ADDSEG_OR_DIE|ADDSEG_SPARSE) ) loader_failure(); } } if ( !manualMode && !armCode ) { // check if first dword is 1; if so, skip it if ( get_dword(code1ea) == 1 ) { // codewarrior startup static const uchar pattern[] = { 0x00, 0x00, 0x00, 0x01, // dc.l 1 0x48, 0x7A, 0x00, 0x04, // pea $A 0x06, 0x97, 0xFF, 0xFF, 0xFF, 0xFF, // addi.l #(__Startup__-$A),(sp) 0x4E, 0x75, // rts }; if ( equal_bytes(code1ea, pattern, SKIP_FF_MASK, sizeof(pattern), true) ) { plan_to_apply_idasgn("cwpalm.sig"); } create_dword(code1ea, 4); inf_set_start_ip(4); } // is main code segment GLib? if ( inf_get_start_cs() > 0 && re[int(inf_get_start_cs()-1)].fcType == PILOT_RSC_GLIB && a4 == BADADDR && datastart != BADADDR ) { // GLib's a4 points at the start of data segment a4 = datastart; create_byte(a4, 1); set_name(a4, "A4BASE", SN_NOCHECK|SN_AUTO); set_cmt(a4, "A4 points here", 0); } // check for CodeWarrior's jumptables in additional code segments and fix them up for ( i=0; i < h.numRecords; i++ ) { if ( re[i].fcType == PILOT_RSC_CODE && re[i].id > 1 ) { segment_t *seg = get_segm_by_sel(i+1); if ( seg != NULL ) fix_jumptables(seg->start_ea, seg->end_ea, i+1, a5, a4); } } // TODO: handle prc-tools and multilink's 'rloc' segments } if ( dgroup != BADSEL ) set_default_dataseg(dgroup); // input: selector describe_all(h); exec_system_script("pilot.idc"); } //-------------------------------------------------------------------------- // it is impossible to use ph.id, // the processor module is not loaded yet inline bool is_arm_specified(void) { return strnieq(inf_get_procname().c_str(), "ARM", 3); } inline bool is_68k_specified(void) { char pname[IDAINFO_PROCNAME_SIZE]; inf_get_procname(pname, sizeof(pname)); return strnieq(pname, "68K", 3) || strnieq(pname, "68000", 5) || strnieq(pname, "68010", 5) || strnieq(pname, "68020", 5) || strnieq(pname, "68030", 5) || strnieq(pname, "68040", 5) || strnieq(pname, "68330", 5) || strnieq(pname, "68882", 5) || strnieq(pname, "68851", 5) || strnieq(pname, "ColdFire", 8); } //-------------------------------------------------------------------------- static int idaapi accept_file( qstring *fileformatname, qstring *processor, linput_t *li, const char *) { static int n = 0; int k = is_prc_file(li); if ( k == 0 ) return 0; int ftype = 0; if ( n == 1 ) { if ( k == 2 ) // has ARM segments? { *fileformatname = PRC_ARM; *processor = "ARM"; ftype = f_PRC; if ( is_arm_specified() ) ftype |= ACCEPT_FIRST; } } else { n++; *fileformatname = PRC_68K; *processor = "68K"; ftype = f_PRC|ACCEPT_CONTINUE; if ( is_68k_specified() ) ftype |= ACCEPT_FIRST; } return ftype; } //-------------------------------------------------------------------------- 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, };