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

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,
};