update to ida 7.6, add builds
This commit is contained in:
376
idasdk76/module/iohandler.hpp
Normal file
376
idasdk76/module/iohandler.hpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
|
||||
This file contains functions common to many processor modules
|
||||
to manage configuration files. The following functions can be called:
|
||||
|
||||
bool apply_config_file(int _respect_info);
|
||||
Read and parse the config file
|
||||
|
||||
void set_device_name(const char *dname, int respect_info);
|
||||
Set a new device name and reread the config file
|
||||
|
||||
bool display_infotype_dialog(int *respect_info, const char *cfgname);
|
||||
Display a form and allow the user to clear some IORESP_ bits
|
||||
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <pro.h>
|
||||
#include <ida.hpp>
|
||||
#include <netnode.hpp>
|
||||
#include <bytes.hpp>
|
||||
#include <diskio.hpp>
|
||||
#include <segment.hpp>
|
||||
#include <entry.hpp>
|
||||
#include <name.hpp>
|
||||
#include <xref.hpp>
|
||||
#include <offset.hpp>
|
||||
#include <idp.hpp>
|
||||
|
||||
struct iohandler_t
|
||||
{
|
||||
qstring device;
|
||||
ioports_t ports;
|
||||
qstring deviceparams;
|
||||
#define IORESP_PORT 1 // rename port names in memory
|
||||
#define IORESP_AREA 2 // respect "area" directives
|
||||
#define IORESP_INT 4 // respect interrupt information
|
||||
|
||||
#define IORESP_ALL (IORESP_PORT|IORESP_AREA|IORESP_INT)
|
||||
#define IORESP_NONE 0
|
||||
int respect_info = IORESP_NONE;
|
||||
netnode &helper;
|
||||
|
||||
iohandler_t(netnode &_helper) : helper(_helper) {}
|
||||
virtual ~iohandler_t() {}
|
||||
|
||||
#define NONEPROC "NONE"
|
||||
|
||||
// Option: additional segment class to appear in the device description
|
||||
// Default: EEPROM
|
||||
virtual const char *aux_segm() const { return "EEPROM"; }
|
||||
|
||||
// Option: respect configuration information for different file types?
|
||||
// Default: only binary-like files use IORESP_PORT, AREA, INT
|
||||
virtual bool check_ioresp() const { return inf_like_binary(); }
|
||||
|
||||
// Option: a callback function to parse additional configuration file lines
|
||||
// Default: "interrupt" and "entry" keywords are recognized
|
||||
virtual const char *iocallback(const ioports_t &iop, const char *line)
|
||||
{
|
||||
return standard_callback(iop, line);
|
||||
}
|
||||
|
||||
// can be used as object handler for read_ioports2()
|
||||
struct ioports_loader_t : public ioports_fallback_t
|
||||
{
|
||||
iohandler_t *_this;
|
||||
ioports_loader_t(iohandler_t *_t) : _this(_t) {}
|
||||
|
||||
virtual bool handle(qstring *errbuf, const ioports_t &_ports, const char *line) override
|
||||
{
|
||||
const char *errmsg = _this->iocallback(_ports, line);
|
||||
if ( errmsg == nullptr )
|
||||
return true;
|
||||
if ( errmsg == IOPORT_SKIP_DEVICE )
|
||||
errmsg = "SKIP device (logic error):";
|
||||
*errbuf = errmsg;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Option: the function that will actually apply the IO port info into the IDB.
|
||||
// Default: will simply set name & comment.
|
||||
virtual void apply_io_port(ea_t ea, const char *name, const char *cmt)
|
||||
{
|
||||
set_name(ea, name, SN_NODUMMY);
|
||||
set_cmt(ea, cmt, true);
|
||||
}
|
||||
|
||||
// Option: the function that will be called for unknown directives
|
||||
// (e.g., "area", "mirror", ...)
|
||||
// Default: standard_handle_unknown_directive
|
||||
virtual const char *handle_unknown_directive(const char *line)
|
||||
{
|
||||
return parse_area_line(&deviceparams, line);
|
||||
}
|
||||
|
||||
// Option: function to handle entry points
|
||||
// Default: create an entry point
|
||||
//-V:entry_processing:669
|
||||
virtual bool entry_processing(ea_t &, const char * /*word*/, const char * /*cmt*/) { return false; }
|
||||
|
||||
// Option: function to handle areas
|
||||
// Default: create a segment
|
||||
virtual bool area_processing(ea_t /*start*/, ea_t /*end*/, const char * /*name*/, const char * /*aclass*/) { return false; }
|
||||
|
||||
virtual bool segment_created(ea_t /*start*/, ea_t /*end*/, const char * /*name*/, const char * /*aclass*/) { return false; }
|
||||
|
||||
// Option: define function get_cfg_path()
|
||||
// Default: yes, it returns a file name using the current processor name
|
||||
virtual void get_cfg_filename(char *buf, size_t bufsize)
|
||||
{
|
||||
inf_get_procname(buf, bufsize);
|
||||
qstrlwr(buf);
|
||||
qstrncat(buf, ".cfg", bufsize);
|
||||
}
|
||||
|
||||
GCC_DIAG_OFF(format-nonliteral);
|
||||
//------------------------------------------------------------------
|
||||
const char *parse_area_line(qstring *buf, const char *line)
|
||||
{
|
||||
if ( line[0] != ';' )
|
||||
{
|
||||
char word[MAXSTR];
|
||||
char aclass[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
aclass[MAXSTR-1] = '\0';
|
||||
ea_t ea1, ea2;
|
||||
CASSERT(MAXSTR == 1024);
|
||||
if ( qsscanf(line, "area %1023s %1023s %a:%a", aclass, word, &ea1, &ea2) == 4 )
|
||||
{
|
||||
size_t _ram = 0;
|
||||
size_t _rom = 0;
|
||||
size_t _eprom = 0;
|
||||
size_t _eeprom = 0;
|
||||
qstring format("RAM=%" FMT_Z " ROM=%" FMT_Z " EPROM=%" FMT_Z " ");
|
||||
format.append(aux_segm());
|
||||
format.append("=%" FMT_Z);
|
||||
qsscanf(buf->c_str(), format.c_str(), &_ram, &_rom, &_eprom, &_eeprom);
|
||||
size_t size = size_t(ea2 - ea1);
|
||||
if ( stristr(word, "RAM") != NULL )
|
||||
_ram += size;
|
||||
else if ( stristr(word, aux_segm()) != NULL )
|
||||
_eeprom += size;
|
||||
else if ( stristr(word, "EPROM") != NULL )
|
||||
_eprom += size;
|
||||
else if ( stristr(word, "ROM") != NULL )
|
||||
_rom += size;
|
||||
if ( _ram || _rom || _eprom || _eeprom )
|
||||
buf->sprnt(format.c_str(), _ram, _rom, _eprom, _eeprom);
|
||||
else
|
||||
buf->qclear();
|
||||
if ( (respect_info & IORESP_AREA) != 0 && get_first_seg() != NULL )
|
||||
{
|
||||
if ( !area_processing(ea1, ea2, word, aclass) )
|
||||
{
|
||||
if ( !segment_created(ea1, ea2, word, aclass) )
|
||||
{
|
||||
segment_t s;
|
||||
s.sel = setup_selector(0);
|
||||
s.start_ea = ea1;
|
||||
s.end_ea = ea2;
|
||||
s.align = saRelByte;
|
||||
s.comb = streq(aclass, "STACK") ? scStack : scPub;
|
||||
s.bitness = PH.get_segm_bitness();
|
||||
if ( s.bitness == 0 && s.size() > 0xFFFF )
|
||||
s.bitness = 1;
|
||||
int sfl = ADDSEG_NOSREG;
|
||||
if ( !is_loaded(s.start_ea) )
|
||||
sfl |= ADDSEG_SPARSE;
|
||||
add_segm_ex(&s, word, aclass, sfl);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return "syntax error";
|
||||
}
|
||||
GCC_DIAG_ON(format-nonliteral);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
struct parse_area_line0_t : public choose_ioport_parser_t
|
||||
{
|
||||
iohandler_t &_this;
|
||||
parse_area_line0_t(iohandler_t &_t) : _this(_t) {}
|
||||
|
||||
virtual bool parse(qstring *param, const char *line) override
|
||||
{
|
||||
_this.respect_info = 0;
|
||||
_this.parse_area_line(param, line);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------
|
||||
const char *idaapi standard_callback(const ioports_t &, const char *line)
|
||||
{
|
||||
int len;
|
||||
ea_t ea1;
|
||||
char word[MAXSTR];
|
||||
word[MAXSTR-1] = '\0';
|
||||
CASSERT(MAXSTR == 1024);
|
||||
if ( qsscanf(line, "interrupt %1023s %" FMT_EA "i%n", word, &ea1, &len) == 2 )
|
||||
{
|
||||
if ( (respect_info & IORESP_INT) != 0 )
|
||||
{
|
||||
ea_t proc, wrong;
|
||||
segment_t *s = getseg(ea1);
|
||||
if ( s == nullptr || s->is_16bit() )
|
||||
{
|
||||
create_word(ea1, 2);
|
||||
proc = get_word(ea1);
|
||||
wrong = 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
create_dword(ea1, 4);
|
||||
proc = get_dword(ea1);
|
||||
wrong = 0xFFFFFFFF;
|
||||
}
|
||||
if ( proc != wrong && is_mapped(proc) )
|
||||
{
|
||||
op_plain_offset(ea1, 0, 0);
|
||||
add_entry(proc, proc, word, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_name(ea1, word, SN_NODUMMY);
|
||||
}
|
||||
const char *ptr = &line[len];
|
||||
ptr = skip_spaces(ptr);
|
||||
if ( ptr[0] != '\0' )
|
||||
set_cmt(ea1, ptr, true);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if ( qsscanf(line, "entry %1023s %" FMT_EA "i%n", word, &ea1, &len) == 2 )
|
||||
{
|
||||
if ( (respect_info & IORESP_INT) != 0 )
|
||||
{
|
||||
if ( is_mapped(ea1) )
|
||||
{
|
||||
const char *ptr = &line[len];
|
||||
ptr = skip_spaces(ptr);
|
||||
if ( !entry_processing(ea1, word, ptr) )
|
||||
{
|
||||
add_entry(ea1, ea1, word, true);
|
||||
if ( ptr[0] != '\0' )
|
||||
set_cmt(ea1, ptr, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return handle_unknown_directive(line);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
bool apply_config_file(int _respect_info)
|
||||
{
|
||||
if ( device == NONEPROC ) // processor not selected
|
||||
return true;
|
||||
|
||||
char cfgfile[QMAXFILE];
|
||||
get_cfg_filename(cfgfile, sizeof(cfgfile));
|
||||
deviceparams.qclear();
|
||||
if ( !check_ioresp() )
|
||||
_respect_info = 0;
|
||||
respect_info = _respect_info;
|
||||
ports.clear();
|
||||
ioports_loader_t ldr(this);
|
||||
read_ioports2(&ports, &device, cfgfile, &ldr);
|
||||
if ( respect_info & IORESP_PORT )
|
||||
{
|
||||
for ( size_t i=0; i < ports.size(); i++ )
|
||||
{
|
||||
const ioport_t &p = ports[i];
|
||||
ea_t ea = p.address;
|
||||
apply_io_port(ea, p.name.c_str(), p.cmt.c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void set_device_name(const char *dname, int respinfo)
|
||||
{
|
||||
if ( dname != NULL )
|
||||
{
|
||||
device = dname;
|
||||
helper.supset(-1, device.c_str());
|
||||
apply_config_file(respinfo);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
void restore_device(int respinfo = IORESP_NONE)
|
||||
{
|
||||
if ( helper.supstr(&device, -1) > 0 )
|
||||
apply_config_file(respinfo);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Some processor modules wrongly store device with index 0 (some store
|
||||
// duplicate value with both indices 0 and -1). Upgrade IDB to use -1
|
||||
void upgrade_device_index()
|
||||
{
|
||||
qstring old_device;
|
||||
if ( helper.supstr(&old_device, 0) >= 0 )
|
||||
{
|
||||
helper.supset(-1, old_device.c_str());
|
||||
helper.supdel(0);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Display a dialog form with the information types
|
||||
// Let the user to clear some checkboxes if he wants so
|
||||
// Returns: true - the user clicked OK
|
||||
bool display_infotype_dialog(
|
||||
int display_info,
|
||||
int *p_resp_info,
|
||||
const char *cfg_filename)
|
||||
{
|
||||
if ( display_info == 0 )
|
||||
return false;
|
||||
static const char *const form =
|
||||
"Loaded information type\n"
|
||||
"\n"
|
||||
"Please specify what information should be loaded from\n"
|
||||
"the configuration file %s to the database.\n"
|
||||
"\n"
|
||||
"If the input file does not contain parts corresponding to\n"
|
||||
"the segmentation defined in the config file, you might want\n"
|
||||
"to clear the 'memory layout' checkbox or even cancel this\n"
|
||||
"dialog box.\n";
|
||||
char buf[MAXSTR];
|
||||
char *ptr = buf + qsnprintf(buf, sizeof(buf), form, cfg_filename);
|
||||
char *const end = buf + sizeof(buf);
|
||||
int B = 1;
|
||||
ushort b = 0;
|
||||
ushort r = (ushort)*p_resp_info;
|
||||
#define ADD_FIELD(bit, desc) \
|
||||
if ( display_info & bit ) \
|
||||
{ \
|
||||
if ( r & bit ) \
|
||||
b |= B; \
|
||||
B <<= 1; \
|
||||
APPEND(ptr, end, desc); \
|
||||
}
|
||||
ADD_FIELD(IORESP_PORT, "\n<#Rename port and I/O registers#I/O ports:C>")
|
||||
ADD_FIELD(IORESP_AREA, "\n<#Adjust the segments#Memory layout:C>")
|
||||
ADD_FIELD(IORESP_INT, "\n<#Create interrupt vectors and/or entry points#Interrupts:C>")
|
||||
#undef ADD_FIELD
|
||||
qnotused(B);
|
||||
APPEND(ptr, end, ">\n\n");
|
||||
if ( !ask_form(buf, &b) )
|
||||
return false;
|
||||
B = 1;
|
||||
if ( display_info & IORESP_PORT )
|
||||
{
|
||||
setflag(r, IORESP_PORT, (B & b) != 0);
|
||||
B <<= 1;
|
||||
}
|
||||
if ( display_info & IORESP_AREA )
|
||||
{
|
||||
setflag(r, IORESP_AREA, (B & b) != 0);
|
||||
B <<= 1;
|
||||
}
|
||||
if ( display_info & IORESP_INT )
|
||||
setflag(r, IORESP_INT, (B & b) != 0);
|
||||
*p_resp_info = r;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user