update to ida 7.6, add builds

This commit is contained in:
2021-10-31 21:20:46 +02:00
parent e0e0f2be99
commit b1809fe2d9
1408 changed files with 279193 additions and 302468 deletions

427
idasdk76/ldr/aif/aif.cpp Normal file
View File

@@ -0,0 +1,427 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-97 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
* ARM Image File (AIF) Loader
* ---------------------------
* This module allows IDA to load ARM image files into
* its database and to disassemble them correctly.
*
* NOTE: Compressed image files are not supported
* Self-relocating image files are not supported
* Thumb image files are not supported
* Only 32-bit image files are supported
*
* This module automatically detects the byte sex and sets inf.mf
* variable accrodingly.
*
* The debug information is partially processed.
*
*/
#include <stddef.h>
#include "../idaldr.h"
#include "aif.h"
#include "../aof/aof.h"
// the following function is defined to be used by aifcmn.cpp
// included below (see also efd/aif.cpp)
inline bool is_mf() { return inf_is_be(); }
#include "aifcmn.cpp"
//--------------------------------------------------------------------------
//
// 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 *)
{
if ( !is_aif_file(li) )
return 0;
*fileformatname = "ARM Image File";
*processor = "arm";
return 1;
}
//--------------------------------------------------------------------------
// Create a section.
static void create_section(
ushort sel,
ea_t start_ea,
ea_t end_ea,
const char *name,
const char *classname)
{
set_selector(sel, 0);
segment_t s;
s.sel = sel;
s.start_ea = start_ea;
s.end_ea = end_ea;
s.align = saRelByte;
s.comb = scPub;
s.bitness = 1; // 32-bit
int flags = ADDSEG_SPARSE | ADDSEG_NOSREG | ADDSEG_NOTRUNC;
if ( !add_segm_ex(&s, name, classname, flags) )
loader_failure();
segment_t *sptr = getseg(start_ea);
set_arm_segm_flags(start_ea, 2 << 10); // alignment
sptr->update();
}
//--------------------------------------------------------------------------
// The assembler and the compiler generate lots of meaningless symbols.
// We will ignore them.
static bool special_name(const char *name)
{
int i;
if ( name[0] == '\0' )
return true;
if ( name[0] == '$' )
return true;
const char *ptr = strchr(name,'$');
if ( ptr != NULL && ptr[1] == '$' )
return true;
static const char *const ex[] =
{
"_etext",
"_edata",
"_end",
"!!!"
};
for ( i=0; i < qnumber(ex); i++ )
if ( strcmp(ex[i],name) == 0 )
return true;
static const char *const data_names[] = { "x$constdata", "x$litpool" };
for ( i=0; i < qnumber(data_names); i++ )
if ( strncmp(name, data_names[i], strlen(data_names[i])) == 0 )
return true;
return false;
}
//--------------------------------------------------------------------------
// The debug information says that "xlitpool" symbols have "CODE" type.
// We cannot base on this because doing so we would convert
// xlitpools to instructions.
// So, we will look at the names and if a location has
// "xlitpool" or similar name, we will not convert it to instructions
// even it is marked as "CODE".
//
// Later: I decided not to use all those names at all.
static bool is_true_text_symbol(dsym_t *ds,const char *name)
{
if ( ds->is_text() )
{
static const char *const data_names[] = { "x$constdata", "x$litpool" };
for ( int i=0; i < qnumber(data_names); i++ )
if ( strncmp(name,data_names[i],strlen(data_names[i])) == 0 )
return false;
return true;
}
return false;
}
//--------------------------------------------------------------------------
// Process debugging information item and try to incorporate it into
// the database.
// NOTE: This function does not process all debugging information.
// It knows only about some types of debugingo.
static size_t process_item(uchar *di, size_t disize, section_t *sect)
{
uchar *const end = di + disize;
if ( disize < 4 )
return 0;
uint32 fw = *(uint32 *)di;
if ( inf_is_be() )
fw = swap32(fw);
size_t len = fw >> 16;
if ( len == 0 || len > disize )
return 0;
switch ( fw & 0xFFFF )
{
case AIF_DEB_SECT: // section
if ( disize < sizeof(section_t) )
return 0;
sect = (section_t *)di;
if ( inf_is_be() )
swap_section(sect);
if ( sect->debugsize != 0 )
{
len = sect->debugsize;
if ( len > disize )
return 0;
}
switch ( sect->lang )
{
case LANG_C:
add_extra_cmt(sect->codestart, true, "C source level debugging data is present");
break;
case LANG_PASCAL:
add_extra_cmt(sect->codestart, true, "Pascal source level debugging data is present");
break;
case LANG_FORTRAN:
add_extra_cmt(sect->codestart, true, "Fortran-77 source level debugging data is present");
break;
case LANG_ASM:
add_extra_cmt(sect->codestart, true, "ARM assembler line number data is present");
break;
}
if ( sect->lang == LANG_NONE )
{
size_t nsyms = size_t(sect->name);
dsym_t *ds = (dsym_t *)(sect+1);
char *str = (char *)(ds+nsyms);
if ( !is_mul_ok(nsyms, sizeof(dsym_t)) || ds+nsyms < ds || str >= (char *)end )
return 0;
bool use_pascal = swap_symbols(ds, str, end, nsyms);
for ( int i=0; i < nsyms; i++,ds++ )
{
if ( ds->sym & ASD_16BITSYM )
continue;
size_t off = size_t(ds->sym & ASD_SYMOFF);
char *name = str + off + use_pascal;
if ( name < str || name >= (char *)end )
continue;
if ( special_name(name) )
continue;
if ( ds->sym == ASD_ABSSYM ) // if the symbol is absolute
{
add_pgm_cmt("%s = 0x%X", name, ds->value);
}
else if ( is_mapped(ds->value) )
{
if ( ds->sym & ASD_GLOBSYM )
{
add_entry(ds->value, ds->value, name, is_true_text_symbol(ds, name), AEF_IDBENC);
}
else
{
force_name(ds->value, name, SN_IDBENC);
if ( is_true_text_symbol(ds, name) )
auto_make_code(ds->value);
}
}
}
}
else
{
char name[64];
const uchar *nptr = (const uchar *)&sect->name;
size_t namelen = *nptr++;
if ( namelen > end-nptr || namelen >= sizeof(name) )
return 0;
qstrncpy(name, (const char *)nptr, sizeof(name));
name[namelen] = '\0';
if ( sect->codestart != 0 )
add_extra_cmt(sect->codestart, true, "Section \"%s\", size 0x%X",name,sect->codesize);
if ( sect->datastart != 0 )
add_extra_cmt(sect->datastart, true, "Section \"%s\", size 0x%X",name,sect->datasize);
}
#if 0
if ( sect->fileinfo != 0 ) // fileinfo is present?
process_item(di+size_t(sect->fileinfo),sect);
#endif
break;
case AIF_DEB_FDEF: // procedure/function definition
deb(IDA_DEBUG_LDR, "procedure/function definition\n");
break;
case AIF_DEB_ENDP: // endproc
deb(IDA_DEBUG_LDR, "endproc\n");
break;
case AIF_DEB_VAR: // variable
deb(IDA_DEBUG_LDR, "variable\n");
break;
case AIF_DEB_TYPE: // type
deb(IDA_DEBUG_LDR, "type\n");
break;
case AIF_DEB_STRU: // struct
deb(IDA_DEBUG_LDR, "struct\n");
break;
case AIF_DEB_ARRAY: // array
deb(IDA_DEBUG_LDR, "array\n");
break;
case AIF_DEB_RANGE: // subrange
deb(IDA_DEBUG_LDR, "subrange\n");
break;
case AIF_DEB_SET: // set
deb(IDA_DEBUG_LDR, "set\n");
break;
case AIF_DEB_FILE: // fileinfo
deb(IDA_DEBUG_LDR, "fileinfo\n");
break;
case AIF_DEB_CENUM: // contiguous enumeration
deb(IDA_DEBUG_LDR, "contiguous enumeration\n");
break;
case AIF_DEB_DENUM: // discontiguous enumeration
deb(IDA_DEBUG_LDR, "discontiguous enumeration\n");
break;
case AIF_DEB_FDCL: // procedure/function declaration
deb(IDA_DEBUG_LDR, "procedure/function declaration\n");
break;
case AIF_DEB_SCOPE: // begin naming scope
deb(IDA_DEBUG_LDR, "begin naming scope\n");
break;
case AIF_DEB_ENDS: // end naming scope
deb(IDA_DEBUG_LDR, "end naming scope\n");
break;
case AIF_DEB_BITF: // bitfield
deb(IDA_DEBUG_LDR, "bitfield\n");
break;
case AIF_DEB_MACRO: // macro definition
deb(IDA_DEBUG_LDR, "macro definition\n");
break;
case AIF_DEB_ENDM: // macro undefinition
deb(IDA_DEBUG_LDR, "macro undefinition\n");
break;
case AIF_DEB_CLASS: // class
deb(IDA_DEBUG_LDR, "class\n");
break;
case AIF_DEB_UNION: // union
deb(IDA_DEBUG_LDR, "union\n");
break;
case AIF_DEB_FPMAP: // FP map fragment
deb(IDA_DEBUG_LDR, "FP map fragment\n");
break;
default:
msg("unknown (0x%u.)!!!\n", fw & 0xFFFF);
break;
}
return len;
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
aif_header_t hd;
set_processor_type("arm", SETPROC_LOADER);
lread(li, &hd, sizeof(hd));
inf_set_be(match_zero_code(&hd) != 1);
if ( (hd.address_mode & 0xFF) != 32 )
{
if ( (hd.address_mode & 0xFF) != 0 )
loader_failure("26-bit modules are not supported");
msg("Old AIF format file...");
}
if ( hd.decompress_code != NOP )
loader_failure("Compressed modules are not supported");
if ( hd.self_reloc_code != NOP )
loader_failure("Self-relocating modules are not supported");
inf_set_baseaddr(0);
int isexec = is_bl(hd.entry_point);
qoff64_t offset = sizeof(aif_header_t);
ea_t start = hd.image_base;
if ( isexec )
{
start += sizeof(aif_header_t);
hd.readonly_size -= sizeof(aif_header_t);
}
uint64 rest = qlsize(li) - offset;
if ( rest < hd.readonly_size )
BAD_FILE:
loader_failure("Corrupted file");
ea_t end = start + hd.readonly_size;
file2base(li, offset, start, end, FILEREG_PATCHABLE);
create_section(1, start, end, NAME_CODE, CLASS_CODE);
offset += hd.readonly_size;
if ( hd.readwrite_size != 0 )
{
rest = qlsize(li) - offset;
if ( rest < hd.readwrite_size )
goto BAD_FILE;
start = (hd.address_mode & AIF_SEP_DATA) ? hd.data_base : end;
end = start + hd.readwrite_size;
file2base(li, offset, start, end, FILEREG_PATCHABLE);
create_section(2, start, end, NAME_DATA, CLASS_DATA);
offset += hd.readwrite_size;
}
if ( hd.zero_init_size != 0 )
{
start = end;
end = start + hd.zero_init_size;
create_section(3, start, end, NAME_BSS, CLASS_BSS);
}
create_filename_cmt();
if ( isexec )
hd.entry_point = hd.image_base
+ offsetof(aif_header_t,entry_point)
+ ((hd.entry_point & ~BLMASK) << 2)
+ 8;
inf_set_start_cs(1);
inf_set_start_ip(hd.entry_point);
inf_set_start_ea(hd.entry_point);
validate_array_count(li, &hd.debug_size, 1, "Size of debug info", offset);
if ( hd.debug_size != 0 )
{
msg("Debugging information is present (%u bytes at file offset 0x%" FMT_64 "X)...\n",
hd.debug_size, offset);
uchar *di = qalloc_array<uchar>(size_t(hd.debug_size));
if ( di == NULL )
nomem("AIF debugging info");
qlseek(li, offset);
lread(li, di, size_t(hd.debug_size));
uchar *ptr = di;
uchar *diend = di + size_t(hd.debug_size);
section_t *sect = NULL;
while ( ptr < diend )
{
size_t len = process_item(ptr, diend-ptr, sect);
if ( len == 0 )
{
warning("Corrupted debug info");
break;
}
ptr += len;
}
qfree(di);
}
}
//----------------------------------------------------------------------
//
// 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,
};

177
idasdk76/ldr/aif/aif.h Normal file
View File

@@ -0,0 +1,177 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-97 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
* ARM Image File Format
*
*/
#ifndef __AIF_H__
#define __AIF_H__
//-------------------------------------------------------------------------
struct aif_header_t
{
uint32 decompress_code;// BL or NOP if the image is not compressed.
uint32 self_reloc_code;// BL or NOP if the image is not self-relocating.
uint32 zero_init; // (or DBGInit) BL or NOP if the image has none.
uint32 entry_point; // BL or EntryPoint offset
uint32 program_exit; // usually SWI instruction
uint32 readonly_size; // Includes header size if executable AIF;
// excludes header size if non-executable AIF
uint32 readwrite_size; // Exact size (a multiple of 4 bytes).
uint32 debug_size; // Exact size (a multiple of 4 bytes).
uint32 zero_init_size; // Exact size (a multiple of 4 bytes).
uint32 debug_type; // bitwise OR of the following:
#define AIF_DEBUG_NONE 0
#define AIF_DEBUG_LOW 1 // Low-level debugging data is present
#define AIF_DEBUG_SRC 2 // Source level (ASD) debugging data is present
uint32 image_base; // Address where the image (code) was linked.
uint32 work_space; // Minimum work space (in bytes) to be reserved by a
// self-moving relocatable image.
uint32 address_mode; // 26/32 + 3 flag bytes LS byte contains 26 or 32;
// bit 8 set when using a separate data base.
#define AIF_SEP_DATA 0x100 // if set, data_base is meaningful.
uint32 data_base; // Address where the image data was linked.
uint32 reserved[2]; // Two reserved words (initially 0)
uint32 debug_init; // NOP if unused.
uint32 zero_code[15]; // Zero-init code.
};
//-------------------------------------------------------------------------
#define ZERO_CODE1 \
0xE04EC00F, 0xE08FC00C, 0xE99C000F, \
0xE24CC010, 0xE59C2030, 0xE3120C01, 0x159CC034, \
0x008CC000, 0xE08CC001, 0xE3A00000, 0xE3530000, \
0xD1A0F00E, 0xE48C0004, 0xE2533004, 0xEAFFFFFB
#define ZERO_CODE2 \
0xE04EC00F, 0xE08FC00C, 0xE99C0017, \
0xE24CC010, 0xE08CC000, 0xE08CC001, 0xE3A00000, \
0xE3A01000, 0xE3A02000, 0xE3A03000, 0xE3540000, \
0xD1A0F00E, 0xE8AC000F, 0xE2544010, 0xEAFFFFFB,
#define NOP 0xE1A00000L // opcode of NOP instruction
#define BL 0xEB000000L // opcode of BL instruction
#define BLMASK 0xFF000000L // mask to check BL instruction
// is BL instruction opcode?
inline int is_bl(uint32 code) { return (code & BLMASK) == BL; }
//-------------------------------------------------------------------------
// Debug item codes:
#define AIF_DEB_SECT 1 // section
#define AIF_DEB_FDEF 2 // procedure/function definition
#define AIF_DEB_ENDP 3 // endproc
#define AIF_DEB_VAR 4 // variable
#define AIF_DEB_TYPE 5 // type
#define AIF_DEB_STRU 6 // struct
#define AIF_DEB_ARRAY 7 // array
#define AIF_DEB_RANGE 8 // subrange
#define AIF_DEB_SET 9 // set
#define AIF_DEB_FILE 10 // fileinfo
#define AIF_DEB_CENUM 11 // contiguous enumeration
#define AIF_DEB_DENUM 12 // discontiguous enumeration
#define AIF_DEB_FDCL 13 // procedure/function declaration
#define AIF_DEB_SCOPE 14 // begin naming scope
#define AIF_DEB_ENDS 15 // end naming scope
#define AIF_DEB_BITF 16 // bitfield
#define AIF_DEB_MACRO 17 // macro definition
#define AIF_DEB_ENDM 18 // macro undefinition
#define AIF_DEB_CLASS 19 // class
#define AIF_DEB_UNION 20 // union
#define AIF_DEB_FPMAP 32 // FP map fragment
//-------------------------------------------------------------------------
struct section_t
{
uint32 code; // Section code and length
uchar lang; // Language codes:
#define LANG_NONE 0 // Low-level debugging data only
#define LANG_C 1 // C source level debugging data
#define LANG_PASCAL 2 // Pascal source level debugging data
#define LANG_FORTRAN 3 // Fortran-77 source level debugging data
#define LANG_ASM 4 // ARM assembler line number data
uchar flags; // Format is unknown :(
uchar reserved;
uchar asdversion; // ASD version.
#define ASD_VERSION 2
uint32 codestart; // Address of first instruction in this section,
// relocated by the linker.
uint32 datastart; // Address of start of static data for this section,
// relocated by the linker.
uint32 codesize; // Byte size of executable code in this section.
uint32 datasize; // Byte size of the static data in this section.
uint32 fileinfo; // Offset in the debugging area of the fileinfo item
// for this section (0 if no fileinfo item present).
// The fileinfo field is 0 if no source file
// information is present.
uint32 debugsize; // Total byte length of debug data for this section.
uint32 name; // ...or nsyms. String or integer. The name field
// contains the program name for Pascal and Fortran
// programs. For C programs it contains a name derived
// by the compiler from the root filename (notionally
// a module name). In each case, the name is similar
// to a variable name in the source language. For a
// low-level debugging section (language = 0), the
// field is treated as a four-byte integer giving the
// number of symbols following.
};
//-------------------------------------------------------------------------
// Debug symbol types:
struct dsym_t
{
uint32 sym; // Flags + byte offset in string table of symbol name.
#define ASD_SYMOFF 0x00FFFFFFL
// sym encodes an index into the string table in the 24 least
// significant bits, and the following flag values in the
// eight most significant bits:
#define ASD_ABSSYM 0x00000000L // if the symbol is absolute
#define ASD_GLOBSYM 0x01000000L // if the symbol is global
#define ASD_SYMMASK 0x06000000L // mask to determine the symbol type
#define ASD_TEXTSYM 0x02000000L // if the symbol names code
#define ASD_DATASYM 0x04000000L // if the symbol names data
#define ASD_ZINITSYM 0x06000000L // if the symbol names 0-initialized data
#define ASD_16BITSYM 0x10000000L // bit set if the symbol is a Thumb symbol
uint32 value; // the symbol's value.
int is_text(void) { return (sym & ASD_SYMMASK) == ASD_TEXTSYM; }
int is_data(void) { return (sym & ASD_SYMMASK) == ASD_DATASYM; }
int is_bss(void) { return (sym & ASD_SYMMASK) == ASD_ZINITSYM; }
};
/*
Several of the debugging data items (eg. procedure and variable) have a type
word field to identify their data type. This field contains
in the most significant 24 bits, a code to identify a base
in the least significant 8 bits, a pointer count:
0 denotes the type itself
1 denotes a pointer to the type
2 denotes a pointer to a pointer
void 0
signed integers
single byte 10
halfword 11
word 12
double word 13
unsigned integers
single byte 20
halfword 21
word 22
double word 23
floating point
float 30
double 31
int32 double 32
complex
single complex 41
double complex 42
functions
function 100
*/
#endif

View File

@@ -0,0 +1,88 @@
static const uint32 magic1[] = { ZERO_CODE1 };
static const uint32 magic2[] = { ZERO_CODE2 };
static const uint32 *const magics[] = { magic1, magic2 };
//--------------------------------------------------------------------------
static void swap_header(aif_header_t *hd)
{
uint32 *ptr = (uint32 *)hd;
const int size = sizeof(aif_header_t) / sizeof(uint32);
for ( size_t i=0; i < size; i++, ptr++ )
*ptr = swap32(*ptr);
}
//--------------------------------------------------------------------------
// 0-failed, 1-little endian, 2-big endian
static int match_zero_code(aif_header_t *hd)
{
int mostfirst = 0;
for ( int i=0; i < qnumber(magics); i++ )
{
if ( memcmp(hd->zero_code, magics[i], sizeof(hd->zero_code)) == 0 )
return mostfirst+1;
swap_header(hd);
mostfirst = !mostfirst;
if ( memcmp(hd->zero_code, magics[i], sizeof(hd->zero_code)) == 0 )
return mostfirst+1;
}
return 0;
}
//--------------------------------------------------------------------------
//
// check input file format. if recognized, then return 1
// otherwise return 0
//
bool is_aif_file(linput_t *li)
{
aif_header_t hd;
qlseek(li, 0);
if ( qlread(li, &hd, sizeof(hd)) != sizeof(hd) )
return false;
return match_zero_code(&hd) != 0;
}
//--------------------------------------------------------------------------
static void swap_section(section_t *s)
{
s->codestart = swap32(s->codestart);
s->datastart = swap32(s->datastart);
s->codesize = swap32(s->codesize);
s->datasize = swap32(s->datasize);
s->fileinfo = swap32(s->fileinfo);
s->debugsize = swap32(s->debugsize);
s->name = swap32(s->name);
}
//--------------------------------------------------------------------------
static void swap_dsym(dsym_t *s)
{
s->sym = swap32(s->sym);
s->value = swap32(s->value);
}
//--------------------------------------------------------------------------
// returns true - debug info with pascal symbols
static bool swap_symbols(dsym_t *ds, char *str, uchar *end, size_t nsyms)
{
int npascal = 0; // number of pascal strings
int nc = 0; // number of c strings
for ( int i=0; i < nsyms; i++,ds++ )
{
if ( is_mf() )
swap_dsym(ds);
if ( ds->sym & ASD_16BITSYM )
continue;
size_t off = size_t(ds->sym & ASD_SYMOFF);
char *name = str + off;
if ( name >= (char *)end )
continue;
if ( name[0] == strlen(name)-1 )
npascal++;
else
nc++;
}
return npascal > nc;
}

14
idasdk76/ldr/aif/makefile Normal file
View File

@@ -0,0 +1,14 @@
PROC=aif
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)aif$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../aof/aof.h ../idaldr.h aif.cpp aif.h \
aifcmn.cpp

View File

@@ -0,0 +1,610 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2020 by Ilfak Guilfanov, <ig@datarescue.com>
* ALL RIGHTS RESERVED.
*
* AMIGA hunk file loader
*
*/
#include "../idaldr.h"
#include "amiga.hpp"
#define SkipLong(Longs) do { if ( qlseek(li, 4 * qoff64_t(Longs), SEEK_CUR) == -1 ) goto TRUNCATED_INPUT; } while ( 0 )
#define SkipWord(Words) do { if ( qlseek(li, 2 * qoff64_t(Words), SEEK_CUR) == -1 ) goto TRUNCATED_INPUT; } while ( 0 )
#define SkipByte(Bytes) do { if ( qlseek(li, 1 * qoff64_t(Bytes), SEEK_CUR) == -1 ) goto TRUNCATED_INPUT; } while ( 0 )
//------------------------------------------------------------------------------
static void ask_for_help(void)
{
ask_for_feedback("This file contains some untested records");
}
//------------------------------------------------------------------------------
static char *read_name(linput_t *li, char *buf, size_t bufsize, int Longs)
{
if ( ssize_t(bufsize) > 0 )
{
size_t sz = Longs;
if ( sz != 0 )
{
sz *= 4;
if ( sz >= bufsize )
sz = bufsize-1;
lread(li, buf, sz);
}
buf[sz] = '\0';
}
return buf;
}
//------------------------------------------------------------------------------
void idaapi load_file(linput_t *li,ushort /*_neflags*/,const char * /*fileformatname*/)
{
set_processor_type("68040", SETPROC_LOADER);
uint32 Type, Data, i;
int nums;
char NameString[MAXSTR];
bool has_header = false;
bool shortreloc = false;
ea_t start = to_ea(inf_get_baseaddr(), 0);
ea_t end = start;
//
// The first pass
//
qoff64_t fsize = qlsize(li);
qlseek(li, 0);
while ( true )
{
i = (uint32)qlread(li, &Type, sizeof(Type));
if ( i != sizeof(Type) )
{
if ( i != 0 )
warning("There %s %u extra byte%s at end of file.",
i == 1 ? "is" : "are",
i,
i == 1 ? "" : "s");
break;
}
Type = swap32(Type);
if ( Type == HUNK_DREL32 && has_header )
Type = HUNK_DREL32EXE;
switch ( Type & 0xFFFF )
{
case HUNK_UNIT:
read_name(li, NameString, sizeof(NameString), mf_readlong(li));
break;
case HUNK_NAME:
read_name(li, NameString, sizeof(NameString), mf_readlong(li));
break;
case HUNK_LIB:
SkipLong(1);
break;
case HUNK_INDEX:
SkipLong(mf_readlong(li));
break;
case HUNK_CODE:
case HUNK_PPC_CODE:
case HUNK_DATA:
case HUNK_BSS:
{
Data = mf_readlong(li);
Data <<= 2;
Data &= 0x7FFFFFFF;
start = free_chunk(end, Data, -0xF);
end = start + Data;
if ( end < start )
loader_failure("Segment address overlow: %a..%a", start, end);
const char *sname = NULL;
sel_t sel = get_segm_qty() + 1;
set_selector(sel, 0);
switch ( Type & 0xFFFF )
{
case HUNK_PPC_CODE:
set_processor_type("ppc", SETPROC_LOADER);
sname = "PPC_CODE";
break;
case HUNK_CODE:
sname = "CODE";
if ( inf_get_start_cs() == BADSEL )
{
inf_set_start_cs(sel);
inf_set_start_ip(start);
}
break;
case HUNK_DATA:
sname = "DATA";
break;
case HUNK_BSS:
sname = "BSS";
break;
}
if ( (Type & 0xFFFF) != HUNK_BSS )
{
uint64 rest = fsize - qltell(li);
if ( end-start > rest )
loader_failure("Too big segment %a..%a", start, end);
file2base(li, qltell(li), start, end, FILEREG_PATCHABLE);
}
segment_t s;
s.sel = setup_selector(sel);
s.start_ea = start;
s.end_ea = end;
s.align = saRelByte;
s.comb = scPub;
s.bitness = PH.get_segm_bitness();
add_segm_ex(&s, sname, sname, ADDSEG_NOSREG|ADDSEG_SPARSE);
}
break;
case HUNK_RELOC32SHORT:
case HUNK_DREL32EXE:
shortreloc = true;
// no break
case HUNK_RELRELOC32:
case HUNK_ABSRELOC16:
case HUNK_RELRELOC26:
case HUNK_RELOC32:
case HUNK_RELOC16:
case HUNK_RELOC8:
case HUNK_DREL32:
case HUNK_DREL16:
case HUNK_DREL8:
nums = 0;
while ( true )
{
if ( qltell(li) >= fsize )
TRUNCATED_INPUT:
loader_failure("Truncated file");
Data = shortreloc ? mf_readshort(li) : mf_readlong(li);
if ( Data == 0 )
break;
shortreloc ? mf_readshort(li) : mf_readlong(li);
if ( shortreloc )
SkipWord(Data);
else
SkipLong(Data);
nums += Data;
}
if ( (nums & 1) == 0 && shortreloc )
SkipWord(1);
shortreloc = false;
break;
case HUNK_EXT:
while ( true )
{
if ( qltell(li) >= fsize )
goto TRUNCATED_INPUT;
Data = mf_readlong(li);
if ( Data == 0 )
break;
/* Is it followed by a symbol name? */
if ( Data & 0xFFFFFF )
read_name(li, NameString, sizeof(NameString), Data & 0xFFFFFF);
/* Remember extension type. */
int32 exttype = (Data >> 24) & 0xFF;
/* Display value of symbol. */
if ( exttype == EXT_DEF || exttype == EXT_ABS || exttype == EXT_RES )
mf_readlong(li);
/* Skip relocation information. */
if ( exttype == EXT_REF32
|| exttype == EXT_REF16
|| exttype == EXT_REF8
// || exttype == EXT_DEXT32
// || exttype == EXT_DEXT16
// || exttype == EXT_DEXT8
// || exttype == EXT_RELREF32
|| exttype == EXT_RELREF26 )
{
SkipLong(mf_readlong(li));
}
/* Display size of common block. */
if ( exttype == EXT_COMMON )
{
mf_readlong(li);
SkipLong(mf_readlong(li));
}
}
break;
case HUNK_SYMBOL:
while ( true )
{
if ( qltell(li) >= fsize )
goto TRUNCATED_INPUT;
Data = mf_readlong(li);
if ( Data == 0 )
break;
read_name(li, NameString, sizeof(NameString), Data & 0xFFFFFF);
mf_readlong(li);
}
break;
case HUNK_DEBUG:
SkipLong(mf_readlong(li));
break;
case HUNK_END:
break;
case HUNK_HEADER:
{
has_header = true;
while ( true )
{
if ( qltell(li) >= fsize )
goto TRUNCATED_INPUT;
Data = mf_readlong(li);
if ( Data == 0 )
break;
read_name(li, NameString, sizeof(NameString), Data);
}
mf_readlong(li);
int32 From = mf_readlong(li);
int32 To = mf_readlong(li);
SkipLong(To-From+1);
}
break;
case HUNK_OVERLAY:
{
int32 TabSize = mf_readlong(li);
if ( TabSize )
{
mf_readlong(li);
SkipLong(TabSize);
}
int32 hunktype = mf_readlong(li);
if ( TabSize && hunktype >= HUNK_UNIT && hunktype <= HUNK_ABSRELOC16 )
qlseek(li, -4, SEEK_CUR);
}
break;
case HUNK_BREAK:
break;
default:
warning("Unknown hunk type %04X - Aborting!", Type & 0xFFFF);
return;
}
}
//
// The second pass
//
qlseek(li, 0);
int nseg = 0;
while ( true )
{
i = (uint32)qlread(li, &Type, sizeof(Type));
if ( i != sizeof(Type) )
break;
Type = swap32(Type);
if ( Type == HUNK_DREL32 && has_header )
Type = HUNK_DREL32EXE;
switch ( Type & 0xFFFF )
{
case HUNK_UNIT:
read_name(li, NameString, sizeof(NameString), mf_readlong(li));
add_pgm_cmt("Unit: %s", NameString);
break;
case HUNK_NAME:
read_name(li, NameString, sizeof(NameString), mf_readlong(li));
add_pgm_cmt("Title: %s", NameString);
break;
case HUNK_LIB:
mf_readlong(li);
break;
case HUNK_INDEX:
SkipLong(mf_readlong(li));
break;
case HUNK_CODE:
case HUNK_PPC_CODE:
case HUNK_DATA:
case HUNK_BSS:
Data = mf_readlong(li);
Data <<= 2;
Data &= 0x7FFFFFFF;
if ( (Type & 0xFFFF) != HUNK_BSS )
SkipByte(Data);
nseg++;
break;
case HUNK_RELOC32SHORT:
case HUNK_DREL32EXE:
shortreloc = true;
// no break
case HUNK_RELRELOC32:
case HUNK_ABSRELOC16:
case HUNK_RELRELOC26:
case HUNK_RELOC32:
case HUNK_RELOC16:
case HUNK_RELOC8:
case HUNK_DREL32:
case HUNK_DREL16:
case HUNK_DREL8:
nums = 0;
while ( (Data=(shortreloc ? mf_readshort(li) : mf_readlong(li))) != 0 )
{
uint32 dat2 = shortreloc ? mf_readshort(li) : mf_readlong(li);
segment_t *s = get_segm_by_sel(dat2+1);
segment_t *ssrc = get_segm_by_sel(nseg);
ea_t base = BADADDR;
if ( ssrc != NULL )
base = ssrc->start_ea;
else
s = NULL;
int elsize = shortreloc ? 2 : 4;
validate_array_count_or_die(li, Data, elsize, "Number of relocations");
for ( uint32 dat3 = Data; dat3; --dat3 )
{
uint32 off = shortreloc ? mf_readshort(li) : mf_readlong(li);
if ( s != NULL )
{
ea_t src = base + off;
ea_t dst = s->start_ea;
ea_t target = BADADDR;
fixup_type_t fd_type = 0;
switch ( Type & 0xFFFF )
{
case HUNK_RELRELOC32:
case HUNK_RELOC32:
case HUNK_DREL32:
case HUNK_RELOC32SHORT:
case HUNK_DREL32EXE:
target = get_dword(src)+dst;
put_dword(src, target);
fd_type = FIXUP_OFF32;
break;
case HUNK_ABSRELOC16:
case HUNK_RELRELOC26:
case HUNK_RELOC16:
case HUNK_DREL16:
target = get_word(src)+dst;
put_word(src, target);
fd_type = FIXUP_OFF16;
break;
case HUNK_RELOC8:
case HUNK_DREL8:
target = get_byte(src)+dst;
put_byte(src, (uint32)target);
fd_type = FIXUP_OFF8;
break;
}
if ( fd_type != 0 )
{
fixup_data_t fd(fd_type);
fd.sel = dat2 + 1;
fd.off = target;
fd.set(src);
}
}
else
{
ask_for_help();
}
}
nums += Data;
}
if ( (nums & 1) == 0 && shortreloc )
SkipWord(1);
shortreloc = false;
break;
case HUNK_EXT:
ask_for_help();
while ( (Data=mf_readlong(li)) != 0 )
{
switch ( (Data >> 24) & 0xFF )
{
case EXT_DEF: msg(" EXT_DEF"); break;
case EXT_ABS: msg(" EXT_ABS"); break;
case EXT_RES: msg(" EXT_RES"); break;
case EXT_REF32: msg(" EXT_REF32"); break;
case EXT_COMMON: msg(" EXT_COMMON"); break;
case EXT_REF16: msg(" EXT_REF16"); break;
case EXT_REF8: msg(" EXT_REF8"); break;
// case EXT_DEXT32: msg(" EXT_DEXT32"); break;
// case EXT_DEXT16: msg(" EXT_DEXT16"); break;
// case EXT_DEXT8: msg(" EXT_DEXT8"); break;
// case EXT_RELREF32: msg(" EXT_RELREF32"); break;
// case EXT_RELREF26: msg(" EXT_RELREF26"); break;
// case EXT_RELCOMMON: msg(" EXT_RELCOMMON"); break;
default: msg(" EXT_??? (%02x)\n",(Data >> 24) & 0xFF); break;
}
/* Is it followed by a symbol name? */
if ( Data & 0xFFFFFF )
{
read_name(li, NameString, sizeof(NameString), Data & 0xFFFFFF);
msg(" %s", NameString);
}
/* Remember extension type. */
int32 exttype = (Data >> 24) & 0xFF;
/* Display value of symbol. */
if ( exttype == EXT_DEF || exttype == EXT_ABS || exttype == EXT_RES )
{
if ( !(Data & 0xFFFFFF) )
msg(" ???");
Data = mf_readlong(li);
msg("%08X", Data);
}
/* Skip relocation information. */
if ( exttype == EXT_REF32
|| exttype == EXT_REF16
|| exttype == EXT_REF8
// || exttype == EXT_DEXT32
// || exttype == EXT_DEXT16
// || exttype == EXT_DEXT8
// || exttype == EXT_RELREF32
|| exttype == EXT_RELREF26 )
{
Data = mf_readlong(li);
msg("= %u entr%s", Data, Data == 1 ? "y" : "ies");
SkipLong(Data);
}
/* Display size of common block. */
if ( exttype == EXT_COMMON )
{
Data = mf_readlong(li);
msg(" Size = %u bytes", Data << 2);
Data = mf_readlong(li);
SkipLong(Data);
}
msg("\n");
}
break;
case HUNK_SYMBOL:
while ( (Data=mf_readlong(li)) != 0 )
{
/* Display name. */
read_name(li, NameString, sizeof(NameString), Data & 0xFFFFFF);
/* Display value. */
Data = mf_readlong(li);
segment_t *ssrc = get_segm_by_sel(nseg);
if ( ssrc == NULL )
ask_for_help();
else
set_name(ssrc->start_ea+Data, NameString, SN_NOCHECK | SN_NOWARN | SN_IDBENC);
}
break;
case HUNK_DEBUG:
SkipLong(mf_readlong(li));
break;
case HUNK_END:
break;
case HUNK_HEADER:
{
has_header = true;
while ( (Data=mf_readlong(li)) != 0 )
read_name(li, NameString, sizeof(NameString), Data);
mf_readlong(li);
int32 From = mf_readlong(li);
int32 To = mf_readlong(li);
SkipLong(To-From+1);
}
break;
case HUNK_OVERLAY:
{
int32 TabSize = mf_readlong(li);
if ( TabSize )
{
mf_readlong(li);
SkipLong(TabSize);
}
int32 hunktype = mf_readlong(li);
if ( TabSize && hunktype >= HUNK_UNIT && hunktype <= HUNK_ABSRELOC16 )
qlseek(li, -4, SEEK_CUR);
}
break;
case HUNK_BREAK:
break;
default:
warning("Unknown hunk type %04X - Aborting!", Type & 0xFFFF);
return;
}
}
create_filename_cmt();
}
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
qlseek(li, 0);
uint32 type;
if ( qlread(li, &type, sizeof(uint32)) == sizeof(uint32)
&& swap32(type) == HUNK_HEADER )
{
*fileformatname = "Amiga hunk file";
*processor = "68040";
return 1;
}
return 0;
}
//--------------------------------------------------------------------------
int idaapi move_segm_relocs(ea_t from, ea_t to, asize_t size, const char *fileformatname)
{
qnotused(size);
qnotused(fileformatname);
if ( from == BADADDR )
{
// The entire program is being rebased.
// In this case, 'to' actually contains a delta value; the number of bytes
// forward (positive) or backward (negative) that the whole database is
// being moved.
ea_t delta = to;
// fix up relocations
fixup_data_t fd;
for ( ea_t xEA = get_first_fixup_ea(); xEA != BADADDR; xEA = get_next_fixup_ea(xEA) )
{
show_addr(xEA);
get_fixup(&fd, xEA);
fd.off += delta;
switch ( fd.get_type() )
{
case FIXUP_OFF8:
put_byte(xEA, fd.off);
break;
case FIXUP_OFF16:
put_word(xEA, fd.off);
break;
case FIXUP_OFF32:
put_dword(xEA, fd.off);
break;
}
set_fixup(xEA, fd);
}
// Record the new image base address.
inf_set_baseaddr(inf_get_baseaddr() + delta);
// set_imagebase(new_base);
}
return 1;
}
//--------------------------------------------------------------------------
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)
move_segm_relocs,
NULL,
};

View File

@@ -0,0 +1,59 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2000 by Ilfak Guilfanov, <ig@datarescue.com>
* ALL RIGHTS RESERVED.
*
*/
//
// AMIGA hunk files
//
#ifndef AMIGA_HPP
#define AMIGA_HPP
#define HUNK_UNIT 999
#define HUNK_NAME 1000
#define HUNK_CODE 1001
#define HUNK_DATA 1002
#define HUNK_BSS 1003
#define HUNK_RELOC32 1004
#define HUNK_RELOC16 1005
#define HUNK_RELOC8 1006
#define HUNK_EXT 1007
#define HUNK_SYMBOL 1008
#define HUNK_DEBUG 1009
#define HUNK_END 1010
#define HUNK_HEADER 1011
#define HUNK_UNUSED 1012 // unused hunk number?
#define HUNK_OVERLAY 1013
#define HUNK_BREAK 1014
#define HUNK_DREL32 1015
#define HUNK_DREL16 1016
#define HUNK_DREL8 1017
#define HUNK_LIB 1018
#define HUNK_INDEX 1019
#define HUNK_RELOC32SHORT 1020
#define HUNK_RELRELOC32 1021
#define HUNK_ABSRELOC16 1022
#define HUNK_DREL32EXE 1023
#define HUNK_PPC_CODE 1257
#define HUNK_RELRELOC26 1260
#define EXT_RELREF26 229
// i don't know the values! (these symbols are used with HUNK_CODE, _DATA, _BSS)
#define HUNKF_CHIP 0x00000000
#define HUNKF_FAST 0x00000000
#define HUNKF_ADVISORY 0x00000000
#define EXT_SYMB 0
#define EXT_DEF 1
#define EXT_ABS 2
#define EXT_RES 3
#define EXT_REF32 129
#define EXT_COMMON 130
#define EXT_REF16 131
#define EXT_REF8 132
#endif // AMIGA_HPP

View File

@@ -0,0 +1,13 @@
PROC=amiga
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)amiga$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h amiga.cpp amiga.hpp

724
idasdk76/ldr/aof/aof.cpp Normal file
View File

@@ -0,0 +1,724 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-97 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
* ARM Object File Loader
* ----------------------
* This module allows IDA to load ARM object files into
* its database and to disassemble them correctly.
*
* NOTE 1: for the moment only B/BL instruction relocations are
* supported. I cannot find other relocation examples so
* they are not implemented yet.
*
* NOTE 2: Thumb modules are not supported.
*
* This module automatically detects the byte sex and sets inf.mf
* variable accrodingly.
*
*
*/
#include "../idaldr.h"
#include "aof.h"
//--------------------------------------------------------------------------
NORETURN static void nomem(void)
{
nomem("AOF loader");
}
//--------------------------------------------------------------------------
static void *read_chunk(linput_t *li, const chunk_entry_t &ce)
{
void *chunk = qalloc_array<char>(ce.size);
if ( chunk == NULL )
nomem();
qlseek(li, ce.file_offset);
lread(li, chunk, ce.size);
return chunk;
}
//--------------------------------------------------------------------------
static void check_chunk_ptr(
const chunk_entry_t &ce,
const void *chunkstart,
const void *chunkptr,
size_t ptrsize)
{
const char *p0 = (const char*)chunkstart;
const char *p1 = (const char*)chunkptr;
if ( p1 < p0 || p1 + ptrsize < p0 || (p1 + ptrsize - p0) > ce.size )
loader_failure("Corrupted file");
}
//--------------------------------------------------------------------------
static void check_chunk_str(
const chunk_entry_t &ce,
const void *chunkstart,
const void *chunkptr)
{
const char *p0 = (const char*)chunkstart;
const char *p1 = (const char*)chunkptr;
if ( p1 >= p0 )
{
const char *chunk_end = p0 + ce.size;
while ( p1 < chunk_end )
{
if ( *p1 == '\0' )
return;
++p1;
}
}
loader_failure("Corrupted file");
}
//--------------------------------------------------------------------------
//
// 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 *)
{
chunk_header_t hd;
if ( qlread(li, &hd, sizeof(hd)) != sizeof(hd) )
return 0;
if ( hd.ChunkFileId != AOF_MAGIC && hd.ChunkFileId != AOF_MAGIC_B )
return 0;
if ( hd.num_chunks > hd.max_chunks )
return 0;
*fileformatname = "ARM Object File";
*processor = "arm";
return 1;
}
//--------------------------------------------------------------------------
static void create32(
sel_t sel,
ea_t start_ea,
ea_t end_ea,
const char *name,
const char *classname)
{
set_selector(sel, 0);
segment_t s;
s.sel = sel;
s.start_ea = start_ea;
s.end_ea = end_ea;
s.align = saRelByte;
s.comb = scPub;
s.bitness = 1; // 32-bit
if ( !add_segm_ex(&s, name, classname, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure();
}
//--------------------------------------------------------------------------
static ea_t get_area_base(int idx)
{
segment_t *s = get_segm_by_sel(idx+1);
if ( s == NULL )
return BADADDR;
return s->start_ea;
}
//--------------------------------------------------------------------------
static ea_t find_area(
const chunk_entry_t &ce,
const area_header_t *ah,
int maxarea,
const char *strings,
const char *areaname)
{
for ( int i=0; i < maxarea; i++, ah++ )
{
const char *name = strings + size_t(ah->name);
check_chunk_str(ce, strings, name);
if ( streq(name, areaname) )
return get_area_base(i);
}
return BADADDR;
}
//--------------------------------------------------------------------------
static ea_t create_spec_seg(
int *nsegs,
int nelem,
const char *name,
uchar seg_type)
{
ea_t ea = BADADDR;
if ( nelem != 0 )
{
nelem *= 4;
ea = free_chunk(inf_get_max_ea(), nelem, 0xFFF);
(*nsegs)++;
create32(*nsegs, ea, ea+nelem, name, CLASS_DATA);
segment_t *s = getseg(ea);
s->type = seg_type;
s->update();
set_arm_segm_flags(s->start_ea, 2 << SEGFL_SHIFT); // alignment
}
return ea;
}
//--------------------------------------------------------------------------
static void process_name(ea_t ea, const char *name, uint32 flags, bool iscode)
{
// ignore aux names -- they hinder data creation
if ( strstr(name, "$litpool_e$") != NULL )
return;
if ( flags & SF_PUB )
{
add_entry(ea, ea, name, iscode, AEF_IDBENC);
make_name_public(ea);
}
else
{
force_name(ea, name, SN_IDBENC);
}
if ( flags & SF_WEAK )
make_name_weak(ea);
if ( flags & SF_ICASE )
add_extra_cmt(ea, true, "Case-insensitive label");
if ( flags & SF_STRNG )
add_extra_cmt(ea, true, "Strong name");
}
//--------------------------------------------------------------------------
static void reloc_insn(ea_t ea, uint32 rvalue, uint32 type)
{
uint32 code = get_dword(ea);
switch ( (code >> 24) & 0xF )
{
case 0x0A: // B
case 0x0B: // BL
{
int32 off = code & 0x00FFFFFFL;
if ( off & 0x00800000L )
off |= ~0x00FFFFFFL; // extend sign
off <<= 2;
off += rvalue;
off >>= 2;
off &= 0xFFFFFFL;
code &= 0xFF000000L;
code |= off;
put_dword(ea, code);
}
break;
default:
warning("This relocation type is not implemented yet\n"
"\3%a: reloc insn rvalue=%x, rt=%lx", ea, rvalue,
type & RF_II);
break;
}
}
//--------------------------------------------------------------------------
inline void swap_chunk_entry(chunk_entry_t *ce)
{
ce->file_offset = swap32(ce->file_offset);
ce->size = swap32(ce->size);
}
//--------------------------------------------------------------------------
static void swap_aof_header(aof_header_t *ahd)
{
ahd->obj_file_type = swap32(ahd->obj_file_type);
ahd->version = swap32(ahd->version);
ahd->num_areas = swap32(ahd->num_areas);
ahd->num_syms = swap32(ahd->num_syms);
ahd->entry_area = swap32(ahd->entry_area);
ahd->entry_offset = swap32(ahd->entry_offset);
}
//--------------------------------------------------------------------------
static void swap_area_header(area_header_t *ah)
{
ah->name = swap32(ah->name);
ah->flags = swap32(ah->flags);
ah->size = swap32(ah->size);
ah->num_relocs = swap32(ah->num_relocs);
ah->baseaddr = swap32(ah->baseaddr);
}
//--------------------------------------------------------------------------
static void swap_sym(sym_t *s)
{
s->name = swap32(s->name);
s->flags = swap32(s->flags);
s->value = swap32(s->value);
s->area = swap32(s->area);
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
int i;
chunk_header_t hd;
set_processor_type("arm", SETPROC_LOADER);
lread(li, &hd, sizeof(hd));
if ( hd.ChunkFileId == AOF_MAGIC_B ) // BIG ENDIAN
{
inf_set_be(true);
hd.max_chunks = swap32(hd.max_chunks);
hd.num_chunks = swap32(hd.num_chunks);
}
validate_array_count_or_die(li, hd.max_chunks, sizeof(chunk_entry_t), "Number of chunks");
chunk_entry_t *ce = qalloc_array<chunk_entry_t>(size_t(hd.max_chunks));
if ( ce == NULL )
nomem();
lread(li, ce, sizeof(chunk_entry_t)*size_t(hd.max_chunks));
if ( inf_is_be() )
for ( i=0; i < hd.max_chunks; i++ )
swap_chunk_entry(ce+i);
int head = -1; // AOF Header
int area = -1; // Areas
int idfn = -1; // Identification
int symt = -1; // Symbol Table
int strt = -1; // String Table
for ( i=0; i < hd.max_chunks; i++ )
{
if ( ce[i].file_offset == 0 )
continue;
if ( strneq(ce[i].chunkId, OBJ_HEAD, sizeof(ce[i].chunkId)) )
head = i;
if ( strneq(ce[i].chunkId, OBJ_AREA, sizeof(ce[i].chunkId)) )
area = i;
if ( strneq(ce[i].chunkId, OBJ_IDFN, sizeof(ce[i].chunkId)) )
idfn = i;
if ( strneq(ce[i].chunkId, OBJ_SYMT, sizeof(ce[i].chunkId)) )
symt = i;
if ( strneq(ce[i].chunkId, OBJ_STRT, sizeof(ce[i].chunkId)) )
strt = i;
}
if ( head == -1 || area == -1 || strt == -1 || symt == -1 || idfn == -1 )
{
qfree(ce);
loader_failure("One of required chunks is missing");
}
char *strings = (char *)read_chunk(li, ce[strt]);
aof_header_t *ahd = (aof_header_t *)read_chunk(li, ce[head]);
check_chunk_ptr(ce[head], ahd, ahd, sizeof(aof_header_t));
if ( inf_is_be() )
swap_aof_header(ahd);
//
// Areas
//
area_header_t *ah = (area_header_t *)(ahd + 1);
if ( inf_is_be() )
{
for ( i=0; i < ahd->num_areas; i++ )
{
check_chunk_ptr(ce[head], ahd, ah+i, sizeof(area_header_t));
swap_area_header(ah+i);
}
}
qoff64_t offset = ce[area].file_offset;
inf_set_specsegs(inf_is_64bit() ? 8 : 4);
ea_t ea = to_ea(inf_get_baseaddr(), 0);
for ( i=0; i < ahd->num_areas; i++, ah++ )
{
check_chunk_ptr(ce[head], ahd, ah, sizeof(area_header_t));
if ( ah->flags & AREA_DEBUG )
{
offset += ah->size;
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
continue;
}
if ( ah->flags & AREA_ABS )
{
ea = ah->baseaddr;
if ( free_chunk(ea, ah->size, 1) != ea )
error("Cannot allocate area at %a", ea);
}
else
{
ea = free_chunk(ea, ah->size, 0xFFF);
}
if ( (ah->flags & AREA_BSS) == 0 )
{
ea_t end = ea + ah->size;
uint64 fsize = qlsize(li);
if ( offset > fsize
|| fsize-offset < ah->size
|| end < ea )
{
loader_failure("Corrupted file");
}
file2base(li, offset, ea, end, FILEREG_PATCHABLE);
offset += ah->size;
}
const char *name = strings + size_t(ah->name);
check_chunk_str(ce[strt], strings, name);
const char *classname;
if ( ah->flags & AREA_CODE )
classname = CLASS_CODE;
else if ( ah->flags & (AREA_BSS|AREA_COMREF) )
classname = CLASS_BSS;
else
classname = CLASS_DATA;
create32(i+1, ea, ea+ah->size, name, classname);
segment_t *s = getseg(ea);
ushort sflags = (ah->flags & 0x1F) << SEGFL_SHIFT; // alignment
if ( ah->flags & AREA_BASED )
sflags |= (SEGFL_BASED|ah->get_based_reg());
if ( ah->flags & AREA_PIC )
sflags |= SEGFL_PIC;
if ( ah->flags & AREA_REENTR )
sflags |= SEGFL_REENTR;
if ( ah->flags & AREA_HALFW )
sflags |= SEGFL_HALFW;
if ( ah->flags & AREA_INTER )
sflags |= SEGFL_INTER;
if ( ah->flags & AREA_COMMON )
sflags |= SEGFL_COMDEF;
if ( ah->flags & (AREA_COMMON|AREA_COMREF) )
s->comb = scCommon;
if ( ah->flags & AREA_RDONLY )
s->perm = SEGPERM_READ;
if ( ah->flags & AREA_ABS )
s->align = saAbs;
s->update();
set_arm_segm_flags(s->start_ea, sflags);
if ( i == 0 )
{
create_filename_cmt();
char *id = (char *)read_chunk(li, ce[idfn]);
check_chunk_str(ce[idfn], id, id);
add_pgm_cmt("Translator : %s", id);
qfree(id);
}
if ( ah->flags & AREA_CODE )
{
if ( (ah->flags & AREA_32BIT) == 0 )
add_pgm_cmt("The 26-bit area");
if ( (ah->flags & AREA_EXTFP) != 0 )
add_pgm_cmt("Extended FP instructions are used");
if ( (ah->flags & AREA_NOCHK) != 0 )
add_pgm_cmt("No Software Stack Check");
if ( (ah->flags & AREA_THUMB) != 0 )
add_pgm_cmt("Thumb code area");
}
else
{
if ( (ah->flags & AREA_SHARED) != 0 )
add_pgm_cmt("Shared Library Stub Data");
}
ea += ah->size;
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
}
int nsegs = i;
//
// Symbol Table
//
ah = (area_header_t *)(ahd + 1);
uint32 *delta = qalloc_array<uint32>(size_t(ahd->num_syms));
if ( delta == NULL )
nomem();
memset(delta, 0, sizeof(uint32)*size_t(ahd->num_syms));
sym_t *syms = (sym_t *)read_chunk(li, ce[symt]);
if ( inf_is_be() )
{
for ( i=0; i < ahd->num_syms; i++ )
{
check_chunk_ptr(ce[symt], syms, syms+i, sizeof(sym_t));
swap_sym(syms+i);
}
}
int n_undef = 0;
int n_abs = 0;
int n_comm = 0;
for ( i=0; i < ahd->num_syms; i++ )
{
sym_t *s = syms + i;
check_chunk_ptr(ce[symt], syms, syms+i, sizeof(sym_t));
if ( s->flags & SF_DEF )
{
if ( s->flags & SF_ABS )
{
n_abs++;
}
else
{
const char *areaname = strings + size_t(s->area);
check_chunk_str(ce[strt], strings, areaname);
ea_t areabase = find_area(ce[strt], ah, size_t(ahd->num_areas), strings, areaname);
delta[i] = (uint32)areabase;
ea_t symea = areabase + s->value;
const char *name = strings + size_t(s->name);
check_chunk_str(ce[strt], strings, name);
if ( s->value == 0 && strcmp(areaname, name) == 0 )
continue; // HACK!
process_name(symea, name, s->flags, segtype(areabase) == SEG_CODE);
}
}
else
{
if ( (s->flags & SF_PUB) && (s->flags & SF_COMM) ) // ref to common
n_comm++;
else
n_undef++;
}
}
ea_t abs_ea = create_spec_seg(&nsegs, n_abs, NAME_ABS, SEG_ABSSYM);
ea_t undef_ea = create_spec_seg(&nsegs, n_undef, NAME_UNDEF, SEG_XTRN);
ea_t comm_ea = create_spec_seg(&nsegs, n_comm, NAME_COMMON, SEG_COMM);
if ( n_abs+n_undef+n_comm != 0 )
{
for ( i=0; i < ahd->num_syms; i++ )
{
sym_t *s = syms + i;
const char *name = strings + size_t(s->name);
check_chunk_str(ce[strt], strings, name);
if ( s->flags & SF_DEF )
{
if ( s->flags & SF_ABS )
{
if ( inf_get_specsegs() == 8 )
{
put_qword(abs_ea, s->value);
create_qword(abs_ea, 8);
}
else
{
put_dword(abs_ea, s->value);
create_dword(abs_ea, 4);
}
process_name(abs_ea, name, s->flags, false);
delta[i] = s->value;
s->value = uint32(abs_ea - delta[i]);
abs_ea += inf_get_specsegs();
}
}
else
{
if ( (s->flags & SF_PUB) && (s->flags & SF_COMM) ) // ref to common
{
if ( inf_get_specsegs() == 8 )
put_qword(comm_ea, s->value);
else
put_dword(comm_ea, s->value);
process_name(comm_ea, name, s->flags, false);
delta[i] = (uint32)comm_ea;
comm_ea += inf_get_specsegs();
}
else
{
put_dword(undef_ea, 0xE1A0F00E); // RET
process_name(undef_ea, name, s->flags, false);
delta[i] = (uint32)undef_ea;
undef_ea += inf_get_specsegs();
}
s->value = 0;
}
}
}
//
// Relocations
//
offset = ce[area].file_offset;
for ( i=0; i < ahd->num_areas; i++, ah++ )
{
if ( ah->flags & AREA_DEBUG )
{
offset += ah->size;
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
continue;
}
if ( (ah->flags & AREA_BSS) == 0 )
offset += ah->size;
qlseek(li, offset);
ea_t base = get_area_base(i);
validate_array_count(li, &ah->num_relocs, sizeof(reloc_t), "Number of relocs", offset);
for ( int j=0; j < ah->num_relocs; j++ )
{
reloc_t r;
lread(li, &r, sizeof(reloc_t));
if ( inf_is_be() )
{
r.type = swap32(r.type);
r.offset = swap32(r.offset);
}
size_t sid = r.sid();
ea_t rvalue;
ea_t target;
fixup_data_t fd;
if ( r.type & RF_A )
{
if ( sid >= ahd->num_syms )
loader_failure("Bad relocation record at file offset %" FMT_64 "x", qltell(li)-sizeof(reloc_t));
rvalue = delta[sid];
target = syms[sid].value + rvalue;
fd.set_extdef();
}
else
{
rvalue = get_area_base((int)sid);
target = rvalue;
if ( rvalue == BADADDR )
loader_failure("Bad reference to area %" FMT_Z " at file offset %" FMT_64 "x", sid, qltell(li)-sizeof(reloc_t));
}
segment_t *s = getseg(target);
if ( s == NULL )
loader_failure("Can't find area for relocation target %a at %" FMT_64 "x", target, qltell(li)-sizeof(reloc_t));
fd.sel = s->sel;
fd.off = target - get_segm_base(s);
if ( (r.type & RF_R) != 0 )
{
if ( (r.type & RF_A) != 0 )
{
// R=1 B=0 or R=1 B=1
// This specifies PC-relative relocation: to the subject field
// is added the difference between the relocation value and
// the base of the area containing the subject field.
// In pseudo C:
// subject_field = subject_field +
// (relocation_value -
// base_of_area_containing(subject_field))
rvalue -= base;
}
else
{
//
// As a special case, if A is 0, and the relocation value is
// specified as the base of the area containing the subject
// field, it is not added and:
// subject_field = subject_field -
// base_of_area_containing(subject_field)
// This caters for relocatable PC-relative branches to fixed
// target addresses. If R is 1, B is usually 0. A B value of 1
// is used to denote that the inter-link-unit value of a
// branch destination is to be used, rather than the more
// usual intra-link-unit value.
rvalue = -base;
}
}
else
{
if ( (r.type & RF_B) != 0 )
{ // R=0 B=1
// This specifies based area relocation. The relocation value
// must be an address within a based data area. The subject
// field is incremented by the difference between this value
// and the base address of the consolidated based area group
// (the linker consolidates all areas based on the same base
// register into a single, contiguous region of the output
// image). In pseudo C:
// subject_field = subject_field +
// (relocation_value -
// base_of_area_group_containing(relocation_value))
// For example, when generating re-entrant code, the C
// compiler places address constants in an adcon area based
// on register sb, and loads them using sb relative LDRs.
// At link time, separate adcon areas will be merged and sb
// will no longer point where presumed at compile time. B
// type relocation of the LDR instructions corrects for this.
rvalue -= get_area_base((int)sid);
}
else
{ // R=0 B=0
// This specifies plain additive relocation: the relocation
// value is added to the subject field. In pseudo C:
// subject_field = subject_field + relocation_value
/* nothing to do */;
}
}
ea_t relea = base + r.offset;
switch ( r.type & RF_FT )
{
case RF_FT_BYTE: // 00 the field to be relocated is a byte
fd.set_type(FIXUP_OFF8);
fd.displacement = get_byte(relea);
add_byte(relea, (uint32)rvalue);
break;
case RF_FT_HALF: // 01 the field to be relocated is a halfword (two bytes)
fd.set_type(FIXUP_OFF16);
fd.displacement = get_word(relea);
add_word(relea, rvalue);
break;
case RF_FT_WORD: // 10 the field to be relocated is a word (four bytes)
fd.set_type(FIXUP_OFF32);
fd.displacement = get_dword(relea);
add_dword(relea, rvalue);
break;
case RF_FT_INSN: // 11 the field to be relocated is an instruction or instruction sequence
reloc_insn(relea, (uint32)rvalue, r.type);
break;
}
fd.set(relea);
}
offset += qoff64_t(ah->num_relocs) * sizeof(reloc_t);
}
if ( ahd->entry_area != 0 )
{
inf_set_start_cs(ahd->entry_area);
inf_set_start_ip(ahd->entry_offset);
inf_set_start_ea(ahd->entry_offset);
}
qfree(syms);
qfree(delta);
qfree(ahd);
qfree(strings);
qfree(ce);
inf_set_baseaddr(0);
}
//----------------------------------------------------------------------
//
// 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,
};

246
idasdk76/ldr/aof/aof.h Normal file
View File

@@ -0,0 +1,246 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-97 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
* ARM Object File Loader
*
*/
#ifndef __AOF_H__
#define __AOF_H__
//-------------------------------------------------------------------------
struct chunk_header_t
{
uint32 ChunkFileId;
#define AOF_MAGIC 0xC3CBC6C5L // magic value of chunk file
#define AOF_MAGIC_B 0xC5C6CBC3L // magic value of chunk file (big endian)
uint32 max_chunks; // defines the number of the entries in the
// header, fixed when the file is created.
uint32 num_chunks; // defines how many chunks are currently used in
// the file, which can vary from 0 to maxChunks.
// It is redundant in that it can be found by scanning
// the entries.
};
//-------------------------------------------------------------------------
struct chunk_entry_t
{
char chunkId[8]; // an 8-byte field identifying what data the chunk
// contains. Note that this is an 8-byte field, not
// a 2-word field, so it has the same byte order
// independent of endianness.
#define OBJ_HEAD "OBJ_HEAD" // AOF Header
#define OBJ_AREA "OBJ_AREA" // Areas
#define OBJ_IDFN "OBJ_IDFN" // Identification
#define OBJ_SYMT "OBJ_SYMT" // Symbol Table
#define OBJ_STRT "OBJ_STRT" // String Table
uint32 file_offset; // a one-word field defining the byte offset within
// the file of the start of the chunk. All chunks are
// word-aligned, so it must be divisible by four.
// A value of zero indicates that the chunk entry
// is unused.
uint32 size; // a one-word field defining the exact byte size
// of the chunk's contents (which need not be a
// multiple of four).
};
//-------------------------------------------------------------------------
struct aof_header_t
{
uint32 obj_file_type; // the value 0xC5E2D080 marks the file as being in
// relocatable object format (the usual output of
// compilers and assemblers and the usual input to
// the linker). The endianness of the object code
// can be deduced from this value and must be
// identical to the endianness of the containing
// chunk file.
#define OBJ_FILE_TYPE_MAGIC 0xC5E2D080L
uint32 version; // encodes the version of AOF with which the object
// file complies
// version 1.50 is denoted by decimal 150
// version 2.00 is denoted by decimal 200
// this version is denoted by decimal 310 (0x136)
uint32 num_areas; // Number of Areas
uint32 num_syms; // Number of Symbols
uint32 entry_area; // Entry Area Index. in the range 1 to Number of
// Areas, gives the 1-origin index in the following
// array of area headers of the area containing the
// entry point. The entry address is defined to be
// the base address of this area plus Entry Offset.
// A value of 0 for Entry Area Index signifies that
// no program entry address is defined by this AOF
// file.
uint32 entry_offset;
};
//-------------------------------------------------------------------------
struct area_header_t
{
uint32 name; // Area name (offset into string table)
uint32 flags; // Attributes + Alignment
// The least significant eight bits of this word
// encode the alignment of the start of the area as a
// power of 2 and must have a value between 2 and 32.
#define AREA_ABS 0x00000100L // The absolute attribute: denotes that the
// area must be placed at its Base Address.
// This bit is not usually set by language
// processors.
#define AREA_CODE 0x00000200L // CODE (otherwise DATA)
#define AREA_COMMON 0x00000400L // The area is a common definition.
#define AREA_COMREF 0x00000800L // The area is a reference to a common block:
// preclude the area having initializing data
// (see AREA_BSS). In effect, AREA_COMREF
// implies AREA_BSS.
// If both bits AREA_COMMON and AREA_COMREF
// are set, bit AREA_COMREF is ignored.
#define AREA_BSS 0x00001000L // Zero-initialized: the area has no
// initializing data in this object file,
// and that the area contents are missing from
// the OBJ_AREA chunk.
#define AREA_RDONLY 0x00002000L // Readonly area
#define AREA_PIC 0x00004000L // The position independent (PI) area
#define AREA_DEBUG 0x00008000L // The debugging table.
// CODE areas only:
#define AREA_32BIT 0x00010000L // 32-bit area (not 26bit)
#define AREA_REENTR 0x00020000L // The re-entrant area
#define AREA_EXTFP 0x00040000L // Extended floating-point instruction set
// is used in the area.
#define AREA_NOCHK 0x00080000L // No Software Stack Check
#define AREA_THUMB 0x00100000L // Thumb code area
#define AREA_HALFW 0x00200000L // Halfword instructions may be present
#define AREA_INTER 0x00400000L // Area has been compiled to be suitable for
// ARM/Thumb interworking.
// DATA areas only:
#define AREA_BASED 0x00100000L // Based area
inline int get_based_reg() { return int(flags >> 24) & 15; }
#define AREA_SHARED 0x00200000L // Shared Library Stub Data
uint32 size; // Area Size. Gives the size of the area in bytes,
// which must be a multiple of 4. Unless the
// "Not Initialised" bit (bit 12) is set in the area
// attributes, there must be this number of bytes
// for this area in the OBJ_AREA chunk.
// If the "Not Initialised" bit is set, there must be
// no initializing bytes for this area in the
// OBJ_AREA chunk.
uint32 num_relocs; // Number of Relocations. Specifies the number of
// relocation directives which apply to this area
// (which is equivalent to the number of relocation
// records following the area's contents in the
// OBJ_AREA chunk.
uint32 baseaddr; // Base Address or 0. Is unused unless the area has
// the absolute attribute. In this case, the field
// records the base address of the area. In general,
// giving an area a base address prior to linking
// will cause problems for the linker and may prevent
// linking altogether, unless only a single object
// file is involved.
};
//-------------------------------------------------------------------------
// segment flag bits in IDA for ARM module:
// the bits are kept in netnode().altval(seg_start_ea)
#ifdef _NETNODE_HPP
#define SEGFL_NETNODE_NAME "$ arm segflags"
#define SEGFL_BREG 0x000F
#define SEGFL_PIC 0x0010
#define SEGFL_REENTR 0x0020
#define SEGFL_HALFW 0x0040
#define SEGFL_INTER 0x0080
#define SEGFL_COMDEF 0x0100
#define SEGFL_BASED 0x0200
#define SEGFL_ALIGN 0x7C00
#define SEGFL_SHIFT 10
inline void set_arm_segm_flags(ea_t ea, ushort flags)
{
netnode n;
n.create(SEGFL_NETNODE_NAME);
n.altset_ea(ea, flags);
}
inline ushort get_arm_segm_flags(ea_t ea)
{
return (ushort)netnode(SEGFL_NETNODE_NAME).altval_ea(ea);
}
#endif
//-------------------------------------------------------------------------
struct reloc_t
{
uint32 offset;
uint32 type; // Low 24bits are SID
size_t sid(void) { return size_t(type & 0x00FFFFFFL); }
#define RF_II 0x60000000uL // if RF_FT == 11, then:
// 00 no constraint (the linker may modify as many contiguous instructions as it needs to)
// 01 the linker will modify at most 1 instruction
// 10 the linker will modify at most 2 instructions
// 11 the linker will modify at most 3 instructions
#define RF_B 0x10000000uL // Based
#define RF_A 0x08000000uL // 1: The subject field is relocated by the
// value of the symbol of which SID is the
// zero-origin index in the symbol table
// chunk.
// 0: The subject field is relocated by the
// base of the area of which SID is the
// zero-origin index in the array of areas,
// (or, equivalently, in the array of area
// headers).
#define RF_R 0x04000000uL // PC relative
#define RF_FT 0x03000000uL
#define RF_FT_BYTE 0x00000000uL // 00 the field to be relocated is a byte
#define RF_FT_HALF 0x01000000uL // 01 the field to be relocated is a halfword (two bytes)
#define RF_FT_WORD 0x02000000uL // 10 the field to be relocated is a word (four bytes)
#define RF_FT_INSN 0x03000000uL // 11 the field to be relocated is an instruction or instruction sequence
};
//-------------------------------------------------------------------------
struct sym_t
{
uint32 name; // Offset in the string table (in chunk OBJ_STRT) of
// the character string name of the symbol.
uint32 flags; // Attributes.
#define SF_DEF 0x00000001 // Symbol is defined in this file
#define SF_PUB 0x00000002 // Symbol has a global scope
#define SF_ABS 0x00000004 // Absolute attribute
#define SF_ICASE 0x00000008 // Case-insensitive attribute
#define SF_WEAK 0x00000010 // Weak attribute
#define SF_STRNG 0x00000020 // Strong attribute
#define SF_COMM 0x00000040 // Common attribute
// Code symbols only:
#define SF_CDATA 0x00000100 // Code area datum attribute
#define SF_FPREG 0x00000200 // FP args in FP regs attribute
#define SF_LEAF 0x00000800 // Simple leaf function attribute
#define SF_THUMB 0x00001000 // Thumb symbol
uint32 value; // is meaningful only if the symbol is a defining
// occurrence (bit 0 of Attributes set), or a common
// symbol (bit 6 of Attributes set):
// - if the symbol is absolute (bits 0-2 of
// Attributes set), this field contains the value
// of the symbol
// - if the symbol is a common symbol (bit 6 of
// Attributes set), this contains the byte length
// of the referenced common area
// - otherwise, value is interpreted as an offset
// from the base address of the area named by
// Area Name, which must be an area defined in
// this object file
uint32 area; // Area Name is meaningful only if the symbol is a
// non-absolute defining occurrence (bit 0 of
// Attributes set, bit 2 unset). In this case it
// gives the index into the string table for the name
// of the area in which the symbol is defined (which
// must be an area in this object file).
};
#endif

20
idasdk76/ldr/aof/makefile Normal file
View File

@@ -0,0 +1,20 @@
PROC=aof
include ../loader.mak
#----------------------------------------------------------------------
# the 'unlib' target must be called explicitly
.PHONY:
unlib: $(F)unlib$(B)
$(F)unlib$(B): $(call dumb_target, pro, $(F)unlib$(O))
# MAKEDEP dependency list ------------------
$(F)aof$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h aof.cpp aof.h
$(F)unlib$(O) : $(I)fpro.h $(I)llong.hpp $(I)pro.h aof.h unlib.cpp

199
idasdk76/ldr/aof/unlib.cpp Normal file
View File

@@ -0,0 +1,199 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-97 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
* ARM Object Librarian (Unpacker)
*
* This program unpacks a library. It extracts all the modules
* from the input library and puts them into separate files.
*
*/
#include <pro.h>
#include <fpro.h>
#include "aof.h"
#define LIB_DIRY "LIB_DIRY" // Directory
#define LIB_TIME "LIB_TIME" // Time stamp
#define LIB_VRSN "LIB_VRSN" // Version
#define LIB_DATA "LIB_DATA" // Data
#define OFL_SYMT "OFL_SYMT" // Symbol table
#define OFL_TIME "OFL_TIME" // Time stamp
static FILE *outfp = NULL;
static char outfile[QMAXPATH] = "";
static char infile[QMAXPATH] = "";
static char modname[MAXSTR] = "";
static int mf = 0;
//-----------------------------------------------------------------------
static void fatal(const char *format,...)
{
if ( infile[0] != '\0' && modname[0] != '\0' )
qeprintf("Fatal [%s] (%s): ",infile,modname);
va_list va;
va_start(va,format);
qveprintf(format,va);
va_end(va);
qeprintf("\n");
qfclose(outfp);
unlink(outfile);
// qeprintf("press enter to exit.\n");
// getchar();
qexit(1);
}
void warning(const char *format,...)
{
qeprintf("Warning [%s] (%s): ",infile,modname);
va_list va;
va_start(va,format);
qveprintf(format,va);
va_end(va);
qeprintf("\n");
}
static void nomem(const char *format,...)
{
char buf[512];
va_list va;
va_start(va,format);
qvsnprintf(buf, sizeof(buf), format, va);
va_end(va);
fatal("No memory: %s",buf);
}
//--------------------------------------------------------------------------
static void *read_chunk(FILE *fp, chunk_entry_t *ce, int32 i)
{
size_t idx = size_t(i);
void *chunk = qalloc_array<char>(ce[idx].size);
if ( chunk == NULL )
nomem("chunk size %d",size_t(ce[idx].size));
qfseek(fp,ce[idx].file_offset,SEEK_SET);
if ( qfread(fp,chunk,size_t(ce[idx].size)) != ce[idx].size )
fatal("Chunk read error: %s",strerror(errno));
return chunk;
}
//--------------------------------------------------------------------------
static uint32 swap(uint32 x)
{
union
{
uint32 l;
char c[4];
} u;
char chr;
u.l = x;
chr = u.c[3]; u.c[3] = u.c[0]; u.c[0] = chr;
chr = u.c[2]; u.c[2] = u.c[1]; u.c[1] = chr;
return u.l;
}
//--------------------------------------------------------------------------
inline void swap_chunk_entry(chunk_entry_t *ce)
{
ce->file_offset = swap(ce->file_offset);
ce->size = swap(ce->size);
}
//--------------------------------------------------------------------------
int main(int argc,char *argv[])
{
int i;
qeprintf("ARM Library unpacker. Copyright 1997 by Ilfak Guilfanov. Version 1.00\n");
if ( argc < 2 )
fatal("Usage: unlib libfile");
qstrncpy(infile, argv[1], sizeof(infile));
FILE *fp = qfopen(infile,"rb");
if ( fp == NULL )
fatal("Can't open library %s",infile);
chunk_header_t hd;
if ( qfread(fp, &hd, sizeof(hd)) != sizeof(hd)
|| (hd.ChunkFileId != AOF_MAGIC && hd.ChunkFileId != AOF_MAGIC_B) )
{
fatal("Bad library format");
}
if ( hd.ChunkFileId == AOF_MAGIC_B ) // BIG ENDIAN
{
mf = 1;
hd.max_chunks = swap(hd.max_chunks);
hd.num_chunks = swap(hd.num_chunks);
}
chunk_entry_t *ce = qalloc_array<chunk_entry_t>(hd.max_chunks);
if ( ce == NULL )
nomem("chunk entries (%d)",size_t(hd.max_chunks));
qfread(fp, ce, sizeof(chunk_entry_t)*size_t(hd.max_chunks));
if ( mf )
for ( i=0; i < hd.max_chunks; i++ )
swap_chunk_entry(ce+i);
int vrsn = -1;
int diry = -1;
int data = 0;
for ( i=0; i < hd.max_chunks; i++ )
{
if ( ce[i].file_offset == 0 )
continue;
if ( strncmp(ce[i].chunkId,LIB_DIRY,sizeof(ce[i].chunkId)) == 0 )
diry = i;
if ( strncmp(ce[i].chunkId,LIB_VRSN,sizeof(ce[i].chunkId)) == 0 )
vrsn = i;
if ( strncmp(ce[i].chunkId,LIB_DATA,sizeof(ce[i].chunkId)) == 0 )
data++;
}
if ( diry == -1 )
fatal("Can't find library directory!");
if ( data == 0 )
fatal("No modules in the library!");
if ( vrsn == -1 )
fatal("Can't determine library version!");
uint32 *version = (uint32 *)read_chunk(fp,ce,vrsn);
if ( mf )
*version = swap(*version);
if ( *version != 1 )
fatal("Wrong library version (%ld)",*version);
qfree(version);
uint32 *dir = (uint32 *)read_chunk(fp,ce,diry);
uint32 *end = dir + size_t(ce[diry].size/4);
while ( dir < end )
{
uint32 idx = *dir++;
/* uint32 elen = */ *dir++;
uint32 dlen = *dir++;
if ( mf )
{
idx = swap(idx);
dlen = swap(dlen);
}
if ( idx != 0 )
{
printf("%d. %s\n",idx,dir);
qstrncpy(modname,(char *)dir,sizeof(modname));
modname[sizeof(modname)-1] = '\0';
void *core = read_chunk(fp,ce,idx);
outfp = qfopen(modname,"wb");
if ( outfp == NULL )
{
warning("Can't open output file %s",modname);
}
else
{
qfwrite(outfp,core,size_t(ce[size_t(idx)].size));
qfclose(outfp);
}
qfree(core);
}
dir += size_t(dlen/4);
}
qfree(dir);
qfclose(fp);
return 0;
}

660
idasdk76/ldr/aout/aout.cpp Normal file
View File

@@ -0,0 +1,660 @@
/*
* This Loader Module is written by Yury Haron
*
*/
/*
L O A D E R for a.out (Linux)
*/
#include "../idaldr.h"
//#define DEBUG
#include "aout.h"
#include "common.cpp"
#include "../../module/sparc/notify_codes.hpp"
class aout_t
{
public:
exec ex;
nlist *symtab;
char *strtab;
uint32 symcount; // number of symbols in symtab
uint32 text; // first address of each section
uint32 data;
uint32 bss;
uint32 extrn;
uint32 top; // next available address
uint32 treloff; // file offset of each section
uint32 dreloff;
uint32 symoff;
uint32 stroff;
bool msb;
aout_t(void)
{
memset((void*) this, 0, sizeof(*this));
}
~aout_t()
{
if ( symtab != NULL )
{
qfree(symtab);
symtab = NULL;
}
if ( strtab != NULL )
{
qfree(strtab);
strtab = NULL;
}
}
};
//--------------------------------------------------------------------------
static const char *guess_processor(const exec &ex)
{
if ( N_MACHTYPE(ex) )
{
switch ( N_MACHTYPE(ex) )
{
case M_386:
case M_386_NETBSD:
return "metapc";
case M_ARM:
case M_ARM6_NETBSD:
return "arm";
case M_SPARC:
return "sparcb";
default:
break;
}
}
return NULL;
}
//--------------------------------------------------------------------------
//
// 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 *)
{
exec ex;
int i = get_aout_file_format_index(li, &ex);
#ifdef DEBUG
msg("getfmtindex=%d\n", i);
#endif
if ( i == 0 )
return 0;
static const char *const ff[] =
{
"demand-paged executable with NULL-ptr check", // q
"object or impure executable", // o
"demand-paged executable", // z
"core", // c
"pure executable", // n
"OpenBSD demand-paged executable", // zo
};
fileformatname->sprnt("a.out (%s)", ff[i-1]);
*processor = guess_processor(ex);
#ifdef DEBUG
msg("%s\n", fileformatname.c_str());
#endif
return f_AOUT;
}
//--------------------------------------------------------------------------
static void create32(
processor_t &ph,
ushort sel,
ea_t start_ea,
ea_t end_ea,
const char *name,
const char *classname)
{
set_selector(sel, 0);
if ( !add_segm(sel, start_ea, end_ea, name, classname, ADDSEG_SPARSE) )
loader_failure();
if ( ph.id == PLFM_386 )
set_segm_addressing(getseg(start_ea), 1);
}
//--------------------------------------------------------------------------
bool ana_hdr(processor_t &ph, linput_t *li, exec *_ex)
{
bool msb = false;
exec &ex = *_ex;
lread(li, &ex, sizeof(ex));
if ( N_BADMAG(ex) )
{
swap_exec(ex);
msb = true;
msg("Assuming big-endian...\n");
}
const char *proc = guess_processor(ex);
if ( proc != NULL )
{
set_processor_type(proc, SETPROC_LOADER);
if ( N_MACHTYPE(ex) == M_SPARC )
sparc_module_t::set_v8(true); // set SPARC_V8 parameter
}
else
{
if ( ask_yn(ASKBTN_YES,
"HIDECANCEL\n"
"AUTOHIDE REGISTRY\n"
"Missing machine type. Continue?") <= ASKBTN_NO )
{
loader_failure();
}
if ( ph.id == -1 )
set_processor_type(inf_get_procname().c_str(), SETPROC_LOADER);
}
return msb;
}
//--------------------------------------------------------------------------
inline fixup_type_t get_hi22_reltype()
{
static fixup_type_t hi22_reltype = FIXUP_CUSTOM;
if ( hi22_reltype == FIXUP_CUSTOM )
hi22_reltype = find_custom_fixup("HI22");
return hi22_reltype;
}
//--------------------------------------------------------------------------
inline fixup_type_t get_lo10_reltype()
{
static fixup_type_t lo10_reltype = FIXUP_CUSTOM;
if ( lo10_reltype == FIXUP_CUSTOM )
lo10_reltype = find_custom_fixup("LO10");
return lo10_reltype;
}
//--------------------------------------------------------------------------
static void do_fixup(uint32 where, uint32 delta, uint32 target, fixup_type_t type, int external)
{
fixup_data_t fd(type);
if ( external )
fd.set_extdef();
fd.displacement = delta;
if ( external )
target -= delta;
segment_t *s = getseg(target);
if ( s != NULL )
{
fd.sel = s->sel;
fd.off = target - get_segm_base(s);
}
else
{
fd.off = target;
}
fd.set(where);
}
#define S_MASK(x) ((1 << (x)) - 1)
//----------------------------------------------------------------------
static void do_relocation_sparc(
linput_t *li,
const aout_t &ctx,
uint32 off,
uint32 len,
int seg)
{
const segment_t *seg_p = getnseg(seg);
if ( seg_p == NULL )
{
msg("relocation data for missing segment %d ignored\n", seg);
return;
}
uint32 base = seg == 1 ? ctx.text : ctx.data;
#ifdef DEBUG
msg("seg %d base 0x%08X\n", seg, base);
#endif
// load relocation table
uint32 relcount = len / sizeof(reloc_info_sparc);
validate_array_count(li, &relcount, sizeof(reloc_info_sparc), "Relocation count", off);
if ( relcount == 0 )
return;
reloc_info_sparc *reltab = qalloc_array<reloc_info_sparc>(relcount);
if ( reltab == NULL )
loader_failure("Unable to allocate relocation table for %u entries\n", relcount);
qlseek(li, off);
for ( reloc_info_sparc *rel = reltab; rel < reltab + relcount; rel++ )
{
uint32 temp = 0;
lread4bytes(li, &rel->r_address, ctx.msb);
lread4bytes(li, &temp, ctx.msb);
lread4bytes(li, &rel->r_addend, ctx.msb);
rel->r_index = (temp >> 8) & 0x00FFFFFF;
rel->r_extern = (temp >> 7) & 1;
rel->r_type = (reloc_type_sparc) ((temp) & 0x1F);
#ifdef DEBUG
if ( rel->r_address >= 0x80C8 && rel->r_address <= 0x8200 )
msg("%08X: index=0x%06X extern=%d type=%02X addend=0x%08X\n",
rel->r_address, rel->r_index, rel->r_extern, rel->r_type, rel->r_addend);
#endif
}
// perform relocation
for ( reloc_info_sparc *rel = reltab; rel < reltab + relcount; rel++ )
{
uint32 where = base + rel->r_address;
uint32 instr = get_dword(where);
fixup_type_t type = FIXUP_OFF32;
uint32 target = where;
uint32 value;
uint32 merged;
#ifdef DEBUG
value = instr;
merged = instr;
#endif
if ( rel->r_extern )
{
if ( rel->r_index >= ctx.symcount )
{
msg("%08X: relocation to extern symbol idx %08X out of bounds, ignored\n", where, rel->r_index);
continue;
}
nlist *sym = &ctx.symtab[rel->r_index];
// The in-database address for this symbol was set when loading the symtab.
target = sym->n_value;
target += rel->r_addend;
/*
if ( (sym->n_type & N_TYPE ) != N_ABS &&
(sym->n_type & N_TYPE) != N_COMM)
target += where;
if ( (rel->r_type == SPARC_RELOC_PC10 ) ||
(rel->r_type == SPARC_RELOC_PC22))
target -= where;
*/
}
else
{
if ( rel->r_type == SPARC_RELOC_HI22 || rel->r_type == SPARC_RELOC_LO10 )
target = rel->r_addend;
if ( seg == 2 && rel->r_type == SPARC_RELOC_32 )
target = rel->r_addend;
/*
if ( (rel->r_index == N_TEXT ) ||
(rel->r_index == N_DATA) ||
(rel->r_index == N_BSS))
target = rel->r_addend;
*/
}
uint32 delta = 0;
switch ( rel->r_type )
{
case SPARC_RELOC_32:
value = instr;
target += value;
merged = target;
break;
case SPARC_RELOC_WDISP30:
value = (instr & S_MASK(30));
target += value;
merged = (instr & ~S_MASK(30)) | ((target >> 2) & S_MASK(30));
break;
case SPARC_RELOC_WDISP22:
value = (instr & S_MASK(22));
target += value;
merged = (instr & ~S_MASK(22)) | ((target >> 2) & S_MASK(22));
break;
case SPARC_RELOC_HI22:
value = (instr & S_MASK(22)) << 10;
target += value;
merged = (instr & ~S_MASK(22)) | ((target >> 10) & S_MASK(22));
delta = 0; //-(target & S_MASK(10));
type = get_hi22_reltype();
break;
case SPARC_RELOC_LO10:
value = (instr & S_MASK(10));
target += value;
merged = (instr & ~S_MASK(10)) | ((target) & S_MASK(10));
type = get_lo10_reltype();
break;
default:
msg("Unsupported sparc relocation type 0x%02X, ignored\n", rel->r_type);
continue;
}
#ifdef DEBUG
// if ( rel->r_address < 0x300 )
// msg("%08X: %08X -> %08X (%08X -> %08X)\n", where, instr, merged, value, target);
#endif
put_dword(where, merged);
do_fixup(where, rel->r_extern ? rel->r_addend : delta, target, type, rel->r_extern);
}
qfree(reltab);
}
//----------------------------------------------------------------------
static void do_relocation(linput_t *li, const aout_t &ctx, uint32 off, uint32 len, int seg)
{
switch ( N_MACHTYPE(ctx.ex) )
{
case M_SPARC:
do_relocation_sparc(li, ctx, off, len, seg);
break;
default:
msg("Warning: Relocation in image file not supported yet for this processor\n");
break;
}
}
//----------------------------------------------------------------------
void load_syms(linput_t *li, aout_t &ctx)
{
// get string table length
uint32 tabsize = 0;
qlseek(li, ctx.stroff);
lread4bytes(li, &tabsize, ctx.msb);
#ifdef DEBUG
msg("symoff=0x%08x symlen=0x%08x stroff=0x%08x strlen=0x%08x\n",
ctx.symoff, ctx.ex.a_syms, ctx.stroff, tabsize);
#endif
// load string table
char *strtab = (char *)qalloc(tabsize+1);
if ( strtab == NULL )
loader_failure("Unable to allocate string table for %u bytes\n", tabsize+1);
qlseek(li, ctx.stroff);
lreadbytes(li, strtab, tabsize, false);
strtab[tabsize] = '\0'; // ensure trailing zero
// load symbol table
ctx.symcount = ctx.ex.a_syms / sizeof(nlist);
validate_array_count_or_die(li, ctx.symcount, sizeof(nlist),
"Number of symbols", ctx.symoff);
nlist *symtab = qalloc_array<nlist>(ctx.symcount);
if ( symtab == NULL )
loader_failure("Unable to allocate symbol table for %u entries\n", ctx.symcount);
qlseek(li, ctx.symoff);
uint32 extern_count = 0;
for ( nlist *sym = symtab; sym < symtab + ctx.symcount; sym++ )
{
lread4bytes(li, &sym->n_un.n_strx, ctx.msb);
lreadbytes(li, &sym->n_type, 1, ctx.msb);
lreadbytes(li, &sym->n_other, 1, ctx.msb);
lread2bytes(li, &sym->n_desc, ctx.msb);
lread4bytes(li, &sym->n_value, ctx.msb);
if ( sym->n_type == N_EXT )
extern_count++;
}
// create extern section
uint32 extern_base = ctx.top;
if ( extern_count != 0 )
{
// create new segment
add_segm(0, extern_base, extern_base + (extern_count * 4), "extern", "XTRN", ADDSEG_SPARSE);
ctx.extrn = extern_base;
ctx.top += extern_count * 4;
}
// import symbols
#ifdef DEBUG
int i = 0;
#endif
uint32 i_extern = 0;
for ( nlist *sym = symtab; sym < symtab + ctx.symcount; sym++ )
{
if ( sym->n_type & N_STAB ) // debug stab info, not a symbol
continue;
if ( sym->n_type == N_EXT )
{
sym->n_value = extern_base + (i_extern * 4);
if ( getseg(sym->n_value) )
put_dword(sym->n_value, 0);
i_extern++;
}
if ( getseg(sym->n_value) != NULL )
{
if ( sym->n_un.n_strx < tabsize )
{
set_name(sym->n_value, strtab + sym->n_un.n_strx,
(sym->n_type & N_EXT ? SN_PUBLIC : SN_NON_PUBLIC)|SN_NOCHECK|SN_NOWARN|SN_IDBENC);
}
else
{
msg("%08X: type=0x%02X other=0x%02X desc=0x%04X: bad str offset %08X\n",
sym->n_value, sym->n_type, sym->n_other, sym->n_desc,
sym->n_un.n_strx);
}
}
if ( (sym->n_type & N_TYPE) == N_ABS )
{
#ifdef DEBUG
msg("%04X: %08X: type=0x%02X other=0x%02X desc=0x%04X: %s\n",
i, sym->n_value, sym->n_type, sym->n_other, sym->n_desc,
strtab + sym->n_un.n_strx);
#endif
}
#ifdef DEBUG
i++;
#endif
}
ctx.strtab = strtab;
ctx.symtab = symtab;
}
//--------------------------------------------------------------------------
static void handle_ld_info(linput_t *li, int diroff, int base)
{
lddir_t lddir;
qlseek(li, diroff);
lread(li, &lddir, sizeof(lddir));
ld_info_t ldinfo;
qlseek(li, lddir.ldinfo-base);
lread(li, &ldinfo, sizeof(ldinfo));
qoff64_t fpos = ldinfo.symbols - base;
int nsyms = (ldinfo.strings - ldinfo.symbols) / sizeof(ld_symbol_t);
validate_array_count(li, &nsyms, sizeof(ld_symbol_t), "Symbol count", fpos);
qlseek(li, fpos);
for ( int i=0; i < nsyms; i++ )
{
ld_symbol_t sym;
lread(li, &sym, sizeof(sym));
char name[MAXSTR];
qlgetz(li, ldinfo.strings + sym.nameoff - base, name, sizeof(name));
set_name(sym.addr, name, SN_IDBENC);
if ( (sym.flags & (AOUT_LD_FUNC|AOUT_LD_DEF)) == AOUT_LD_FUNC )
{ // imported function
put_byte(sym.addr, 0xC3); // return
if ( sym.addr <= ldinfo.ldentry )
warning("interr: symbol #%d (%s) is not in the plt", i, name);
}
}
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
processor_t &ph = PH;
aout_t ctx;
exec &ex = ctx.ex;
ctx.msb = ana_hdr(ph, li, &ex);
ctx.symtab = NULL;
ctx.symcount = 0;
ctx.strtab = NULL;
ctx.treloff = N_TRELOFF(ex);
ctx.dreloff = N_DRELOFF(ex);
ctx.symoff = N_SYMOFF(ex);
ctx.stroff = N_STROFF(ex);
int txtoff = N_TXTOFF(ex);
int txtadr;
switch ( ph.id )
{
case PLFM_SPARC:
txtoff = N_TXTOFF_SPARC(ex);
txtadr = N_TXTADDR_SPARC(ex);
ctx.treloff = N_TRELOFF_SPARC(ex);
ctx.dreloff = N_DRELOFF_SPARC(ex);
ctx.symoff = N_SYMOFF_SPARC(ex);
ctx.stroff = N_STROFF_SPARC(ex);
break;
case PLFM_ARM:
txtadr = N_TXTADDR_ARM(ex);
break;
default:
txtadr = N_TXTADDR(ex);
switch ( N_MAGIC(ex) )
{
// case NMAGIC:
// case CMAGIC:
default:
loader_failure("This image type is not supported yet");
case ZMAGIC:
if ( qlsize(li) < ex.a_text + ex.a_data + N_SYMSIZE(ex) + txtoff )
{
txtoff = 0;
txtadr = 0x1000;
}
else if ( txtoff < 512 )
{
loader_failure("Size of demand page < size of block");
}
// fallthrough
case QMAGIC:
if ( ex.a_text & 0xFFF || ex.a_data & 0xFFF )
loader_failure("Executable is not page aligned");
break;
case OMAGIC:
txtoff = sizeof(ex);
break;
}
break;
}
inf_set_baseaddr(0);
uint32 base, top;
top = base = txtadr;
if ( ex.a_text || ex.a_data )
{
top += ex.a_text;
// msg("txtoff=%d, base=%d top=%d end=%d\n", txtoff, base, top, top+ex.a_data);
file2base(li, txtoff, base, top + ex.a_data, FILEREG_PATCHABLE);
if ( ex.a_text )
{
create32(ph, 1, base, top, NAME_CODE, CLASS_CODE);
inf_set_start_cs(1);
inf_set_start_ip(ex.a_entry);
ctx.text = base;
}
if ( ex.a_data )
{
base = top;
create32(ph, 2, base, top += ex.a_data, NAME_DATA, CLASS_DATA);
set_default_dataseg(2);
ctx.data = base;
}
}
if ( ex.a_bss )
{
create32(ph, 3, top, top + ex.a_bss, NAME_BSS, CLASS_BSS);
ctx.bss = top;
}
ctx.top = top + ex.a_bss;
if ( ex.a_syms )
load_syms(li, ctx);
if ( N_TRSIZE(ex) )
do_relocation(li, ctx, ctx.treloff, N_TRSIZE(ex), 1);
if ( N_DRSIZE(ex) )
do_relocation(li, ctx, ctx.dreloff, N_DRSIZE(ex), 2);
// We come in here for the regular a.out style of shared libraries */
// ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) ||
// return -ENOEXEC;
// }
// For QMAGIC, the starting address is 0x20 into the page. We mask
// this off to get the starting address for the page */
// start_addr = ex.a_entry & 0xfffff000;
//////
if ( ph.id != PLFM_SPARC && N_FLAGS(ex) & EX_PIC )
handle_ld_info(li, ex.a_text, txtadr);
create_filename_cmt();
add_pgm_cmt("Flag value: %Xh", N_FLAGS(ex));
}
//----------------------------------------------------------------------
//
// 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,
};

283
idasdk76/ldr/aout/aout.h Normal file
View File

@@ -0,0 +1,283 @@
#ifndef __AOUT_H__
#define __AOUT_H__
#pragma pack(push, 1)
struct exec
{
uint32 a_info; // Use macros N_MAGIC, etc for access
uint32 a_text; // length of text, in bytes
uint32 a_data; // length of data, in bytes
uint32 a_bss; // length of bss area for file, in bytes
uint32 a_syms; // length of symbol table data in file, in bytes
uint32 a_entry; // start address
uint32 a_trsize; // length of relocation info for text, in bytes
uint32 a_drsize; // length of relocation info for data, in bytes
// Added for i960
// uint32 a_tload; // Text runtime load adderr
// uint32 a_dload; // Data runtime load address
// uchar a_talign; // Alignment of text segment
// uchar a_dalign; // Alignmrnt of data segment
// uchar a_balign; // Alignment of bss segment
// char a_relaxable;// Enough info for linker relax
};
//====================
#define N_TRSIZE(a) ((a).a_trsize)
#define N_DRSIZE(a) ((a).a_drsize)
#define N_SYMSIZE(a) ((a).a_syms)
#define N_DYNAMIC(exec) ((exec).a_info & 0x80000000ul)
#define N_MAGIC(exec) ((exec).a_info & 0xffff)
#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff))
#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff)
//====================
enum machine_type
{
// M_OLDSUN2 = 0,
M_UNKNOWN = 0,
M_68010 = 1,
M_68020 = 2,
M_SPARC = 3,
/*-----------------11.07.98 04:09-------------------
* skip a bunch so we don't run into any of suns numbers */
/*-----------------11.07.98 04:09-------------------
* make these up for the ns32k*/
M_NS32032 = (64), /* ns32032 running ? */
M_NS32532 = (64 + 5), /* ns32532 running mach */
M_386 = 100,
M_29K = 101, /* AMD 29000 */
M_386_DYNIX = 102, /* Sequent running dynix */
M_ARM = 103, /* Advanced Risc Machines ARM */
M_SPARCLET = 131, /* SPARClet = M_SPARC + 128 */
M_386_NETBSD = 134, /* NetBSD/i386 binary */
M_68K_NETBSD = 135, /* NetBSD/m68k binary */
M_68K4K_NETBSD = 136, /* NetBSD/m68k4k binary */
M_532_NETBSD = 137, /* NetBSD/ns32k binary */
M_SPARC_NETBSD = 138, /* NetBSD/sparc binary */
M_PMAX_NETBSD = 139, /* NetBSD/pmax (MIPS little-endian) binary */
M_VAX_NETBSD = 140, /* NetBSD/vax binary */
M_ALPHA_NETBSD = 141, /* NetBSD/alpha binary */
M_ARM6_NETBSD = 143, /* NetBSD/arm32 binary */
M_SPARCLET_1 = 147, /* 0x93, reserved */
M_MIPS1 = 151, /* MIPS R2000/R3000 binary */
M_MIPS2 = 152, /* MIPS R4000/R6000 binary */
M_SPARCLET_2 = 163, /* 0xa3, reserved */
M_SPARCLET_3 = 179, /* 0xb3, reserved */
M_SPARCLET_4 = 195, /* 0xc3, reserved */
M_HP200 = 200, /* HP 200 (68010) BSD binary */
M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */
M_HPUX = (0x20c % 256), /* HP 200/300 HPUX binary */
M_SPARCLET_5 = 211, /* 0xd3, reserved */
M_SPARCLET_6 = 227, /* 0xe3, reserved */
M_SPARCLET_7 = 243 /* 0xf3, reserved */
};
//====================
#define OMAGIC 0407 // object file or impure executable
#define NMAGIC 0410 // pure executeable
#define ZMAGIC 0413 // demand-paged executable
#define BMAGIC 0415 // Used by a b.out object
#define QMAGIC 0314 // demand-paged executable with the header in the text.
// The first page is unmapped to help trap NULL pointer
// referenced
#define CMAGIC 0421 // core file
//====================
// Flags:
#define EX_PIC 0x80 /* contains position independent code */
#define EX_DYNAMIC 0x40 /* contains run-time link-edit info */
#define EX_DPMASK 0xC0 /* mask for the above */
//====================
#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \
&& N_MAGIC(x) != NMAGIC \
&& N_MAGIC(x) != ZMAGIC \
&& N_MAGIC(x) != QMAGIC)
#define _N_HDROFF(x) (1024 - sizeof(struct exec))
#define N_TXTOFF(x) \
(N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
(N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data)
#define N_DRELOFF(x) (N_TRELOFF(x) + N_TRSIZE(x))
#define N_SYMOFF(x) (N_DRELOFF(x) + N_DRSIZE(x))
#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms)
// Address of text segment in memory after it is loaded
#define PAGE_SIZE (1UL << 12)
#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0)
#define PAGE_SIZE_ARM 0x8000UL
#define N_TXTADDR_ARM(x) (N_MAGIC(x) == QMAGIC ? 0 : PAGE_SIZE_ARM)
// Address of data segment in memory after it is loaded. (for linux)
/*
#define SEGMENT_SIZE 1024
#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
#define N_DATADDR(x) \
(N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) : \
(_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
// Address of bss segment in memory after it is loaded
#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data)
*/
//========================
struct nlist
{
union
{
int32 n_strx;
} n_un;
uchar n_type;
char n_other;
short n_desc;
uint32 n_value;
};
#define N_UNDF 0 // Undefined symbol
#define N_ABS 2 // Absolute symbol -- addr
#define N_TEXT 4 // Text sym -- offset in text segment
#define N_DATA 6 // Data sym -- offset in data segment
#define N_BSS 8 // BSS sym -- offset in bss segment
#define N_COMM 0x12 // Common symbol (visible after shared)
#define N_FN 0x1F // File name of .o file
#define N_FN_SEQ 0x0C // N_FN from Sequent compilers
#define N_EXT 1 // External (ORed wits UNDF, ABS, TEXT, DATA or BSS)
#define N_TYPE 0x1E
#define N_STAB 0xE0 // If present - debug symbol
#define N_INDR 0xA // symbol refernced to another symbol
#define N_SETA 0x14 // Absolute set element symbol
#define N_SETT 0x16 // Text set element symbol
#define N_SETD 0x18 // Data set element symbol
#define N_SETB 0x1A // Bss set element symbol
#define N_SETV 0x1C // Pointer to set vector in data area. (from LD)
#define N_WARNING 0x1E // Text has warnings
// Weak symbols
#define N_WEAKU 0x0D // Weak undefined
#define N_WEAKA 0x0E // Weak Absolute
#define N_WEAKT 0x0F // Weak Text
#define N_WEAKD 0x10 // Weak Data
#define N_WEAKB 0x11 // Weak BSS
//=======================
struct relocation_info
{
int32 r_address; // Adress (within segment) to be relocated
uint32 r_symbolnum:24;// The meaning of r_symbolnum depends on r_extern
uint32 r_pcrel:1; // Nonzero means value is a pc-relative offset
uint32 r_length:2; // Length (exp of 2) of the field to be relocated.
uint32 r_extern:1; // 1 => relocate with value of symbol.
// r_symbolnum is the index of the symbol
// in file's the symbol table.
// 0 => relocate with the address of a segment.
// r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS
uint32 r_bsr:1;
uint32 r_disp:1;
uint32 r_pad:2;
};
//============================
// The SPARC_ prefix is added to the canonical names below to avoid a name
// conflict if other architectures are added
enum reloc_type_sparc
{
SPARC_RELOC_8, SPARC_RELOC_16, SPARC_RELOC_32, // simplest relocs
SPARC_RELOC_DISP8, SPARC_RELOC_DISP16, SPARC_RELOC_DISP32, // disp's (pc-rel)
SPARC_RELOC_WDISP30, SPARC_RELOC_WDISP22, // SR word disp's
SPARC_RELOC_HI22, SPARC_RELOC_22, // SR 22-bit relocs
SPARC_RELOC_13, SPARC_RELOC_LO10, // SR 13&10-bit relocs
SPARC_RELOC_SFA_BASE, SPARC_RELOC_SFA_OFF13, // SR S.F.A. relocs
SPARC_RELOC_BASE10, SPARC_RELOC_BASE13, SPARC_RELOC_BASE22, // base_relative pic
SPARC_RELOC_PC10, SPARC_RELOC_PC22, // special pc-rel pic
SPARC_RELOC_JMP_TBL, // jmp_tbl_rel in pic
SPARC_RELOC_SEGOFF16, // ShLib offset-in-seg
SPARC_RELOC_GLOB_DAT, SPARC_RELOC_JMP_SLOT, SPARC_RELOC_RELATIVE, // rtld relocs
};
struct reloc_info_sparc
{
uint32 r_address; // relocation address (offset in segment)
uint32 r_index:24; // segment index or symbol index
uint32 r_extern:1; // if F, r_index==SEG#, if T, SYM index
uint32 :2; // unused
uint32 r_type:5; // type of relocation to perform
uint32 r_addend; // addend for relocation value
};
CASSERT(sizeof(reloc_info_sparc) == 12);
#define N_PAGSIZ_SPARC(x) 0x02000
#define N_SEGSIZ_SPARC(x) N_PAGSIZ_SPARC
#define N_TXTOFF_SPARC(x) ((N_MAGIC(x) == ZMAGIC) ? 0 : sizeof (struct exec))
#define N_TXTADDR_SPARC(x) \
((N_MAGIC(x) == OMAGIC) ? (x).a_entry \
: ((N_MAGIC(x) == ZMAGIC) && ((x).a_entry < N_PAGSIZ_SPARC(x)) ? 0 \
: N_PAGSIZ_SPARC(x)) \
)
#define N_DATOFF_SPARC(x) (N_TXTOFF_SPARC(x) + (x).a_text)
#define N_DATADDR_SPARC(x) \
((N_MAGIC(x) == OMAGIC) ? (N_TXTADDR_SPARC(x) + (x).a_text) \
: (N_SEGSIZ_SPARC(x)+((N_TXTADDR_SPARC(x)+(x).a_text-1) \
& ~(N_SEGSIZ_SPARC(x)-1))))
#define N_BSSADDR_SPARC(x) (N_DATADDR_SPARC(x) + (x).a_data)
#define N_TRELOFF_SPARC(x) (N_DATOFF_SPARC(x) + (x).a_data)
#define N_DRELOFF_SPARC(x) (N_TRELOFF_SPARC(x) + N_TRSIZE(x))
#define N_SYMOFF_SPARC(x) (N_DRELOFF_SPARC(x) + N_DRSIZE(x))
#define N_STROFF_SPARC(x) (N_SYMOFF_SPARC(x) + (x).a_syms)
//============================
// Dynamic loader info (restored from a binary form in pc_bsd.aout, not exact):
struct lddir_t
{
uint32 unknown0; // 8
uint32 unknown1; // offset dword_5010
uint32 ldinfo;
};
struct ld_info_t
{
uint32 unknown0; // 0
uint32 onemoretable;
uint32 unknown1; // 0
uint32 off_5060; // points to the end of this struct
uint32 ldentry; // main dynamic loader entry
uint32 imports;
uint32 pairs; // pairs of symbol numbers
uint32 symbols;
uint32 unknown2; // 0
uint32 unknown3; // 16h
uint32 strings;
uint32 unknown4; // 310h
uint32 unknown5; // 4000h
uint32 unknown6; // 148h
uint32 unknown7; // offset dword_5000
};
struct ld_symbol_t
{
uint32 nameoff; // offset from the beginning of the string table
uint32 flags;
#define AOUT_LD_FUNC 0x200
#define AOUT_LD_DEF 0x004 // defined, otherwise - imported
#define AOUT_LD_DATA 0x002 // data
uint32 addr; // pointer to the object
uint32 zero; // always zero?
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,76 @@
//--------------------------------------------------------------------------
static void swap_exec(exec &ex)
{
ex.a_info = swap32(ex.a_info);
ex.a_text = swap32(ex.a_text);
ex.a_data = swap32(ex.a_data);
ex.a_bss = swap32(ex.a_bss);
ex.a_syms = swap32(ex.a_syms);
ex.a_entry = swap32(ex.a_entry);
ex.a_trsize = swap32(ex.a_trsize);
ex.a_drsize = swap32(ex.a_drsize);
}
//--------------------------------------------------------------------------
int get_aout_file_format_index(linput_t *li, exec *_ex)
{
exec &ex = *_ex;
int i = 0;
if ( qlread(li, &ex, sizeof(ex)) != sizeof(ex) )
return false;
if ( N_BADMAG(ex) )
{
swap_exec(ex);
switch ( N_MACHTYPE(ex) )
{
case M_386_NETBSD:
case M_68K_NETBSD:
case M_68K4K_NETBSD:
case M_532_NETBSD:
case M_SPARC:
case M_SPARC_NETBSD:
case M_PMAX_NETBSD:
case M_VAX_NETBSD:
case M_ALPHA_NETBSD:
case M_ARM6_NETBSD:
break;
default:
return false;
}
}
switch ( N_MAGIC(ex) )
{
case NMAGIC:
++i;
case CMAGIC:
++i;
case ZMAGIC:
++i;
case OMAGIC:
++i;
case QMAGIC:
if ( N_MACHTYPE(ex) == M_SPARC )
break; // SPARC uses different TXTOFF
#ifdef DEBUG
msg("magic=%04x text=%08x data=%08x symsize=%08x txtoff=%08x sum=%08x // qlsize=%08x\n", N_MAGIC(ex), ex.a_text, ex.a_data,
N_SYMSIZE(ex), N_TXTOFF(ex), ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex),
qlsize(li));
#endif
if ( qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex) )
break;
if ( N_MAGIC(ex) == ZMAGIC
&& qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) )
{
i = 5; // OpenBSD demand-paged
break;
}
default:
return false;
}
return i+1;
}

View File

@@ -0,0 +1,14 @@
PROC=aout
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)aout$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../../module/sparc/notify_codes.hpp \
../idaldr.h aout.cpp aout.h common.cpp

149
idasdk76/ldr/ar/aixar.hpp Normal file
View File

@@ -0,0 +1,149 @@
/* IBM_PROLOG_BEGIN_TAG */
/* This is an automatically generated prolog. */
/* */
/* bos420 src/bos/usr/include/ar.h */
/* */
/* Licensed Materials - Property of IBM */
/* */
/* (C) COPYRIGHT International Business Machines Corp. 1989,1995 */
/* All Rights Reserved */
/* */
/* US Government Users Restricted Rights - Use, duplication or */
/* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */
/* */
/* IBM_PROLOG_END_TAG */
/* @(#)25 1.8 src/bos/usr/include/ar.h, cmdar, bos420, 9613T 6/16/90 00:07:48 */
/* ar.h 5.1 - 86/12/09 - 06:03:39 */
#ifndef _H_AR
#define _H_AR
#pragma pack(push, 1)
/*
* COMPONENT_NAME: CMDAR
*
* FUNCTIONS: none
*
* ORIGINS: 27, 3
*
* (C) COPYRIGHT International Business Machines Corp. 1989
* All Rights Reserved
* Licensed Materials - Property of IBM
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/* AIX INDEXED ARCHIVE FORMAT
*
* ARCHIVE File Organization:
* _____________________________________________
* |__________FIXED HEADER "fl_hdr"______________|
* +--- | |
* | |__________ARCHIVE_FILE_MEMBER_1______________|
* +--> | |
* | Archive Member Header "ar_hdr" |
* +--- |.............................................| <--+
* | | Member Contents | |
* | |_____________________________________________| |
* | |________ARCHIVE_FILE_MEMBER_2________________| |
* +--> | | ---+
* | Archive Member Header "ar_hdr" |
* +--- |.............................................| <--+
* | | Member Contents | |
* | |_____________________________________________| |
* | | . . . | |
* . | . . . | .
* . | . . . | .
* . |_____________________________________________| .
* | |________ARCHIVE_FILE_MEMBER_n-1______________| |
* +--> | | ---+
* | Archive Member Header "ar_hdr" |
* +--- |.............................................| <--+
* | | Member Contents | |
* | | (Member Table, always present) | |
* | |_____________________________________________| |
* | |_____________________________________________| |
* | |________ARCHIVE_FILE_MEMBER_n________________| |
* | | | |
* +--> | Archive Member Header "ar_hdr" | ---+
* |.............................................|
* | Member Contents |
* | (Global Symbol Table if present) |
* |_____________________________________________|
*
*/
#define AIAMAG "<aiaff>\n"
#define AIAMAGBIG "<bigaf>\n"
#define SAIAMAG 8
#define AIAFMAG "`\n"
struct fl_hdr /* archive fixed length header */
{
char fl_magic[SAIAMAG]; /* Archive magic string */
char fl_memoff[20]; /*Offset to member table */
char fl_gstoff[20]; /*Offset to global symbol table */
char fl_gst64off[20]; /*Offset global symbol table for 64-bit objects */
char fl_fstmoff[20]; /*Offset to first archive member */
char fl_lstmoff[20]; /*Offset to last archive member */
char fl_freeoff[20]; /*Offset to first mem on free list */
};
struct aix_ar_hdr /* archive file member header - printable ascii */
{
char ar_size[20]; /* File member size - decimal */
char ar_nxtmem[20]; /* Next member offset-decimal */
char ar_prvmem[20]; /* Previous member offset-dec */
char ar_date[12]; /* File member date-decimal */
char ar_uid[12]; /* File member userid-decimal */
char ar_gid[12]; /* File member group id-decimal */
char ar_mode[12]; /* File member mode-octal */
char ar_namlen[4]; /* File member name length-dec */
#if 0
union
{
char ar_name[2]; /* variable length member name */
char ar_fmag[2]; /* AIAFMAG - string to end header */
} _ar_name; /* and variable length name */
#endif
};
struct fl_hdr_small /* archive fixed length header (prior to Version 4.3) */
{
char fl_magic[SAIAMAG]; /* Archive file magic string */
char fl_memoff[12]; /* Offset to member table */
char fl_gstoff[12]; /* Offset to global symbol table */
char fl_fstmoff[12]; /* Offset to first archive member */
char fl_lstmoff[12]; /* Offset to last archive member */
char fl_freeoff[12]; /* Offset to first mem on free list */
};
struct aix_ar_hdr_small /* archive file member header - printable ascii */
{
char ar_size[12]; /* file member size - decimal */
char ar_nxtmem[12]; /* pointer to next member - decimal */
char ar_prvmem[12]; /* pointer to previous member - decimal */
char ar_date[12]; /* file member date - decimal */
char ar_uid[12]; /* file member user id - decimal */
char ar_gid[12]; /* file member group id - decimal */
char ar_mode[12]; /* file member mode - octal */
char ar_namlen[4]; /* file member name length - decimal */
#if 0
union
{
char ar_name[2]; /* variable length member name */
char ar_fmag[2]; /* AIAFMAG - string to end header */
} _ar_name; /* and variable length name */
#endif
};
/*
* Note: 'ar_namlen' contains the length of the member name which
* may be up to 255 chars. The character string containing
* the name begins at '_ar_name.ar_name'. The terminating
* string AIAFMAG, is only cosmetic. File member contents begin
* at the first even byte boundary past 'header position +
* sizeof(struct ar_hdr) + ar_namlen', and continue for
* 'ar_size' bytes.
*/
#pragma pack(pop)
#endif /* _H_AR */

113
idasdk76/ldr/ar/ar.hpp Normal file
View File

@@ -0,0 +1,113 @@
/* So far this is correct for BSDish archives. Don't forget that
files must begin on an even byte boundary. */
#ifndef __AR_H__
#define __AR_H__
#pragma pack(push, 1)
/* Note that the usual '\n' in magic strings may translate to different
characters, as allowed by ANSI. '\012' has a fixed value, and remains
compatible with existing BSDish archives. */
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */
#define ARMAGB "!<bout>\012" /* For b.out archives */
#define ARMAGE "!<elf_>\012" /* For ELF archives */
#define SARMAG 8
#define ARFMAG "`\012"
/* The ar_date field of the armap (__.SYMDEF) member of an archive
must be greater than the modified date of the entire file, or
BSD-derived linkers complain. We originally write the ar_date with
this offset from the real file's mod-time. After finishing the
file, we rewrite ar_date if it's not still greater than the mod date. */
#define ARMAP_TIME_OFFSET 60
struct ar_hdr
{
char ar_name[16]; /* name of this member */
char ar_date[12]; /* file mtime */
char ar_uid[6]; /* owner uid; printed as decimal */
char ar_gid[6]; /* owner gid; printed as decimal */
char ar_mode[8]; /* file mode, printed as octal */
char ar_size[10]; /* file size, printed as decimal */
char ar_fmag[2]; /* should contain ARFMAG */
};
#define AR_EFMT1 "#1/" /* extended format #1: BSD/Apple archives */
// ig. get all module names from ar
int process_ar(
char *libfile, /* return 0 - ok */
int (*_callback)(
void *ud,
int32 offset,
int method,
uint32 csize,
uint32 ucsize,
uint32 attributes,
const char *filename),
void *ud);
// The first linker member has the following format. This information appears after the
// header:
//
// Offset Size Field Description
// 0 4 Number of Symbols Unsigned long containing the number of symbols indexed.
// This number is stored in big-endian format. Each object-file member
// typically defines one or more external symbols.
// 4 4*n Offsets Array of file offsets to archive member headers, in which n is
// equal to Number of Symbols. Each number in the array is an unsigned long
// stored in big-endian format. For each symbol named in the String Table,
// the corresponding element in the Offsets array gives the location of the
// archive member that contains the symbol.
// * * String Table Series of null-terminated strings that name all the symbols
// in the directory. Each string begins immediately after the null character
// in the previous string. The number of strings must be equal to the value
// of the Number of Symbols fields.
//
// -----------------------------
// The second linker member has the name '\' as does the first linker member. Although
// both the linker members provide a directory of symbols and archive members that contain
// them, the second linker member is used in preference to the first by all current
// linkers. The second linker member includes symbol names in lexical order, which enables
// faster searching by name.
//
// The first second member has the following format. This information appears after the
// header:
//
// Offset Size Field Description
// 0 4 Number of Members Unsigned long containing the number of archive members.
// 4 4*m Offsets Array of file offsets to archive member headers, arranged in
// ascending order. Each offset is an unsigned long. The number m is equal
// to the value of the Number of Members field.
// * 4 Number of Symbols Unsigned long containing the number of symbols indexed.
// Each object-file member typically defines one or more external symbols.
// * 2*n Indices Array of 1-based indices (unsigned short) which map symbol names
// to archive member offsets. The number n is equal to Number of Symbols.
// For each symbol named in the String Table, the corresponding element in
// the Indices array gives an index into the Offsets array. The Offsets
// array, in turn, gives the location of the archive member that contains
// the symbol.
// * * String Table Series of null-terminated strings that name all the symbols
// in the directory. Each string begins immediately after the null byte in
// the previous string. The number of strings must be equal to the value of
// the Number of Symbols fields. This table lists all the symbol names in
// ascending lexical order.
//
// //-----------------------------
// The name of the longnames member is '\\'. The longnames member is a series of
// strings of archive member names. A name appears here only when there is insufficient
// room in the Name field (16 bytes). The longnames member can be empty, though its
// header must appear.
//
// The strings are null-terminated. Each string begins immediately after the null byte
// in the previous string.
//
bool is_ar_file(linput_t *li, qoff64_t offset, bool include_aix);
#pragma pack(pop)
#endif /* __AR_H__ */

238
idasdk76/ldr/ar/arcmn.cpp Normal file
View File

@@ -0,0 +1,238 @@
#include <diskio.hpp>
#define MAGICLEN ((SARMAG > SAIAMAG) ? SARMAG : SAIAMAG)
//------------------------------------------------------------------------
bool is_ar_file(linput_t *li, qoff64_t offset, bool include_aix)
{
char magic[MAGICLEN];
qlseek(li, offset);
if ( qlread(li, magic, sizeof(magic)) != sizeof(magic) )
return false;
return memcmp(magic, ARMAG, SARMAG) == 0
|| memcmp(magic, ARMAGB, SARMAG) == 0
|| memcmp(magic, ARMAGE, SARMAG) == 0
|| include_aix
&& (memcmp(magic,AIAMAG,SAIAMAG) == 0
|| memcmp(magic,AIAMAGBIG,SAIAMAG) == 0);
}
//------------------------------------------------------------------------
static char *get_msft_module_name(
const char *ahname,
const char *ahend,
char *name,
size_t size)
{
if ( size == 0 )
return NULL;
char *ptr = name;
for ( size_t i=0; ahname < ahend; i++,ptr++ )
{
char chr = *ahname++;
if ( chr == '\n' || i == size-1 )
chr = '\0';
*ptr = chr;
if ( chr == '\0' )
break;
}
while ( ptr > name && qisspace(ptr[-1]) )
*--ptr = '\0';
if ( ptr > name && ptr[-1] == '/' )
ptr[-1] = '\0';
return name;
}
//------------------------------------------------------------------------
static const char *get_ar_modname(
const char *lnames,
const char *end,
const char *name,
char *buf,
size_t bufsize)
{
if ( lnames != NULL && *name == '/' )
{
name++;
size_t off = size_t(atol(name));
while ( qisdigit(*name) )
name++;
if ( *name == '\0' )
{
if ( lnames+off < lnames )
return qstrncpy(buf, "?", bufsize);
return get_msft_module_name(lnames+off, end, buf, bufsize);
}
}
return qstrncpy(buf, name, bufsize);
}
//------------------------------------------------------------------------
// return codes:
// 0: ok
// 1: no input file
// 2: read error
// 3: bad archive
// 4: not enough memory
// 5: maxpos reached
struct ar_visitor_t
{
virtual ssize_t idaapi visit_ar_module(
qoff64_t offset,
ar_hdr *ah,
uint64 size,
char *filename) = 0;
};
// Enumerate modules in AR archive.
// \param maxpos Max position in file. Typically is used when
// archive is embedded within other file.
ssize_t enum_ar_contents(linput_t *li, ar_visitor_t &av, int32 maxpos = -1)
{
ssize_t code = 0;
char *names = NULL;
size_t names_size = 0;
while ( true )
{
ar_hdr ah;
qoff64_t filepos = qltell(li);
if ( filepos & 1 )
qlseek(li, filepos+1);
if ( maxpos > -1 && filepos >= maxpos )
{
code = 5;
break;
}
ssize_t bytes = qlread(li, &ah, sizeof(ah));
if ( bytes == 0 )
break; // end of archive, no error
if ( bytes != sizeof(ah) )
{
code = 2; // read error
break;
}
if ( memcmp(ah.ar_fmag, ARFMAG, sizeof(ah.ar_fmag)) != 0 )
{
code = 3; // bad archive
break;
}
char name[sizeof(ah.ar_name)+1];
get_msft_module_name(ah.ar_name, ah.ar_name+sizeof(ah.ar_name), name, sizeof(name));
uint64 size = qatoll(ah.ar_size);
filepos = qltell(li);
if ( names == NULL && name[0] == '/' && name[1] == '\0' )
{
if ( size != 0 )
{
names = (char *)qalloc(size);
if ( names == NULL )
{
code = 4; // not enough memory
break;
}
names_size = size;
if ( qlread(li, names, size) != size )
{
code = 2; // read error
break;
}
}
continue;
}
if ( memcmp(name, AR_EFMT1, 3) == 0 )
{
// BSD/Apple archive: the length of long name follows
// #1/nnn
size_t extralen = size_t(atol(name+3));
char *modname = (char *)qalloc(extralen+1);
if ( modname == NULL )
{
code = 4; // not enough memory
break;
}
if ( qlread(li, modname, extralen) != extralen )
{
code = 2; // read error
break;
}
modname[extralen]='\0';
// skip special files
if ( !strneq(modname, "__.SYMDEF", sizeof("__.SYMDEF")-1) )
{
code = av.visit_ar_module(qoff64_t(filepos+extralen), &ah, size-extralen, modname);
if ( code != 0 )
break;
}
qfree(modname);
}
else if ( name[0] != '\0' )
{
char modname[MAXSTR];
get_ar_modname(names, names+names_size, name, modname, sizeof(modname));
code = av.visit_ar_module(filepos, &ah, size, modname);
if ( code != 0 )
break;
}
qlseek(li, qoff64_t(filepos+size));
}
qfree(names);
return code;
}
//--------------------------------------------------------------------------
// convert small archive header to big one
bool upgrade_aix_fl_hdr(fl_hdr *fh, const fl_hdr_small *fh_small)
{
if ( memcmp(fh_small->fl_magic, AIAMAG, SAIAMAG) != 0 )
return false; // not small archive
qstrncpy(fh->fl_memoff, fh_small->fl_memoff, sizeof(fh->fl_memoff));
qstrncpy(fh->fl_gstoff, fh_small->fl_gstoff, sizeof(fh->fl_gstoff));
fh->fl_gst64off[0] = '\0';
qstrncpy(fh->fl_fstmoff, fh_small->fl_fstmoff, sizeof(fh->fl_fstmoff));
qstrncpy(fh->fl_lstmoff, fh_small->fl_lstmoff, sizeof(fh->fl_lstmoff));
qstrncpy(fh->fl_freeoff, fh_small->fl_freeoff, sizeof(fh->fl_freeoff));
return true;
}
//--------------------------------------------------------------------------
bool read_aix_fl_hdr(fl_hdr *fh, linput_t *li)
{
size_t nread = qlread(li, fh, sizeof(*fh));
if ( nread == sizeof(*fh) && memcmp(fh->fl_magic, AIAMAGBIG, SAIAMAG) == 0 )
return true;
if ( nread < sizeof(fl_hdr_small) )
return false;
fl_hdr_small fh_small;
memcpy(&fh_small, fh, sizeof(fh_small)); //-V512 call of the 'memcpy' function will lead to underflow of the buffer
return upgrade_aix_fl_hdr(fh, &fh_small);
}
//--------------------------------------------------------------------------
// convert small member header to big one
void upgrade_aix_ar_hdr(aix_ar_hdr *ah, const aix_ar_hdr_small *ah_small)
{
qstrncpy(ah->ar_size, ah_small->ar_size, sizeof(ah->ar_size));
qstrncpy(ah->ar_nxtmem, ah_small->ar_nxtmem, sizeof(ah->ar_nxtmem));
qstrncpy(ah->ar_prvmem, ah_small->ar_prvmem, sizeof(ah->ar_prvmem));
qstrncpy(ah->ar_date, ah_small->ar_date, sizeof(ah->ar_date));
qstrncpy(ah->ar_uid, ah_small->ar_uid, sizeof(ah->ar_uid));
qstrncpy(ah->ar_gid, ah_small->ar_gid, sizeof(ah->ar_gid));
qstrncpy(ah->ar_mode, ah_small->ar_mode, sizeof(ah->ar_mode));
qstrncpy(ah->ar_namlen, ah_small->ar_namlen, sizeof(ah->ar_namlen));
}
//--------------------------------------------------------------------------
bool read_aix_ar_hdr(aix_ar_hdr *ah, const fl_hdr *fh, linput_t *li)
{
if ( memcmp(fh->fl_magic, AIAMAGBIG, SAIAMAG) == 0 )
return qlread(li, ah, sizeof(*ah)) == sizeof(*ah);
aix_ar_hdr_small ah_small;
if ( qlread(li, &ah_small, sizeof(ah_small)) != sizeof(ah_small) )
return false;
upgrade_aix_ar_hdr(ah, &ah_small);
return true;
}

View File

@@ -0,0 +1,91 @@
#ifndef _H_DBXSTCLASS
#define _H_DBXSTCLASS
/*
* XCOFF STORAGE CLASSES AND STABSTRINGS DESIGNED SPECIFICALLY FOR DBX
*/
#define DBXMASK 0x80
#define C_GSYM 0x80 // Global variable.
#define C_LSYM 0x81 // Automatic variable allocated on stack.
#define C_PSYM 0x82 // Argument to subroutine allocated on stack.
#define C_RSYM 0x83 // Register variable.
#define C_RPSYM 0x84 // Argument to function or procedure stored in the register.
#define C_STSYM 0x85 // Statically allocated symbol.
#define C_TCSYM 0x86
#define C_BCOMM 0x87 // Beginning of common block.
#define C_ECOML 0x88 // Local member of common block.
#define C_ECOMM 0x89 // End of common block.
#define C_DECL 0x8c // Declaration of object.
#define C_ENTRY 0x8d // Alternate entry.
#define C_FUN 0x8e // Function or procedure.
#define C_BSTAT 0x8f // Beginning of static block.
#define C_ESTAT 0x90 // End of static block.
#define TP_ARRAY \
{\
"int:t-1=r-1;-2147483648;2147483647",\
"char:t-2=@s8;r-2;0;255",\
"short:t-3=@s16;r-3;-32768;32767",\
"long:t-4=-1",\
"unsigned char:t-5=@s8;r-5;0;255",\
"signed char:t-6=@s8;r-6;-128;127",\
"unsigned short:t-7=@s16;r-7;0;65535",\
"unsigned int:t-8=r-8;0;4294967295",\
"unsigned:t-9=-8",\
"unsigned long:t-10=-8",\
"void:t-11=r-11;0;0",\
"float:t-12=g-12;4",\
"double:t-13=g-12;8",\
"long double:t-14=g-12;10",\
"integer:t-15=-1",\
"boolean:t-16=efalse:0,true:1,",\
"shortreal:t-17=g-12;4",\
"real:t-18=g-12;8",\
"stringptr:t-19=N-19",\
"character:t-20=@s8;r-20;0;255",\
"logical*1:t-21=@s8;r-21;0;255",\
"logical*2:t-22=@s16;r-22;0;65535",\
"logical*4:t-23=r-23;0;4294967295",\
"logical:t-24=-23",\
"complex:t-25=c-25;8",\
"double complex:t-26=c-25;16",\
"integer*1:t-27=-6",\
"integer*2:t-28=-3",\
"integer*4:t-29=-1",\
"wchar:t-30=@s16;r-30;0;65535" \
}
#define TP_INT (-1)
#define TP_CHAR (-2)
#define TP_SHORT (-3)
#define TP_LONG (-4)
#define TP_UCHAR (-5)
#define TP_SCHAR (-6)
#define TP_USHORT (-7)
#define TP_UINT (-8)
#define TP_UNSIGNED (-9)
#define TP_ULONG (-10)
#define TP_VOID (-11)
#define TP_FLOAT (-12)
#define TP_DOUBLE (-13)
#define TP_LDOUBLE (-14)
#define TP_PASINT (-15)
#define TP_BOOL (-16)
#define TP_SHRTREAL (-17)
#define TP_REAL (-18)
#define TP_STRNGPTR (-19)
#define TP_FCHAR (-20)
#define TP_LOGICAL1 (-21)
#define TP_LOGICAL2 (-22)
#define TP_LOGICAL4 (-23)
#define TP_LOGICAL (-24)
#define TP_COMPLEX (-25)
#define TP_DCOMPLEX (-26)
#define TP_INTEGER1 (-27)
#define TP_INTEGER2 (-28)
#define TP_INTEGER4 (-29)
#define TP_WCHAR (-30)
#define TP_NTYPES 30
#endif /* _H_DBXSTCLASS */

View File

@@ -0,0 +1,82 @@
#ifndef _H_STCLASS
#define _H_STCLASS
/*********************************************************************
*
* COFF Extended Object File Format:
* storclass.h
* Derived from AT&T UNIX System V Release 2.0 COFF
*
* Structure similar to original COFF
*
*********************************************************************/
/*
* STORAGE CLASSES
*/
/* This used to be defined as -1, but now n_sclass is unsigned. */
#define C_EFCN 0xff /* physical end of function */
#define C_NULL 0
#define C_AUTO 1 /* automatic variable */
#define C_EXT 2 /* external symbol */
#define C_STAT 3 /* static */
#define C_REG 4 /* register variable */
#define C_EXTDEF 5 /* external definition */
#define C_LABEL 6 /* label */
#define C_ULABEL 7 /* undefined label */
#define C_MOS 8 /* member of structure */
#define C_ARG 9 /* function argument */
#define C_STRTAG 10 /* structure tag */
#define C_MOU 11 /* member of union */
#define C_UNTAG 12 /* union tag */
#define C_TPDEF 13 /* type definition */
#define C_USTATIC 14 /* undefined static */
#define C_ENTAG 15 /* enumeration tag */
#define C_MOE 16 /* member of enumeration */
#define C_REGPARM 17 /* register parameter */
#define C_FIELD 18 /* bit field */
#define C_AUTOARG 19 /* auto argument */
#define C_LASTENT 20 /* dummy entry (end of block) */
#define C_BLOCK 100 /* ".bb" or ".eb" */
#define C_FCN 101 /* ".bf" or ".ef" */
#define C_EOS 102 /* end of structure */
#define C_FILE 103 /* file name */
#define C_LINE 104 /* line # reformatted as symbol table entry */
#define C_ALIAS 105 /* duplicate tag */
#define C_HIDDEN 106 /* ext symbol in dmert public lib */
/* New storage classes for WINDOWS_NT */
#define C_SECTION 104 /* section name */
#define C_NT_WEAK 105 /* weak external */
/* New storage classes for 80960 */
/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */
#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */
#define C_SCALL 107 /* Procedure reachable via system call */
#define C_LEAFEXT 108 /* External leaf */
#define C_LEAFSTAT 113 /* Static leaf */
#define C_OPTVAR 109 /* Optimized variable */
#define C_DEFINE 110 /* Preprocessor #define */
#define C_PRAGMA 111 /* Advice to compiler or linker */
#define C_SEGMENT 112 /* 80960 segment name */
/* Storage classes for m88k */
#define C_SHADOW 107 /* shadow symbol */
#define C_VERSION 108 /* coff version symbol */
/* New storage classes for RS/6000 */
#define C_HIDEXT 107 /* Un-named external symbol */
#define C_BINCL 108 /* Marks beginning of include file */
#define C_EINCL 109 /* Marks ending of include file */
#define C_WEAKEXT 111 /* Weak external symbol */
/* Storage classes for MS Windows */
#define IMAGE_SYM_CLASS_TOKEN 107
#include <../ldr/coff/dbxstcla.h>
#endif /* _H_STCLASS */

862
idasdk76/ldr/coff/syms.h Normal file
View File

@@ -0,0 +1,862 @@
#ifndef _H_SYMS
#define _H_SYMS
#include <../ldr/coff/storclas.h>
#pragma pack(push, 1)
#define SYMNMLEN 8 /* Number of characters in a symbol name */
#define FILNMLEN 14 /* Number of characters in a file name */
#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */
struct coff_sym_t // here for efd(di) and ldr/dbg
{
union
{
char _n_name[SYMNMLEN]; /* old COFF version */
struct
{
int32 _n_zeroes; /* new == 0 */
int32 _n_offset; /* offset into string table */
} _n_n;
// char *_n_nptr[2]; /* allows for overlaying */
} _n;
uint32 n_value; /* value of symbol */
uint16 n_scnum; /* section number */
uint16 n_type; /* type and derived type */
uchar n_sclass; /* storage class */
uchar n_numaux; /* number of aux. entries */
};
struct coff_sym64_t
{
uint64 n_value64; /* value of symbol */
uint32 n_offset64; /* offset into string table */
uint16 n_scnum; /* section number */
union
{
unsigned short _n_type; /* type and derived type */
struct
{
unsigned char _n_lang; /* source language id */
unsigned char _n_cpu; /* cputype id */
} _n_lc;
} _n_tylc;
char n_sclass; /* storage class */
char n_numaux; /* number of aux. entries */
};
#define IDA_SYM_SZ (SYMNMLEN + 8 + 4 + 2 + 2*1)
struct ida_sym_t // internal, translated form
{
union
{
char _n_name[SYMNMLEN]; /* old for short name (<=8) */
struct
{
int32 _n_zeroes; /* for long name == 0 */
int32 _n_offset; /* offset into string table */
} _n_n;
} _n;
uint64 n_value; /* value of symbol */
uint32 n_scnum; /* section number */
uint16 n_type; /* type and derived type */
uchar n_sclass; /* storage class */
uchar n_numaux; /* number of aux. entries */
};
DECLARE_TYPE_AS_MOVABLE(ida_sym_t);
#define COFF_SYM_SZ (SYMNMLEN + 4 + 2*2 + 2*1)
#define COFF_SYM64_SZ (8 + 4 + 2 + 2 + 2*1)
#define n_name _n._n_name
#define n_nptr _n._n_nptr[1]
#define n_zeroes _n._n_n._n_zeroes
#define n_offset _n._n_n._n_offset
/*
* Relocatable symbols have a section number of the
* section in which they are defined. Otherwise, section
* numbers have the following meanings:
*/
#define N_UNDEF 0 // undefined symbol
#define N_ABS uint16(-1) // value of symbol is absolute
#define N_DEBUG uint16(-2) // special debugging symbol -- value of symbol is meaningless
#define N_TV uint16(-3) // indicates symbol needs transfer vector (preload)
#define P_TV uint16(-4) // indicates symbol needs transfer vector (postload)
/*
* The fundamental type of a symbol packed into the low
* 4 bits of the word.
*/
#if 0
#define _EF ".ef"
#endif
/*
* Type of a symbol, in low N bits of the word
*/
#define T_NULL 0
#define T_VOID 1 /* function argument (only used by compiler) */
#define T_CHAR 2 /* character */
#define T_SHORT 3 /* short integer */
#define T_INT 4 /* integer */
#define T_LONG 5 /* long integer */
#define T_FLOAT 6 /* floating point */
#define T_DOUBLE 7 /* double word */
#define T_STRUCT 8 /* structure */
#define T_UNION 9 /* union */
#define T_ENUM 10 /* enumeration */
#define T_MOE 11 /* member of enumeration*/
#define T_UCHAR 12 /* unsigned character */
#define T_USHORT 13 /* unsigned short */
#define T_UINT 14 /* unsigned integer */
#define T_ULONG 15 /* unsigned long */
#define T_LNGDBL 16 /* long double */
/*
* derived types, in n_type
*/
#define DT_NON (0) /* no derived type */
#define DT_PTR (1) /* pointer */
#define DT_FCN (2) /* function */
#define DT_ARY (3) /* array */
/*
* type packing constants
*/
#define IDA_N_BTMASK 017
#define IDA_N_TMASK 060
#define IDA_N_TMASK1 0300
#define IDA_N_TMASK2 0360
#define IDA_N_BTSHFT 4
#define IDA_N_TSHIFT 2
//--------------------------------------------------------------------------
/* Basic Type of x */
#define IDA_BTYPE(x) ((x) & IDA_N_BTMASK)
/* Is x a pointer ? */
#define IDA_ISPTR(x) (((x) & IDA_N_TMASK) == (DT_PTR << IDA_N_BTSHFT))
/* Is x a function ? */
#define IDA_ISFCN(x) (((x) & IDA_N_TMASK) == (DT_FCN << IDA_N_BTSHFT))
/* Is x an array ? */
#define IDA_ISARY(x) (((x) & IDA_N_TMASK) == (DT_ARY << IDA_N_BTSHFT))
/* Is x a structure, union, or enumeration TAG? */
#define IDA_ISTAG(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG)
#define IDA_INCREF(x) ((((x)&~IDA_N_BTMASK)<<IDA_N_TSHIFT)|(DT_PTR<<IDA_N_BTSHFT)|(x&IDA_N_BTMASK))
#define IDA_DECREF(x) ((((x)>>IDA_N_TSHIFT)&~IDA_N_BTMASK)|((x)&IDA_N_BTMASK))
/*************************************************************************
*
* AUXILIARY ENTRY FORMAT
*
*************************************************************************/
typedef union auxent
{
struct
{
int32 x_tagndx; /* str, un, or enum tag indx */
#define x_exptr x_tagndx /* exception table offset */
union
{
struct
{
uint16 x_lnno; /* declaration line number */
uint16 x_size; /* str, union, array size */
} x_lnsz;
int32 x_fsize; /* size of function */
} x_misc;
union
{
struct
{ /* if ISFCN, tag, or .bb */
int32 x_lnnoptr; /* ptr to fcn line # */
int32 x_endndx; /* entry ndx past block end */
} x_fcn;
struct
{ /* if ISARY, up to 4 dimen. */
uint16 x_dimen[DIMNUM];
} x_ary;
} x_fcnary;
uint16 x_tvndx; /* tv index */
} x_sym;
struct
{
struct
{
struct
{
int x_lnno;
} x_lnsz;
} x_misc;
char pad[13];
char x_auxtype;
} x_sym64;
union
{
char x_fname[FILNMLEN];
struct
{
uint32 x_zeroes;
uint32 x_offset;
} _x;
} x_file;
struct
{
int32 x_scnlen; /* section length */
uint16 x_nreloc; /* number of relocation entries */
uint16 x_nlinno; /* number of line numbers */
uint32 x_chksum; /* checksumm for comdat's */
uint16 x_asscnt; /* section number to associate with */
uchar x_select; /* comdat selection type */
#define SSEL_NODUPL 1 // no duplicate
#define SSEL_ANY 2 // select any
#define SSEL_SIZE 3
#define SSEL_EXACT 4 // by checksumm
#define SSEL_ASSOC 5 // associative
#define SSEL_LARGEST 6
#define SSEL_NEWEST 7
uchar __align__; /* for COFF+ only */
uint16 x_asscnt_hi; /* for COFF+ only - hi part of x_asscnt */
} x_scn; // always <= sizeof(SYMENT) :)
struct
{
int32 x_tvfill; /* tv fill value */
uint16 x_tvlen; /* length of .tv */
uint16 x_tvran[2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
/******************************************
* RS/6000-specific auxent - last auxent for every external symbol
******************************************/
struct
{
int32 x_scnlen; /* csect length */
int32 x_parmhash; /* parm type hash index */
uint16 x_snhash; /* sect num with parm hash */
uchar x_smtyp; /* symbol align and type */
/* 0-4 - Log 2 of alignment */
/* 5-7 - symbol type */
#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */
#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */
/* Symbol type values: */
#define XTY_ER 0 /* External reference */
#define XTY_SD 1 /* Csect definition */
#define XTY_LD 2 /* Label definition */
#define XTY_CM 3 /* .BSS */
#define XTY_EM 4 /* Error message */
#define XTY_US 5 /* "Reserved for internal use" */
uchar x_smclas; /* storage mapping class */
#define XMC_PR 0 /* Read-only program code */
#define XMC_RO 1 /* Read-only constant */
#define XMC_DB 2 /* Read-only debug dictionary table */
#define XMC_TC 3 /* Read-write general TOC entry */
#define XMC_UA 4 /* Read-write unclassified */
#define XMC_RW 5 /* Read-write data */
#define XMC_GL 6 /* Read-only global linkage */
#define XMC_XO 7 /* Read-only extended operation */
#define XMC_SV 8 /* Read-only supervisor call */
#define XMC_BS 9 /* Read-write BSS */
#define XMC_DS 10 /* Read-write descriptor csect */
#define XMC_UC 11 /* Read-write unnamed Fortran common */
#define XMC_TI 12 /* Read-only traceback index csect */
#define XMC_TB 13 /* Read-only traceback table csect */
/* 14 ??? */
#define XMC_TC0 15 /* Read-write TOC anchor */
#define XMC_TD 16 /* Read-write data in TOC */
int32 x_stab; /* dbx stab info index */
uint16 x_snstab; /* sect num with dbx stab */
} x_csect; /* csect definition information */\
/* XCOFF64 _csect */
struct
{
uint32 x_scnlen_lo;
int32 x_parmhash;
uint16 x_snhash;
uchar x_smtyp;
uchar x_smclas;
#define XMC_SV64 17
#define XMC_SV2364 18
int32 x_scnlen_hi;
char pad;
char x_auxtype;
} x_csect64;
/******************************************
* I960-specific *2nd* aux. entry formats
******************************************/
struct
{
#define x_stdindx x_stindx /* This is a very old typo that keeps getting propagated. */
int32 x_stindx; /* sys. table entry */
} x_sc; /* system call entry */
struct
{
uint32 x_balntry; /* BAL entry point */
} x_bal; /* BAL-callable function */
} AUXENT;
/* Defines for "special" symbols */
#if vax
#define _ETEXT "_etext"
#define _EDATA "_edata"
#define _END "_end"
#else
#define _ETEXT "etext"
#define _EDATA "edata"
#define _END "end"
#endif
#define _START "_start"
//================================================================================
// ECOFF symbols
//================================================================================
#define estNil 0 /* Nuthin' special */
#define estGlobal 1 /* external symbol */
#define estStatic 2 /* static */
#define estParam 3 /* procedure argument */
#define estLocal 4 /* local variable */
#define estLabel 5 /* label */
#define estProc 6 /* " " Procedure */
#define estBlock 7 /* beginnning of block */
#define estEnd 8 /* end (of anything) */
#define estMember 9 /* member (of anything - struct/union/enum */
#define estTypedef 10 /* type definition */
#define estFile 11 /* file name */
#define estRegReloc 12 /* register relocation */
#define estForward 13 /* forwarding address */
#define estStaticProc 14 /* load time only static procs */
#define estConstant 15 /* const */
#define estStaParam 16 /* Fortran static parameters */
/* These new symbol types have been recently added to SGI machines. */
#define estStruct 26 /* Beginning of block defining a struct type */
#define estUnion 27 /* Beginning of block defining a union type */
#define estEnum 28 /* Beginning of block defining an enum type */
#define estIndirect 34 /* Indirect type specification */
/* Pseudo-symbols - internal to debugger */
#define estStr 60 /* string */
#define estNumber 61 /* pure number (ie. 4 NOR 2+2) */
#define estExpr 62 /* 2+2 vs. 4 */
#define estType 63 /* post-coersion SER */
#define estMax 64
#define escNil 0
#define escText 1 /* text symbol */
#define escData 2 /* initialized data symbol */
#define escBss 3 /* un-initialized data symbol */
#define escRegister 4 /* value of symbol is register number */
#define escAbs 5 /* value of symbol is absolute */
#define escUndefined 6 /* who knows? */
#define escCdbLocal 7 /* variable's value is IN se->va.?? */
#define escBits 8 /* this is a bit field */
#define escCdbSystem 9 /* variable's value is IN CDB's address space */
#define escDbx 9 /* overlap dbx internal use */
#define escRegImage 10 /* register value saved on stack */
#define escInfo 11 /* symbol contains debugger information */
#define escUserStruct 12 /* address in struct user for current process */
#define escSData 13 /* load time only small data */
#define escSBss 14 /* load time only small common */
#define escRData 15 /* load time only read only data */
#define escVar 16 /* Var parameter (fortran,pascal) */
#define escCommon 17 /* common variable */
#define escSCommon 18 /* small common */
#define escVarRegister 19 /* Var parameter in a register */
#define escVariant 20 /* Variant record */
#define escSUndefined 21 /* small undefined(external) data */
#define escInit 22 /* .init section symbol */
#define escBasedVar 23 /* Fortran or PL/1 ptr based var */
#define escXData 24 /* exception handling data */
#define escPData 25 /* Procedure section */
#define escFini 26 /* .fini section */
#define escRConst 27 /* .rconst section */
#define escMax 32
struct ecoff_hdr
{
uint16 magic;
#define ECOFF_SYM_MAGIC 0x1992
uint16 vstamp;
uint32 ilineMax;
uint32 idnMax;
uint32 ipdMax;
uint32 isymMax;
uint32 ioptMax;
uint32 iauxMax;
uint32 issMax;
uint32 issExtMax;
uint32 ifdMax;
uint32 crfd;
uint32 iextMax;
uint64 cbLine;
uint64 cbLineOffset;
uint64 cbDnOffset;
uint64 cbPdOffset;
uint64 cbSymOffset;
uint64 cbOptOffset;
uint64 cbAuxOffset;
uint64 cbSsOffset;
uint64 cbSsExtOffset;
uint64 cbFdOffset;
uint64 cbRfdOffset;
uint64 cbExtOffset;
};
struct ecoff_fdr
{
uint64 f_adr;
uint64 f_cbLineOffset;
uint64 f_cbLine;
uint64 f_cbSs;
uint32 f_rss;
uint32 f_issBase;
uint32 f_isymBase;
uint32 f_csym;
uint32 f_ilineBase;
uint32 f_cline;
uint32 f_ioptBase;
uint32 f_copt;
uint32 f_ipdFirst;
uint32 f_cpd;
uint32 f_iauxBase;
uint32 f_caux;
uint32 f_rfdBase;
uint32 f_crfd;
uchar f_bits1;
uchar f_bits2[3];
uchar f_padding[4];
};
/* Procedure descriptor external record */
struct ecoff_pdr
{
uint64 adr;
uint64 cbLineOffset;
uint32 isym;
uint32 iline;
uint32 regmask;
uint32 regoffset;
uint32 iopt;
uint32 fregmask;
uint32 fregoffset;
uint32 frameoffset;
uint32 lnLow;
uint32 lnHigh;
uchar gp_prologue;
uchar bits1;
uchar bits2;
uchar localoff;
uint16 framereg;
uint16 pcreg;
};
/* Line numbers */
struct ecoff_line
{
uint32 l_line;
};
/* Symbol external record */
#define SYM_BITS1_ST_BIG 0xFC
#define SYM_BITS1_ST_SH_BIG 2
#define SYM_BITS1_ST_LITTLE 0x3F
#define SYM_BITS1_ST_SH_LITTLE 0
#define SYM_BITS1_SC_BIG 0x03
#define SYM_BITS1_SC_SH_LEFT_BIG 3
#define SYM_BITS1_SC_LITTLE 0xC0
#define SYM_BITS1_SC_SH_LITTLE 6
#define SYM_BITS2_SC_BIG 0xE0
#define SYM_BITS2_SC_SH_BIG 5
#define SYM_BITS2_SC_LITTLE 0x07
#define SYM_BITS2_SC_SH_LEFT_LITTLE 2
#define SYM_BITS2_RESERVED_BIG 0x10
#define SYM_BITS2_RESERVED_LITTLE 0x08
#define SYM_BITS2_INDEX_BIG 0x0F
#define SYM_BITS2_INDEX_SH_LEFT_BIG 16
#define SYM_BITS2_INDEX_LITTLE 0xF0
#define SYM_BITS2_INDEX_SH_LITTLE 4
#define SYM_BITS3_INDEX_SH_LEFT_BIG 8
#define SYM_BITS3_INDEX_SH_LEFT_LITTLE 4
#define SYM_BITS4_INDEX_SH_LEFT_BIG 0
#define SYM_BITS4_INDEX_SH_LEFT_LITTLE 12
struct ecoff_sym
{
uint64 s_value;
uint32 s_iss;
uchar s_bits1;
uchar s_bits2;
uchar s_bits3;
uchar s_bits4;
uchar st(bool mf)
{
return mf
? ((s_bits1 & SYM_BITS1_ST_BIG ) >> SYM_BITS1_ST_SH_BIG)
: ((s_bits1 & SYM_BITS1_ST_LITTLE) >> SYM_BITS1_ST_SH_LITTLE);
}
uchar sc(bool mf)
{
return mf
? (((s_bits1 & SYM_BITS1_SC_BIG ) << SYM_BITS1_SC_SH_LEFT_BIG)
| ((s_bits2 & SYM_BITS2_SC_BIG ) >> SYM_BITS2_SC_SH_BIG))
: (((s_bits1 & SYM_BITS1_SC_LITTLE) >> SYM_BITS1_SC_SH_LITTLE)
| ((s_bits2 & SYM_BITS2_SC_LITTLE) << SYM_BITS2_SC_SH_LEFT_LITTLE));
}
uint32 index(bool mf)
{
return mf
? (((s_bits2 & SYM_BITS2_INDEX_BIG) << SYM_BITS2_INDEX_SH_LEFT_BIG)
| (s_bits3 << SYM_BITS3_INDEX_SH_LEFT_BIG)
| (s_bits4 << SYM_BITS4_INDEX_SH_LEFT_BIG))
: (((s_bits2 & SYM_BITS2_INDEX_LITTLE) >> SYM_BITS2_INDEX_SH_LITTLE)
| (s_bits3 << SYM_BITS3_INDEX_SH_LEFT_LITTLE)
| (s_bits4 << SYM_BITS4_INDEX_SH_LEFT_LITTLE));
}
};
/* The auxiliary type information is the same on all known ECOFF
targets. The internal forms are
defined in coff/sym.h, which was originally donated by MIPS
Computer Systems. */
/* Type information external record */
struct ecoff_tir
{
uchar t_bits1;
uchar t_tq45;
uchar t_tq01;
uchar t_tq23;
bool fBitfield(bool mf) { return (t_bits1 & (mf ? 0x80 : 0x01)) != 0; }
bool continued(bool mf) { return (t_bits1 & (mf ? 0x40 : 0x02)) != 0; }
uchar bt(bool mf) { return mf ? (t_bits1 & 0x3F) >> 0 : (t_bits1 & 0xFC) >> 2; }
uchar tq4(bool mf) { return mf ? (t_tq45 & 0xF0) >> 4 : (t_tq45 & 0x0F) >> 0; }
uchar tq5(bool mf) { return mf ? (t_tq45 & 0x0F) >> 0 : (t_tq45 & 0xF0) >> 4; }
uchar tq0(bool mf) { return mf ? (t_tq01 & 0xF0) >> 4 : (t_tq01 & 0x0F) >> 0; }
uchar tq1(bool mf) { return mf ? (t_tq01 & 0x0F) >> 0 : (t_tq01 & 0xF0) >> 4; }
uchar tq2(bool mf) { return mf ? (t_tq23 & 0xF0) >> 4 : (t_tq23 & 0x0F) >> 0; }
uchar tq3(bool mf) { return mf ? (t_tq23 & 0x0F) >> 0 : (t_tq23 & 0xF0) >> 4; }
};
/* Relative symbol external record */
struct ecoff_rndx
{
uchar r_bits[4];
uint16 rfd(bool mf)
{
return mf
? (r_bits[0] << 4) | ((r_bits[1] & 0xF0) >> 4)
: (r_bits[0] << 0) | ((r_bits[1] & 0x0F) << 8);
}
uint32 index(bool mf)
{
return mf
? ((r_bits[1] & 0x0F) << 16)
| (r_bits[2] << 8)
| (r_bits[3] << 0)
: ((r_bits[1] & 0xF0) >> 4)
| (r_bits[2] << 4)
| (r_bits[3] << 12);
}
};
/* Auxiliary symbol information external record */
union ecoff_aux
{
ecoff_tir a_ti;
ecoff_rndx a_rndx;
uint32 a_dnLow;
uint32 a_dnHigh;
uint32 a_isym;
uint32 a_iss;
uint32 a_width;
uint32 a_count;
};
/* External symbol external record */
struct ecoff_ext
{
ecoff_sym es_asym;
uchar es_bits1;
uchar es_bits2[3];
uint32 es_ifd;
};
/* Dense numbers external record */
struct ecoff_dnr
{
uint32 d_rfd;
uint32 d_index;
};
/* Relative file descriptor */
struct ecoff_rfd
{
uint32 rfd;
};
/* Optimizer symbol external record */
struct ecoff_opt
{
uchar o_bits1;
uchar o_bits2;
uchar o_bits3;
uchar o_bits4;
ecoff_rndx o_rndx;
uint32 o_offset;
uchar ot(void) { return o_bits1; }
uint32 value(bool mf)
{
return mf
? ((uint32(o_bits2) << 16)
| (uint32(o_bits3) << 8)
| (uint32(o_bits4) << 0))
: ((uint32(o_bits2) << 0)
| (uint32(o_bits3) << 8)
| (uint32(o_bits4) << 16));
}
};
//---------------------------------------------------------------------------
// MIPS symbolic information
//---------------------------------------------------------------------------
struct mips_ecoff_hdr
{
uint16 magic;
#define MIPS_SYM_MAGIC 0x7002
uint16 vstamp;
uint32 ilineMax;
uint32 cbLine;
uint32 cbLineOffset;
uint32 idnMax;
uint32 cbDnOffset;
uint32 ipdMax;
uint32 cbPdOffset;
uint32 isymMax;
uint32 cbSymOffset;
uint32 ioptMax;
uint32 cbOptOffset;
uint32 iauxMax;
uint32 cbAuxOffset;
uint32 issMax;
uint32 cbSsOffset;
uint32 issExtMax;
uint32 cbSsExtOffset;
uint32 ifdMax;
uint32 cbFdOffset;
uint32 crfd;
uint32 cbRfdOffset;
uint32 iextMax;
uint32 cbExtOffset;
};
struct mips_ecoff_fdr
{
uint32 f_adr;
uint32 f_rss;
uint32 f_issBase;
uint32 f_cbSs;
uint32 f_isymBase;
uint32 f_csym;
uint32 f_ilineBase;
uint32 f_cline;
uint32 f_ioptBase;
uint32 f_copt;
uint16 f_ipdFirst;
uint16 f_cpd;
uint32 f_iauxBase;
uint32 f_caux;
uint32 f_rfdBase;
uint32 f_crfd;
uchar f_bits1;
uchar f_bits2[3];
uint32 f_cbLineOffset;
uint32 f_cbLine;
};
/* Procedure descriptor external record */
struct mips_ecoff_pdr
{
uint32 adr;
uint32 isym;
uint32 iline;
uint32 regmask;
uint32 regoffset;
uint32 iopt;
uint32 fregmask;
uint32 fregoffset;
uint32 frameoffset;
uint16 framereg;
uint16 pcreg;
uint32 lnLow;
uint32 lnHigh;
uint32 cbLineOffset;
};
/* Line numbers */
struct mips_ecoff_line
{
uint32 l_line;
};
/* Symbol external record */
struct mips_ecoff_sym
{
uint32 s_iss;
uint32 s_value;
uchar s_bits1;
uchar s_bits2;
uchar s_bits3;
uchar s_bits4;
uchar st(bool mf)
{
return mf
? ((s_bits1 & SYM_BITS1_ST_BIG ) >> SYM_BITS1_ST_SH_BIG)
: ((s_bits1 & SYM_BITS1_ST_LITTLE) >> SYM_BITS1_ST_SH_LITTLE);
}
uchar sc(bool mf)
{
return mf
? (((s_bits1 & SYM_BITS1_SC_BIG ) << SYM_BITS1_SC_SH_LEFT_BIG)
| ((s_bits2 & SYM_BITS2_SC_BIG ) >> SYM_BITS2_SC_SH_BIG))
: (((s_bits1 & SYM_BITS1_SC_LITTLE) >> SYM_BITS1_SC_SH_LITTLE)
| ((s_bits2 & SYM_BITS2_SC_LITTLE) << SYM_BITS2_SC_SH_LEFT_LITTLE));
}
uint32 index(bool mf)
{
return mf
? (((s_bits2 & SYM_BITS2_INDEX_BIG) << SYM_BITS2_INDEX_SH_LEFT_BIG)
| (s_bits3 << SYM_BITS3_INDEX_SH_LEFT_BIG)
| (s_bits4 << SYM_BITS4_INDEX_SH_LEFT_BIG))
: (((s_bits2 & SYM_BITS2_INDEX_LITTLE) >> SYM_BITS2_INDEX_SH_LITTLE)
| (s_bits3 << SYM_BITS3_INDEX_SH_LEFT_LITTLE)
| (s_bits4 << SYM_BITS4_INDEX_SH_LEFT_LITTLE));
}
};
#define mips_ecoff_aux ecoff_aux
/* External symbol external record */
struct mips_ecoff_ext
{
uchar es_bits1;
uchar es_bits2;
uint16 es_ifd;
mips_ecoff_sym es_asym;
};
#define mips_ecoff_dnr ecoff_dnr
#define mips_ecoff_rfd ecoff_rfd
#define mips_ecoff_opt ecoff_opt
/* segment information */
struct ic_seginfo_t
{
const ida_sym_t *sym = nullptr; // comdat symbol
ea_t start = BADADDR; // segment start address, BADADDR - not loaded
adiff_t delta = 0; // difference between the loaded address
// and address in the file
ea_t paddr = 0; // s_paddr from the segment descriptor
};
DECLARE_TYPE_AS_MOVABLE(ic_seginfo_t);
struct ic_seginfos_t : public qvector<ic_seginfo_t> {};
//----------------------------------------------------------------------
inline bool is_arm_switcher(const char *name)
{
return strncmp(name, "$CODE", 5) == 0
&& (name[5] == '1' || name[5] == '3')
&& (name[6] == '6' || name[6] == '2')
&& name[7] == '\0';
}
struct i960_sym_t;
struct coff_sym_ex_t;
struct ida_filhdr_t;
struct ida_scnhdr_t;
//----------------------------------------------------------------------
class ida_syms_t
{
struct coff_vars_t &ctx;
qstring str_table; // standard COFF string table (includes size in first 4 bytes)
qstring dtable; // XCOFF debug table (does not include size)
void from_coff960(const i960_sym_t *pc, uint nsyms, bool coff_hdr_mf);
void from_bigcoff(const coff_sym_ex_t *pc, uint nsyms, bool coff_hdr_mf);
void from_xcoff64(const coff_sym64_t *pc, uint nsyms, bool coff_hdr_mf);
void from_coffsym(const coff_sym_t *pc, uint nsyms, bool coff_hdr_mf);
public:
qvector<ida_sym_t> symtab;
ida_syms_t(coff_vars_t &_ctx) : ctx(_ctx) {}
bool str_table_from_file(linput_t *li, bool coff_hdr_mf);
bool str_table_from_mem(const void *buf, size_t bufsize, bool coff_hdr_mf);
bool load_from_file(
linput_t *li,
const ida_filhdr_t &fh,
bool coff_hdr_mf);
bool load_from_mem(const void *symbuf, size_t bufsize, uint32 nsyms, bool coff_hdr_mf);
#if !defined(COMPILE_DBG_LOADER)
void load_xcoff_debug_table(linput_t *li, const qvector<ida_scnhdr_t> &sechdrs);
#endif
const ida_sym_t *load_external_coff_symbols(linput_t *li, ida_filhdr_t &hf, bool mf);
void qclear()
{
str_table.qclear();
dtable.qclear();
symtab.qclear();
}
void copy_from_str_table(char *buf, size_t bufsz, uint32 off, bool use_dtable = false) const;
const char *get_segment_name(const char *name, size_t fixlen, char *buffer, size_t bufsize, uint32 f_magic) const;
bool getaux(uint symidx, AUXENT &aux, uint &n_aux) const;
char *getname(uint symidx, char *buf, size_t bufsize) const;
};
#pragma pack(pop)
#endif /* _H_SYMS */

1310
idasdk76/ldr/dos/cv.hpp Normal file

File diff suppressed because it is too large Load Diff

762
idasdk76/ldr/dos/dos.cpp Normal file
View File

@@ -0,0 +1,762 @@
/*
* This Loader Module is written by Ilfak Guilfanov and
* rewriten by Yury Haron
*
*/
/*
L O A D E R for MS-DOS file format's
*/
#include "../idaldr.h"
#include <exehdr.h>
#include <setjmp.h>
#include <typeinf.hpp>
#include "dos_ovr.h"
#include "cv.hpp"
static const char fn_ovr[] = "MS-DOS executable (perhaps overlayed)",
fn_exe[] = "MS-DOS executable (EXE)",
fn_drv[] = "MS-DOS SYS-file (perhaps device driver)";
const char e_exe[] = "exe";
static jmp_buf jmpb;
#define R_ss 18 // this comes from intel.hpp
//--------------------------------------------------------------------------
//
// 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 *filename)
{
static int order = 0;
if ( order >= 4 )
return 0;
uint32 fLen = qlsize(li);
const char *file_ext = get_file_ext(filename);
if ( file_ext == NULL )
file_ext = "";
exehdr E;
*processor = "metapc";
switch ( order )
{
case 0:
if ( fLen <= sizeof(E) )
{
order = 3; // check for com
break;
}
CASSERT(sizeof(E) >= 16);
lread(li, &E, sizeof(E));
if ( E.exe_ident != EXE_ID && E.exe_ident != EXE_ID2
|| E.HdrSize*16 < sizeof(E) )
{
order = 2; // check for drv
break;
}
if ( fLen < E.HdrSize*16 )
return 0;
if ( E.ReloCnt != 0 )
{
if ( E.TablOff + (E.ReloCnt*4) > fLen
|| E.TablOff != 0 && E.TablOff < sizeof(E)
|| E.TablOff == 0 )
{
return 0;
}
}
if ( E.CalcEXE_Length() < fLen - E.HdrSize*16
&& PrepareOverlayType(li, &E) != ovr_noexe )
{
*fileformatname = fn_ovr;
++order;
return f_EXE | ACCEPT_CONTINUE;
}
// no break
case 1:
*fileformatname = fn_exe;
order = 5; // done
return f_EXE;
case 2:
case 3:
break;
default:
return 0;
}
if ( ++order == 3 )
{
if ( strieq(file_ext, "sys") || strieq(file_ext, "drv") )
{
*fileformatname = fn_drv;
return f_DRV | ACCEPT_CONTINUE;
}
order++; // 4
}
if ( strieq(file_ext, "com") )
{ // com files must be readable
// on wince, file .exe files are unreadable. we do not want them to
// be detected as com files
qlseek(li, 0);
if ( qlread(li, &fLen, 1) == 1 )
{
*fileformatname = "MS-DOS COM-file";
return f_COM;
}
}
return 0;
}
//-------------------------------------------------------------------------
NORETURN void errstruct(void)
{
if ( ask_yn(ASKBTN_CANCEL,
"HIDECANCEL\n"
"Bad file structure or read error.\n"
"Proceed with the loaded infomration?") <= ASKBTN_NO )
{
loader_failure();
}
longjmp(jmpb, 1);
#ifdef __CODEGEARC__
exit(0); // suppress compiler error
#endif
}
//-------------------------------------------------------------------------
int CheckCtrlBrk(void)
{
if ( user_cancelled() )
{
if ( ask_yn(ASKBTN_NO,
"HIDECANCEL\n"
"Do you really want to abort loading?") > ASKBTN_NO )
{
loader_failure();
}
clr_cancelled();
return 1;
}
return 0;
}
//-------------------------------------------------------------------------
void add_segm_by_selector(sel_t base, const char *sclass)
{
segment_t *ptr = get_segm_by_sel(base);
if ( ptr == NULL || ptr->sel != base )
{
ea_t ea = sel2ea(base);
if ( ea > inf_get_omax_ea() )
inf_set_omax_ea(ea);
segment_t s;
s.sel = base;
s.start_ea = sel2ea(base);
s.end_ea = inf_get_omax_ea();
s.align = saRelByte;
s.comb = sclass != NULL && strcmp(sclass, "STACK") == 0 ? scStack : scPub;
add_segm_ex(&s, NULL, sclass, ADDSEG_SPARSE | ADDSEG_NOSREG);
}
}
//-------------------------------------------------------------------------
//
// For all addresses in relocation table:
// add 'delta'
// if ( dosegs ) then make segments
//
static void doRelocs(int16 delta, bool dosegs, netnode ovr_info)
{
if ( ovr_info == BADNODE )
return;
fixup_data_t fd(FIXUP_SEG16);
for ( ea_t xEA = ovr_info.altfirst(); xEA != BADADDR; xEA = ovr_info.altnext(xEA) )
{
show_addr(xEA);
uint16 curval = get_word(xEA);
uint16 base = curval + delta;
if ( base < curval && delta > 0 )
{
ask_for_feedback("%a: fixup overflow; skipping fixup processing", xEA);
break;
}
put_word(xEA, base);
fd.sel = base;
fd.set(xEA);
if ( dosegs )
add_segm_by_selector(base, NULL);
CheckCtrlBrk();
}
}
//--------------------------------------------------------------------------
static void create_msdos_segments(bool com_mode, netnode ovr_info)
{
// msg("Creating segments...\n");
add_segm_by_selector(find_selector(inf_get_start_cs()), CLASS_CODE);
if ( com_mode ) // COM/DRV
{
set_segm_start(inf_get_omin_ea(), inf_get_omin_ea(), SEGMOD_KILL);
inf_set_min_ea(inf_get_omin_ea());
segment_t *s = getseg(inf_get_min_ea());
if ( s )
{
s->set_comorg(); // i display ORG directive
s->update();
}
}
if ( inf_get_start_ss() != BADSEL && inf_get_start_ss() != inf_get_start_cs() )
add_segm_by_selector(inf_get_start_ss(), CLASS_STACK);
else // specify the sp value for the first segment
set_default_sreg_value(get_segm_by_sel(inf_get_start_cs()), R_ss, inf_get_start_cs());
doRelocs(inf_get_baseaddr(), true, ovr_info);
ea_t ea = inf_get_omin_ea();
ea_t omea = inf_get_omax_ea();
for ( int i = 0; ea < omea; )
{
segment_t *sptr = getnseg(i);
if ( sptr == NULL || ea < sptr->start_ea )
{
msg("Dummy segment at 0x%a (next segment at 0x%a)\n",
ea,
sptr == NULL ? BADADDR : sptr->start_ea);
add_segm_by_selector(unsigned(ea>>4), "DUMMY");
}
else
{
ea = sptr->end_ea;
if ( !is_mapped(ea) )
ea = next_addr(ea);
++i;
}
}
}
//--------------------------------------------------------------------------
bool pos_read(linput_t *li, uint32 pos, void *buf, size_t size)
{
qlseek(li, pos);
return qlread(li, buf, size) != size;
}
//--------------------------------------------------------------------------
static ea_t FindDseg(void)
{
ea_t dea = to_ea(inf_get_start_cs(), inf_get_start_ip());
if ( get_byte(dea) == 0x9A ) // call far
{
dea = to_ea(sel2para(get_word(dea+3)), get_word(dea+1));
inf_set_strtype(STRTYPE_PASCAL);
}
//
// Borland startup
//
uchar code = get_byte(dea);
uchar reg = code & 7;
if ( (code & ~7) == 0xB8 // mov reg, ????
&& ((get_byte(dea+3) == 0x8E
&& ((code=get_byte(dea+4)) & ~7) == 0xD8 // mov ds, reg
&& (code & 7) == reg)
|| (get_byte(dea+3) == 0x2E // mov cs:@DGROUP, reg
&& get_byte(dea+4) == 0x89
&& ((code = get_byte(dea+5)) & 0x8F) == 6
&& ((code>>3) & 7) == reg)) )
{
segment_t *s = get_segm_by_sel(get_word(dea + 1));
return s == NULL ? BADADDR : s->start_ea;
}
//
// Watcom startup
//
if ( get_byte(dea) == 0xE9 ) // jmp ???
{
dea = dea + 3 + get_word(dea + 1);
if ( get_byte(dea + 0) == 0xFB // sti
&& get_byte(dea + 1) == 0xB9 ) // mov cx, ???
{
segment_t *s = get_segm_by_sel(get_word(dea + 2));
return s == NULL ? BADADDR : s->start_ea;
}
}
//
// Generic: find copyright notice
//
static const char *const copyr[] =
{
" - Copyright",
// "Borland C++ - Copyright 1991 Borland Intl.",
// "Turbo-C - Copyright (c) 1988 Borland Intl.",
// "Turbo C - Copyright 1989 Borland Intl.",
// "Turbo C++ - Copyright 1990 Borland Intl.",
// "MS Run-Time Library - Copyright (c)",
NULL
};
for ( const char *const *p = copyr; *p != NULL; ++p )
{
msg("Looking for '%s'...\n", *p);
ea_t dataea = bin_search2(inf_get_min_ea(),
inf_get_max_ea(),
(uchar *)*p,
NULL,
strlen(*p),
BIN_SEARCH_CASE|BIN_SEARCH_FORWARD);
if ( dataea != BADADDR )
return dataea;
}
return BADADDR;
}
//--------------------------------------------------------------------------
static void setup_default_ds_register(sel_t ds_value)
{
segment_t *dseg;
if ( ds_value != BADSEL )
{
dseg = get_segm_by_sel(ds_value);
goto setname;
}
msg("Searching for the data segment...\n");
switch ( inf_get_filetype() )
{
case f_EXE: // Find default data seg
{
ea_t dataea = FindDseg();
if ( dataea == BADADDR )
return;
dseg = getseg(dataea);
if ( dseg == NULL )
return;
}
dseg->align = saRelPara;
ds_value = dseg->sel;
setname:
set_segm_class(dseg, CLASS_DATA);
set_segm_name(dseg, "dseg");
break;
case f_COM:
ds_value = find_selector(inf_get_start_cs());
break;
default:
return;
}
msg("Default DS register: 0x%*a\n", 4, ds_value);
set_default_dataseg(ds_value);
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
void idaapi load_file(linput_t *li, ushort neflag, const char *fileformatname)
{
exehdr E;
netnode ovr_info = BADNODE;
volatile int type = 0; // volatile because of setjmp()
volatile sel_t dseg = BADSEL;
volatile o_type ovr_type = ovr_noexe;
processor_t &ph = PH;
if ( setjmp(jmpb) == 0 )
{
set_processor_type("metapc", SETPROC_LOADER);
type = strieq(fileformatname, fn_ovr) ? 3
: strieq(fileformatname, fn_exe) ? 2
: strieq(fileformatname, fn_drv) ? 1
: 0;
clr_cancelled();
uval_t start_off;
uval_t fcoresize;
cm_t cm = inf_get_cc_cm() & CM_CC_MASK;
if ( type < 2 ) // COM/DRV
{
inf_set_cc_cm(cm | C_PC_SMALL);
if ( !type ) // f_COM
{
inf_set_start_ip(0x100);
inf_set_min_ea(to_ea(inf_get_baseaddr(), inf_get_start_ip()));
}
else
{ // f_DRV
inf_set_start_ip(BADADDR);
inf_set_min_ea(to_ea(inf_get_baseaddr(), 0 /*binoff*/));
// binoff has no sense for COM/DRV
}
inf_set_start_cs(inf_get_baseaddr());
start_off = 0;
fcoresize = qlsize(li);
inf_set_max_ea(inf_get_min_ea() + fcoresize);
}
else
{ // EXE (/OVR)
inf_set_cc_cm(cm | C_PC_LARGE);
lread(li, &E, sizeof(E));
if ( !E.ReloCnt
&& ask_yn(ASKBTN_YES,
"HIDECANCEL\nPossibly packed file, continue?") <= ASKBTN_NO )
{
loader_failure();
}
inf_set_start_ss(E.ReloSS);
inf_set_start_cs(E.ReloCS);
inf_set_start_sp(E.ExeSP);
inf_set_start_ip(E.ExeIP);
// take into account pointers like FFF0:0100
// FFF0 should be treated as signed in this case
if ( inf_get_start_cs() >= 0xFFF0 || inf_get_start_ss() >= 0xFFF0 )
{
if ( inf_get_baseaddr() < 0x10 )
inf_set_baseaddr(0x10);
if ( inf_get_start_cs() >= 0xFFF0 )
inf_set_start_cs(short(inf_get_start_cs()));
if ( inf_get_start_ss() >= 0xFFF0 )
inf_set_start_ss(short(inf_get_start_ss()));
}
inf_set_start_ss(inf_get_start_ss() + inf_get_baseaddr());
inf_set_start_cs(inf_get_start_cs() + inf_get_baseaddr());
inf_set_min_ea(to_ea(inf_get_baseaddr(), 0));
fcoresize = E.CalcEXE_Length();
ovr_info.create(LDR_INFO_NODE);
ovr_info.set((char *)&E, sizeof(E));
// i Check for file size
uint32 fsize = qlsize(li) - E.HdrSize*16;
if ( fcoresize > fsize )
fcoresize = fsize;
if ( type == 2
&& fcoresize < fsize
&& ask_yn(ASKBTN_YES,
"HIDECANCEL\n"
"The input file has extra information at the end\n"
"(tail %Xh, loaded %ah), continue?",
fsize,
fcoresize) <= ASKBTN_NO )
{
loader_failure();
}
inf_set_max_ea(inf_get_min_ea() + fcoresize);
ea_t stackEA = to_ea(inf_get_start_ss(), inf_get_start_sp());
if ( inf_get_max_ea() < stackEA )
inf_set_max_ea(stackEA);
msg("Reading relocation table...\n");
if ( E.ReloCnt )
{
qlseek(li, E.TablOff);
for ( int i = 0; i < E.ReloCnt; ++i )
{
ushort buf[2];
lread(li, buf, sizeof(buf));
ea_t xEA = to_ea((ushort)(inf_get_baseaddr() + buf[1]), buf[0]); // we need ushort() here!
if ( xEA >= inf_get_max_ea() )
errstruct();
ovr_info.altset(xEA, 1);
}
}
start_off = E.HdrSize * 16;
// i preset variable for overlay loading
if ( type == 3 )
ovr_type = PrepareOverlayType(li, &E);
}
// next 2 strings for create_msdos_segments & CppOverlays
inf_set_omin_ea(inf_get_min_ea());
inf_set_omax_ea(inf_get_max_ea());
file2base(li, start_off, inf_get_min_ea(), inf_get_min_ea() + fcoresize,
FILEREG_PATCHABLE);
if ( ovr_type != ovr_cpp )
{
if ( type == 3 || (neflag & NEF_SEGS) )
create_msdos_segments((type <= 1), ovr_info);
else
doRelocs(inf_get_baseaddr(), false, ovr_info);
}
create_filename_cmt();
add_pgm_cmt("Base Address: %ah Range: %ah-%ah Loaded length: %ah",
inf_get_baseaddr(), inf_get_min_ea(), inf_get_max_ea(), fcoresize);
if ( type >= 2 )
{ // f_EXE
linput_t *volatile lio = NULL;
add_pgm_cmt("Entry Point : %a:%a", inf_get_start_cs(), inf_get_start_ip());
if ( type == 2 // && E.CalcEXE_Length() < qlsize(li) - E.HdrSize*16
&& (lio = CheckExternOverlays()) != NULL )
{
++type;
}
if ( type != 3 )
{
ovr_info.altset(-1, type); // EXE without overlays
}
else
{
switch ( ovr_type )
{
case ovr_pascal:
lio = li;
// fallthrough
case ovr_noexe:
LoadPascalOverlays(lio);
if ( ovr_type == ovr_noexe )
close_linput(lio);
break;
case ovr_cpp:
dseg = LoadCppOverlays(li);
doRelocs(inf_get_baseaddr(), false, ovr_info);
break;
case ovr_ms:
dseg = LoadMsOverlays(li, E.Overlay == 0);
break;
}
}
}
}
setup_default_ds_register(dseg); // former SRcreate()
if ( dseg != BADSEL && ovr_type == ovr_ms )
{
segment_t *s = get_segm_by_sel(find_selector(inf_get_start_cs()));
if ( s != NULL )
set_default_sreg_value(s, ph.reg_data_sreg, s->sel);
}
inf_set_start_ea((inf_get_start_ip() == BADADDR)
? BADADDR
: to_ea(sel2para(inf_get_start_cs()), inf_get_start_ip()));
if ( inf_get_start_ip() != BADADDR )
{
uval_t val;
if ( type < 2 )
val = find_selector(inf_get_start_cs()); // COM/DRV
else if ( get_str_type_code(inf_get_strtype()) == STRTYPE_PASCAL )
val = get_sreg(inf_get_start_ea(), ph.reg_data_sreg); // i set in [srareaovl.cpp]FindDseg
else
val = inf_get_baseaddr() - 0x10;
split_sreg_range(inf_get_start_ea(), ph.reg_data_sreg, val, SR_autostart, true);
}
if ( inf_get_filetype() == f_COM )
{
inf_set_lowoff(0x100);
}
else
{
// check for the debug information
char debug_magic[4];
qlseek(li, -8, SEEK_END);
lread(li, debug_magic, 4);
if ( is_codeview_magic(debug_magic) )
load_dbg_dbginfo(NULL, li);
}
}
//--------------------------------------------------------------------------
static int expand_file(FILE *fp, uint32 pos)
{
// return chsize(li, pos) || qfseek(fp, pos, SEEK_SET);
// but qchsize(), which does not fill with zeroes.
uint32 curpos = qftell(fp);
QASSERT(20041, curpos <= pos);
while ( curpos < pos )
{
if ( qfputc(0, fp) == EOF )
return 0;
++curpos;
}
return 1;
}
//--------------------------------------------------------------------------
//
// generate binary file.
//
int idaapi save_file(FILE *fp, const char * /*fileformatname*/)
{
int retcode;
uint32 codeoff;
netnode ovr_info(LDR_INFO_NODE, 0, 0);
if ( fp == NULL )
return ovr_info == BADNODE || ovr_info.altval(-1) == 2;
if ( ovr_info != BADNODE ) // f_EXE
{
exehdr E;
ovr_info.valobj(&E, sizeof(E));
if ( qfwrite(fp, &E, sizeof(E)) != sizeof(E) )
return 0;
if ( E.ReloCnt )
{
if ( !expand_file(fp, E.TablOff) )
return 0;
for ( uval_t x = ovr_info.altfirst();
x != BADADDR;
x = ovr_info.altnext(x) )
{
ushort buf[2];
buf[1] = ushort((x >> 4) - inf_get_baseaddr());
buf[0] = ushort(x) & 0xF;
if ( qfwrite(fp, buf, sizeof(buf)) != sizeof(buf) )
return 0;
}
}
codeoff = E.HdrSize * 16;
if ( !expand_file(fp, codeoff) )
return 0;
}
else
{
codeoff = 0; // f_COM, f_DRV
}
doRelocs(-inf_get_baseaddr(), 0, ovr_info);
retcode = base2file(fp, codeoff, inf_get_omin_ea(), inf_get_omax_ea());
doRelocs(inf_get_baseaddr(), 0, ovr_info);
return retcode;
}
//----------------------------------------------------------------------
static int idaapi move_segm(ea_t from, ea_t to, asize_t /*size*/, const char * /*fileformatname*/)
{
// Before relocating, we need all of the relocation entries, which were
// part of the original executable file and consequently stored in our
// private loader node.
netnode ovr_info(LDR_INFO_NODE, 0, 0);
if ( ovr_info == BADNODE )
{
// Can't find our private loader node.
msg("Couldn't find dos.ldr node, assuming file has no relocations.\n");
return 1;
}
if ( from == BADADDR )
{
// The entire program is being rebased.
// In this case, 'to' actually contains a delta value; the number of bytes
// forward (positive) or backward (negative) that the whole database is
// being moved.
int32 delta = to;
// If the delta is not a multiple of 16 bytes, we can't reliably
// relocate the executable.
if ( (delta % 16) != 0 )
{
warning("DOS images can only be relocated to 16-byte boundaries.");
return 0;
}
// Fixup the relocation entry netnode. It contains entries that point
// to locations that needed fixups when the image was located at its
// old address. Change the entries so that they point to the appropriate
// places in the new image location.
ea_t current_base = uint32(inf_get_baseaddr() << 4);
ea_t new_base = current_base + delta;
ovr_info.altshift(current_base, new_base, inf_get_privrange_start_ea());
// remember bases for later remapping of segment regs
std::map<ea_t, ea_t> segmap;
// Now that the relocation entries point to the correct spots, go fix
// those spots up so that they point to the correct places.
doRelocs(delta >> 4, false, ovr_info);
// IDA has adjusted all segment start and end addresses to cover their
// new effective address ranges, but we, the loader, must finish the
// job by rebasing each segment.
for ( int i = 0; i < get_segm_qty(); ++i )
{
segment_t *seg = getnseg(i);
ea_t curbase = get_segm_base(seg); // Returns base in EA
ea_t newbase = curbase + delta;
set_segm_base(seg, newbase >> 4); // Expects base in Paragraphs
segmap[curbase >> 4] = newbase >> 4;
seg->update();
}
// fix up segment registers
// rebase segment registers
processor_t &ph = PH;
for ( int sr = 0; sr < SREG_NUM; ++sr )
{
int sra_num = get_sreg_ranges_qty(ph.reg_first_sreg + sr);
for ( int i = 0; i < sra_num; ++i )
{
sreg_range_t sra;
if ( !getn_sreg_range(&sra, sr, i) )
break;
sel_t reg = sra.val;
if ( reg != BADSEL )
{
std::map<ea_t, ea_t>::const_iterator p = segmap.find(reg);
if ( p != segmap.end() )
split_sreg_range(sra.start_ea, ph.reg_first_sreg + sr, p->second, SR_auto, true);
}
}
}
// Record the new image base address.
inf_set_baseaddr(new_base >> 4);
set_imagebase(new_base);
}
return 1;
}
//----------------------------------------------------------------------
//
// LOADER DESCRIPTION BLOCK
//
//----------------------------------------------------------------------
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
// loader flags
0,
// 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.
save_file,
// take care of a moved segment (fix up relocations, for example)
move_segm,
NULL,
};

1068
idasdk76/ldr/dos/dos_ovr.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
/*
* Interactive disassembler (IDA).
* Version 3.00
* Copyright (c) 1990-94 by Ilfak Guilfanov. (2:5020/209@fidonet)
* ALL RIGHTS RESERVED.
*
*/
#ifndef _DOS_OVR_H_
#define _DOS_OVR_H_
// the following structures are 1-byte aligned (!)
#pragma pack(push,1)
struct fbov_t
{
ushort fb;
#define FB_MAGIC 0x4246
ushort ov;
#define OV_MAGIC 0x564F
uint32 ovrsize;
uint32 exeinfo;
int32 segnum;
};
struct seginfo_t
{
ushort seg;
ushort maxoff; // FFFF - unknown
ushort flags;
#define SI_COD 0x0001
#define SI_OVR 0x0002
#define SI_DAT 0x0004
ushort minoff;
};
struct stub_t
{
uchar CDh; // 0
uchar intnum; // 1
ushort memswap; // 2
int32 fileoff; // 4
ushort codesize; // 8
ushort relsize; // 10
ushort nentries; // 12
ushort prevstub; // 14
#define STUBUNK_SIZE (0x20-0x10)
uchar unknown[STUBUNK_SIZE];
};
struct ovrentry_t
{
ushort int3f;
ushort off;
char segc;
};
CASSERT(sizeof(ovrentry_t) == 5);
struct ms_entry
{
uchar CDh;
uchar intnum; // normally 3Fh
ushort ovr_index;
ushort entry_off;
};
bool pos_read(linput_t *fp, uint32 pos, void *buf, size_t size);
int CheckCtrlBrk(void);
void add_segm_by_selector(sel_t base, const char *sclass);
extern const char e_exe[];
//
enum o_type { ovr_noexe, ovr_pascal, ovr_cpp, ovr_ms };
o_type PrepareOverlayType(linput_t *fp, exehdr *E);
linput_t *CheckExternOverlays(void);
sel_t LoadCppOverlays(linput_t *fp);
sel_t LoadMsOverlays(linput_t *fp, bool PossibleDynamic);
void LoadPascalOverlays(linput_t *fp);
NORETURN void errstruct(void);
#pragma pack(pop)
#endif

24
idasdk76/ldr/dos/makefile Normal file
View File

@@ -0,0 +1,24 @@
PROC=dos
O1=dos_ovr
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)dos$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)exehdr.h \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaldr.h \
cv.hpp dos.cpp dos_ovr.h
$(F)dos_ovr$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)exehdr.h \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)struct.hpp $(I)ua.hpp $(I)xref.hpp ../idaldr.h \
dos_ovr.cpp dos_ovr.h

348
idasdk76/ldr/dump/dump.cpp Normal file
View File

@@ -0,0 +1,348 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2001 by Ilfak Guilfanov (ig@datarescue.com)
* http://www.datarescue.com
* ALL RIGHTS RESERVED.
*
*/
#include "../idaldr.h"
//--------------------------------------------------------------------------
static int make_words(char *line, char **words, int maxwords)
{
while ( qisspace(*line) )
line++;
int i;
for ( i=0; *line && i < maxwords; i++ )
{
words[i] = line;
while ( !qisspace(*line) && *line != '\0' )
line++;
if ( *line != '\0' )
*line++ = '\0';
while ( qisspace(*line) )
line++;
}
return i;
}
//--------------------------------------------------------------------------
inline uint32 hex(char *&word)
{
return strtoul(word, &word, 16);
}
//--------------------------------------------------------------------------
inline uint32 oct(char *&word)
{
return strtoul(word, &word, 8);
}
#define FAILED \
do \
{ \
deb(IDA_DEBUG_LDR, \
"failed at %d (input file line %d)\n", \
__LINE__, \
nl); \
return 0; \
} while ( false )
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *,
linput_t *li,
const char *)
{
char line[MAXSTR];
char *words[MAXSTR];
// We try to interpret the input file as a text
// file with a dump format, i.e. all lines should look like
// 00000020: 59 69 74 54-55 B6 3E F7-D6 B9 C9 B9-45 E6 A4 52
// 0020: 59 69 74 54 55 B6 3E F7 D6 B9 C9 B9 45 E6 A4 52
// 1000: 12 23 34 56 78
// 0100: 31 C7 1D AF 32 04 1E 32 05 1E 3C 32 07 1E 21 D9
// 12 23 34 56 78
// and similar lines
// We allow non-ascii characters at the end of the line
// We skip empty lines
ssize_t p0len = -1; // length of the first word's hex part
char w0sep[10]; // separator after the first word
w0sep[0] = '\0';
int nl = 0;
int nontrivial_line_count = 0;
bool no_more_lines = false;
bool has_star = false;
uint32 adr, oldadr=0;
while ( qlgets(line, sizeof(line), li) )
{
nl++;
strrpl(line, '-', ' ');
int nw = make_words(line, words, qnumber(words));
if ( line[0] == ';' || line[0] == '#' || nw == 0 )
{
if ( has_star )
FAILED;
continue;
}
if ( no_more_lines )
FAILED;
// od -x format may contain '*' lines which mean repetition
if ( strcmp(words[0], "*") == 0 && nw == 1 )
{
if ( nontrivial_line_count == 0 )
FAILED;
if ( has_star )
FAILED;
has_star = true;
continue;
}
has_star = false;
nontrivial_line_count++;
// the first word must be a number (more than one digit)
char *ptr = words[0];
adr = hex(ptr);
ssize_t p0 = ptr - words[0];
if ( p0 <= 1 || p0 > 16 )
FAILED;
if ( nontrivial_line_count > 1 && p0 < p0len )
FAILED;
p0len = p0;
// take the separator from the first line
if ( nontrivial_line_count == 1 )
{
qstrncpy(w0sep, ptr, sizeof(w0sep));
while ( *ptr )
if ( strchr(":>-.", *ptr++) == NULL )
FAILED;
}
else
{
if ( strcmp(w0sep, ptr) != 0 )
FAILED;
}
bool haspref = p0len >= 4 || w0sep[0] != '\0';
if ( haspref )
{
// if the line contains only the address, then don't accept lines anymore
if ( nw == 1 )
{
if ( nontrivial_line_count == 1 )
FAILED;
no_more_lines = true;
if ( adr <= oldadr )
FAILED;
}
else
{
// the remaining words should be numbers with at least 1 position
// (at least the second word should be so)
ptr = words[1];
hex(ptr);
if ( ptr == words[1] )
FAILED;
}
}
oldadr = adr;
}
if ( nontrivial_line_count == 0 || has_star )
FAILED;
*fileformatname = "Dump file";
return 1;
}
//--------------------------------------------------------------------------
static uchar bytes[MAXSTR/2];
static bool iscode;
static sel_t sel;
static ea_t sea;
static ea_t eea;
static ushort neflag;
static void copy(const ea_t ea, const ea_t top)
{
if ( sea == BADADDR )
{
if ( neflag & NEF_SEGS )
{
const char *sname = iscode ? "CODE" : "DATA";
sel = setup_selector(0);
add_segm(sel, ea, top, sname, sname);
}
sea = ea;
eea = top;
}
else
{
if ( eea < top )
{ // if the gap > 256KB, use sparse storage
int flags = top - eea > 256 * 1024 ? SEGMOD_SPARSE : 0;
eea = top;
set_segm_end(sea, eea, flags);
}
}
mem2base(bytes, ea, top, -1);
}
//--------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort _neflag, const char * /*fileformatname*/)
{
char line[MAXSTR];
char *words[MAXSTR];
neflag = _neflag;
iscode = (neflag & NEF_CODE) != 0;
sel = BADSEL;
sea = BADADDR;
ea_t ea = 0;
ea_t top= 0;
bool octpref = false;
bool octnum = false;
size_t fill = 0;
// Since we made all the checks in accept_file,
// here we don't repeat them
size_t max_p0len = 0;
char w0sep[10]; // separator after the first word
w0sep[0] = '\0';
int nontrivial_line_count = 0;
while ( qlgets(line, sizeof(line), li) )
{
strrpl(line, '-', ' ');
if ( line[0] == ';' || line[0] == '#' )
continue;
int n = make_words(line, words, qnumber(words));
if ( n == 0 )
continue;
nontrivial_line_count++;
ssize_t bi;
// od -x format may contain '*' lines which mean repetition
if ( strcmp(words[0], "*") == 0 && n == 1 )
{
fill = size_t(top - ea);
octpref = true; // od -x have octal prefixes
continue;
}
// the first word must be a number (more than one digit)
char *ptr = words[0];
uint32 w0 = octpref ? oct(ptr) : hex(ptr);
// length of the first word's hex part
size_t p0len = ptr - words[0];
if ( p0len > max_p0len )
max_p0len = p0len;
// take the separator from the first line
if ( nontrivial_line_count == 1 )
qstrncpy(w0sep, ptr, sizeof(w0sep));
// process '*' and fill the gap
if ( fill > 0 )
{
while ( top < w0 )
{
ea = top;
top = ea + fill;
copy(ea, top);
}
}
int idx = 0;
if ( w0sep[0] != '\0' || p0len >= 4 )
{
if ( nontrivial_line_count > 1 && !octpref && top != w0 )
{
// strange, the sequence is not contiguous
// check if the prefixes are octal (od -x)
ptr = words[0];
if ( oct(ptr) == top )
{
octpref = true;
ptr = words[0];
w0 = oct(ptr);
}
}
ea = w0;
idx = 1;
}
else
{
ea = top;
}
for ( bi=0; idx < n; idx++ ) //lint !e443
{
ptr = words[idx];
if ( nontrivial_line_count == 1 && !octnum && strlen(ptr) == 6 )
{
oct(ptr);
if ( ptr-words[idx] == 6 )
octnum = true;
ptr = words[idx];
// msg("ptr=%s octnum=%d\n", ptr, octnum);
}
uint32 b = octnum ? oct(ptr) : hex(ptr);
ssize_t nc = ptr - words[idx];
if ( nc < 2 )
{
// we tolerate one-letter separators between numbers
if ( words[idx][1] == '\0' && strchr("\xA6|-:", words[idx][0]) != NULL )
continue;
break;
}
nc /= octnum ? 3 : 2; // number of bytes
*(uint32 *)&bytes[bi] = b;
bi += nc;
}
top = ea + bi;
copy(ea, top);
}
if ( neflag & NEF_SEGS )
{
size_t bitness = eea >= 0x10000 || max_p0len > 4 ? 1 : 0; // 32/16
#ifdef __EA64__
if ( eea >= ea_t(0x100000000ull) || max_p0len > 8 )
bitness = 2; // 64
#endif
if ( bitness != 0 )
{
set_segm_addressing(getseg(sea), bitness);
inf_set_lflags(inf_get_lflags() | LFLG_PC_FLAT);
}
set_default_dataseg(sel);
}
if ( (neflag & NEF_RELOAD) == 0 )
create_filename_cmt();
}
//--------------------------------------------------------------------------
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
LDRF_REQ_PROC // requires the target processor to the set
| LDRF_RELOAD, // supports reloading the input file
//
// 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,
NULL,
NULL,
};

View File

@@ -0,0 +1,13 @@
PROC=dump
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)dump$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h dump.cpp

104
idasdk76/ldr/elf/common.cpp Normal file
View File

@@ -0,0 +1,104 @@
/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* E-mail: ig@datarescue.com
* ELF binary loader.
* Copyright (c) 1995-2006 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
* ALL RIGHTS RESERVED.
*
*/
#include <idp.hpp>
#include "elfbase.h"
//--------------------------------------------------------------------------
// Functions common for EFD & DEBUGGER
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
static bool dummy_error_handler(const reader_t &, reader_t::errcode_t, ...)
{
// ignore all errors
return true;
}
//--------------------------------------------------------------------------
bool is_elf_file(linput_t *li)
{
reader_t reader(li);
reader.set_handler(dummy_error_handler);
return reader.read_ident() && reader.read_header();
}
//--------------------------------------------------------------------------
inline bool can_be_solaris(reader_t &reader)
{
switch ( reader.get_header().e_machine )
{
case EM_SPARC:
case EM_SPARC32PLUS:
case EM_SPARC64:
case EM_386:
case EM_486:
case EM_X86_64:
return true;
}
return false;
}
//--------------------------------------------------------------------------
int elf_machine_2_proc_module_id(reader_t &reader)
{
int id = -1;
switch ( reader.get_header().e_machine )
{
#define CASE(E_ID, P_ID) case EM_##E_ID: id = PLFM_##P_ID; break
CASE(ARM, ARM);
CASE(SH, SH);
CASE(PPC, PPC);
CASE(PPC64, PPC);
CASE(860, I860);
CASE(68K, 68K);
CASE(MIPS, MIPS);
CASE(CISCO7200, MIPS);
CASE(CISCO3620, MIPS);
CASE(386, 386);
CASE(486, 386);
CASE(X86_64, 386);
CASE(SPARC, SPARC);
CASE(SPARC32PLUS, SPARC);
CASE(SPARC64, SPARC);
CASE(ALPHA, ALPHA);
CASE(IA64, IA64);
CASE(H8300, H8);
CASE(H8300H, H8);
CASE(H8S, H8);
CASE(H8500, H8);
CASE(V850, NEC_V850X);
CASE(NECV850, NEC_V850X);
CASE(PARISC, HPPA);
CASE(6811, 6800);
CASE(6812, MC6812);
CASE(I960, I960);
CASE(ARC, ARC);
CASE(ARCOMPACT, ARC);
CASE(ARC_COMPACT2, ARC);
CASE(M32R, M32R);
CASE(ST9, ST9);
CASE(FR, FR);
CASE(AVR, AVR);
CASE(SPU, SPU);
CASE(C166, C166);
CASE(M16C, M16C);
CASE(MN10200, MN102L00);
// CASE(MN10300, MN103L00); // FIXME: Dunno what to do, here.
// CASE(MCORE, MCORE); // FIXME: PLFM_MCORE still defined in mcore/reg.cpp
CASE(S390, S390);
#undef CASE
}
return id;
}

3249
idasdk76/ldr/elf/elf.h Normal file

File diff suppressed because it is too large Load Diff

1014
idasdk76/ldr/elf/elfbase.h Normal file

File diff suppressed because it is too large Load Diff

542
idasdk76/ldr/elf/elfr_arm.h Normal file
View File

@@ -0,0 +1,542 @@
#ifndef __ELFR_ARM_H__
#define __ELFR_ARM_H__
#ifndef __ELFBASE_H__
#include "elfbase.h"
#endif
// relocation field - word32 with HIGH BYTE FIRST!!!
// A- from Elf32_Rela
// B- Loading address of shared object (REAL section when symbol defined)
// (not) G- offset into global objet table
// (not) GOT- adress of global object table
// (not) L- linkage table entry
// P- place of storage unit (computed using r_offset)
// S- value of symbol
enum elf_RTYPE_arm
{
R_ARM_NONE = 0, // No reloc
R_ARM_PC24 = 1, // S-P+A (relative 26 bit branch)
R_ARM_ABS32 = 2, // S+A
R_ARM_REL32 = 3, // S-P+A
R_ARM_LDR_PC_G0 = 4, // S-P+A
R_ARM_ABS16 = 5, // S+A
R_ARM_ABS12 = 6, // S+A
R_ARM_THM_ABS5 = 7, // S+A
R_ARM_ABS8 = 8, // S+A
R_ARM_SBREL32 = 9, // S-B+A
R_ARM_THM_CALL = 10, // S-P+A
R_ARM_THM_PC8 = 11, // S-P+A
R_ARM_BREL_ADJ = 12, // S-B+A
R_ARM_TLS_DESC = 13, //
R_ARM_THM_SWI8 = 14, // S+A (obsolete)
R_ARM_XPC25 = 15, // S-P+A (obsolete)
R_ARM_THM_XPC22 = 16, // S-P+A (obsolete)
R_ARM_TLS_DTPMOD32 = 17, /* ID of module containing symbol */
R_ARM_TLS_DTPOFF32 = 18, /* Offset in TLS block */
R_ARM_TLS_TPOFF32 = 19, /* Offset in static TLS block */
// linux-specific
R_ARM_COPY = 20, // none (copy symbol at runtime)
R_ARM_GLOB_DAT = 21, // S (create .got entry)
R_ARM_JUMP_SLOT = 22, // S (create .plt entry)
R_ARM_RELATIVE = 23, // B+A (adjust by programm base)
R_ARM_GOTOFF32 = 24, // S+A-GOT (32bit offset to .got)
R_ARM_BASE_PREL = 25, // B+A-P
R_ARM_GOT_BREL = 26, // G+A-GOT (32bit .got entry)
R_ARM_PLT32 = 27, // L+A-P (32bit .plt entry)
R_ARM_CALL = 28,
R_ARM_JUMP24 = 29,
R_ARM_THM_JUMP24 = 30, // ((S + A) | T) - P
R_ARM_BASE_ABS = 31, // B + A
R_ARM_ALU_PCREL7_0 = 32,
R_ARM_ALU_PCREL15_8 = 33,
R_ARM_ALU_PCREL23_15 = 34,
R_ARM_LDR_SBREL_11_0 = 35,
R_ARM_ALU_SBREL_19_12 = 36,
R_ARM_ALU_SBREL_27_20 = 37,
R_ARM_TARGET1 = 38,
R_ARM_ROSEGREL32 = 39,
R_ARM_V4BX = 40,
R_ARM_TARGET2 = 41,
R_ARM_PREL31 = 42,
R_ARM_MOVW_ABS_NC = 43, // Static ARM (S + A) | T
R_ARM_MOVT_ABS = 44, // Static ARM S + A
R_ARM_MOVW_PREL_NC = 45, // Static ARM ((S + A) | T) - P
R_ARM_MOVT_PREL = 46, // Static ARM S + A - P
R_ARM_THM_MOVW_ABS_NC = 47, // Static Thumb32 (S + A) | T
R_ARM_THM_MOVT_ABS = 48, // Static Thumb32 S + A
R_ARM_THM_MOVW_PREL_NC= 49, // Static Thumb32 ((S + A) | T) - P
R_ARM_THM_MOVT_PREL = 50, // Static Thumb32 S + A - P
R_ARM_THM_JUMP19 = 51, // Static Thumb32 ((S + A) | T) - P
R_ARM_THM_JUMP6 = 52, // Static Thumb16 S + A - P
R_ARM_THM_ALU_PREL_11_0= 53, // Static Thumb32 ((S + A) | T) - Pa
R_ARM_THM_PC12 = 54, // Static Thumb32 S + A - Pa
R_ARM_ABS32_NOI = 55, // Static Data S + A
R_ARM_REL32_NOI = 56, // Static Data S + A - P
R_ARM_ALU_PC_G0_NC = 57, // Static ARM ((S + A) | T) - P
R_ARM_ALU_PC_G0 = 58, // Static ARM ((S + A) | T) - P
R_ARM_ALU_PC_G1_NC = 59, // Static ARM ((S + A) | T) - P
R_ARM_ALU_PC_G1 = 60, // Static ARM ((S + A) | T) - P
R_ARM_ALU_PC_G2 = 61, // Static ARM ((S + A) | T) - P
R_ARM_LDR_PC_G1 = 62, // Static ARM S + A - P
R_ARM_LDR_PC_G2 = 63, // Static ARM S + A - P
R_ARM_LDRS_PC_G0 = 64, // Static ARM S + A - P
R_ARM_LDRS_PC_G1 = 65, // Static ARM S + A - P
R_ARM_LDRS_PC_G2 = 66, // Static ARM S + A - P
R_ARM_LDC_PC_G0 = 67, // Static ARM S + A - P
R_ARM_LDC_PC_G1 = 68, // Static ARM S + A - P
R_ARM_LDC_PC_G2 = 69, // Static ARM S + A - P
R_ARM_ALU_SB_G0_NC = 70, // Static ARM ((S + A) | T) - B(S)
R_ARM_ALU_SB_G0 = 71, // Static ARM ((S + A) | T) - B(S)
R_ARM_ALU_SB_G1_NC = 72, // Static ARM ((S + A) | T) - B(S)
R_ARM_ALU_SB_G1 = 73, // Static ARM ((S + A) | T) - B(S)
R_ARM_ALU_SB_G2 = 74, // Static ARM ((S + A) | T) - B(S)
R_ARM_LDR_SB_G0 = 75, // Static ARM S + A - B(S)
R_ARM_LDR_SB_G1 = 76, // Static ARM S + A - B(S)
R_ARM_LDR_SB_G2 = 77, // Static ARM S + A - B(S)
R_ARM_LDRS_SB_G0 = 78, // Static ARM S + A - B(S)
R_ARM_LDRS_SB_G1 = 79, // Static ARM S + A - B(S)
R_ARM_LDRS_SB_G2 = 80, // Static ARM S + A - B(S)
R_ARM_LDC_SB_G0 = 81, // Static ARM S + A - B(S)
R_ARM_LDC_SB_G1 = 82, // Static ARM S + A - B(S)
R_ARM_LDC_SB_G2 = 83, // Static ARM S + A - B(S)
R_ARM_MOVW_BREL_NC = 84, // Static ARM ((S + A) | T) - B(S)
R_ARM_MOVT_BREL = 85, // Static ARM S + A - B(S)
R_ARM_MOVW_BREL = 86, // Static ARM ((S + A) | T) - B(S)
R_ARM_THM_MOVW_BREL_NC = 87, // Static Thumb32 ((S + A) | T) - B(S)
R_ARM_THM_MOVT_BREL = 88, // Static Thumb32 S + A - B(S)
R_ARM_THM_MOVW_BREL = 89, // Static Thumb32 ((S + A) | T) - B(S)
R_ARM_TLS_GOTDESC = 90, // Static Data
R_ARM_TLS_CALL = 91, // Static ARM
R_ARM_TLS_DESCSEQ = 92, // Static ARM TLS relaxation
R_ARM_THM_TLS_CALL = 93, // Static Thumb32
R_ARM_PLT32_ABS = 94, // Static Data PLT(S) + A
R_ARM_GOT_ABS = 95, // G+A
R_ARM_GOT_PREL = 96, // G+A-P
R_ARM_GOT_BREL12 = 97, // G+A-GOT
R_ARM_GOTOFF12 = 98, // S+A-GOT
R_ARM_GOTRELAX = 99,
R_ARM_GNU_VTENTRY = 100,
R_ARM_GNU_VTINHERIT = 101,
R_ARM_THM_PC11 = 102, /* Cygnus extension to abi: Thumb unconditional branch. */
R_ARM_THM_PC9 = 103, /* Cygnus extension to abi: Thumb conditional branch. */
R_ARM_THM_JUMP11 = 102, // Static Thumb16 S + A - P
R_ARM_THM_JUMP8 = 103, // Static Thumb16 S + A - P
R_ARM_TLS_GD32 = 104, // Static Data GOT(S) + A - P
R_ARM_TLS_LDM32 = 105, // Static Data GOT(S) + A - P
R_ARM_TLS_LDO32 = 106, // Static Data S + A - TLS
R_ARM_TLS_IE32 = 107, // Static Data GOT(S) + A - P
R_ARM_TLS_LE32 = 108, // Static Data S + A - tp
R_ARM_TLS_LDO12 = 109, // Static ARM S + A - TLS
R_ARM_TLS_LE12 = 110, // Static ARM S + A - tp
R_ARM_TLS_IE12GP = 111, // Static ARM GOT(S) + A - GOT_ORG
R_ARM_PRIVATE_0 = 112, // Private (n = 0, 1, ... 15)
R_ARM_PRIVATE_1 = 113,
R_ARM_PRIVATE_2 = 114,
R_ARM_PRIVATE_3 = 115,
R_ARM_PRIVATE_4 = 116,
R_ARM_PRIVATE_5 = 117,
R_ARM_PRIVATE_6 = 118,
R_ARM_PRIVATE_7 = 119,
R_ARM_PRIVATE_8 = 120,
R_ARM_PRIVATE_9 = 121,
R_ARM_PRIVATE_10 = 122,
R_ARM_PRIVATE_11 = 123,
R_ARM_PRIVATE_12 = 124,
R_ARM_PRIVATE_13 = 125,
R_ARM_PRIVATE_14 = 126,
R_ARM_PRIVATE_15 = 127,
R_ARM_ME_TOO = 128, // Obsolete
R_ARM_THM_TLS_DESCSEQ16 = 129,// Static Thumb16
R_ARM_THM_TLS_DESCSEQ32 = 130,// Static Thumb32
R_ARM_THM_GOT_BREL12 = 131, // GOT entry relative to GOT origin, 12 bit (Thumb32 LDR).
R_ARM_THM_ALU_ABS_G0_NC = 132,
R_ARM_THM_ALU_ABS_G1_NC = 133,
R_ARM_THM_ALU_ABS_G2_NC = 134,
R_ARM_THM_ALU_ABS_G3_NC = 135,
// 136 - 139 Unallocated
// 140 - 159 Dynamic Reserved for future allocation
R_ARM_IRELATIVE = 160,
// 161 - 255 Unallocated
//
// ATT: R_ARM_RXPC25 used ONLY in OLD_ABI (+ 15 OTHER relocs!)
// dynamic sections only
R_ARM_RXPC25 = 249, // (BLX) call between segments
//
R_ARM_RSBREL32 = 250, // (Word) SBrelative offset
R_ARM_THM_RPC22 = 251, // (Thumb BL/BLX) call between segments
R_ARM_RREL32 = 252, // (Word) inter-segment offset
R_ARM_RABS32 = 253, // (Word) Target segment displacement
R_ARM_RPC24 = 254, // (BL/BLX) call between segment
R_ARM_RBASE = 255 // segment being relocated
};
// X is the result of a relocation operation, before any masking or bit-selection
// Page(expr) is the page address of the expression expr, defined as (expr & ~0xFFF)
// GOT is the address of the Global Offset Table
// GDAT(S+A) represents a 64-bit entry in the GOT for address S+A
// G(expr) is the address of the GOT entry for the expression expr
// Delta(S) if S is a normal symbol, resolves to the difference between
// the static link address of S and the execution address of S.
// If S is the null symbol (ELF symbol index 0), resolves to the difference
// between the static link address of P and the execution address of P.
// Indirect(expr) represents the result of calling expr as a function.
// The result is the return value from the function that is returned in r0.
// [msb:lsb] is a bit-mask operation representing the selection of bits in a value
enum elf_RTYPE_aarch64
{
R_AARCH64_NONE = 0x100,
// ILP32 relocations
R_AARCH64_P32_ABS32 = 1,/* Direct 32 bit. */
R_AARCH64_P32_COPY = 180,/* Copy symbol at runtime. */
R_AARCH64_P32_GLOB_DAT = 181,/* Create GOT entry. */
R_AARCH64_P32_JUMP_SLOT = 182,/* Create PLT entry. */
R_AARCH64_P32_RELATIVE = 183,/* Adjust by program base. */
R_AARCH64_P32_TLS_DTPMOD = 184,/* Module number, 32 bit. */
R_AARCH64_P32_TLS_DTPREL = 185,/* Module-relative offset, 32 bit. */
R_AARCH64_P32_TLS_TPREL = 186,/* TP-relative offset, 32 bit. */
R_AARCH64_P32_TLSDESC = 187,/* TLS Descriptor. */
R_AARCH64_P32_IRELATIVE = 188,/* STT_GNU_IFUNC relocation. */
// 4.6.5 Static Data relocations
R_AARCH64_ABS64 = 0x101, // S + A
R_AARCH64_ABS32 = 0x102, // S + A
R_AARCH64_ABS16 = 0x103,
R_AARCH64_PREL64 = 0x104,
R_AARCH64_PREL32 = 0x105,
R_AARCH64_PREL16 = 0x106,
// 4.6.6 Static AArch64 relocations
R_AARCH64_MOVW_UABS_G0 = 0x107,
R_AARCH64_MOVW_UABS_G0_NC = 0x108,
R_AARCH64_MOVW_UABS_G1 = 0x109,
R_AARCH64_MOVW_UABS_G1_NC = 0x10a,
R_AARCH64_MOVW_UABS_G2 = 0x10b,
R_AARCH64_MOVW_UABS_G2_NC = 0x10c,
R_AARCH64_MOVW_UABS_G3 = 0x10d,
R_AARCH64_MOVW_SABS_G0 = 0x10e,
R_AARCH64_MOVW_SABS_G1 = 0x10f,
R_AARCH64_MOVW_SABS_G2 = 0x110,
R_AARCH64_LD_PREL_LO19 = 0x111,
R_AARCH64_ADR_PREL_LO21 = 0x112,
R_AARCH64_ADR_PREL_PG_HI21 = 0x113, // Page(S+A) - Page(P); Set an ADRP immediate value to bits [32:12] of the X
R_AARCH64_ADR_PREL_PG_HI21_NC = 0x114,
R_AARCH64_ADD_ABS_LO12_NC = 0x115, // S+A; Set an ADD immediate value to bits [11:0] of X
R_AARCH64_LDST8_ABS_LO12_NC = 0x116,
R_AARCH64_TSTBR14 = 0x117,
R_AARCH64_CONDBR19 = 0x118,
R_AARCH64_JUMP26 = 0x11a, // S+A-P; Set a B immediate field to bits [27:2] of X
R_AARCH64_CALL26 = 0x11b, // S+A-P; Set a CALL immediate field to bits [27:2] of X
R_AARCH64_LDST16_ABS_LO12_NC = 0x11c,
R_AARCH64_LDST32_ABS_LO12_NC = 0x11d,
R_AARCH64_LDST64_ABS_LO12_NC = 0x11e, // S+A; Set the LD/ST immediate value to bits [11:3] of X
R_AARCH64_MOVW_PREL_G0 = 0x11f,
R_AARCH64_MOVW_PREL_G0_NC = 0x120,
R_AARCH64_MOVW_PREL_G1 = 0x121,
R_AARCH64_MOVW_PREL_G1_NC = 0x122,
R_AARCH64_MOVW_PREL_G2 = 0x123,
R_AARCH64_MOVW_PREL_G2_NC = 0x124,
R_AARCH64_MOVW_PREL_G3 = 0x125,
R_AARCH64_LDST128_ABS_LO12_NC = 0x12b,
R_AARCH64_MOVW_GOTOFF_G0 = 0x12c,
R_AARCH64_MOVW_GOTOFF_G0_NC = 0x12d,
R_AARCH64_MOVW_GOTOFF_G1 = 0x12e,
R_AARCH64_MOVW_GOTOFF_G1_NC = 0x12f,
R_AARCH64_MOVW_GOTOFF_G2 = 0x130,
R_AARCH64_MOVW_GOTOFF_G2_NC = 0x131,
R_AARCH64_MOVW_GOTOFF_G3 = 0x132,
R_AARCH64_GOTREL64 = 0x133,
R_AARCH64_GOTREL32 = 0x134,
R_AARCH64_GOT_LD_PREL19 = 0x135,
R_AARCH64_LD64_GOTOFF_LO15 = 0x136,
R_AARCH64_ADR_GOT_PAGE = 0x137, // Page(G(GDAT(S+A)))-Page(P); Set the immediate value of an ADRP to bits [32:12] of X
R_AARCH64_LD64_GOT_LO12_NC = 0x138, // G(GDAT(S+A)); Set the LD/ST immediate field to bits [11:3] of X
R_AARCH64_LD64_GOTPAGE_LO15 = 0x139,
R_AARCH64_TLSGD_ADR_PREL21 = 0x200,
R_AARCH64_TLSGD_ADR_PAGE21 = 0x201,
R_AARCH64_TLSGD_ADD_LO12_NC = 0x202,
R_AARCH64_TLSGD_MOVW_G1 = 0x203,
R_AARCH64_TLSGD_MOVW_G0_NC = 0x204,
R_AARCH64_TLSLD_ADR_PREL21 = 0x205,
R_AARCH64_TLSLD_ADR_PAGE21 = 0x206,
R_AARCH64_TLSLD_ADD_LO12_NC = 0x207,
R_AARCH64_TLSLD_MOVW_G1 = 0x208,
R_AARCH64_TLSLD_MOVW_G0_NC = 0x209,
R_AARCH64_TLSLD_LD_PREL19 = 0x20a,
R_AARCH64_TLSLD_MOVW_DTPREL_G2 = 0x20b,
R_AARCH64_TLSLD_MOVW_DTPREL_G1 = 0x20c,
R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC = 0x20d,
R_AARCH64_TLSLD_MOVW_DTPREL_G0 = 0x20e,
R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC = 0x20f,
R_AARCH64_TLSLD_ADD_DTPREL_HI12 = 0x210,
R_AARCH64_TLSLD_ADD_DTPREL_LO12 = 0x211,
R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC = 0x212,
R_AARCH64_TLSLD_LDST8_DTPREL_LO12 = 0x213,
R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC = 0x214,
R_AARCH64_TLSLD_LDST16_DTPREL_LO12 = 0x215,
R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC = 0x216,
R_AARCH64_TLSLD_LDST32_DTPREL_LO12 = 0x217,
R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC = 0x218,
R_AARCH64_TLSLD_LDST64_DTPREL_LO12 = 0x219,
R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC = 0x21a,
R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 = 0x21b,
R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC = 0x21c,
R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 = 0x21d,
R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC = 0x21e,
R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 = 0x21f,
R_AARCH64_TLSLE_MOVW_TPREL_G2 = 0x220,
R_AARCH64_TLSLE_MOVW_TPREL_G1 = 0x221,
R_AARCH64_TLSLE_MOVW_TPREL_G1_NC = 0x222,
R_AARCH64_TLSLE_MOVW_TPREL_G0 = 0x223,
R_AARCH64_TLSLE_MOVW_TPREL_G0_NC = 0x224,
R_AARCH64_TLSLE_ADD_TPREL_HI12 = 0x225,
R_AARCH64_TLSLE_ADD_TPREL_LO12 = 0x226,
R_AARCH64_TLSLE_ADD_TPREL_LO12_NC = 0x227,
R_AARCH64_TLSLE_LDST8_TPREL_LO12 = 0x228,
R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC = 0x229,
R_AARCH64_TLSLE_LDST16_TPREL_LO12 = 0x22a,
R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC = 0x22b,
R_AARCH64_TLSLE_LDST32_TPREL_LO12 = 0x22c,
R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC = 0x22d,
R_AARCH64_TLSLE_LDST64_TPREL_LO12 = 0x22e,
R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC = 0x22f,
R_AARCH64_TLSDESC_LD_PREL19 = 0x230,
R_AARCH64_TLSDESC_ADR_PREL21 = 0x231,
R_AARCH64_TLSDESC_ADR_PAGE21 = 0x232, // R_AARCH64_TLSDESC_ADR_PAGE
R_AARCH64_TLSDESC_LD64_LO12 = 0x233, // R_AARCH64_TLSDESC_LD64_LO12_NC
R_AARCH64_TLSDESC_ADD_LO12 = 0x234, // R_AARCH64_TLSDESC_ADD_LO12_NC
R_AARCH64_TLSDESC_OFF_G1 = 0x235,
R_AARCH64_TLSDESC_OFF_G0_NC = 0x236,
R_AARCH64_TLSDESC_LDR = 0x237,
R_AARCH64_TLSDESC_ADD = 0x238,
R_AARCH64_TLSDESC_CALL = 0x239,
R_AARCH64_TLSLE_LDST128_TPREL_LO12 = 0x23a,
R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC = 0x23b,
R_AARCH64_TLSLD_LDST128_DTPREL_Lo12 = 0x23c,
R_AARCH64_TLSLD_LDST128_DTPREL_Lo12_NC= 0x23d,
// 4.6.11 Dynamic relocations
R_AARCH64_COPY = 0x400,
R_AARCH64_GLOB_DAT = 0x401,
R_AARCH64_JUMP_SLOT = 0x402,
R_AARCH64_RELATIVE = 0x403,
R_AARCH64_TLS_DTPREL64 = 0x404,
R_AARCH64_TLS_DTPMOD64 = 0x405,
R_AARCH64_TLS_TPREL64 = 0x406,
R_AARCH64_TLSDESC = 0x407,
R_AARCH64_IRELATIVE = 0x408,
};
// Flags:
#define EF_ARM_RELEXEC 0x00000001 // dynamic only how to relocation
#define EF_ARM_HASENTRY 0x00000002 // e_entry is real start address
// GNU flags (EABI version = 0)
#define EF_ARM_INTERWORK 0x00000004 // interworking enabled
#define EF_ARM_APCS_26 0x00000008 // APCS-26 used (otherwise APCS-32)
#define EF_ARM_APCS_FLOAT 0x00000010 // floats passed in float registers
#define EF_ARM_PIC 0x00000020 // Position-independent code
#define EF_ARM_ALIGN8 0x00000040 // 8-bit struct alignment
#define EF_ARM_NEW_ABI 0x00000080 // New ABI
#define EF_ARM_OLD_ABI 0x00000100 // Old ABI
#define EF_ARM_SOFT_FLOAT 0x00000200 // software FP
#define EF_ARM_VFP_FLOAT 0x00000400 // VFP float format
#define EF_ARM_MAVERICK_FLOAT 0x00000800 // Maverick float format
// ARM flags:
#define EF_ARM_SYMSARESORTED 0x00000004 // Each subsection of the symbol table is sorted by symbol value (NB conflicts with EF_INTERWORK)
#define EF_ARM_DYNSYMSUSESEGIDX 0x00000008 // Symbols in dynamic symbol tables that are defined in sections
// included in program segment n have st_shndx = n + 1. (NB conflicts with EF_APCS26)
#define EF_ARM_MAPSYMSFIRST 0x00000010 // Mapping symbols precede other local symbols in the symbol
// table (NB conflicts with EF_APCS_FLOAT)
#define EF_ARM_LE8 0x00400000 // LE-8 code
#define EF_ARM_BE8 0x00800000 // BE-8 code for ARMv6 or later
#define EF_ARM_EABIMASK 0xFF000000 // ARM EABI version
/* Additional symbol types for Thumb. */
#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */
#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */
// patching GOT loading,
// discard auxiliary values in plt/got
// can present offset bypass segment
#define ELF_RPL_ARM_DEFAULT (ELF_RPL_GL | ELF_DIS_OFFW | ELF_DIS_GPLT)
enum elf_SHT_ARM
{
SHT_ARM_EXIDX = 0x70000001, // Exception Index table
SHT_ARM_PREEMPTMAP = 0x70000002, // BPABI DLL dynamic linking pre-emption map
SHT_ARM_ATTRIBUTES = 0x70000003, // Object file compatibility attributes
SHT_ARM_DEBUGOVERLAY = 0x70000004, //
SHT_ARM_OVERLAYSECTION = 0x70000005, //
};
enum elf_PT_ARM
{
// From binutils-2.27/elfcpp/elfcpp.h
PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility information
PT_ARM_EXIDX = 0x70000001, // Exception unwind tables
};
enum elf_PT_AARCH64
{
// From binutils-2.27/elfcpp/elfcpp.h
PT_AARCH64_ARCHEXT = 0x70000000, // Platform architecture compatibility information
PT_AARCH64_UNWIND = 0x70000001, // Exception unwind tables
};
enum eabi_tags_t
{
Tag_NULL,
Tag_File, // (=1) <uint32: byte-size> <attribute>*
Tag_Section, // (=2) <uint32: byte-size> <section number>* 0 <attribute>*
Tag_Symbol, // (=3) <unit32: byte-size> <symbol number>* 0 <attribute>*
Tag_CPU_raw_name, // (=4), NTBS
Tag_CPU_name, // (=5), NTBS
Tag_CPU_arch, // (=6), uleb128
Tag_CPU_arch_profile, // (=7), uleb128
Tag_ARM_ISA_use, // (=8), uleb128
Tag_THUMB_ISA_use, // (=9), uleb128
Tag_FP_arch, // (=10), uleb128 (formerly Tag_VFP_arch = 10)
Tag_VFP_arch = Tag_FP_arch,
Tag_WMMX_arch, // (=11), uleb128
Tag_NEON_arch, // (=12), uleb128
Tag_PCS_config, // (=13), uleb128
Tag_ABI_PCS_R9_use, // (=14), uleb128
Tag_ABI_PCS_RW_data, // (=15), uleb128
Tag_ABI_PCS_RO_data, // (=16), uleb128
Tag_ABI_PCS_GOT_use, // (=17), uleb128
Tag_ABI_PCS_wchar_t, // (=18), uleb128
Tag_ABI_FP_rounding, // (=19), uleb128
Tag_ABI_FP_denormal, // (=20), uleb128
Tag_ABI_FP_exceptions, // (=21), uleb128
Tag_ABI_FP_user_exceptions, // (=22), uleb128
Tag_ABI_FP_number_model, // (=23), uleb128
Tag_ABI_align_needed, // (=24), uleb128
Tag_ABI_align8_needed = Tag_ABI_align_needed,
Tag_ABI_align_preserved, // (=25), uleb128
Tag_ABI_align8_preserved = Tag_ABI_align_preserved,
Tag_ABI_enum_size, // (=26), uleb128
Tag_ABI_HardFP_use, // (=27), uleb128
Tag_ABI_VFP_args, // (=28), uleb128
Tag_ABI_WMMX_args, // (=29), uleb128
Tag_ABI_optimization_goals, // (=30), uleb128
Tag_ABI_FP_optimization_goals, // (=31), uleb128
Tag_compatibility, // (=32), uleb128: flag, NTBS: vendor-name
Tag_CPU_unaligned_access=34, // (=34), uleb128
Tag_FP_HP_extension=36, // (=36), uleb128 (formerly Tag_VFP_HP_extension = 36)
Tag_VFP_HP_extension = Tag_FP_HP_extension,
Tag_ABI_FP_16bit_format=38, // (=38), uleb128
Tag_MPextension_use=42, // (=42), uleb128
Tag_DIV_use=44, // (=44), uleb128
Tag_nodefaults=64, // (=64), uleb128: ignored (write as 0)
Tag_also_compatible_with, // (=65), NTBS: data; ULEB128-encoded tag followed by a value of that tag.
Tag_T2EE_use, // (=66), uleb128
Tag_conformance, // (=67), string: ABI-version
Tag_Virtualization_use, // (=68), uleb128
Tag_MPextension_use_legacy=70, // (=70),
};
//----------------------------------------------------------------------------
class arm_arch_specific_t : public arch_specific_t
{
public:
enum isa_t
{
isa_arm = 1,
isa_thumb
};
typedef void isa_handler_t(
reader_t &reader,
sym_rel &symbol,
isa_t isa,
bool force);
private:
typedef std::map<uint64, isa_t> section_isa_ranges_t;
typedef std::map<elf_shndx_t, section_isa_ranges_t> isa_ranges_t;
isa_ranges_t isa_ranges;
std::set<ea_t> forced_isas;
isa_handler_t *isa_handler = nullptr;
ea_t debug_segbase = 0;
bool has_mapsym = false;
bool track_mapsym = false;
bool be8_code = false;
void notify_isa(reader_t &reader, sym_rel &symbol, isa_t isa, bool force)
{
if ( isa_handler != NULL )
isa_handler(reader, symbol, isa, force);
}
isa_t get_isa(const sym_rel &symbol) const;
void set_isa(const sym_rel &symbol, isa_t isa);
friend void arm_isa_handler(
reader_t &reader,
sym_rel &symbol,
arm_arch_specific_t::isa_t isa,
bool force);
public:
virtual ~arm_arch_specific_t() {}
virtual void on_start_symbols(reader_t &reader) override;
virtual void on_symbol_read(reader_t &reader, sym_rel &sym) override;
bool is_mapping_symbol(const char *name) const;
bool has_mapping_symbols() const { return has_mapsym; }
// Tracking mapping symbols can be useful for
// determining whether a certain function is using
// the Thumb or ARM ISA.
// In some ELF files, the only way to know what ISA
// certain functions are in is by looking at some
// mapping symbols (i.e., '$a', '$t').
// By default, tracking of such symbols in an
// instance of this class is _not_ enabled.
void set_mapping_symbols_tracking(bool track) { track_mapsym = track; }
bool is_mapping_symbols_tracking() const { return track_mapsym; }
void set_isa_handler(isa_handler_t *ih, ea_t dea)
{
isa_handler = ih;
debug_segbase = dea;
}
void set_be8(bool be8) { be8_code = be8; }
bool is_be8() { return be8_code; }
};
//----------------------------------------------------------------------------
// Specific flags that will be set on sym_rel instances.
enum arm_sym_rel_flags
{
thumb_function = 1
};
#endif

View File

@@ -0,0 +1,87 @@
#ifndef __ELFR_AVR_H__
#define __ELFR_AVR_H__
#ifndef __ELFBASE_H__
#include "elfbase.h"
#endif
enum elf_RTYPE_avr
{
R_AVR_NONE = 0,
R_AVR_32 = 1,
R_AVR_7_PCREL = 2,
R_AVR_13_PCREL = 3,
R_AVR_16 = 4,
R_AVR_16PM = 5,
R_AVR_LO8_LDI = 6,
R_AVR_HI8_LDI = 7,
R_AVR_HH8_LDI = 8,
R_AVR_LO8_LDI_NEG = 9,
R_AVR_HI8_LDI_NEG = 10,
R_AVR_HH8_LDI_NEG = 11,
R_AVR_LO8_LDI_PM = 12,
R_AVR_HI8_LDI_PM = 13,
R_AVR_HH8_LDI_PM = 14,
R_AVR_LO8_LDI_PM_NEG = 15,
R_AVR_HI8_LDI_PM_NEG = 16,
R_AVR_HH8_LDI_PM_NEG = 17,
R_AVR_CALL = 18,
// *nix obj's specific
R_AVR_LDI = 19,
R_AVR_6 = 20,
R_AVR_6_ADIW = 21,
R_AVR_MS8_LDI = 22,
R_AVR_MS8_LDI_NEG = 23,
R_AVR_LO8_LDI_GS = 24,
R_AVR_HI8_LDI_GS = 25,
R_AVR_8 = 26,
R_AVR_8_LO8 = 27,
R_AVR_8_HI8 = 28,
R_AVR_8_HLO8 = 29,
R_AVR_DIFF8 = 30,
R_AVR_DIFF16 = 31,
R_AVR_DIFF32 = 32,
R_AVR_LDS_STS_16 = 33,
R_AVR_PORT6 = 34,
R_AVR_PORT5 = 35,
R_AVR_32_PCREL = 36,
};
// Flags:
// If bit #7 is set, it is assumed that the elf file uses local symbols
// as reference for the relocations so that linker relaxation is possible.
#define EF_AVR_LINKRELAX_PREPARED 0x80
// Processor specific flags for the ELF header e_flags field.
#define EF_AVR_MACH 0x7F
#define E_AVR_MACH_AVR1 1
#define E_AVR_MACH_AVR2 2
#define E_AVR_MACH_AVR25 25
#define E_AVR_MACH_AVR3 3
#define E_AVR_MACH_AVR31 31
#define E_AVR_MACH_AVR35 35
#define E_AVR_MACH_AVR4 4
#define E_AVR_MACH_AVR5 5
#define E_AVR_MACH_AVR51 51
#define E_AVR_MACH_AVR6 6
#define E_AVR_MACH_TINY 100
#define E_AVR_MACH_XMEGA1 101
#define E_AVR_MACH_XMEGA2 102
#define E_AVR_MACH_XMEGA3 103
#define E_AVR_MACH_XMEGA4 104
#define E_AVR_MACH_XMEGA5 105
#define E_AVR_MACH_XMEGA6 106
#define E_AVR_MACH_XMEGA7 107
// netnode flag's and constant
#define AVR_INFO_NODENAME "$ atmel"
#define ELF_AVR_TAG 'f'
#define ELF_AVR_LDI_NEG 1
#define ELF_AVR_RAM_OFF 2
#define ELF_AVR_EEP_OFF 3
#define ELF_AVR_ABS_OFF 4
#define ELF_AVR_RAMBASE 0x800000
#define ELF_AVR_EEPROMBASE 0x810000
#define ELF_AVR_ABSBASE 0x1000000
#endif

View File

@@ -0,0 +1,272 @@
#ifndef __ELFR_IA64_H__
#define __ELFR_IA64_H__
#ifndef __ELFBASE_H__
#include "elfbase.h"
#endif
/* Bits in the e_flags field of the Elf64_Ehdr: */
#define EF_IA_64_MASKOS 0x00ff000f /* os-specific flags */
#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
#define EFA_IA_64 0x00000000
/* ??? These four definitions are not part of the SVR4 ABI.
They were present in David's initial code drop, so it is probable
that they are used by HP/UX. */
#define EF_IA_64_TRAPNIL (1 << 0) /* Trap NIL pointer dereferences. */
#define EF_IA_64_LAZYSWAP (1 << 1) /* Lazy Swap algorithm */
#define EF_IA_64_EXT (1 << 2) /* Program uses arch. extensions. */
#define EF_IA_64_BE (1 << 3) /* PSR BE bit set (big-endian). */
#define EFA_IA_64_EAS2_3 0x23000000 /* IA64 EAS 2.3. */
#define EF_IA_64_ABI64 (1 << 4) /* 64-bit ABI. */
/* Not used yet. */
#define EF_IA_64_REDUCEDFP (1 << 5) /* Only FP6-FP11 used. */
#define EF_IA_64_CONS_GP (1 << 6) /* gp as program wide constant. */
#define EF_IA_64_NOFUNCDESC_CONS_GP (1 << 7) /* And no function descriptors. */
/* Not used yet. */
#define EF_IA_64_ABSOLUTE (1 << 8) /* Load at absolute addresses. */
/*============================================================================
The R_EM_* macros are the IA_64 relocation types
============================================================================*/
/*
** These are "real" Tahoe relocations. The offset in a relocation
** applied to a data location is the actual byte address of the
** 32-/64-bit field to relocate. The value of (offset & ~3) in
** an instruction relocation is the byte offset of the bundle
** the instruction lives in; the value of (offset & 3) signifies:
** 0: first instruction slot in bundle
** 1: second instruction slot in bundle
** 2: third instruction slot in bundle
**
** Little piece of info: the first (hex) digit specifies the
** expression type, while the second specifies the format of
** the data word being relocated.
*/
// relocation field - word32 with HIGH BYTE FIRST!!!
// A- from Elf32_Rela
// B- Loading address of shared object
// G- offset into global objet table
// GOT- adress of global object table
// L- linkage table entry
// P- plase of storage unit (computed using r_offset)
// S- value of symbol
enum elf_RTYPE_ia64
{
R_IA64_NONE = 0x00, /* none */
R_IA64_IMM14 = 0x21, /* symbol + addend, add imm14 */
R_IA64_IMM22 = 0x22, /* symbol + addend, add imm22 */
R_IA64_IMM64 = 0x23, /* symbol + addend, mov imm64 */
R_IA64_DIR32MSB = 0x24, /* symbol + addend, data4 MSB */
R_IA64_DIR32LSB = 0x25, /* symbol + addend, data4 LSB */
R_IA64_DIR64MSB = 0x26, /* symbol + addend, data8 MSB */
R_IA64_DIR64LSB = 0x27, /* symbol + addend, data8 LSB */
R_IA64_GPREL22 = 0x2a, /* @gprel(sym + add), add imm22 */
R_IA64_GPREL64I = 0x2b, /* @gprel(sym + add), mov imm64 */
R_IA64_GPREL32MSB = 0x2c, /* @gprel(sym + add), data4 MSB ## */
R_IA64_GPREL32LSB = 0x2d, /* @gprel(sym + add), data4 LSB ## */
R_IA64_GPREL64MSB = 0x2e, /* @gprel(sym + add), data8 MSB */
R_IA64_GPREL64LSB = 0x2f, /* @gprel(sym + add), data8 LSB */
R_IA64_LTOFF22 = 0x32, /* @ltoff(sym + add), add imm22 */
R_IA64_LTOFF64I = 0x33, /* @ltoff(sym + add), mov imm64 */
R_IA64_PLTOFF22 = 0x3a, /* @pltoff(sym + add), add imm22 */
R_IA64_PLTOFF64I = 0x3b, /* @pltoff(sym + add), mov imm64 */
R_IA64_PLTOFF64MSB = 0x3e, /* @pltoff(sym + add), data8 MSB */
R_IA64_PLTOFF64LSB = 0x3f, /* @pltoff(sym + add), data8 LSB */
R_IA64_FPTR64I = 0x43, /* @fptr(sym + add), mov imm64 */
R_IA64_FPTR32MSB = 0x44, /* @fptr(sym + add), data4 MSB */
R_IA64_FPTR32LSB = 0x45, /* @fptr(sym + add), data4 LSB */
R_IA64_FPTR64MSB = 0x46, /* @fptr(sym + add), data8 MSB */
R_IA64_FPTR64LSB = 0x47, /* @fptr(sym + add), data8 LSB */
R_IA64_PCREL60B = 0x48, /* @pcrel(sym + add), brl */
R_IA64_PCREL21B = 0x49, /* @pcrel(sym + add), ptb, call */
R_IA64_PCREL21M = 0x4a, /* @pcrel(sym + add), chk.s */
R_IA64_PCREL21F = 0x4b, /* @pcrel(sym + add), fchkf */
R_IA64_PCREL32MSB = 0x4c, /* @pcrel(sym + add), data4 MSB */
R_IA64_PCREL32LSB = 0x4d, /* @pcrel(sym + add), data4 LSB */
R_IA64_PCREL64MSB = 0x4e, /* @pcrel(sym + add), data8 MSB */
R_IA64_PCREL64LSB = 0x4f, /* @pcrel(sym + add), data8 LSB */
R_IA64_LTOFF_FPTR22 = 0x52, /* @ltoff(@fptr(s+a)), imm22 */
R_IA64_LTOFF_FPTR64I = 0x53, /* @ltoff(@fptr(s+a)), imm64 */
R_IA64_LTOFF_FPTR32MSB = 0x54, /* @ltoff(@fptr(s+a)), 4 MSB */
R_IA64_LTOFF_FPTR32LSB = 0x55, /* @ltoff(@fptr(s+a)), 4 LSB */
R_IA64_LTOFF_FPTR64MSB = 0x56, /* @ltoff(@fptr(s+a)), 8 MSB ##*/
R_IA64_LTOFF_FPTR64LSB = 0x57, /* @ltoff(@fptr(s+a)), 8 LSB ##*/
R_IA64_SEGBASE = 0x58, /* set segment base for @segrel ## */
R_IA64_SEGREL32MSB = 0x5c, /* @segrel(sym + add), data4 MSB */
R_IA64_SEGREL32LSB = 0x5d, /* @segrel(sym + add), data4 LSB */
R_IA64_SEGREL64MSB = 0x5e, /* @segrel(sym + add), data8 MSB */
R_IA64_SEGREL64LSB = 0x5f, /* @segrel(sym + add), data8 LSB */
R_IA64_SECREL32MSB = 0x64, /* @secrel(sym + add), data4 MSB */
R_IA64_SECREL32LSB = 0x65, /* @secrel(sym + add), data4 LSB */
R_IA64_SECREL64MSB = 0x66, /* @secrel(sym + add), data8 MSB */
R_IA64_SECREL64LSB = 0x67, /* @secrel(sym + add), data8 LSB */
R_IA64_REL32MSB = 0x6c, /* data 4 + REL */
R_IA64_REL32LSB = 0x6d, /* data 4 + REL */
R_IA64_REL64MSB = 0x6e, /* data 8 + REL */
R_IA64_REL64LSB = 0x6f, /* data 8 + REL */
R_IA64_LTV32MSB = 0x74, /* symbol + addend, data4 MSB */
R_IA64_LTV32LSB = 0x75, /* symbol + addend, data4 LSB */
R_IA64_LTV64MSB = 0x76, /* symbol + addend, data8 MSB */
R_IA64_LTV64LSB = 0x77, /* symbol + addend, data8 LSB */
R_IA64_PCREL21BI = 0x79, /* @pcrel(sym + add), ptb, call */
R_IA64_PCREL22 = 0x7a, /* @pcrel(sym + add), imm22 */
R_IA64_PCREL64I = 0x7b, /* @pcrel(sym + add), imm64 */
R_IA64_IPLTMSB = 0x80, /* dynamic reloc, imported PLT, MSB */
R_IA64_IPLTLSB = 0x81, /* dynamic reloc, imported PLT, LSB */
R_IA64_EPLTMSB = 0x82, /* dynamic reloc, exported PLT, ## */
R_IA64_EPLTLSB = 0x83, /* dynamic reloc, exported PLT, ## */
R_IA64_COPY = 0x84, /* dynamic reloc, data copy ## */
R_IA64_SUB = 0x85, /* Addend and symbol difference */
R_IA64_LTOFF22X = 0x86, /* LTOFF22, relaxable. */
R_IA64_LDXMOV = 0x87, /* Use of LTOFF22X. */
R_IA64_TPREL14 = 0x91, /* @tprel(sym+add), add imm14 */
R_IA64_TPREL22 = 0x92, /* sym-TP+add, add imm22 ## */
R_IA64_TPREL64I = 0x93, /* @tprel(sym+add), add imm64 */
R_IA64_TPREL64MSB = 0x96, /* sym-TP+add, data8 MSB ## */
R_IA64_TPREL64LSB = 0x97, /* sym-TP+add, data8 LSB ## */
R_IA64_LTOFF_TP22 = 0x9a, /* @ltoff(sym-TP+add), add imm22 ## */
R_IA64_DTPMOD64MSB = 0xa6, /* @dtpmod(sym+add), data8 MSB */
R_IA64_DTPMOD64LSB = 0xa7, /* @dtpmod(sym+add), data8 LSB */
R_IA64_LTOFF_DTPMOD22 = 0xaa, /* @ltoff(@dtpmod(s+a)), imm22 */
R_IA64_DTPREL14 = 0xb1, /* @dtprel(sym+add), imm14 */
R_IA64_DTPREL22 = 0xb2, /* @dtprel(sym+add), imm22 */
R_IA64_DTPREL64I = 0xb3, /* @dtprel(sym+add), imm64 */
R_IA64_DTPREL32MSB = 0xb4, /* @dtprel(sym+add), data4 MSB */
R_IA64_DTPREL32LSB = 0xb5, /* @dtprel(sym+add), data4 LSB */
R_IA64_DTPREL64MSB = 0xb6, /* @dtprel(sym+add), data8 MSB */
R_IA64_DTPREL64LSB = 0xb7, /* @dtprel(sym+add), data8 LSB */
R_IA64_LTOFF_DTPREL22 = 0xba, /* @ltoff(@dtprel(s+a)), imm22 */
R_IA64_MAX_RELOC_CODE = 0xba
};
// convert plt PIC => noPIC,
// patching GOT loading,
// discard auxiliary values in plt/got
#define ELF_RPL_IA64_DEFAULT (ELF_RPL_PLP | ELF_RPL_GL)
enum elf_SHT_IA64
{
SHT_IA_64_EXT = 0x70000000, /* extension bits */
SHT_IA_64_UNWIND = 0x70000001, /* unwind bits */
};
/*============================================================================
The PT_* macros are the values of p_type in ElfXX_Phdr.
============================================================================*/
enum elf_PT_IA64
{
PT_HP_TLS = (PT_LOOS + 0x0), /* TLS */
PT_HP_CORE_NONE = (PT_LOOS + 0x1), /* core file information */
PT_HP_CORE_VERSION = (PT_LOOS + 0x2),
PT_HP_CORE_KERNEL = (PT_LOOS + 0x3),
PT_HP_CORE_COMM = (PT_LOOS + 0x4),
PT_HP_CORE_PROC = (PT_LOOS + 0x5),
PT_HP_CORE_LOADABLE = (PT_LOOS + 0x6),
PT_HP_CORE_STACK = (PT_LOOS + 0x7),
PT_HP_CORE_SHM = (PT_LOOS + 0x8),
PT_HP_CORE_MMF = (PT_LOOS + 0x9),
PT_HP_PARALLEL = (PT_LOOS + 0x10), /* parallel information header */
PT_HP_FASTBIND = (PT_LOOS + 0x11), /* fastbind data segment */
PT_HP_OPT_ANNOT = (PT_LOOS + 0x12), /* dynamic opt. annotations */
PT_HP_HSL_ANNOT = (PT_LOOS + 0x13), /* HSL annotations */
PT_HP_STACK = (PT_LOOS + 0x14), /* executable stack */
PT_HP_CORE_UTSNAME = (PT_LOOS + 0x15), /* Extended utsname() core struct */
PT_HP_LINKER_FOOTPRINT = (PT_LOOS + 0x16), /* linker footprint */
PT_IA_64_ARCHEXT = (PT_LOPROC + 0), /* arch. extension bits */
PT_IA_64_UNWIND = (PT_LOPROC + 1), /* IA64 unwind bits */
};
/*============================================================================
The PF_* macros are the segment flag bits in p_flags of ElfXX_Phdr.
============================================================================*/
enum elf_PF_IA64
{
PF_HP_ENABLE_RECOVER = 0x00020000, /* enable recovery mode */
PF_HP_CODE = 0x00040000, /* code hint */
PF_HP_MODIFY = 0x00080000, /* modify hint */
PF_HP_PAGE_SIZE = 0x00100000, /* use explicit page size */
PF_HP_FAR_SHARED = 0x00200000, /* far shared data */
PF_HP_NEAR_SHARED = 0x00400000, /* near shared data */
PF_HP_LAZYSWAP = 0x00800000, /* lazy swap allocation */
PF_IA_64_NORECOV = 0x80000000, /* segment contains code that uses
speculative instructions w/o
recovery code. */
};
/*============================================================================
The NOTE_* macros are the note types for SHT_NOTE sections
============================================================================*/
#define NOTE_HP_COMPILER 1 /* Compiler identification string */
#define NOTE_HP_COPYRIGHT 2 /* Copyright string */
#define NOTE_HP_VERSION 3 /* Version string */
#define NOTE_HP_SRCFILE_INFO 4 /* Source file info for performance tools */
#define NOTE_HP_LINKER 5 /* Linker identification string */
#define NOTE_HP_INSTRUMENTED 6 /* instrumentation data */
#define NOTE_HP_UX_OPTIONS 7 /* elf hdr extension fields */
/*============================================================================
The DT_* defines are the allowed values of d_tag in ElfXX_dyn.
These are the Dynamic Array types.
============================================================================*/
/* (i)gnore (m)andatory */
/* (o)ptional */
/* d_un Exec DLL */
/* ---- ---- --- */
enum elf_DT_IA64
{
DT_HP_LOAD_MAP = (DT_LOOS + 0x0), /* d_ptr m - */
DT_HP_DLD_FLAGS = (DT_LOOS + 0x1), /* d_val m - */
DT_HP_DLD_HOOK = (DT_LOOS + 0x2), /* d_ptr m - */
DT_HP_UX10_INIT = (DT_LOOS + 0x3), /* d_ptr o o */
DT_HP_UX10_INITSZ = (DT_LOOS + 0x4), /* d_ptr o o */
DT_HP_PREINIT = (DT_LOOS + 0x5), /* d_ptr o - */
DT_HP_PREINITSZ = (DT_LOOS + 0x6), /* d_ptr o - */
DT_HP_NEEDED = (DT_LOOS + 0x7), /* d_val o o */
DT_HP_TIME_STAMP = (DT_LOOS + 0x8), /* d_val o o */
DT_HP_CHECKSUM = (DT_LOOS + 0x9), /* d_val o o */
DT_HP_GST_SIZE = (DT_LOOS + 0xa), /* d_val o - */
DT_HP_GST_VERSION = (DT_LOOS + 0xb), /* d_val o o */
DT_HP_GST_HASHVAL = (DT_LOOS + 0xc), /* d_ptr o o */
DT_HP_EPLTREL = (DT_LOOS + 0xd), /* d_ptr o o */
DT_HP_EPLTRELSZ = (DT_LOOS + 0xe), /* d_ptr o o */
DT_HP_FILTERED = (DT_LOOS + 0xf), /* d_val - o */
DT_HP_FILTER_TLS = (DT_LOOS + 0x10),/* d_val - o */
DT_HP_COMPAT_FILTERED = (DT_LOOS + 0x11),/* d_val - o */
DT_HP_LAZYLOAD = (DT_LOOS + 0x12),/* d_val o - */
DT_HP_BIND_NOW_COUNT = (DT_LOOS + 0x13),/* d_val o o */
DT_PLT = (DT_LOOS + 0x14),/* d_ptr o o */
DT_PLT_SIZE = (DT_LOOS + 0x15),/* d_val o o */
DT_DLT = (DT_LOOS + 0x16),/* d_ptr o o */
DT_DLT_SIZE = (DT_LOOS + 0x17),/* d_val o o */
DT_HP_SYM_CHECKSUM = (DT_LOOS + 0x18),/* d_val o o */
DT_IA_64_PLT_RESERVE = 0x70000000,
};
#endif

View File

@@ -0,0 +1,476 @@
#ifndef __ELFR_MIP_H__
#define __ELFR_MIP_H__
#ifndef __ELFBASE_H__
#include "elfbase.h"
#endif
#include "elf.h"
//
// e_flags
//
#define EF_MIPS_NOREORDER 0x00000001 // At least one .noreorder directive appears in the source.
#define EF_MIPS_PIC 0x00000002 // File contains position independent code.
#define EF_MIPS_CPIC 0x00000004 // Code in file uses the standard calling sequence for calling osition independent code.
#define EF_MIPS_UGEN_ALLOC 0x00000008
#define EF_MIPS_UCODE 0x00000010 // Code in file uses UCODE (obsolete)
#define EF_MIPS_ABI2 0x00000020 // Code in file uses new ABI (-n32 on Irix 6).
#define EF_MIPS_DYNAMIC 0x00000040 // MIPS dynamic
#define EF_MIPS_OPTIONS_FIRST 0x00000080
#define EF_MIPS_32BITMODE 0x00000100 // Indicates code compiled for a 64-bit machine in 32-bit mode. (regs are 32-bits wide.)
#define EF_MIPS_FP64 0x00000200 // 32-bit machine but FP registers are 64-bit (gcc -mfp64)
#define EF_MIPS_NAN2008 0x00000400 // Uses IEE 754-2008 NaN encoding
#define EF_MIPS_ARCH 0xF0000000 // Four bit MIPS architecture field.
#define E_MIPS_ARCH_1 0x00000000 // -mips1 code.
#define E_MIPS_ARCH_2 0x10000000 // -mips2 code.
#define E_MIPS_ARCH_3 0x20000000 // -mips3 code.
#define E_MIPS_ARCH_4 0x30000000 // -mips4 code.
#define E_MIPS_ARCH_5 0x40000000 // -mips5 code.
#define E_MIPS_ARCH_32 0x50000000 // -mips32 code.
#define E_MIPS_ARCH_64 0x60000000 // -mips64 code.
#define E_MIPS_ARCH_32R2 0x70000000 // -mips32r2
#define E_MIPS_ARCH_64R2 0x80000000 // -mips64r2
#define E_MIPS_ARCH_32R6 0x90000000 // -mips32r6
#define E_MIPS_ARCH_64R6 0xA0000000 // -mips64r6
#define EF_MIPS_ABI 0x0000F000 // The ABI of the file. Also see EF_MIPS_ABI2 above.
#define E_MIPS_ABI_O32 0x00001000 // The original o32 abi.
#define E_MIPS_ABI_O64 0x00002000 // O32 extended to work on 64 bit architectures
#define E_MIPS_ABI_EABI32 0x00003000 // EABI in 32 bit mode
#define E_MIPS_ABI_EABI64 0x00004000 // EABI in 64 bit mode
#define EF_MIPS_ARCH_ASE 0x0F000000 // Architectural Extensions used by this file
#define EF_MIPS_ARCH_ASE_MDMX 0x08000000 // Use MDMX multimedia extensions
#define EF_MIPS_ARCH_ASE_M16 0x04000000 // Use MIPS-16 ISA extensions
#define EF_MIPS_ARCH_ASE_MICROMIPS 0x02000000 // Use microMIPS ISA extensions
/* Machine variant if we know it. This field was invented at Cygnus,
but it is hoped that other vendors will adopt it. If some standard
is developed, this code should be changed to follow it. */
#define EF_MIPS_MACH 0x00FF0000
/* Cygnus is choosing values between 80 and 9F;
00 - 7F should be left for a future standard;
the rest are open. */
#define E_MIPS_MACH_3900 0x00810000 // R3900/Toshiba TX39
#define E_MIPS_MACH_4010 0x00820000 //
#define E_MIPS_MACH_4100 0x00830000
#define E_MIPS_MACH_4650 0x00850000
#define E_MIPS_MACH_4120 0x00870000
#define E_MIPS_MACH_4111 0x00880000
#define E_MIPS_MACH_MIPS32_4K 0x00890000
#define E_MIPS_MACH_SB1 0x008A0000 // SiByte SB-1
#define E_MIPS_MACH_OCTEON 0x008B0000 // Cavium Networks OCTEON
#define E_MIPS_MACH_XLR 0x008C0000 // RMI XLR
#define E_MIPS_MACH_OCTEON2 0x008D0000 // Cavium Networks OCTEON 2
#define E_MIPS_MACH_OCTEON3 0x008E0000 // Cavium Networks OCTEON 3
#define E_MIPS_MACH_5400 0x00910000
#define E_MIPS_MACH_5900 0x00920000 // r5900 (Sony Playstation 2 Emotion Engine)
#define E_MIPS_MACH_5500 0x00980000
#define E_MIPS_MACH_9000 0x00990000
#define E_MIPS_MACH_LS2E 0x00A00000 // Loongson/Godson 2E
#define E_MIPS_MACH_LS2F 0x00A10000 // Loongson/Godson 2F
#define E_MIPS_MACH_ALLEGREX 0x00A20000 // Allegrex (Sony PlayStation Portable)
#define E_MIPS_MACH_LS3A 0x00A20000 // Loongson/Godson 3A
//
// p_flags
//
#define PF_MIPS_LOCAL 0x10000000 // special p_flags
// relocation field - word32 with HIGH BYTE FIRST!!!
// A- from Elf32_Rela
// B- Loading address of shared object
// G- offset into global objet table
// GOT- adress of global object table
// L- linkage table entry
// P- plase of storage unit (computed using r_offset)
// S- value of symbol
enum elf_RTYPE_mips
{
R_MIPS_NONE = 0, // No reloc
R_MIPS_16 = 1,
R_MIPS_32 = 2, // S+A-P Direct32
R_MIPS_REL = 3, // S+A Relative32
R_MIPS_26 = 4, // S+A Relative26
R_MIPS_HI16 = 5,
R_MIPS_LO16 = 6,
R_MIPS_GPREL = 7, // S+A Relative16
R_MIPS_LITERAL = 8,
R_MIPS_GOT = 9,
R_MIPS_PC16 = 10,
R_MIPS_CALL = 11, // Call16
R_MIPS_GPREL32 = 12,
R_MIPS_SHIFT5 = 16,
R_MIPS_SHIFT6 = 17,
R_MIPS_64 = 18,
R_MIPS_GOT_DISP = 19,
R_MIPS_GOT_PAGE = 20,
R_MIPS_GOT_OFST = 21,
R_MIPS_GOT_HI16 = 22,
R_MIPS_GOT_LO16 = 23,
R_MIPS_SUB = 24,
R_MIPS_INSERT_A = 25,
R_MIPS_INSERT_B = 26,
R_MIPS_DELETE = 27,
R_MIPS_HIGHER = 28,
R_MIPS_HIGHEST = 29,
R_MIPS_CALL_HI16 = 30,
R_MIPS_CALL_LO16 = 31,
R_MIPS_SCN_DISP = 32,
R_MIPS_REL16 = 33,
R_MIPS_ADD_IMMEDIATE = 34,
R_MIPS_PJUMP = 35,
R_MIPS_RELGOT = 36,
R_MIPS_JALR = 37,
R_MIPS_TLS_DTPMOD32 = 38,
R_MIPS_TLS_DTPREL32 = 39,
R_MIPS_TLS_DTPMOD64 = 40,
R_MIPS_TLS_DTPREL64 = 41,
R_MIPS_TLS_GD = 42,
R_MIPS_TLS_LDM = 43,
R_MIPS_TLS_DTPREL_HI16 = 44,
R_MIPS_TLS_DTPREL_LO16 = 45,
R_MIPS_TLS_GOTTPREL = 46,
R_MIPS_TLS_TPREL32 = 47,
R_MIPS_TLS_TPREL64 = 48,
R_MIPS_TLS_TPREL_HI16 = 49,
R_MIPS_TLS_TPREL_LO16 = 50,
R_MIPS_GLOB_DAT = 51,
R_MIPS_PC21_S2 = 60,
R_MIPS_PC26_S2 = 61,
R_MIPS_PC18_S3 = 62,
R_MIPS_PC19_S2 = 63,
R_MIPS_PCHI16 = 64,
R_MIPS_PCLO16 = 65,
R_MIPS16_26 = 100,
R_MIPS16_GPREL = 101,
R_MIPS16_GOT16 = 102,
R_MIPS16_CALL16 = 103,
R_MIPS16_HI16 = 104,
R_MIPS16_LO16 = 105,
R_MIPS16_TLS_GD = 106,
R_MIPS16_TLS_LDM = 107,
R_MIPS16_TLS_DTPREL_HI16= 108,
R_MIPS16_TLS_DTPREL_LO16= 109,
R_MIPS16_TLS_GOTTPREL = 110,
R_MIPS16_TLS_TPREL_HI16 = 111,
R_MIPS16_TLS_TPREL_LO16 = 112,
R_MIPS16_PC16_S1 = 113,
// For these two:
// http://sourceware.org/ml/binutils/2008-07/txt00000.txt
R_MIPS_COPY = 126,
R_MIPS_JUMP_SLOT = 127,
// from binutils/include/elf/mips.h
R_MICROMIPS_26_S1 = 133,
R_MICROMIPS_HI16 = 134,
R_MICROMIPS_LO16 = 135,
R_MICROMIPS_GPREL16 = 136,
R_MICROMIPS_LITERAL = 137,
R_MICROMIPS_GOT16 = 138,
R_MICROMIPS_PC7_S1 = 139,
R_MICROMIPS_PC10_S1 = 140,
R_MICROMIPS_PC16_S1 = 141,
R_MICROMIPS_CALL16 = 142,
R_MICROMIPS_GOT_DISP = 145,
R_MICROMIPS_GOT_PAGE = 146,
R_MICROMIPS_GOT_OFST = 147,
R_MICROMIPS_GOT_HI16 = 148,
R_MICROMIPS_GOT_LO16 = 149,
R_MICROMIPS_SUB = 150,
R_MICROMIPS_HIGHER = 151,
R_MICROMIPS_HIGHEST = 152,
R_MICROMIPS_CALL_HI16 = 153,
R_MICROMIPS_CALL_LO16 = 154,
R_MICROMIPS_SCN_DISP = 155,
R_MICROMIPS_JALR = 156,
R_MICROMIPS_HI0_LO16 = 157,
/* TLS relocations. */
R_MICROMIPS_TLS_GD = 162,
R_MICROMIPS_TLS_LDM = 163,
R_MICROMIPS_TLS_DTPREL_HI16 = 164,
R_MICROMIPS_TLS_DTPREL_LO16 = 165,
R_MICROMIPS_TLS_GOTTPREL = 166,
R_MICROMIPS_TLS_TPREL_HI16 = 169,
R_MICROMIPS_TLS_TPREL_LO16 = 170,
/* microMIPS GP- and PC-relative relocations. */
R_MICROMIPS_GPREL7_S2 = 172,
R_MICROMIPS_PC23_S2 = 173,
R_MIPS_PC32 = 248,
R_MIPS_EH = 249,
R_MIPS_GNU_REL16_S2 = 250,
R_MIPS_GNU_VTINHERIT = 253,
R_MIPS_GNU_VTENTRY = 254,
// artificial types for the complex 32bit relocs
R_MIPS_GPDISP_LO16 = 200,
R_MIPS_GPDISP_HI16 = 201,
R_MICROMIPS_GPDISP_HI16 = 202,
R_MICROMIPS_GPDISP_LO16 = 203,
};
enum elf_ET_MIPS
{
ET_IRX = 0xFF80u, // IRX file for PS2's IOP
ET_PSPEXEC = 0xFFA0u // Sony PSP executable file
};
enum elf_PHT_MIPS
{
PT_MIPS_IOPMOD = 0x70000080, // Sony PS2 IOP module extension
PT_MIPS_EEMOD = 0x70000090, // Sony PS2 EE module extension
PT_MIPS_PSPREL = 0x700000A0, // Sony PRX relocations (ELF-style)
PT_MIPS_PSPREL2 = 0x700000A1, // Sony PRX relocations (packed)
// From binutils-2.27/elfcpp/elfcpp.h
PT_MIPS_REGINFO = 0x70000000, // Register usage information. Identifies one .reginfo section.
PT_MIPS_RTPROC = 0x70000001, // Runtime procedure table.
PT_MIPS_OPTIONS = 0x70000002, // .MIPS.options section.
PT_MIPS_ABIFLAGS = 0x70000003, // .MIPS.abiflags section.
};
enum elf_DTAG_MIPS
{
DT_MIPS_RLD_VERSION = 0x70000001, /* 32 bit version number for runtime linker interface. */
DT_MIPS_TIME_STAMP = 0x70000002, /* Time stamp. */
DT_MIPS_ICHECKSUM = 0x70000003, /* Checksum of external strings and common sizes. */
DT_MIPS_IVERSION = 0x70000004, /* Index of version string in string table. */
DT_MIPS_FLAGS = 0x70000005, /* 32 bits of flags. */
DT_MIPS_BASE_ADDRESS = 0x70000006, /* Base address of the segment. */
DT_MIPS_MSYM = 0x70000007, /* adress of the msym table */
DT_MIPS_CONFLICT = 0x70000008, /* Address of .conflict section. */
DT_MIPS_LIBLIST = 0x70000009, /* Address of .liblist section. */
DT_MIPS_LOCAL_GOTNO = 0x7000000a, /* Number of local global offset table entries. */
DT_MIPS_CONFLICTNO = 0x7000000b, /* Number of entries in the .conflict section. */
DT_MIPS_LIBLISTNO = 0x70000010, /* Number of entries in the .liblist section. */
DT_MIPS_SYMTABNO = 0x70000011, /* Number of entries in the .dynsym section. */
DT_MIPS_UNREFEXTNO = 0x70000012, /* Index of first external dynamic symbol not referenced locally. */
DT_MIPS_GOTSYM = 0x70000013, /* Index of first dynamic symbol in global offset table. */
DT_MIPS_HIPAGENO = 0x70000014, /* Number of page table entries in global offset table. */
DT_MIPS_RLD_MAP = 0x70000016, /* Address of run time loader map, used for debugging. */
DT_MIPS_DELTA_CLASS = 0x70000017, /* Delta C++ class definition. */
DT_MIPS_DELTA_CLASS_NO = 0x70000018, /* Number of entries in DT_MIPS_DELTA_CLASS. */
DT_MIPS_DELTA_INSTANCE = 0x70000019, /* Delta C++ class instances. */
DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a, /* Number of entries in DT_MIPS_DELTA_INSTANCE. */
DT_MIPS_DELTA_RELOC = 0x7000001b, /* Delta relocations. */
DT_MIPS_DELTA_RELOC_NO = 0x7000001c, /* Number of entries in DT_MIPS_DELTA_RELOC. */
DT_MIPS_DELTA_SYM = 0x7000001d, /* Delta symbols that Delta relocations refer to. */
DT_MIPS_DELTA_SYM_NO = 0x7000001e, /* Number of entries in DT_MIPS_DELTA_SYM. */
DT_MIPS_DELTA_CLASSSYM = 0x70000020, /* Delta symbols that hold class declarations. */
DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021, /* Number of entries in DT_MIPS_DELTA_CLASSSYM. */
DT_MIPS_CXX_FLAGS = 0x70000022, /* Flags indicating information about C++ flavor. */
DT_MIPS_PIXIE_INIT = 0x70000023, /* Pixie information (???). */
DT_MIPS_SYMBOL_LIB = 0x70000024, /* Address of .MIPS.symlib */
DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025, /* The GOT index of the first PTE for a segment */
DT_MIPS_LOCAL_GOTIDX = 0x70000026, /* The GOT index of the first PTE for a local symbol */
DT_MIPS_HIDDEN_GOTIDX = 0x70000027, /* The GOT index of the first PTE for a hidden symbol */
DT_MIPS_PROTECTED_GOTIDX = 0x70000028, /* The GOT index of the first PTE for a protected symbol */
DT_MIPS_OPTIONS = 0x70000029, /* Address of `.MIPS.options'. */
DT_MIPS_INTERFACE = 0x7000002a, /* Address of `.interface'. */
DT_MIPS_DYNSTR_ALIGN = 0x7000002b, /* ??? */
DT_MIPS_INTERFACE_SIZE = 0x7000002c, /* Size of the .interface section. */
DT_MIPS_RLD_TEXT_RESOLVE_ADDR= 0x7000002d, /* Size of rld_text_resolve function stored in the GOT. */
DT_MIPS_PERF_SUFFIX = 0x7000002e, /* Default suffix of DSO to be added by rld on dlopen() calls. */
DT_MIPS_COMPACT_SIZE = 0x7000002f, /* Size of compact relocation section (O32). */
DT_MIPS_GP_VALUE = 0x70000030, /* GP value for auxiliary GOTs. */
DT_MIPS_AUX_DYNAMIC = 0x70000031, /* Address of auxiliary .dynamic. */
DT_MIPS_PLTGOT = 0x70000032, /* Address of the base of the PLTGOT */
DT_MIPS_RWPLT = 0x70000034, /* Points to the base of a writable PLT. */
};
enum elf_SHN_MIPS
{
SHN_MIPS_ACOMMON = 0xff00, // Defined and allocated common symbol. Value is virtual address.
SHN_MIPS_TEXT = 0xff01, // Defined and allocated text symbol. Value is virtual address.
SHN_MIPS_DATA = 0xff02, // Defined and allocated data symbol. Value is virtual address.
SHN_MIPS_SCOMMON = 0xff03, // Small common symbol.
SHN_MIPS_SUNDEFINED = 0xff04 // Small undefined symbol.
};
enum elf_SHF_MIPS
{
SHF_MIPS_GPREL = 0x10000000, // Section must be part of global data area.
SHF_MIPS_MERGE = 0x20000000, // Section data should be merged to eliminate duplication
SHF_MIPS_ADDR = 0x40000000, // Section data is addresses by default. Address size to be inferred from section entry size.
SHF_MIPS_STRING = 0x80000000, // Section data is string data by default
SHF_MIPS_NOSTRIP = 0x08000000, // Section data may not be stripped
SHF_MIPS_LOCAL = 0x04000000, // Section data local to process
SHF_MIPS_NAMES = 0x02000000, // Linker must generate implicit hidden weak names
SHF_MIPS_NODUPE = 0x01000000, // Section contains text/data which may be replicated in other sections. Linker must retain only one copy.
};
enum elf_SHT_MIPS
{
SHT_MIPS_LIBLIST = 0x70000000, // contains the set of dynamic shared objects used when statically linking.
SHT_MIPS_MSYM = 0x70000001, // unknown Irix5 usage
SHT_MIPS_CONFLICT = 0x70000002, // list of confliction symbols
SHT_MIPS_GPTAB = 0x70000003, // Section contains the global pointer table.
SHT_MIPS_UCODE = 0x70000004, // microcode information
SHT_MIPS_DEBUG = 0x70000005, // start of debugging information
SHT_MIPS_REGINFO = 0x70000006, // Section contains register usage information.
SHT_MIPS_RELD = 0x70000009, // Dynamic relocation?
SHT_MIPS_IFACE = 0x7000000B, // Subprogram interface information
SHT_MIPS_CONTENT = 0x7000000C, // Section content classification
SHT_MIPS_OPTIONS = 0x7000000D, // General options
SHT_MIPS_DELTASYM = 0x7000001B, // Delta C++: symbol table
SHT_MIPS_DELTAINST = 0x7000001C, // Delta C++: instance table
SHT_MIPS_DELTACLASS = 0x7000001D, // Delta C++: class table
SHT_MIPS_DWARF = 0x7000001E, // DWARF debugging section.
SHT_MIPS_DELTADECL = 0x7000001F, // Delta C++: declarations
SHT_MIPS_SYMBOL_LIB = 0x70000020, // unknown Irix6 usage
SHT_MIPS_EVENTS = 0x70000021, // Events section.
SHT_MIPS_TRANSLATE = 0x70000022, // ???
SHT_MIPS_PIXIE = 0x70000023, // Special pixie sections
SHT_MIPS_XLATE = 0x70000024, // Address translation table
SHT_MIPS_XLATE_DEBUG = 0x70000025, // SGI internal address translation table
SHT_MIPS_WHIRL = 0x70000026, // Intermediate code
SHT_MIPS_EH_REGION = 0x70000027, // C++ exception handling region info
SHT_MIPS_XLATE_OLD = 0x70000028, // Obsolete
SHT_MIPS_PDR_EXCEPTION = 0x70000029, // Runtime procedure descriptor table exception information (ucode)
SHT_MIPS_IOPMOD = 0x70000080, // .ipmod section for PS2 IRXs
SHT_MIPS_PSPREL = 0x700000A0, // PSP executable relocation section
// VU overlay table (PS2?)
SHT_DVP_OVERLAY_TABLE = 0x7FFFF420,
SHT_DVP_OVERLAY = 0x7FFFF421,
};
// Special values for the st_other field in the symbol table.
enum elf_STO_MIPS
{
// Two topmost bits denote the MIPS ISA for .text symbols:
// + 00 -- standard MIPS code,
// + 10 -- microMIPS code,
// + 11 -- MIPS16 code; requires the following two bits to be set too.
// Note that one of the MIPS16 bits overlaps with STO_MIPS_PIC.
STO_MIPS_ISA = 0xc0,
// The MIPS psABI was updated in 2008 with support for PLTs and copy
// relocs. There are therefore two types of nonzero SHN_UNDEF functions:
// PLT entries and traditional MIPS lazy binding stubs. We mark the former
// with STO_MIPS_PLT to distinguish them from the latter.
STO_MIPS_PLT = 0x8,
// This value is used to mark PIC functions in an object that mixes
// PIC and non-PIC. Note that this bit overlaps with STO_MIPS16,
// although MIPS16 symbols are never considered to be MIPS_PIC.
STO_MIPS_PIC = 0x20,
// This value is used for a mips16 .text symbol.
STO_MIPS16 = 0xf0,
// This value is used for a microMIPS .text symbol. To distinguish from
// STO_MIPS16, we set top two bits to be 10 to denote STO_MICROMIPS. The
// mask is STO_MIPS_ISA.
STO_MICROMIPS = 0x80
};
// .MIPS.options descriptor kinds
enum elf_ODK_MIPS
{
ODK_NULL = 0, // Undefined
ODK_REGINFO = 1, // Register usage information
ODK_EXCEPTIONS = 2, // Exception processing options
ODK_PAD = 3, // Section padding options
ODK_HWPATCH = 4, // Hardware patches applied
ODK_FILL = 5, // Linker fill value
ODK_TAGS = 6, // Space for tool identification
ODK_HWAND = 7, // Hardware AND patches applied
ODK_HWOR = 8, // Hardware OR patches applied
ODK_GP_GROUP = 9, // GP group to use for text/data sections
ODK_IDENT = 10, // ID information
ODK_PAGESIZE = 11, // Page size information
};
// PSP-specific encoding of r_info field
// segment in which the relocation resides
// i.e. relocation is at pht[ofs_base].p_vaddr + r_offset
#define ELF32_R_OFS_BASE(i) (((i)>>8) & 0xFF)
// segment number with the target
// i.e. the final address should be adjusted with pht[ofs_base].p_vaddr
#define ELF32_R_ADDR_BASE(i) (((i)>>16) & 0xFF)
// MIPS ELF 64 relocation info access macros.
// they assume BE byte order of the packed r_type field
#define ELF64_MIPS_R_SSYM(i) (((i) >> 24) & 0xff)
#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff)
#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff)
#define ELF64_MIPS_R_TYPE(i) ((i) & 0xff)
// Values found in the r_ssym field of a relocation entry.
// No relocation.
#define RSS_UNDEF 0
// Value of GP.
#define RSS_GP 1
// Value of GP in object being relocated.
#define RSS_GP0 2
// Address of location being relocated.
#define RSS_LOC 3
// MIPS .msym table entry
struct Elf32_Msym
{
uint32 ms_hash_value; // Contains the hash value computed from the name of the corresponding dynamic symbol
uint32 ms_info; // Contains both the dynamic relocation index and the symbol flags field.
};
#define ELF32_MS_REL_INDEX(i) ((i) >> 8)
#define ELF32_MS_FLAGS(i) ((i) & 0xff)
#define ELF32_MS_INFO(r,f) (((r) << 8) + ((f) & 0xff))
// MIPS .liblist entry
typedef struct
{
uint32 l_name; // Records the name of a shared library dependency.
// The value is a string table index. This name can be a
// full pathname, relative pathname, or file name.
uint32 l_time_stamp;// Records the time stamp of a shared library dependency.
uint32 l_checksum; // Records the checksum of a shared library dependency.
uint32 l_version; // Records the interface version of a shared library dependency.
// The value is a string table index.
uint32 l_flags;
} Elf64_Lib;
// bits for l_flags:
#define LL_NONE 0
#define LL_EXACT_MATCH 0x1 // Requires that the run-time dynamic shared library file match
// exactly the shared library file used at static link time.
#define LL_IGNORE_INT_VER 0x2 // Ignores any version incompatibility between the dynamic
// shared library file and the shared library file used at link time.
#define LL_REQUIRE_MINOR 0x4 // Marks shared library dependencies that should be loaded with
// a suffix appended to the name. The DT_SO_SUFFIX entry in
// the .dynamic section records the name of this suffix. This is
// used by object instrumentation tools to distinguish
// instrumented shared libraries.
#define LL_EXPORTS 0x8 // Marks entries for shared libraries that are not loaded as direct
// dependencies of an object.
#define LL_DELAY_LOAD 0x10
#define LL_DELTA 0x20
//.reginfo section
struct Elf32_RegInfo
{
uint32 ri_gprmask;
uint32 ri_cprmask[4];
uint32 ri_gp_value;
};
void set_mips_compact_encoding(ea_t ea, bool enable);
void relocate_psp_section(Elf64_Shdr *rsh, linput_t *li);
inline bool is_psp_file(const reader_t &reader)
{
return reader.get_header().e_machine == EM_MIPS
&& reader.get_header().e_type == ET_PSPEXEC;
}
#endif

383
idasdk76/ldr/elf/elfr_ppc.h Normal file
View File

@@ -0,0 +1,383 @@
#ifndef __ELFR_PPC_H__
#define __ELFR_PPC_H__
#ifndef __ELFBASE_H__
#include "elfbase.h"
#endif
#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag */
#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */
// PowerPC 64 ABI version
#define EF_PPC64_ABI_MASK 3 // original function descriptor using ABI
#define EF_PPC64_UNK_ABI 0 // unspecified or not using any features
// affected by the differences
#define EF_PPC64_AIX_ABI 1 // original function descriptor using ABI
#define EF_PPC64_V2_ABI 2 // revised ABI without function descriptors
enum elf_ET_PPC
{
ET_PS3PRX = 0xFFA4, // Sony PS3 PRX
};
enum elf_SHT_PPC
{
SHT_PS3PRX_RELA = 0x700000A4, // Sony PS3 PRX relocations
};
enum elf_PHT_PPC
{
PHT_PS3PRX_RELA = 0x700000A4, // Sony PS3 PRX relocations
};
enum elf_DT_PPC
{
DT_PPC_GOT = (DT_LOPROC + 0x0), // address of _GLOBAL_OFFSET_TABLE_
};
// relocation field - word32 with HIGH BYTE FIRST!!!
// A- from Elf32_Rela
// B- Loading address of shared object
// G- offset into global objet table
// GOT- adress of global object table
// L- linkage table entry
// P- plase of storage unit (computed using r_offset)
// S- value of symbol
enum elf_RTYPE_ppc
{
R_PPC_NONE = 0, // No reloc
R_PPC_ADDR32 = 1, // S+A-P Direct 32 bit
R_PPC_ADDR24 = 2,
R_PPC_ADDR16 = 3,
R_PPC_ADDR16_LO = 4,
R_PPC_ADDR16_HI = 5,
R_PPC_ADDR16_HA = 6,
R_PPC_ADDR14 = 7,
R_PPC_ADDR14_BRTAKEN = 8,
R_PPC_ADDR14_BRNTAKEN = 9,
R_PPC_REL24 = 10, // S+A relative 24 bit
R_PPC_REL14 = 11,
R_PPC_REL14_BRTAKEN = 12,
R_PPC_REL14_BRNTAKEN = 13,
R_PPC_GOT16 = 14,
R_PPC_GOT16_LO = 15,
R_PPC_GOT16_HI = 16,
R_PPC_GOT16_HA = 17,
R_PPC_PLTREL24 = 18,
R_PPC_COPY = 19,
R_PPC_GLOB_DAT = 20,
R_PPC_JMP_SLOT = 21,
R_PPC_RELATIVE = 22,
R_PPC_LOCAL24PC = 23,
R_PPC_UADDR32 = 24,
R_PPC_UADDR16 = 25,
R_PPC_REL32 = 26,
R_PPC_PLT32 = 27,
R_PPC_PLTREL32 = 28,
R_PPC_PLT16_LO = 29,
R_PPC_PLT16_HI = 30,
R_PPC_PLT16_HA = 31,
R_PPC_SDAREL16 = 32,
R_PPC_SECTOFF = 33,
R_PPC_SECTOFF_LO = 34,
R_PPC_SECTOFF_HI = 35,
R_PPC_SECTOFF_HA = 36,
R_PPC_ADDR30 = 37, // word30 (S + A - P) >> 2
// some undocumented relocs used by freescale
// some seem to be the same as official VLE relocs below
// NB! they conflict with some PPC64 relocations
R_PPC_FVLE_REL8 = 38, // same as R_PPC_VLE_REL8?
R_PPC_FVLE_REL15 = 39, // same as R_PPC_VLE_REL15?
R_PPC_FVLE_REL24 = 40, // same as R_PPC_VLE_REL24?
R_PPC_FVLE_ADDR8 = 44, // ??
R_PPC_FVLE_ADDR4 = 45, // ??
R_PPC_FVLE_SDA = 47, // same as R_PPC_VLE_SDA21?
R_PPC_FVLE_LO16A = 49, // same as R_PPC_VLE_LO16A?
R_PPC_FVLE_HI16A = 50, // same as R_PPC_VLE_HI16A?
R_PPC_FVLE_HA16A = 51, // same as R_PPC_VLE_HA16A?
R_PPC_FVLE_LO16D = 56, // same as R_PPC_VLE_LO16D?
R_PPC_FVLE_HI16D = 57, // same as R_PPC_VLE_HI16D?
R_PPC_FVLE_HA16D = 58, // same as R_PPC_VLE_HA16D?
/* Relocs added to support TLS. */
R_PPC_TLS = 67,
R_PPC_DTPMOD32 = 68,
R_PPC_TPREL16 = 69,
R_PPC_TPREL16_LO = 70,
R_PPC_TPREL16_HI = 71,
R_PPC_TPREL16_HA = 72,
R_PPC_TPREL32 = 73,
R_PPC_DTPREL16 = 74,
R_PPC_DTPREL16_LO = 75,
R_PPC_DTPREL16_HI = 76,
R_PPC_DTPREL16_HA = 77,
R_PPC_DTPREL32 = 78,
R_PPC_GOT_TLSGD16 = 79,
R_PPC_GOT_TLSGD16_LO = 80,
R_PPC_GOT_TLSGD16_HI = 81,
R_PPC_GOT_TLSGD16_HA = 82,
R_PPC_GOT_TLSLD16 = 83,
R_PPC_GOT_TLSLD16_LO = 84,
R_PPC_GOT_TLSLD16_HI = 85,
R_PPC_GOT_TLSLD16_HA = 86,
R_PPC_GOT_TPREL16 = 87,
R_PPC_GOT_TPREL16_LO = 88,
R_PPC_GOT_TPREL16_HI = 89,
R_PPC_GOT_TPREL16_HA = 90,
R_PPC_GOT_DTPREL16 = 91,
R_PPC_GOT_DTPREL16_LO = 92,
R_PPC_GOT_DTPREL16_HI = 93,
R_PPC_GOT_DTPREL16_HA = 94,
R_PPC_TLSGD = 95,
R_PPC_TLSLD = 96,
R_PPC_EMB_NADDR32 = 101, // word32 (A - S)
R_PPC_EMB_NADDR16 = 102, // half16* (A - S)
R_PPC_EMB_NADDR16_LO = 103, // half16 #lo(A - S)
R_PPC_EMB_NADDR16_HI = 104, // half16 #hi(A - S)
R_PPC_EMB_NADDR16_HA = 105, // half16 #ha(A - S)
R_PPC_EMB_SDA_I16 = 106, // half16* T
R_PPC_EMB_SDA2_I16 = 107, // half16* U
R_PPC_EMB_SDA2REL = 108, // half16* S + A - _SDA2_BASE_
R_PPC_EMB_SDA21 = 109, // low21 Y || (X + A)
R_PPC_EMB_MRKREF = 110, // none See below
R_PPC_EMB_RELSEC16 = 111, // half16* V + A
R_PPC_EMB_RELST_LO = 112, // half16 #lo(W + A)
R_PPC_EMB_RELST_HI = 113, // half16 #hi(W + A)
R_PPC_EMB_RELST_HA = 114, // half16 #ha(W + A)
R_PPC_EMB_BIT_FLD = 115, // word32* See below
R_PPC_EMB_RELSDA = 116, // half16* X + A. See below
R_PPC_EMB_RELOC_120 = 120, // half16* S + A
R_PPC_EMB_RELOC_121 = 121, // half16* Same calculation as U, except that the value 0 is used instead of _SDA2_BASE_.
/* The R_PPC_DIAB_SDA21_xx relocation modes work like the R_PPC_EMB_SDA21 mode
* and the R_PPC_DIAB_RELSDA_xx relocation modes work like the R_PPC_EMB_RELSDA mode
* with the following exceptions:
* If the symbol is in .data, .sdata, .bss, .sbss the symbol is DATA relative
(r13 base pointer/_SDA_BASE_ base address)
* If the symbol is in .text, .sdata2, .sbss2 the symbol is CODE relative
(r2 base pointer/_SDA_BASE2_ base address)
* Otherwise the symbol is absolute (r0 base pointer/0 base address)
*/
R_PPC_DIAB_SDA21_LO = 180, // half21 Y || #lo(X + A)
R_PPC_DIAB_SDA21_HI = 181, // half21 Y || #hi(X + A)
R_PPC_DIAB_SDA21_HA = 182, // half21 Y || #ha(X + A)
R_PPC_DIAB_RELSDA_LO = 183, // half16 #lo(X + A)
R_PPC_DIAB_RELSDA_HI = 184, // half16 #hi(X + A)
R_PPC_DIAB_RELSDA_HA = 185, // half16 #ha(X + A)
R_PPC_DIAB_IMTO = 186,
R_PPC_DIAB_IMT = 187,
R_PPC_DIAB_ADDR0 = 188,
R_PPC_DIAB_OVERRIDE0 = 189,
R_PPC_DIAB_VTBL32 = 190,
R_PPC_DIAB_LAST = 191,
R_PPC_EMB_SPE_DOUBLE = 201, // mid5* (#lo(S + A)) >> 3
R_PPC_EMB_SPE_WORD = 202, // mid5* (#lo(S + A)) >> 2
R_PPC_EMB_SPE_HALF = 203, // mid5* (#lo(S + A)) >> 1
R_PPC_EMB_SPE_DOUBLE_SDAREL = 204, // mid5* (#lo(S + A - _SDA_BASE_)) >> 3
R_PPC_EMB_SPE_WORD_SDAREL = 205, // mid5* (#lo(S + A - _SDA_BASE_)) >> 2
R_PPC_EMB_SPE_HALF_SDAREL = 206, // mid5* (#lo(S + A - _SDA_BASE_)) >> 1
R_PPC_EMB_SPE_DOUBLE_SDA2REL = 207, // mid5* (#lo(S + A - _SDA2_BASE_)) >> 3
R_PPC_EMB_SPE_WORD_SDA2REL = 208, // mid5* (#lo(S + A - _SDA2_BASE_)) >> 2
R_PPC_EMB_SPE_HALF_SDA2REL = 209, // mid5* (#lo(S + A - _SDA2_BASE_)) >> 1
R_PPC_EMB_SPE_DOUBLE_SDA0REL = 210, // mid5* (#lo(S + A)) >> 3
R_PPC_EMB_SPE_WORD_SDA0REL = 211, // mid5* (#lo(S + A)) >> 2
R_PPC_EMB_SPE_HALF_SDA0REL = 212, // mid5* (#lo(S + A)) >> 1
R_PPC_EMB_SPE_DOUBLE_SDA = 213, // mid10* Y || ((#lo(X + A)) >> 3)
R_PPC_EMB_SPE_WORD_SDA = 214, // mid10* Y || ((#lo(X + A)) >> 2)
R_PPC_EMB_SPE_HALF_SDA = 215, // mid10* Y || ((#lo(X + A)) >> 1)
R_PPC_VLE_REL8 = 216, // bdh8 (S + A - P) >> 1
R_PPC_VLE_REL15 = 217, // bdh15 (S + A - P) >> 1
R_PPC_VLE_REL24 = 218, // bdh24 (S + A - P) >> 1
R_PPC_VLE_LO16A = 219, // split16a #lo(S + A)
R_PPC_VLE_LO16D = 220, // split16d #lo(S + A)
R_PPC_VLE_HI16A = 221, // split16a #hi(S + A)
R_PPC_VLE_HI16D = 222, // split16d #hi(S + A)
R_PPC_VLE_HA16A = 223, // split16a #ha(S + A)
R_PPC_VLE_HA16D = 224, // split16d #ha(S + A)
R_PPC_VLE_SDA21 = 225, // low21, split20 Y || (X + A)
R_PPC_VLE_SDA21_LO = 226, // low21, split20 Y || #lo(X + A)
R_PPC_VLE_SDAREL_LO16A = 227, // split16a #lo(X + A)
R_PPC_VLE_SDAREL_LO16D = 228, // split16d #lo(X + A)
R_PPC_VLE_SDAREL_HI16A = 229, // split16a #hi(X + A)
R_PPC_VLE_SDAREL_HI16D = 230, // split16d #hi(X + A)
R_PPC_VLE_SDAREL_HA16A = 231, // split16a #ha(X + A)
R_PPC_VLE_SDAREL_HA16D = 232, // split16d #ha(X + A)
R_PPC_REL16DX_HA = 246,
R_PPC_IRELATIVE = 248, // GNU extension to support local ifunc.
/* GNU relocs used in PIC code sequences. */
R_PPC_REL16 = 249, // half16* S + A - P
R_PPC_REL16_LO = 250, // half16 #lo(S + A - P)
R_PPC_REL16_HI = 251, // half16 #hi(S + A - P)
R_PPC_REL16_HA = 252, // half16 #la(S + A - P)
R_PPC_GNU_VTINHERIT = 253,
R_PPC_GNU_VTENTRY = 254,
/* This is a phony reloc to handle any old fashioned TOC16 references
that may still be in object files. */
R_PPC_TOC16 = 255,
// PowerPC64 relocations. Many (but not all) of them are the same as for PPC32
R_PPC64_NONE = R_PPC_NONE,
R_PPC64_ADDR32 = R_PPC_ADDR32, /* 32bit absolute address. */
R_PPC64_ADDR24 = R_PPC_ADDR24, /* 26bit address, word aligned. */
R_PPC64_ADDR16 = R_PPC_ADDR16, /* 16bit absolute address. */
R_PPC64_ADDR16_LO = R_PPC_ADDR16_LO, /* lower 16bits of abs. address. */
R_PPC64_ADDR16_HI = R_PPC_ADDR16_HI, /* high 16bits of abs. address. */
R_PPC64_ADDR16_HA = R_PPC_ADDR16_HA, /* adjusted high 16bits. */
R_PPC64_ADDR14 = R_PPC_ADDR14, /* 16bit address, word aligned. */
R_PPC64_ADDR14_BRTAKEN = R_PPC_ADDR14_BRTAKEN,
R_PPC64_ADDR14_BRNTAKEN = R_PPC_ADDR14_BRNTAKEN,
R_PPC64_REL24 = R_PPC_REL24, /* PC relative 26 bit, word aligned. */
R_PPC64_REL14 = R_PPC_REL14, /* PC relative 16 bit. */
R_PPC64_REL14_BRTAKEN = R_PPC_REL14_BRTAKEN,
R_PPC64_REL14_BRNTAKEN = R_PPC_REL14_BRNTAKEN,
R_PPC64_GOT16 = R_PPC_GOT16,
R_PPC64_GOT16_LO = R_PPC_GOT16_LO,
R_PPC64_GOT16_HI = R_PPC_GOT16_HI,
R_PPC64_GOT16_HA = R_PPC_GOT16_HA,
R_PPC64_PLTREL24 = R_PPC_PLTREL24,
R_PPC64_COPY = R_PPC_COPY,
R_PPC64_GLOB_DAT = R_PPC_GLOB_DAT,
R_PPC64_JMP_SLOT = R_PPC_JMP_SLOT,
R_PPC64_RELATIVE = R_PPC_RELATIVE,
R_PPC64_LOCAL24PC = R_PPC_LOCAL24PC,
R_PPC64_UADDR32 = R_PPC_UADDR32,
R_PPC64_UADDR16 = R_PPC_UADDR16,
R_PPC64_REL32 = R_PPC_REL32,
R_PPC64_PLT32 = R_PPC_PLT32,
R_PPC64_PLTREL32 = R_PPC_PLTREL32,
R_PPC64_PLT16_LO = R_PPC_PLT16_LO,
R_PPC64_PLT16_HI = R_PPC_PLT16_HI,
R_PPC64_PLT16_HA = R_PPC_PLT16_HA,
R_PPC64_SDAREL16 = R_PPC_SDAREL16,
R_PPC64_SECTOFF = R_PPC_SECTOFF,
R_PPC64_SECTOFF_LO = R_PPC_SECTOFF_LO,
R_PPC64_SECTOFF_HI = R_PPC_SECTOFF_HI,
R_PPC64_SECTOFF_HA = R_PPC_SECTOFF_HA,
R_PPC64_ADDR30 = 37, /* word30 (S + A - P) >> 2. */
R_PPC64_ADDR64 = 38, /* doubleword64 S + A. */
R_PPC64_ADDR16_HIGHER = 39, /* half16 #higher(S + A). */
R_PPC64_ADDR16_HIGHERA = 40, /* half16 #highera(S + A). */
R_PPC64_ADDR16_HIGHEST = 41, /* half16 #highest(S + A). */
R_PPC64_ADDR16_HIGHESTA = 42, /* half16 #highesta(S + A). */
R_PPC64_UADDR64 = 43, /* doubleword64 S + A. */
R_PPC64_REL64 = 44, /* doubleword64 S + A - P. */
R_PPC64_PLT64 = 45, /* doubleword64 L + A. */
R_PPC64_PLTREL64 = 46, /* doubleword64 L + A - P. */
R_PPC64_TOC16 = 47, /* half16* S + A - .TOC. */
R_PPC64_TOC16_LO = 48, /* half16 #lo(S + A - .TOC.). */
R_PPC64_TOC16_HI = 49, /* half16 #hi(S + A - .TOC.). */
R_PPC64_TOC16_HA = 50, /* half16 #ha(S + A - .TOC.). */
R_PPC64_TOC = 51, /* doubleword64 .TOC. */
R_PPC64_PLTGOT16 = 52, /* half16* M + A. */
R_PPC64_PLTGOT16_LO = 53, /* half16 #lo(M + A). */
R_PPC64_PLTGOT16_HI = 54, /* half16 #hi(M + A). */
R_PPC64_PLTGOT16_HA = 55, /* half16 #ha(M + A). */
R_PPC64_ADDR16_DS = 56, /* half16ds* (S + A) >> 2. */
R_PPC64_ADDR16_LO_DS = 57, /* half16ds #lo(S + A) >> 2. */
R_PPC64_GOT16_DS = 58, /* half16ds* (G + A) >> 2. */
R_PPC64_GOT16_LO_DS = 59, /* half16ds #lo(G + A) >> 2. */
R_PPC64_PLT16_LO_DS = 60, /* half16ds #lo(L + A) >> 2. */
R_PPC64_SECTOFF_DS = 61, /* half16ds* (R + A) >> 2. */
R_PPC64_SECTOFF_LO_DS = 62, /* half16ds #lo(R + A) >> 2. */
R_PPC64_TOC16_DS = 63, /* half16ds* (S + A - .TOC.) >> 2. */
R_PPC64_TOC16_LO_DS = 64, /* half16ds #lo(S + A - .TOC.) >> 2. */
R_PPC64_PLTGOT16_DS = 65, /* half16ds* (M + A) >> 2. */
R_PPC64_PLTGOT16_LO_DS = 66, /* half16ds #lo(M + A) >> 2. */
/* PowerPC64 relocations defined for the TLS access ABI. */
R_PPC64_TLS = 67, /* none (sym+add)@tls */
R_PPC64_DTPMOD64 = 68, /* doubleword64 (sym+add)@dtpmod */
R_PPC64_TPREL16 = 69, /* half16* (sym+add)@tprel */
R_PPC64_TPREL16_LO = 70, /* half16 (sym+add)@tprel@l */
R_PPC64_TPREL16_HI = 71, /* half16 (sym+add)@tprel@h */
R_PPC64_TPREL16_HA = 72, /* half16 (sym+add)@tprel@ha */
R_PPC64_TPREL64 = 73, /* doubleword64 (sym+add)@tprel */
R_PPC64_DTPREL16 = 74, /* half16* (sym+add)@dtprel */
R_PPC64_DTPREL16_LO = 75, /* half16 (sym+add)@dtprel@l */
R_PPC64_DTPREL16_HI = 76, /* half16 (sym+add)@dtprel@h */
R_PPC64_DTPREL16_HA = 77, /* half16 (sym+add)@dtprel@ha */
R_PPC64_DTPREL64 = 78, /* doubleword64 (sym+add)@dtprel */
R_PPC64_GOT_TLSGD16 = 79, /* half16* (sym+add)@got@tlsgd */
R_PPC64_GOT_TLSGD16_LO = 80, /* half16 (sym+add)@got@tlsgd@l */
R_PPC64_GOT_TLSGD16_HI = 81, /* half16 (sym+add)@got@tlsgd@h */
R_PPC64_GOT_TLSGD16_HA = 82, /* half16 (sym+add)@got@tlsgd@ha */
R_PPC64_GOT_TLSLD16 = 83, /* half16* (sym+add)@got@tlsld */
R_PPC64_GOT_TLSLD16_LO = 84, /* half16 (sym+add)@got@tlsld@l */
R_PPC64_GOT_TLSLD16_HI = 85, /* half16 (sym+add)@got@tlsld@h */
R_PPC64_GOT_TLSLD16_HA = 86, /* half16 (sym+add)@got@tlsld@ha */
R_PPC64_GOT_TPREL16_DS = 87, /* half16ds* (sym+add)@got@tprel */
R_PPC64_GOT_TPREL16_LO_DS = 88, /* half16ds (sym+add)@got@tprel@l */
R_PPC64_GOT_TPREL16_HI = 89, /* half16 (sym+add)@got@tprel@h */
R_PPC64_GOT_TPREL16_HA = 90, /* half16 (sym+add)@got@tprel@ha */
R_PPC64_GOT_DTPREL16_DS = 91, /* half16ds* (sym+add)@got@dtprel */
R_PPC64_GOT_DTPREL16_LO_DS = 92, /* half16ds (sym+add)@got@dtprel@l */
R_PPC64_GOT_DTPREL16_HI = 93, /* half16 (sym+add)@got@dtprel@h */
R_PPC64_GOT_DTPREL16_HA = 94, /* half16 (sym+add)@got@dtprel@ha */
R_PPC64_TPREL16_DS = 95, /* half16ds* (sym+add)@tprel */
R_PPC64_TPREL16_LO_DS = 96, /* half16ds (sym+add)@tprel@l */
R_PPC64_TPREL16_HIGHER = 97, /* half16 (sym+add)@tprel@higher */
R_PPC64_TPREL16_HIGHERA = 98, /* half16 (sym+add)@tprel@highera */
R_PPC64_TPREL16_HIGHEST = 99, /* half16 (sym+add)@tprel@highest */
R_PPC64_TPREL16_HIGHESTA = 100, /* half16 (sym+add)@tprel@highesta */
R_PPC64_DTPREL16_DS = 101, /* half16ds* (sym+add)@dtprel */
R_PPC64_DTPREL16_LO_DS = 102, /* half16ds (sym+add)@dtprel@l */
R_PPC64_DTPREL16_HIGHER = 103, /* half16 (sym+add)@dtprel@higher */
R_PPC64_DTPREL16_HIGHERA = 104, /* half16 (sym+add)@dtprel@highera */
R_PPC64_DTPREL16_HIGHEST = 105, /* half16 (sym+add)@dtprel@highest */
R_PPC64_DTPREL16_HIGHESTA = 106, /* half16 (sym+add)@dtprel@highesta */
#if 0
// These relocation types appear in David Anderson's libdwarf and
// dwarfdump only. The PPC 64-Bit ELF V2 ABI uses these numbers for
// different types (see below).
R_PPC64_TOC32 = 107, /* word32 (.TOC. & 0xffff_ffff) */
R_PPC64_DTPMOD32 = 108, /* word32 (@dtpmod & 0xffff_ffff) */
R_PPC64_TPREL32 = 109, /* word32 (@tprel & 0xffff_ffff) */
R_PPC64_DTPREL32 = 110, /* word32 (@dtprel & 0xffff_ffff) */
#else
// The PPC 64-Bit ELF V2 ABI uses these numbers for different types
R_PPC64_TLSGD = 107, // used as markers on thread local
R_PPC64_TLSLD = 108, // storage (TLS) code sequences
R_PPC64_TOCSAVE = 109, // this relocation type indicates a
// position where a TOC save may be
// inserted in the function to avoid a
// TOC save as part of the PLT stub code
R_PPC64_ADDR16_HIGH = 110, // half16 #hi(S + A)
R_PPC64_ADDR16_HIGHA = 111, // half16 #ha(S + A)
R_PPC64_TPREL16_HIGH = 112, // half16 #hi(@tprel)
R_PPC64_TPREL16_HIGHA = 113, // half16 #ha(@tprel)
R_PPC64_DTPREL16_HIGH = 114, // half16 #hi(@dtprel)
R_PPC64_DTPREL16_HIGHA = 115, // half16 #ha(@dtprel)
R_PPC64_REL24_NOTOC = 116, // low24* (S + A - P) >> 2
R_PPC64_ADDR64_LOCAL = 117, // doubleword64 S + A (see 3.5.4)
#endif
R_PPC64_JMP_IREL = 247, // GNU extension to support local ifunc
// The PPC 64-Bit ELF V2 ABI
R_PPC64_IRELATIVE = 248, // It is used to implement the
// STT_GNU_IFUNC framework
R_PPC64_REL16 = R_PPC_REL16, // half16* S + A - P
R_PPC64_REL16_LO = R_PPC_REL16_LO, // half16 #lo(S + A - P)
R_PPC64_REL16_HI = R_PPC_REL16_HI, // half16* #hi(S + A - P)
R_PPC64_REL16_HA = R_PPC_REL16_HA, // half16* #la(S + A - P)
};
// flags for VLE code
#define SHF_PPC_VLE 0x10000000 /* section header flag */
#define PF_PPC_VLE 0x10000000 /* program header flag */
// patching GOT loading,
// discard auxiliary values in plt/got
// can present offset bypass segment
#define ELF_RPL_PPC_DEFAULT (ELF_RPL_GL | ELF_DIS_OFFW | ELF_DIS_GPLT)
#endif

3558
idasdk76/ldr/elf/reader.cpp Normal file

File diff suppressed because it is too large Load Diff

4
idasdk76/ldr/exports.def Normal file
View File

@@ -0,0 +1,4 @@
{
global: LDSC;
local: *;
};

View File

@@ -0,0 +1,69 @@
//--------------------------------------------------------------------------
static char *token2str(char *buf, size_t bufsize, GEOStoken &t)
{
if ( t.str[0] )
qsnprintf(buf, bufsize, "%4.4s/%u", t.str, t.num);
else
qstrncpy(buf, "-", bufsize);
return buf;
}
//--------------------------------------------------------------------------
static const unsigned char _GeosXlate[] =
{
0x8E, 0x8F, 0x80, 0x90, 0xA5, 0x99, 0x9A, 0xA0,
0x85, 0x83, 0x84, 0x20, 0x86, 0x87, 0x82, 0x8A,
0x88, 0x89, 0xA1, 0x8D, 0x8C, 0x8B, 0xA4, 0xA2,
0x95, 0x93, 0x94, 0x20, 0xA3, 0x97, 0x96, 0x81,
0x20, 0xF8, 0x9B, 0x9C, 0x15, 0xF9, 0x14, 0xE1,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x92, 0x20,
0xEC, 0xF1, 0xF3, 0xF2, 0x9D, 0xE6, 0xEB, 0xE4,
0x20, 0x20, 0xF4, 0xA6, 0xA7, 0xEA, 0x91, 0xED,
0xA8, 0xAD, 0xAA, 0xFB, 0x9F, 0xF7, 0x20, 0xAE,
0xAF, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xF6, 0x04,
0x98, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};
static const unsigned char _GeosXlapp[] =
{
0x8E, 0x8F, 0x80, 0x90, 0xA5, 0x99, 0x9A, 0xA0,
0x85, 0x83, 0x84, 0x61, 0x86, 0x87, 0x82, 0x8A,
0x88, 0x89, 0xA1, 0x8D, 0x8C, 0x8B, 0xA4, 0xA2,
0x95, 0x93, 0x94, 0x6F, 0xA3, 0x97, 0x96, 0x81,
0x2B, 0xF8, 0x9B, 0x9C, 0x15, 0xF9, 0x14, 0xE1,
0x52, 0x43, 0x7E, 0x27, 0x22, 0xD8, 0x92, 0x30,
0xEC, 0xF1, 0xF3, 0xF2, 0x9D, 0xE6, 0xEB, 0xE4,
0xE3, 0xE3, 0xF4, 0xA6, 0xA7, 0xEA, 0x91, 0xED,
0xA8, 0xAD, 0xAA, 0xFB, 0x9F, 0xF7, 0x1E, 0xAE,
0xAF, 0x5F, 0x20, 0x41, 0x41, 0x4F, 0x99, 0x94,
0x2D, 0xC4, 0x22, 0x22, 0x60, 0x27, 0xF6, 0x04,
0x98, 0x59, 0x2F, 0xE8, 0x3C, 0x3E, 0x79, 0x59,
0x2B, 0xFA, 0x2C, 0x22, 0x70, 0x41, 0x45, 0x41,
0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F,
0x20, 0x4F, 0x55, 0x55, 0x55, 0x2C, 0x5E, 0x7E,
0x2D, 0x60, 0xF8, 0xF8, 0x2C, 0x22, 0x2C, 0x27
};
static char *geos2ibm(char *out, char *in, size_t insize)
{
char *saved = out;
for ( int i=0; i < insize; i++ )
{
uchar c = *in++;
if ( !c )
break;
if ( c & 0x80 )
c = _GeosXlapp[c & 0x7F];
*out++ = c;
}
*out = '\0';
return saved;
}

795
idasdk76/ldr/geos/geos.cpp Normal file
View File

@@ -0,0 +1,795 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2000 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*/
#include "../idaldr.h"
#include "geos2.h"
#include "common.cpp"
#include <struct.hpp>
#include <enum.hpp>
#include <typeinf.hpp>
//--------------------------------------------------------------------------
static int create_seg(
ea_t base,
ea_t start,
ea_t end,
const char *name,
const char *sclass)
{
if ( start != BADADDR && end < start )
return 0;
segment_t s;
s.sel = setup_selector(base);
s.start_ea = start;
s.end_ea = end;
s.align = saRelByte;
s.comb = (sclass != NULL && strcmp(sclass,"STACK") == 0) ? scStack : scPub;
s.bitness = 0;
return add_segm_ex(&s, name, sclass, ADDSEG_NOSREG|ADDSEG_SPARSE);
}
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
union
{
GEOSheader h1;
GEOS2header h2;
} h;
qlseek(li, 0);
if ( qlread(li, &h, sizeof(h)) != sizeof(h) )
return 0;
qoff64_t apppos;
int version;
if ( h.h1.ID == GEOS_ID && h.h1.fclass == 0 )
{
apppos = 0xC8;
version = 1;
}
else if ( h.h2.ID == GEOS2_ID && h.h2.fclass == 1 )
{
apppos = sizeof(GEOS2header);
version = 2;
}
else
{
return 0;
}
GEOSappheader ah;
qlseek(li, apppos, SEEK_SET);
if ( qlread(li, &ah, sizeof(ah)) != sizeof(ah) )
return 0;
const char *stype;
switch ( ah.type )
{
case 1: stype = "Application"; break;
case 2: stype = "Library"; break;
case 3: stype = "Driver"; break;
default: stype = "Unknown type";break;
}
fileformatname->sprnt("GEOS%d %s", version, stype);
*processor = "metapc";
return 1;
}
//--------------------------------------------------------------------------
static ea_t get_segea(const GEOSappheader &ah, const uint32 *segea, uint16 s)
{
if ( s >= ah.numseg )
{
ask_for_feedback("Bad segment number %d", s);
return BADADDR;
}
return segea[s] == uint32(BADADDR) ? BADADDR : segea[s];
}
//--------------------------------------------------------------------------
static netnode get_node(const GEOSappheader &ah, const netnode *modnode, uint16 libn)
{
if ( libn >= ah.numlib )
{
ask_for_feedback("Bad library number %d", libn);
return BADNODE;
}
return modnode[libn];
}
//--------------------------------------------------------------------------
static tid_t get_class_struct_flags_enum()
{
static const char enum_name[] = "ClassFlags";
enum_t id = get_enum(enum_name);
if ( id != BADNODE )
return id;
id = add_enum(-1, enum_name, hex_flag());
set_enum_bf(id, true);
add_enum_member(id, "CLASSF_HAS_DEFAULT", (1<<0), (1<<0));
add_enum_member(id, "CLASSF_MASTER_CLASS", (1<<1), (1<<1));
add_enum_member(id, "CLASSF_VARIANT_CLASS", (1<<2), (1<<2));
add_enum_member(id, "CLASSF_DISCARD_ON_SAVE", (1<<3), (1<<3));
add_enum_member(id, "CLASSF_NEVER_SAVED", (1<<4), (1<<4));
add_enum_member(id, "CLASSF_HAS_RELOC", (1<<5), (1<<5));
add_enum_member(id, "CLASSF_C_HANDLERS", (1<<6), (1<<6));
return id;
}
//--------------------------------------------------------------------------
#if 0
static void declare_parameter_types(ea_t ea, int count)
{
static const char class_name[] = "CMethodDef";
struc_t *sptr = get_struc(get_struc_id(class_name));
if ( sptr == NULL )
{
sptr = get_struc(add_struc(-1, class_name));
if ( sptr == NULL )
return;
add_struc_member(sptr, "methodParameterDef", -1, word_flag(), NULL, 2);
add_struc_member(sptr, "handlerTypeDef", -1, byte_flag(), NULL, 1);
}
size_t size = get_struc_size(sptr);
create_struct(ea, size*count, sptr->id);
}
#endif
//--------------------------------------------------------------------------
static void declare_class(ea_t ea, const char *entryname)
{
static const char class_name[] = "ClassStruct";
struc_t *sptr = get_struc(get_struc_id(class_name));
if ( sptr == NULL )
{
sptr = get_struc(add_struc(BADADDR, class_name));
if ( sptr == NULL )
return;
opinfo_t mt;
mt.ri.flags = REF_OFF32;
mt.ri.target = BADADDR;
mt.ri.base = 0;
mt.ri.tdelta = 0;
add_struc_member(sptr, "superClass", BADADDR, off_flag()|dword_flag(), &mt, 4);
add_struc_member(sptr, "masterOffset", BADADDR, word_flag(), NULL, 2);
add_struc_member(sptr, "methodCount", BADADDR, dec_flag()|word_flag(), NULL, 2);
add_struc_member(sptr, "instanceSize", BADADDR, dec_flag()|word_flag(), NULL, 2);
add_struc_member(sptr, "vdRelocTable", BADADDR, word_flag(), NULL, 2);
add_struc_member(sptr, "relocTable", BADADDR, word_flag(), NULL, 2);
mt.ec.tid = get_class_struct_flags_enum();
mt.ec.serial = 0;
add_struc_member(sptr, "flags", BADADDR, enum_flag()|byte_flag(), &mt, 1);
add_struc_member(sptr, "masterMethods",BADADDR, byte_flag(), NULL, 1);
}
asize_t size = get_struc_size(sptr);
create_struct(ea, size, sptr->id);
segment_t *s = getseg(ea);
if ( s == NULL )
return;
int count = get_word(ea+6);
// bool c_handlers = get_byte(ea+14) & (1<<6);
ea += size;
if ( ea+2*count >= s->end_ea )
return;
ea_t messages = ea;
create_word(ea, count*2);
op_dec(ea, 0);
ea += 2*count;
if ( ea+4*count > s->end_ea )
return;
create_dword(ea, count*4);
op_plain_offset(ea, 0, 0);
for ( int i=0; i < count; i++ )
{
ea_t idx = ea + 4*i;
ea_t pea = to_ea(get_word(idx+2), get_word(idx));
auto_make_proc(pea);
char name[MAXSTR];
qsnprintf(name, sizeof(name), "%s_%u", entryname, get_word(messages+2*i));
add_entry(pea, pea, name, true, AEF_IDBENC);
}
// commented out because it doesn't work properly
// see geoplan.geo, entry number 1 for example
// if ( c_handlers )
// declare_parameter_types(ea+count*4, count);
}
//--------------------------------------------------------------------------
static void describe_app(const GEOSappheader &ah, const uint32 *segea)
{
char buf[MAXSTR];
char *end = buf + sizeof(buf);
char *ptr = buf + qsnprintf(buf, sizeof(buf), "Pgm attrs :");
if ( ah.attr & GA_PROCESS ) APPEND(ptr, end, " GA_PROCESS");
if ( ah.attr & GA_LIBRARY ) APPEND(ptr, end, " GA_LIBRARY");
if ( ah.attr & GA_DRIVER ) APPEND(ptr, end, " GA_DRIVER");
if ( ah.attr & GA_KEEP_FILE_OPEN ) APPEND(ptr, end, " GA_KEEP_FILE_OPEN");
if ( ah.attr & GA_SYSTEM ) APPEND(ptr, end, " GA_SYSTEM");
if ( ah.attr & GA_MULTI_LAUNCHABLE ) APPEND(ptr, end, " GA_MULTI_LAUNCHABLE");
if ( ah.attr & GA_APPLICATION ) APPEND(ptr, end, " GA_APPLICATION");
if ( ah.attr & GA_DRIVER_INITIALIZED ) APPEND(ptr, end, " GA_DRIVER_INITIALIZED");
if ( ah.attr & GA_LIBRARY_INITIALIZED ) APPEND(ptr, end, " GA_LIBRARY_INITIALIZED");
if ( ah.attr & GA_GEODE_INITIALIZED ) APPEND(ptr, end, " GA_GEODE_INITIALIZED");
if ( ah.attr & GA_USES_COPROC ) APPEND(ptr, end, " GA_USES_COPROC");
if ( ah.attr & GA_REQUIRES_COPROC ) APPEND(ptr, end, " GA_REQUIRES_COPROC");
if ( ah.attr & GA_HAS_GENERAL_CONSUMER_MODE ) APPEND(ptr, end, " GA_HAS_GENERAL_CONSUMER_MODE");
if ( ah.attr & GA_ENTRY_POINTS_IN_C ) APPEND(ptr, end, " GA_ENTRY_POINTS_IN_C");
add_pgm_cmt("%s", buf);
if ( ah.attr & GA_PROCESS )
{
ea_t entry = get_segea(ah, segea, ah.classptr_seg) + ah.classptr_ofs;
set_name(entry, "ProcessClass", SN_NOCHECK|SN_NOWARN);
declare_class(entry, "ProcessClass");
// inf_set_start_cs(get_segea(ah,segea,ah.classptr_seg) >> 4);
// inf_set_start_ip (ah.classptr_ofs);
entry = get_segea(ah, segea, ah.tokenres_seg) + ah.tokenres_item;
set_name(entry, "ApplicationObject");
add_pgm_cmt("ProcessClass: %d:%04X", ah.classptr_seg, ah.classptr_ofs);
add_pgm_cmt("App object : %d:%04X", ah.tokenres_seg, ah.tokenres_item);
}
if ( ah.attr & GA_LIBRARY && ah.initseg != 0 )
{
inf_set_start_cs(get_segea(ah, segea, ah.initseg) >> 4);
inf_set_start_ip(ah.initofs);
add_pgm_cmt("Library init: %d:%04X", ah.initseg, ah.initofs);
}
if ( ah.attr & GA_DRIVER && ah.startseg != 0 )
{
ea_t entry = get_segea(ah, segea, ah.startseg) + ah.startofs;
set_name(entry, "DriverTable");
// inf_set_start_cs(get_segea(ah, segea, ah.startseg) >> 4);
// inf_set_start_ip (ah.startofs);
add_pgm_cmt("Driver Table: %d:%04X", ah.startseg, ah.startofs);
// add_jmplist(ah.startseg,ah.startofs,4,4);
// Add entry point as "jmplist"
}
}
//--------------------------------------------------------------------------
static void bad_lib_reloc(int i, uint16 off)
{
ask_for_feedback("Strange library relocation at %d:%04X", i, off);
}
//--------------------------------------------------------------------------
static void create_fixup(ea_t ea, fixup_data_t &fd, ea_t target)
{
segment_t *s = getseg(target);
if ( s != NULL )
{
fd.sel = s->sel;
fd.off = target - get_segm_base(s);
}
else
{
fd.sel = sel_t(target >> 4);
fd.off = target & 0xF;
}
fd.displacement = 0;
fd.set(ea);
if ( fd.get_type() == FIXUP_PTR16 )
{
put_word(ea, fd.off);
put_word(ea+2, fd.sel);
}
else if ( fd.get_type() == FIXUP_OFF16 )
{
put_word(ea, fd.off);
}
else // SEG16
{
put_word(ea, fd.sel);
}
}
//--------------------------------------------------------------------------
static void apply_relocations(
linput_t *li,
const GEOSappheader &ah,
const netnode *modnode,
const uint16 *seglen,
const int32 *segpos,
const uint16 *segfix,
const uint32 *segea)
{
// apply relocation information
for ( int i=0; i < ah.numseg; i++ )
{
if ( segfix[i] == 0 )
continue;
GEOSfixup *fix = (GEOSfixup *)qalloc(segfix[i]);
if ( fix == NULL )
nomem("fix");
qlseek(li, segpos[i]+((seglen[i]+0xF)&~0xF));
lread(li, fix, segfix[i]);
int n = segfix[i]/sizeof(GEOSfixup);
sel_t oldsel = BADSEL;
sel_t oldoff = BADSEL;
ea_t oldea = BADADDR;
for ( int j=0; j < n; j++ )
{
ea_t ea = get_segea(ah, segea, (uint16)i) + fix[j].ofs;
int ftype = fix[j].type & 0xF0;
if ( ftype != 0x10 && ftype != 0x20 )
ask_for_feedback("Unknown fixup type %02X", ftype);
netnode libnode = BADNODE;
if ( ftype == 0x10 )
libnode = get_node(ah, modnode, fix[j].type>>8);
uint16 w1 = get_word(ea);
ea_t target = BADADDR;
fixup_data_t fd(FIXUP_SEG16);
switch ( fix[j].type & 0x0F )
{
case 0x0: case 0x4:
fd.set_type_and_flags(FIXUP_PTR16);
if ( ftype == 0x20 ) // program
target = get_segea(ah, segea, w1) + get_word(ea+2);
else // library
{
target = node2ea(libnode.altval(w1+1));
fd.set_extdef();
}
break;
case 0x1: // off
if ( ftype == 0x20 ) // program
{
ask_for_feedback("Program offset relocation encountered");
continue;
}
oldoff = w1;
if ( oldsel != BADSEL )
{
LIB_PTR:
target = node2ea(libnode.altval(oldoff+1));
if ( oldea == ea+2 )
{
fd.set_type_and_flags(FIXUP_PTR16, FIXUPF_EXTDEF);
}
else
{
fd.set_type_and_flags(FIXUP_SEG16, FIXUPF_EXTDEF);
create_fixup(oldea, fd, target);
fd.set_type_and_flags(FIXUP_OFF16, FIXUPF_EXTDEF);
}
oldsel = BADSEL;
oldoff = BADSEL;
oldea = BADSEL;
break;
}
oldea = ea;
continue;
case 0x2: case 0x3:
if ( ftype == 0x20 ) // program
target = get_segea(ah, segea, w1);
else
{
oldsel = w1;
if ( oldoff != BADSEL )
{
ea_t tmp = ea;
ea = oldea;
oldea = tmp;
goto LIB_PTR;
}
oldea = ea;
continue;
}
break;
default:
ask_for_feedback("Unknown relocation type %02X", fix[j].type);
}
create_fixup(ea, fd, target);
}
qfree(fix);
}
}
//--------------------------------------------------------------------------
static void find_imports_in_relocations(
linput_t *li,
const GEOSappheader &ah,
const netnode *modnode,
const uint16 *seglen,
const int32 *segpos,
const uint16 *segfix)
{
for ( int i=0; i < ah.numseg; i++ )
{
if ( segfix[i] == 0 )
continue;
GEOSfixup *fix = (GEOSfixup *)qalloc(segfix[i]);
if ( fix == NULL )
nomem("fix");
qlseek(li, segpos[i]+((seglen[i]+0xF)&~0xF));
lread(li, fix, segfix[i]);
// i don't understand why this should be done
// besides, if we uncomment it, the library fixups are
// not handled properly
// if ( fix[0].ofs == 0 )
// fix[0].ofs = 0xFFFF;
int num = segfix[i]/sizeof(GEOSfixup);
sel_t oldseg = BADSEL;
sel_t oldoff = BADSEL;
sel_t oldlib = BADSEL;
for ( int j=0; j < num; j++ )
{
if ( fix[j].ofs == 0xFFFF )
continue;
if ( (fix[j].type & 0xF0) != 0x10 )
continue; // only library!
int libn = fix[j].type>>8;
if ( libn >= ah.numlib )
{
ask_for_feedback("Illegal library number in relocations");
continue;
}
netnode n = modnode[libn];
uint16 ofs = fix[j].ofs;
qlseek(li, segpos[i]+ofs);
uint16 w1;
lread(li, &w1, sizeof(w1));
switch ( fix[j].type & 0x0F )
{
case 0x0: case 0x4: // exported entry
n.altset(w1+1, 1);
oldseg = BADSEL;
oldoff = BADSEL;
oldlib = BADSEL;
break;
case 0x1: // off
if ( oldseg != BADSEL )
{
if ( libn != oldlib || oldseg != w1 )
bad_lib_reloc(i, ofs);
n.altset(w1+1, 1);
oldseg = BADSEL;
break;
}
oldoff = w1;
oldlib = libn;
break;
case 0x2: case 0x3: // seg #
if ( oldoff != BADSEL )
{
if ( libn != oldlib || oldoff != w1 )
bad_lib_reloc(i, ofs);
n.altset(w1+1, 1);
oldoff = BADSEL;
break;
}
oldseg = w1;
oldlib = libn;
break;
default:
ask_for_feedback("Unknown relocation type %02X", fix[j].type);
}
}
if ( oldseg != BADSEL && oldoff != BADSEL )
ask_for_feedback("Some library relocations are strange");
qfree(fix);
}
}
//--------------------------------------------------------------------------
static void create_extern_segments(
const GEOSappheader &ah,
const GEOSliblist *lib,
const netnode *modnode)
{
inf_set_specsegs(inf_is_64bit() ? 8 : 4);
for ( int i=0; i < ah.numlib; i++ )
{
char libname[8+1];
qstrncpy(libname, lib[i].name, sizeof(libname));
trim(libname);
netnode n = modnode[i];
uval_t x;
int nimps = 0;
for ( x=n.altfirst(); x != BADNODE; x=n.altnext(x) )
nimps++;
if ( nimps == 0 )
continue;
ea_t ea = free_chunk(inf_get_max_ea(), nimps*4, -15);
ea_t end = ea + nimps*4;
create_seg(ea>>4, ea, end, libname, "XTRN");
for ( x=n.altfirst(); x != BADNODE; x=n.altnext(x),ea+=4 )
{
char buf[MAXSTR];
qsnprintf(buf, sizeof(buf), "%s_%u", libname, uint16(x)-1);
put_dword(ea, 0xCB);
create_insn(ea);
force_name(ea, buf, SN_IDBENC);
nodeidx_t ndx = ea2node(ea);
n.altset(x, ndx);
}
import_module(libname, NULL /*windir*/, n, NULL, "geos");
}
}
//--------------------------------------------------------------------------
static void create_exports(
const GEOSappheader &ah,
const GEOSexplist *explist,
const uint32 *segea,
const char *modname)
{
int i;
netnode n;
n.create();
for ( i=0; i < ah.numexp; i++ )
{
ea_t ea = get_segea(ah, segea, explist[i].seg) + explist[i].ofs;
add_extra_cmt(ea, true, "Exported entry %d", i);
nodeidx_t ndx = ea2node(ea);
n.altset(i+1, ndx);
}
import_module(modname, NULL /*windir*/, n, NULL, "geos");
for ( i=0; i < ah.numexp; i++ )
{
ea_t ea = get_segea(ah, segea, explist[i].seg) + explist[i].ofs;
qstring name;
if ( get_name(&name, ea, GN_NOT_DUMMY) <= 0 )
name.sprnt("%s_%d", modname, i);
bool makecode = segtype(ea) == SEG_CODE;
add_entry(i, ea, name.begin(), makecode, AEF_IDBENC);
if ( !makecode )
declare_class(ea, name.begin());
}
}
//--------------------------------------------------------------------------
void load_application(linput_t *li, int32 fpos, int32 fdelta)
{
GEOSappheader ah;
qlseek(li, fpos);
lread(li, &ah, sizeof(ah));
// build our name
char modname[sizeof(ah.name)+1];
qstrncpy(modname, ah.name, sizeof(ah.name));
trim(modname);
// read in library information
GEOSliblist *lib = NULL;
netnode *modnode = NULL;
validate_array_count(li, &ah.numlib, sizeof(GEOSliblist), "The library count");
if ( ah.numlib != 0 )
{
lib = qalloc_array<GEOSliblist>(ah.numlib);
if ( lib == NULL )
nomem("libs");
lread(li, lib, ah.numlib*sizeof(GEOSliblist));
modnode = qalloc_array<netnode>(ah.numlib);
if ( modnode == NULL )
nomem("libnode");
for ( int i=0; i < ah.numlib; i++ )
{
char libname[8+1];
qstrncpy(libname, lib[i].name, sizeof(libname));
trim(libname);
char buf[20];
qsnprintf(buf, sizeof(buf), "$lib %.8s", libname);
modnode[i].create(buf);
}
}
// read in export information
GEOSexplist *explist = NULL;
validate_array_count(li, &ah.numexp, sizeof(GEOSexplist), "Number of exports");
if ( ah.numexp != 0 )
{
explist = qalloc_array<GEOSexplist>(ah.numexp);
if ( explist == NULL )
nomem("exp");
lread(li, explist, ah.numexp*sizeof(GEOSexplist));
}
// read in segment information
void *segd = NULL;
uint16 *seglen = NULL;
int32 *segpos = NULL;
uint16 *segfix = NULL;
uint16 *segflg;
sel_t ds_sel = BADSEL;
uint32 *segea = NULL;
validate_array_count(li, &ah.numseg, 14, "Number of segments");
if ( ah.numseg != 0 )
{
if ( !is_mul_ok<ushort>(ah.numseg, 14) )
NOMEM:
nomem("geos_segments");
segd = qalloc(ah.numseg*14);
if ( segd == NULL )
goto NOMEM;
lread(li, segd, ah.numseg*10);
seglen = (uint16 *)segd;
segpos = (int32 *)(seglen + ah.numseg);
segfix = (uint16 *)(segpos + ah.numseg);
segflg = (uint16 *)(segfix + ah.numseg);
segea = (uint32 *)(segflg + ah.numseg);
ea_t ea = to_ea(inf_get_baseaddr(), 0);
for ( int i=0; i < ah.numseg; i++ )
{
uint16 f = segflg[i];
segpos[i] += fdelta;
segea[i] = uint32(BADADDR);
if ( seglen[i] == 0 )
continue;
size_t bss_size = 0;
// if this is the data segment, increase its size by stacksize.
// i'm not aware of a reliable way to find it, so use heuristics
bool found_data_segment = false;
if ( ds_sel == BADSEL
&& (f & (HF_READ_ONLY|HF_SHARABLE|HF_CODE)) == 0
&& (f & HF_FIXED) != 0 )
{
found_data_segment = true;
bss_size = ah.stacksize;
}
ea = free_chunk(ea, bss_size + seglen[i], -15);
ea_t endea = ea + seglen[i] + bss_size;
if ( (f & HF_ZERO_INIT) == 0 )
file2base(li, segpos[i], ea, endea - bss_size, FILEREG_PATCHABLE);
create_seg(ea>>4, ea, endea, NULL, (f & HF_CODE) ? "CODE" : "DATA");
if ( found_data_segment )
ds_sel = find_selector(ea>>4);
char buf[MAXSTR];
char *end = buf + sizeof(buf);
char *ptr = buf + qsnprintf(buf, sizeof(buf), "Segm attrs :");
if ( f & HF_ZERO_INIT ) APPEND(ptr, end, " ZEROINIT");
if ( f & HF_LOCK ) APPEND(ptr, end, " LOCK");
if ( f & HF_NO_ERR ) APPEND(ptr, end, " NO_ERR");
if ( f & HF_UI ) APPEND(ptr, end, " UI");
if ( f & HF_READ_ONLY ) APPEND(ptr, end, " RONLY");
if ( f & HF_OBJECT_RESOURCE ) APPEND(ptr, end, " OBJ_RES");
if ( f & HF_CODE ) APPEND(ptr, end, " CODE");
if ( f & HF_CONFORMING ) APPEND(ptr, end, " CONFORMING");
if ( f & HF_FIXED ) APPEND(ptr, end, " FIXED");
if ( f & HF_SHARABLE ) APPEND(ptr, end, " SHARABLE");
if ( f & HF_DISCARDABLE ) APPEND(ptr, end, " DISCARDABLE");
if ( f & HF_SWAPABLE ) APPEND(ptr, end, " SWAPABLE");
if ( f & HF_LMEM ) APPEND(ptr, end, " LMEM");
if ( f & HF_DEBUG ) APPEND(ptr, end, " DEBUG");
if ( f & HF_DISCARDED ) APPEND(ptr, end, " DISCARDED");
if ( f & HF_SWAPPED ) APPEND(ptr, end, " SWAPPED");
add_extra_cmt(ea, true, "%s", buf);
segea[i] = (uint32)ea;
ea = endea;
}
}
find_imports_in_relocations(li, ah, modnode, seglen, segpos, segfix);
create_extern_segments(ah, lib, modnode);
set_default_dataseg(ds_sel);
if ( !qgetenv("IDA_NORELOC") )
apply_relocations(li, ah, modnode, seglen, segpos, segfix, segea);
create_exports(ah, explist, segea, modname);
describe_app(ah, segea);
qfree(lib);
qfree(modnode);
qfree(explist);
qfree(segd);
}
//--------------------------------------------------------------------------
static void show_geos1(GEOSheader &h)
{
char buf[MAXSTR];
add_pgm_cmt("Name : %s", geos2ibm(buf, h.name, sizeof(h.name)));
add_pgm_cmt("Token : %s", token2str(buf, sizeof(buf), h.token));
add_pgm_cmt("Creator : %s", token2str(buf, sizeof(buf), h.appl));
add_pgm_cmt("Release : %u.%u.%u.%u",
h.release.versmaj,
h.release.versmin,
h.release.revmaj,
h.release.revmin);
add_pgm_cmt("Protocol : %u.%03u",
h.protocol.vers,
h.protocol.rev);
add_pgm_cmt("Flags : %04X", h.flags);
add_pgm_cmt("User info : %s", geos2ibm(buf, h.info, sizeof(h.info)));
add_pgm_cmt("Copyright : %s", geos2ibm(buf, h._copyright, sizeof(h._copyright)));
}
//--------------------------------------------------------------------------
static void show_geos2(GEOS2header &h)
{
char buf[MAXSTR];
add_pgm_cmt("Name : %s", geos2ibm(buf, h.name, sizeof(h.name)));
add_pgm_cmt("Token : %s", token2str(buf, sizeof(buf), h.token));
add_pgm_cmt("Creator : %s", token2str(buf, sizeof(buf), h.appl));
add_pgm_cmt("Release : %u.%u.%u.%u",
h.release.versmaj,
h.release.versmin,
h.release.revmaj,
h.release.revmin);
add_pgm_cmt("Protocol : %u.%03u",
h.protocol.vers,
h.protocol.rev);
add_pgm_cmt("Flags : %04X", h.flags);
add_pgm_cmt("Password : %.*s", int(sizeof(h.password)), h.password);
add_pgm_cmt("User info : %s", geos2ibm(buf, h.info, sizeof(h.info)));
add_pgm_cmt("Copyright : %s", geos2ibm(buf, h._copyright, sizeof(h._copyright)));
}
//--------------------------------------------------------------------------
void idaapi load_file(linput_t *li, uint16 /*neflag*/, const char * /*fileformatname*/)
{
set_processor_type("metapc", SETPROC_LOADER);
union
{
GEOSheader h1;
GEOS2header h2;
} h;
qlseek(li, 0);
lread(li, &h, sizeof(h));
int32 apppos;
int32 fdelta;
if ( h.h1.ID == GEOS_ID )
{
apppos = 0xC8;
fdelta = 0;
}
else
{
apppos = sizeof(GEOS2header);
fdelta = apppos;
}
load_application(li, apppos, fdelta);
create_filename_cmt();
if ( h.h1.ID == GEOS_ID )
show_geos1(h.h1);
else
show_geos2(h.h2);
inf_set_cc_cm(inf_get_cc_cm() | C_PC_LARGE);
add_til("geos", ADDTIL_DEFAULT);
}
//--------------------------------------------------------------------------
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,
};

173
idasdk76/ldr/geos/geos.h Normal file
View File

@@ -0,0 +1,173 @@
/*
GEOS.H
by Marcus Groeber 1992-95
Include file for the PC/GEOS file format
20.06.00: Modified by Ilfak Guilfanov <ig@datarescue.com>
*/
#if !defined(_GEOS_H)
#define _GEOS_H
#pragma pack(push, 1)
#define GEOS_TOKENLEN 4
struct GEOStoken
{ /*** ID for file types/icons */
char str[GEOS_TOKENLEN]; // 4 byte string
ushort num; // additional id number (?)
};
struct GEOSprotocol
{ /*** Protocol/version number */
ushort vers; // protocol
ushort rev; // sub revision
};
struct GEOSrelease
{ /*** "Release" */
ushort versmaj,versmin; // "release" x.y
ushort revmaj,revmin; // value "a-b" behind "release"
};
/******************************************************************************
* GEOS standard file header (all file types) *
******************************************************************************/
#define GEOS_LONGNAME 36 // length of filename
#define GEOS_INFO 100 // length of user file info
#define GEOS_ID 0x53CF45C7 // GEOS file identification "magic"
struct GEOSheader
{ /*** Standard-Dateikof */
int32 ID; // GEOS id magic: C7 45 CF 53
ushort fclass; // 00=applciation, 01=VM file
ushort flags; // flags ??? (always seen 0000h)
GEOSrelease release; // "release"
GEOSprotocol protocol; // protocol/version
GEOStoken token; // file type/icon
GEOStoken appl; // "token" of creator application
char name[GEOS_LONGNAME]; // long filename
char info[GEOS_INFO]; // user file info
char _copyright[24]; // original files: Copyright notice
};
/******************************************************************************
* GEOS program files ("geodes") *
******************************************************************************/
#define GEOS_FNAME 8 // Length of internale filename/ext
#define GEOS_FEXT 4
struct GEOSappheader
{ /*** Additional geode file header */
ushort _attr; // attribute (see below)
#define GA_PROCESS 0x8000
#define GA_LIBRARY 0x4000
#define GA_DRIVER 0x2000
#define GA_KEEP_FILE_OPEN 0x1000
#define GA_SYSTEM 0x0800
#define GA_MULTI_LAUNCHABLE 0x0400
#define GA_APPLICATION 0x0200
#define GA_DRIVER_INITIALIZED 0x0100
#define GA_LIBRARY_INITIALIZED 0x0080
#define GA_GEODE_INITIALIZED 0x0040
#define GA_USES_COPROC 0x0020
#define GA_REQUIRES_COPROC 0x0010
#define GA_HAS_GENERAL_CONSUMER_MODE 0x0008
#define GA_ENTRY_POINTS_IN_C 0x0004
ushort _type; // program type (see below)
GEOSprotocol kernelprot; // expected kernel protocoll
ushort resourceCount; // number of segments
ushort importLibraryCount; // number of included libraries
ushort exportEntryCount; // number of exported locations
ushort stacksize; // default stack size (or udataSize)
ushort classptr_ofs; // if application: segment/offset of ???
ushort classptr_seg;
ushort tokenres_item; // if application: segment/item of
ushort tokenres_seg; // ressource with application token
char _x21[2];
// GEOS2 header start here:
ushort attr; // attribute
ushort type; // program type: 01=application
// 02=library
// 03=device driver
GEOSrelease release; // "release"
GEOSprotocol protocol; // protocol/version
ushort timestamp; // time stamp (SWAT uniqueness)
char name[GEOS_FNAME],ext[GEOS_FEXT]; // internal filename/ext (blank padded)
GEOStoken token; // file type/icon
char _x3[2];
ushort startofs; // if driver: entry location
ushort startseg; // " "
ushort initofs; // if library: init location (?)
ushort initseg; // " "
char _x33[2];
ushort numexp; // number of exports
ushort numlib; // number of included libraries
char _x4[2];
ushort numseg; // Number of program segments
char _x5[6];
};
struct GEOSexplist
{ /*** Base type of "exported" array */
ushort ofs; // Routine entry location
ushort seg; // " " "
};
struct GEOSliblist
{ /*** Base typ of library array */
char name[GEOS_FNAME]; // library name
ushort type; // library type: 2000h=driver
// 4000h=library
GEOSprotocol protocol; // required lib protocol/version
};
typedef ushort GEOSseglen; /*** Base type of segment size array */
typedef int32 GEOSsegpos; /*** Base type of segment loc array */
typedef ushort GEOSsegfix; /*** Base type of fixup tab size ary */
typedef ushort GEOSsegflags; /*** Base type of flag array:
xxxx xxxx xxxx xxxxb
*/
#define HF_ZERO_INIT 0x8000
#define HF_LOCK 0x4000
#define HF_NO_ERR 0x2000
#define HF_UI 0x1000
#define HF_READ_ONLY 0x0800
#define HF_OBJECT_RESOURCE 0x0400
#define HF_CODE 0x0200
#define HF_CONFORMING 0x0100
#define HF_FIXED 0x0080
#define HF_SHARABLE 0x0040
#define HF_DISCARDABLE 0x0020
#define HF_SWAPABLE 0x0010
#define HF_LMEM 0x0008
#define HF_DEBUG 0x0004
#define HF_DISCARDED 0x0002
#define HF_SWAPPED 0x0001
struct GEOSfixup
{ /*** Base typ of segment fixup table */
ushort type; // Type of fixup:
// xxxxh
// +|||
// | |0 = 16/16 pointer to routine #
// | |1 = 16 offset to routine #
// | |2 = 16 segment of routine #
// | |3 = 16 segment
// | |4 = 16/16 pointer (seg,ofs!)
// | 0 = kernel
// | 1 = library
// | 2 = program
// xx = if library: library ord #
ushort ofs; // Offset relative to segment
};
#pragma pack(pop)
#endif

60
idasdk76/ldr/geos/geos2.h Normal file
View File

@@ -0,0 +1,60 @@
/*
GEOS2.H
by Marcus Groeber 1993-94
Include file for the PC/GEOS 2 file format
20.06.00: Modified by Ilfak Guilfanov <ig@datarescue.com>
*/
#ifndef GEOS2_H
#define GEOS2_H
#include "geos.h"
#pragma pack(push, 1)
/*
* Packed time and date structures; bitfield order is compiler dependant.
*/
struct PackedFileDate
{
ushort d:5;
ushort m:4;
ushort y:7;
};
struct PackedFileTime
{
ushort s_2:5;
ushort m:6;
ushort h:5;
};
/******************************************************************************
* GEOS standard file header (all file types) *
******************************************************************************/
#define GEOS2_ID 0x53C145C7 // GEOS2 file identification "magic"
struct GEOS2header
{ /*** GEOS2 standard header */
int32 ID; // GEOS2 id magic: C7 45 CF 53
char name[GEOS_LONGNAME]; // long filename
ushort fclass; // geos filetype, see SDK docs
// 1-executable
ushort flags; // attributes
GEOSrelease release; // "release"
GEOSprotocol protocol; // protocol/version
GEOStoken token; // file type/icon
GEOStoken appl; // "token" of creator application
char info[GEOS_INFO]; // user file info
char _copyright[24]; // original files: Copyright notice
char _x[8];
PackedFileDate create_date;
PackedFileTime create_time; // creation date/time in DOS format
char password[8]; // password, encrypted as hex string
char _x2[44]; // not yet decoded
};
#pragma pack(pop)
#endif // define GEOS2_H

View File

@@ -0,0 +1,14 @@
PROC=geos
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)geos$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)enum.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)struct.hpp $(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../idaldr.h common.cpp geos.cpp geos.h geos2.h

624
idasdk76/ldr/hex/hex.cpp Normal file
View File

@@ -0,0 +1,624 @@
#define BUFFSIZE ((255+6)*2+76) // buffer to read the string
#define MAX_BYTES 24 // Max number of bytes per line for write
#define SEGMENTGAP (1*1024*1024) // make new segment if gap between addresses
// is greater than this value
#define SPARSE_GAP (256*1024) // switch to sparse storage if the gap
// is greater than this value
/*
* This Loader Module is written by Ilfak Guilfanov and
* rewriten by Yury Haron
*
*/
/*
Interesting documentation:
http://www.intel.com/design/zapcode/Intel_HEX_32_Format.doc
http://www.keil.com/support/docs/1584.htm
*/
#include "../idaldr.h"
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *,
linput_t *li,
const char *)
{
char str[80];
if ( qlgets(str, sizeof(str), li) == NULL )
return 0;
const char *p = str;
while ( *p == ' ' )
p++;
int type = 0;
if ( qisxdigit((uchar)*(p+1)) && qisxdigit((uchar)*(p+2)) )
{
switch ( *p )
{
case ':':
p = "Intel Hex Object Format";
type = f_HEX;
break;
case ';':
p = "MOS Technology Hex Object Format";
type = f_MEX;
break;
case 'S':
p = "Motorola S-record Format";
type = f_SREC;
default:
break;
}
}
if ( type != 0 )
*fileformatname = p;
return type;
}
//--------------------------------------------------------------------------
// this struct was created to save space in the data segment (yes, we were
// counting each byte at that time)
static struct local_data
{
union
{
char *ptr; // load
int sz; // write
};
union
{
uint32 ln; // load
int size; // write
};
ushort sum; // load/write
uchar len; // load
} lc;
//--------------------------------------------------------------------------
NORETURN static void errfmt(void)
{
loader_failure("Bad hex input file format, line %u", lc.ln);
}
//--------------------------------------------------------------------------
// reads the specified number of bytes from the input line
// if size==0, then initializes itself for a new line
static uint32 hexdata(int size)
{
int i = size;
if ( i == 0 )
{
i = 2;
}
else
{
if ( lc.len < i )
errfmt();
lc.len -= (uchar)i;
i <<= 1;
}
char n[10];
char *p = n;
while ( i-- )
*p++ = *lc.ptr++;
*p = '\0';
char *endp;
uint32 data = strtoul(n, &endp, 16);
if ( endp != p )
errfmt();
switch ( size )
{
case 0:
lc.len = (uchar)data;
lc.sum = lc.len;
break;
case 4:
lc.sum += (uchar)(data >> 24);
case 3:
lc.sum += (uchar)(data >> 16);
case 2:
lc.sum += (uchar)(data >> 8);
default: // 1
lc.sum += (uchar)data;
break;
}
return data;
}
//--------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort neflag, const char * /*fileformatname*/)
{
memset(&lc, 0, sizeof(local_data));
inf_set_start_ip(BADADDR); // f_SREC without start record
processor_t &ph = PH;
bool iscode = (neflag & NEF_CODE) != 0;
uint bs = iscode ? ph.cbsize() : ph.dbsize(); // number of bytes
ea_t start_ea = to_ea(inf_get_baseaddr(), 0);
sel_t sel = setup_selector(start_ea >> 4);
bool segment_created = false;
bool cvt_to_bytes = false;
if ( ph.id == PLFM_PIC )
{
// pic12xx and pic16xx use 12-bit and 14-bit words in program memory
// pic18xx uses 16-bit opcodes but byte addressing
if ( strncmp(inf_get_procname().c_str(), "PIC18", 5) != 0 )
{
static const char *const form =
// "PIC HEX file addressing mode\n"
// "\n"
"There are two flavors of HEX files for PIC: with word addressing\n"
"and with byte addressing. It is not possible to recognize the\n"
"flavor automatically. Please specify what addressing mode should\n"
"be used to load the input file. If you don't know, try both and\n"
"choose the one which produces the more meaningful result\n";
int code = ask_buttons("~B~yte addressing",
"~W~ord addressing",
"~C~ancel",
1,
form);
switch ( code )
{
case 1:
break;
case 0:
cvt_to_bytes = true;
break;
default:
loader_failure();
}
}
}
bool bs_addr_scale = true;
if ( ph.id == PLFM_TMS320C28 )
bs_addr_scale = false;
filetype_t ftype = inf_get_filetype();
char rstart = (ftype == f_SREC) ? 'S'
: (ftype == f_HEX) ? ':'
: ';';
ea_t addr;
ea_t end_ea = 0;
ea_t seg_start = 0;
ea_t subs_addr20 = 0;
ea_t subs_addr32 = 0;
bool bigaddr = false;
char line[BUFFSIZE];
for ( lc.ln = 1; qlgets(line, BUFFSIZE, li); lc.ln++ )
{
char *p = line;
while ( *p == ' ' )
++p;
if ( *p == '\n' || *p == '\r' )
continue;
if ( *p++ != rstart )
errfmt();
int sz = 2;
int mode = (ftype == f_SREC) ? (uchar)*p++ : 0x100;
lc.ptr = p;
hexdata(0);
if ( mode == 0x100 )
{
if ( !lc.len )
break;
lc.len += 2;
if ( ftype == f_HEX )
++lc.len;
}
else
{
switch ( mode )
{
default:
errfmt();
case '0':
case '5':
continue;
case '3':
case '7':
++sz;
// fallthrough
case '2':
case '8':
++sz;
// fallthrough
case '1':
case '9':
if ( mode > '3' )
mode = 0;
--lc.len;
break;
}
}
addr = hexdata(sz);
if ( ftype != f_SREC && bs_addr_scale )
addr = addr / bs;
if ( !mode )
{
inf_set_start_ip(addr);
continue;
}
if ( ftype == f_HEX )
{
int type = hexdata(1); // record type
switch ( type )
{
case 0xFF: // mitsubishi hex format
case 4: // Extended linear address record (bits 16..31 of the start address)
{
uint32 seg_addr = uint32(hexdata(2) << 16);
if ( bs_addr_scale )
seg_addr /= bs;
subs_addr32 = seg_addr;
}
break;
case 2: // Extended segment address record (bits 4..19 of the start address)
{
uint32 seg_addr = uint32(hexdata(2) << 4);
if ( bs_addr_scale )
seg_addr /= bs;
subs_addr20 = seg_addr;
}
break;
case 5: // start address (ARM)
{
uint32 start_addr = hexdata(4);
if ( ph.has_code16_bit() && (start_addr & 1) != 0 )
{
processor_t::set_code16_mode(start_addr, true);
start_addr &= ~1;
}
inf_set_start_ip(start_addr);
inf_set_start_ea(start_addr);
}
break;
}
if ( type != 0 )
{
if ( type == 1 )
break; // end of file record
continue; // not a data record
}
}
// add the extended address bits
addr += subs_addr20;
addr += subs_addr32;
if ( lc.len )
{
ea_t top = addr + lc.len / bs;
p = line;
while ( lc.len )
{
*p++ = (uchar)hexdata(1);
if ( cvt_to_bytes ) // pic
*p++ = '\0';
}
if ( top >= 0x10000 )
bigaddr = true;
addr += start_ea;
show_addr(addr);
top += start_ea;
if ( top > end_ea || !segment_created )
{
asize_t delta = addr - end_ea;
if ( delta >= SEGMENTGAP )
segment_created = false; // force creation of new segment
end_ea = top;
if ( neflag & NEF_SEGS )
{
if ( !segment_created )
{
if ( !add_segm(sel, addr, end_ea, NULL, iscode ? CLASS_CODE : CLASS_DATA) )
loader_failure();
segment_created = true;
seg_start = addr;
}
else
{
int flags = delta > SPARSE_GAP ? SEGMOD_SPARSE : 0;
set_segm_end(seg_start, end_ea, flags);
}
}
}
if ( seg_start > addr )
{
if ( (neflag & NEF_SEGS) != 0 )
{
int flags = seg_start-addr > SPARSE_GAP ? SEGMOD_SPARSE : 0;
set_segm_start(seg_start, addr, flags);
}
seg_start = addr;
}
mem2base(line, addr, top, -1);
}
{
ushort chi; // checksum
++lc.len;
switch ( ftype )
{
case f_SREC:
chi = (uchar)(~lc.sum);
chi ^= (uchar)hexdata(1);
break;
case f_HEX:
hexdata(1);
chi = (uchar)lc.sum;
break;
default: // MEX
++lc.len;
chi = lc.sum;
chi -= (ushort)hexdata(2);
break;
}
if ( chi )
{
static bool displayed = false;
if ( !displayed )
{
displayed = true;
warning("Bad hex input file checksum, line %u. Ignore?", lc.ln);
}
}
}
}
if ( (neflag & NEF_SEGS) != 0 )
{
if ( bigaddr )
{
set_segm_addressing(get_first_seg(), 1);
if ( ph.id == PLFM_386 )
inf_set_lflags(inf_get_lflags() | LFLG_PC_FLAT);
}
set_default_dataseg(sel);
inf_set_start_cs(sel);
}
else
{
enable_flags(start_ea, end_ea, STT_CUR);
}
inf_set_af(inf_get_af() & ~AF_FINAL); // behave as a binary file
create_filename_cmt();
}
//--------------------------------------------------------------------------
static int set_s_type(ea_t addr)
{
int off = 0;
lc.sz = 4;
lc.size += 3;
if ( addr >= 0x10000 )
{
++off;
lc.sz += 2;
lc.sum += (uchar)(addr >> 16);
++lc.size;
if ( addr >= 0x01000000 )
{
++off;
lc.sz += 2;
lc.sum += (uchar)(addr >> 24);
++lc.size;
}
}
return off;
}
//--------------------------------------------------------------------------
GCC_DIAG_OFF(format-nonliteral);
int idaapi write_file(FILE *fp, const char * /*fileformatname*/)
{
//#define TEST_COMPILATION
#ifdef TEST_COMPILATION
# define DECL_FMT(x, y) static const char *const x = y
#else
# define DECL_FMT(x, y) static char x[] = y
#endif
DECL_FMT(fmt0, "%02X%0*" FMT_EA "X%s%0?X\r\n");
DECL_FMT(fmt1, "?00?00001FF\r\n");
DECL_FMT(fone, "%02X");
ea_t base = to_ea(inf_get_baseaddr(), 0);
if ( inf_get_min_ea() < base )
base = BADADDR;
if ( fp == NULL )
{
if ( inf_get_filetype() == f_SREC )
return 1;
ea_t ea1 = inf_get_max_ea() - inf_get_min_ea();
if ( ea1 <= 0x10000 )
return 1;
ea_t strt = 0;
ea_t addr;
for ( addr = inf_get_min_ea(); addr < inf_get_max_ea(); )
{
segment_t *ps = getseg(addr);
if ( ps == NULL || ps->type != SEG_IMEM )
{
if ( is_loaded(addr) )
break;
if ( base != BADADDR )
{
if ( --ea1 <= 0x10000 )
return 1;
}
else
{
++strt;
}
++addr;
continue;
}
if ( strt )
{
ea1 -= strt;
if ( ea1 != 0x10000 )
return 1;
strt = 0;
}
ea1 -= (ps->end_ea - addr);
if ( ea1 < 0x10000 )
return 1;
++ea1;
addr = ps->end_ea;
}
if ( base == BADADDR )
{
segment_t *ps = getseg(addr);
ea1 -= (ps == NULL) ? addr : ps->start_ea;
if ( ea1 <= 0x10000 )
return 1;
}
if ( addr == inf_get_max_ea() )
return 0;
for ( base = inf_get_max_ea()-1; base > addr; )
{
segment_t *ps = getseg(base);
if ( ps == NULL || ps->type != SEG_IMEM )
{
if ( is_loaded(base) )
break;
if ( --ea1 <= 0x10000 )
return 1;
--base;
continue;
}
ea1 -= (base - ps->start_ea);
if ( ea1 < 0x10000 )
return 1;
++ea1;
base = ps->start_ea;
}
return 0;
}
char ident;
const char *found = qstrrchr(fmt0, '?');
QASSERT(20067, found != NULL);
int fmt0_marker = ((char *) found) - fmt0;
fmt0[fmt0_marker] = '2';
switch ( inf_get_filetype() )
{
case f_SREC:
ident = 'S';
break;
case f_HEX:
ident = ':';
fmt1[3] = '0';
break;
default:
ident = ';';
fmt0[fmt0_marker] = '4';
fmt1[3] = '\0';
break;
}
fmt1[0] = ident;
lc.sz = 4;
ea_t strt = inf_get_start_ip();
for ( ea_t ea1 = inf_get_min_ea(); ea1 < inf_get_max_ea(); )
{
char str[(2 * MAX_BYTES) + 3];
char *const end = str + sizeof(str);
if ( !is_loaded(ea1) || segtype(ea1) == SEG_IMEM )
{
++ea1;
continue;
}
if ( base == BADADDR )
{
segment_t *ps = getseg(ea1);
base = ps == NULL ? ea1 : ps->start_ea;
if ( strt != BADADDR )
strt += inf_get_min_ea() - base;
}
ea_t addr = ea1 - base;
lc.sum = (uchar)addr + (uchar)(addr >> 8);
char *p = str;
if ( inf_get_filetype() == f_HEX )
{
*p++ = '0';
*p++ = '0';
}
lc.size = 0;
do
{
uchar b = get_byte(ea1++);
p += qsnprintf(p, end-p, fone, (unsigned)b);
lc.sum += b;
} while ( ++lc.size < MAX_BYTES
&& ea1 < inf_get_max_ea()
&& is_loaded(ea1)
&& segtype(ea1) != SEG_IMEM );
qfputc(ident, fp);
if ( inf_get_filetype() == f_SREC )
{
char type = '1' + (char)set_s_type(addr);
qfputc(type, fp);
++lc.sum; // correct to NOT
} // else addr = (ushort)addr; // force check
lc.sum += (ushort)lc.size;
if ( inf_get_filetype() != f_MEX )
lc.sum = (uchar)(0-lc.sum);
qfprintf(fp, fmt0, lc.size, lc.sz, addr, str, lc.sum);
}
if ( inf_get_filetype() != f_SREC )
{
qfprintf(fp, "%s", fmt1);
}
else if ( strt != BADADDR )
{
qfputc(ident, fp);
lc.sum = 0;
lc.size = 0;
char type = '9' - (char)set_s_type(strt);
qfputc(type, fp);
lc.sum = (~(lc.size + lc.sum)) & 0xFF;
qfprintf(fp, fmt0, lc.size, lc.sz, strt, &fone[sizeof(fone)-1], lc.sum);
}
return 1;
}
GCC_DIAG_ON(format-nonliteral);
//--------------------------------------------------------------------------
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
LDRF_REQ_PROC, // requires the target processor to the set
//
// 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.
//
write_file,
NULL,
NULL,
};

13
idasdk76/ldr/hex/makefile Normal file
View File

@@ -0,0 +1,13 @@
PROC=hex
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)hex$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h hex.cpp

View File

@@ -0,0 +1,197 @@
//--------------------------------------------------------------------------
void sys_clock::swap(void)
{
secs = swap32(secs);
nanosecs = swap32(nanosecs);
};
//--------------------------------------------------------------------------
void header::swap(void)
{
system_id= swap16(system_id);
a_magic= swap16(a_magic);
file_time.swap();
version_id= swap32(version_id);
entry_space= swap32(entry_space);
entry_subspace= swap32(entry_subspace);
entry_offset= swap32(entry_offset);
aux_header_location= swap32(aux_header_location);
aux_header_size= swap32(aux_header_size);
som_length= swap32(som_length);
presumed_dp= swap32(presumed_dp);
space_location= swap32(space_location);
space_total= swap32(space_total);
subspace_location= swap32(subspace_location);
subspace_total= swap32(subspace_total);
loader_fixup_location= swap32(loader_fixup_location);
loader_fixup_total= swap32(loader_fixup_total);
space_strings_location= swap32(space_strings_location);
space_strings_size= swap32(space_strings_size);
init_array_location= swap32(init_array_location);
init_array_total= swap32(init_array_total);
compiler_location= swap32(compiler_location);
compiler_total= swap32(compiler_total);
symbol_location= swap32(symbol_location);
symbol_total= swap32(symbol_total);
fixup_request_location= swap32(fixup_request_location);
fixup_request_total= swap32(fixup_request_total);
symbol_strings_location= swap32(symbol_strings_location);
symbol_strings_size= swap32(symbol_strings_size);
unloadable_sp_location= swap32(unloadable_sp_location);
unloadable_sp_size= swap32(unloadable_sp_size);
checksum= swap32(checksum);
}
//--------------------------------------------------------------------------
void aux_id::swap(void)
{
type = swap16(type);
length = swap32(length);
}
//--------------------------------------------------------------------------
void som_exec_auxhdr::swap(void)
{
header_id.swap();
exec_tsize = swap32(exec_tsize); /* text size */
exec_tmem = swap32(exec_tmem); /* start address of text */
exec_tfile = swap32(exec_tfile); /* file ptr to text */
exec_dsize = swap32(exec_dsize); /* data size */
exec_dmem = swap32(exec_dmem); /* start address of data */
exec_dfile = swap32(exec_dfile); /* file ptr to data */
exec_bsize = swap32(exec_bsize); /* bss size */
exec_entry = swap32(exec_entry); /* address of entry point */
exec_flags = swap32(exec_flags); /* loader flags */
exec_bfill = swap32(exec_bfill); /* bss initialization value */
}
//--------------------------------------------------------------------------
void user_string_aux_hdr::swap(void) /* Version string auxiliary header */
{
header_id.swap();
string_length = swap32(string_length); /* strlen(user_string) */
}
//--------------------------------------------------------------------------
void copyright_aux_hdr::swap(void)
{
header_id.swap();
string_length = swap32(string_length); /* strlen(user_string) */
}
//--------------------------------------------------------------------------
void shlib_version_aux_hdr::swap(void)
{
header_id.swap();
version = swap16(version); /* version number */
}
//--------------------------------------------------------------------------
void space_dictionary_record::swap(void)
{
name.n_strx = swap32(name.n_strx);
space_number = swap32(space_number);
subspace_index = swap32(subspace_index);
subspace_quantity = swap32(subspace_quantity);
loader_fix_index = swap32(loader_fix_index);
loader_fix_quantity = swap32(loader_fix_quantity);
init_pointer_index = swap32(init_pointer_index);
init_pointer_quantity = swap32(init_pointer_quantity);
};
//--------------------------------------------------------------------------
void subspace_dictionary_record::swap(void)
{
space_index = swap32(space_index);
file_loc_init_value = swap32(file_loc_init_value);
initialization_length = swap32(initialization_length);
subspace_start = swap32(subspace_start);
subspace_length = swap32(subspace_length);
reserved2 = swap16(reserved2);
alignment = swap16(alignment);
name.n_strx = swap32(name.n_strx);
fixup_request_index = swap32(fixup_request_index);
fixup_request_quantity = swap32(fixup_request_quantity);
}
//--------------------------------------------------------------------------
void symbol_dictionary_record::swap(void)
{
name.n_strx = swap32(name.n_strx);
qualifier_name.n_strx = swap32(qualifier_name.n_strx);
symbol_info = swap32(symbol_info);
symbol_value = swap32(symbol_value);
}
//--------------------------------------------------------------------------
void dl_header::swap(void)
{
hdr_version = swap32(hdr_version);
ltptr_value = swap32(ltptr_value);
shlib_list_loc = swap32(shlib_list_loc);
shlib_list_count = swap32(shlib_list_count);
import_list_loc = swap32(import_list_loc);
import_list_count = swap32(import_list_count);
hash_table_loc = swap32(hash_table_loc);
hash_table_size = swap32(hash_table_size);
export_list_loc = swap32(export_list_loc);
export_list_count = swap32(export_list_count);
string_table_loc = swap32(string_table_loc);
string_table_size = swap32(string_table_size);
dreloc_loc = swap32(dreloc_loc);
dreloc_count = swap32(dreloc_count);
dlt_loc = swap32(dlt_loc);
plt_loc = swap32(plt_loc);
dlt_count = swap32(dlt_count);
plt_count = swap32(plt_count);
highwater_mark = swap16(highwater_mark);
flags = swap16(flags);
export_ext_loc = swap32(export_ext_loc);
module_loc = swap32(module_loc);
module_count = swap32(module_count);
elaborator = swap32(elaborator);
initializer = swap32(initializer);
embedded_path = swap32(embedded_path);
initializer_count = swap32(initializer_count);
tdsize = swap32(tdsize);
fastbind_list_loc = swap32(fastbind_list_loc);
}
//--------------------------------------------------------------------------
void import_entry::swap(void)
{
name = swap32(name);
}
//--------------------------------------------------------------------------
void misc_info::swap(void)
{
version = swap16(version);
flags = swap16(flags);
}
//--------------------------------------------------------------------------
void export_entry::swap(void)
{
next = swap32(next);
name = swap32(name);
value = swap32(value);
if ( type == ST_STORAGE )
info.size = swap32(info.size);
else
info.misc.swap();
module_index = swap16(module_index);
}
//--------------------------------------------------------------------------
static uint32 compute_som_checksum(void *p)
{
int n = sizeof(header) / sizeof(uint32);
uint32 *ptr = (uint32 *)p;
uint32 sum = 0;
for ( int i=0; i < n; i++ )
sum ^= *ptr++;
return sum;
}

View File

@@ -0,0 +1,441 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2000 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*/
#include "../idaldr.h"
#include <typeinf.hpp>
#include "hpsom.hpp"
#include "common.cpp"
static int first_text_subspace_idx = -1;
static int32 first_text_subspace_fpos = -1;
static char *dl_strings = NULL;
static size_t dl_ssize = 0;
static ea_t data_start = 0;
static int64 fsize = 0;
//--------------------------------------------------------------------------
static void complain_fixup(void)
{
static bool complained = false;
if ( !complained )
{
warning("The input file contains relocation information.\n"
"Currently IDA doesn't handle relocation information,\n"
"so it will be skipped");
complained = true;
}
}
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
header h;
qlseek(li, 0);
if ( qlread(li, &h, sizeof(h)) != sizeof(h) )
return 0;
if ( compute_som_checksum(&h) != 0 )
return 0;
h.swap();
const char *type;
switch ( h.a_magic )
{
case EXELIB_MAGIC : type = "Executable Library"; break;
case REL_MAGIC : type = "Relocatable"; break;
case EXE_MAGIC : type = "Non-sharable, executable"; break;
case SHREXE_MAGIC : type = "Sharable, executable"; break;
case SHREXELD_MAGIC: type = "Sharable, demand-loadable executable"; break;
case DLL_MAGIC : type = "Dynamic Load Library"; break;
case SHLIB_MAGIC : type = "Shared Library"; break;
case RELLIB_MAGIC : type = "Relocatable Library"; break;
default: return 0;
}
fileformatname->sprnt("HP-UX SOM (%s)", type);
*processor = "hppa";
return 1;
}
//--------------------------------------------------------------------------
static void load_aux_headers(linput_t *li, int32 fpos, size_t size)
{
if ( size == 0 )
return;
size_t rest = fsize - fpos;
if ( rest <= size )
loader_failure("Wrong header::aux_header_size");
qlseek(li, fpos);
while ( size > 0 )
{
char buf[4096];
CASSERT(sizeof(buf) >= sizeof(aux_id));
aux_id &aih = *(aux_id *)buf;
lread(li, &aih, sizeof(aih));
aih.swap();
size_t total = sizeof(aih) + aih.length;
if ( total < sizeof(aih) || total >= sizeof(buf) )
loader_failure("Wrong aux_header size %" FMT_Z, total);
if ( total > size )
return; // loader_failure("Illegal aux header size %u, rest %u", total, size);
size -= total;
lread(li, &aih+1, aih.length);
switch ( aih.type )
{
case HPUX_AUX_ID:
{
som_exec_auxhdr *p = (som_exec_auxhdr*)buf;
p->swap();
inf_set_start_cs(0);
inf_set_start_ip(p->exec_entry);
data_start = p->exec_dmem;
}
break;
case VERSION_AUX_ID:
case COPYRIGHT_AUX_ID:
case SHLIB_VERSION_AUX_ID:
default:
break;
}
}
}
//--------------------------------------------------------------------------
static char *get_name(linput_t *li, int32 tableoff, size_t tablesize, int32 nidx, char *buf, size_t bufsize)
{
if ( nidx >= tablesize )
{
APPZERO(buf, buf+bufsize);
}
else
{
qoff64_t fpos = qltell(li);
qlseek(li, tableoff+nidx-4);
uint32 len;
lread(li, &len, sizeof(len));
len = swap32(len);
if ( len >= bufsize )
len = uint32(bufsize-1);
lread(li, buf, len);
buf[len] = '\0';
qlseek(li, fpos);
}
return buf;
}
//--------------------------------------------------------------------------
inline char *get_space_name(linput_t *li, const header &h, int32 nidx, char *buf, size_t bufsize)
{
return get_name(li,
h.space_strings_location,
h.space_strings_size,
nidx,
buf,
bufsize);
}
inline char *get_symbol_name(linput_t *li, const header &h, int32 nidx, char *buf, size_t bufsize)
{
return get_name(li,
h.symbol_strings_location,
h.symbol_strings_size,
nidx,
buf,
bufsize);
}
//--------------------------------------------------------------------------
static void load_spaces(linput_t *li, const header &h, int32 fpos, int n)
{
if ( n == 0 )
return;
qlseek(li, fpos);
space_dictionary_record sr;
validate_array_count_or_die(li, n, sizeof(sr), "Number of spaces", fpos);
for ( int i=0; i < n; i++ )
{
lread(li, &sr, sizeof(sr));
sr.swap();
char buf[MAXSTR];
get_space_name(li, h, sr.name.n_strx, buf, sizeof(buf));
if ( streq(buf, "$TEXT$") )
first_text_subspace_idx = sr.subspace_index;
}
}
//--------------------------------------------------------------------------
static void load_subspaces(linput_t *li, const header &h, qoff64_t fpos, int n)
{
if ( n == 0 )
return;
subspace_dictionary_record sr;
validate_array_count_or_die(li, n, sizeof(sr), "Number of subspaces", fpos);
for ( int i=0; i < n; i++,fpos+=sizeof(sr) )
{
qlseek(li, fpos);
lread(li, &sr, sizeof(sr));
sr.swap();
if ( !sr.is_loadable() || !sr.subspace_length )
continue;
if ( sr.fixup_request_quantity )
complain_fixup();
ea_t start = sr.subspace_start;
ea_t end = start + sr.initialization_length;
qoff64_t fpos2 = sr.file_loc_init_value;
if ( end < start || fpos2 > fsize || fsize-fpos2 < end-start )
loader_failure("Wrong segment size %a..%a", start, end);
file2base(li, fpos2, start, end, FILEREG_PATCHABLE);
char buf[MAXSTR];
char *name = get_space_name(li, h, sr.name.n_strx, buf, sizeof(buf));
set_selector(i, 0);
const char *sclass = strstr(name, "CODE") != NULL ? CLASS_CODE : CLASS_DATA;
segment_t s;
s.sel = setup_selector(i);
s.start_ea = start;
s.end_ea = start + sr.subspace_length;
s.align = saRelByte;
s.comb = scPub;
s.bitness = (uchar)PH.get_segm_bitness();
if ( !add_segm_ex(&s, name, sclass, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed to create segment %a..%a", s.start_ea, s.end_ea);
if ( i == first_text_subspace_idx )
first_text_subspace_fpos = sr.file_loc_init_value;
// sr.alignment,
}
}
//--------------------------------------------------------------------------
static void load_symbols(linput_t *li, const header &h, int32 fpos, int n)
{
if ( n == 0 )
return;
qlseek(li, fpos);
symbol_dictionary_record sr;
validate_array_count_or_die(li, n, sizeof(sr), "Number of symbols", fpos);
for ( int i=0; i < n; i++ )
{
lread(li, &sr, sizeof(sr));
sr.swap();
if ( sr.symbol_scope() == SS_UNSAT )
continue;
char buf[MAXSTR];
char *name = get_symbol_name(li, h, sr.name.n_strx, buf, sizeof(buf));
ea_t ea = sr.symbol_value & ~3;
switch ( sr.symbol_type() )
{
case ST_NULL:
case ST_ABSOLUTE:
break;
case ST_DATA:
force_name(ea, name, SN_IDBENC);
break;
case ST_STUB:
append_cmt(ea, "STUB", false);
// fallthrough
case ST_CODE:
case ST_ENTRY:
case ST_MILLICODE:
case ST_MILLI_EXT:
add_entry(ea, ea, name, true, AEF_IDBENC);
add_entry(ea, ea, name, true, AEF_IDBENC);
break;
case ST_PRI_PROG:
case ST_STORAGE:
case ST_MODULE:
case ST_SYM_EXT:
case ST_ARG_EXT:
case ST_PLABEL:
case ST_OCT_DIS:
case ST_TSTORAGE:
break;
}
}
}
//--------------------------------------------------------------------------
static char *get_text_name(int nidx, char *buf, size_t bufsize)
{
if ( nidx == -1 )
return NULL;
if ( nidx >= 0 && nidx < dl_ssize )
qstrncpy(buf, dl_strings + nidx, bufsize);
else
qsnprintf(buf, bufsize, "0x%08X", nidx);
return buf;
}
//--------------------------------------------------------------------------
static void load_imports(linput_t *li, const dl_header &dl)
{
if ( dl.import_list_count == 0 )
return;
qoff64_t fpos = first_text_subspace_fpos + dl.import_list_loc;
qlseek(li, fpos);
ea_t ea = data_start + dl.dlt_loc;
int n = dl.dlt_count;
import_entry ie;
validate_array_count_or_die(li, dl.import_list_count, sizeof(ie), "Number of imports", fpos);
for ( int i=0; i < dl.import_list_count; i++ )
{
lread(li, &ie, sizeof(ie));
ie.swap();
if ( n == 0 )
ea = data_start + dl.plt_loc;
n--;
char buf[MAXSTR];
buf[0] = '.';
get_text_name(ie.name, &buf[1], sizeof(buf)-1);
force_name(ea, buf, SN_IDBENC);
create_dword(ea, 4);
op_plain_offset(ea, 0, 0);
if ( n > 0 )
{
ea += 4;
}
else
{
ea_t ea2 = get_dword(ea);
force_name(ea2, &buf[1], SN_IDBENC);
add_func(ea2);
set_func_cmt(get_func(ea2), "THUNK", false);
create_dword(ea+4, 4);
ea += 8;
}
}
}
//--------------------------------------------------------------------------
static void load_exports(linput_t *li, const dl_header &dl)
{
if ( dl.export_list_count == 0 )
return;
export_entry ee;
qoff64_t fpos = first_text_subspace_fpos + dl.export_list_loc;
qlseek(li, fpos);
validate_array_count_or_die(li, dl.export_list_count, sizeof(ee), "Number of exports", fpos);
for ( int i=0; i < dl.export_list_count; i++ )
{
lread(li, &ee, sizeof(ee));
ee.swap();
char buf[MAXSTR];
const char *name = get_text_name(ee.name, buf, sizeof(buf));
add_entry(ee.value, ee.value, name, ee.type == ST_CODE, AEF_IDBENC);
}
}
//--------------------------------------------------------------------------
static void load_dl_header(linput_t *li)
{
if ( first_text_subspace_fpos == -1 )
return;
qlseek(li, first_text_subspace_fpos);
dl_header dl;
lread(li, &dl, sizeof(dl));
dl.swap();
switch ( dl.hdr_version )
{
case OLD_HDR_VERSION: break;
case HDR_VERSION: break;
default:
msg("Unknown DL header version, skipping...\n");
}
if ( dl.string_table_size != 0 )
{
qoff64_t fpos = first_text_subspace_fpos + dl.string_table_loc;
qlseek(li, fpos);
dl_ssize = dl.string_table_size;
validate_array_count_or_die(li, dl_ssize, 1, "String table size", fpos);
dl_strings = (char *)qalloc(dl_ssize);
if ( dl_strings == NULL )
nomem("dl_strings");
lread(li, dl_strings, dl_ssize);
}
if ( dl.dreloc_count != 0 )
complain_fixup();
load_imports(li, dl);
load_exports(li, dl);
qfree(dl_strings);
dl_strings = NULL;
}
//--------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
set_processor_type("hppa", SETPROC_LOADER);
header h;
qlseek(li, 0);
lread(li, &h, sizeof(h));
h.swap();
inf_set_baseaddr(0);
fsize = qlsize(li);
load_aux_headers(li, h.aux_header_location, h.aux_header_size);
load_spaces(li, h, h.space_location, h.space_total);
load_subspaces(li, h, h.subspace_location, h.subspace_total);
load_symbols(li, h, h.symbol_location, h.symbol_total);
load_dl_header(li);
create_filename_cmt();
size_t dp = h.presumed_dp;
if ( dp == 0 )
{
// 23 61 28 00 ldil ...., %dp
// 37 7B 01 60 ldo 0xB0(%dp), %dp
insn_t insn;
if ( decode_insn(&insn, inf_get_start_ip()) > 0
&& insn.Op1.type == o_imm
&& insn.Op2.type == o_reg )
{
uval_t v = insn.Op1.value;
if ( decode_insn(&insn, insn.ea+4) && insn.Op1.type == o_displ )
dp = size_t(v + insn.Op1.addr);
}
}
if ( dp != 0 )
set_gotea(dp);
add_til("hpux", ADDTIL_DEFAULT);
}
//--------------------------------------------------------------------------
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,
};

View File

@@ -0,0 +1,542 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2000 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*/
#ifndef HPSOM_HPP
#define HPSOM_HPP
// The timestamp is a two-word structure as shown below. If unused, both fields are
// zero.
struct sys_clock
{
uint secs;
uint nanosecs;
void swap(void);
};
struct header
{
short system_id; /* system id */
#define SYSTEM_10 0x20B // PA-RISC 1.0
#define SYSTEM_11 0x210 // PA-RISC 1.1
#define SYSTEM_20 0x214 // PA-RISC 2.0
short int a_magic; /* magic number */
#define EXELIB_MAGIC 0x104 // Executable SOM Library
#define REL_MAGIC 0x106 // Relocatable SOM
#define EXE_MAGIC 0x107 // Non-sharable, executable SOM
#define SHREXE_MAGIC 0x108 // Sharable, executable SOM
#define SHREXELD_MAGIC 0x10B // Sharable, demand-loadable executable SOM
#define DLL_MAGIC 0x10D // Dynamic Load Library
#define SHLIB_MAGIC 0x10E // Shared Library
#define RELLIB_MAGIC 0x619 // Relocatable SOM Library
uint version_id; /* a.out format version */
struct sys_clock file_time; /* timestamp */
uint entry_space; /* index of space containing entry point */
uint entry_subspace; /* subspace index of entry */
uint entry_offset; /* offset of entry point */
uint aux_header_location; /* file ptr to aux hdrs */
uint aux_header_size; /* sizeof aux hdrs */
uint som_length; /* length of object module */
uint presumed_dp; /* DP value assumed during compilation */
uint space_location; /* file ptr to space dict */
uint space_total; /* # of spaces */
uint subspace_location; /* file ptr to subsp dict */
uint subspace_total; /* # of subspaces */
uint loader_fixup_location; /* space reference array */
uint loader_fixup_total; /* # of space reference recs */
uint space_strings_location; /* file ptr to sp. strings */
uint space_strings_size; /* sizeof sp. strings */
uint init_array_location; /* location of init pointers */
uint init_array_total; /* # of init pointers */
uint compiler_location; /* file ptr to comp recs */
uint compiler_total; /* # of compiler recs */
uint symbol_location; /* file ptr to sym table */
uint symbol_total; /* # of symbols */
uint fixup_request_location; /* file ptr to fixups */
uint fixup_request_total; /* # of fixups */
uint symbol_strings_location; /* file ptr to sym strings */
uint symbol_strings_size; /* sizeof sym strings */
uint unloadable_sp_location; /* file ptr to debug info */
uint unloadable_sp_size; /* size of debug info */
uint checksum; /* header checksum */
void swap(void);
};
//--------------------------------------------------------------------------
// Auxiliary Headers
//
// The auxiliary headers are contained in a single contiguous area in the file, and
// are located by a pointer in the file header. Auxiliary headers are used for two
// purposes: to attach users' version and copyright strings to an object file, and
// to contain the information needed to load an executable program. In an
// executable program, the HP-UX auxiliary header must precede all other auxiliary
// headers.
struct aux_id
{
unsigned char flags;
#define AUX_MANDATORY 0x10 /* linker must understand aux hdr info */
#define AUX_COPY 0x20 /* copy aux hdr without modification */
#define AUX_APPEND 0x40 /* merge multiple entries of same type */
#define AUX_IGNORE 0x80 /* ignore aux hdr if type unknown */
bool mandatory(void) { return (flags & AUX_MANDATORY) != 0; }
bool copy(void) { return (flags & AUX_COPY ) != 0; }
bool append(void) { return (flags & AUX_APPEND ) != 0; }
bool ignore(void) { return (flags & AUX_IGNORE ) != 0; }
uchar reserved;
ushort type; /* aux hdr type */
uint length; /* sizeof rest of aux hdr */
void swap(void);
};
/* Values for the aux_id.type field */
#define HPUX_AUX_ID 4
#define VERSION_AUX_ID 6
#define COPYRIGHT_AUX_ID 9
#define SHLIB_VERSION_AUX_ID 10
struct som_exec_auxhdr /* HP-UX auxiliary header */
{
struct aux_id header_id; /* aux header id */
int32 exec_tsize; /* text size */
int32 exec_tmem; /* start address of text */
int32 exec_tfile; /* file ptr to text */
int32 exec_dsize; /* data size */
int32 exec_dmem; /* start address of data */
int32 exec_dfile; /* file ptr to data */
int32 exec_bsize; /* bss size */
int32 exec_entry; /* address of entry point */
int32 exec_flags; /* loader flags */
int32 exec_bfill; /* bss initialization value */
void swap(void);
};
/* Values for exec_flags */
#define TRAP_NIL_PTRS 01
struct user_string_aux_hdr /* Version string auxiliary header */
{
struct aux_id header_id; /* aux header id */
uint string_length; /* strlen(user_string) */
char user_string[1]; /* user-defined string */
void swap(void);
};
struct copyright_aux_hdr /* Copyright string auxiliary header */
{
struct aux_id header_id; /* aux header id */
uint string_length; /* strlen(user_string) */
char copyright[1]; /* user-defined string */
void swap(void);
};
struct shlib_version_aux_hdr
{
struct aux_id header_id; /* aux header id */
short version; /* version number */
void swap(void);
};
//--------------------------------------------------------------------------
// Space Dictionary
//
// The space dictionary consists of a sequence of space records
//
// The strings for the space names are contained in the space strings table, which
// is located by a pointer in the file header. Each entry in the space strings
// table is preceded by a 4-byte integer that defines the length of the string, and
// is terminated by one to five null characters to pad the string out to a word
// boundary. Indices to this table are relative to the start of the table, and
// point to the first byte of the string (not the preceding length word). The union
// defined above is used for all such string pointers; the character pointer is
// defined for programs that read the string table into memory and wish to relocate
// in-memory copies of space records.
union name_pt
{
// char *n_name;
uint n_strx;
};
struct space_dictionary_record
{
union name_pt name; /* index to space name */
unsigned char flags;
#define SPACE_IS_LOADABLE 0x80 /* space is loadable */
#define SPACE_IS_DEFINED 0x40 /* space is defined within file */
#define SPACE_IS_PRIVATE 0x20 /* space is not sharable */
#define SPACE_HAS_INTERM 0x10 /* contains intermediate code */
#define SPACE_IS_TSPEC 0x08 /* space is $thread_specific$ */
bool is_loadable(void) { return (flags & SPACE_IS_LOADABLE) != 0; }
bool is_defined(void) { return (flags & SPACE_IS_DEFINED ) != 0; }
bool is_private(void) { return (flags & SPACE_IS_PRIVATE ) != 0; }
bool has_intermediate_code(void) { return (flags & SPACE_HAS_INTERM ) != 0; }
bool is_tspecific(void) { return (flags & SPACE_IS_TSPEC ) != 0; }
unsigned char reserved;
unsigned char sort_key; /* sort key for space */
unsigned char reserved2; /* reserved */
int space_number; /* space index */
int subspace_index; /* index to first subspace */
uint subspace_quantity; /* # of subspaces in space */
int loader_fix_index; /* index into loader fixup array */
uint loader_fix_quantity; /* # of loader fixups in space */
int init_pointer_index; /* index into init pointer array */
uint init_pointer_quantity; /* # of init ptrs */
void swap(void);
};
//--------------------------------------------------------------------------
// Subspace Dictionary
//
// The subspace dictionary consists of a sequence of subspace records, as defined
// in <scnhdr.h>. Strings for subspace names are contained in the space strings
// table.
struct subspace_dictionary_record
{
int space_index; /* index into space dictionary */
unsigned char f1;
#define SUBS_F1_ACCESS 0xFE /* access and priv levels of subsp */
#define SUBS_F1_MEMRES 0x01 /* lock in memory during exec */
int access_control_bits(void) { return (f1 & SUBS_F1_ACCESS) >> 1; }
bool memory_resident(void) { return (f1 & SUBS_F1_MEMRES) != 0; }
unsigned char f2;
#define SUBS_F2_DUPCOM 0x80 /* duplicate data symbols allowed */
#define SUBS_F2_INICOM 0x40 /* initialized common block */
#define SUBS_F2_ISLOAD 0x20 /* subspace is loadable */
#define SUBS_F2_QUADR 0x18 /* quadrant in space subsp should reside in */
#define SUBS_F2_FROZEN 0x04 /* lock in memory when OS booted */
#define SUBS_F2_FIRST 0x02 /* must be first subspace */
#define SUBS_F2_CODE 0x01 /* subspace contains only code */
bool dup_common(void) { return (f2 & SUBS_F2_DUPCOM) != 0; }
bool is_common(void) { return (f2 & SUBS_F2_INICOM) != 0; }
bool is_loadable(void) { return (f2 & SUBS_F2_ISLOAD) != 0; }
int quadrant(void) { return (f2 & SUBS_F2_QUADR ) >> 3; }
bool initially_frozen(void) { return (f2 & SUBS_F2_FROZEN) != 0; }
bool is_first(void) { return (f2 & SUBS_F2_FIRST ) != 0; }
bool code_only(void) { return (f2 & SUBS_F2_CODE ) != 0; }
unsigned char sort_key; /* subspace sort key */
unsigned char f3;
#define SUBS_F3_REPINI 0x80 /* init values to be replicated to fill subsp len */
#define SUBS_F3_CONTIN 0x40 /* subspace is a continuation */
#define SUBS_F3_ISTSPC 0x20 /* subspace contains TLS */
bool replicate_init(void) { return (f3 & SUBS_F3_REPINI) != 0; }
bool continuation(void) { return (f3 & SUBS_F3_CONTIN) != 0; }
bool is_tspecific(void) { return (f3 & SUBS_F3_ISTSPC) != 0; }
int file_loc_init_value; /* file location or init value */
uint initialization_length; /* length of initialization */
uint subspace_start; /* starting offset */
uint subspace_length; /* total subspace length */
unsigned short reserved2; /* reserved */
unsigned short alignment; /* alignment required */
union name_pt name; /* index of subspace name */
int fixup_request_index; /* index to first fixup */
uint fixup_request_quantity; /* # of fixup requests */
void swap(void);
};
//--------------------------------------------------------------------------
// Symbol Table
//
// The symbol table consists of a sequence of entries described by the structure
// shown below, from <syms.h>. Strings for symbol and qualifier names are contained
// in the symbol strings table, whose structure is identical with the space strings
// table.
struct symbol_dictionary_record
{
unsigned char f1;
#define SYM_F1_HIDDEN 0x80 /* symbol not visible to loader */
#define SYM_F1_SECDEF 0x40 /* secondary def symbol */
#define SYM_F1_TYPE 0x3F /* symbol type */
bool hidden(void) { return (f1 & SYM_F1_HIDDEN) != 0; }
bool secondary_def(void) { return (f1 & SYM_F1_SECDEF) != 0; }
int symbol_type(void) { return (f1 & SYM_F1_TYPE); }
unsigned char f2;
#define SYM_F2_SCOPE 0xF0 /* symbol value */
#define SYM_F2_CHKLVL 0x0E /* type checking level */
#define SYM_F2_MSTQUL 0x01 /* qualifier required */
int symbol_scope(void) { return (f2 & SYM_F2_SCOPE ) >> 4; }
int check_level(void) { return (f2 & SYM_F2_CHKLVL) >> 1; }
bool must_qualify(void) { return (f2 & SYM_F2_MSTQUL) != 0; }
unsigned short f3;
#define SYM_F3_FROZEN 0x8000 /* lock in memory when OS booted */
#define SYM_F3_MEMRES 0x4000 /* lock in memory during exec */
#define SYM_F3_ISCOM 0x2000 /* common block */
#define SYM_F3_DUPCOM 0x1000 /* duplicate data symbols allowed */
#define SYM_F3_XLEAST 0x0C00 /* MPE-only */
#define SYM_F3_ARGREL 0x03FF /* parameter relocation bits */
bool initially_frozen(void) { return (f3 & SYM_F3_FROZEN) != 0; }
bool memory_resident(void) { return (f3 & SYM_F3_MEMRES) != 0; }
bool is_common(void) { return (f3 & SYM_F3_ISCOM ) != 0; }
bool dup_common(void) { return (f3 & SYM_F3_DUPCOM) != 0; }
int xleast(void) { return (f3 & SYM_F3_XLEAST) >>10; }
int arg_reloc(void) { return (f3 & SYM_F3_ARGREL); }
union name_pt name; /* index to symbol name */
union name_pt qualifier_name; /* index to qual name */
uint symbol_info; /* subspace index */
uint symbol_value; /* symbol value */
void swap(void);
};
/* Values for symbol_type */
#define ST_NULL 0 /* unused symbol entry */
#define ST_ABSOLUTE 1 /* non-relocatable symbol */
#define ST_DATA 2 /* initialized data symbol */
#define ST_CODE 3 /* generic code symbol */
#define ST_PRI_PROG 4 /* program entry point */
#define ST_SEC_PROG 5 /* secondary prog entry point*/
#define ST_ENTRY 6 /* procedure entry point */
#define ST_STORAGE 7 /* storage request */
#define ST_STUB 8 /* MPE-only */
#define ST_MODULE 9 /* Pascal module name */
#define ST_SYM_EXT 10 /* symbol extension record */
#define ST_ARG_EXT 11 /* argument extension record */
#define ST_MILLICODE 12 /* millicode entry point */
#define ST_PLABEL 13 /* MPE-only */
#define ST_OCT_DIS 14 /* Used by OCT only--ptr to translated code */
#define ST_MILLI_EXT 15 /* address of external millicode */
#define ST_TSTORAGE 16 /* TLS common symbol */
/* Values for symbol_scope */
#define SS_UNSAT 0 /* unsatisfied reference */
#define SS_EXTERNAL 1 /* import request to external symbol */
#define SS_LOCAL 2 /* local symbol */
#define SS_UNIVERSAL 3 /* global symbol */
// The meaning of the symbol value depends on the symbol type. For the code symbols
// (generic code, program entry points, procedure and millicode entry points), the
// low-order two bits of the symbol value encode the execution privilege level,
// which is not used on HP-UX, but is generally set to 3. The symbol value with
// those bits masked out is the address of the symbol (which is always a multiple
// of 4). For data symbols, the symbol value is simply the address of the symbol.
// For thread local storage symbols (not commons), the symbol value is the thread
// local storage offset in a library or executable file, and is the size of the
// symbol if in a relocatable object file. For storage requests and thread local
// storage commons, the symbol value is the number of bytes requested; the linker
// allocates space for the largest request for each symbol in the $BSS$ or $TBSS$
// subspaces, unless a local or universal symbol is found for that symbol (in which
// case the storage request is treated like an unsatisfied reference).
//
// If a relocatable file is compiled with parameter type checking, extension
// records follow symbols that define and reference procedure entry points and
// global variables. The first extension record, the symbol extension record,
// defines the type of the return value or global variable, and (if a procedure or
// function) the number of parameters and the types of the first three parameters.
// If more parameter type descriptors are needed, one or more argument extension
// records follow, each containing four more descriptors. A check level of 0
// specifies no type checking; no extension records follow. A check level of 1 or
// more specifies checking of the return value or global variable type. A check
// level of 2 or more specifies checking of the number of parameters, and a check
// level of 3 specifies checking the types of each individual parameter. The linker
// performs the requested level of type checking between unsatisfied symbols and
// local or universal symbols as it resolves symbol references.
union arg_descriptor
{
struct
{
uint reserved: 3; /* reserved */
uint packing: 1; /* packing algorithm used */
uint alignment: 4; /* byte alignment */
uint mode: 4; /* type of descriptor and its use */
uint structure: 4; /* structure of symbol */
uint hash: 1; /* set if arg_type is hashed */
int arg_type: 15; /* data type */
} arg_desc;
uint word;
};
struct symbol_extension_record
{
uint type: 8; /* always ST_SYM_EXT */
uint max_num_args: 8; /* max # of parameters */
uint min_num_args: 8; /* min # of parameters */
uint num_args: 8; /* actual # of parameters */
union arg_descriptor symbol_desc; /* symbol type desc. */
union arg_descriptor argument_desc[3]; /* first 3 parameters */
};
struct argument_desc_array
{
uint type: 8; /* always ST_ARG_EXT */
uint reserved: 24; /* reserved */
union arg_descriptor argument_desc[4]; /* next 4 parameters */
};
// The alignment field in arg_descriptor indicates the minimum alignment of the
// data, where a value of n represents 2^n byte alignment. The values for the mode,
// structure, and arg_type (when the data type is not hashed) fields in
// arg_descriptor are given in the following table.
//
// Value mode structure arg_type
// 0 any any any
// 1 value parm scalar void
// 2 reference parm array signed byte
// 3 value-result struct unsigned byte
// 4 name pointer signed short
// 5 variable int32 ptr unsigned short
// 6 function return C string signed int32
// 7 procedure Pascal string unsigned int32
// 8 int32 ref parm procedure signed dbl word
// 9 function unsigned dbl word
// 10 label short real
// 11 real
// 12 int32 real
// 13 short complex
// 14 complex
// 15 int32 complex
// 16 packed decimal
// 17 struct/array
//
//
// For procedure entry points, the parameter relocation bits define the locations
// of the formal parameters and the return value. Normally, the first four words of
// the parameter list are passed in general registers (r26-r23) instead of on the
// stack, and the return value is returned in r29. Floating-point parameters in
// this range are passed instead in floating-point registers (fr4-fr7) and a
// floating-point value is returned in fr4. The parameter relocation bits consist
// of five pairs of bits that describe the first four words of the parameter list
// and the return value. The leftmost pair of bits describes the first parameter
// word, and the rightmost pair of bits describes the return value. The meanings of
// these bits are shown in the following table.
//
// Bits Meaning
// 00 No parameter or return value
// 01 Parameter or return value in general register
// 10 Parameter or return value in floating-point register
// 11 Double-precision floating-point value
//
//
// For double-precision floating-point parameters, the odd-numbered parameter word
// should be marked 11 and the even-numbered parameter word should be marked 10.
// Double-precision return values are simply marked 11.
//
// Every procedure call is tagged with a similar set of bits (see "Relocation
// Information" below), so that the linker can match each call with the
// expectations of the procedure entry point. If the call and entry point mismatch,
// the linker creates a stub that relocates the parameters and return value as
// appropriate.
//--------------------------------------------------------------------------
// DL header
//
// The DL header appears in every shared library and in incomplete executables (program
// files linked with shared libraries--may contain unsatisfied symbols which will be satis-fied
// at run time by the dynamic loader). It is assumed to be at offset 0 in the $TEXT$
// space. It defines fields used by the dynamic loader and various other tools when attach-ing
// the shared libraries at run time. The header contains information on the location of
// the export and import lists, the module table, the linkage tables, as well as the sizes of
// the tables.
struct dl_header
{
int hdr_version; /* header version number */
#define OLD_HDR_VERSION 89060912 // prior to 10.0
#define HDR_VERSION 93092112
int ltptr_value; /* data offset of LT pointer (R19) */
int shlib_list_loc; /* text offset of shlib list */
int shlib_list_count; /* count of items in shlib list */
int import_list_loc; /* text offset of import list */
int import_list_count; /* count of items in import list */
int hash_table_loc; /* text offset of export hash table */
int hash_table_size; /* count of slots in export hash table */
int export_list_loc; /* text offset of export list */
int export_list_count; /* count of items in export list */
int string_table_loc; /* text offset of string table */
int string_table_size; /* length in bytes of string table */
int dreloc_loc; /* text offset of dynamic reloc records */
int dreloc_count; /* number of dynamic relocation records */
int dlt_loc; /* data offset of data linkage table */
int plt_loc; /* data offset of procedure linkage table */
int dlt_count; /* number of dlt entries in linkage table */
int plt_count; /* number of plt entries in linkage table */
short highwater_mark; /* highest version number seen in lib or in shlib list*/
short flags; /* various flags */
#define ELAB_DEFINED 1 /* an elaborator has been defined for this library */
#define INIT_DEFINED 2 /* an initializer has been defined for this library */
#define SHLIB_PATH_ENABLE 4 /* allow search of SHLIB_PATH at runtime */
#define EMBED_PATH_ENABLE 8 /*allow search of embed path at runtime*/
#define SHLIB_PATH_FIRST 16 /* search SHLIB_PATH first */
#define SEARCH_ALL_STORS 32 /* search all shlibs to satisfy STOR import */
#define SHLIB_INTERNAL_NAME 64 /*shlib has an internal name, for library-level versioning support*/
int export_ext_loc; /* text offset of export extension tbl */
int module_loc; /* text offset of module table*/
int module_count; /* number of module entries */
int elaborator; /* import index of elaborator */
int initializer; /* import index of initializer */
int embedded_path; /* index into string table for search path. index must be > 0 to be valid */
int initializer_count; /* count of items in initializer import list*/
int tdsize; /* size of the TSD area */
int fastbind_list_loc; /* text-relative offset of fastbind info */
void swap(void);
};
// Import entry
struct import_entry // parallel with DLT followed by PLT
{
int name; /* offset in string table */
short reserved2; /* unused */
unsigned char type; /* symbol type */
unsigned char flags;
#define IMP_ENTRY_BYPASS 0x80 /* address of code symbol not taken in shlib */
#define IMP_ENTRY_TPREL 0x40 /* new field*/
bool bypassable(void) { return (flags & IMP_ENTRY_BYPASS) != 0; }
bool is_tp_relative(void) { return (flags & IMP_ENTRY_TPREL ) != 0; }
void swap(void);
};
// Export entry
struct misc_info
{
short version; /* months since January, 1990 */
ushort flags;
#define MISC_INFO_RELOC 0x3FF /* parameter relocation bits (5*2) */
uint arg_reloc(void) { return flags & MISC_INFO_RELOC; }
void swap(void);
};
struct export_entry
{
int next; /* index of next export entry in hash chain */
int name; /* offset within string table */
int value; /* offset of symbol (subject to relocation) */
union
{
int size; /* storage request area size in bytes */
struct misc_info misc; /* version, etc. N/A to storage requests */
} info;
unsigned char type; /* symbol type */
unsigned char flags;
#define EXP_ENTRY_TPREL 0x80 /* TLS export*/
bool is_tp_relative(void) { return (flags & EXP_ENTRY_TPREL ) != 0; }
short module_index; /* index of module defining this symbol */
void swap(void);
};
#endif // ifndef HPSOM_HPP

View File

@@ -0,0 +1,14 @@
PROC=hpsom
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)hpsom$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaldr.h \
common.cpp hpsom.cpp hpsom.hpp

212
idasdk76/ldr/idaldr.h Normal file
View File

@@ -0,0 +1,212 @@
#ifndef __IDALDR_H__
#define __IDALDR_H__
#include <ida.hpp>
#include <fpro.h>
#include <idp.hpp>
#include <loader.hpp>
#include <name.hpp>
#include <bytes.hpp>
#include <offset.hpp>
#include <segment.hpp>
#include <segregs.hpp>
#include <fixup.hpp>
#include <entry.hpp>
#include <auto.hpp>
#include <diskio.hpp>
#include <kernwin.hpp>
//----------------------------------
#define CLASS_CODE "CODE"
#define NAME_CODE ".text"
#define CLASS_DATA "DATA"
#define CLASS_CONST "CONST"
#define NAME_DATA ".data"
#define CLASS_BSS "BSS"
#define NAME_BSS ".bss"
#define NAME_EXTERN "extern"
#define NAME_COMMON "common"
#define NAME_ABS "abs"
#define NAME_UNDEF "UNDEF"
#define CLASS_STACK "STACK"
#define CLASS_RES16 "RESOURCE"
#define LDR_NODE "$ IDALDR node for ids loading $"
#define LDR_INFO_NODE "$ IDALDR node for unload $"
//--------------------------------------------------------------------------
template <class T> bool _validate_array_count(
linput_t *li,
T *p_cnt,
size_t elsize,
int64 current_offset=-1,
int64 max_offset=-1)
{
if ( current_offset == -1 )
current_offset = qltell(li);
if ( max_offset == -1 )
max_offset = qlsize(li);
int64 rest = max_offset - current_offset;
T cnt = *p_cnt;
if ( current_offset >= 0 && rest >= 0 )
{
#ifndef __X86__
typedef size_t biggest_t;
#else
typedef ea_t biggest_t;
#endif
if ( is_mul_ok<biggest_t>(elsize, cnt) )
{
biggest_t needed = elsize * cnt;
#ifdef __X86__
if ( needed == size_t(needed) )
#endif
if ( rest >= needed )
return true; // all ok
}
cnt = rest / elsize;
}
else
{
cnt = 0;
}
*p_cnt = cnt;
return false;
}
//--------------------------------------------------------------------------
// Validate a counter taken from the input file. If there are not enough bytes
// in the input file, ask the user if we may continue and fix the counter.
template <class T> void validate_array_count(
linput_t *li,
T *p_cnt,
size_t elsize,
const char *counter_name,
int64 curoff=-1,
int64 maxoff=-1)
{
T old = *p_cnt;
if ( !_validate_array_count(li, p_cnt, elsize, curoff, maxoff) )
{
static const char *const format =
"AUTOHIDE SESSION\n"
"HIDECANCEL\n"
"%s %" FMT_64 "u is incorrect, maximum possible value is %" FMT_64 "u%s";
#ifndef __KERNEL__
if ( ask_yn(ASKBTN_YES,
format,
counter_name,
uint64(old),
uint64(*p_cnt),
". Do you want to continue with the new value?") != ASKBTN_YES )
{
loader_failure(NULL);
}
#else
warning(format, counter_name, uint64(old), uint64(*p_cnt), "");
#endif
}
}
//--------------------------------------------------------------------------
// Validate a counter taken from the input file. If there are not enough bytes
// in the input file, die.
template <class T> void validate_array_count_or_die(
linput_t *li,
T cnt,
size_t elsize,
const char *counter_name,
int64 curoff=-1,
int64 maxoff=-1)
{
if ( !_validate_array_count(li, &cnt, elsize, curoff, maxoff) )
{
static const char *const format =
"%s is incorrect, maximum possible value is %u%s";
#ifndef __KERNEL__
loader_failure(format, counter_name, uint(cnt), "");
#else
error(format, counter_name, uint(cnt), "");
#endif
}
}
//-------------------------------------------------------------------------
// Read a string table in COFF format.
inline bool read_string_table(qstring *out, linput_t *li, qoff64_t filepos=0, bool mf=false)
{
if ( filepos != 0 && qlseek(li, filepos, SEEK_SET) != filepos )
return false;
// read the string table length
uint32 strtsize;
if ( qlread(li, &strtsize, 4) != 4 )
return false;
if ( mf )
strtsize = swap32(strtsize);
// it includes the length field itself, so should be greater than 4
if ( strtsize <= 4 )
return false; // too small table
qlseek(li, -4, SEEK_CUR);
#ifdef LOADER_COMPILE
// Loaders display a message about the problematic size, to inform the user
// and give him a choice.
validate_array_count(li, &strtsize, 1, "String table size");
#else
// Other modules silently fail.
if ( !_validate_array_count(li, &strtsize, 1) )
return false;
#endif
char *stable = (char *)qalloc(strtsize + 1);
if ( stable == NULL )
return false; // out of memory?!
bool ok;
if ( qlread(li, stable, strtsize) == strtsize )
{
stable[strtsize] = '\0';
out->clear();
out->inject(stable, strtsize + 1);
ok = true;
}
else
{
qfree(stable);
ok = false;
}
return ok;
}
//-------------------------------------------------------------------------
inline uchar readchar(linput_t *li)
{
uchar x;
lread(li, &x, sizeof(x));
return x;
}
//-------------------------------------------------------------------------
inline uint16 readshort(linput_t *li)
{
uint16 x;
lread(li, &x, sizeof(x));
return x;
}
//-------------------------------------------------------------------------
inline uint32 readlong(linput_t *li)
{
uint32 x;
lread(li, &x, sizeof(x));
return x;
}
inline uint32 mf_readlong(linput_t *li) { return swap32(readlong(li)); }
inline uint16 mf_readshort(linput_t *li) { return swap16(readshort(li)); }
// each loader must declare and export this symbol:
idaman loader_t ida_module_data LDSC;
#endif // __IDALDR_H__

View File

@@ -0,0 +1,46 @@
//-----------------------------------------------------------------------
bool is_intelomf_file(linput_t *li)
{
uchar magic;
lmh h;
qlseek(li, 0);
if ( qlread(li, &magic, sizeof(magic)) != sizeof(magic)
|| qlread(li, &h, sizeof(h)) != sizeof(h) )
{
return false;
}
int64 fsize = qlsize(li);
return magic == INTELOMF_MAGIC_BYTE
&& h.tot_length < fsize;
}
//-----------------------------------------------------------------------
static int read_pstring(linput_t *li, char *name, int size)
{
char buf[256];
uchar nlen;
lread(li, &nlen, sizeof(nlen));
lread(li, buf, nlen);
buf[nlen] = '\0';
qstrncpy(name, buf, size);
return nlen;
}
//-----------------------------------------------------------------------
static uint32 readdw(const uchar *&ptr, bool wide)
{
uint32 x;
if ( wide )
{
x = *(uint32 *)ptr;
ptr += sizeof(uint32);
}
else
{
x = *(uint16 *)ptr;
ptr += sizeof(uint16);
}
return x;
}

View File

@@ -0,0 +1,439 @@
/*
* Interactive disassembler (IDA).
* Version 4.20
* Copyright (c) 2002 by Ilfak Guilfanov. (ig@datarescue.com)
* ALL RIGHTS RESERVED.
*
* Intel OMF386
*
*/
#include "../idaldr.h"
#include "intelomf.hpp"
#include "common.cpp"
static lmh h;
static ea_t xea;
static sel_t dsel = BADSEL;
//--------------------------------------------------------------------------
static void create32(
sel_t sel,
ea_t start_ea,
ea_t end_ea,
const char *name,
const char *sclass)
{
set_selector(sel, 0);
segment_t s;
s.sel = sel;
s.start_ea = start_ea;
s.end_ea = end_ea;
s.align = saRelByte;
s.comb = sclass != NULL && streq(sclass, "STACK") ? scStack : scPub;
s.bitness = 1; // 32-bit
if ( !add_segm_ex(&s, name, sclass, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure();
}
//-----------------------------------------------------------------------
static void show_segdefs(linput_t *li, uint32 offset, uint32 length)
{
if ( offset == 0 || length == 0 )
return;
qlseek(li, offset);
int n = 0;
for ( int i=0; i < length; )
{
if ( qltell(li) >= qlsize(li) )
BAD_FILE:
loader_failure("Corrupted segmentation info");
segdef s;
const int size = offsetof(segdef, combine_name);
lread(li, &s, size);
int nlen = read_pstring(li, s.combine_name, sizeof(s.combine_name));
i += size + 1 + nlen;
n++;
const char *sname = s.combine_name;
const char *sclas = sname;
if ( strnicmp(sname, "CODE", 4) == 0 )
sclas = "CODE";
if ( strnicmp(sname, "DATA", 4) == 0 )
sclas = "DATA";
if ( strnicmp(sname, "CONST", 5) == 0 )
sclas = "CONST";
if ( stricmp(sname, "STACK") == 0 )
sclas = "STACK";
if ( strchr(sname, ':') != NULL )
continue;
int segsize = s.slimit + 1;
if ( segsize < 0 || qltell(li) >= qlsize(li) )
goto BAD_FILE;
if ( strcmp(sname, "DATA") == 0 )
dsel = n;
set_selector(n, 0);
ea_t ea = free_chunk(inf_get_max_ea(), segsize, -(1<<s.align));
create32(n, ea, ea+segsize, sname, sclas);
}
}
//-----------------------------------------------------------------------
static ea_t getsea(ushort i)
{
segment_t *s = get_segm_by_sel(i & 0xFF);
return s ? s->start_ea : BADADDR;
}
//-----------------------------------------------------------------------
static void show_pubdefs(linput_t *li, uint32 offset, uint32 length)
{
if ( offset == 0 || length == 0 )
return;
qlseek(li, offset);
for ( int i=0; i < length; )
{
pubdef p;
const int size = offsetof(pubdef, sym_name);
if ( qlread(li, &p, size) != size )
loader_failure("Corrupted pubdefs");
int nlen = read_pstring(li, p.sym_name, sizeof(p.sym_name));
i += size + 1 + nlen;
ea_t sea = getsea(p.PUB_segment);
if ( sea != BADADDR )
{
sea += p.PUB_offset;
add_entry(sea, sea, p.sym_name, segtype(sea) == SEG_CODE, AEF_IDBENC);
}
}
}
//-----------------------------------------------------------------------
static void show_extdefs(linput_t *li, uint32 offset, uint32 length)
{
if ( offset == 0 || length == 0 )
return;
qlseek(li, offset);
uchar ss = inf_is_64bit() ? 8 : 4;
inf_set_specsegs(ss);
int16 segsize = ss * h.num_externals;
if ( !is_mul_ok(uint16(ss), uint16(h.num_externals))
|| segsize < 0
|| segsize < h.num_externals )
{
BAD_EXTDEFS:
loader_failure("Corrupted extdefs");
}
sel_t sel = h.num_segs+1;
set_selector(sel, 0);
xea = free_chunk(inf_get_max_ea(), segsize, -15);
create32(sel, xea, xea+segsize, "XTRN", "XTRN");
int n = 0;
for ( int i=0; i < length; )
{
extdef p;
const int size = offsetof(extdef, allocate_len);
if ( qlread(li, &p, size) != size )
goto BAD_EXTDEFS;
p.allocate_len.len_4 = 0;
if ( p.allocate != 0 )
{
ask_for_feedback("extdef.allocate\n");
lread(li, &p.allocate_len.len_4, sizeof(p.allocate_len.len_4));
}
int nlen = read_pstring(li, p.sym_name, sizeof(p.sym_name));
i += size + 1 + nlen;
ea_t a = xea + 4 * n++;
set_name(a, p.sym_name, SN_IDBENC);
if ( p.allocate )
put_dword(a, p.allocate_len.len_4);
}
}
//-----------------------------------------------------------------------
static void read_text(linput_t *li)
{
text txt;
const int size = offsetof(text, segment);
if ( qlread(li, &txt, size) != size || txt.length < 0 )
loader_failure("Corrupted text data");
if ( txt.length != 0 )
{
qoff64_t fptr = qltell(li);
ea_t sea = getsea(txt.txt_IN);
if ( sea != BADADDR )
{
ea_t start = sea + txt.txt_offset;
ea_t end = start + txt.length;
uint64 fsize = qlsize(li);
segment_t *s = getseg(start);
if ( start < sea
|| end < start
|| fptr > fsize
|| fsize-fptr < txt.length
|| s == NULL
|| s->end_ea < end )
{
loader_failure("Corrupted text data");
}
if ( change_storage_type(start, end, STT_VA) != eOk )
INTERR(20060);
file2base(li, fptr, start, end, FILEREG_PATCHABLE);
}
qlseek(li, fptr+txt.length);
}
}
//-----------------------------------------------------------------------
static void read_fixup(linput_t *li)
{
fixup fix;
const int size = offsetof(fixup, fixups);
if ( qlread(li, &fix, size) != size || fix.length < 0 )
loader_failure("Corrupted fixups");
qoff64_t fptr = qltell(li);
ea_t sea = getsea(fix.where_IN);
if ( sea != BADADDR )
{
validate_array_count(li, &fix.length, 1, "Fixup count");
uchar *b = (uchar *)qalloc(fix.length);
if ( b == NULL )
nomem("read_fixup");
lread(li, b, fix.length);
// show_hex(b, fix.length, "\nFIXUP SEG %04X, %04X BYTES, KIND %02X\n",
// fix.where_IN,
// fix.length,
// b[0]);
const uchar *ptr = b;
const uchar *end = b + fix.length;
while ( ptr < end )
{
uint32 where_offset = 0;
uint32 what_offset = 0;
ushort what_in = 9;
bool selfrel = false;
bool isfar = false;
fixup_data_t fd(FIXUP_OFF32);
switch ( *ptr++ )
{
case 0x2C: // GEN
isfar = true;
ask_for_feedback("Untested relocation type");
case 0x24: // GEN
where_offset = readdw(ptr, false);
what_offset = readdw(ptr, false);
what_in = (ushort)readdw(ptr, false);
break;
case 0x2D:
isfar = true;
case 0x25: // INTRA
where_offset = readdw(ptr, false);
what_offset = readdw(ptr, false);
what_in = fix.where_IN;
break;
case 0x2A: // CALL
where_offset = readdw(ptr, false);
what_offset = 0;
what_in = (ushort)readdw(ptr, false);
selfrel = true;
break;
case 0x2E: // OFF32?
isfar = true;
case 0x26:
where_offset = readdw(ptr, false);
what_offset = 0;
what_in = (ushort)readdw(ptr, false);
break;
default:
ask_for_feedback("Unknown relocation type %02X", ptr[-1]);
add_pgm_cmt("!!! Unknown relocation type %02X", ptr[-1]);
break;
}
ea_t source = sea + where_offset;
ea_t target = BADADDR;
switch ( what_in >> 12 )
{
case 0x02: // segments
target = getsea(what_in);
break;
case 0x06: // externs
target = xea + 4 * ((what_in & 0xFFF) - 1);
fd.set_extdef();
break;
default:
ask_for_feedback("Unknown relocation target %04X", what_in);
add_pgm_cmt("!!! Unknown relocation target %04X", what_in);
break;
}
fd.set_target_sel();
if ( !fd.is_extdef() )
{
target += what_offset;
what_offset = 0;
}
fd.off = target - fd.get_base();
fd.displacement = what_offset;
target += what_offset;
if ( selfrel )
target -= source + 4;
fd.set(source);
put_dword(source, target);
if ( isfar )
{
fd.set_type_and_flags(FIXUP_SEG16);
fd.set(source+4);
put_word(source+4, fd.sel);
}
}
qfree(b);
}
qlseek(li, fptr + fix.length);
}
//-----------------------------------------------------------------------
static void read_iterat(linput_t *li)
{
iterat itr;
const int size = offsetof(iterat, text) + offsetof(temp, value);
lread(li, &itr, size);
itr.text.value = NULL;
if ( itr.text.length != 0 )
{
if ( itr.text.length < 0 || itr.it_count < 0 )
BAD_FILE:
loader_failure("Corrupted iterated data");
qoff64_t fptr = qltell(li);
ea_t sea = getsea(itr.it_segment);
if ( sea != BADADDR )
{
uint64 fsize = qlsize(li);
ea_t start = sea + itr.it_offset;
segment_t *s = getseg(start);
if ( start < sea
|| fptr > fsize
|| fsize-fptr < itr.text.length
|| !is_mul_ok(uint32(itr.text.length), uint32(itr.it_count))
|| s == NULL )
{
goto BAD_FILE;
}
uint32 total = itr.text.length * itr.it_count;
ea_t final_end = start + total;
if ( final_end < start || final_end > s->end_ea )
goto BAD_FILE;
if ( change_storage_type(start, final_end, STT_VA) != eOk )
INTERR(20061);
for ( int i=0; i < itr.it_count; i++ )
{
ea_t end = start + itr.text.length;
file2base(li, fptr, start, end, FILEREG_PATCHABLE);
start = end;
}
}
qlseek(li, fptr+itr.text.length);
}
}
//-----------------------------------------------------------------------
static void show_txtfixs(linput_t *li, uint32 offset, uint32 length)
{
if ( offset == 0 || length == 0 )
return;
uint64 fsize = qlsize(li);
uint64 eoff = offset + length;
if ( eoff < offset || offset > fsize || eoff > fsize )
loader_failure("Corrupted fixups");
qlseek(li, offset);
while ( qltell(li) < eoff )
{
char type;
lread(li, &type, sizeof(type));
switch ( type )
{
case 0:
read_text(li);
break;
case 1:
read_fixup(li);
break;
case 2:
read_iterat(li);
break;
default:
ask_for_feedback("txtfix.blk_type == %d!\n", type);
return;
}
}
}
//--------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
if ( is_intelomf_file(li) )
{
*fileformatname = "Intel OMF386";
*processor = "metapc";
return 1;
}
return 0;
}
//--------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
set_processor_type("metapc", SETPROC_LOADER);
qlseek(li, 1);
lread(li, &h, sizeof(h));
toc_p1 toc;
lread(li, &toc, sizeof(toc));
// we add one to skip the magic byte
show_segdefs(li, toc.SEGDEF_loc+1, toc.SEGDEF_len);
show_pubdefs(li, toc.PUBDEF_loc+1, toc.PUBDEF_len);
show_extdefs(li, toc.EXTDEF_loc+1, toc.EXTDEF_len);
show_txtfixs(li, toc.TXTFIX_loc+1, toc.TXTFIX_len);
if ( dsel != BADSEL )
set_default_dataseg(dsel);
add_pgm_cmt("Module: %*.*s", h.mod_name[0], uchar(h.mod_name[0]), &h.mod_name[1]);
}
//--------------------------------------------------------------------------
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,
NULL,
NULL,
};

View File

@@ -0,0 +1,397 @@
/*
* Interactive disassembler (IDA).
* Version 4.20
* Copyright (c) 2002 by Ilfak Guilfanov. (ig@datarescue.com)
* ALL RIGHTS RESERVED.
*
*/
//
// Intel OMF386
//
#ifndef INTELOMF_HPP
#define INTELOMF_HPP
#pragma pack(push, 1)
#define INTELOMF_MAGIC_BYTE 0xB0 // The first byte of the file
// must have this value
//-----------------------------------------------------------------------
// Linkable Module Header
// A linkable object file contains one or more linkable modules
//-----------------------------------------------------------------------
struct lmh /* linkable module header */
{
uint32 tot_length; /* total length of the module on disk in bytes */
int16 num_segs; /* number of SEGDEF sections in the module */
int16 num_gates; /* number of GATDEF sections in the module */
int16 num_publics; /* number of PUBDEF sections in the module */
int16 num_externals; /* number of EXTDEF sections in the module */
char linked; /* linked = 0, if the module was produced by a translator */
char date[8]; /* the creation date, written in the form MM/DD/YY */
char time[8]; /* the creation time, written in the form HH:MM:SS */
char mod_name[41]; /* name of the module, the first char is the string's length */
char creator[41]; /* the name of the program which created the module */
char src_path[46]; /* the path to the source file which produced the module */
char trans_id; /* translator id, mainly for debugger */
char trans_vers[4]; /* translator version (ASCII) */
char OMF_vers; /* OMF version */
};
//-----------------------------------------------------------------------
struct toc_p1 /* Table of contents for first partition */
{
int32 SEGDEF_loc; /* all the following _loc represents location of the first byte */
int32 SEGDEF_len; /* of the section in current module, unit is byte; */
int32 GATDEF_loc; /* all the following _len represents the length of the section */
int32 GATDEF_len; /* also the unit is byte. */
int32 TYPDEF_loc;
int32 TYPDEF_len;
int32 PUBDEF_loc;
int32 PUBDEF_len;
int32 EXTDEF_loc;
int32 EXTDEF_len;
int32 TXTFIX_loc;
int32 TXTFIX_len;
int32 REGINT_loc;
int32 REGINT_len;
int32 next_partition;
int32 reserved;
};
//-----------------------------------------------------------------------
struct segdef /* segment definition */
{
int16 attributes; /* need to be separated into bits to get bitwise info(cf. [1]) */
int32 slimit; /* the length of the segment minus one, in bytes */
int32 dlength; /* the number of data bytes in the segment, only for dsc seg*/
int32 speclength; /* the total number of bytes in the segment */
int16 ldt_position; /* the position in LDT that this segment must occupy */
char align; /* alignment requirements of the segment */
char combine_name[41]; /* first char is the length of the string in byte,
rest is name */
};
//-----------------------------------------------------------------------
// The GATDEF section defines an entry for each gate occurring in the module.
// There is a 1-byte field in the data structure which is used to identify type
// of gate from call gate, task gate, interrupt gate or trap gate. (cf. [1])
struct gatdef /* Gate definition */
{
char privilege; /* privilege of gate */
char present;
char gate_type;
int32 GA_offset; /* gate entry GA consists of GA_offset and GA_segment */
int16 GA_segment;
};
//-----------------------------------------------------------------------
// The TYPDEF section serves two purposes: to allow Relocation and Linkage
// software to check the validity of sharing data across external linkages,
// and to provide type information to debuggers to interpret data correct.
// [2] provides storage size equivalence tables and lists the syntactical
// constructs for high level languages PL/M, PASCAL, FORTRAN and C.
struct leaf
{
char type; /* an 8-bit number defines the type of the leaf */
union /* following are different kind of leaves */
{
char *string;
int16 num_2;
int32 num_4;
uint64 num_8;
int64 s_8;
int16 s_2;
int32 s_4;
} content;
struct leaf *next; /* points to next leaf */
};
struct typdef /* type definition */
{
char linkage; /* is TRUE, if for public-external linkage; is FALSE, if only for debug symbols. */
int16 length; /* the length in bytes of all the leaves in it */
struct leaf leaves; /* all different leaves format */
};
//-----------------------------------------------------------------------
// PUBDEF section contains a list of public names with their general
// addresses for the public symbols. The 2-byte field type_IN specifies
// an internal name for a segment, gate, GDT selector or the special
// CONST$IN. This section serves to define symbols to be exported to
// other modules.
struct pubdef /* public definition */
{
int32 PUB_offset; /* gen addr consists of PUB_offset and PUB_segment */
int16 PUB_segment;
int16 type_IN; /* internal name for the type of the public of symbol */
char wordcount; /* the total # of 16-bit entities of stacked parameters */
char sym_name[256];
};
//-----------------------------------------------------------------------
// EXTDEF section lists all external symbols, which are then referenced
// elsewhere in the module by means of their internal name. The 2-byte
// field seg_IN specifies the segment that is assumed to contain the
// matching public symbol and the 2-byte value of type_IN defines the
// type of the external symbol. (cf. [1])
struct extdef /* external definition */
{
int16 seg_IN; /* internal name of segment having matched public symbol */
int16 type_IN; /* internal name for the type of the external symbol */
char allocate; /* not zero, if R&L needs allocate space for external symbol*/
union
{
int16 len_2;
int32 len_4;
} allocate_len; /* number of bytes needed allocated for the external symbol */
char sym_name[256]; /* the 1st char is length , the rest are name of the symbol*/
};
//-----------------------------------------------------------------------
// text block contains binaries for code segment and data segment.
// These segments are relocatable. Other than that, all the SLD information
// is also implemented in this block by a translator under debug option.
// Segment MODULES in the text block is designed with the purpose of
// providing general information about the current module. Segment MBOLS
// provides entries for each symbol used in the module, including stack
// symbols, local symbols and symbols that are used as procedure or block
// start entries. Segment LINES consists of line offset values, each line
// offset is the byte offset of the start of a line in the code segment.
// Segment SRCLINES consists of line offsets of the source files.
struct mod /* MODULES segment */
{
int16 ldt_sel; /* a selector into the GDT for an LDT which contains the segments in this module */
int32 code_offset; /* code segment GA consists of code_offset and code_IN */
int16 code_IN;
int32 types_offset; /* TYPES GA consists of types_offset and types_IN */
int16 types_IN;
int32 sym_offset; /* MBOLS GA consists of sym_coffset and sym_IN */
int16 sym_IN;
int32 lines_offset; /* LINES GA consists of lines_offset and lines_IN */
int16 lines_IN;
int32 pub_offset; /* PUBLICS GA consists of pub_offset and pub_IN */
int16 pub_IN;
int32 ext_offset; /* EXTERNAL GA consists of ext_offset and ext_IN */
int16 ext_IN;
int32 src_offset; /* SRCLINES GA consists of src_offset and src_IN */
int16 src_IN;
int16 first_line; /* first line number */
char kind; /* 0 value for 286, 1 value for 386 format */
char trans_id; /* same as lmh */
char trans_vers[4]; /* same as lmh */
char *mod_name; /* same as lmh */
};
struct blk /* block start entry */
{
int32 offset; /* offset in code segment */
int32 blk_len; /* block length */
char *blk_name; /* block name, note that first byte is the length of string */
};
struct proc /* procedure start entry */
{
int32 offset; /* offset in code segment */
int16 type_IN; /* internal name of the typdef associated with the proc */
char kind; /* specifying 16-bit or 32-bit */
int32 ebp_offset; /* offset of return address from EBP */
int32 proc_len; /* procedure length */
char *proc_name; /* procedure name, as always, the 1st char is string length */
};
struct sbase /* symbol base entry */
{
int32 offset;
int16 s_IN;
};
struct symbol /* symbol entry */
{
int32 offset;
int16 type_IN;
char *sym_name;
};
struct sym /* MBOLS segment */
{
char kind; /* kind of entries */
union
{
struct blk blk_start; /* block start entry */
struct proc prc_start; /* procedure start entry */
struct sbase sym_base; /* symbol base entry */
struct symbol s_ent; /* symbol entry */
} entry;
struct sym *next;
};
struct line /* LINES segment */
{
int32 offset;
struct lines *next;
};
struct src /* SRCLINES segment */
{
char *src_file; /* source file name */
int16 count;
struct lines *src_line;
struct srclines *next;
};
struct text /* text block */
{
int32 txt_offset; /* gen addr consists of txt_offset and txt_IN */
int16 txt_IN; /* internal segment name */
int32 length; /* the length of the text content, in byte */
union
{
char *code; /* CODE segment */
char *data; /* DATA segment */
struct mod modules; /* MODULES segment */
struct sym symbols; /* MBOLS segment */
struct line lines; /* LINES segment */
struct src srclines;/* SRCLINES segment */
} segment;
};
//-----------------------------------------------------------------------
// block contains information that allows the binder or linker to resolve
// (fix up) and eventually relocate references between object modules.
// The attributes where_IN and where_offset in the following data structures
// make a generalized address specifying the target for the fixup. Similarly,
// the attributes what_IN and what_offset make a generalized address
// specifying the target to which the fixup is to be applied.
// There are four kinds of fixups for Intel linkable object modules.
// They are:
// general fixup,
// intra-segment fixup,
// call fixup
// addition fixup.
// The general fixup and the addition fixup have the same data structure,
// both provide general addresses for where_IN, where_offset, and what_IN,
// what_offset. The intra-segment fixup is equivalent to a general fixup
// with what_IN = where_IN, and the call fixup is also equivalent to a
// general fixup with what_offset = 0. (cf. [1])
struct gen /* for general fixup */
{
char kind; /* specifying the kind of fixup */
union
{
int16 num2;
int32 num4;
} where_offset; /* 2- or 4- byte where_offset */
union
{
int16 num2;
int32 num4;
} what_offset; /* 2- or 4- byte what_offset */
int16 what_IN; /* what_IN & what_offset specify the target for the fixup*/
union fixups *next;
};
struct intra /* for intra-segment fixup */
{
char kind; /* specifying the kind of fixup */
union
{
int16 num2;
int32 num4;
} where_offset; /* 2- or 4- byte where_offset */
union
{
int16 num2;
int32 num4;
} what_offset; /* 2- or 4- byte what_offset */
union fixups *next;
};
struct cal /* for call fixup */
{
char kind; /* specifying the kind of fixup */
union
{
int16 num2;
int32 num4;
} where_offset; /* 2- or 4- byte where-offset */
int16 what_IN;
union fixups *next;
};
struct ad /* for addition fixup */
{
char kind; /* specifying the kind of fixup */
union
{
int16 num2;
int32 num4;
} where_offset; /* specifying the target to which the fixup is to be applied */
union
{
int16 num2;
int32 num4;
} what_offset;
int16 what_IN;
union fixups *next;
};
struct temp /* for the text template in the iterated text block */
{
int32 length; /* the length, in bytes, of a single mem blk to be initialized */
char *value; /* the text or data to be used to initialize any single mem blk*/
};
struct iterat /* for iterated text block */
{
int32 it_offset;
int16 it_segment; /* above two specify a gen addr to put 1st byte of the text */
int32 it_count; /* the # of times the text template is to be repeated */
struct temp text; /* the text template */
};
struct fixup /* fixup block */
{
int16 where_IN; /* specifying the segment to which fixups should be applied*/
int16 length; /* the length in bytes of the fixups */
union
{
struct gen general; /* for general fixup */
struct intra in_seg; /* for intra-segment fixup */
struct cal call_fix; /* call fixup */
struct ad addition; /* addition fixup */
} fixups;
};
//-----------------------------------------------------------------------
// The TXTFIX section consists of intermixed text block, fixup block and
// iterated text block. As one can see, it is the TXTFIX section that
// records the binaries for machine codes, initialized data and
// uninitialized data. TXTFIX section output by a translator under debug
// option will also contain SLD information.
struct txtfix /* text, iterated text and fixup block */
{
char blk_type; /* 0 for text blk; 1 for fixup blk and 2 for iterated text blk */
union
{
struct text text_blk; /* text block */
struct fixup fixup_blk; /* fixup block */
struct iterat it_text_blk; /* iterated text block */
} block;
struct txtfix *next;
};
// The file ends with a checksum byte
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,14 @@
PROC=intelomf
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)intelomf$(O): $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h common.cpp intelomf.cpp \
intelomf.hpp

View File

@@ -0,0 +1,108 @@
/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* E-mail: ig@datarescue.com
*
* Java Virtual Machine pseudo-loader.
* Copyright (c) 1995-2006 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
* ALL RIGHTS RESERVED.
*
*/
/*
L O A D E R for Java-classFile
*/
#include "../idaldr.h"
#include "../../module/java/classfil.hpp"
#include "../../module/java/notify_codes.hpp"
//--------------------------------------------------------------------------
//
// 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 *)
{
uint32 magic;
uint16 min_ver, maj_ver;
if ( lread4bytes(li, &magic, 1) != 0
|| magic != MAGICNUMBER
|| lread2bytes(li, &min_ver, 1) != 0
|| lread2bytes(li, &maj_ver, 1) != 0 )
{
goto BADFMT;
}
uchar jdk;
if ( maj_ver <= JDK_MIN_MAJOR )
{
if ( maj_ver < JDK_MIN_MAJOR )
goto BADFMT;
jdk = maj_ver >= JDK_1_1_MINOR; //-V547 'maj_ver >= 3' is always true
}
else if ( maj_ver > JDK_MAX_MAJOR )
{
BADFMT:
return 0;
}
else
{
jdk = (uchar)(maj_ver - (JDK_MIN_MAJOR-1));
}
fileformatname->sprnt("JavaVM Class File (JDK 1.%u%s)",
jdk,
jdk == 3 ? "/CLDC" : "");
*processor = "java";
return f_LOADER;
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
static void idaapi load_file(linput_t *li, ushort neflag, const char * /*fileformatname*/)
{
set_processor_type("java", SETPROC_LOADER);
if ( !java_module_t::load_file(li, (neflag & NEF_LOPT) != 0) )
INTERR(20047);
}
//----------------------------------------------------------------------
//
// 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,
};

View File

@@ -0,0 +1,15 @@
PROC=javaldr
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)javaldr$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../../module/java/classfil.hpp \
../../module/java/notify_codes.hpp ../idaldr.h \
javaldr.cpp

15
idasdk76/ldr/loader.mak Normal file
View File

@@ -0,0 +1,15 @@
__FUZZ_LOADERS__=1
SRC_PATH = $(IDA)ldr/
BIN_PATH = $(R)loaders/
BASE_OBJS += $(F)$(PROC)$(O)
ifdef __NT__
DLLFLAGS += /BASE:0x140000000
endif
CC_DEFS += LOADER_COMPILE
include ../../module.mak

39
idasdk76/ldr/makefile Normal file
View File

@@ -0,0 +1,39 @@
include ../allmake.mak
GOALS += loaders
.PHONY: $(GOALS)
all: $(GOALS)
#----------------------------------------------------------------------
ALLDIRS += aif
ALLDIRS += amiga
ALLDIRS += aof
ALLDIRS += aout
ALLDIRS += dos
ALLDIRS += dump
ALLDIRS += geos
ALLDIRS += hex
ALLDIRS += intelomf
ALLDIRS += mas
ALLDIRS += nlm
ALLDIRS += pef
ALLDIRS += pilot
ALLDIRS += qnx
ALLDIRS += script_ldrs
ALLDIRS += w32run
ALLDIRS-$(IDAADV) += hpsom
ALLDIRS-$(IDAADV) += javaldr
ALLDIRS-$(IDAADV) += os9
ALLDIRS-$(IDAADV) += rt11
ALLDIRS-$(IDAADV) += snes
ALLDIRS += $(ALLDIRS-1)
loaders: $(ALLDIRS)
#----------------------------------------------------------------------
.PHONY: $(ALLDIRS)
$(ALLDIRS):
$(Q)$(MAKE) -C $@
#----------------------------------------------------------------------
clean::
$(foreach dir,$(ALLDIRS),$(MAKE) -C $(dir) clean;)

13
idasdk76/ldr/mas/makefile Normal file
View File

@@ -0,0 +1,13 @@
PROC=mas
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)mas$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h mas.cpp mas.hpp

407
idasdk76/ldr/mas/mas.cpp Normal file
View File

@@ -0,0 +1,407 @@
// Loader for the Macro-assembler-related binary format
#include "../idaldr.h"
#include "mas.hpp"
// undefine this to print some debugging information
// in the IDA console.
//#define DEBUG
//-----------------------------------------------------------------------------
struct gas_family
{
uchar code;
const char *processor; //lint !e958 padding is required to align members
};
static const struct gas_family families[] =
{
{ 0x01, "68k" },
// 0x03 : M*Core
{ 0x05, "ppc" },
{ 0x09, "dsp56k" },
{ 0x11, "m740" },
// 0x12 : MELPS-4500
// 0x13 : M16
// 0x14 : M16C
// 0x15 : F2MC8L
{ 0x16, "f2mc16l" },
{ 0x19, "m7700" },
// 0x21 : MCS-48
// 0x25 : SYM53C8xx
// 0x29 : 29xxx
{ 0x2A, "i960b" }, // little or big endian ????
// 0x31 : MCS-51
{ 0x32, "st9" },
{ 0x33, "st7" },
// 0x38 : 1802/1805
// 0x39 : MCS-96/196/296
// 0x3A : 8X30x
{ 0x3B, "avr" },
// 0x3C : XA
// 0x3F : 4004/4040
{ 0x41, "8085" },
{ 0x42, "8086" },
{ 0x47, "tms320c6" },
// 0x48 : TMS9900
// 0x49 : TMS370xxx
// 0x4A : MSP430
{ 0x4B, "tms32054" },
{ 0x4C, "c166" },
{ 0x51, "z80" },
// 0x52 : TLCS-900
// 0x53 : TLCS-90
// 0x54 : TLCS-870
// 0x55 : TLCS-47
// 0x56 : TLCS-9000
{ 0x61, "6800" },
{ 0x62, "6805" },
{ 0x63, "6809" },
// 0x64 : 6804
// 0x65 : 68HC16
// 0x66 : 68HC12
// 0x67 : ACE
{ 0x68, "h8300" },
{ 0x69, "h8500" },
// 0x6C : SH7000
// 0x6C : SC14xxx
// 0x6C : SC/MP
// 0x6C : COP8
{ 0x70, "pic16cxx" },
{ 0x71, "pic16cxx" },
// 0x72 : PIC17C4x
// 0x73 : TMS-7000
// 0x74 : TSM3201x
// 0x75 : TSM320C2x
// 0x76 : TSM320C3x
{ 0x77, "tms320c2" },
// 0x78 : ST6uPD772
{ 0x79, "z8" }
// 0x7A : uPD78(C)10
// 0x7B : 75K0
// 0x7C : 78K0
// 0x7D : uPD7720
// 0x7E : uPD7725
// 0x7F : uPD77230
};
static char creator[MAXSTR]; // program name which created the binary
static int entry_point; // address of the entry point
static const char *set_proc = NULL;
//-----------------------------------------------------------------------------
// output an error and exit loader.
AS_PRINTF(1, 2) NORETURN static void mas_error(const char *format, ...)
{
char b[MAXSTR];
va_list va;
va_start(va, format);
qvsnprintf(b, sizeof(b), format, va);
va_end(va);
loader_failure("mas loader critical error: %s", b);
}
//-----------------------------------------------------------------------------
// set the current processor type according to "cpu_type".
static bool mas_set_cpu(uchar cpu_type)
{
for ( int i = 0; i < qnumber(families); i++ )
{
if ( families[i].code != cpu_type )
continue;
const char *proc = families[i].processor;
if ( set_proc != NULL && !streq(proc, set_proc) )
mas_error("only one processor record is allowed");
set_proc = proc;
set_processor_type(proc, SETPROC_LOADER);
#if defined(DEBUG)
msg("MAS: detected processor %s\n", proc);
#endif
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// return a segment name according to its "segment_type".
static const char *mas_get_segname(uchar segment_type)
{
switch ( segment_type )
{
case 0x00: return "UNDEFINED";
case 0x01: return "CODE";
case 0x02: return "DATA";
case 0x03: return "IDATA";
case 0x04: return "XDATA";
case 0x05: return "YDATA";
case 0x06: return "BDATA";
case 0x07: return "IO";
case 0x08: return "REG";
case 0x09: return "ROMDATA";
}
return NULL;
}
//-----------------------------------------------------------------------------
// write comments.
static void mas_write_comments(void)
{
create_filename_cmt();
char entry_point_str[20];
if ( entry_point == -1 )
qstrncpy(entry_point_str, "NOT DETECTED", sizeof(entry_point_str));
else
qsnprintf(entry_point_str, sizeof(entry_point_str), "0x%X", entry_point);
// write name of the creator program
add_pgm_cmt("Creator program : %s", creator);
// write address of the entry point
add_pgm_cmt("Entry point : %s", entry_point_str);
}
//-----------------------------------------------------------------------------
// detect macro assembler files using the start sequence.
static int idaapi accept_file(
qstring *fileformatname,
qstring *, // too difficult to determine the processor
linput_t *li,
const char *)
{
// read the first word
uint16 word = 0;
if ( qlread(li, &word, 2) != 2 )
return 0;
#if defined(DEBUG)
msg("MAS: 2 first bytes : 0x%X\n", word);
#endif
// first word must match the start_sequence
if ( word != START_SEQUENCE )
return 0;
*fileformatname = "Macro Assembler by Alfred Arnold";
#if defined(DEBUG)
msg("MAS: detected mas binary file !\n");
#endif
return 1;
}
//-----------------------------------------------------------------------------
static void load_bytes(linput_t *li, ea_t ea, asize_t size, const char *segname)
{
// validate the segment size
ea_t end = ea + size;
qoff64_t curpos = qltell(li);
qoff64_t endpos = curpos + size;
if ( ea == BADADDR || end < ea || endpos < curpos || endpos > qlsize(li) )
mas_error("wrong or too big segment %a..%a", ea, end);
// send code in the database
file2base(li, curpos, ea, end, FILEREG_PATCHABLE);
// set selector
sel_t selector = allocate_selector(0);
// create data segment
add_segm(selector, ea, end, segname, segname, ADDSEG_SPARSE);
}
//-----------------------------------------------------------------------------
static void check_target_processor()
{
if ( PH.id == -1 )
loader_failure("Failed to determine the target processor, please specify it manually");
}
//-----------------------------------------------------------------------------
// process a file record according to its "record_type".
// return true if there is no more records to process.
static bool process_record(linput_t *li, const uchar record_type, bool load)
{
bool finished = false;
switch ( record_type )
{
// A record with a header byte of $81 is a record that may contain code or
// data from arbitrary segments.
//
// header : 1 byte
// segment : 1 byte
// gran : 1 byte
// start_addr : 4 bytes (entry point)
// length : 2 bytes
// data : length bytes
case 0x81:
{
mas_header_t header;
memset(&header, 0, sizeof(header));
// read the header
if ( qlread(li, &header, sizeof(header)) != sizeof(header) )
mas_error("unable to read header (%" FMT_Z " bytes)", sizeof(header));
// granularities that differ from 1 are rare and mostly appear
// in DSP CPU's that are not designed for byte processing.
if ( header.gran != 1 )
mas_error("unsupported granularity (%d)", header.gran);
// set processor
if ( !mas_set_cpu(header.header) )
mas_error("processor type '0x%X' is currently unsupported", header.header);
if ( !load ) // we have the processor, nothing else to do
{
finished = true;
break;
}
// get segment name
const char *segname = mas_get_segname(header.segment);
if ( segname == NULL )
mas_error("invalid segment '0x%X'", header.segment);
#if defined(DEBUG)
msg("MAS: ready to read %d bytes (0x%X -> 0x%X)\n",
header.length, header.start_addr, header.start_addr + header.length);
#endif
load_bytes(li, header.start_addr, header.length, segname);
}
break;
// The last record in a file bears the Header $00 and has only a string as
// data field. This string does not have an explicit length specification;
// its end is equal to the file's end.
//
// The string contains only the name of the program that created the file
// and has no further meaning.
//
// creator : x bytes
case 0x00:
{
uint32 length = qlsize(li) - qltell(li);
#if defined(DEBUG)
msg("MAS: creator length : %ld bytes\n", length);
#endif
if ( length >= sizeof(creator) )
mas_error("creator length is too large (%u >= %" FMT_Z,
length, sizeof(creator));
ssize_t tmp = qlread(li, creator, length);
if ( tmp != length )
mas_error("unable to read creator string (i read %" FMT_ZS")", tmp);
creator[length] = '\0';
}
finished = true;
break;
// entry_point : 4 bytes
case 0x80:
{
if ( qlread(li, &entry_point, 4) != 4 )
mas_error("unable to read entry_point");
if ( load )
{
#if defined(DEBUG)
msg("MAS: detected entry point : 0x%X\n", entry_point);
#endif
inf_set_start_ip(entry_point); // entry point
segment_t *s = getseg(entry_point);
inf_set_start_cs(s ? s->sel : 0); // selector of code
}
}
break;
default:
// start_addr : 4 bytes
// length : 2 bytes
// data : length bytes
if ( record_type >= 0x01 && record_type <= 0x7F )
{
check_target_processor();
struct
{
int start_addr;
short length;
} header;
memset(&header, 0, sizeof(header));
// read the header
if ( qlread(li, &header, sizeof(header)) != sizeof(header) )
mas_error("unable to read header (%" FMT_Z " bytes)", sizeof(header));
if ( load )
load_bytes(li, header.start_addr, header.length, "DATA");
else
qlseek(li, qltell(li)+header.length);
}
else
{
mas_error("invalid record type '0x%X'\n", record_type);
}
}
return finished;
}
//-----------------------------------------------------------------------------
// load a macro assembler file in IDA.
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
// already read the 2 first bytes
qlseek(li, 2);
// initialize static variables
qstrncpy(creator, "UNKNOWN", sizeof(creator));
entry_point = -1;
bool finished = false;
while ( !finished )
{
uchar record_type = 0;
// read the record type
if ( qlread(li, &record_type, 1) != 1 )
mas_error("unable to read the record type");
finished = process_record(li, record_type, true);
}
#if defined(DEBUG)
msg("MAS: reading complete\n");
#endif
check_target_processor();
mas_write_comments();
}
//-----------------------------------------------------------------------------
// 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,
};

19
idasdk76/ldr/mas/mas.hpp Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __MAS_HPP_
#define __MAS_HPP_
#pragma pack(push, 1)
#define START_SEQUENCE 0x1489
struct mas_header_t
{
uchar header;
uchar segment;
uchar gran;
int start_addr;
short length;
};
#pragma pack(pop)
#endif /* __MAS_HPP_ */

14
idasdk76/ldr/nlm/makefile Normal file
View File

@@ -0,0 +1,14 @@
PROC=nlm
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)nlm$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp ../idaldr.h \
nlm.cpp nlm.h

1023
idasdk76/ldr/nlm/nlm.cpp Normal file

File diff suppressed because it is too large Load Diff

43
idasdk76/ldr/nlm/nlm.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef __NLM_H__
#define __NLM_H__
#pragma pack(push, 1)
struct nlmexe_t
{
#define NLM_MAGIC_SIZE 0x18
char magic[NLM_MAGIC_SIZE];
#define NLM_MAGIC "NetWare Loadable Module\x1A"
uint32 version; // file Version
#define NLM_COMPRESSED 0x00000080L // compressed NLM file
char fnamelen; // modulename length
char fname[12+1];
uint32 codeoff; // offset to code segment
uint32 codelen; // length of code segment
uint32 dataoff; // offset to data segment
uint32 datalen; // length of data segment
uint32 bssSize; // Unitialized data size
uint32 custoff; // help off
uint32 custlen; // help length
uint32 autoliboff; // autoload library offset
uint32 autolibnum; // number of autoload libraries
uint32 fixupoff; // offset to fixups
uint32 fixupnum; // number of fixups
uint32 impoff; // offset to imported names
uint32 impnum; // number of imported names
uint32 expoff; // offset to exported names
uint32 expnum; // number of exported names
uint32 puboff; // offset to public names
uint32 pubnum; // number of public names
uint32 startIP; // entry point?
uint32 endIP; // terminate NLM
uint32 auxIP; // additional entry point
uint32 modType; // Module type
uint32 flags; // Module flags
};
#define NLM_MODNAMOFF 0x82 //sizeof
CASSERT(NLM_MODNAMOFF == sizeof(nlmexe_t));
#pragma pack(pop)
#endif

14
idasdk76/ldr/os9/makefile Normal file
View File

@@ -0,0 +1,14 @@
PROC=os9
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)os9$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../../module/mc68xx/notify_codes.hpp \
../idaldr.h os9.cpp os9.hpp

332
idasdk76/ldr/os9/os9.cpp Normal file
View File

@@ -0,0 +1,332 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov <ig@datarescue.com>
* ALL RIGHTS RESERVED.
*
* This file is able to load:
* - OS9 object files
* - FLEX STX files
* for 6809
*
*/
#include "../idaldr.h"
#include "../../module/mc68xx/notify_codes.hpp"
#include "os9.hpp"
//----------------------------------------------------------------------
static void swap_os9_header(os9_header_t &h)
{
#if __MF__
qnotused(h);
#else
h.magic = swap16(h.magic);
h.size = swap16(h.size);
h.name = swap16(h.name);
h.start = swap16(h.start);
h.storage = swap16(h.storage);
#endif
}
//----------------------------------------------------------------------
// calc header parity
static uchar calc_os9_parity(os9_header_t &h)
{
uchar *ptr = (uchar *)&h;
int parity = 0;
for ( int i=0; i < 8; i++ )
parity ^= *ptr++;
return (uchar)~parity;
}
//----------------------------------------------------------------------
static const char object_name[] = "OS9 object file for 6809";
static bool is_os9_object_file(qstring *fileformatname, linput_t *li)
{
os9_header_t h;
qlseek(li, 0);
if ( qlread(li,&h,sizeof(os9_header_t)) != sizeof(os9_header_t) )
return false;
swap_os9_header(h);
if ( h.magic == OS9_MAGIC
&& calc_os9_parity(h) == h.parity
&& (h.type_lang & OS9_LANG) == OS9_LANG_OBJ )
{
*fileformatname = object_name;
return true;
}
return false;
}
//----------------------------------------------------------------------
static const char flex_name[] = "FLEX STX file";
static bool is_os9_flex_file(qstring *fileformatname, linput_t *li)
{
qlseek(li, 0);
int64 fsize = qlsize(li);
int nrec2 = 0;
qoff64_t fpos = 0;
while ( 1 )
{
if ( fpos > fsize )
return false;
qlseek(li, fpos, SEEK_SET);
int c = qlgetc(li);
if ( c == EOF )
break;
if ( fpos == 0 && c != 0x2 )
return false; // the first byte must be 0x2
switch ( c )
{
case 0:
fpos++;
break;
case 0x2:
{
c = qlgetc(li);
int adr = (c<<8) | qlgetc(li);
if ( adr == EOF )
return false;
c = qlgetc(li); // number of bytes
if ( c == 0 || c == EOF )
return false;
fpos += c+4;
nrec2++;
}
break;
case 0x16:
fpos += 3;
break;
default:
return false;
}
}
if ( nrec2 == 0 )
return false;
*fileformatname = flex_name;
return true;
}
//----------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
if ( is_os9_object_file(fileformatname, li) // OS9
|| is_os9_flex_file(fileformatname, li) ) // FLEX
{
*processor = "6809";
return 1;
}
return 0;
}
//----------------------------------------------------------------------
static const char *get_os9_type_name(uchar type)
{
switch ( type )
{
case OS9_TYPE_ILL: return "illegal";
case OS9_TYPE_PRG: return "Program module";
case OS9_TYPE_SUB: return "Subroutine module";
case OS9_TYPE_MUL: return "Multi-Module (for future use)";
case OS9_TYPE_DAT: return "Data module";
case OS9_TYPE_SYS: return "OS-9 System Module";
case OS9_TYPE_FIL: return "OS-9 File Manager Module";
case OS9_TYPE_DRV: return "OS-9 Device Driver Module";
case OS9_TYPE_DDM: return "OS-9 Device Descriptor Module";
default: return "unknown";
}
}
//----------------------------------------------------------------------
static const char *get_os9_lang_name(uchar lang)
{
switch ( lang )
{
case OS9_LANG_DAT: return "Data (not executable)";
case OS9_LANG_OBJ: return "6809 object code";
case OS9_LANG_BAS: return "BASIC09 I-Code";
case OS9_LANG_PAS: return "PASCAL P-Code";
case OS9_LANG_C: return "C I-Code";
case OS9_LANG_CBL: return "COBOL I-Code";
case OS9_LANG_FTN: return "FORTRAN I-Code";
default: return "unknown";
}
}
//--------------------------------------------------------------------------
static void create32(
sel_t sel,
ea_t start_ea,
ea_t end_ea,
const char *name,
const char *classname)
{
set_selector(sel, 0);
segment_t s;
s.sel = sel;
s.start_ea = start_ea;
s.end_ea = end_ea;
s.align = saRelByte;
s.comb = scPub;
if ( !add_segm_ex(&s, name, classname, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure();
}
//----------------------------------------------------------------------
#define LOADING_OFFSET 0x1000
void load_obj_file(linput_t *li)
{
os9_header_t h;
qlseek(li, 0);
lread(li, &h, sizeof(os9_header_t));
swap_os9_header(h);
set_processor_type("6809", SETPROC_LOADER);
set_target_assembler(5);
uint64 fsize = qlsize(li);
qoff64_t fpos = qltell(li);
uint64 rest = fsize - fpos;
ea_t start = to_ea(inf_get_baseaddr(), LOADING_OFFSET);
ea_t end = start + h.size;
if ( end <= start || fsize < fpos || fsize-fpos < rest )
loader_failure("Corrupted input file");
file2base(li, 0, start, end, FILEREG_PATCHABLE);
create32(inf_get_baseaddr(), start, start + h.size, "TEXT", "CODE");
create_filename_cmt();
ea_t ea = start;
set_name(ea, "magic", SN_IDBENC);
create_word(ea, 2);
op_num(ea,0);
ea += 2;
set_name(ea, "size", SN_IDBENC);
create_word(ea, 2);
op_num(ea,0);
ea += 2;
set_name(ea, "name", SN_IDBENC);
create_word(ea, 2);
if ( h.name < h.size )
op_plain_offset(ea,0, start);
ea += 2;
set_name(ea, "type_lang", SN_IDBENC);
create_byte(ea, 1);
op_num(ea,0);
append_cmt(ea, get_os9_type_name(h.type_lang & OS9_TYPE), 0);
append_cmt(ea, get_os9_lang_name(h.type_lang & OS9_LANG), 0);
ea += 1;
set_name(ea, "attrib", SN_IDBENC);
create_byte(ea, 1);
op_num(ea,0);
if ( h.attrib & OS9_SHARED )
append_cmt(ea, "Shared module", 0);
ea += 1;
set_name(ea, "parity", SN_IDBENC);
create_byte(ea, 1);
op_num(ea,0);
ea += 1;
set_name(ea, "start_ptr", SN_IDBENC);
create_word(ea, 2);
op_plain_offset(ea,0, start);
ea += 2;
set_name(ea, "storage", SN_IDBENC);
create_word(ea, 2); op_num(ea,0);
inf_set_start_ip(LOADING_OFFSET + h.start);
inf_set_start_cs(inf_get_baseaddr());
}
//----------------------------------------------------------------------
void load_flex_file(linput_t *li)
{
qlseek(li, 0);
set_processor_type("6809", SETPROC_LOADER);
set_target_assembler(5);
ea_t bottom = BADADDR;
ea_t top = 0;
while ( 1 )
{
int c = qlgetc(li);
if ( c == EOF )
break;
switch ( c )
{
case 0:
break;
case 0x2:
{
c = qlgetc(li);
int adr = (c<<8) | qlgetc(li);
c = qlgetc(li); // number of bytes
ea_t start = to_ea(inf_get_baseaddr(), adr);
ea_t end = start + c;
file2base(li, qltell(li), start, end, FILEREG_PATCHABLE);
if ( bottom > start )
bottom = start;
if ( top < end )
top = end;
}
break;
case 0x16:
c = qlgetc(li);
inf_set_start_ip(int(c<<8) | qlgetc(li));
inf_set_start_cs(inf_get_baseaddr());
break;
default:
INTERR(20065);
}
}
create32(inf_get_baseaddr(), bottom, top, "TEXT", "CODE");
create_filename_cmt();
mc68xx_module_t::notify_flex_format(); // tell the module that the file has FLEX format
}
//----------------------------------------------------------------------
void idaapi load_file(linput_t *li,ushort /*_neflags*/,const char *fileformatname)
{
if ( strcmp(fileformatname, object_name) == 0 )
load_obj_file(li);
else
load_flex_file(li);
}
//--------------------------------------------------------------------------
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,
};

78
idasdk76/ldr/os9/os9.hpp Normal file
View File

@@ -0,0 +1,78 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-99 by Ilfak Guilfanov <ig@datarescue.com>
* ALL RIGHTS RESERVED.
*
* This file describes two different formats:
* - OS9 object files
* - FLEX STX files
*
*/
#ifndef _OS9_HPP
#define _OS9_HPP
#pragma pack(push, 1)
//----------------------------------------------------------------------
//
// OS9 object code files have the following header at the start:
//
struct os9_header_t
{
ushort magic; // $00 2 Sync Bytes (always $87CD)
#define OS9_MAGIC 0x87CD
ushort size; // $02 2 Module Size (bytes)
ushort name; // $04 2 Module Name Offset
uchar type_lang; // $06 1 Type/Language
#define OS9_TYPE 0xF0 // Type
#define OS9_TYPE_ILL 0x00 // this one is illegal
#define OS9_TYPE_PRG 0x10 // Program module
#define OS9_TYPE_SUB 0x20 // Subroutine module
#define OS9_TYPE_MUL 0x30 // Multi-Module (for future use)
#define OS9_TYPE_DAT 0x40 // Data module
//#define OS9_$50-$B0 User defined
#define OS9_TYPE_SYS 0xC0 // OS-9 System Module
#define OS9_TYPE_FIL 0xD0 // OS-9 File Manager Module
#define OS9_TYPE_DRV 0xE0 // OS-9 Device Driver Module
#define OS9_TYPE_DDM 0xF0 // OS-9 Device Descriptor Module
#define OS9_LANG 0x0F // Language
#define OS9_LANG_DAT 0x00 // Data (not executable)
#define OS9_LANG_OBJ 0x01 // 6809 object code <- this is the only one to disassemble
#define OS9_LANG_BAS 0x02 // BASIC09 I-Code
#define OS9_LANG_PAS 0x03 // PASCAL P-Code
#define OS9_LANG_C 0x04 // C I-Code
#define OS9_LANG_CBL 0x05 // COBOL I-Code
#define OS9_LANG_FTN 0x06 // FORTRAN I-Code
uchar attrib; // $07 1 Attrib/Revision
#define OS9_REVSN 0x0F // Module revision
// The higher the number the more current
// the revision. When modules are loaded by
// the OS, if there is already module loaded
// with the same name, type, language, etc.
// the one with the highest revision will be used.
#define OS9_SHARED 0x80 // The module is reentrant and sharable
uchar parity; // $08 1 header parity byte
// It is the ones complement of the vertical
// parity (exclusive OR) of the previous
// eight bytes.
ushort start; // $09 2 Execution Offset
ushort storage; // $0B 2 Permenant Storage Requirements
// $0D Module Body
};
//----------------------------------------------------------------------
// Flex files have the following format:
// 0x02 0xYY 0xYY 0xZZ ...........
// where 0xYY is a 16 bit address, and 0xZZ is the byte count (0x00-0xFF).
// The reason for this is that the user could assign a program to be
// loaded and executed from anywhere in memory. So each executable file
// had the loading info in the file.
// 0x16 0xYY 0xYY
// The starting address of the program was specified in the binary files
// with a 0x16 0xYY 0xYY record. The 0xYY was the transfer address to be
// JMP'ed to when the program finished loading. This is the way FLEX and
// SK*DOS worked for the 6800, 6809 and 68K.
#pragma pack(pop)
#endif // define _OS9_HPP

701
idasdk76/ldr/pe/common.cpp Normal file
View File

@@ -0,0 +1,701 @@
#include <auto.hpp>
#include "common.h"
#include "../idaldr.h"
//------------------------------------------------------------------------
#ifdef LOADER_SOURCE // building a loader?
AS_PRINTF(1, 2) inline void pe_failure(const char *format, ...)
{
va_list va;
va_start(va, format);
qstring question("AUTOHIDE REGISTRY\n");
question.cat_vsprnt(format, va);
question.append("\nDo you wish to continue?");
if ( ask_yn(ASKBTN_YES, "%s", question.c_str()) != ASKBTN_YES )
{
loader_failure(NULL);
}
va_end(va);
}
#else
// for other purposes: just print the error message and continue
AS_PRINTF(1, 2) inline void pe_failure(const char *format, ...)
{
va_list va;
va_start(va, format);
qvprintf(format, va);
qprintf("\n");
va_end(va);
}
#endif
//------------------------------------------------------------------------
inline bool pe64_to_pe(peheader_t &pe, const peheader64_t &pe64, bool silent, bool zero_bad_data)
{
bool ok = true;
switch ( pe64.magic )
{
default:
if ( !silent )
{
ask_for_feedback("The input file has non-standard magic number (%x)",
pe64.magic);
}
ok = false;
/* no break */
case MAGIC_P32:
case MAGIC_ROM:
case 0:
memcpy(&pe, &pe64, sizeof(pe));
break;
case MAGIC_P32_PLUS:
// Copy the constant part
memcpy(&pe, &pe64, offsetof(peheader_t, stackres));
// Copy after the changed part
memcpy(&pe.loaderflags, &pe64.loaderflags,
sizeof(pe) - qoffsetof(peheader_t, loaderflags));
// Truncate the 64bit to 32bit
pe.stackres = low(pe64.stackres);
pe.stackcom = low(pe64.stackcom);
pe.heapres = low(pe64.heapres);
pe.heapcom = low(pe64.heapcom);
break;
}
// Do various checks
if ( !pe.is_efi()
&& (pe.objalign < pe.filealign
|| pe.filealign != 0 && (pe.filealign & (pe.filealign-1)) != 0 // check for power of 2
|| pe.objalign != 0 && (pe.objalign & (pe.objalign -1)) != 0) ) // check for power of 2
{
if ( !silent )
pe_failure("Invalid file: bad alignment value specified (section alignment: %08X, file alignment: %08X)", pe.objalign, pe.filealign);
}
if ( pe.imagesize > 0x77000000 || pe.imagesize < pe.allhdrsize )
{
if ( !silent )
pe_failure("Invalid file: bad ImageSize value %x", pe.imagesize);
}
if ( zero_bad_data )
{
if ( pe.nrvas != 0 && pe.nrvas < total_rvatab_count )
memset(&pe.expdir + pe.nrvas, 0, total_rvatab_size - pe.nrvas * sizeof(petab_t));
size_t fullhdrsize = pe.is_pe_plus() ? sizeof(pe64) : sizeof(pe);
size_t sectblstart = pe.first_section_pos(0);
// clear items covered by section table
if ( sectblstart < fullhdrsize
&& total_rvatab_size < fullhdrsize
&& sectblstart >= fullhdrsize - total_rvatab_size )
{
if ( !silent )
msg("Warning: image directories are covered by the section table, some entries will be ignored\n");
size_t clearcount = (fullhdrsize - sectblstart + sizeof(petab_t) -1 )/ sizeof(petab_t);
memset(&pe.expdir + (total_rvatab_count- clearcount), 0, clearcount * sizeof(petab_t));
}
}
return ok;
}
//------------------------------------------------------------------------
inline bool te_to_pe(peheader_t &pe, const teheader_t &te)
{
bool ok = true;
memset(&pe, 0, sizeof(pe));
pe.signature = te.signature;
pe.machine = te.machine;
pe.nobjs = te.nobjs;
pe.magic = pe.is_64bit_cpu() ? MAGIC_P32_PLUS : MAGIC_P32;
pe.entry = te.entry;
pe.text_start = te.text_start;
pe.allhdrsize = te.text_start + te.te_adjust();
if ( pe.is_pe_plus() )
pe.imagebase64 = te.imagebase64;
else
pe.imagebase32 = te.imagebase64;
pe.subsys = te.subsys;
pe.reltab = te.reltab;
pe.debdir = te.debdir;
pe.objalign = 1;
pe.filealign = 1;
return ok;
}
//------------------------------------------------------------------------
inline bool pe_loader_t::read_header(linput_t *li, off_t _peoff, bool silent, bool zero_bad_data)
{
peoff = _peoff;
qlseek(li, peoff);
memset(&pe64, 0, sizeof(pe64));
qlseek(li, peoff);
size_t size = qlread(li, &pe64, sizeof(pe64));
size_t minsize = pe64.magic == MAGIC_P32_PLUS
? qoffsetof(peheader64_t, subsys)
: qoffsetof(peheader_t, subsys);
bool ok = size > minsize
&& size <= sizeof(pe64)
&& (pe64.signature == PEEXE_ID || pe64.signature == BPEEXE_ID || pe64.signature == PLEXE_ID)
&& pe64_to_pe(pe, pe64, silent, zero_bad_data);
if ( ok )
{
// initialize imagebase for loading
set_imagebase((ea_t)pe.imagebase());
}
return ok;
}
//------------------------------------------------------------------------
inline bool pe_loader_t::read_header(linput_t *li, bool silent, bool zero_bad_data)
{
uint32 hdroff = 0;
link_ulink = false;
qlseek(li, hdroff);
if ( qlread(li, &exe, sizeof(exe)) != sizeof(exe) )
return false;
if ( exe.exe_ident != PEEXE_ID )
{
if ( exe.exe_ident == TEEXE_ID )
{
qlseek(li, hdroff);
if ( qlread(li, &te, sizeof(te)) != sizeof(te) )
return false;
bool ok = te_to_pe(pe, te);
if ( ok )
{
// initialize imagebase for loading
set_imagebase((ea_t)pe.imagebase());
peoff = hdroff;
}
return ok;
}
if ( exe.exe_ident == EXE_ID || exe.exe_ident == EXE_ID2 )
{
char tmp[8];
if ( qlread(li, tmp, sizeof(tmp)) == sizeof(tmp)
&& memcmp(tmp, "UniLink", 8) == 0 )
{
link_ulink = true;
}
qlseek(li, PE_PTROFF);
if ( qlread(li, &hdroff, sizeof(hdroff)) != sizeof(hdroff) )
return false;
}
}
return read_header(li, hdroff, silent, zero_bad_data);
}
//------------------------------------------------------------------------
inline bool pe_loader_t::vseek(linput_t *li, uint32 rva)
{
ea_t fpos = get_linput_type(li) == LINPUT_PROCMEM ? rva : map_ea(rva);
if ( fpos != BADADDR )
{
qlseek(li, fpos);
return true;
}
qlseek(li, rva, SEEK_SET);
return false;
}
//------------------------------------------------------------------------
inline char *pe_loader_t::asciiz(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok)
{
vseek(li, rva);
buf[0] = '\0';
char *ret = qlgetz(li, -1, buf, bufsize);
*ok = buf[0] != '\0';
return ret;
}
//------------------------------------------------------------------------
// same as asciiz() but don't set ok to false for successfully read empty strings
inline char *pe_loader_t::asciiz2(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok)
{
vseek(li, rva);
buf[0] = '\0';
// do not use qlgetz() here because we won't distinguish empty strings from read errors
ssize_t readsize = qlread(li, buf, bufsize-1);
if ( readsize < 0 || readsize >= bufsize )
*ok = false;
else
buf[readsize] = '\0';
return buf;
}
//------------------------------------------------------------------------
inline int pe_loader_t::process_sections(
linput_t *li,
off_t first_sec_pos,
int nobjs,
pe_section_visitor_t &psv)
{
transvec.qclear();
qvector<pesection_t> sec_headers;
// does the file layout match memory layout?
bool alt_align = pe.objalign == pe.filealign && pe.objalign < PAGE_SIZE;
qlseek(li, first_sec_pos);
validate_array_count(li, &nobjs, sizeof(pesection_t), "Number of sections", first_sec_pos);
for ( int i=0; i < nobjs; i++ )
{
pesection_t &sh = sec_headers.push_back();
if ( qlread(li, &sh, sizeof(sh)) != sizeof(sh) )
return -1;
if ( sh.s_vaddr != uint32(sh.s_scnptr) || sh.s_vsize > sh.s_psize )
alt_align = false;
}
if ( alt_align || pe.is_te() )
{
// according to Ivan Teblin from AVERT Labs, such files are
// mapped by Windows as-is and not section by section
// we mimic that behaviour
int code = psv.load_all();
if ( code != 0 )
return code;
}
int off_align = alt_align ? pe.filealign : FILEALIGN;
if ( pe.is_efi() || pe.is_te() )
off_align = 1;
uint32 max_va = 0;
for ( int i=0; i < nobjs; i++ )
{
pesection_t &sh = sec_headers[i];
uint32 scnptr = align_down(sh.s_scnptr, off_align);
transl_t &tr = transvec.push_back();
tr.start = sh.s_vaddr;
tr.psize = sh.get_psize(pe);
tr.end = pe.align_up_in_file(uint32(sh.s_vaddr + tr.psize));
tr.pos = scnptr;
if ( pe.is_te() )
tr.pos += te.te_adjust();
int code = psv.visit_section(sh, scnptr);
if ( code != 0 )
return code;
if ( max_va < sh.s_vaddr + sh.s_vsize )
max_va = sh.s_vaddr + sh.s_vsize;
}
if ( pe.is_te() )
pe.imagesize = max_va;
if ( nobjs == 0 || alt_align )
{
// add mapping for the header
transl_t tr;
tr.start = 0;
tr.psize = qlsize(li);
tr.end = pe.align_up_in_file(pe.imagesize);
tr.pos = 0;
// insert at the front so that it's always consulted last
transvec.insert(transvec.begin(), tr);
}
return 0;
}
//------------------------------------------------------------------------
inline int pe_loader_t::process_sections(linput_t *li, pe_section_visitor_t &psv)
{
off_t first_sec_pos = pe.is_te() ? te.first_section_pos(peoff) : pe.first_section_pos(peoff);
return process_sections(li, first_sec_pos, pe.nobjs, psv);
}
//------------------------------------------------------------------------
inline int pe_loader_t::process_sections(linput_t *li)
{
pe_section_visitor_t v;
return process_sections(li, v);
}
//-------------------------------------------------------------------------
inline void to_utf8(char *buf, size_t bufsz, bool force=false)
{
if ( force || !is_valid_utf8(buf) )
{
qstring qbuf;
if ( idb_utf8(&qbuf, buf) )
qstrncpy(buf, qbuf.c_str(), bufsz);
}
}
//------------------------------------------------------------------------
// process import table for one dll
inline int pe_loader_t::process_import_table(
linput_t *li,
ea_t atable,
ea_t ltable,
pe_import_visitor_t &piv)
{
bool is_pe_plus = pe.is_pe_plus();
uint32 elsize = piv.elsize = is_pe_plus ? 8 : 4;
const uint64 mask = is_pe_plus ? IMP_BY_ORD64 : IMP_BY_ORD32;
bool ok = true;
uint32 i;
for ( i=0; ok; i++, atable += elsize )
{
char buf[MAXSTR];
if ( !is_mul_ok(i, elsize) )
return 1;
uval_t rva_off = i * elsize;
if ( !is_add_ok(ltable, rva_off) )
return 1;
ea_t rva = ltable + rva_off;
if ( piv.withbase )
rva -= (uval_t)pe.imagebase();
uint32 fof = uint32(rva);
uint64 entry = is_pe_plus ? vaint64(li, fof, &ok) : valong(li, fof, &ok);
if ( entry == 0 )
break;
show_addr(atable);
int code;
if ( (entry & mask) == 0 ) // by name
{
ea_t nrva = (uval_t)entry + sizeof(short);
if ( piv.withbase )
nrva -= (uval_t)pe.imagebase();
fof = uint32(nrva);
asciiz2(li, fof, buf, sizeof(buf), &ok);
to_utf8(buf, sizeof(buf));
code = piv.visit_import(atable, entry, buf);
}
else
{
// ordinals are always 32bit, even in pe64
uint32 ord = entry & ~mask;
code = piv.visit_import(atable, ord, NULL);
}
if ( code != 0 )
return code;
}
return piv.leave_module(i);
}
//------------------------------------------------------------------------
// this function tries to read from a file as if it was reading from memory
// if translation not found for the given RVA then ZEROs are returned
// in addition, if it tries to read beyond a translation physical size
// the additional bytes will be returned as zeros
inline bool pe_loader_t::vmread(linput_t *li, uint32 rva, void *buf, size_t sz)
{
// clear whole user buffer
memset(buf, 0, sz);
size_t may_read = sz;
if ( get_linput_type(li) == LINPUT_PROCMEM )
{
qlseek(li, rva, SEEK_SET);
}
else
{
const transl_t *tr;
ea_t fpos = map_ea(rva, &tr);
// cannot find translation?
if ( fpos == BADADDR )
{
qlseek(li, int32(rva), SEEK_SET);
return true;
}
uint32 sectend = tr->pos + tr->psize; // section end
if ( fpos >= sectend )
return false; // data not present in the input file
qlseek(li, fpos);
// reading beyond section's limit?
uint32 after_read_pos = fpos + sz;
if ( after_read_pos < fpos )
return false; // integer overflow
if ( after_read_pos >= sectend )
{
// check if position belongs to the header and if reading beyond the limit
if ( uint32(fpos) < pe.allhdrsize && after_read_pos > pe.allhdrsize )
may_read = pe.allhdrsize - size_t(fpos);
else
may_read = sectend - fpos; // just read as much as section limit allows
}
}
QASSERT(20045, ssize_t(may_read) >= 0);
return qlread(li, buf, may_read) == (ssize_t)may_read;
}
//------------------------------------------------------------------------
// process all imports of a pe file
// returns: -1:could not read an impdir; 0-ok;
// other values can be returned by the visitor
inline int pe_loader_t::process_imports(linput_t *li, pe_import_visitor_t &piv)
{
if ( pe.impdir.rva == 0 )
return 0;
if ( transvec.empty() )
process_sections(li);
int code = 0;
for ( int ni=0; ; ni++ )
{
off_t off = pe.impdir.rva + ni*sizeof(peimpdir_t);
peimpdir_t &id = piv.id;
if ( !vmread(li, off, &id, sizeof(id)) )
{
memset(&id, 0, sizeof(id));
// we continue if the import descriptor is within the page belonging
// to the program
if ( map_ea(off) == BADADDR || map_ea(off+sizeof(id)-1) == BADADDR )
{
code = piv.impdesc_error(off);
if ( code != 0 )
break;
}
}
if ( id.dllname == 0 || id.looktab == 0 )
break;
ea_t ltable = id.table1; // OriginalFirstThunk
ea_t atable = id.looktab; // FirstThunk
bool ok = true;
char dll[MAXSTR];
asciiz(li, id.dllname, dll, sizeof(dll), &ok);
if ( !ok )
break;
to_utf8(dll, sizeof(dll), /*force=*/ true);
if ( map_ea(ltable) == BADADDR
|| ltable < pe.allhdrsize
|| pe.imagesize != 0 && ltable >= pe.imagesize )
{
ltable = atable;
}
atable += get_imagebase();
code = piv.visit_module(dll, atable, ltable);
if ( code != 0 )
break;
code = process_import_table(li, atable, ltable, piv);
if ( code != 0 )
break;
}
return code;
}
//------------------------------------------------------------------------
inline int pe_loader_t::process_delayed_imports(linput_t *li, pe_import_visitor_t &il)
{
if ( pe.didtab.rva == 0 )
return 0;
if ( transvec.empty() )
process_sections(li);
int code = 0;
uint32 ni = 0;
bool ok = true;
while ( true )
{
uint32 table = pe.didtab.rva + ni*uint32(sizeof(dimpdir_t));
if ( !vseek(li, table) )
break;
dimpdir_t &id = il.did;
if ( qlread(li, &id, sizeof(id)) != sizeof(id) )
return -1;
if ( !id.dllname )
break;
il.withbase = (id.attrs & DIMP_NOBASE) == 0;
uval_t base = il.withbase ? 0 : uval_t(get_imagebase());
ea_t atable = id.diat + base;
ea_t ltable = id.dint;
char dll[MAXSTR];
uint32 off = uint32(il.withbase ? id.dllname - (ea_t)pe.imagebase() : id.dllname);
asciiz(li, off, dll, sizeof(dll), &ok);
if ( !ok )
break;
to_utf8(dll, sizeof(dll), /*force=*/ true);
code = il.visit_module(dll, atable, ltable);
if ( code != 0 )
break;
code = process_import_table(li, atable, ltable, il);
if ( code != 0 )
break;
ni++;
}
return ok || code != 0 ? code : -1;
}
//------------------------------------------------------------------------
// process all exports of a pe file
// returns -2: could not read expdir, -1: other read errors, 0-ok,
// other values can be returned by the visitor
inline int pe_loader_t::process_exports(linput_t *li, pe_export_visitor_t &pev)
{
if ( pe.expdir.rva == 0 )
return 0;
if ( transvec.empty() )
process_sections(li);
if ( !vseek(li, pe.expdir.rva) )
return -2;
// process export directory
bool fok = true;
char buf[MAXSTR];
peexpdir_t ed;
if ( qlread(li, &ed, sizeof(ed)) != sizeof(ed) )
return -1;
asciiz2(li, ed.dllname, buf, sizeof(buf), &fok);
to_utf8(buf, sizeof(buf), /*force=*/ true);
int code = pev.visit_expdir(ed, buf);
if ( code != 0 )
return code;
// I'd like to have a better validation
uint64 maxsize = qlsize(li) + 4096;
if ( maxsize > pe.expdir.size && pe.expdir.size != 0 )
maxsize = pe.expdir.size;
validate_array_count(NULL, &ed.nnames, 6, "Number of exported names",
pe.expdir.rva, pe.expdir.rva+maxsize);
validate_array_count(NULL, &ed.naddrs, 4, "Number of exported addresses",
pe.expdir.rva, pe.expdir.rva+maxsize);
// gather name information
typedef std::map<int, qstring> names_t;
names_t names;
int rcode = fok ? 0 : -1;
for ( uint32 i=0; i < ed.nnames; i++ )
{
fok = true;
uint32 ordidx = vashort(li, ed.ordtab + i*sizeof(ushort), &fok);
if ( !fok )
{
if ( rcode == 0 )
rcode = -1;
continue;
}
ushort ord = ushort(ordidx + ed.ordbase);
uint32 rva = valong(li, ed.namtab + i*sizeof(uint32), &fok);
if ( !fok )
{
if ( rcode == 0 )
rcode = -1;
continue;
}
asciiz2(li, rva, buf, sizeof(buf), &fok);
if ( !fok )
{
if ( rcode == 0 )
rcode = -1;
continue;
}
to_utf8(buf, sizeof(buf));
names[ord] = buf;
}
// visit all exports
uint32 expdir_start_rva = pe.expdir.rva;
uint32 expdir_end_rva = pe.expdir.rva + maxsize;
for ( uint32 i = 0; i < ed.naddrs; i++ )
{
fok = true;
uint32 rva = valong(li, ed.adrtab + i*sizeof(uint32), &fok);
if ( rva != 0 && fok )
{
uint32 ord = i + ed.ordbase;
names_t::iterator p = names.find(ord);
const char *name = p != names.end() ? p->second.c_str() : "";
const char *forwarder = NULL;
if ( rva >= expdir_start_rva && rva < expdir_end_rva )
{
// string inside export directory: this is a forwarded export
asciiz(li, rva, buf, sizeof(buf), &fok);
if ( !fok )
{
if ( rcode == 0 )
rcode = -1;
continue;
}
char *dot = strrchr(buf, '.');
if ( dot != NULL )
{
char before_dot[MAXSTR];
char after_dot[MAXSTR];
*dot = '\0';
qstrncpy(before_dot, buf, sizeof(before_dot));
qstrncpy(after_dot, dot+1, sizeof(after_dot));
to_utf8(before_dot, sizeof(before_dot), /*force=*/ true);
to_utf8(after_dot, sizeof(after_dot), /*force=*/ false);
qsnprintf(buf, sizeof(buf), "%s.%s", before_dot, after_dot);
}
else
{
to_utf8(buf, sizeof(buf), /*force=*/ true);
}
forwarder = buf;
}
code = pev.visit_export(rva, ord, name, forwarder);
if ( code != 0 )
{
if ( rcode == 0 )
rcode = code;
}
}
else if ( !fok )
rcode = -1;
}
return rcode;
}
//------------------------------------------------------------------------
inline const char *get_pe_machine_name(uint16 machine)
{
switch ( machine )
{
case PECPU_80386: return "80386";
case PECPU_80486: return "80486";
case PECPU_80586: return "80586";
case PECPU_SH3: return "SH3";
case PECPU_SH3DSP: return "SH3DSP";
case PECPU_SH3E: return "SH3E";
case PECPU_SH4: return "SH4";
case PECPU_SH5: return "SH5";
case PECPU_ARM: return "ARM";
case PECPU_ARMI: return "ARMI";
case PECPU_ARMV7: return "ARMv7";
case PECPU_EPOC: return "ARM EPOC";
case PECPU_PPC: return "PPC";
case PECPU_PPCFP: return "PPC FP";
case PECPU_PPCBE: return "PPC BE";
case PECPU_IA64: return "IA64";
case PECPU_R3000: return "MIPS R3000";
case PECPU_R4000: return "MIPS R4000";
case PECPU_R6000: return "MIPS R6000";
case PECPU_R10000: return "MIPS R10000";
case PECPU_MIPS16: return "MIPS16";
case PECPU_WCEMIPSV2: return "MIPS WCEv2";
case PECPU_ALPHA: return "ALPHA";
case PECPU_ALPHA64: return "ALPHA 64";
case PECPU_AMD64: return "AMD64";
case PECPU_ARM64: return "ARM64";
case PECPU_M68K: return "M68K";
case PECPU_MIPSFPU: return "MIPS FPU";
case PECPU_MIPSFPU16: return "MIPS16 FPU";
case PECPU_EBC: return "EFI Bytecode";
case PECPU_AM33: return "AM33";
case PECPU_M32R: return "M32R";
case PECPU_CEF: return "CEF";
case PECPU_CEE: return "CEE";
case PECPU_TRICORE: return "TRICORE";
}
return NULL;
}
//-------------------------------------------------------------------------
inline bool pe_loader_t::read_strtable(qstring *out, linput_t *li)
{
bool ok = false;
if ( pe.symtof != 0 )
{
qoff64_t strtoff = qoff64_t(pe.symtof) + pe.nsyms * 18;
ok = read_string_table(out, li, strtoff);
}
return ok;
}

306
idasdk76/ldr/pe/common.h Normal file
View File

@@ -0,0 +1,306 @@
#ifndef _PE_LDR_COMMON_H_
#define _PE_LDR_COMMON_H_
#include <netnode.hpp>
#include <idp.hpp>
#include <loader.hpp>
#include <diskio.hpp>
#define PAGE_SIZE 0x1000
//------------------------------------------------------------------------
struct pe_section_visitor_t
{
virtual int idaapi visit_section(const pesection_t &, off_t /*file_offset*/) { return 0; }
virtual int idaapi load_all() { return 0; }
virtual ~pe_section_visitor_t(void) {}
};
//------------------------------------------------------------------------
//-V:pe_import_visitor_t:730 not all members of a class are initialized inside the constructor
struct pe_import_visitor_t
{
bool withbase;
int elsize; // initialized by process_import_table()
peimpdir_t id;
dimpdir_t did;
pe_import_visitor_t(void) : withbase(false) {}
virtual int idaapi visit_module(const char * /*dll*/, ea_t /*iat_start*/, ea_t /*int_rva*/) { return 0; }
virtual int idaapi leave_module(uint32 /*nprocessed_imports*/) { return 0; }
// buf==NULL:by ordinal
virtual int idaapi visit_import(ea_t impea, uint32 ordinal, const char *buf) = 0;
virtual int idaapi impdesc_error(off_t /*file_offset*/) { return 0; }
virtual ~pe_import_visitor_t(void) {}
};
//------------------------------------------------------------------------
struct pe_export_visitor_t
{
// this function will be called once at the start.
// it must return 0 to continue
virtual int idaapi visit_expdir(const peexpdir_t & /*ed*/, const char * /*modname*/) { return 0; }
// this function is called for each export. name is never NULL, forwarder may point to the forwarder function
// it must return 0 to continue
virtual int idaapi visit_export(uint32 rva, uint32 ord, const char *name, const char *forwarder) = 0;
virtual ~pe_export_visitor_t(void) {}
};
//------------------------------------------------------------------------
class pe_loader_t
{
int process_import_table(
linput_t *li,
ea_t atable,
ea_t ltable,
pe_import_visitor_t &piv);
template <class T>
T varead(linput_t *li, uint32 rva, bool *ok)
{
T x = 0;
bool _ok = vseek(li, rva) && qlread(li, &x, sizeof(x)) == sizeof(x);
if ( ok != NULL )
*ok = _ok;
return x;
}
public:
struct transl_t
{
ea_t start;
ea_t end;
off_t pos;
size_t psize;
};
typedef qvector<transl_t> transvec_t;
transvec_t transvec;
union
{
exehdr exe;
teheader_t te;
};
peheader_t pe;
peheader64_t pe64; // original 64bit header, should not be used
// because all fields are copied to pe
// nb: imagebase is truncated during the copy!
ea_t load_imagebase; // imagebase used during loading; initialized from the PE header but can be changed by the user
off_t peoff; // offset to pe header
bool link_ulink; // linked with unilink?
// low level functions
//------------------------------------------------------------------------
// NB! We need to walk the mapping backwards, because
// the later sections take priority over earlier ones
//
// e.g. consider
// section 0: start=1000, end=5000, pos=1000
// section 1: start=3000, end=4000, pos=5000
// for byte at RVA 3500:
// section 0 maps it from the file offset 3500
// but section 1 overrides it with the byte from file offset 5500!
//
inline ea_t map_ea(ea_t rva, const transl_t **tl=NULL)
{
for ( ssize_t i=transvec.size()-1; i >= 0; i-- )
{
const transl_t &trans = transvec[i];
if ( trans.start <= rva && trans.end > rva )
{
if ( tl != NULL )
*tl = &trans;
return rva-trans.start + trans.pos;
}
}
return BADADDR;
}
ea_t get_imagebase(void) const { return load_imagebase; }
void set_imagebase(ea_t newimagebase) { load_imagebase=newimagebase; }
virtual bool vseek(linput_t *li, uint32 rva);
inline uint16 vashort(linput_t *li, uint32 addr, bool *ok) { return varead<uint16>(li, addr, ok); }
inline uint32 valong(linput_t *li, uint32 addr, bool *ok) { return varead<uint32>(li, addr, ok); }
inline uint64 vaint64(linput_t *li, uint32 addr, bool *ok) { return varead<uint64>(li, addr, ok); }
char *asciiz(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok);
char *asciiz2(linput_t *li, uint32 rva, char *buf, size_t bufsize, bool *ok);
int process_sections(linput_t *li, off_t fist_sec_pos, int nojbs, pe_section_visitor_t &psv);
int process_sections(linput_t *li, pe_section_visitor_t &psv);
// If 'zero_bad_data==true' (i.e., the default), extra 'directories'
// in the pe/pe64 headers will be set to zero.
bool read_header(linput_t *li, off_t _peoff, bool silent, bool zero_bad_data = true);
// high level functions
bool read_header(linput_t *li, bool silent=false, bool zero_bad_data = true);
int process_sections(linput_t *li);
int process_delayed_imports(linput_t *li, pe_import_visitor_t &il);
int process_imports(linput_t *li, pe_import_visitor_t &piv);
int process_exports(linput_t *li, pe_export_visitor_t &pev);
bool vmread(linput_t *li, uint32 rva, void *buf, size_t sz);
bool read_strtable(qstring *out, linput_t *li);
virtual ~pe_loader_t(void) {}
};
//------------------------------------------------------------------------
struct import_loader_t : public pe_import_visitor_t
{
struct dllinfo_t
{
qstring orig_name;
qstring name;
netnode node; // will be used by import_module()
bool imported_module;
dllinfo_t()
: imported_module(false)
{}
};
typedef qvector<dllinfo_t> dllinfo_vec_t;
processor_t &ph;
peheader_t &pe;
dllinfo_vec_t dlls; // visited modules
range_t imprange;
ea_t astart;
ea_t last_imp;
ea_t int_rva;
int ndid; // number of delayed import dirs
bool displayed;
bool got_new_imports;
bool delayed_imports;
inline void preprocess(void);
inline bool has_module(const char *mod) const
{
size_t ndlls = dlls.size();
for ( size_t i = 0; i < ndlls; i++ )
if ( !stricmp(dlls[i].orig_name.c_str(), mod) )
return true;
return false;
}
int idaapi visit_module(const char *dll, ea_t iat_start, ea_t _int_rva) override;
int idaapi visit_import(ea_t impea, uint32 ordinal, const char *buf) override;
int idaapi leave_module(uint32 nprocessed_imports) override;
int idaapi impdesc_error(off_t off) override;
inline void postprocess(void);
import_loader_t(processor_t &_ph, peheader_t &_pe, bool di)
: ph(_ph), pe(_pe), astart(BADADDR), last_imp(BADADDR), int_rva(0),
ndid(0),
displayed(false), got_new_imports(false), delayed_imports(di)
{
imprange.start_ea = BADADDR;
imprange.end_ea = 0;
}
};
#ifdef __EA64__
struct function_entry_x64
{
uint32 BeginAddress;
uint32 EndAddress;
uint32 UnwindData;
bool operator<(const function_entry_x64 &r) const { return BeginAddress < r.BeginAddress; }
bool operator!=(const function_entry_x64 &r) const
{
return BeginAddress != r.BeginAddress
|| EndAddress != r.EndAddress
|| UnwindData != r.UnwindData;
}
};
struct unwind_info_x64
{
uint8 Version_Flags;
uint8 SizeOfProlog; //lint -e754 local structure member not referenced
uint8 CountOfCodes;
uint8 FrameRegister_Offset;
};
#endif
//------------------------------------------------------------------------
struct ida_loader_t : public pe_loader_t
{
processor_t &ph;
eavec_t asked_eas;
import_loader_t imploader; // used in load_imports()
import_loader_t didloader; // used in load_delayed_imports()
eavec_t imp_fixups; // fixups to the import tables,
// they will be updated after a creation of
// the .idata segment
bool loaded_header = false;
bool vseek_asked = false;
bool has_embedded_pdb = false;
virtual bool vseek(linput_t *li, uint32 rva) override
{
ea_t fpos;
if ( get_linput_type(li) == LINPUT_PROCMEM )
{
fpos = rva;
}
else
{
fpos = map_ea(rva);
if ( fpos == BADADDR && rva < peoff+pe.allhdrsize )
fpos = rva;
}
if ( fpos != BADADDR )
{
qoff64_t p2 = qlseek(li, qoff64_t(fpos));
return p2 != -1;
}
if ( !vseek_asked
&& ask_yn(ASKBTN_YES,
"HIDECANCEL\n"
"Can't find translation for relative virtual address %08X, continue?",
rva) <= ASKBTN_NO )
{
loader_failure();
}
vseek_asked = true;
qlseek(li, rva, SEEK_SET);
return false;
}
ida_loader_t(void) //lint !e1401 non-static data member 'pe_loader_t::*' not initialized by constructor
: ph(PH),
imploader(ph, pe, false),
didloader(ph, pe, true) {}
void setup_entry_and_dgroup(linput_t *li, sel_t dgroup);
bool make_beginning_loaded(linput_t *li, ea_t begin);
sel_t load_sections(linput_t *li, bool aux, const qstring *strtable=nullptr);
void load_tls(linput_t *li);
void load_exports(linput_t *li);
void load_imports(linput_t *li);
void load_delayed_imports(linput_t *li);
void read_and_save_fixups(linput_t *li);
bool has_imports_by_ordinal(linput_t *li);
void load_cli_module(linput_t *_li);
void load_pdata(linput_t *li);
void pe_convert_idata();
void comment_impexp(linput_t *li);
void load_loadconfig(linput_t *li);
void load_header_section(linput_t *li, bool visible);
void load_debug_info(linput_t *li);
void remember_imp_fixup(ea_t fixup_ea, ea_t target)
{
for ( const auto &impldr : { imploader, didloader } )
{
if ( impldr.imprange.contains(target) )
{
imp_fixups.add(fixup_ea);
break;
}
}
}
bool has_ntdll() const { return imploader.has_module("ntdll.dll"); }
#ifdef __EA64__
int check_chained_uw(linput_t *li, uint32 rva, function_entry_x64 *chained, int nest_count = 0);
void load_pdata_x64(linput_t *li, uint32 pdata_rva, asize_t psize);
bool has_bad_uwopcodes(linput_t *li, uint32 uw_rva, ea_t funcstart);
#endif
};
#endif

2532
idasdk76/ldr/pe/cor.h Normal file

File diff suppressed because it is too large Load Diff

1845
idasdk76/ldr/pe/corhdr.h Normal file

File diff suppressed because it is too large Load Diff

507
idasdk76/ldr/pe/mycor.h Normal file
View File

@@ -0,0 +1,507 @@
// Borland-compatible Microsoft.Net definitions
// Only the most important headers are declared
//
// The second half of the file contains the structures saved in the
// database
#ifndef __MYCOR_H
#define __MYCOR_H
#pragma pack(push, 1)
#ifdef __NT__
typedef wchar_t wchar;
#else
typedef wchar16_t wchar;
#endif
#ifndef _WINDOWS_ // define some MS Windows symbols if <windows.h> is not included
#define __int8 char
#ifdef __GNUC__
#define __cdecl
#define __stdcall
#endif
typedef int32 HRESULT;
#define S_OK 0
#define S_FALSE (!S_OK)
#define E_FAIL 0x80004005
#define SEVERITY_SUCCESS 0
#define SEVERITY_ERROR 1
#define FACILITY_URT 19
#define MAKE_HRESULT(sev,fac,code) \
((HRESULT) (((uint32)(sev)<<31) | ((uint32)(fac)<<16) | ((uint32)(code))) )
#define EMAKEHR(val) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, val)
#define SMAKEHR(val) MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_URT, val)
#define META_E_BAD_SIGNATURE EMAKEHR(0x1192) // Bad binary signature
#define FAILED(hr) (((HRESULT)(hr)) < 0)
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#undef UNALIGNED
#define UNALIGNED
typedef uchar BYTE;
typedef short SHORT;
typedef ushort USHORT;
typedef ushort WORD;
typedef uint32 ULONG;
typedef uint ULONG32;
typedef uint32 DWORD;
typedef uint64 DWORD64;
typedef void *LPVOID;
typedef bool BOOL;
typedef int32 LONG;
typedef uint32 ULONG;
typedef int64 LONGLONG;
typedef uint64 ULONGLONG;
typedef wchar *LPWSTR;
typedef const void *UVCP_CONSTANT;
typedef ULONG &LPCWSTR;
typedef float FLOAT;
typedef double DOUBLE;
typedef uint32 SCODE;
typedef void *BSTR; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms221069(v=vs.85).aspx
typedef void *PVOID;
typedef int INT;
typedef uint UINT;
typedef char CHAR;
typedef DOUBLE DATE;
class IUnknown;
struct OSINFO
{
DWORD dwOSPlatformId;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
};
struct ASSEMBLYMETADATA
{
USHORT usMajorVersion;
USHORT usMinorVersion;
USHORT usBuildNumber;
USHORT usRevisionNumber;
LPWSTR szLocale;
ULONG cbLocale;
DWORD *rdwProcessor;
ULONG ulProcessor;
OSINFO *rOS;
ULONG ulOS;
};
struct GUID
{
uint32 Data1;
ushort Data2;
ushort Data3;
uchar Data4[8];
};
struct IMAGE_DATA_DIRECTORY
{
uint32 VirtualAddress;
uint32 Size;
};
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221061(v=vs.85).aspx
typedef struct tagDEC
{
USHORT wReserved;
union
{
struct
{
BYTE scale;
BYTE sign;
};
USHORT signscale;
};
ULONG Hi32;
union
{
struct
{
ULONG Lo32;
ULONG Mid32;
};
ULONGLONG Lo64;
};
} DECIMAL;
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221223(v=vs.85).aspx
typedef union tagCY
{
struct
{
unsigned long Lo;
long Hi;
};
LONGLONG int64;
} CY, CURRENCY;
typedef struct tagSAFEARRAYBOUND
{
ULONG cElements;
LONG lLbound;
} SAFEARRAYBOUND, *LPSAFEARRAYBOUND;
// http://msdn.microsoft.com/en-us/library/9ec8025b-4763-4526-ab45-390c5d8b3b1e(VS.85)
typedef struct tagSAFEARRAY
{
USHORT cDims;
USHORT fFeatures;
ULONG cbElements;
ULONG cLocks;
PVOID pvData;
SAFEARRAYBOUND rgsabound[1];
} SAFEARRAY, *LPSAFEARRAY;
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627(v=vs.85).aspx
typedef unsigned short VARTYPE;
typedef uint16 VARIANT_BOOL;
typedef uint16 _VARIANT_BOOL;
struct IRecordInfo;
typedef struct tagVARIANT
{
union
{
struct
{
VARTYPE vt;
WORD wReserved1;
WORD wReserved2;
WORD wReserved3;
union
{
LONGLONG llVal;
LONG lVal;
BYTE bVal;
SHORT iVal;
FLOAT fltVal;
DOUBLE dblVal;
VARIANT_BOOL boolVal;
/* _VARIANT_BOOL bool; */
SCODE scode;
CY cyVal;
DATE date;
BSTR bstrVal;
IUnknown *punkVal;
/* IDispatch *pdispVal; */
SAFEARRAY *parray;
BYTE *pbVal;
SHORT *piVal;
LONG *plVal;
LONGLONG *pllVal;
FLOAT *pfltVal;
DOUBLE *pdblVal;
VARIANT_BOOL *pboolVal;
/* _VARIANT_BOOL *pbool; */
SCODE *pscode;
CY *pcyVal;
DATE *pdate;
BSTR *pbstrVal;
/* IUnknown **ppunkVal; */
/* IDispatch **ppdispVal; */
SAFEARRAY **pparray;
/* VARIANT *pvarVal; */
PVOID byref;
CHAR cVal;
USHORT uiVal;
ULONG ulVal;
ULONGLONG ullVal;
INT intVal;
UINT uintVal;
DECIMAL *pdecVal;
CHAR *pcVal;
USHORT *puiVal;
ULONG *pulVal;
ULONGLONG *pullVal;
INT *pintVal;
UINT *puintVal;
struct /*__tagBRECORD*/
{
PVOID pvRecord;
IRecordInfo *pRecInfo;
} /* __VARIANT_NAME_4*/;
} /* __VARIANT_NAME_3*/;
} /* __VARIANT_NAME_2*/;
DECIMAL decVal;
};
} VARIANT, *LPVARIANT, VARIANTARG, *LPVARIANTARG;
#define VT_EMPTY 0x0000
#define VT_NULL 0x0001
#define VT_I2 0x0002
#define VT_I4 0x0003
#define VT_R4 0x0004
#define VT_R8 0x0005
#define VT_CY 0x0006
#define VT_DATE 0x0007
#define VT_BSTR 0x0008
#define VT_DISPATCH 0x0009
#define VT_ERROR 0x000A
#define VT_BOOL 0x000B
#define VT_VARIANT 0x000C
#define VT_UNKNOWN 0x000D
#define VT_DECIMAL 0x000E
#define VT_I1 0x0010
#define VT_UI1 0x0011
#define VT_UI2 0x0012
#define VT_UI4 0x0013
#define VT_I8 0x0014
#define VT_UI8 0x0015
#define VT_INT 0x0016
#define VT_UINT 0x0017
#define VT_VOID 0x0018
#define VT_HRESULT 0x0019
#define VT_PTR 0x001A
#define VT_SAFEARRAY 0x001B
#define VT_CARRAY 0x001C
#define VT_USERDEFINED 0x001D
#define VT_LPSTR 0x001E
#define VT_LPWSTR 0x001F
#define VT_RECORD 0x0024
#define VT_INT_PTR 0x0025
#define VT_UINT_PTR 0x0026
#define VT_ARRAY 0x2000
#define VT_BYREF 0x4000
#define VariantInit(v_ptr) (v_ptr)->vt = VT_EMPTY
inline HRESULT VariantClear(VARIANTARG *pVar)
{
memset(pVar, 0, sizeof(VARIANT));
return S_OK;
}
#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
#define SCODE_CODE(sc) ((sc) & 0xFFFF)
#define CLDB_S_TRUNCATION SMAKEHR(0x1106)
#define CLDB_E_TRUNCATION EMAKEHR(0x1106)
#endif // __UNIX__
#include "corhdr.h"
#include "cor.h"
//--------------------------------------------------------------------
// what netnode tag
#define CLITAG_MDA 0 // the assembly mda is here at index 0
#define CLITAG_MTK 1 // the scope mtk is here at index 0
#define CLITAG_STRUCT 'a' // the structure itself is saved here
#define CLITAG_NAME 'b' // char *name (deprecated for strings, see CLITAG_STRING)
// saved as blob
#define CLITAG_VALUE 'c' // void *pval
#define CLITAG_SIG 'd' // PCOR_SIGNATURE[]
#define CLITAG_OTHER 'e' // mdToken others[]
//#define CLITAG_TITLE 'f' // assembly title
//#define CLITAG_DESCR 'g' // assembly description
//#define CLITAG_ALIAS 'h' // assembly alias
#define CLITAG_PUBKEY 'i' // public key blob
#define CLITAG_PINV 'k' // pinvoke_info_t
#define CLITAG_PNAME 'l' // name of pinvoke method
#define CLITAG_LAYOUT 'm' // layout_info_t
#define CLITAG_OFFSETS 'n' // COR_FIELD_OFFSET[]
#define CLITAG_CUST 'o' // custom attribute blob
#define CLITAG_TOKEN 'p' // ea: method, field, property, event token is here
#define CLITAG_CLASS 'q' // ea: typedef token
#define CLITAG_STRING 'r' // ea: address of string's bytes in .strings segment
#define CLITAG_CLASSEND 's' // ea: typedef token
#define CLITAG_TRY 't' // ea: try block start/cor_exception_info_t
#define CLITAG_BEND 'u' // ea: block end
#define CLITAG_HASH 'v' // hash
#define CLITAG_FRVA 'x' // field rva
#define CLITAG_EXCEPTION 128 // exception blocks: several indexes
// enumeration blobs
// global enumerations have index 0
#define CLITAG_PARAMS 'A'
#define CLITAG_FIELDS 'B'
#define CLITAG_METHODS 'C'
#define CLITAG_EVENTS 'D'
#define CLITAG_PROPERTIES 'E'
#define CLITAG_INTERFACES 'F'
#define CLITAG_TYPEDEFS 'G'
#define CLITAG_TYPEREFS 'H'
#define CLITAG_TYPESPECS 'I'
#define CLITAG_USERSTRINGS 'J'
#define CLITAG_CUSTATTRS 'K'
#define CLITAG_MODULEREFS 'L'
#define CLITAG_MEMBERREFS 'M' // 'N' shouldn't be used (as well as 'V')
struct param_info_t // +name +value
{
mdToken method;
ULONG n;
ULONG flags;
DWORD deftype;
};
struct field_info_t // +name +sig +value
{
mdToken owner;
ULONG flags;
DWORD deftype;
ea_t ea;
};
struct method_info_t // +name +sig +params
{
mdToken owner;
DWORD flags;
ULONG rva; // ea later
DWORD implflags;
mdToken lvars;
uint32 maxstack;
uint32 methodflags;
};
struct pinvoke_info_t // +pname
{
DWORD mappingflags;
mdToken dlltok;
};
struct property_info_t // +name +sig +other_tokens +value
{
mdToken owner;
ULONG flags;
DWORD deftype;
mdToken setter, getter;
// mdToken backing; disappeared in Beta2
ea_t ea;
};
struct event_info_t // +name +other_tokens
{
mdToken owner;
ULONG flags;
mdToken type;
mdToken addon, removeon, fire;
ea_t ea;
};
struct interfaceimpl_info_t
{
mdToken inttok;
};
struct typedef_info_t // +name +fields +methods +layout +offsets
{
DWORD flags;
mdToken super;
};
struct layout_info_t
{
DWORD packsize;
ULONG classsize;
ULONG noffsets;
};
struct typeref_info_t // +name
{
mdToken scope;
};
struct moduleref_info_t // +name
{
};
struct memberref_info_t // +name +sig
{
mdToken owner;
};
struct typespec_info_t // +sig
{
};
struct userstring_info_t // +name
{
};
struct custattr_info_t // +blob
{
mdToken owner;
mdToken type;
};
struct assembly_info_t // +name +orig +title +desc +alias
{
ULONG hash;
DWORD flags;
USHORT usMajorVersion;
USHORT usMinorVersion;
USHORT usRevisionNumber;
USHORT usBuildNumber;
};
struct assemblyref_info_t // +name +orig +hash
{
DWORD flags;
// mdToken exeloc;
USHORT usMajorVersion;
USHORT usMinorVersion;
USHORT usRevisionNumber;
USHORT usBuildNumber;
};
struct file_info_t // +name +hash
{
DWORD flags;
};
struct comtype_info_t // +name +descr
{
ULONG flags;
mdToken impl, type, exeloc;
};
struct cor_module_info_t // +name
{
mdToken mtk;
GUID mid;
};
struct cor_exception_info_t
{
ULONG flags;
ULONG param;
};
struct longname_director_t
{
char zero;
uval_t node;
};
CASSERT(sizeof(longname_director_t) == 1 + sizeof(uval_t));
//------------------------------------------------------------------------
ea_t get_free_address(void);
void expand(ea_t ea);
void define_class(mdToken, const char *name, ea_t ea1, ea_t ea2);
mdToken define_method(mdToken method, const char *name, method_info_t &b, ea_t *ea);
void supset(ea_t idx, const void *body, int size, char tag);
ssize_t supstr(ea_t idx, char *buf, size_t bufsize, char tag);
void altset(ea_t idx, ea_t val, char tag);
void setblob(ea_t idx, const void *body, int size, char tag);
void save_name(ea_t idx, const qstring &name);
qstring retrieve_name(ea_t idx);
uint32 get_constant_element_type_raw_size(CorElementType type, uint32 chars);
bool load_metadata(const void *metadata, size_t metasize);
#pragma pack(pop)
#endif // define __MYCOR_H

1174
idasdk76/ldr/pe/pe.h Normal file

File diff suppressed because it is too large Load Diff

313
idasdk76/ldr/pef/common.cpp Normal file
View File

@@ -0,0 +1,313 @@
//----------------------------------------------------------------------
static void swap_pef(pef_t &pef)
{
#if __MF__
qnotused(pef);
#else
pef.formatVersion = swap32(pef.formatVersion);
pef.dateTimeStamp = swap32(pef.dateTimeStamp);
pef.oldDefVersion = swap32(pef.oldDefVersion);
pef.oldImpVersion = swap32(pef.oldImpVersion);
pef.currentVersion = swap32(pef.currentVersion);
pef.reservedA = swap32(pef.reservedA);
pef.sectionCount = swap16(pef.sectionCount);
pef.instSectionCount = swap16(pef.instSectionCount);
#endif
}
//----------------------------------------------------------------------
static void swap_pef_section(pef_section_t &ps)
{
#if __MF__
qnotused(ps);
#else
ps.nameOffset = swap32(ps.nameOffset);
ps.defaultAddress = swap32(ps.defaultAddress);
ps.totalSize = swap32(ps.totalSize);
ps.unpackedSize = swap32(ps.unpackedSize);
ps.packedSize = swap32(ps.packedSize);
ps.containerOffset = swap32(ps.containerOffset);
#endif
}
//----------------------------------------------------------------------
static void swap_pef_loader(pef_loader_t &pl)
{
#if __MF__
qnotused(pl);
#else
pl.mainSection = swap32(pl.mainSection);
pl.mainOffset = swap32(pl.mainOffset);
pl.initSection = swap32(pl.initSection);
pl.initOffset = swap32(pl.initOffset);
pl.termSection = swap32(pl.termSection);
pl.termOffset = swap32(pl.termOffset);
pl.importLibraryCount = swap32(pl.importLibraryCount);
pl.totalImportedSymbolCount = swap32(pl.totalImportedSymbolCount);
pl.relocSectionCount = swap32(pl.relocSectionCount);
pl.relocInstrOffset = swap32(pl.relocInstrOffset);
pl.loaderStringsOffset = swap32(pl.loaderStringsOffset);
pl.exportHashOffset = swap32(pl.exportHashOffset);
pl.exportHashTablePower = swap32(pl.exportHashTablePower);
pl.exportedSymbolCount = swap32(pl.exportedSymbolCount);
#endif
}
//----------------------------------------------------------------------
static void swap_pef_library(pef_library_t &pil)
{
#if __MF__
qnotused(pil);
#else
pil.nameOffset = swap32(pil.nameOffset);
pil.oldImpVersion = swap32(pil.oldImpVersion);
pil.currentVersion = swap32(pil.currentVersion);
pil.importedSymbolCount = swap32(pil.importedSymbolCount);
pil.firstImportedSymbol = swap32(pil.firstImportedSymbol);
pil.reservedB = swap16(pil.reservedB);
#endif
}
//----------------------------------------------------------------------
static void swap_pef_reloc_header(pef_reloc_header_t &prh)
{
#if __MF__
qnotused(prh);
#else
prh.sectionIndex = swap16(prh.sectionIndex);
prh.reservedA = swap16(prh.reservedA);
prh.relocCount = swap32(prh.relocCount);
prh.firstRelocOffset = swap32(prh.firstRelocOffset);
#endif
}
//----------------------------------------------------------------------
static void swap_pef_export(pef_export_t &pe)
{
#if __MF__
qnotused(pe);
#else
pe.classAndName = swap32(pe.classAndName);
pe.symbolValue = swap32(pe.symbolValue);
pe.sectionIndex = swap16(pe.sectionIndex);
#endif
}
//----------------------------------------------------------------------
const char *get_pef_processor(const pef_t &pef)
{
if ( strneq(pef.architecture, PEF_ARCH_PPC, 4) ) // PowerPC
return "ppc";
if ( strneq(pef.architecture, PEF_ARCH_68K, 4) ) // or 68K
return "68000";
return NULL;
}
//----------------------------------------------------------------------
const char *get_pef_processor(linput_t *li)
{
pef_t pef;
if ( qlread(li, &pef, sizeof(pef_t)) != sizeof(pef_t) )
return NULL;
swap_pef(pef);
if ( !strneq(pef.tag1, PEF_TAG_1, 4) // Joy!
|| !strneq(pef.tag2, PEF_TAG_2, 4) // peff
|| pef.formatVersion != PEF_VERSION ) // 1
{
return NULL;
}
return get_pef_processor(pef);
}
//----------------------------------------------------------------------
bool is_pef_file(linput_t *li)
{
const char *proc = get_pef_processor(li);
return proc != NULL;
}
//----------------------------------------------------------------------
static char *get_string(
linput_t *li,
qoff64_t snames_table,
int32 off,
char *buf,
size_t bufsize)
{
if ( ssize_t(bufsize) <= 0 )
return NULL;
if ( off == -1 )
{
buf[0] = '\0';
return NULL;
}
qlseek(li, snames_table+off);
lread(li, buf, bufsize);
buf[bufsize-1] = '\0';
return buf;
}
//----------------------------------------------------------------------
inline const char *get_impsym_name(
const char *stable,
const void *end,
const uint32 *impsym,
int i)
{
size_t off = mflong(impsym[i]) & 0xFFFFFF;
if ( stable + off >= end )
return NULL;
return stable + off;
}
//----------------------------------------------------------------------
inline size_t get_expsym_name_length(const uint32 *keytable, int i)
{
return mflong(keytable[i]) >> 16;
}
//----------------------------------------------------------------------
static bool get_expsym_name(
const char *stable,
const uint32 *keytable,
const pef_export_t *pe,
int i,
const void *end,
char *buf,
size_t bufsize)
{
pe += i;
size_t off = (pe->classAndName & 0xFFFFFFL);
size_t len = get_expsym_name_length(keytable, i);
if ( len >= bufsize )
len = bufsize-1;
if ( stable+off+len >= end )
return false;
memcpy(buf, stable+off, len);
buf[len] = 0;
return true;
}
//----------------------------------------------------------------------
// is data pointed by [ptr, end) completely inside vector?
static bool inside(const bytevec_t &vec, const void *ptr, size_t nelems, size_t elsize)
{
if ( !is_mul_ok(nelems, elsize) )
return false;
const uchar *p = (const uchar *)ptr;
const uchar *e = p + nelems * elsize;
return p >= vec.begin()
&& p <= vec.end()
&& e >= p
&& e <= vec.end();
}
//----------------------------------------------------------------------
struct pef_loader_data_t
{
pef_loader_t pl;
pef_library_t *pil;
uint32 *impsym;
pef_reloc_header_t *prh;
const char *stable;
const uint16 *relptr;
const uint32 *hash;
const uint32 *keytable;
pef_export_t *pe;
pef_loader_data_t(void) { memset(this, 0, sizeof(*this)); }
~pef_loader_data_t(void)
{
qfree(pil);
qfree(prh);
qfree(pe);
qfree(impsym);
}
};
enum elderr_t
{
ELDERR_OK, // loader data ok
ELDERR_SHORT, // too short (not enough data even for the header)
ELDERR_IMPLIBS, // wrong imported library info
ELDERR_IMPSYMS, // wrong imported symbols
ELDERR_RELHDRS, // wrong relocation headers
ELDERR_STABLE, // wrong symbol table
ELDERR_RELOCS, // wrong relocation instructions
ELDERR_KEYTABLE, // wrong keytable
ELDERR_EXPSYMS, // wrong exported symbols
ELDERR_VECTORS, // wrong term/init/main vectors
ELDERR_LAST,
};
static elderr_t extract_loader_data(
pef_loader_data_t *pd,
const bytevec_t &ldrdata,
const qvector<pef_section_t> &sec)
{
if ( ldrdata.size() < sizeof(pef_loader_t) )
return ELDERR_SHORT;
pd->pl = *(pef_loader_t *)ldrdata.begin();
pef_loader_t &pl = pd->pl;
swap_pef_loader(pl);
const pef_library_t *pil = (pef_library_t *)(ldrdata.begin() + sizeof(pl));
const uint32 *impsym = (uint32 *)(pil + pl.importLibraryCount);
const pef_reloc_header_t *prh =
(pef_reloc_header_t *)(impsym + pl.totalImportedSymbolCount);
const char *stable = (char *)(ldrdata.begin() + pl.loaderStringsOffset);
const uint16 *relptr = (uint16 *)(ldrdata.begin() + pl.relocInstrOffset);
const uint32 *hash = (uint32 *)(ldrdata.begin() + pl.exportHashOffset);
const uint32 hashsize = (1 << pl.exportHashTablePower);
const uint32 *keytable = hash + hashsize;
const pef_export_t *pe = (pef_export_t *)(keytable + pl.exportedSymbolCount);
if ( !inside(ldrdata, pil, pl.importLibraryCount, sizeof(*pil)) )
return ELDERR_IMPLIBS;
if ( !inside(ldrdata, impsym, pl.totalImportedSymbolCount, sizeof(*impsym)) )
return ELDERR_IMPSYMS;
if ( !inside(ldrdata, prh, pl.relocSectionCount, sizeof(*prh)) )
return ELDERR_RELHDRS;
if ( !inside(ldrdata, stable, 0, 0) )
return ELDERR_STABLE;
if ( !inside(ldrdata, relptr, 0, 0) )
return ELDERR_RELOCS;
if ( !inside(ldrdata, pe, pl.exportedSymbolCount, sizeof(*pe)) )
return ELDERR_EXPSYMS;
if ( !inside(ldrdata, keytable, pl.exportedSymbolCount, sizeof(*keytable)) )
return ELDERR_KEYTABLE;
// x < -1 || x >= nsecs => unsigned(x+1) > nsecs
size_t nsecs = sec.size();
if ( pl.termSection+1 > nsecs
|| pl.initSection+1 > nsecs
|| pl.mainSection+1 > nsecs )
{
return ELDERR_VECTORS;
}
{ // malicious input file may have overlapping structures that may
// lead too all kinds of problems when we swap their contents.
// we simply make a copy and modify copies to ensure that there is
// no interference between different structures.
pd->pil = qalloc_array<pef_library_t>(pl.importLibraryCount);
memmove(pd->pil, pil, pl.importLibraryCount*sizeof(*pil));
pd->prh = qalloc_array<pef_reloc_header_t>(pl.relocSectionCount);
memmove(pd->prh, prh, pl.relocSectionCount*sizeof(*prh));
pd->pe = qalloc_array<pef_export_t>(pl.exportedSymbolCount);
memmove(pd->pe, pe, pl.exportedSymbolCount*sizeof(*pe));
pd->impsym = qalloc_array<uint32>(pl.totalImportedSymbolCount);
memmove(pd->impsym, impsym, pl.totalImportedSymbolCount*sizeof(*impsym));
}
#if !__MF__
for ( int i=0; i < pl.importLibraryCount; i++ )
swap_pef_library(pd->pil[i]);
for ( int i=0; i < pl.relocSectionCount; i++ )
swap_pef_reloc_header(pd->prh[i]);
for ( int i=0; i < pl.exportedSymbolCount; i++ )
swap_pef_export(pd->pe[i]);
#endif
pd->stable = stable;
pd->relptr = relptr;
pd->hash = hash;
pd->keytable = keytable;
return ELDERR_OK;
}

16
idasdk76/ldr/pef/makefile Normal file
View File

@@ -0,0 +1,16 @@
PROC=pef
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)pef$(O) : $(I)../ldr/coff/dbxstcla.h $(I)../ldr/coff/storclas.h \
$(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp \
$(I)typeinf.hpp $(I)ua.hpp $(I)xref.hpp \
../../module/ppc/notify_codes.hpp ../coff/syms.h \
../idaldr.h common.cpp pef.cpp pef.hpp

766
idasdk76/ldr/pef/pef.cpp Normal file
View File

@@ -0,0 +1,766 @@
/*
* 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,
};

184
idasdk76/ldr/pef/pef.hpp Normal file
View File

@@ -0,0 +1,184 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@datarescue.com
*
*/
//
// PEF file format (Mac OS, Be OS)
//
#ifndef PEF_HPP
#define PEF_HPP
#pragma pack(push, 1)
//-----------------------------------------------------------------------
#if __MF__
#define mfshort(x) (x)
#define lfshort(x) swap16(x)
#define mflong(x) (x)
#define lflong(x) swap32(x)
#else
#define mfshort(x) swap16(x)
#define lfshort(x) (x)
#define mflong(x) swap32(x)
#define lflong(x) (x)
#endif
typedef int16 sint16;
typedef int32 sint32;
//-----------------------------------------------------------------------
struct pef_t
{
char tag1[4]; // Designates Apply-defined format
#define PEF_TAG_1 "Joy!"
char tag2[4]; // Type of container
#define PEF_TAG_2 "peff"
char architecture[4]; // Target architecture
#define PEF_ARCH_PPC "pwpc"
#define PEF_ARCH_68K "m68k"
uint32 formatVersion; // Version of PEF
#define PEF_VERSION 1
uint32 dateTimeStamp; // Number of seconds from January 1, 1904
uint32 oldDefVersion;
uint32 oldImpVersion;
uint32 currentVersion;
uint16 sectionCount; // Total number of sections
uint16 instSectionCount; // Number of instantiated sections
uint32 reservedA; // Should be 0
};
//-----------------------------------------------------------------------
struct pef_section_t
{
sint32 nameOffset; // Offset from the start of the section
// name table
// No name is -1
uint32 defaultAddress; // Preferred address for section
uint32 totalSize; // Total size of section in memory
uint32 unpackedSize; // Initialized size of section in memory
uint32 packedSize; // Size of section in file
uint32 containerOffset; // Offset from the beginning of the file
uint8 sectionKind; // Type of section:
#define PEF_SEC_CODE 0 // Code segment
#define PEF_SEC_DATA 1 // Unpacked data segment
#define PEF_SEC_PDATA 2 // Pattern initialized data segment
#define PEF_SEC_CONST 3 // Read only data
#define PEF_SEC_LOADER 4 // Loader section
#define PEF_SEC_DEBUG 5 // Reserved for future use
#define PEF_SEC_EDATA 6 // Executable data segment
#define PEF_SEC_EXCEPT 7 // Reserved for future use
#define PEF_SEC_TRACEB 8 // Reserved for future use
uint8 shareKind; // Section share properties
#define PEF_SH_PROCESS 1 // Shared within process
#define PEF_SH_GLOBAL 4 // Shared between all processes
#define PEF_SH_PROTECT 5 // Shared between all processes but protected
uint8 alignment; // Section alignment as power of 2
// (here we have an exponent)
uint8 reservedA; // Should be 0
};
//-----------------------------------------------------------------------
struct pef_loader_t
{
sint32 mainSection; // Number of section with "main" symbol (-1 - none)
uint32 mainOffset; // Offset to "main" symbol
sint32 initSection; // Number of section with initialization transition vector (-1 - none)
uint32 initOffset; // Offset to initialization transition vector
sint32 termSection; // Number of section with termination transition vector (-1 - none)
uint32 termOffset; // Offset to termination transition vector
uint32 importLibraryCount; // Number of imported libraries
uint32 totalImportedSymbolCount;
uint32 relocSectionCount;
uint32 relocInstrOffset;
uint32 loaderStringsOffset;
uint32 exportHashOffset;
uint32 exportHashTablePower;
uint32 exportedSymbolCount;
};
//-----------------------------------------------------------------------
struct pef_library_t // Imported Library
{
uint32 nameOffset; // Offset from beginning of loader string table
uint32 oldImpVersion;
uint32 currentVersion;
uint32 importedSymbolCount;
uint32 firstImportedSymbol;
uint8 options;
#define PEF_LIB_INIT 0x80 // Non-default init order of library
#define PEF_LIB_WEAK 0x40 // Weak library
uint8 reservedA;
uint16 reservedB;
};
//-----------------------------------------------------------------------
// Imported symbol classes
#define kPEFCodeSymbol 0 // a code address
#define kPEFDataSymbol 1 // a data address
#define kPEFTVectSymbol 2 // a standard procedure pointer
#define kPEFTOCSymbol 3 // a direct data area (TOC) symbol
#define kPEFGlueSymbol 4 // a linker-inserted glue symbol
#define kPEFWeak 0x80 // Weak symbol mask
//-----------------------------------------------------------------------
// Relocation Header
struct pef_reloc_header_t
{
uint16 sectionIndex;
uint16 reservedA;
uint32 relocCount;
uint32 firstRelocOffset;
};
//-----------------------------------------------------------------------
// Relocation Instructions
enum
{
kPEFRelocBySectDWithSkip= 0x00,/* binary: 00xxxxx */
kPEFRelocBySectC = 0x20, /* binary: 0100000 */
kPEFRelocBySectD = 0x21, /* binary: 0100001 */
kPEFRelocTVector12 = 0x22, /* binary: 0100010 */
kPEFRelocTVector8 = 0x23, /* binary: 0100011 */
kPEFRelocVTable8 = 0x24, /* binary: 0100100 */
kPEFRelocImportRun = 0x25, /* binary: 0100101 */
kPEFRelocSmByImport = 0x30, /* binary: 0110000 */
kPEFRelocSmSetSectC = 0x31, /* binary: 0110001 */
kPEFRelocSmSetSectD = 0x32, /* binary: 0110010 */
kPEFRelocSmBySection = 0x33, /* binary: 0110011 */
kPEFRelocIncrPosition= 0x40, /* binary: 1000xxx */
kPEFRelocSmRepeat = 0x48, /* binary: 1001xxx */
kPEFRelocSetPosition = 0x50, /* binary: 101000x */
kPEFRelocLgByImport = 0x52, /* binary: 101001x */
kPEFRelocLgRepeat = 0x58, /* binary: 101100x */
kPEFRelocLgSetOrBySection= 0x5A,/* binary: 101101x */
};
//-----------------------------------------------------------------------
// Exported Symbols
struct pef_export_t
{
uint32 classAndName;
uint32 symbolValue;
sint16 sectionIndex;
};
#pragma pack(pop)
#endif // PEF_HPP

View File

@@ -0,0 +1,144 @@
//-------------------------------------------------------------------------
static void swap_prc(DatabaseHdrType &h)
{
h.attributes = swap16(h.attributes);
h.version = swap16(h.version);
h.creationDate = swap32(h.creationDate);
h.modificationDate = swap32(h.modificationDate);
h.lastBackupDate = swap32(h.lastBackupDate);
h.modificationNumber = swap32(h.modificationNumber);
h.appInfoID = swap32(h.appInfoID);
h.sortInfoID = swap32(h.sortInfoID);
// h.type = swap32(h.type);
// h.id = swap32(h.id);
h.uniqueIDSeed = swap32(h.uniqueIDSeed);
h.nextRecordListID = swap32(h.nextRecordListID);
h.numRecords = swap16(h.numRecords);
}
//-------------------------------------------------------------------------
static void swap_resource_map_entry(ResourceMapEntry &re)
{
re.id = swap16(re.id);
re.ulOffset = swap32(re.ulOffset);
}
//-------------------------------------------------------------------------
void swap_bitmap(pilot_bitmap_t *b)
{
b->cx = swap16(b->cx);
b->cy = swap16(b->cy);
b->cbRow = swap16(b->cbRow);
b->ausUnk[0] = swap16(b->ausUnk[0]);
b->ausUnk[1] = swap16(b->ausUnk[1]);
b->ausUnk[2] = swap16(b->ausUnk[2]);
b->ausUnk[3] = swap16(b->ausUnk[3]);
}
//-------------------------------------------------------------------------
void swap_code0000(code0000_t *cp)
{
cp->nBytesAboveA5 = swap32(cp->nBytesAboveA5);
cp->nBytesBelowA5 = swap32(cp->nBytesBelowA5);
}
//-------------------------------------------------------------------------
void swap_pref0000(pref0000_t *pp)
{
pp->flags = swap16(pp->flags);
pp->stack_size = swap32(pp->stack_size);
pp->heap_size = swap32(pp->heap_size);
}
//-------------------------------------------------------------------------
// Since the Palm Pilot programs are really poorly recognized by usual
// methods, we are forced to read the resource tablee to determine
// if everying is ok
// return 0 if not a PRC, 2 if has ARM code segments, 1 otherwise
int is_prc_file(linput_t *li)
{
DatabaseHdrType h;
if ( qlread(li,&h,sizeof(h)) != sizeof(h) )
return 0;
swap_prc(h);
if ( (h.attributes & dmHdrAttrResDB) == 0 )
return 0;
if ( short(h.numRecords) <= 0 )
return 0;
const uint64 filesize = qlsize(li);
const uint64 lowestpos = uint64(h.numRecords)*sizeof(ResourceMapEntry) + sizeof(h);
if ( lowestpos > filesize )
return 0;
// the dates can be plain wrong, so don't check them:
// uint32 now = time(NULL);
// && uint32(h.lastBackupDate) <= now // use unsigned comparition!
// && uint32(h.creationDate) <= now // use unsigned comparition!
// && uint32(h.modificationDate) <= now // use unsigned comparition!
qvector<ResourceMapEntry> re;
re.resize(h.numRecords);
size_t size = sizeof(ResourceMapEntry) * h.numRecords;
if ( qlread(li, re.begin(), size) != size )
return 0;
bool hasArmCode = false;
for ( int i=0; i < h.numRecords; i++ )
{
swap_resource_map_entry(re[i]);
if ( re[i].ulOffset >= filesize || re[i].ulOffset < lowestpos )
return 0;
if ( re[i].fcType == PILOT_RSC_ARMC || re[i].fcType == PILOT_RSC_ARMCL )
hasArmCode = true;
}
return hasArmCode ? 2 : 1;
}
bool isKnownResource(uint32 resId)
{
switch ( resId )
{
case MC4('t', 'F', 'R', 'M'):
case MC4('t', 'B', 'T', 'N'):
case MC4('t', 'C', 'B', 'X'):
case MC4('t', 'F', 'B', 'M'):
case MC4('t', 'F', 'L', 'D'):
case MC4('t', 'g', 'b', 'n'):
case MC4('t', 'G', 'D', 'T'):
case MC4('t', 'g', 'p', 'b'):
case MC4('t', 'g', 'r', 'b'):
case MC4('t', 'G', 'S', 'I'):
case MC4('t', 'L', 'B', 'L'):
case MC4('t', 'L', 'S', 'T'):
case MC4('t', 'P', 'B', 'N'):
case MC4('t', 'P', 'U', 'L'):
case MC4('t', 'P', 'U', 'T'):
case MC4('t', 'R', 'E', 'P'):
case MC4('t', 'S', 'C', 'L'):
case MC4('t', 's', 'l', 'd'):
case MC4('t', 's', 'l', 'f'):
case MC4('t', 'S', 'L', 'T'):
case MC4('t', 'T', 'B', 'L'):
case MC4('T', 'a', 'l', 't'):
case MC4('M', 'B', 'A', 'R'):
case MC4('M', 'E', 'N', 'U'):
case MC4('t', 'S', 'T', 'R'):
case MC4('t', 'S', 'T', 'L'):
case MC4('T', 'b', 'm', 'p'):
case MC4('t', 'b', 'm', 'f'):
case MC4('P', 'I', 'C', 'T'):
case MC4('t', 'v', 'e', 'r'):
case MC4('t', 'A', 'I', 'N'):
case MC4('t', 'a', 'i', 'c'):
case MC4('t', 'A', 'I', 'S'):
case MC4('t', 'A', 'I', 'B'):
case MC4('t', 'a', 'i', 'f'):
case MC4('I', 'C', 'O', 'N'):
case MC4('c', 'i', 'c', 'n'):
case MC4('p', 'r', 'e', 'f'):
case MC4('x', 'p', 'r', 'f'):
return true;
}
return false;
}

View File

@@ -0,0 +1,14 @@
PROC=pilot
IDCS=pilot.idc
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)pilot$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp $(I)expr.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h common.cpp pilot.cpp pilot.hpp

View File

@@ -0,0 +1,912 @@
/*
* 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 <expr.hpp>
#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<ResourceMapEntry> 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,
};

View File

@@ -0,0 +1,148 @@
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* ALL RIGHTS RESERVED.
* E-mail: ig@estar.msk.su
* FIDO: 2:5020/209
*
*/
#ifndef __PILOT_H
#define __PILOT_H
#pragma pack(push, 1)
#include <time.h>
#define PRC_68K "PalmPilot program file (68K)"
#define PRC_ARM "PalmPilot program file (ARM)"
// Regular resources:
#define PILOT_RSC_CODE 0x65646F63L // "code\0\0\0\1" program code
#define PILOT_RSC_PREF 0x66657270L // "pref\0\0\0\0" preferences (not used yet)
#define PILOT_RSC_DATA 0x61746164L // "data\0\0\0\0" image of global data
#define PILOT_RSC_LIBR 0x7262696CL // "libr" SysLib-type shared library code
#define PILOT_RSC_GLIB 0x62694C47L // "GLib" PRC-Tools GLib-type shared library code
#define PILOT_RSC_RLOC 0x636F6C72L // "rloc" PRC-Tools and Multilink relocations
#define PILOT_RSC_ARMC 0x434D5241L // "ARMC" ARM native code
#define PILOT_RSC_ARMCL 0x636D7261L // "armc" ARM native code
// UI resources:
#define PILOT_RSC_MBAR 0x5241424DL // "MBAR" Menu bar
#define PILOT_RSC_MENU 0x554E454DL // "MENU" Menu options
#define PILOT_RSC_ICON 0x4E494174L // "tAIN" Application icon name
#define PILOT_RSC_AIB 0x42494174L // "tAIB" Application icon bitmap
#define PILOT_RSC_AIS 0x53494174L // "tAIS" Application information string
#define PILOT_RSC_ALERT 0x746C6154L // "Talt" Alert
#define PILOT_RSC_BITMAP 0x706D6254L // "Tbmp" Bitmap
#define PILOT_RSC_BUTTON 0x4E544274L // "tBTN" Button
#define PILOT_RSC_CHECK 0x58424374L // "tCBX" Check box
#define PILOT_RSC_FBM 0x4D424674L // "tFBM" Form bitmap
#define PILOT_RSC_FIELD 0x444C4674L // "tFLD" Field
#define PILOT_RSC_FORM 0x4D524674L // "tFRM" Form
#define PILOT_RSC_GADGET 0x54444774L // "tGDT" Gadget
#define PILOT_RSC_GRAFF 0x49534774L // "tGSI" Graffiti Shift
#define PILOT_RSC_LABEL 0x4C424C74L // "tLBL" Label
#define PILOT_RSC_LIST 0x54534C74L // "tLST" List box
#define PILOT_RSC_PUSH 0x4E425074L // "tPBN" Push button
#define PILOT_RSC_POPUPL 0x4C555074L // "tPUL" Popup list
#define PILOT_RSC_POPUPT 0x54555074L // "tPUT" Popup trigger
#define PILOT_RSC_REPEAT 0x50455274L // "tREP" Repeating control
#define PILOT_RSC_SELECT 0x544C5374L // "tSLT" Selector trigger
#define PILOT_RSC_STRING 0x52545374L // "tSTR" String
#define PILOT_RSC_TABLE 0x4C425474L // "tTBL" Table
#define PILOT_RSC_TITLE 0x4C545474L // "tTTL" Title
#define PILOT_RSC_VER 0x72657674L // "tver" Version number string
typedef uchar Byte;
typedef ushort Word;
typedef uint32 DWord;
typedef DWord LocalID;
//
// Header of PRC file:
//
struct DatabaseHdrType
{
Byte name[32]; // name of database
#define PILOT_CREATOR_PILA 0x616C6950L // "Pila"
Word attributes; // database attributes
#define dmHdrAttrResDB 0x0001 // Resource database
#define dmHdrAttrReadOnly 0x0002 // Read Only database
#define dmHdrAttrAppInfoDirty 0x0004 // Set if Application Info block is dirty
// Optionally supported by an App's conduit
#define dmHdrAttrBackup 0x0008 // Set if database should be backed up to PC if
// no app-specific synchronization conduit has
// been supplied.
#define dmHdrAttrOpen 0x8000 // Database not closed properly
Word version; // version of database
DWord creationDate; // creation date of database
DWord modificationDate; // latest modification date
DWord lastBackupDate; // latest backup date
DWord modificationNumber; // modification number of database
LocalID appInfoID; // application specific info
LocalID sortInfoID; // app specific sorting info
DWord type; // database type
#define PILOT_TYPE_APPL 0x6C707061L // "appl"
DWord id; // program id
DWord uniqueIDSeed; // used to generate unique IDs.
// Note that only the low order
// 3 bytes of this is used (in
// RecordEntryType.uniqueID).
// We are keeping 4 bytes for
// alignment purposes.
LocalID nextRecordListID; // local chunkID of next list
Word numRecords; // number of records in this list
};
//
// Each resource has the following entry:
//
struct ResourceMapEntry
{
uint32 fcType;
ushort id;
uint32 ulOffset;
};
// Pilot bitmap format (also format of icon)
struct pilot_bitmap_t
{
ushort cx;
ushort cy;
ushort cbRow;
ushort ff;
ushort ausUnk[4];
};
/*
* code0000[long 0] nBytesAboveA5
* code0000[long 1] nBytesBelowA5
*/
struct code0000_t
{
uint32 nBytesAboveA5;
uint32 nBytesBelowA5;
};
// pref0000
struct pref0000_t
{
ushort flags;
#define sysAppLaunchFlagNewThread 0x0001
#define sysAppLaunchFlagNewStack 0x0002
#define sysAppLaunchFlagNewGlobals 0x0004
#define sysAppLaunchFlagUIApp 0x0008
#define sysAppLaunchFlagSubCall 0x0010
uint32 stack_size;
uint32 heap_size;
};
#pragma pack(pop)
#endif // __PILOT_H

View File

@@ -0,0 +1,216 @@
//
// This file is executed when a PalmPilot program is loaded.
// You may customize it as you wish.
//
// TODO:
// - decompilation of various resource types
// (we don't have any information on the formats)
//
#include <idc.idc>
//-----------------------------------------------------------------------
//
// Process each resource and make some routine tasks
//
static process_segments()
{
auto ea,segname,prefix;
for ( ea=get_first_seg(); ea != BADADDR; ea=get_next_seg(ea) )
{
segname = get_segm_name(ea);
prefix = substr(segname,0,4);
if ( segname == "data0000" )
{
if ( get_wide_dword(ea) == 0xFFFFFFFF )
{
create_dword(ea);
set_cmt(ea,"Loader stores SysAppInfoPtr here", 0);
}
continue;
}
if ( prefix == "TRAP" )
{
create_word(ea);
op_hex(ea,0);
set_cmt(ea,"System trap function code", 0);
continue;
}
if ( prefix == "tSTR" )
{
create_strlit(ea,get_segm_end(ea));
set_cmt(ea,"String resource", 0);
continue;
}
if ( prefix == "tver" )
{
create_strlit(ea,get_segm_end(ea));
set_cmt(ea,"Version number string", 0);
continue;
}
if ( prefix == "tAIN" )
{
create_strlit(ea,get_segm_end(ea));
set_cmt(ea,"Application icon name", 0);
continue;
}
if ( prefix == "pref" )
{
auto flags,cmt;
flags = get_wide_word(ea);
create_word(ea); op_hex(ea,0); set_name(ea,"flags");
#define sysAppLaunchFlagNewThread 0x0001
#define sysAppLaunchFlagNewStack 0x0002
#define sysAppLaunchFlagNewGlobals 0x0004
#define sysAppLaunchFlagUIApp 0x0008
#define sysAppLaunchFlagSubCall 0x0010
cmt = "";
if ( flags & sysAppLaunchFlagNewThread ) cmt = cmt + "sysAppLaunchFlagNewThread\n";
if ( flags & sysAppLaunchFlagNewStack ) cmt = cmt + "sysAppLaunchFlagNewStack\n";
if ( flags & sysAppLaunchFlagNewGlobals) cmt = cmt + "sysAppLaunchFlagNewGlobals\n";
if ( flags & sysAppLaunchFlagUIApp ) cmt = cmt + "sysAppLaunchFlagUIApp\n";
if ( flags & sysAppLaunchFlagSubCall ) cmt = cmt + "sysAppLaunchFlagSubCall";
set_cmt(ea,cmt, 0);
ea = ea + 2;
create_dword(ea); op_hex(ea,0); set_name(ea,"stack_size");
ea = ea + 4;
create_dword(ea); op_hex(ea,0); set_name(ea,"heap_size");
}
}
}
//-----------------------------------------------------------------------
//
// Create a enumeration with system action codes
//
static make_actions()
{
auto id;
id = add_enum(-1,"SysAppLaunchCmd",FF_0NUMD);
if ( id != -1 )
{
set_enum_cmt(id,"Action codes",0);
add_enum_member(id, "sysAppLaunchCmdNormalLaunch", 0, -1);
add_enum_member(id, "sysAppLaunchCmdFind", 1, -1);
add_enum_member(id, "sysAppLaunchCmdGoTo", 2, -1);
add_enum_member(id, "sysAppLaunchCmdSyncNotify", 3, -1);
add_enum_member(id, "sysAppLaunchCmdTimeChange", 4, -1);
add_enum_member(id, "sysAppLaunchCmdSystemReset", 5, -1);
add_enum_member(id, "sysAppLaunchCmdAlarmTriggered", 6, -1);
add_enum_member(id, "sysAppLaunchCmdDisplayAlarm", 7, -1);
add_enum_member(id, "sysAppLaunchCmdCountryChange", 8, -1);
add_enum_member(id, "sysAppLaunchCmdSyncRequest", 9, -1);
add_enum_member(id, "sysAppLaunchCmdSaveData", 10, -1);
add_enum_member(id, "sysAppLaunchCmdInitDatabase", 11, -1);
add_enum_member(id, "sysAppLaunchCmdSyncCallApplication", 12, -1);
set_enum_member_cmt(get_enum_member(id, 0, 0, -1), "Normal Launch", 1);
set_enum_member_cmt(get_enum_member(id, 1, 0, -1), "Find string", 1);
set_enum_member_cmt(get_enum_member(id, 2, 0, -1), "Launch and go to a particular record", 1);
set_enum_member_cmt(get_enum_member(id, 3, 0, -1),
"Sent to apps whose databases changed\n"
"during HotSync after the sync has\n"
"been completed", 1);
set_enum_member_cmt(get_enum_member(id, 4, 0, -1), "The system time has changed", 1);
set_enum_member_cmt(get_enum_member(id, 5, 0, -1), "Sent after System hard resets", 1);
set_enum_member_cmt(get_enum_member(id, 6, 0, -1), "Schedule next alarm", 1);
set_enum_member_cmt(get_enum_member(id, 7, 0, -1), "Display given alarm dialog", 1);
set_enum_member_cmt(get_enum_member(id, 8, 0, -1), "The country has changed", 1);
set_enum_member_cmt(get_enum_member(id, 9, 0, -1), "The \"HotSync\" button was pressed", 1);
set_enum_member_cmt(get_enum_member(id, 10, 0, -1),
"Sent to running app before\n"
"sysAppLaunchCmdFind or other\n"
"action codes that will cause data\n"
"searches or manipulation", 1);
set_enum_member_cmt(get_enum_member(id, 11, 0, -1),
"Initialize a database; sent by\n"
"DesktopLink server to the app whose\n"
"creator ID matches that of the database\n"
"created in response to the \"create db\" request", 1);
set_enum_member_cmt(get_enum_member(id, 12, 0, -1),
"Used by DesktopLink Server command\n"
"\"call application\"", 1);
}
}
//-----------------------------------------------------------------------
//
// Create a enumeration with event codes
//
static make_events()
{
auto id;
id = add_enum(-1,"events",FF_0NUMD);
if ( id != -1 )
{
set_enum_cmt(id,"Event codes",0);
add_enum_member(id, "nilEvent", 0, -1);
add_enum_member(id,"penDownEvent", 1, -1);
add_enum_member(id,"penUpEvent", 2, -1);
add_enum_member(id,"penMoveEvent", 3, -1);
add_enum_member(id,"keyDownEvent", 4, -1);
add_enum_member(id,"winEnterEvent", 5, -1);
add_enum_member(id,"winExitEvent", 6, -1);
add_enum_member(id,"ctlEnterEvent", 7, -1);
add_enum_member(id,"ctlExitEvent", 8, -1);
add_enum_member(id,"ctlSelectEvent", 9, -1);
add_enum_member(id,"ctlRepeatEvent", 10, -1);
add_enum_member(id,"lstEnterEvent", 11, -1);
add_enum_member(id,"lstSelectEvent", 12, -1);
add_enum_member(id,"lstExitEvent", 13, -1);
add_enum_member(id,"popSelectEvent", 14, -1);
add_enum_member(id,"fldEnterEvent", 15, -1);
add_enum_member(id,"fldHeightChangedEvent", 16, -1);
add_enum_member(id,"fldChangedEvent", 17, -1);
add_enum_member(id,"tblEnterEvent", 18, -1);
add_enum_member(id,"tblSelectEvent", 19, -1);
add_enum_member(id,"daySelectEvent", 20, -1);
add_enum_member(id,"menuEvent", 21, -1);
add_enum_member(id,"appStopEvent", 22, -1);
add_enum_member(id,"frmLoadEvent", 23, -1);
add_enum_member(id,"frmOpenEvent", 24, -1);
add_enum_member(id,"frmGotoEvent", 25, -1);
add_enum_member(id,"frmUpdateEvent", 26, -1);
add_enum_member(id,"frmSaveEvent", 27, -1);
add_enum_member(id,"frmCloseEvent", 28, -1);
add_enum_member(id,"tblExitEvent", 29, -1);
}
}
//-----------------------------------------------------------------------
static main()
{
process_segments();
make_actions();
make_events();
}
//-----------------------------------------------------------------------
#ifdef __undefined_symbol__
// WE DO NOT USE IDC HOTKEYS, JUST SIMPLE KEYBOARD MACROS
// (see IDA.CFG, macro Alt-5 for mc68k)
//-----------------------------------------------------------------------
//
// Register Ctrl-R as a hotkey for "make offset from A5" command
// (not used, simple keyboard macro is used instead, see IDA.CFG)
//
// There is another (manual) way to convert an operand to an offset:
// - press Ctrl-R
// - enter "A5BASE"
// - press Enter
//
static setup_pilot()
{
auto h0,h1;
h0 = "Alt-1";
h1 = "Alt-2";
add_idc_hotkey(h0,"a5offset0");
add_idc_hotkey(h1,"a5offset1");
msg("Use %s to convert the first operand to an offset from A5\n",h0);
msg("Use %s to convert the second operand to an offset from A5\n",h1);
}
static a5offset0(void) { op_plain_offset(get_screen_ea(),0,get_name_ea_simple("A5BASE")); }
static a5offset1(void) { op_plain_offset(get_screen_ea(),1,get_name_ea_simple("A5BASE")); }
#endif // 0

115
idasdk76/ldr/qnx/lmf.h Normal file
View File

@@ -0,0 +1,115 @@
/*
* lmf.h Load Module Format
*
* Copyright by QNX Software Systems Limited 1990-1993. All rights reserved.
*/
#ifndef __LMF_H_INCLUDED
#define __LMF_H_INCLUDED
#pragma pack(push, 1)
struct _lmf_header { /* This preceeds each record defined below */
char rec_type,
zero1;
short unsigned data_nbytes,
spare;
} ;
struct _lmf_definition { /* Must be first record in load file */
short unsigned version_no,
cflags,
cpu,
fpu,
code_index,
stack_index,
heap_index,
argv_index,
zero1[4];
int32 code_offset,
stack_nbytes,
heap_nbytes,
flat_offset,
unmapped_size,
zero2;
/* Variable length field of n longs starts here */
} ;
struct _lmf_data { /* Code or data record to load into memory */
short segment_index;
uint32 offset;
/* Variable length field of n bytes starts here */
} ;
struct _lmf_seg_fixup { /* Segment fixup record */
struct fixups {
short unsigned fixup_seg_index;
int32 fixup_offset;
} data[1]; /* May be n of these */
} ;
struct _lmf_linear_fixup { /* Segment fixup record */
short unsigned fixup_seg_index;
int32 fixup_offset[1];
} ;
struct _lmf_eof {
char zero[6];
} ;
struct _lmf_resource {
short unsigned resource_type; /* 0 - usage messages */
short unsigned zero[3];
} ;
/*
* Record types
*/
#define _LMF_DEFINITION_REC 0
#define _LMF_COMMENT_REC 1
#define _LMF_DATA_REC 2
#define _LMF_FIXUP_SEG_REC 3
#define _LMF_FIXUP_80X87_REC 4
#define _LMF_EOF_REC 5
#define _LMF_RESOURCE_REC 6
#define _LMF_ENDDATA_REC 7
#define _LMF_FIXUP_LINEAR_REC 8
#define _LMF_PHRESOURCE 9 // A widget resource for photon apps
/*
* Bit defitions for lh_code_flags
*/
#define _PCF_LONG_LIVED 0x0001
#define _PCF_32BIT 0x0002
#define _PCF_PRIVMASK 0x000c /* Two bits */
#define _PCF_FLAT 0x0010
#define _PCF_NOSHARE 0x0020
/*
* The top 4 bits of the segment sizes
*/
#define _LMF_CODE 0x2
#define MIN_SEGMENTS 1 // usually 2 or 4
#define MAX_SEGMENTS 4
struct ex_header {
struct _lmf_header lmf_header;
struct _lmf_definition lmf_definition;
uint32 segsizes[MAX_SEGMENTS];
};
#pragma pack(pop)
#endif

13
idasdk76/ldr/qnx/makefile Normal file
View File

@@ -0,0 +1,13 @@
PROC=qnx
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)qnx$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h lmf.h qnx.cpp

372
idasdk76/ldr/qnx/qnx.cpp Normal file
View File

@@ -0,0 +1,372 @@
/*
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,
};

25
idasdk76/ldr/readme.txt Normal file
View File

@@ -0,0 +1,25 @@
This directory contains file loaders.
aif ARM Image File
amiga Amige Hunk File
aof ARM Object File
aout a.out
dos MS DOS File
dump Memory Dump File
geos GEOS File
hex Intel/Motorola HEX File
hpsom HP SOM
intelomf Intel Object File
javaldr Java Class Loader
mas Macro Assembler
nlm Netware Loader Module
os9 FLEX/9
pef Portable Executable Format (MAC)
pilot Palm Pilot
qnx Qnx
rt11 RT/11
w32run Watcom RUN32
Compile them as usual (see how to compile processor modules, for example)

View File

@@ -0,0 +1,14 @@
PROC=rt11
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)rt11$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../../module/pdp11/pdp_ml.h ../idaldr.h \
rt11.cpp

351
idasdk76/ldr/rt11/rt11.cpp Normal file
View File

@@ -0,0 +1,351 @@
/*
* Interactive disassembler (IDA)
* Copyright (c) 1990-98 by Ilfak Guilfanov.
* E-mail: ig@datarescue.com
* RT11 executable Loader.
* Copyright (c) 1995-2006 by Iouri Kharon.
* E-mail: yjh@styx.cabel.net
*
* ALL RIGHTS RESERVED.
*
*/
/*
L O A D E R for RT11 .sav-files
*/
#include "../idaldr.h"
#include "../../module/pdp11/pdp_ml.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 *filename)
{
uint64 fsize = qlsize(li);
if ( (fsize % 512) || !fsize )
return 0;
qlseek(li, 040);
ushort tmp;
lread2bytes(li, &tmp, 0);
if ( tmp > fsize || (tmp & 1) || tmp < 0400 )
return 0;
lread2bytes(li, &tmp, 0);
if ( tmp > fsize )
return 0;
qlseek(li, 050);
lread2bytes(li, &tmp, 0);
if ( tmp & 1 || tmp > fsize )
return 0;
// 20.11.01, ig
// got tired of too many false positives
// now we'll check the file extension
const char *ext = get_file_ext(filename);
if ( ext == NULL || stricmp(ext, "sav") != 0 )
return 0;
*fileformatname = "RT11 (pdp11) sav-file";
*processor = "pdp11";
return f_LOADER;
}
//--------------------------------------------------------------------------
static void loadchunk(
linput_t *li,
ea_t ea,
size_t size,
ea_t base,
int32 fpos,
const char *sclass)
{
qoff64_t p = qltell(li);
file2base(li, fpos, ea, ea+size, FILEREG_PATCHABLE);
add_segm(base, ea, ea+size, NULL, sclass);
qlseek(li, p);
}
//--------------------------------------------------------------------------
//
// load file into the database.
//
void idaapi load_file(linput_t *li, ushort /*neflag*/, const char * /*fileformatname*/)
{
set_processor_type("pdp11", SETPROC_LOADER);
pdp_ml_t *ml = NULL;
netnode *ml_ovrtrans = NULL;
if ( !pdp11_module_t::get_ml_ptr(&ml, &ml_ovrtrans)
|| !ml
|| !ml_ovrtrans )
{
error("Internal error in loader<->module link");
}
//
// Find out asect section and load it
//
int i;
segment_t s;
s.start_ea = to_ea(inf_get_baseaddr(), 0);
qlseek(li, 040);
ushort startIP, topPrg, svrEnd, ovt;
lread(li, &startIP, sizeof(ushort));
lread(li, &ml->asect_top, sizeof(ushort));
if ( (startIP & 1) || startIP < 0400 )
startIP = 0;
else
inf_set_start_ip(startIP);
qlseek(li, 050);
lread(li, &topPrg, sizeof(ushort));
if ( topPrg & 1 || (uint64)topPrg > qlsize(li) )
topPrg = 0;
if ( topPrg > 01000
&& ml->asect_top < (topPrg - 01000 )
&& ml->asect_top > 0400 )
{
svrEnd = ml->asect_top;
if ( ml->asect_top > 01000 )
svrEnd = 01000;
}
else
{
ml->asect_top = svrEnd = 01000;
}
if ( startIP && ml->asect_top > startIP )
{
svrEnd = 01000;
if ( svrEnd > startIP )
svrEnd = startIP;
s.end_ea = s.start_ea + svrEnd;
}
else
{
s.end_ea = s.start_ea + ml->asect_top;
}
inf_set_start_cs(inf_get_baseaddr());
file2base(li, 0, s.start_ea, s.end_ea, FILEREG_PATCHABLE);
s.type = SEG_IMEM;
s.sel = find_selector(inf_get_baseaddr());
add_segm_ex(&s, "asect", NULL, ADDSEG_NOSREG);
if ( inf_get_start_ip() != BADADDR )
op_plain_offset(s.start_ea + 040, 0, s.start_ea);
else
create_word(s.start_ea + 040, 2);
create_word(s.start_ea + 042, 2); // begin stack value
create_word(s.start_ea + 044, 2); // JSW
create_word(s.start_ea + 046, 2); // load USR address
create_word(s.start_ea + 050, 2); // top programm loading address
ushort begovrtbl = get_word(s.start_ea + 064);
ea_t ei;
for ( ei = s.start_ea; ei < s.start_ea + 040; ei += 2 )
{
if ( get_word(ei) )
{
create_word(ei, 2);
}
else
{
del_value(ei);
del_value(ei+1);
}
}
for ( ei = s.start_ea + 052; ei < s.end_ea; ei += 2 )
{
if ( get_word(ei) )
{
create_word(ei, 2);
}
else
{
del_value(ei);
del_value(ei+1);
}
}
ovt = ml->asect_top;
if ( s.end_ea != (s.start_ea + ml->asect_top) )
{
loadchunk(li, s.end_ea, ml->asect_top - svrEnd, inf_get_baseaddr(), svrEnd, "USER");
s.end_ea += (ml->asect_top - svrEnd);
ml->asect_top = svrEnd;
}
if ( get_word(s.start_ea + 044) & 01000 )
{
if ( begovrtbl == 0 )
{
static const ushort chkold[] = { 010046, 010146, 010246, 0421, 010001, 062701 };
qlseek(li, ovt);
ushort temp;
for ( i = 0; i < sizeof(chkold)/2; i++ )
{
lread(li, &temp, sizeof(ushort));
if ( temp != chkold[i] )
goto nons;
}
lread(li, &temp, sizeof(ushort));
if ( temp != ovt + 076 )
goto nons;
qlseek(li, ovt + 0100);
lread(li, &temp, sizeof(ushort));
if ( temp != 0104376 )
goto nons;
lread(li, &temp, sizeof(ushort));
if ( temp != 0175400 )
{
nons:
warning("OLD-style overlay not implemented.");
goto stdload;
}
begovrtbl = ovt + 0104;
warning("Loader overlay v3 is not fully tested.");
}
else
{
qlseek(li, begovrtbl);
}
ushort root_top;
lread(li, &root_top, sizeof(ushort));
if ( root_top == 0 || (root_top & 1) || root_top >= topPrg )
{
warning("Illegal overlay structure. Not implemented.");
goto stdload;
}
msg("loading overlay program...\n");
netnode temp; // temporary array for overlay start addresses
temp.create();
// load root module at the end of asect (& USER)
inf_set_start_cs(inf_get_baseaddr()+2);
loadchunk(li, s.end_ea += 0x20, root_top - ovt, inf_get_start_cs(), ovt, "ROOT");
add_segment_translation(inf_get_start_cs()<<4,
inf_get_baseaddr()<<4); // translate to asect
ushort loadAddr = root_top, fileBlock, ovrsizeW,
oldBase = 0, numOvr = 0, numSeg = 0;
char name[8] = "ov";
for ( i = 6; loadAddr != 04537; begovrtbl += 6, i += 6 )
{
if ( loadAddr != oldBase )
{
oldBase = loadAddr;
++numOvr;
numSeg = 1;
}
else
{
++numSeg;
}
qsnprintf(&name[2], sizeof(name)-2, "%02d_%02d", numOvr, numSeg);
lread(li, &fileBlock, sizeof(ushort));// file block number
lread(li, &ovrsizeW, sizeof(ushort)); // segment size in words
ovrsizeW <<= 1; // in bytes
uint32 ovrstart = (inf_get_max_ea() & ~0xF) + (loadAddr & 0xF) + 0x10;
uint32 sel_l = ushort((ovrstart >> 4) - (loadAddr >> 4));
loadchunk(li, ovrstart+2, ovrsizeW-2, sel_l, fileBlock*512L+2, "OVR");
add_segment_translation(sel_l<<4, inf_get_baseaddr()<<4); // translate to asect
add_segment_translation(sel_l<<4, inf_get_start_cs()<<4); // translate to main
segment_t *s2 = getseg(ovrstart+2);
s2->ovrname = ((uint32)numOvr << 16) | numSeg;
set_segm_name(s2, name);
temp.altset(i, ovrstart - loadAddr);
lread(li, &loadAddr, sizeof(ushort)); // segment loading address
}
// Entry points loading
ml->ovrcallbeg = begovrtbl;
for ( ; loadAddr == 04537; begovrtbl += 8 )
{
ushort ovrentry, ovrind, ovraddr;
lread(li, &ovrentry, sizeof(ushort)); // overlay entry-
lread(li, &ovrind, sizeof(ushort)); // index+6 in the segments table
lread(li, &ovraddr, sizeof(ushort)); // segment entry point
ml_ovrtrans->altset(begovrtbl, temp.altval(ovrind) + ovraddr);
lread(li, &loadAddr, sizeof(ushort)); // next jsr R5,@#
}
ml->ovrcallend = begovrtbl - 8;
temp.kill();
ea_t base = s.end_ea - ovt + ml->ovrcallbeg;
i = ml->ovrcallend - ml->ovrcallbeg + 8;
set_segm_start(s.end_ea, base+i, SEGMOD_KILL);
set_segm_name(getseg(base+i), "main");
loadchunk(li, base -= 0x10, i, inf_get_baseaddr()+1, ml->ovrcallbeg, "TBL");
ml->ovrtbl_base = (uint32)to_ea(inf_get_baseaddr()+1, 0);
set_segm_name(getseg(base), "ov_call");
char labname[17] = "cl_";
for ( int j = 0; j < i; j += 8 )
{
uint32 trans = (uint32)ml_ovrtrans->altval(ml->ovrcallbeg+j);
qstring sname;
get_segm_name(&sname, getseg(trans));
labname[3+7] = '\0';
if ( sname == &labname[3] )
{
++numSeg;
}
else
{
numSeg = 1;
qstrncpy(&labname[3], sname.c_str(), sizeof(labname)-3);
}
qsnprintf(&labname[3+7], sizeof(labname)-3-7, "_en%02d", numSeg);
auto_make_code(trans);
set_name(trans, &labname[3], SN_IDBENC);
set_name(base + j, labname, SN_IDBENC);
create_word(base + j, 2*3);
op_plain_offset(base + j + 6, 0, get_segm_base(getseg(trans)));
}
}
else
{
//
// Load regular file/load root of overlay
//
stdload:
loadchunk(li, s.end_ea, qlsize(li) - ovt, inf_get_baseaddr(), ovt, "CODE");
}
ml_ovrtrans->altset(n_asect, ml->asect_top);
ml_ovrtrans->altset(n_ovrbeg, ml->ovrcallbeg);
ml_ovrtrans->altset(n_ovrend, ml->ovrcallend);
ml_ovrtrans->altset(n_asciiX, false);
ml_ovrtrans->altset(n_ovrbas, ml->ovrtbl_base);
}
//----------------------------------------------------------------------
//
// 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,
};

View File

@@ -0,0 +1,162 @@
# Sample archive loader: TAR file format
# Feel free to improve it, this is just a sample
import os
import os.path
import tarfile
import shutil
import tempfile
import idaapi
from ida_kernwin import Choose
# -----------------------------------------------------------------------
def accept_file(li, filename):
"""
Check input file format.
This function will be called one or more times depending on the result value.
@param li: a file-like object which can be used to access the input data
@param filename: name of the file, if it is an archive member name then the actual file doesn't exist
@return: 0 - no more supported formats
string "name" - format name to display in the chooser dialog
dictionary {
'format': "name",
'options': integer,
'flags': integer
}
options: should be 1,
if ORed with ACCEPT_ARCHIVE then it is an archive loader
if ORed with ACCEPT_CONTINUE then this function will be called another time
if ORed with ACCEPT_FIRST then indicates preferred format
loader_flags: see GENFLG_
"""
li.seek(0)
try:
t = tarfile.open(fileobj=li, mode='r|*')
t.close()
(_, ext) = os.path.splitext(filename)
if ext not in (".tar", ".tgz", "tar.gz"):
return 0
return {'format': "TAR archive",
'options': 1 | idaapi.ACCEPT_ARCHIVE}
except Exception:
pass
return 0
# -----------------------------------------------------------------------
def _read_whole_file(li):
li.seek(0)
return li.read(li.size())
# -----------------------------------------------------------------------
def _tmpnam():
(h, n) = tempfile.mkstemp()
os.close(h)
return n
# -----------------------------------------------------------------------
class TarMemberChoose(Choose):
"""
TAR archive members selection chooser
"""
def __init__(self, archive, items):
title = "Archive: " + archive
Choose.__init__(
self,
title,
[["File name", Choose.CHCOL_PATH | 60],
["Size", Choose.CHCOL_DEC | 10]],
icon=-1, y1=-2,
flags = Choose.CH_MODAL | Choose.CH_NOIDB)
self.items = items
def OnGetLine(self, n):
return [self.items[n].name, str(self.items[n].size)]
def OnGetSize(self):
return len(self.items)
# -----------------------------------------------------------------------
def process_archive(li, archive, defmember, neflags, formatname):
"""
Display list of archive members and let the user select one.
Extract the selected archive member into a temporary file.
@param li: a file-like object which can be used to access the input data
@param archive: name of archive
@param defmember: extract the specified member
@param neflags: options selected by the user, see loader.hpp
@param formatname: name of type of the file
@return: '' cancelled by the user
string error message
dictionary {
'temp_file': string,
'module_name': string,
'neflags': integer
}
temp_file: name of the file with the extracted archive member
module_name: name of the extracted archive member
neflags: options selected by the user, see loader.hpp
"""
li.seek(0)
try:
t = tarfile.open(fileobj=li, mode='r|*')
except tarfile.TarError as e:
return str(e)
# list of archive members,
members = t.getmembers()
t.close()
# we are interested in regular files only
items = [members[i] for i in range(0, len(members))]
# if default archive member is specified
if defmember:
for m in items:
if os.path.basename(m.name) == defmember:
selected_item = m
break
else:
return "Unknown TAR archive default member: %s" % defmember
else:
chooser = TarMemberChoose(archive, items)
code = chooser.Show(True)
if code == Choose.NO_SELECTION:
return "" # user canceled
selected_item = items[code]
# construct archive member name
member_name = os.path.basename(selected_item.name)
module_name = os.path.join(os.path.dirname(archive), member_name)
# file for archive member
workfile = _tmpnam()
# extract member
# there is a bug reported in 2010 year but not fixed yet:
# http://bugs.python.org/issue10436
li.seek(0)
buf = _read_whole_file(li)
(h, workfile_tar) = tempfile.mkstemp()
os.write(h, buf)
os.close(h)
t = tarfile.open(name=workfile_tar, mode='r:*')
tarinfo = t.getmember(selected_item.name)
f_in = t.extractfile(tarinfo)
f_out = open(workfile, 'wb')
shutil.copyfileobj(f_in, f_out)
f_out.close()
f_in.close()
t.close()
os.unlink(workfile_tar)
return {'temp_file': workfile, 'module_name': module_name}

View File

@@ -0,0 +1,74 @@
/*
Sample IDC loader: load BIOS image
Feel free to improve it, this is just a sample
*/
#include <idc.idc>
//--------------------------------------------------------------------------
// Verify the input file format
// li - loader_input_t object. it is positioned at the file start
// Returns: if the input file is not recognized
// return 0
// else
// return object with 2 attributes:
// format: description of the file format
// options:1 or ACCEPT_FIRST. it is ok not to set this attribute.
// or return a string designating the format name
static accept_file(li, filename)
{
if ( li.size() > 0x10000 ) // we support max 64K images
return 0;
li.seek(-16, SEEK_END);
if ( li.getc() != 0xEA ) // jmp?
return 0;
li.seek(-2, SEEK_END);
if ( (li.getc() & 0xF0) != 0xF0 ) // reasonable computer type?
return 0;
auto buf;
li.seek(-11, SEEK_END);
li.read(&buf, 9);
// 06/03/08
if ( buf[2] != "/" || buf[5] != "/" || buf[8] != "\x00" )
return 0;
// accept the file
auto res = object();
res.format = "BIOS Image"; // description of the file format
return res;
}
//--------------------------------------------------------------------------
// Load the file into the database
// li - loader_input_t object. it is positioned at the file start
// neflags - combination of NEF_... bits describing how to load the file
// probably NEF_MAN is the most interesting flag that can
// be used to select manual loading
// format - description of the file format
// Returns: 1 - means success, 0 - failure
static load_file(li, neflags, format)
{
set_processor_type("metapc", SETPROC_LOADER);
auto base = 0xF000;
auto start = base << 4;
auto size = li.size();
// copy bytes to the database
loadfile(li, 0, base<<4, size);
// create a segment
add_segm_ex(start, start+size, base, 0, saRelPara, scPub, ADDSEG_NOSREG);
// set the entry registers
set_inf_attr(INF_START_IP, size-16);
set_inf_attr(INF_START_CS, base);
return 1;
}

View File

@@ -0,0 +1,114 @@
import sys
import idaapi
import idc
# -----------------------------------------------------------------------
def accept_file(li, filename):
# ignore any trailer; align on 64KB boundary
size = li.size()
if (size & 0xFFF) != 0:
size &= ~0xFFFF
if size < 16:
return 0
# check the code at F000:FFF0
li.seek(size-16);
jump = li.read(16)
# skip any nops
while jump[:1] == b'\x90':
jump = jump[1:]
# skip wbinvd
if jump.startswith(b'\x0F\x09'):
jump = jump[2:]
_byte = ord if sys.version_info.major < 3 else lambda t: t
# is it a jump?
if (
jump.startswith(b'\xEA') # jmp ptr16:16 EA oo oo ss ss
and len(jump) >= 5
and 0xF0 <= _byte(jump[4]) <= 0xFE # segment should be above F000
) or (
jump.startswith(b'\xE9') # jmp rel16 E9 ll hh
and len(jump) >= 3
# and (_byte(jump[2]) & 0x80) != 0 # jump backwards
) or (
jump.startswith(b'\xEB') # jmp rel8 EB dd
and len(jump) >= 2
and (_byte(jump[1]) & 0x80) != 0 # jump backwards
):
return {'format': "BIOS Image", 'processor':'metapc'} # accept the file
return 0
def myAddSeg(startea, endea, base, use32, name, clas):
s = idaapi.segment_t()
s.start_ea = startea
s.end_ea = endea
s.sel = idaapi.setup_selector(base)
s.bitness = use32
s.align = idaapi.saRelPara
s.comb = idaapi.scPub
idaapi.add_segm_ex(s, name, clas, idaapi.ADDSEG_NOSREG|idaapi.ADDSEG_OR_DIE)
# -----------------------------------------------------------------------
def load_file(li, neflags, format):
chunksize = 0x10000
base = 0xF000
start = base << 4;
size = li.size()
if (size & 0xFFF) != 0:
size &= ~0xFFFF
offs = size - chunksize
idaapi.set_processor_type("metapc", idaapi.SETPROC_LOADER)
if size < chunksize:
offs = 0
start += (chunksize - size)
chunksize = size
# make E and F segments for real-mode part
myAddSeg(start, start+chunksize, base, 0, "BIOS_F", "CODE")
li.file2base(offs, start, start+chunksize, 1)
if offs > 0 and base > 0xE000:
base -= 0x1000
start -= chunksize
offs -= chunksize
myAddSeg(start, start+chunksize, base, 0, "BIOS_%X" % (base>>12), "CODE")
li.file2base(offs, start, start+chunksize, 1)
# set default ds to point to the current segment
idc.set_default_sreg_value(start, "ds", base)
if offs > 0:
# file is bigger than 128KB
# make a flat 32-bit segment for the flash alias area
start = (-size) & 0xFFFFFFFF # place it so that it ends at 4GB
chunksize = size
if not idc.__EA64__:
chunksize -= 2 # truncate last two bytes to avoid address space overlap
# map the whole file
offs = 0
base = 0
myAddSeg(start, start+chunksize, base, 1, "BIOS_FLASH", "CODE")
li.file2base(offs, start, start+chunksize, 1)
# set the entry registers to F000:FFF0
idc.set_inf_attr(idc.INF_START_IP, 0xFFF0)
idc.set_inf_attr(idc.INF_START_CS, 0xF000)
# turn off "Convert 32bit instruction operand to offset", too many false positives in high areas
idc.set_inf_attr(idc.INF_AF, idc.get_inf_attr(idc.INF_AF) & ~idc.AF_IMMOFF)
# turn off "Create function tails"
idc.set_inf_attr(idc.INF_AF, idc.get_inf_attr(idc.INF_AF) & ~idc.AF_FTAIL)
return 1
# -----------------------------------------------------------------------
def move_segm(frm, to, sz, fileformatname):
idc.warning("move_segm(from=%s, to=%s, sz=%d, formatname=%s" % (hex(frm), hex(to), sz, fileformatname))
return 0

View File

@@ -0,0 +1,600 @@
//
// Loader for HP-UX PA-Risc core dumps that are not ELF
//
// Avi Cohen Stuart avi.cohenstuart@infor.com
// August 2010
//
// The core image exists of sections defined by the types below
//struct corehead {
// int type;
// uint space;
// uint addr;
// uint len;
//};
//
// Analysing a core file can be tedious without the binary that
// caused the crash.
//
// Note that the CORE_PROC section contains information about the
// state of the process. See the proc_info in /usr/include/sys/core.h on
// a HP-UX PA-Risc machine.
//
#include <idc.idc>
#define CORE_NONE 0x00000000 /* reserved for future use */
#define CORE_FORMAT 0x00000001 /* core version */
#define CORE_KERNEL 0x00000002 /* kernel version */
#define CORE_PROC 0x00000004 /* per process information */
#define CORE_TEXT 0x00000008 /* reserved for future use */
#define CORE_DATA 0x00000010 /* data of the process */
#define CORE_STACK 0x00000020 /* stack of the process */
#define CORE_SHM 0x00000040 /* reserved for future use */
#define CORE_MMF 0x00000080 /* reserved for future use */
#define CORE_EXEC 0x00000100 /* exec information */
#define CORE_ANON_SHMEM 0x00000200 /* anonymous shared memory */
static Structures_0(id) {
auto mid;
id = add_struc(-1,"__reg32_t",0);
id = add_struc(-1,"__reg64_t",0);
id = add_struc(-1,"__save_state::$8C0FCFCC2B9ACB495244C4B504AA9783",1);
id = add_struc(-1,"fp_int_block_t",0);
id = add_struc(-1,"fp_dbl_block_t",0);
id = add_struc(-1,"__save_state::$F0F3A0B47411777C5961C26FBCE8E4DA",1);
id = add_struc(-1,"__ss_narrow_t",0);
id = add_struc(-1,"save_state_t",0);
id = add_struc(-1,"aux_id",0);
id = add_struc(-1,"som_exec_auxhdr",0);
id = add_struc(-1,"proc_exec::$733C094BD5627056653FFCFE6E9DB4EB",0);
id = add_struc(-1,"proc_info",0);
id = add_struc(-1,"shl_descriptor",0);
id = add_struc(-1,"proc_exec",0);
id = get_struc_id("__reg32_t");
mid = add_struc_member(id,"ss_reserved", 0X0, 0x20000400, -1, 8);
mid = add_struc_member(id,"ss_gr1_hi", 0X8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr1_lo", 0XC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_rp_hi", 0X10, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_rp_lo", 0X14, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr3_hi", 0X18, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr3_lo", 0X1C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr4_hi", 0X20, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr4_lo", 0X24, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr5_hi", 0X28, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr5_lo", 0X2C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr6_hi", 0X30, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr6_lo", 0X34, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr7_hi", 0X38, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr7_lo", 0X3C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr8_hi", 0X40, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr8_lo", 0X44, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr9_hi", 0X48, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr9_lo", 0X4C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr10_hi", 0X50, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr10_lo", 0X54, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr11_hi", 0X58, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr11_lo", 0X5C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr12_hi", 0X60, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr12_lo", 0X64, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr13_hi", 0X68, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr13_lo", 0X6C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr14_hi", 0X70, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr14_lo", 0X74, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr15_hi", 0X78, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr15_lo", 0X7C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr16_hi", 0X80, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr16_lo", 0X84, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr17_hi", 0X88, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr17_lo", 0X8C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr18_hi", 0X90, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr18_lo", 0X94, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr19_hi", 0X98, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr19_lo", 0X9C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr20_hi", 0XA0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr20_lo", 0XA4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr21_hi", 0XA8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr21_lo", 0XAC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr22_hi", 0XB0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr22_lo", 0XB4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg3_hi", 0XB8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg3_lo", 0XBC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg2_hi", 0XC0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg2_lo", 0XC4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg1_hi", 0XC8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg1_lo", 0XCC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg0_hi", 0XD0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg0_lo", 0XD4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_dp_hi", 0XD8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_dp_lo", 0XDC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_ret0_hi", 0XE0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_ret0_lo", 0XE4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_ret1_hi", 0XE8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_ret1_lo", 0XEC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sp_hi", 0XF0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sp_lo", 0XF4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr31_hi", 0XF8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr31_lo", 0XFC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr11_hi", 0X100, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr11_lo", 0X104, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_head_hi", 0X108, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_head_lo", 0X10C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_head_hi", 0X110, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_head_lo", 0X114, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_tail_hi", 0X118, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_tail_lo", 0X11C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_tail_hi", 0X120, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_tail_lo", 0X124, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr15_hi", 0X128, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr15_lo", 0X12C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr19_hi", 0X130, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr19_lo", 0X134, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr20_hi", 0X138, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr20_lo", 0X13C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr21_hi", 0X140, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr21_lo", 0X144, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr22_hi", 0X148, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr22_lo", 0X14C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cpustate_hi", 0X150, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cpustate_lo", 0X154, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr4_hi", 0X158, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr4_lo", 0X15C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr0_hi", 0X160, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr0_lo", 0X164, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr1_hi", 0X168, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr1_lo", 0X16C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr2_hi", 0X170, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr2_lo", 0X174, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr3_hi", 0X178, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr3_lo", 0X17C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr5_hi", 0X180, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr5_lo", 0X184, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr6_hi", 0X188, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr6_lo", 0X18C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr7_hi", 0X190, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr7_lo", 0X194, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr0_hi", 0X198, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr0_lo", 0X19C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr8_hi", 0X1A0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr8_lo", 0X1A4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr9_hi", 0X1A8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr9_lo", 0X1AC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr10_hi", 0X1B0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr10_lo", 0X1B4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr12_hi", 0X1B8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr12_lo", 0X1BC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr13_hi", 0X1C0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr13_lo", 0X1C4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr24_hi", 0X1C8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr24_lo", 0X1CC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr25_hi", 0X1D0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr25_lo", 0X1D4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr26_hi", 0X1D8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr26_lo", 0X1DC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr27_hi", 0X1E0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr27_lo", 0X1E4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_reserved2", 0X1E8, 0x20000400, -1, 16);
mid = add_struc_member(id,"ss_oldcksum", 0X1F8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_newcksum", 0X1FC, 0x20000400, -1, 4);
id = get_struc_id("__reg64_t");
mid = add_struc_member(id,"ss_reserved", 0X0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr1", 0X8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_rp", 0X10, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr3", 0X18, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr4", 0X20, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr5", 0X28, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr6", 0X30, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr7", 0X38, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr8", 0X40, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr9", 0X48, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr10", 0X50, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr11", 0X58, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr12", 0X60, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr13", 0X68, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr14", 0X70, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr15", 0X78, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr16", 0X80, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr17", 0X88, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr18", 0X90, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr19", 0X98, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr20", 0XA0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr21", 0XA8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr22", 0XB0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_arg3", 0XB8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_arg2", 0XC0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_arg1", 0XC8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_arg0", 0XD0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_dp", 0XD8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_ret0", 0XE0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_ret1", 0XE8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sp", 0XF0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_gr31", 0XF8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr11", 0X100, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_pcoq_head", 0X108, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_pcsq_head", 0X110, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_pcoq_tail", 0X118, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_pcsq_tail", 0X120, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr15", 0X128, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr19", 0X130, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr20", 0X138, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr21", 0X140, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr22", 0X148, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cpustate", 0X150, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr4", 0X158, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr0", 0X160, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr1", 0X168, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr2", 0X170, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr3", 0X178, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr5", 0X180, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr6", 0X188, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_sr7", 0X190, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr0", 0X198, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr8", 0X1A0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr9", 0X1A8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr10", 0X1B0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr12", 0X1B8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr13", 0X1C0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr24", 0X1C8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr25", 0X1D0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr26", 0X1D8, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_cr27", 0X1E0, 0x30000400, -1, 8);
mid = add_struc_member(id,"ss_reserved2", 0X1E8, 0x30000400, -1, 16);
mid = add_struc_member(id,"ss_oldcksum", 0X1F8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_newcksum", 0X1FC, 0x20000400, -1, 4);
id = get_struc_id("__save_state::$8C0FCFCC2B9ACB495244C4B504AA9783");
mid = add_struc_member(id,"ss_64", 0X0, 0x60000400, get_struc_id("__reg64_t"), 512);
mid = add_struc_member(id,"ss_32", 0X0, 0x60000400, get_struc_id("__reg32_t"), 512);
id = get_struc_id("fp_int_block_t");
mid = add_struc_member(id,"ss_fpstat", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept1", 0X4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept2", 0X8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept3", 0XC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept4", 0X10, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept5", 0X14, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept6", 0X18, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpexcept7", 0X1C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp4_hi", 0X20, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp4_lo", 0X24, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp5_hi", 0X28, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp5_lo", 0X2C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp6_hi", 0X30, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp6_lo", 0X34, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp7_hi", 0X38, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp7_lo", 0X3C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp8_hi", 0X40, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp8_lo", 0X44, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp9_hi", 0X48, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp9_lo", 0X4C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp10_hi", 0X50, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp10_lo", 0X54, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp11_hi", 0X58, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp11_lo", 0X5C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp12_hi", 0X60, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp12_lo", 0X64, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp13_hi", 0X68, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp13_lo", 0X6C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp14_hi", 0X70, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp14_lo", 0X74, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp15_hi", 0X78, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp15_lo", 0X7C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp16_hi", 0X80, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp16_lo", 0X84, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp17_hi", 0X88, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp17_lo", 0X8C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp18_hi", 0X90, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp18_lo", 0X94, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp19_hi", 0X98, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp19_lo", 0X9C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp20_hi", 0XA0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp20_lo", 0XA4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp21_hi", 0XA8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp21_lo", 0XAC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp22_hi", 0XB0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp22_lo", 0XB4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp23_hi", 0XB8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp23_lo", 0XBC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp24_hi", 0XC0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp24_lo", 0XC4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp25_hi", 0XC8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp25_lo", 0XCC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp26_hi", 0XD0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp26_lo", 0XD4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp27_hi", 0XD8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp27_lo", 0XDC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp28_hi", 0XE0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp28_lo", 0XE4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp29_hi", 0XE8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp29_lo", 0XEC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp30_hi", 0XF0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp30_lo", 0XF4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp31_hi", 0XF8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fp31_lo", 0XFC, 0x20000400, -1, 4);
id = get_struc_id("fp_dbl_block_t");
mid = add_struc_member(id,"ss_fp0", 0X0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp1", 0X8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp2", 0X10, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp3", 0X18, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp4", 0X20, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp5", 0X28, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp6", 0X30, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp7", 0X38, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp8", 0X40, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp9", 0X48, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp10", 0X50, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp11", 0X58, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp12", 0X60, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp13", 0X68, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp14", 0X70, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp15", 0X78, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp16", 0X80, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp17", 0X88, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp18", 0X90, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp19", 0X98, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp20", 0XA0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp21", 0XA8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp22", 0XB0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp23", 0XB8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp24", 0XC0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp25", 0XC8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp26", 0XD0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp27", 0XD8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp28", 0XE0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp29", 0XE8, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp30", 0XF0, 0x90000400, -1, 8);
mid = add_struc_member(id,"ss_fp31", 0XF8, 0x90000400, -1, 8);
id = get_struc_id("__save_state::$F0F3A0B47411777C5961C26FBCE8E4DA");
mid = add_struc_member(id,"fpdbl", 0X0, 0x60000400, get_struc_id("fp_dbl_block_t"), 256);
mid = add_struc_member(id,"fpint", 0X0, 0x60000400, get_struc_id("fp_int_block_t"), 256);
id = get_struc_id("__ss_narrow_t");
mid = add_struc_member(id,"ss_gr1", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_rp", 0X4, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_gr3", 0X8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr4", 0XC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr5", 0X10, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr6", 0X14, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr7", 0X18, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr8", 0X1C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr9", 0X20, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr10", 0X24, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr11", 0X28, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr12", 0X2C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr13", 0X30, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr14", 0X34, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr15", 0X38, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr16", 0X3C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr17", 0X40, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr18", 0X44, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr19", 0X48, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr20", 0X4C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr21", 0X50, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_gr22", 0X54, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_arg3", 0X58, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_arg2", 0X5C, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_arg1", 0X60, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_arg0", 0X64, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_dp", 0X68, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_ret0", 0X6C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_ret1", 0X70, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sp", 0X74, 0x20500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ss_gr31", 0X78, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr11", 0X7C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_head", 0X80, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_head", 0X84, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcoq_tail", 0X88, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_pcsq_tail", 0X8C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr15", 0X90, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr19", 0X94, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr20", 0X98, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr21", 0X9C, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr22", 0XA0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cpustate", 0XA4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr4", 0XA8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr0", 0XAC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr1", 0XB0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr2", 0XB4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr3", 0XB8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr5", 0XBC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr6", 0XC0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_sr7", 0XC4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr0", 0XC8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr8", 0XCC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr9", 0XD0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr10", 0XD4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr12", 0XD8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr13", 0XDC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr24", 0XE0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr25", 0XE4, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr26", 0XE8, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_cr27", 0XEC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_mpsfu_low", 0XF0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_mpsfu_ovflo", 0XF4, 0x20000400, -1, 4);
id = get_struc_id("save_state_t");
mid = add_struc_member(id,"ss_flags", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_narrow", 0X4, 0x60000400, get_struc_id("__ss_narrow_t"), 248);
mid = add_struc_member(id,"ss_pad", 0XFC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ss_fpblock", 0X100, 0x60000400, get_struc_id("__save_state::$F0F3A0B47411777C5961C26FBCE8E4DA"), 256);
mid = add_struc_member(id,"ss_xor", 0X200, 0x000400, -1, 128);
mid = add_struc_member(id,"ss_wide", 0X280, 0x60000400, get_struc_id("__save_state::$8C0FCFCC2B9ACB495244C4B504AA9783"), 512);
id = get_struc_id("proc_info");
mid = add_struc_member(id,"sig", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"trap_type", 0X4, 0x20000400, -1, 4);
mid = add_struc_member(id,"hw_regs", 0X8, 0x60000400, get_struc_id("save_state_t"), 1152);
mid = add_struc_member(id,"lwpid", 0X488, 0x20000400, -1, 4);
mid = add_struc_member(id,"user_tid", 0X48C, 0x30000400, -1, 8);
id = get_struc_id("shl_descriptor");
mid = add_struc_member(id,"tstart", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"tend", 0X4, 0x20000400, -1, 4);
mid = add_struc_member(id,"dstart", 0X8, 0x20000400, -1, 4);
mid = add_struc_member(id,"dend", 0XC, 0x20000400, -1, 4);
mid = add_struc_member(id,"ltptr", 0X10, 0x25500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"handle", 0X14, 0x25500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"filename", 0X18, 0x50000400, 0x0, 1025);
mid = add_struc_member(id,"initializer", 0X41C, 0x25500400, 0XFFFFFFFF, 4, 0XFFFFFFFF, 0X0, 0x000002);
mid = add_struc_member(id,"ref_count", 0X420, 0x20000400, -1, 4);
mid = add_struc_member(id,"reserved3", 0X424, 0x20000400, -1, 4);
mid = add_struc_member(id,"reserved2", 0X428, 0x20000400, -1, 4);
mid = add_struc_member(id,"reserved1", 0X42C, 0x20000400, -1, 4);
mid = add_struc_member(id,"reserved0", 0X430, 0x20000400, -1, 4);
id = get_struc_id("aux_id");
mid = add_struc_member(id,"type", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"length", 0X4, 0x20000400, -1, 4);
id = get_struc_id("som_exec_auxhdr");
mid = add_struc_member(id,"som_auxhdr", 0X0, 0x60000400, get_struc_id("aux_id"), 8);
mid = add_struc_member(id,"exec_tsize", 0X8, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_tmem", 0XC, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_tfile", 0X10, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_dsize", 0X14, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_dmem", 0X18, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_dfile", 0X1C, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_bsize", 0X20, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_entry", 0X24, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_flags", 0X28, 0x20000400, -1, 4);
mid = add_struc_member(id,"exec_bfill", 0X2C, 0x20000400, -1, 4);
id = get_struc_id("proc_exec::$733C094BD5627056653FFCFE6E9DB4EB");
mid = add_struc_member(id,"u_magic", 0X0, 0x20000400, -1, 4);
mid = add_struc_member(id,"som_aux", 0X4, 0x60000400, get_struc_id("som_exec_auxhdr"), 48);
id = get_struc_id("proc_exec");
mid = add_struc_member(id,"exdata", 0X0, 0x60000400, get_struc_id("proc_exec::$733C094BD5627056653FFCFE6E9DB4EB"), 52);
mid = add_struc_member(id,"cmd", 0X34, 0x50000400, 0x0, 15);
mid = add_struc_member(id,"_padding", 0X43, 0x000400, -1, 1);
return id;
}
//------------------------------------------------------------------------
// Information about structure types
static Structures(void) {
auto id;
id = Structures_0(id);
}
// End of file.
static accept_file(li, filename)
{
auto buf;
li.seek(16,0); // skip first header
li.read(&buf, 6);
// Magic:
if (buf != "HP-UX\0")
return 0;
return "HP-UX HP-PA Core dump Image (non ELF)";
}
static read_core_head(li)
{
auto core_type;
auto core_space;
auto core_addr;
auto core_len;
auto proc_info_addr;
auto proc_exec_addr;
auto proc_exec_sel;
proc_info_addr = 0;
proc_exec_addr = 0;
proc_exec_sel = 0;
auto ret;
auto mf = (get_inf_attr(INF_LFLAGS) & LFLG_MSF) != 0;
li.seek(0, 0);
ret = 0;
// keep reading corehead structs and process them
while (1) {
ret = li.readbytes(&core_type, 4, mf);
if (ret!=0) break;
//msg("ret: %d\n", ret);
ret = li.readbytes(&core_space, 4, mf);
ret= li.readbytes(&core_addr, 4, mf);
ret= li.readbytes(&core_len, 4, mf);
//msg("type %x addr %x len %x\n", core_type, core_addr, core_len);
loadfile(li, li.tell(), core_addr, core_len);
AddSeg(core_addr, core_addr+core_len, 0, 1, saRelPara, 2);
if (core_type==CORE_FORMAT) {
set_segm_class(core_addr, "FORMAT");
set_segm_type(core_addr, SEG_DATA);
}
if (core_type==CORE_PROC) {
set_segm_class(core_addr, "PROC");
set_segm_type(core_addr, SEG_DATA);
proc_info_addr = core_addr;
}
if (core_type==CORE_DATA) {
set_segm_class(core_addr, "DATA");
set_segm_type(core_addr, SEG_DATA);
}
if (core_type==CORE_STACK) {
set_segm_class(core_addr, "STACK");
set_segm_type(core_addr, SEG_DATA);
}
if (core_type==CORE_MMF) {
set_segm_class(core_addr, "MMF");
}
if (core_type==CORE_NONE) {
set_segm_class(core_addr, "NONE");
}
if (core_type==CORE_EXEC) {
set_segm_class(core_addr, "EXEC");
set_segm_type(core_addr, SEG_DATA);
proc_exec_addr = core_addr;
proc_exec_sel = get_segm_attr(core_addr, SEGATTR_SEL);
}
}
set_inf_attr(INF_COMPILER, COMP_GNU); // closest to HP compiler
set_inf_attr(INF_SIZEOF_ALGN, 4);
Structures();
if (proc_info_addr !=0) {
//provide sime initial information about
//the process state
msg("set proc_data\n");
create_struct(proc_info_addr, -1, "proc_info");
}
if (proc_exec_addr !=0) {
// provide some info about the exec
create_struct(proc_exec_addr, -1 , "proc_exec");
set_inf_attr(INF_START_IP, proc_exec_addr);
set_inf_attr(INF_START_CS, proc_exec_sel);
}
//
// from here on, in a future version: locate the binary,
// shared libraries and load them as well into the idb...
}
static load_file(li, neflags, format)
{
set_processor_type("hppa", SETPROC_LOADER);
msg("file size %d\n", li.size());
read_core_head(li);
return 1;
}

View File

@@ -0,0 +1,24 @@
include ../../allmake.mak
LDRDIR = $(R)loaders
LOADERS += archldr_tar.py
LOADERS += bios_image.py
LOADERS += pdfldr.py
LOADERS += uimage.py
LOADERS += wince.py
LOADERS-$(IDAADV) += hppacore.idc
LOADERS += $(LOADERS-1)
all: $(addprefix $(LDRDIR)/, $(LOADERS))
$(LDRDIR)/%.idc: %.idc
$(CP) $? $@
$(LDRDIR)/%.py: %.py
$(CP) $? $@
clean::
rm -f $(addprefix $(LDRDIR)/, $(LOADERS))

View File

@@ -0,0 +1,319 @@
"""
A script that extracts shellcode from PDF files
The script uses very basic shellcode extraction algorithm
Copyright (c) 1990-2021 Hex-Rays
ALL RIGHTS RESERVED.
Revision history
=========================
v1.0 - initial version
Possible enhancements:
=========================
1. From Didier:
-----------------
FYI: the regex you use to match /JavaScript /JS will fail to match
name obfuscation. Name obuscation use a feature of the PDF language
that allows a character in a name (like /JavaScript) to be replaced
with its hexcode. Example: /#4AavaScript
http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
It's something that's used in-the-wild.
I've updated your regex to support name obfuscation. The JavaScript
itself is now captured in group 13.
\/S\s*\/(J|#4A|#4a)(a|#61)(v|#76)(a|#61)(S|#53)(c|#63)(r|#72)(i|#69)(p|#70)(t|#74)\s*\/(J|#4A|#4a)(S|#53)
\((.+?)>>
2.
---------------
"""
import sys
import re
import zlib
SAMPLE1 = 'malware1.pdf.vir'
SAMPLE2 = 'heapspray-simpler-calc.pdf.vir'
try:
import idaapi
import idc
import ida_idp
ida = True
except:
ida = False
# -----------------------------------------------------------------------
# Tries to find shellcode inside JavaScript statements
# The seach algorithm is simple: it searchs for anything between unescape()
# if it encounters %u or %x it correctly decodes them to characters
def extract_shellcode(lines):
p = 0
shellcode = [] # accumulate shellcode
while True:
p = lines.find(b'unescape("', p)
if p == -1:
break
e = lines.find(b')', p)
if e == -1:
break
expr = lines[p+9:e]
data = []
def put_byte(b):
if sys.version_info.major >= 3:
data.append(b)
else:
data.append(chr(b))
for i in range(0, len(expr)):
if expr[i:i+2] == b"%u":
i += 2
put_byte(int(expr[i+2:i+4], 16))
put_byte(int(expr[i:i+2], 16))
i += 4
elif expr[i] == b"%":
i += 1
put_byte(int(expr[i:i+2], 16))
i += 2
# advance the match pos
p += 8
if sys.version_info.major >= 3:
shellcode.append(bytes(data))
else:
shellcode.append("".join(data))
# That's it
return shellcode
# -----------------------------------------------------------------------
# Given a PDF object id and version, we return the object declaration
def find_obj(buf, id, ver):
stream = re.search(b'%d %d obj(.*?)endobj' % (id, ver), buf, re.MULTILINE | re.DOTALL)
if not stream:
return None
return buf[stream.start(1):stream.end(1)]
# -----------------------------------------------------------------------
# Find JavaScript objects and extract the referenced script object id/ver
def find_js_ref_streams(buf):
o = []
js_ref_streams = re.finditer(r'\/S\s*\/JavaScript\/JS (\d+) (\d+) R'.encode("UTF-8"), buf)
for g in js_ref_streams:
id = int(g.group(1))
ver = int(g.group(2))
o.append([id, ver])
return o
# -----------------------------------------------------------------------
# Find JavaScript objects and extract the embedded script
def find_embedded_js(buf):
r = re.finditer(r'\/S\s*\/JavaScript\s*\/JS \((.+?)>>'.encode("UTF-8"), buf, re.MULTILINE | re.DOTALL)
if not r:
return None
ret = []
for js in r:
p = buf.rfind(b'obj', 0, js.start(1))
if p == -1:
return None
scs = extract_shellcode(js.group(1))
if not scs:
return None
t = buf[p - min(20, len(buf)): p + 3]
obj = re.search('(\d+) (\d+) obj'.encode("UTF-8"), t)
if not obj:
id, ver = 0
else:
id = int(obj.group(1))
ver = int(obj.group(2))
n = 0
for sc in scs:
n += 1
ret.append([id, ver, n, sc])
return ret
# -----------------------------------------------------------------------
# Given a gzipped stream object, it returns the decompressed contents
def decompress_stream(buf):
if buf.find(b'Filter[/FlateDecode]') == -1:
return None
m = re.search(b'stream\s*(.+?)\s*endstream', buf, re.DOTALL | re.MULTILINE)
if not m:
return None
# Decompress and return
return zlib.decompress(m.group(1))
# -----------------------------------------------------------------------
def read_whole_file(li):
li.seek(0)
return li.read(li.size())
# -----------------------------------------------------------------------
def extract_pdf_shellcode(buf):
ret = []
# find all JS stream references
r = find_js_ref_streams(buf)
for id, ver in r:
# extract the JS stream object
obj = find_obj(buf, id, ver)
# decode the stream
stream = decompress_stream(obj)
# extract shell code
scs = extract_shellcode(stream)
i = 0
for sc in scs:
i += 1
ret.append([id, ver, i, sc])
# find all embedded JS
r = find_embedded_js(buf)
if r:
ret.extend(r)
return ret
# -----------------------------------------------------------------------
def accept_file(li, filename):
"""
Check if the file is of supported format
@param li: a file-like object which can be used to access the input data
@param filename: name of the file, if it is an archive member name then the actual file doesn't exist
@return: 0 - no more supported formats
string "name" - format name to display in the chooser dialog
dictionary { 'format': "name", 'options': integer }
options: should be 1, possibly ORed with ACCEPT_FIRST (0x8000)
to indicate preferred format
"""
# we support only one format per file
li.seek(0)
if li.read(5) != b'%PDF-':
return 0
buf = read_whole_file(li)
r = extract_pdf_shellcode(buf)
if not r:
return 0
return {'format': 'PDF with shellcode', 'processor': 'metapc'}
# -----------------------------------------------------------------------
def load_file(li, neflags, format):
"""
Load the file into database
@param li: a file-like object which can be used to access the input data
@param neflags: options selected by the user, see loader.hpp
@return: 0-failure, 1-ok
"""
# Select the PC processor module
idaapi.set_processor_type("metapc", ida_idp.SETPROC_LOADER)
buf = read_whole_file(li)
r = extract_pdf_shellcode(buf)
if not r:
return 0
# Load all shellcode into different segments
start = 0x10000
seg = idaapi.segment_t()
for id, ver, n, sc in r:
size = len(sc)
end = start + size
# Create the segment
seg.start_ea = start
seg.end_ea = end
seg.bitness = 1 # 32-bit
idaapi.add_segm_ex(seg, "obj_%d_%d_%d" % (id, ver, n), "CODE", 0)
# Copy the bytes
idaapi.mem2base(sc, start, end)
# Mark for analysis
idc.AutoMark(start, idc.AU_CODE)
# Compute next loading address
start = ((end // 0x1000) + 1) * 0x1000
# Select the bochs debugger
idc.load_debugger("bochs", 0)
return 1
# -----------------------------------------------------------------------
def test1(sample = SAMPLE1):
# open the file
f = file(sample, 'rb')
buf = f.read()
f.close()
# find all JS stream references
r = find_js_ref_streams(buf)
if not r:
return
for id, ver in r:
obj = find_obj(buf, id, ver)
# extract the JS stream object
f = file('obj_%d_%d.bin' % (id, ver), 'wb')
f.write(obj)
f.close()
# decode the stream
stream = decompress_stream(obj)
f = file('dec_%d_%d.bin' % (id, ver), 'wb')
f.write(stream)
f.close()
# extract shell code
scs = extract_shellcode(stream)
i = 0
for sc in scs:
i += 1
f = file('sh_%d_%d_%d.bin' % (id, ver, i), 'wb')
f.write(sc)
f.close()
# -----------------------------------------------------------------------
def test2(sample = SAMPLE1):
# open the file
f = file(sample, 'rb')
buf = f.read()
f.close()
r = extract_pdf_shellcode(buf)
for id, ver, n, sc in r:
print("sc %d.%d[%d]=%d" % (id, ver, n, len(sc)))
# -----------------------------------------------------------------------
def test3(sample = SAMPLE2):
# open the file
f = file(sample, 'rb')
buf = f.read()
f.close()
t = find_embedded_js(buf)
print(t)
# -----------------------------------------------------------------------
def main():
test1(SAMPLE1)
if not ida:
main()

View File

@@ -0,0 +1,218 @@
# a file loader for U-Boot "uImage" flash images
# Copyright (c) 2011-2021 Hex-Rays
# ALL RIGHTS RESERVED.
import idaapi
import idc
import zlib
import ida_idp
import ida_typeinf
IH_TYPE_INVALID = 0 # /* Invalid Image */
IH_TYPE_STANDALONE = 1 # /* Standalone Program */
IH_TYPE_KERNEL = 2 # /* OS Kernel Image */
IH_TYPE_RAMDISK = 3 # /* RAMDisk Image */
IH_TYPE_MULTI = 4 # /* Multi-File Image */
IH_TYPE_FIRMWARE = 5 # /* Firmware Image */
IH_TYPE_SCRIPT = 6 # /* Script file */
IH_TYPE_FILESYSTEM = 7 # /* Filesystem Image (any type) */
ImageTypeNames = [ "Invalid", "Standalone Program", "OS Kernel", "RAMDisk",
"Multi-File", "Firmware", "Script file", "Filesystem" ]
IH_ARCH_INVALID = 0 # /* Invalid CPU */
IH_ARCH_ALPHA = 1 # /* Alpha */
IH_ARCH_ARM = 2 # /* ARM */
IH_ARCH_I386 = 3 # /* Intel x86 */
IH_ARCH_IA64 = 4 # /* IA64 */
IH_ARCH_MIPS = 5 # /* MIPS */
IH_ARCH_MIPS64 = 6 # /* MIPS 64 Bit */
IH_ARCH_PPC = 7 # /* PowerPC */
IH_ARCH_S390 = 8 # /* IBM S390 */
IH_ARCH_SH = 9 # /* SuperH */
IH_ARCH_SPARC = 10 # /* Sparc */
IH_ARCH_SPARC64 = 11 # /* Sparc 64 Bit */
IH_ARCH_M68K = 12 # /* M68K */
IH_ARCH_NIOS = 13 # /* Nios-32 */
IH_ARCH_MICROBLAZE = 14 # /* MicroBlaze */
IH_ARCH_NIOS2 = 15 # /* Nios-II */
IH_ARCH_BLACKFIN = 16 # /* */
IH_ARCH_AVR32 = 17 # /* */
IH_ARCH_ST200 = 18 # /* */
IH_ARCH_SANDBOX = 19 # /* */
IH_ARCH_NDS32 = 20 # /* */
IH_ARCH_OPENRISC = 21 # /* */
IH_ARCH_ARM64 = 22 # /* */
IH_ARCH_ARC = 23 # /* */
CPUNames = [ "Invalid", "Alpha", "ARM", "x86", "IA64", "MIPS", "MIPS64", "PowerPC",
"IBM S390", "SuperH", "Sparc", "Sparc64", "M68K", "Nios-32", "MicroBlaze", "Nios-II",
"Blackfin", "AVR32", "ST200","Sandbox","NDS32", "OpenRISC", "ARM64", "ARC" ]
IDACPUNames = { IH_ARCH_ALPHA: "alphab",
IH_ARCH_ARM:"ARM",
IH_ARCH_I386: "metapc",
IH_ARCH_IA64: "ia64b",
IH_ARCH_MIPS:"mipsl",
IH_ARCH_MIPS64:"mipsl",
IH_ARCH_PPC: "ppc",
IH_ARCH_SH: "SH4",
IH_ARCH_SPARC: "sparcb",
IH_ARCH_SPARC64:"sparcb",
IH_ARCH_M68K:"68K",
IH_ARCH_ARM64:"ARM",
IH_ARCH_ARC: "arcmpct" }
IDAABINames = { IH_ARCH_MIPS:"n32",
IH_ARCH_MIPS64:"n64" }
IH_COMP_NONE = 0 # /* No Compression Used */
IH_COMP_GZIP = 1 # /* gzip Compression Used */
IH_COMP_BZIP2 = 2 # /* bzip2 Compression Used */
IH_COMP_LZMA = 3 # /* lzma Compression Used */
IH_COMP_LZO = 4 # /* lzo Compression Used */
CompTypeNames = [ "", "gzip", "bzip2", "lzma", "lzo" ]
IH_MAGIC = 0x27051956 # Image Magic Number
IH_NMLEN = 32 # Image Name Length
import ctypes
uint8_t = ctypes.c_byte
uint32_t = ctypes.c_uint
class image_header(ctypes.BigEndianStructure):
_fields_ = [
("ih_magic", uint32_t), # Image Header Magic Number
("ih_hcrc", uint32_t), # Image Header CRC Checksum
("ih_time", uint32_t), # Image Creation Timestamp
("ih_size", uint32_t), # Image Data Size
("ih_load", uint32_t), # Data Load Address
("ih_ep", uint32_t), # Entry Point Address
("ih_dcrc", uint32_t), # Image Data CRC Checksum
("ih_os", uint8_t), # Operating System
("ih_arch", uint8_t), # CPU architecture
("ih_type", uint8_t), # Image Type
("ih_comp", uint8_t), # Compression Type
("ih_name", uint8_t * IH_NMLEN), # Image Name
]
RomFormatName = "U-Boot image"
# -----------------------------------------------------------------------
def dwordAt(li, off):
li.seek(off)
s = li.read(4)
if len(s) < 4:
return 0
return struct.unpack('<I', s)[0]
def read_struct(li, struct):
s = struct()
s.ih_magic = 0
slen = ctypes.sizeof(s)
if li.size() >= slen:
bytes = li.read(slen)
fit = min(len(bytes), slen)
ctypes.memmove(ctypes.addressof(s), bytes, fit)
return s
# -----------------------------------------------------------------------
def accept_file(li, filename):
"""
Check if the file is of supported format
@param li: a file-like object which can be used to access the input data
@param filename: name of the file, if it is an archive member name then the actual file doesn't exist
@return: 0 - no more supported formats
string "name" - format name to display in the chooser dialog
dictionary { 'format': "name", 'options': integer }
options: should be 1, possibly ORed with ACCEPT_FIRST (0x8000)
to indicate preferred format
"""
header = read_struct(li, image_header)
# check the signature
if header.ih_magic == IH_MAGIC:
# accept the file
t = header.ih_type
c = header.ih_arch
if t >= len(ImageTypeNames):
t = "unknown type(%d)" % t
else:
t = ImageTypeNames[t]
if c >= len(CPUNames):
cname = "unknown CPU(%d)" % c
else:
cname = CPUNames[c]
fmt = "%s (%s for %s)" % (RomFormatName, t, cname)
comp = header.ih_comp
if comp != IH_COMP_NONE:
if comp >= len (CompTypeNames):
cmpname = "unknown compression(%d)"
else:
cmpname = "%s compressed" % CompTypeNames[comp]
fmt += " [%s]" % cmpname
proc = ''
if c in IDACPUNames:
proc = IDACPUNames[c]
return {'format': fmt, 'processor': proc}
# unrecognized format
return 0
# -----------------------------------------------------------------------
def load_file(li, neflags, format):
"""
Load the file into database
@param li: a file-like object which can be used to access the input data
@param neflags: options selected by the user, see loader.hpp
@return: 0-failure, 1-ok
"""
if format.startswith(RomFormatName):
li.seek(0)
header = read_struct(li, image_header)
c = header.ih_arch
cname = IDACPUNames.get(c)
if not cname:
idc.warning("Unsupported CPU")
#return
if not header.ih_comp in (IH_COMP_NONE, IH_COMP_GZIP):
idc.warning("Can only handle uncompressed or gzip-compressed images")
return
if cname:
idaapi.set_processor_type(cname, ida_idp.SETPROC_LOADER)
idc.AddSeg(header.ih_load, header.ih_load + header.ih_size, 0, 1, idaapi.saRelPara, idaapi.scPub)
# copy bytes to the database
if header.ih_comp == IH_COMP_NONE:
li.file2base(ctypes.sizeof(header), header.ih_load, header.ih_load + header.ih_size, 0)
else:
cdata = li.read(header.ih_size)
d = zlib.decompressobj(zlib.MAX_WBITS|32)
udata = d.decompress(cdata)
udata += d.flush()
# expand segment to fit uncompressed data
idc.set_segment_bounds(header.ih_load, header.ih_load, header.ih_load+len(udata), idc.SEGMOD_KEEP)
idaapi.put_bytes(header.ih_load, udata)
if cname == "ARM" and (header.ih_ep & 1) != 0:
# Thumb entry point
header.ih_ep -= 1
split_sreg_range(header.ih_ep, "T", 1)
idaapi.add_entry(header.ih_ep, header.ih_ep, "start", 1)
aname = IDAABINames.get(header.ih_arch)
if aname:
ida_typeinf.set_abi_name(aname)
print("Load OK")
return 1

View File

@@ -0,0 +1,119 @@
# an example of a file loader in Python
# The scripting loader must define at least two functions: accept_file and load_file
# other optional functions are: save_file, move_segm, ...
#
# see also loader.hpp
import idaapi
import ida_idp
import idc
import struct
ROM_SIGNATURE_OFFSET = 64
ROM_SIGNATURE = "ECEC"
RomFormatName = "Windows CE ROM"
# -----------------------------------------------------------------------
def dwordAt(li, off):
li.seek(off)
s = li.read(4)
if len(s) < 4:
return 0
return struct.unpack('<I', s)[0]
# -----------------------------------------------------------------------
def guess_processor(li):
jump = dwordAt(li, 0)
if jump & 0xFF000000 == 0xEA000000: # looks like an ARM branch?
return "arm"
else:
return "metapc"
# -----------------------------------------------------------------------
def accept_file(li, filename):
"""
Check if the file is of supported format
@param li: a file-like object which can be used to access the input data
@param filename: name of the file, if it is an archive member name then the actual file doesn't exist
@return: 0 - no more supported formats
string "name" - format name to display in the chooser dialog
dictionary { 'format': "name", 'options': integer }
options: should be 1, possibly ORed with ACCEPT_FIRST (0x8000)
to indicate preferred format
"""
# check the CECE signature
li.seek(ROM_SIGNATURE_OFFSET)
if li.read(4) == ROM_SIGNATURE:
# accept the file
proc = guess_processor(li)
return {'format': RomFormatName, 'processor': proc}
# unrecognized format
return 0
# -----------------------------------------------------------------------
def load_file(li, neflags, format):
"""
Load the file into database
@param li: a file-like object which can be used to access the input data
@param neflags: options selected by the user, see loader.hpp
@return: 0-failure, 1-ok
"""
if format == RomFormatName:
proc = guess_processor(li)
idaapi.set_processor_type(proc, ida_idp.SETPROC_LOADER)
li.seek(0, idaapi.SEEK_END)
size = li.tell()
#next dword after signature is a pointer to ROMHDR
romhdr = dwordAt(li, ROM_SIGNATURE_OFFSET + 4)
# let's try to find such imagebase that potential ROMHDR's "physfirst" value matches it
imgbase = (romhdr-size) & ~0xfff
bases = []
maxbase = 0
while imgbase < romhdr+8:
physfirst = dwordAt(li, romhdr - imgbase + 8)
if physfirst == imgbase:
bases.append(imgbase)
imgbase += 0x1000
if len(bases) == 1:
start = bases[0]
elif len(bases) > 1:
print("warning: several potential imagebases detemined: " + ", ".join("%08X"%i for i in bases))
start = bases[-1]
else:
warning("Unable to determine load image base.")
start = 0x80000000
print("Using imagebase %08X" % start)
physlast = dwordAt(li, romhdr - start + 12)
if physlast <= start:
warning("Internal error")
return 0
size = physlast - start
idc.AddSeg(start, start+size, 0, 1, idaapi.saRelPara, idaapi.scPub)
# copy bytes to the database
li.seek(0)
li.file2base(0, start, start+size, 0)
idaapi.add_entry(start, start, "start", 1)
print("Load OK")
return 1
idc.warning("Unknown format name: '%s'" % format)
return 0
# -----------------------------------------------------------------------
def move_segm(frm, to, sz, fileformatname):
idc.warning("move_segm(from=%s, to=%s, sz=%d, formatname=%s" % (hex(frm), hex(to), sz, fileformatname))
return 0

883
idasdk76/ldr/snes/addr.cpp Normal file
View File

@@ -0,0 +1,883 @@
// This file is included from the loader module and the processor module
#include "super-famicom.hpp"
class snes_addr_t
{
SuperFamicomCartridge g_cartridge;
//----------------------------------------------------------------------------
ea_t xlat_system(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// WRAM
if ( bank >= 0x7e && bank <= 0x7f )
return address;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr <= 0x1fff ) // Low RAM
return 0x7e0000 + addr;
else if ( addr >= 0x2100 && addr <= 0x213f ) // PPU registers
return addr;
else if ( addr >= 0x2140 && addr <= 0x2183 ) // CPU registers
return addr;
else if ( addr >= 0x4016 && addr <= 0x4017 ) // CPU registers
return addr;
else if ( addr >= 0x4200 && addr <= 0x421f ) // CPU registers
return addr;
else if ( addr >= 0x4300 && addr <= 0x437f ) // CPU registers
return addr;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// hitachidsp model=HG51B169 frequency=20000000
// rom id=program name=program.rom size=hex(rom_size)
// rom id=data name=cx4.data.rom size=0xc00
// ram id=data size=0xc00
// map id=io address=00-3f,80-bf:6000-7fff
// map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000
// map id=ram address=70-77:0000-7fff
ea_t xlat_cx4(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0
&& bank >= 0x70
&& bank <= 0x77
&& addr <= 0x7fff )
{
return address;
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank <= 0xbf )
{
if ( addr >= 0x8000 )
{
// ROM
return address;
}
else if ( addr >= 0x6000 )
{
// CX4 registers
return addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// spc7110
// rom id=program name=program.rom size=0x100000
// rom id=data name=data.rom size=hex(rom_size - 0x100000)
// ram name=save.ram size=0x", hex(ram_size)
// map id=io address=00-3f,80-bf:4800-483f
// map id=io address=50:0000-ffff
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=c0-ff:0000-ffff
// map id=ram address=00-3f,80-bf:6000-7fff mask=0xe000
ea_t xlat_spc7110(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((ram_offset >> 13) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
// Decompressed ROM
if ( bank >= 0x50 && bank <= 0x5f )
return address;
// mirror 00-7d => 80-fd (excluding SRAM, Decompressed ROM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else
{
if ( addr >= 0x8000 )
{
// ROM (LoROM-like layout)
return ((0xc0 + (bank & 0x3f)) << 16) + addr;
}
else if ( addr >= 0x4800 && addr <= 0x483f )
{
// SPC7110 registers
return addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sdd1
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=io address=00-3f,80-bf:4800-4807
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=c0-ff:0000-ffff
// map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000
// map id=ram address=70-7f:0000-7fff
ea_t xlat_sdd1(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank >= 0x70 && bank <= 0x7d )
{
if ( addr <= 0x7fff )
{
// LoROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
else if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM style)
return ((bank | 0x80) << 16) + addr;
}
else if ( addr >= 0x4800 && addr <= 0x4807 )
{
// S-DD1 registers
return addr;
}
}
else if ( bank >= 0xc0 )
{
// ROM (HiROM style)
return address;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-7f,80-ff:8000-ffff mask=0x8000
// map id=ram address=70-7f,f0-ff:[0000-7fff|0000-ffff]
ea_t xlat_lorom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
bool preserve_rom_mirror = (g_cartridge.rom_size > 0x200000) || (g_cartridge.ram_size > 32 * 1024);
if ( ( bank >= 0x70 && bank <= 0x7d ) || bank >= 0xf0 )
{
if ( addr <= 0x7fff || !preserve_rom_mirror )
{
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 ea = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
if ( bank >= 0xfe )
ea += 0x800000;
return ea;
}
}
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
// ROM
if ( bank <= 0xbf )
{
if ( addr >= 0x8000 )
{
return address;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=40-7f,c0-ff:0000-ffff
// map id=ram address=10-3f,90-bf:6000-7fff mask=0xe000
ea_t xlat_hirom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( ( bank >= 0x10 && bank <= 0x3f ) || ( bank >= 0x90 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// Typically, HiROM SRAM starts from $20:0000, but there are exceptions.
// Example: Donkey Kong Country 2 (reads $B0:6000 for 2 kilobytes SRAM)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
// mirror 00-7d => 80-fd (excluding SRAM)
if ( bank <= 0x7d )
{
address += 0x800000;
bank += 0x80;
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else
{
if ( addr >= 0x8000 )
{
// ROM (LoROM-like layout)
return ((0xc0 + (bank & 0x3f)) << 16) + addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=40-7f:0000-ffff
// map id=ram address=20-3f,a0-bf:6000-7fff
// map id=ram address=70-7f:0000-7fff
ea_t xlat_exlorom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank >= 0x70 && bank <= 0x7d )
{
if ( addr <= 0x7fff )
{
// LoROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
else if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
}
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM style)
return ((bank | 0x80) << 16) + addr;
}
}
else if ( bank <= 0x7f )
{
// ROM (HiROM style)
return address;
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=rom address=00-3f:8000-ffff base=0x400000
// map id=rom address=40-7f:0000-ffff base=0x400000
// map id=rom address=80-bf:8000-ffff mask=0xc00000
// map id=rom address=c0-ff:0000-ffff mask=0xc00000
// map id=ram address=20-3f,a0-bf:6000-7fff mask=0xe000
// map id=ram address=70-7f:[0000-7fff|0000-ffff]
ea_t xlat_exhirom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SRAM
if ( g_cartridge.ram_size != 0 )
{
if ( ( bank >= 0x20 && bank <= 0x3f ) || ( bank >= 0xa0 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// HiROM SRAM style
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0x1f) << 13) + (addr - 0x6000)) & ram_mask;
uint32 res = ((0x20 + (ram_offset >> 13)) << 16) + (0x6000 + (ram_offset & 0x1fff));
return res;
}
}
else if ( bank >= 0x70 && bank <= 0x7d )
{
bool preserve_rom_mirror = (g_cartridge.rom_size > 0x200000) || (g_cartridge.ram_size > 32 * 1024);
if ( addr <= 0x7fff || !preserve_rom_mirror )
{
// LoROM SRAM style (not usually used?)
uint32 ram_mask = g_cartridge.ram_size - 1;
uint32 ram_offset = (((bank & 0xf) << 15) + (addr & 0x7fff)) & ram_mask;
uint32 res = ((0x70 + (ram_offset >> 15)) << 16) + (ram_offset & 0x7fff);
return res;
}
}
}
if ( bank >= 0xc0 )
{
// ROM
return address;
}
else if ( bank >= 0x80 )
{
if ( addr >= 0x8000 )
{
// ROM (mirror to c0-ff)
return ((bank + 0x40) << 16) + addr;
}
}
else if ( bank >= 0x40 )
{
// Extended ROM
return address;
}
else
{
if ( addr >= 0x8000 )
{
// Extended ROM (mirror to 40-7f)
return ((bank + 0x40) << 16) + addr;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// superfx revision=4
// rom name=program.rom size=hex(rom_size)
// ram name=save.ram size=hex(ram_size)
// map id=io address=00-3f,80-bf:3000-34ff
// map id=rom address=00-3f,80-bf:8000-ffff mask=0x8000
// map id=rom address=40-5f,c0-df:0000-ffff
// map id=ram address=00-3f,80-bf:6000-7fff size=0x2000
// map id=ram address=70-71,f0-f1:0000-ffff
ea_t xlat_superfxrom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// SuperFX RAM
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// 2kB Game Work RAM
return (0x00 << 16) + addr;
}
}
else if ( ( bank >= 0x70 && bank <= 0x7f ) || ( bank >= 0xf0 && bank <= 0xf1 ) )
{
// 128kB SRAM address space
return ( ( bank & ~0x80 ) << 16 ) + addr;
}
}
if ( ( bank >= 0x40 && bank <= 0x5f ) || ( bank >= 0xc0 && bank <= 0xdf ) )
{
// ROM (HiROM layout)
return address;
}
else if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM layout)
return address;
}
}
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sa1
// rom name=program.rom size=hex(rom_size)
// ram id=bitmap name=save.ram size=hex(ram_size)
// ram id=internal size=0x800
// map id=io address=00-3f,80-bf:2200-23ff
// map id=rom address=00-3f,80-bf:8000-ffff
// map id=rom address=c0-ff:0000-ffff
// map id=bwram address=00-3f,80-bf:6000-7fff
// map id=bwram address=40-4f:0000-ffff
// map id=iram address=00-3f,80-bf:3000-37ff
ea_t xlat_sa1rom(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
// mirror 80-bf => 00-3f
if ( bank >= 0x80 && bank <= 0xbf )
{
address -= 0x800000;
bank -= 0x80;
}
// SA1 BWRAM (SRAM)
if ( g_cartridge.ram_size != 0 )
{
if ( bank <= 0x3f )
{
if ( addr >= 0x6000 && addr <= 0x7fff )
{
// 8 kilobytes RAM (shared with 40:0000-1fff)
uint32 ram_offset = (addr & 0x7fff) - 0x6000;
return (0x40 << 16) + ram_offset;
}
}
else if ( bank <= 0x4f )
{
// 128 kB address space, redirects to banks 40-41
return ((bank & ~0xe) << 16) + addr;
}
}
if ( bank >= 0xc0 )
{
// ROM (HiROM layout)
return address;
}
else if ( bank <= 0x3f )
{
if ( addr >= 0x8000 )
{
// ROM (LoROM layout)
return address;
}
}
// TODO: SA1 Missing Memory Map
// 00-3f|80-bf:0000-07ff IWRAM (SA1 side)
// 60-6f:0000-ffff BWRAM Bitmap (SA1 side)
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// sharprtc
// ram name=rtc.ram size=0x10
// map id=io address=00-3f,80-bf:2800-2801
ea_t xlat_sharprtc(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x2800 && addr <= 0x2801 )
{
return addr;
}
}
dispatched = false;
return false;
}
//----------------------------------------------------------------------------
// epsonrtc
// ram name=rtc.ram size=0x10
// map id=io address=00-3f,80-bf:4840-4842
ea_t xlat_epsonrtc(ea_t address, bool & dispatched)
{
uint16 addr = address & 0xffff;
uint8 bank = (address >> 16) & 0xff;
dispatched = true;
if ( bank <= 0x3f || ( bank >= 0x80 && bank <= 0xbf ) )
{
if ( addr >= 0x4840 && addr <= 0x4842 )
{
return addr;
}
}
dispatched = false;
return false;
}
//----------------------------------------------------------------------------
// obc1
// ram name=save.ram size=0x2000
// map id=io address=00-3f,80-bf:6000-7fff
ea_t xlat_obc1(ea_t address, bool & dispatched)
{
// TODO: Add OBC-1 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp1b.program.rom size=0x1800
// rom id=data name=dsp1b.data.rom size=0x800
// ram id=data size=0x200
//
// when DSP1LoROM1MB:
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
//
// when DSP1LoROM2MB:
// map id=io address=60-6f,e0-ef:0000-7fff select=0x4000
//
// when DSP1HiROM:
// map id=io address=00-1f,80-9f:6000-7fff select=0x1000
ea_t xlat_dsp1(ea_t address, SuperFamicomCartridge::DSP1MemoryMapper /*dsp1_mapper*/, bool & dispatched)
{
// TODO: Add DSP-1 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp2.program.rom size=0x1800
// rom id=data name=dsp2.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
ea_t xlat_dsp2(ea_t address, bool & dispatched)
{
// TODO: Add DSP-2 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp3.program.rom size=0x1800
// rom id=data name=dsp3.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=20-3f,a0-bf:8000-ffff select=0x4000
ea_t xlat_dsp3(ea_t address, bool & dispatched)
{
// TODO: Add DSP-3 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD7725 frequency=8000000
// rom id=program name=dsp4.program.rom size=0x1800
// rom id=data name=dsp4.data.rom size=0x800
// ram id=data size=0x200
// map id=io address=30-3f,b0-bf:8000-ffff select=0x4000
ea_t xlat_dsp4(ea_t address, bool & dispatched)
{
// TODO: Add DSP-4 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD96050 frequency=11000000
// rom id=program name=st010.program.rom size=0xc000
// rom id=data name=st010.data.rom size=0x1000
// ram id=data name=save.ram size=0x1000
// map id=io address=60-67,e0-e7:0000-3fff select=0x0001
// map id=ram address=68-6f,e8-ef:0000-7fff
ea_t xlat_st010(ea_t address, bool & dispatched)
{
// TODO: Add ST-010 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// necdsp model=uPD96050 frequency=15000000
// rom id=program name=st011.program.rom size=0xc000
// rom id=data name=st011.data.rom size=0x1000
// ram id=data name=save.ram size=0x1000
// map id=io address=60-67,e0-e7:0000-3fff select=0x0001
// map id=ram address=68-6f,e8-ef:0000-7fff
ea_t xlat_st011(ea_t address, bool & dispatched)
{
// TODO: Add ST-011 address mapping
dispatched = false;
return address;
}
//----------------------------------------------------------------------------
// armdsp frequency=21477272
// rom id=program name=st018.program.rom size=0x20000
// rom id=data name=st018.data.rom size=0x8000
// ram name=save.ram size=0x4000
// map id=io address=00-3f,80-bf:3800-38ff
ea_t xlat_st018(ea_t address, bool & dispatched)
{
// TODO: Add ST-018 address mapping
dispatched = false;
return address;
}
public:
//----------------------------------------------------------------------------
bool addr_init(const SuperFamicomCartridge & cartridge)
{
g_cartridge = cartridge;
switch ( g_cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
case SuperFamicomCartridge::HiROM:
case SuperFamicomCartridge::ExLoROM:
case SuperFamicomCartridge::ExHiROM:
case SuperFamicomCartridge::SuperFXROM:
case SuperFamicomCartridge::SA1ROM:
case SuperFamicomCartridge::SPC7110ROM:
return true;
default:
return false;
}
}
//----------------------------------------------------------------------------
ea_t xlat(ea_t address)
{
bool dispatched;
ea_t remapped_address;
remapped_address = xlat_system(address, dispatched);
if ( dispatched )
return remapped_address;
if ( g_cartridge.has_cx4 )
{
remapped_address = xlat_cx4(address, dispatched);
}
else if ( g_cartridge.has_sdd1 )
{
remapped_address = xlat_sdd1(address, dispatched);
}
else
{
switch ( g_cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
remapped_address = xlat_lorom(address, dispatched);
break;
case SuperFamicomCartridge::HiROM:
remapped_address = xlat_hirom(address, dispatched);
break;
case SuperFamicomCartridge::ExLoROM:
remapped_address = xlat_exlorom(address, dispatched);
break;
case SuperFamicomCartridge::ExHiROM:
remapped_address = xlat_exhirom(address, dispatched);
break;
case SuperFamicomCartridge::SuperFXROM:
remapped_address = xlat_superfxrom(address, dispatched);
break;
case SuperFamicomCartridge::SA1ROM:
remapped_address = xlat_sa1rom(address, dispatched);
break;
case SuperFamicomCartridge::SPC7110ROM:
remapped_address = xlat_spc7110(address, dispatched);
break;
default:
break;
}
}
if ( dispatched )
return remapped_address;
if ( g_cartridge.has_sharprtc )
{
remapped_address = xlat_sharprtc(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_epsonrtc )
{
remapped_address = xlat_epsonrtc(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_obc1 )
{
remapped_address = xlat_obc1(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp1 )
{
remapped_address = xlat_dsp1(address, g_cartridge.dsp1_mapper, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp2 )
{
remapped_address = xlat_dsp2(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp3 )
{
remapped_address = xlat_dsp3(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_dsp4 )
{
remapped_address = xlat_dsp4(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st010 )
{
remapped_address = xlat_st010(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st011 )
{
remapped_address = xlat_st011(address, dispatched);
if ( dispatched )
return remapped_address;
}
if ( g_cartridge.has_st018 )
{
remapped_address = xlat_st018(address, dispatched);
if ( dispatched )
return remapped_address;
}
return address;
}
};

View File

@@ -0,0 +1,14 @@
PROC=snes
include ../loader.mak
# MAKEDEP dependency list ------------------
$(F)snes$(O) : $(I)auto.hpp $(I)bitrange.hpp $(I)bytes.hpp \
$(I)config.hpp $(I)diskio.hpp $(I)entry.hpp \
$(I)fixup.hpp $(I)fpro.h $(I)funcs.hpp \
$(I)ida.hpp $(I)idp.hpp $(I)ieee.h $(I)kernwin.hpp \
$(I)lines.hpp $(I)llong.hpp $(I)loader.hpp $(I)nalt.hpp \
$(I)name.hpp $(I)netnode.hpp $(I)offset.hpp $(I)pro.h \
$(I)range.hpp $(I)segment.hpp $(I)segregs.hpp $(I)ua.hpp \
$(I)xref.hpp ../idaldr.h addr.cpp snes.cpp \
super-famicom.hpp

716
idasdk76/ldr/snes/snes.cpp Normal file
View File

@@ -0,0 +1,716 @@
#include "../idaldr.h"
#include "addr.cpp"
//----------------------------------------------------------------------------
static void map_io_seg(ea_t start, ea_t end, const char *const name)
{
segment_t s;
s.start_ea = start;
s.end_ea = end;
s.type = SEG_IMEM;
s.sel = allocate_selector(start >> 4);
if ( !add_segm_ex(&s, name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", name);
}
//----------------------------------------------------------------------------
static void map_hwregs()
{
map_io_seg(0x2100, 0x2140, "ppu");
map_io_seg(0x2140, 0x2144, "apu");
map_io_seg(0x2180, 0x2184, "wramrw");
map_io_seg(0x4016, 0x4018, "joypad");
map_io_seg(0x4200, 0x4220, "misc");
map_io_seg(0x4300, 0x4380, "dma");
}
//----------------------------------------------------------------------------
static void map_wram()
{
segment_t s;
s.start_ea = 0x7e0000;
s.end_ea = 0x800000;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "wram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_lorom_sram_offset(uint32 ram_size, uint8 start_bank)
{
// Usually, the lower half of bank (0x8000 bytes) is SRAM, and the upper half is ROM mirror.
// However, some cartridges maps the whole of bank (0x10000 bytes) to SRAM.
// In that case, the upper half is probably mirrored as same as the lower half.
// create ram banks
const uint32 bank_size = 0x8000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = start_bank; mapped < ram_chunks; bank++, mapped++ )
{
if ( bank == 0x7e )
bank = 0xfe;
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_hirom_sram_offset(uint32 ram_size, uint8 start_bank)
{
// create ram banks
const uint32 bank_size = 0x2000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = start_bank; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32((bank << 16) + 0x6000);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_lorom_sram(uint32 ram_size)
{
// create ram banks 70-7d (and fe-ff)
map_lorom_sram_offset(ram_size, 0x70);
}
//----------------------------------------------------------------------------
static void map_hirom_sram(uint32 ram_size)
{
// create ram banks 20-3f
map_hirom_sram_offset(ram_size, 0x20);
}
//----------------------------------------------------------------------------
static void map_superfx_sram(uint32 ram_size)
{
// create ram banks 70-71
const uint32 bank_size = 0x10000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = 0x70; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_superfx_workram()
{
segment_t s;
s.start_ea = 0x6000;
s.end_ea = 0x8000;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "sfxram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_superfx_hwregs()
{
map_io_seg(0x3000, 0x3500, "superfx");
}
//----------------------------------------------------------------------------
static void map_sa1_bwram(uint32 ram_size)
{
// create ram banks 40-41
const uint32 bank_size = 0x10000;
uint32 ram_chunks = (ram_size + bank_size - 1) / bank_size;
for ( uint32 mapped = 0, bank = 0x40; mapped < ram_chunks; bank++, mapped++ )
{
segment_t s;
s.start_ea = uint32(bank << 16);
s.end_ea = s.start_ea + bank_size;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm_ex(&s, seg_name, "BANK_RAM", ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
}
//----------------------------------------------------------------------------
static void map_sa1_iram()
{
segment_t s;
s.start_ea = 0x3000;
s.end_ea = 0x3800;
s.type = SEG_IMEM;
s.sel = allocate_selector(s.start_ea >> 4);
char seg_name[0x10];
qsnprintf(seg_name, sizeof(seg_name), "iram");
if ( !add_segm_ex(&s, seg_name, NULL, ADDSEG_NOSREG|ADDSEG_SPARSE) )
loader_failure("Failed adding %s segment\n", seg_name);
}
//----------------------------------------------------------------------------
static void map_sa1_hwregs()
{
map_io_seg(0x2200, 0x2400, "sa1");
}
//----------------------------------------------------------------------------
static void map_cx4_hwregs()
{
map_io_seg(0x6000, 0x8000, "cx4");
}
//----------------------------------------------------------------------------
static void map_spc7110_hwregs()
{
map_io_seg(0x4800, 0x4840, "spc7110");
map_io_seg(0x500000, 0x600000, "decomprom");
}
//----------------------------------------------------------------------------
static void map_sdd1_hwregs()
{
map_io_seg(0x4800, 0x4808, "sdd1");
}
//----------------------------------------------------------------------------
static sel_t map_lorom_offset(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint8 start_bank, uint32 offset)
{
// 32KB chunks count
uint32 chunks = (rom_size + 0x8000 - 1) / 0x8000;
// map rom to banks
sel_t start_sel = 0;
for ( uint32 mapped = 0, bank = start_bank; mapped < chunks; bank++, mapped++ )
{
if ( bank == 0x7e || bank == 0x7f )
continue;
uint32 map_size = qmin(0x8000, rom_size - (0x8000 * mapped));
ea_t start = uint32((bank << 16) + 0x8000);
ea_t end = start + 0x8000;
uint32 off_in_file = rom_start_in_file + offset + (mapped << 15);
if ( !file2base(li, off_in_file, start, start + map_size, FILEREG_PATCHABLE) )
loader_failure("Failed mapping 0x%x -> [0x%a, 0x%a)\n", off_in_file, start, end);
char seg_name[0x10];
sel_t selector = allocate_selector((start - 0x8000) >> 4);
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm(selector, start, end, seg_name, "BANK_ROM") )
loader_failure("Failed adding .BANK segment\n");
if ( bank == start_bank )
start_sel = selector;
}
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_hirom_offset(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint8 start_bank, uint32 offset)
{
sel_t start_sel = 0;
// map rom to banks
uint32 chunks = (rom_size + 0x10000 - 1) / 0x10000;
for ( uint32 mapped = 0, bank = start_bank; mapped < chunks; bank++, mapped++ )
{
if ( bank == 0x7e || bank == 0x7f )
continue;
uint32 map_size = qmin(0x10000, rom_size - (0x10000 * mapped));
ea_t start = uint32(bank << 16);
ea_t end = start + 0x10000;
uint32 off_in_file = rom_start_in_file + offset + (mapped << 16);
if ( !file2base(li, off_in_file, start, start + map_size, FILEREG_PATCHABLE) )
loader_failure("Failed mapping 0x%x -> [0x%a, 0x%a)\n", off_in_file, start, end);
char seg_name[0x10];
sel_t selector = allocate_selector((start) >> 4);
qsnprintf(seg_name, sizeof(seg_name), ".%02X", bank);
if ( !add_segm(selector, start, end, seg_name, "BANK_ROM") )
loader_failure("Failed adding .BANK segment\n");
if ( bank == start_bank )
start_sel = selector;
}
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_lorom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 80-ff
return map_lorom_offset(li, rom_start_in_file, rom_size, 0x80, 0);
}
//----------------------------------------------------------------------------
static sel_t map_hirom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks c0-ff
return map_hirom_offset(li, rom_start_in_file, rom_size, 0xc0, 0);
}
//----------------------------------------------------------------------------
static sel_t map_exhirom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
if ( rom_size <= 0x400000 )
return BADSEL;
// map rom to banks 40-7f
sel_t start_sel = map_hirom_offset(li, rom_start_in_file, rom_size - 0x400000, 0x40, 0x400000);
// map rom to banks c0-ff
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_superfx(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 00-3f (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x00, 0);
// map rom to banks c0-df (HiROM layout)
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sa1(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 00-3f (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x00, 0);
// map rom to banks c0-ff (HiROM layout)
map_hirom_offset(li, rom_start_in_file, rom_size, 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sdd1rom(linput_t *li, uint32 rom_start_in_file, uint32 rom_size)
{
// map rom to banks 80-bf (LoROM layout)
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x80, 0);
// map rom to banks c0-ff (HiROM layout)
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0xc0, 0);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_lorom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_lorom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_lorom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_hirom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_hirom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_hirom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_exlorom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
// S-DD1 cartridge should be handled by map_sdd1_cartridge
sel_t start_sel = map_lorom_offset(li, rom_start_in_file, qmin(rom_size, 0x200000), 0x80, 0);
map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x400000), 0x40, 0);
map_lorom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_exhirom_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_exhirom(li, rom_start_in_file, rom_size);
map_hirom_sram(ram_size);
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_superfx_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_superfx(li, rom_start_in_file, rom_size);
map_superfx_sram(ram_size);
map_superfx_workram();
map_superfx_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sa1_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_sa1(li, rom_start_in_file, rom_size);
map_sa1_bwram(ram_size);
map_sa1_iram();
map_sa1_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_cx4_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_lorom(li, rom_start_in_file, qmin(rom_size, 0x400000));
map_lorom_sram(ram_size);
map_cx4_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_spc7110_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_hirom_offset(li, rom_start_in_file, qmin(rom_size, 0x100000), 0xc0, 0);
// create ram banks 00-3f
map_hirom_sram_offset(ram_size, 0x00);
map_spc7110_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static sel_t map_sdd1_cartridge(linput_t *li, uint32 rom_start_in_file, uint32 rom_size, uint32 ram_size)
{
sel_t start_sel = map_sdd1rom(li, rom_start_in_file, rom_size);
map_lorom_sram(ram_size);
map_sdd1_hwregs();
return start_sel;
}
//----------------------------------------------------------------------------
static void map_sharprtc()
{
map_io_seg(0x2800, 0x2802, "sharprtc");
}
//----------------------------------------------------------------------------
static void map_epsonrtc()
{
map_io_seg(0x4840, 0x4843, "epsonrtc");
}
//----------------------------------------------------------------------------
static void map_obc1()
{
// TODO: Add OBC-1 registers
}
//----------------------------------------------------------------------------
static void map_dsp1(SuperFamicomCartridge::DSP1MemoryMapper /*dsp1_mapper*/)
{
// TODO: Add DSP-1 registers
}
//----------------------------------------------------------------------------
static void map_dsp2()
{
// TODO: Add DSP-2 registers
}
//----------------------------------------------------------------------------
static void map_dsp3()
{
// TODO: Add DSP-3 registers
}
//----------------------------------------------------------------------------
static void map_dsp4()
{
// TODO: Add DSP-4 registers
}
//----------------------------------------------------------------------------
static void map_st010()
{
// TODO: Add ST-010 registers
}
//----------------------------------------------------------------------------
static void map_st011()
{
// TODO: Add ST-011 registers
}
//----------------------------------------------------------------------------
static void map_st018()
{
// TODO: Add ST-018 registers
}
//----------------------------------------------------------------------------
static int idaapi accept_file(
qstring *fileformatname,
qstring *processor,
linput_t *li,
const char *)
{
SuperFamicomCartridge cartridge(li);
unsigned score = SuperFamicomCartridge::score_header(li, cartridge.header_offset);
// It is enough to have the first byte of the supposed 'reset vector' match
// one of 6 values, to have a treshold of 8. arm_eep0.bin has such a byte.
// Thus a treshold of 9 (or more) seems in order. Here are some scores:
// - m65816_ffVI.snes: 20
// - m65816_pacman.snes: 14
// - m65816_z2ybd.snes: 14
const int ACCEPTABLE_SCORE_TRESHOLD = 9;
if ( score >= ACCEPTABLE_SCORE_TRESHOLD
&& cartridge.type != SuperFamicomCartridge::TypeUnknown )
{
*fileformatname = "SNES ROM";
*processor = "m65816";
return 1;
}
return 0;
}
//----------------------------------------------------------------------------
static void add_interrupt_vector(snes_addr_t &sa, uint16 addr, const char *name, bool make_code)
{
// Set 'addr' as dword
ea_t real_ea = sa.xlat(addr);
create_word(real_ea, 2);
ea_t orig_vector_addr = get_word(real_ea);
ea_t vector_addr = sa.xlat(orig_vector_addr);
if ( orig_vector_addr != 0 && orig_vector_addr != 0xffff )
{
// Set 'vector_addr' name to be 'name'
if ( !has_user_name(get_flags(vector_addr)) )
set_name(vector_addr, name, SN_NOCHECK);
// Push the vector_addr into the autoanalysis queue.
// Do not make use of auto_make_proc(), because some
// interrupt handler functions are ``overlaid''. Thus,
// we'd break a procedure w/ inserting another
// procedure right into the previous procedure's code.
if ( make_code )
auto_make_code(vector_addr);
// Set 'real_ea' as offset
refinfo_t ri;
ri.init(REF_OFF16, vector_addr - orig_vector_addr);
op_offset_ex(real_ea, OPND_MASK, &ri);
set_cmt(real_ea, name, false);
}
}
//----------------------------------------------------------------------------
void idaapi load_file(linput_t *li, ushort /*neflags*/, const char * /*ffn*/)
{
// One should always set the processor type
// as early as possible: IDA will draw some
// informations from it; e.g., the size of segments.
//
// Should this instruction be placed after the calls to
// map_mode_2x(), IDA would create 32-bits segments,
// because, until the processor type is specified, IDA
// assumes x86.
set_processor_type("m65816", SETPROC_LOADER);
SuperFamicomCartridge cartridge(li);
// Determine whether ROM has a header
int32 start = cartridge.has_copier_header ? 512 : 0;
// Store information for the cpu module
netnode node;
node.create("$ m65816");
node.hashset("device", "snes");
cartridge.write_hash(node);
snes_addr_t sa;
sa.addr_init(cartridge);
sel_t start_cs;
if ( cartridge.has_cx4 )
{
start_cs = map_cx4_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else if ( cartridge.has_spc7110 )
{
start_cs = map_spc7110_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else if ( cartridge.has_sdd1 )
{
start_cs = map_sdd1_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
}
else
{
switch ( cartridge.mapper )
{
case SuperFamicomCartridge::LoROM:
start_cs = map_lorom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::HiROM:
start_cs = map_hirom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::ExLoROM:
start_cs = map_exlorom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::ExHiROM:
start_cs = map_exhirom_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::SuperFXROM:
start_cs = map_superfx_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
case SuperFamicomCartridge::SA1ROM:
start_cs = map_sa1_cartridge(li, start, cartridge.rom_size, cartridge.ram_size);
break;
default:
loader_failure("Unsupported mapper: %s", cartridge.mapper_string());
}
}
inf_set_start_cs(start_cs);
// Hardware registers
map_hwregs();
// WRAM
map_wram();
if ( cartridge.has_sharprtc )
map_sharprtc();
if ( cartridge.has_epsonrtc )
map_epsonrtc();
if ( cartridge.has_obc1 )
map_obc1();
if ( cartridge.has_dsp1 )
map_dsp1(cartridge.dsp1_mapper);
if ( cartridge.has_dsp2 )
map_dsp2();
if ( cartridge.has_dsp3 )
map_dsp3();
if ( cartridge.has_dsp4 )
map_dsp4();
if ( cartridge.has_st010 )
map_st010();
if ( cartridge.has_st011 )
map_st011();
if ( cartridge.has_st018 )
map_st018();
ea_t reset_vector_loc = sa.xlat(0xfffc);
uint16 start_pc = get_word(reset_vector_loc);
ea_t start_address = sa.xlat(start_pc);
inf_set_start_ip(start_address & 0xffff);
// ------- Most important vectors
// http://en.wikibooks.org/wiki/Super_NES_Programming/SNES_memory_map
add_interrupt_vector(sa, 0xfffc, "Emulation-mode RESET", true);
add_interrupt_vector(sa, 0xffea, "Native-mode NMI", true);
add_interrupt_vector(sa, 0xffee, "Native-mode IRQ", true);
add_interrupt_vector(sa, 0xfffe, "Emulation-mode IRQ", true);
// ------- Native-mode vectors
add_interrupt_vector(sa, 0xffe4, "Native-mode COP", false);
add_interrupt_vector(sa, 0xffe6, "Native-mode BRK", false);
add_interrupt_vector(sa, 0xffe8, "Native-mode ABORT", false);
add_interrupt_vector(sa, 0xffec, "Native-mode RESET", false);
// ------- Emulation-mode vectors
add_interrupt_vector(sa, 0xfff4, "Emulation-mode COP", false);
add_interrupt_vector(sa, 0xfff8, "Emulation-mode ABORT", false);
add_interrupt_vector(sa, 0xfffa, "Emulation-mode NMI", false);
// ------- Undefined vectors
create_word(sa.xlat(0xffe0), 2);
create_word(sa.xlat(0xffe2), 2);
create_word(sa.xlat(0xfff0), 2);
create_word(sa.xlat(0xfff2), 2);
create_word(sa.xlat(0xfff6), 2);
// Header info
ea_t header = sa.xlat(0xffc0);
set_name(header, "snes_header");
create_strlit(header, 21, STRTYPE_C);
set_cmt(header, "Game Title", false);
create_byte(header + 0x15, 1);
set_cmt(header + 0x15, "ROM Makeup / ROM Speed and Map Mode", false);
create_byte(header + 0x16, 1);
set_cmt(header + 0x16, "Chipset", false);
create_byte(header + 0x17, 1);
set_cmt(header + 0x17, "ROM Size", false);
create_byte(header + 0x18, 1);
set_cmt(header + 0x18, "RAM Size", false);
create_byte(header + 0x19, 1);
set_cmt(header + 0x19, "Country", false);
create_byte(header + 0x1a, 1);
set_cmt(header + 0x1a, "Developer ID", false);
create_byte(header + 0x1b, 1);
set_cmt(header + 0x1b, "ROM Version", false);
create_word(header + 0x1c, 2);
set_cmt(header + 0x1c, "Checksum Complement", false);
create_word(header + 0x1e, 2);
set_cmt(header + 0x1e, "Checksum", false);
}
//----------------------------------------------------------------------------
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
LDRF_RELOAD,
accept_file,
load_file,
NULL,
NULL,
NULL,
};

View File

@@ -0,0 +1,934 @@
/*
SPECIAL LICENSE AGREEMENT
This file originally comes from the 'higan' emulator
<http://byuu.org/emulation/higan/>, and should normally only be
used in agreement with the terms of the GPLv3 license.
Hex-Rays has been granted, by written consent of its author, the use
of this file within the scope of the 'snes' loader plugin, as well as
within the scope of the '65816' processor module for the Interactive
DisAssembler, without requiring Hex-Rays to release any other source code
that composes the Interactive DisAssembler (or any of its plugins.)
This special license agreement extends to anyone who may want to
modify, re-compile & re-link the 'snes' loader or the '65816' processor
module.
The stated agreement stands only for use of this file within the
'snes' loader plugin and the '65816' processor module for the Interactive
DisAssembler, and cannot be applied to any other project (other
Interactive DisAssembler plugin, or unrelated project.)
Should this file be included in another project than the 'snes' loader
or the '65816' processor module for the Interactive DisAssembler, the
original GPLv3 licensing terms will apply.
*/
// This file is included from the loader module and the processor module
// original source: higan/ananke/heuristics/super-famicom.hpp
#ifndef __SUPER_FAMICOM_HPP__
#define __SUPER_FAMICOM_HPP__
struct SuperFamicomCartridge {
SuperFamicomCartridge();
SuperFamicomCartridge(linput_t *li);
//private:
void read_header(linput_t *li);
static unsigned find_header(linput_t *li);
static unsigned score_header(linput_t *li, unsigned addr);
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
RomType = 0x16,
RomSize = 0x17,
RamSize = 0x18,
CartRegion = 0x19,
Company = 0x1a,
Version = 0x1b,
Complement = 0x1c, //inverse checksum
Checksum = 0x1e,
ResetVector = 0x3c,
};
enum Type {
TypeNormal = 0,
TypeBsxSlotted,
TypeBsxBios,
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
enum Region {
NTSC = 0,
PAL,
};
enum MemoryMapper {
LoROM = 0,
HiROM,
ExLoROM,
ExHiROM,
SuperFXROM,
SA1ROM,
SPC7110ROM,
BSCLoROM,
BSCHiROM,
BSXROM,
STROM,
};
enum DSP1MemoryMapper {
DSP1Unmapped = 0,
DSP1LoROM1MB,
DSP1LoROM2MB,
DSP1HiROM,
};
static inline const char * type_to_string(Type type);
static inline Type string_to_type(const char * str);
static inline const char * region_to_string(Region region);
static inline Region string_to_region(const char * str);
static inline const char * mapper_to_string(MemoryMapper mapper);
static inline MemoryMapper string_to_mapper(const char * str);
static inline const char * dsp1_mapper_to_string(DSP1MemoryMapper dsp1_mapper);
static inline DSP1MemoryMapper string_to_dsp1_mapper(const char * str);
inline const char * type_string() const;
inline const char * region_string() const;
inline const char * mapper_string() const;
inline const char * dsp1_mapper_string() const;
void read_hash(const netnode & node);
void write_hash(netnode & node) const;
void print() const;
unsigned rom_size;
unsigned ram_size;
bool firmware_appended; //true if firmware is appended to end of ROM data
bool has_copier_header;
unsigned header_offset;
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
bool has_bsx_slot;
bool has_superfx;
bool has_sa1;
bool has_sharprtc;
bool has_epsonrtc;
bool has_sdd1;
bool has_spc7110;
bool has_cx4;
bool has_dsp1;
bool has_dsp2;
bool has_dsp3;
bool has_dsp4;
bool has_obc1;
bool has_st010;
bool has_st011;
bool has_st018;
};
SuperFamicomCartridge::SuperFamicomCartridge() :
rom_size(0),
ram_size(0),
firmware_appended(false),
has_copier_header(false),
header_offset(0),
type(TypeUnknown),
region(NTSC),
mapper(LoROM),
dsp1_mapper(DSP1Unmapped),
has_bsx_slot(false),
has_superfx(false),
has_sa1(false),
has_sharprtc(false),
has_epsonrtc(false),
has_sdd1(false),
has_spc7110(false),
has_cx4(false),
has_dsp1(false),
has_dsp2(false),
has_dsp3(false),
has_dsp4(false),
has_obc1(false),
has_st010(false),
has_st011(false),
has_st018(false)
{
}
SuperFamicomCartridge::SuperFamicomCartridge(linput_t *li) {
int32 size = qlsize(li);
if(size < 0) {
return;
}
firmware_appended = false;
//skip copier header
if((size & 0x7fff) == 512) size -= 512;
if(size < 0x8000) return;
read_header(li);
if(type == TypeGameBoy) return;
if(type == TypeBsx) return;
if(type == TypeSufamiTurbo) return;
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) {
if((rom_size & 0x7fff) == 0x100) {
firmware_appended = true;
rom_size -= 0x100;
}
}
else if(has_cx4) {
if((rom_size & 0x7fff) == 0xc00) {
firmware_appended = true;
rom_size -= 0xc00;
}
}
if(has_dsp1) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp2) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp3) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_dsp4) {
if((size & 0x7fff) == 0x2000) {
firmware_appended = true;
rom_size -= 0x2000;
}
}
if(has_st010) {
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st011) {
if((size & 0xffff) == 0xd000) {
firmware_appended = true;
rom_size -= 0xd000;
}
}
if(has_st018) {
if((size & 0x3ffff) == 0x28000) {
firmware_appended = true;
rom_size -= 0x28000;
}
}
}
void SuperFamicomCartridge::read_header(linput_t *li) {
int32 size = qlsize(li);
if(size < 0) return;
//skip copier header
uint32 start = 0;
has_copier_header = (size & 0x7fff) == 512;
if(has_copier_header) start += 512, size -= 512;
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = size;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_sharprtc = false;
has_epsonrtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts
//=====================
if(size >= 0x0140) {
uint8 data[0x140];
qlseek(li, start);
qlread(li, data, 0x140);
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
type = TypeGameBoy;
return;
}
}
if(size < 32768) {
type = TypeUnknown;
return;
}
const unsigned index = find_header(li);
header_offset = index;
uint8 extended_header[16 + 64];
qlseek(li, start + index - 16);
qlread(li, extended_header, 16 + 64);
uint8 * header = &extended_header[16];
const uint8 mapperid = header[Mapper];
const uint8 rom_type = header[RomType];
const uint8 lrom_size = header[RomSize];
const uint8 company = header[Company];
const uint8 regionid = header[CartRegion] & 0x7f;
ram_size = 1024 << (header[RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
if(lrom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes)
//0, 1, 13 = NTSC; 2 - 12 = PAL
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
//=======================
if(header[0x13] == 0x00 || header[0x13] == 0xff) {
if(header[0x14] == 0x00) {
const uint8 n15 = header[0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(header[0x1a] == 0x33 || header[0x1a] == 0xff) {
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
}
}
//=========================
//detect Sufami Turbo carts
//=========================
uint8 data[32];
qlseek(li, start);
qlread(li, data, 32);
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
type = TypeSufamiTurboBios;
} else {
type = TypeSufamiTurbo;
}
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(header, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(header, "Super GAMEBOY", 13)) {
type = TypeSuperGameBoy1Bios;
return;
}
//=====================
//detect standard carts
//=====================
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(header[-14] == 'Z') {
if(header[-11] == 'J') {
uint8 n13 = header[-13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (header[-10] == 0x00 && header[-4] == 0x00)) {
has_bsx_slot = true;
}
}
}
}
if(has_bsx_slot) {
if(!memcmp(header, "Satellaview BS-X ", 21)) {
//BS-X base cart
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else if(index == 0x7fc0) {
mapper = LoROM;
} else if(index == 0xffc0) {
mapper = HiROM;
} else { //index == 0x40ffc0
mapper = ExHiROM;
}
}
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (header[-3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapperid == 0x35 && rom_type == 0x55) {
has_sharprtc = true;
}
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_epsonrtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
has_dsp1 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
has_dsp1 = true;
}
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
has_dsp1 = true;
}
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM;
}
}
if(mapperid == 0x20 && rom_type == 0x05) {
has_dsp2 = true;
}
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
has_dsp3 = true;
}
if(mapperid == 0x30 && rom_type == 0x03) {
has_dsp4 = true;
}
if(mapperid == 0x30 && rom_type == 0x25) {
has_obc1 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size >= 10) {
has_st010 = true;
}
if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size < 10) {
has_st011 = true;
}
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}
unsigned SuperFamicomCartridge::find_header(linput_t *li) {
unsigned score_lo = score_header(li, 0x007fc0);
unsigned score_hi = score_header(li, 0x00ffc0);
unsigned score_ex = score_header(li, 0x40ffc0);
if(score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits
if(score_lo >= score_hi && score_lo >= score_ex) {
return 0x007fc0;
} else if(score_hi >= score_ex) {
return 0x00ffc0;
} else {
return 0x40ffc0;
}
}
unsigned SuperFamicomCartridge::score_header(linput_t *li, unsigned addr) {
int32 size = qlsize(li);
if(size < 0x8000) return 0;
//skip copier header
uint32 start = 0;
if((size & 0x7fff) == 512) start += 512, size -= 512;
if((uint32)size < addr + 64) return 0; //image too small to contain header at this location?
int score = 0;
uint8 header[64];
qlseek(li, start + addr);
qlread(li, header, 64);
uint16 resetvector = header[ResetVector] | (header[ResetVector + 1] << 8);
uint16 checksum = header[Checksum ] | (header[Checksum + 1] << 8);
uint16 complement = header[Complement ] | (header[Complement + 1] << 8);
uint32 resetop_addr = (addr & ~0x7fff) | (resetvector & 0x7fff);
if(qlseek(li, start + resetop_addr) != (start + resetop_addr)) return 0;
uint8 resetop;
if(qlread(li, &resetop, sizeof(uint8)) != sizeof(uint8)) return 0; //first opcode executed upon reset
uint8 mapper = header[Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit
//$00:[000-7fff] contains uninitialized RAM and MMIO.
//reset vector must point to ROM at $00:[8000-ffff] to be considered valid.
if(resetvector < 0x8000) return 0;
//some images duplicate the header in multiple locations, and others have completely
//invalid header information that cannot be relied upon.
//below code will analyze the first opcode executed at the specified reset vector to
//determine the probability that this is the correct header.
//most likely opcodes
if(resetop == 0x78 //sei
|| resetop == 0x18 //clc (clc; xce)
|| resetop == 0x38 //sec (sec; xce)
|| resetop == 0x9c //stz $nnnn (stz $4200)
|| resetop == 0x4c //jmp $nnnn
|| resetop == 0x5c //jml $nnnnnn
) score += 8;
//plausible opcodes
if(resetop == 0xc2 //rep #$nn
|| resetop == 0xe2 //sep #$nn
|| resetop == 0xad //lda $nnnn
|| resetop == 0xae //ldx $nnnn
|| resetop == 0xac //ldy $nnnn
|| resetop == 0xaf //lda $nnnnnn
|| resetop == 0xa9 //lda #$nn
|| resetop == 0xa2 //ldx #$nn
|| resetop == 0xa0 //ldy #$nn
|| resetop == 0x20 //jsr $nnnn
|| resetop == 0x22 //jsl $nnnnnn
) score += 4;
//implausible opcodes
if(resetop == 0x40 //rti
|| resetop == 0x60 //rts
|| resetop == 0x6b //rtl
|| resetop == 0xcd //cmp $nnnn
|| resetop == 0xec //cpx $nnnn
|| resetop == 0xcc //cpy $nnnn
) score -= 4;
//least likely opcodes
if(resetop == 0x00 //brk #$nn
|| resetop == 0x02 //cop #$nn
|| resetop == 0xdb //stp
|| resetop == 0x42 //wdm
|| resetop == 0xff //sbc $nnnnnn,x
) score -= 8;
//at times, both the header and reset vector's first opcode will match ...
//fallback and rely on info validity in these cases to determine more likely header.
//a valid checksum is the biggest indicator of a valid header.
if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4;
if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM
if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM
if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM
if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM
if(header[Company] == 0x33) score += 2; //0x33 indicates extended header
if(header[RomType] < 0x08) score++;
if(header[RomSize] < 0x10) score++;
if(header[RamSize] < 0x08) score++;
if(header[CartRegion] < 14) score++;
if(score < 0) score = 0;
return score;
}
const char * SuperFamicomCartridge::type_to_string(Type type)
{
switch(type)
{
case TypeNormal:
return "TypeNormal";
case TypeBsxSlotted:
return "TypeBsxSlotted";
case TypeBsxBios:
return "TypeBsxBios";
case TypeBsx:
return "TypeBsx";
case TypeSufamiTurboBios:
return "TypeSufamiTurboBios";
case TypeSufamiTurbo:
return "TypeSufamiTurbo";
case TypeSuperGameBoy1Bios:
return "TypeSuperGameBoy1Bios";
case TypeSuperGameBoy2Bios:
return "TypeSuperGameBoy2Bios";
case TypeGameBoy:
return "TypeGameBoy";
case TypeUnknown:
return "TypeUnknown";
}
return NULL;
}
SuperFamicomCartridge::Type SuperFamicomCartridge::string_to_type(const char * str)
{
if (streq(str, "TypeNormal"))
return TypeNormal;
else if (streq(str, "TypeBsxSlotted"))
return TypeBsxSlotted;
else if (streq(str, "TypeBsxBios"))
return TypeBsxBios;
else if (streq(str, "TypeBsx"))
return TypeBsx;
else if (streq(str, "TypeSufamiTurboBios"))
return TypeSufamiTurboBios;
else if (streq(str, "TypeSufamiTurbo"))
return TypeSufamiTurbo;
else if (streq(str, "TypeSuperGameBoy1Bios"))
return TypeSuperGameBoy1Bios;
else if (streq(str, "TypeSuperGameBoy2Bios"))
return TypeSuperGameBoy2Bios;
else if (streq(str, "TypeGameBoy"))
return TypeGameBoy;
else if (streq(str, "TypeUnknown"))
return TypeUnknown;
else
return TypeUnknown;
}
const char * SuperFamicomCartridge::region_to_string(Region region)
{
switch(region)
{
case NTSC:
return "NTSC";
case PAL:
return "PAL";
}
return NULL;
}
SuperFamicomCartridge::Region SuperFamicomCartridge::string_to_region(const char * str)
{
if (streq(str, "NTSC"))
return NTSC;
else if (streq(str, "PAL"))
return PAL;
else
return NTSC;
}
const char * SuperFamicomCartridge::mapper_to_string(MemoryMapper mapper)
{
switch(mapper)
{
case LoROM:
return "LoROM";
case HiROM:
return "HiROM";
case ExLoROM:
return "ExLoROM";
case ExHiROM:
return "ExHiROM";
case SuperFXROM:
return "SuperFXROM";
case SA1ROM:
return "SA1ROM";
case SPC7110ROM:
return "SPC7110ROM";
case BSCLoROM:
return "BSCLoROM";
case BSCHiROM:
return "BSCHiROM";
case BSXROM:
return "BSXROM";
case STROM:
return "STROM";
}
return NULL;
}
SuperFamicomCartridge::MemoryMapper SuperFamicomCartridge::string_to_mapper(const char * str)
{
if (streq(str, "LoROM"))
return LoROM;
else if (streq(str, "HiROM"))
return HiROM;
else if (streq(str, "ExLoROM"))
return ExLoROM;
else if (streq(str, "ExHiROM"))
return ExHiROM;
else if (streq(str, "SuperFXROM"))
return SuperFXROM;
else if (streq(str, "SA1ROM"))
return SA1ROM;
else if (streq(str, "SPC7110ROM"))
return SPC7110ROM;
else if (streq(str, "BSCLoROM"))
return BSCLoROM;
else if (streq(str, "BSCHiROM"))
return BSCHiROM;
else if (streq(str, "BSXROM"))
return BSXROM;
else if (streq(str, "STROM"))
return STROM;
else
return LoROM;
}
const char * SuperFamicomCartridge::dsp1_mapper_to_string(DSP1MemoryMapper dsp1_mapper)
{
switch(dsp1_mapper)
{
case DSP1Unmapped:
return "DSP1Unmapped";
case DSP1LoROM1MB:
return "DSP1LoROM1MB";
case DSP1LoROM2MB:
return "DSP1LoROM2MB";
case DSP1HiROM:
return "DSP1HiROM";
}
return NULL;
}
SuperFamicomCartridge::DSP1MemoryMapper SuperFamicomCartridge::string_to_dsp1_mapper(const char * str)
{
if (streq(str, "DSP1Unmapped"))
return DSP1Unmapped;
else if (streq(str, "DSP1LoROM1MB"))
return DSP1LoROM1MB;
else if (streq(str, "DSP1LoROM2MB"))
return DSP1LoROM2MB;
else if (streq(str, "DSP1HiROM"))
return DSP1HiROM;
else
return DSP1Unmapped;
}
const char * SuperFamicomCartridge::type_string() const
{
return type_to_string(type);
}
const char * SuperFamicomCartridge::region_string() const
{
return region_to_string(region);
}
const char * SuperFamicomCartridge::mapper_string() const
{
return mapper_to_string(mapper);
}
const char * SuperFamicomCartridge::dsp1_mapper_string() const
{
return dsp1_mapper_to_string(dsp1_mapper);
}
void SuperFamicomCartridge::read_hash(const netnode & node)
{
char buf[MAXSTR];
ssize_t len;
rom_size = node.hashval_long("rom_size");
ram_size = node.hashval_long("ram_size");
firmware_appended = node.hashval_long("firmware_appended") != 0;
header_offset = node.hashval_long("header_offset");
len = node.hashstr("type", buf, sizeof(buf));
if(len >= 0) type = string_to_type(buf);
len = node.hashstr("region", buf, sizeof(buf));
if(len >= 0) region = string_to_region(buf);
len = node.hashstr("mapper", buf, sizeof(buf));
if(len >= 0) mapper = string_to_mapper(buf);
len = node.hashstr("dsp1_mapper", buf, sizeof(buf));
if(len >= 0) dsp1_mapper = string_to_dsp1_mapper(buf);
has_bsx_slot = node.hashval_long("has_bsx_slot") != 0;
has_superfx = node.hashval_long("has_superfx") != 0;
has_sa1 = node.hashval_long("has_sa1") != 0;
has_sharprtc = node.hashval_long("has_sharprtc") != 0;
has_epsonrtc = node.hashval_long("has_epsonrtc") != 0;
has_sdd1 = node.hashval_long("has_sdd1") != 0;
has_spc7110 = node.hashval_long("has_spc7110") != 0;
has_cx4 = node.hashval_long("has_cx4") != 0;
has_dsp1 = node.hashval_long("has_dsp1") != 0;
has_dsp2 = node.hashval_long("has_dsp2") != 0;
has_dsp3 = node.hashval_long("has_dsp3") != 0;
has_dsp4 = node.hashval_long("has_dsp4") != 0;
has_obc1 = node.hashval_long("has_obc1") != 0;
has_st010 = node.hashval_long("has_st010") != 0;
has_st011 = node.hashval_long("has_st011") != 0;
has_st018 = node.hashval_long("has_st018") != 0;
}
void SuperFamicomCartridge::write_hash(netnode & node) const
{
node.hashset("rom_size", rom_size);
node.hashset("ram_size", ram_size);
node.hashset("firmware_appended", firmware_appended ? 1 : 0);
node.hashset("header_offset", header_offset);
node.hashset("type", type_string());
node.hashset("region", region_string());
node.hashset("mapper", mapper_string());
node.hashset("dsp1_mapper", dsp1_mapper_string());
node.hashset("has_bsx_slot", has_bsx_slot ? 1 : 0);
node.hashset("has_superfx", has_superfx ? 1 : 0);
node.hashset("has_sa1", has_sa1 ? 1 : 0);
node.hashset("has_sharprtc", has_sharprtc ? 1 : 0);
node.hashset("has_epsonrtc", has_epsonrtc ? 1 : 0);
node.hashset("has_sdd1", has_sdd1 ? 1 : 0);
node.hashset("has_spc7110", has_spc7110 ? 1 : 0);
node.hashset("has_cx4", has_cx4 ? 1 : 0);
node.hashset("has_dsp1", has_dsp1 ? 1 : 0);
node.hashset("has_dsp2", has_dsp2 ? 1 : 0);
node.hashset("has_dsp3", has_dsp3 ? 1 : 0);
node.hashset("has_dsp4", has_dsp4 ? 1 : 0);
node.hashset("has_obc1", has_obc1 ? 1 : 0);
node.hashset("has_st010", has_st010 ? 1 : 0);
node.hashset("has_st011", has_st011 ? 1 : 0);
node.hashset("has_st018", has_st018 ? 1 : 0);
}
void SuperFamicomCartridge::print() const
{
// print informations for debug purpose
msg("SuperFamicomCartridge::rom_size=%d\n", rom_size);
msg("SuperFamicomCartridge::ram_size=%d\n", ram_size);
msg("SuperFamicomCartridge::firmware_appended=%s\n", firmware_appended ? "true" : "false");
msg("SuperFamicomCartridge::has_copier_header=%s\n", has_copier_header ? "true" : "false");
msg("SuperFamicomCartridge::header_offset=0x%04X\n", header_offset);
msg("SuperFamicomCartridge::type=%d\n", type);
msg("SuperFamicomCartridge::region=%d\n", region);
msg("SuperFamicomCartridge::mapper=%d\n", mapper);
msg("SuperFamicomCartridge::dsp1_mapper=%d\n", dsp1_mapper);
msg("SuperFamicomCartridge::extra_chips=[");
if(has_bsx_slot) msg(" BSX Slot");
if(has_superfx) msg(" SuperFX");
if(has_sa1) msg(" SA1");
if(has_sharprtc) msg(" Sharp RTC");
if(has_epsonrtc) msg(" Epson RTC");
if(has_sdd1) msg(" SDD1");
if(has_spc7110) msg(" SPC7110");
if(has_cx4) msg(" CX4");
if(has_dsp1) msg(" DSP1");
if(has_dsp2) msg(" DSP2");
if(has_dsp3) msg(" DSP3");
if(has_dsp4) msg(" DSP4");
if(has_obc1) msg(" OBC1");
if(has_st010) msg(" ST010");
if(has_st011) msg(" ST011");
if(has_st018) msg(" ST018");
msg(" ]\n");
}
#endif //__SUPER_FAMICOM_HPP__

Some files were not shown because too many files have changed in this diff Show More