349 lines
8.7 KiB
C++
349 lines
8.7 KiB
C++
/*
|
|
* 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,
|
|
};
|