Files
sigmaker-ida/idasdk76/ldr/qnx/qnx.cpp
2021-10-31 21:20:46 +02:00

373 lines
9.8 KiB
C++

/*
IDA LOADER for QNX 16/32 bit executables
(c) Zhengxi Ltd., 1998.
start: 25.07.98
end: 26.07.98
changed:
28.07.98 Yury Haron
09.08.98 Denis Petrov
10.08.98 YH - patch to new sdk format
*/
#include "../idaldr.h"
#include "lmf.h"
//--------------------------------------------------------------------------
//
// 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 *)
{
ex_header ex; // lmf header
uint32 n_segments; // segment count
if ( qlread(li, &ex, sizeof(ex)) != sizeof(ex) )
return 0;
if ( 0 != ex.lmf_header.rec_type )
return 0;
if ( 0 != ex.lmf_header.zero1 )
return 0;
// if ( 0x38 != ex.lmf_header.data_nbytes ) return 0;
if ( 0 != ex.lmf_header.spare )
return 0;
if ( 386 != ex.lmf_definition.cpu
&& 286 != ex.lmf_definition.cpu )
{
return 0;
}
n_segments = (ex.lmf_header.data_nbytes - sizeof(_lmf_definition))
/ sizeof (uint32);
if ( (MIN_SEGMENTS > n_segments) || (n_segments > MAX_SEGMENTS) )
return 0;
_lmf_data lmf_data;
lmf_data.segment_index = -1;
uint64 file_size = qlsize(li);
for ( uint32 at = sizeof(ex.lmf_header) + ex.lmf_header.data_nbytes;
lmf_data.segment_index != _LMF_EOF_REC;
)
{
qlseek(li, at, 0);
if ( sizeof(_lmf_data) != qlread(li, &lmf_data, sizeof(_lmf_data) ) )
return 0;
switch ( lmf_data.segment_index )
{
case _LMF_DEFINITION_REC:
return 0;
case _LMF_COMMENT_REC:
break;
case _LMF_DATA_REC:
break;
case _LMF_FIXUP_SEG_REC:
break;
case _LMF_FIXUP_80X87_REC:
break;
case _LMF_EOF_REC:
if ( lmf_data.offset != sizeof(_lmf_eof) )
return 0;
break;
case _LMF_RESOURCE_REC:
break;
case _LMF_ENDDATA_REC:
if ( lmf_data.offset != 6 /*sizeof(???)*/ )
return 0;
break;
case _LMF_FIXUP_LINEAR_REC:
break;
case _LMF_PHRESOURCE:
return 0;
default:
return 0;
}
if ( sizeof(lmf_data) + uint64(lmf_data.offset) > file_size )
return 0;
at += sizeof(lmf_data) + lmf_data.offset;
}
fileformatname->sprnt("QNX %d-executable",
(_PCF_32BIT & ex.lmf_definition.cflags)
? 32
: 16);
*processor = "metapc";
return f_LOADER;
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
//#define _CODE 0
//#define _DATA 1
//#define _BSS 2
//#define _STACK 3
//#define MAXSEG 2
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
ex_header ex; // lmf header
uint32 n_segments; // segment count
uint32 nseg; // watcom 10.6 not working properly without this!
qoff64_t filelen = qlsize(li);
set_processor_type("metapc", SETPROC_LOADER);
qlseek(li, 0);
lread(li, &ex, sizeof(ex));
struct
{
uint32 minea,topea;
} perseg[MAX_SEGMENTS];
n_segments = (ex.lmf_header.data_nbytes - sizeof(_lmf_definition))
/ sizeof (uint32);
if ( n_segments > MAX_SEGMENTS )
{
msg("QNX: a lot of segments %u\n", n_segments);
loader_failure("Bad file header format");
}
for ( nseg = 0; nseg < n_segments; nseg++ )
{
if ( nseg == 0 )
perseg[nseg].minea = ex.lmf_definition.flat_offset;
else
perseg[nseg].minea = (perseg[nseg-1].topea + 0x0FFF) & ~0x0FFF;
perseg[nseg].topea = perseg[nseg].minea + (ex.segsizes[nseg] & 0x0FFFFFFF);
if ( perseg[nseg].minea > perseg[nseg].topea )
loader_failure("Bad file header format");
}
uint32 ring = (_PCF_PRIVMASK &ex.lmf_definition.cflags)>>2;
// uint32 myselector = 0x04 + ring;
// LDT selectors in order.
#define LDT_SELECTOR(nseg) (((nseg)<<3)+0x04+ring)
#define ISFLAT (_PCF_FLAT &ex.lmf_definition.cflags)
inf_set_baseaddr(0);
if ( ISFLAT )
{
inf_set_lflags(inf_get_lflags() | LFLG_PC_FLAT);
// inf.s_prefflag &= ~PREF_SEGADR;
// inf.nametype = NM_EA4;
}
inf_set_start_ip(ex.lmf_definition.code_offset);
if ( ex.lmf_definition.code_index >= n_segments )
loader_failure("Corrupted file");
if ( ISFLAT )
inf_set_start_ip(inf_get_start_ip() + perseg[ex.lmf_definition.code_index].minea);
inf_set_start_cs(LDT_SELECTOR(ex.lmf_definition.code_index));
_lmf_data lmf_data, lmf_data2;
lmf_data.segment_index = -1;
for ( uint32 at = sizeof(ex.lmf_header)+ex.lmf_header.data_nbytes;
lmf_data.segment_index != _LMF_EOF_REC;
at += sizeof(lmf_data) + lmf_data.offset )
{
if ( qlseek(li, at ) != at )
loader_failure("Corrupted file");
lread(li, &lmf_data, sizeof(_lmf_data));
switch ( lmf_data.segment_index )
{
case _LMF_DEFINITION_REC:
break;
case _LMF_COMMENT_REC:
break;
case _LMF_DATA_REC:
{
lread(li, &lmf_data2, sizeof(_lmf_data));
if ( lmf_data2.segment_index >= n_segments )
loader_failure("Corrupted file");
uint32 body_offset = perseg[lmf_data2.segment_index].minea
+ lmf_data2.offset;
uint32 body_size = lmf_data.offset-sizeof(_lmf_data);
if ( body_offset > body_offset + body_size
|| body_offset + body_size > perseg[lmf_data2.segment_index].topea )
{
loader_failure("Corrupted file");
}
file2base(li,
at+sizeof(_lmf_data)+sizeof(_lmf_data),
body_offset,
body_offset + body_size,
FILEREG_PATCHABLE);
}
break;
case _LMF_FIXUP_SEG_REC:
{
fixup_data_t fd(FIXUP_SEG16);
uint32 n_fixups;
_lmf_seg_fixup lmf_seg_fixup;
n_fixups = lmf_data.offset / sizeof(_lmf_seg_fixup);
while ( n_fixups-- )
{
lread(li, &lmf_seg_fixup, sizeof(_lmf_seg_fixup));
uint32 ea=lmf_seg_fixup.data[0].fixup_offset;
if ( lmf_seg_fixup.data[0].fixup_seg_index >= n_segments )
loader_failure("Corrupted file");
ea += perseg[ lmf_seg_fixup.data[0].fixup_seg_index ].minea; // fix!
if ( perseg[ lmf_seg_fixup.data[0].fixup_seg_index ].minea > ea
|| ea > perseg[ lmf_seg_fixup.data[0].fixup_seg_index ].topea )
{
loader_failure("Corrupted file");
}
fd.sel = get_word(ea); //lmf_seg_fixup.data[0].fixup_seg_index;
fd.set(ea);
}
}
break;
case _LMF_FIXUP_80X87_REC: // x87 FPU instruction offsets
break;
case _LMF_EOF_REC: // no interesting for ida
break;
case _LMF_RESOURCE_REC: // don't support now
break;
case _LMF_ENDDATA_REC: // 6 bytes of uknown data
break;
case _LMF_FIXUP_LINEAR_REC:
break;
case _LMF_PHRESOURCE: // don't support now
break;
}
}
uint32 itxt = 0;
uint32 idat = 0;
for ( nseg = 0; nseg < n_segments; nseg++ )
{
uint32 selector = LDT_SELECTOR(nseg);
char seg_name[8];
const char *seg_class;
if ( (ex.segsizes[nseg]>>28) == _LMF_CODE )
{
qsnprintf(seg_name, sizeof(seg_name), "cseg_%.02u", ++itxt);
seg_class = CLASS_CODE;
}
else
{
qsnprintf(seg_name, sizeof(seg_name), "dseg_%.02u", ++idat);
seg_class = CLASS_DATA;
}
set_selector(selector, ISFLAT ? 0 : perseg[nseg].minea>>4);
segment_t s;
s.sel = selector;
s.start_ea = perseg[nseg].minea;
s.end_ea = perseg[nseg].topea;
s.align = saRelByte;
s.comb = scPub;
s.bitness = (_PCF_32BIT & ex.lmf_definition.cflags) ? 1 : 0;
bool sparse = (perseg[nseg].topea - perseg[nseg].minea) > filelen;
int flags = (sparse ? ADDSEG_SPARSE : 0) | ADDSEG_NOSREG;
if ( !add_segm_ex(&s, seg_name, seg_class, flags) )
loader_failure();
if ( _PCF_32BIT &ex.lmf_definition.cflags )
set_segm_addressing(getseg(perseg[nseg].minea), 1); // 32bit
}
set_default_dataseg(LDT_SELECTOR(ex.lmf_definition.argv_index));
create_filename_cmt();
add_pgm_cmt("Version : %d.%d",
ex.lmf_definition.version_no>>8,
ex.lmf_definition.version_no&255);
add_pgm_cmt("Priv level : %d",
(_PCF_PRIVMASK &ex.lmf_definition.cflags)>>2);
char str[MAXSTR], *p = str;
char *e = str + sizeof(str);
if ( _PCF_LONG_LIVED & ex.lmf_definition.cflags )
APPEND(p, e, " LONG_LIVED");
if ( _PCF_32BIT & ex.lmf_definition.cflags )
{
if ( p != str )
APPCHAR(p, e, ',');
APPEND(p, e, " 32BIT");
}
if ( ISFLAT )
{
if ( p != str )
APPCHAR(p, e, ',');
APPEND(p, e, " FLAT");
}
if ( _PCF_NOSHARE & ex.lmf_definition.cflags )
{
if ( p != str )
APPCHAR(p, e, ',');
APPEND(p, e, " NOSHARE");
}
if ( p == str ) APPEND(p, e, " None");
add_pgm_cmt("Code flags :%s", str);
// ig 08.09.00: Automatically load the Watcom signature file
plan_to_apply_idasgn(ISFLAT ? "wa32qnx" : "wa16qnx");
}
//----------------------------------------------------------------------
//
// 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,
};