740 lines
25 KiB
C++
740 lines
25 KiB
C++
#ifndef __DEBUGGER_MODULE__
|
|
#define __DEBUGGER_MODULE__
|
|
|
|
//
|
|
//
|
|
// This is the base debmod_t class definition
|
|
// From this class all debugger code must inherite and specialize
|
|
//
|
|
// Some OS specific functions must be implemented:
|
|
// bool init_subsystem();
|
|
// bool term_subsystem();
|
|
// debmod_t *create_debug_session(void *);
|
|
// int create_thread(thread_cb_t thread_cb, void *context);
|
|
//
|
|
|
|
#include <deque>
|
|
|
|
#include <pro.h>
|
|
#include <idd.hpp>
|
|
#include <network.hpp>
|
|
|
|
//--------------------------------------------------------------------------
|
|
extern debugger_t debugger;
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct name_info_t
|
|
{
|
|
eavec_t addrs;
|
|
qvector<char *> names;
|
|
void clear(void)
|
|
{
|
|
addrs.clear();
|
|
names.clear();
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Extended process info
|
|
struct ext_process_info_t : public process_info_t
|
|
{
|
|
int addrsize; // process bitness 32bit - 4, 64bit - 8, 0 - unknown
|
|
qstring ext_name; // human-readable name (e.g. with command line agrs)
|
|
void copy_to(process_info_t *dst)
|
|
{
|
|
dst->pid = pid;
|
|
dst->name = ext_name.empty() ? name : ext_name;
|
|
}
|
|
};
|
|
typedef qvector<ext_process_info_t> procvec_t;
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Very simple class to store pending events
|
|
enum queue_pos_t
|
|
{
|
|
IN_FRONT,
|
|
IN_BACK
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct pagebpt_data_t
|
|
{
|
|
ea_t ea; // address of the bpt as specified by the user
|
|
ea_t page_ea; // real address of the bpt as written to the process
|
|
int user_len; // breakpoint length as specified by the user
|
|
int aligned_len; // breakpoint length aligned to the page size
|
|
int real_len; // real length of the breakpoint as written to the process
|
|
uint32 old_prot; // old page protections (before writing the bpt to the process)
|
|
// if 0, the bpt has not been written to the process yet.
|
|
uint32 new_prot; // new page protections (when the bpt is active)
|
|
bpttype_t type; // breakpoint type
|
|
};
|
|
|
|
// Information about page breakpoints is stored in this data structure.
|
|
// The map is indexed by the page start address (not the address specified
|
|
// by the user!)
|
|
typedef std::map<ea_t, pagebpt_data_t> page_bpts_t; // page_ea -> bpt info
|
|
typedef qvector<page_bpts_t::iterator> pbpt_iterators_t; // list of iterators into page_bpts_t
|
|
|
|
//--------------------------------------------------------------------------
|
|
// set of addresses
|
|
typedef std::set<ea_t> easet_t;
|
|
|
|
//-------------------------------------------------------------------------
|
|
class idc_value_t;
|
|
class rpc_engine_t;
|
|
error_t idaapi idc_get_reg_value(idc_value_t *argv, idc_value_t *r);
|
|
error_t idaapi idc_set_reg_value(idc_value_t *argv, idc_value_t *r);
|
|
void report_idc_error(rpc_engine_t *rpc, ea_t ea, error_t code, ssize_t errval, const char *errprm);
|
|
|
|
// IDC function name that is exported by a debugger module
|
|
// to allow scripts to send debugger commands
|
|
#define IDC_SENDDBG_CMD "send_dbg_command"
|
|
#define IDC_READ_MSR "read_msr"
|
|
#define IDC_WRITE_MSR "write_msr"
|
|
#define IDC_STEP_BACK "step_back"
|
|
#define IDC_SET_TEV "set_current_tev"
|
|
#define IDC_GET_TEV "get_current_tev"
|
|
|
|
// A macro to convert a pointer to ea_t without sign extension.
|
|
#define EA_T(ptr) (ea_t)(size_t)(ptr)
|
|
|
|
//--------------------------------------------------------------------------
|
|
//-V:debmod_bpt_t:730 not all members of a class are initialized inside the constructor: saved
|
|
struct debmod_bpt_t
|
|
{
|
|
ea_t ea;
|
|
uchar saved[8]; // size of the biggest supported bpt size (PPC64)
|
|
uchar nsaved;
|
|
int bid; // (epoc) breakpoint id (from TRK)
|
|
debmod_bpt_t() : ea(BADADDR), nsaved(0), bid(0) {}
|
|
debmod_bpt_t(ea_t _ea, uchar _nsaved) : ea(_ea), nsaved(_nsaved), bid(0) { QASSERT(1796, nsaved < sizeof(saved)); }
|
|
};
|
|
typedef std::map<ea_t, debmod_bpt_t> debmodbpt_map_t;
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct eventlist_t : public std::deque<debug_event_t>
|
|
{
|
|
public:
|
|
// save a pending event
|
|
void enqueue(const debug_event_t &ev, queue_pos_t pos)
|
|
{
|
|
if ( pos != IN_BACK )
|
|
push_front(ev);
|
|
else
|
|
push_back(ev);
|
|
}
|
|
|
|
// retrieve a pending event
|
|
bool retrieve(debug_event_t *event)
|
|
{
|
|
if ( empty() )
|
|
return false;
|
|
// get the first event and return it
|
|
*event = front();
|
|
pop_front();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
int send_ioctl(rpc_engine_t *rpc, int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize);
|
|
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
|
|
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
|
|
void set_arm_thumb_modes(ea_t *addrs, int qty);
|
|
char *debug_event_str(const debug_event_t *ev, char *buf, size_t bufsize);
|
|
char *debug_event_str(const debug_event_t *ev); // returns static buf
|
|
|
|
//--------------------------------------------------------------------------
|
|
// describes a dll to be imported
|
|
struct import_request_t
|
|
{
|
|
ea_t base;
|
|
qstring path;
|
|
bytevec_t uuid;
|
|
import_request_t(ea_t _base, const qstring &_path, const bytevec_t &_uuid)
|
|
: base(_base), path(_path), uuid(_uuid) {}
|
|
};
|
|
DECLARE_TYPE_AS_MOVABLE(import_request_t);
|
|
typedef qvector<import_request_t> import_infos_t;
|
|
int import_dll(const import_request_t &req);
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct regctx_t;
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct regctx_entry_t
|
|
{
|
|
enum type_t
|
|
{
|
|
IVAL = 0,
|
|
FVAL = 1,
|
|
DATA = 2,
|
|
FUNC = 3,
|
|
} type;
|
|
int reg_class;
|
|
int reg_idx;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
size_t offset_in_ctx;
|
|
size_t size_in_ctx;
|
|
size_t reg_size;
|
|
};
|
|
struct
|
|
{
|
|
void (*read_func)(const regctx_t *, regval_t *, void *);
|
|
void (*write_func)(regctx_t *, const regval_t *, void *);
|
|
void *user_data;
|
|
};
|
|
};
|
|
|
|
uint64_t truncate_ival(uint64_t ival) const
|
|
{
|
|
switch ( reg_size )
|
|
{
|
|
case 1: ival = uint8_t(ival); break;
|
|
case 2: ival = uint16_t(ival); break;
|
|
case 4: ival = uint32_t(ival); break;
|
|
}
|
|
return ival;
|
|
}
|
|
|
|
void read(regval_t *value, const uint8_t *ptr) const
|
|
{
|
|
if ( type == regctx_entry_t::FUNC )
|
|
{
|
|
read_func((regctx_t *) ptr, value, user_data);
|
|
}
|
|
else
|
|
{
|
|
const uint8_t *p = ptr + offset_in_ctx;
|
|
switch ( type )
|
|
{
|
|
case regctx_entry_t::IVAL:
|
|
{
|
|
uint64_t ival = 0;
|
|
switch ( size_in_ctx )
|
|
{
|
|
case 1: ival = *(uint8_t *)p; break;
|
|
case 2: ival = *(uint16_t *)p; break;
|
|
case 4: ival = *(uint32_t *)p; break;
|
|
case 8: ival = *(uint64_t *)p; break;
|
|
}
|
|
ival = truncate_ival(ival);
|
|
value->ival = ival;
|
|
}
|
|
break;
|
|
case regctx_entry_t::FVAL:
|
|
// TODO: for x86, the value is converted to IEEE format in
|
|
// x86_read_registers(). clean this up somehow.
|
|
memcpy(&value->fval, p, size_in_ctx);
|
|
value->rvtype = RVT_FLOAT;
|
|
break;
|
|
case regctx_entry_t::DATA:
|
|
value->set_bytes(p, size_in_ctx);
|
|
break;
|
|
case regctx_entry_t::FUNC:
|
|
// never happens; makes compiler happy.
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool patch(uint8_t *ptr, const regval_t *value) const
|
|
{
|
|
if ( type == regctx_entry_t::FUNC )
|
|
{
|
|
write_func((regctx_t *) ptr, value, user_data);
|
|
}
|
|
else
|
|
{
|
|
uint8_t *p = ptr + offset_in_ctx;
|
|
switch ( type )
|
|
{
|
|
case regctx_entry_t::IVAL:
|
|
{
|
|
uint64_t ival = value->ival;
|
|
ival = truncate_ival(ival);
|
|
switch ( size_in_ctx )
|
|
{
|
|
case 1: *(uint8_t *)p = ival; break;
|
|
case 2: *(uint16_t *)p = ival; break;
|
|
case 4: *(uint32_t *)p = ival; break;
|
|
case 8: *(uint64_t *)p = ival; break;
|
|
}
|
|
}
|
|
break;
|
|
case regctx_entry_t::FVAL:
|
|
// TODO: for x86, the value is converted from IEEE format in
|
|
// x86_write_register(). clean this up somehow.
|
|
memcpy(p, &value->fval, size_in_ctx);
|
|
break;
|
|
case regctx_entry_t::DATA:
|
|
if ( value->get_data_size() != size_in_ctx )
|
|
return false;
|
|
memcpy(p, value->get_data(), value->get_data_size());
|
|
break;
|
|
case regctx_entry_t::FUNC:
|
|
// never happens; makes compiler happy.
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
DECLARE_TYPE_AS_MOVABLE(regctx_entry_t);
|
|
typedef qvector<regctx_entry_t> reg_ctx_entries_t;
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct regctx_base_t
|
|
{
|
|
dynamic_register_set_t &idaregs; // linked to debmod_t's variable of the same name
|
|
thid_t tid;
|
|
int clsmask;
|
|
|
|
reg_ctx_entries_t entries;
|
|
|
|
void setup(thid_t _tid, int _clsmask=0)
|
|
{
|
|
tid = _tid;
|
|
clsmask = _clsmask;
|
|
}
|
|
|
|
void setup_reg(int dyn_reg_idx)
|
|
{
|
|
clsmask |= entries[dyn_reg_idx].reg_class;
|
|
}
|
|
|
|
regctx_base_t(dynamic_register_set_t &_idaregs)
|
|
: idaregs(_idaregs)
|
|
{
|
|
setup(0, 0);
|
|
}
|
|
|
|
void add_idareg(register_info_t &ri)
|
|
{
|
|
idaregs.add_register(ri.name,
|
|
ri.flags,
|
|
ri.dtype,
|
|
ri.register_class,
|
|
ri.bit_strings,
|
|
ri.default_bit_strings_mask);
|
|
}
|
|
|
|
size_t add_entry(
|
|
regctx_entry_t::type_t type,
|
|
register_info_t &ri,
|
|
size_t offset_in_ctx,
|
|
size_t size_in_ctx,
|
|
size_t reg_size)
|
|
{
|
|
size_t dyn_reg_idx = entries.size();
|
|
regctx_entry_t &entry = entries.push_back();
|
|
entry.type = type;
|
|
entry.reg_class = ri.register_class;
|
|
entry.reg_idx = dyn_reg_idx;
|
|
entry.offset_in_ctx = offset_in_ctx;
|
|
entry.size_in_ctx = size_in_ctx;
|
|
entry.reg_size = reg_size;
|
|
add_idareg(ri);
|
|
return dyn_reg_idx;
|
|
}
|
|
|
|
size_t add_ival(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
|
{
|
|
QASSERT(1797, size_in_ctx <= sizeof(regval_t::ival));
|
|
size_t reg_size = ri.dtype == dt_word ? 2
|
|
: ri.dtype == dt_dword ? 4
|
|
: ri.dtype == dt_qword ? 8
|
|
: 0;
|
|
QASSERT(1798, reg_size != 0);
|
|
return add_entry(regctx_entry_t::IVAL, ri, offset_in_ctx, size_in_ctx, reg_size);
|
|
}
|
|
|
|
size_t add_fval(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
|
{
|
|
QASSERT(1799, size_in_ctx <= sizeof(regval_t::fval));
|
|
return add_entry(regctx_entry_t::FVAL, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
|
|
}
|
|
|
|
size_t add_data(register_info_t &ri, size_t offset_in_ctx, size_t size_in_ctx)
|
|
{
|
|
return add_entry(regctx_entry_t::DATA, ri, offset_in_ctx, size_in_ctx, size_in_ctx);
|
|
}
|
|
|
|
size_t add_func(
|
|
register_info_t &ri,
|
|
void (*read_func)(const regctx_t *, regval_t *, void *),
|
|
void (*write_func)(regctx_t *, const regval_t *, void *),
|
|
void *user_data=nullptr)
|
|
{
|
|
size_t dyn_reg_idx = entries.size();
|
|
regctx_entry_t &entry = entries.push_back();
|
|
entry.type = regctx_entry_t::FUNC;
|
|
entry.reg_class = ri.register_class;
|
|
entry.reg_idx = dyn_reg_idx;
|
|
entry.read_func = read_func;
|
|
entry.write_func = write_func;
|
|
entry.user_data = user_data;
|
|
add_idareg(ri);
|
|
return dyn_reg_idx;
|
|
}
|
|
|
|
void read_all(regval_t *values)
|
|
{
|
|
for ( const regctx_entry_t &entry: entries )
|
|
if ( (clsmask & entry.reg_class) != 0 )
|
|
entry.read(&values[entry.reg_idx], (const uint8_t *) this);
|
|
}
|
|
|
|
bool patch(int dyn_reg_idx, const regval_t *value)
|
|
{
|
|
return entries[dyn_reg_idx].patch((uint8_t *) this, value);
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Main class to represent a debugger module
|
|
class debmod_t
|
|
{
|
|
protected:
|
|
// processor_t &ph;
|
|
typedef std::map<int, regval_t> regval_map_t;
|
|
qvector<exception_info_t> exceptions;
|
|
name_info_t dn_names;
|
|
// Pending events. currently used only to store
|
|
// exceptions that happen while attaching
|
|
eventlist_t events;
|
|
// The last event received via a successful get_debug_event()
|
|
debug_event_t last_event;
|
|
|
|
// debugged process attributes (may be changed after process start/attach)
|
|
debapp_attrs_t debapp_attrs;
|
|
|
|
procvec_t proclist;
|
|
|
|
// appcall contexts
|
|
struct call_context_t
|
|
{
|
|
regvals_t saved_regs;
|
|
ea_t sp;
|
|
ea_t ctrl_ea;
|
|
bool regs_spoiled;
|
|
call_context_t() : sp(BADADDR), ctrl_ea(BADADDR), regs_spoiled(false) {}
|
|
};
|
|
typedef qstack<call_context_t> call_contexts_t;
|
|
typedef std::map<thid_t, call_contexts_t> appcalls_t;
|
|
appcalls_t appcalls;
|
|
|
|
int send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize)
|
|
{
|
|
return ::send_ioctl(rpc, fn, buf, size, poutbuf, poutsize);
|
|
}
|
|
// If an IDC error occurs: we cannot prepare an error message on the server
|
|
// side because we do not have access to error strings (they are in ida.hlp).
|
|
// We pass the error code to IDA (with eventual arguments) so it can prepare
|
|
// a nice error message for the user
|
|
void report_idc_error(ea_t ea, error_t code, ssize_t errval, const char *errprm)
|
|
{
|
|
return ::report_idc_error(rpc, ea, code, errval, errprm);
|
|
}
|
|
|
|
typedef std::map<ea_t, lowcnd_t> lowcnds_t;
|
|
lowcnds_t cndmap;
|
|
eavec_t handling_lowcnds;
|
|
bool evaluate_and_handle_lowcnd(debug_event_t *event, int elc_flags=0);
|
|
bool handle_lowcnd(lowcnd_t *lc, debug_event_t *event, int elc_flags);
|
|
#define ELC_KEEP_EIP 0x0001 // do not reset eip before stepping
|
|
#define ELC_KEEP_SUSP 0x0002 // keep suspended state, do not resume after stepping
|
|
|
|
// helper functions for programmatical single stepping
|
|
virtual drc_t dbg_perform_single_step(debug_event_t *event, const insn_t &ins);
|
|
virtual int dbg_freeze_threads_except(thid_t) { return 0; }
|
|
virtual int dbg_thaw_threads_except(thid_t) { return 0; }
|
|
drc_t resume_app_and_get_event(debug_event_t *dev);
|
|
void set_platform(const char *platform_name);
|
|
|
|
// return number of processes, -1 - not implemented
|
|
virtual int idaapi get_process_list(procvec_t *proclist, qstring *errbuf);
|
|
|
|
public:
|
|
// initialized by dbg_init()
|
|
int debugger_flags;
|
|
meminfo_vec_t old_ranges;
|
|
rpc_engine_t *rpc;
|
|
bool debug_debugger;
|
|
// Is dynamic library?
|
|
bool is_dll;
|
|
|
|
// indexes of sp and program counter registers.
|
|
// Must be initialized by derived classes.
|
|
int sp_idx;
|
|
int pc_idx;
|
|
|
|
// index of frame pointer register
|
|
int fp_idx;
|
|
|
|
// Total number of registers.
|
|
// Must be initialized by derived classes.
|
|
int nregs;
|
|
|
|
// Breakpoint code.
|
|
// Must be initialized by derived classes.
|
|
bytevec_t bpt_code;
|
|
|
|
qstring input_file_path;
|
|
|
|
page_bpts_t page_bpts;
|
|
|
|
// will either send as msg/warning/error through callui,
|
|
// or through 'rpc' if it is present.
|
|
DEFINE_ALL_NOTIFICATION_FUNCTIONS(rpc);
|
|
AS_PRINTF(3,0) static ssize_t dvnotif(int code, rpc_engine_t *rpc, const char *format, va_list va);
|
|
|
|
bool broken_connection;
|
|
pid_t pid;
|
|
|
|
debmodbpt_map_t bpts;
|
|
update_bpt_vec_t deleted_bpts; // deleted bpts in the last update_bpts() call
|
|
// if bpt EA was deleted then bpt raised in the same place for the
|
|
// same thread does not belong to IDA
|
|
bool is_ida_bpt(ea_t ea, thid_t tid)
|
|
{
|
|
if ( bpts.find(ea) != bpts.end() )
|
|
return true;
|
|
update_bpt_info_t b;
|
|
b.ea = ea;
|
|
return deleted_bpts.find(b) != deleted_bpts.end()
|
|
&& (last_event.eid() != BREAKPOINT
|
|
|| last_event.ea != ea
|
|
|| last_event.tid != tid);
|
|
}
|
|
|
|
static bool reuse_broken_connections;
|
|
|
|
//------------------------------------
|
|
// Dynamic register set for debugger_t
|
|
//------------------------------------
|
|
dynamic_register_set_t idaregs;
|
|
|
|
//------------------------------------
|
|
// Constructors and destructors
|
|
//------------------------------------
|
|
debmod_t();
|
|
virtual ~debmod_t() { cleanup(); }
|
|
|
|
//------------------------------------
|
|
// Debug names methods
|
|
//------------------------------------
|
|
void clear_debug_names();
|
|
name_info_t *get_debug_names();
|
|
void save_debug_name(ea_t ea, const char *name);
|
|
int set_debug_names();
|
|
int send_debug_names_to_ida(ea_t *addrs, const char *const *names, int qty);
|
|
int send_debug_event_to_ida(const debug_event_t *ev, int rqflags);
|
|
ea_t find_debug_name(const char *name) const;
|
|
//------------------------------------
|
|
// Utility methods
|
|
//------------------------------------
|
|
void cleanup(void);
|
|
AS_PRINTF(2, 3) void debdeb(const char *format, ...);
|
|
AS_PRINTF(2, 3) bool deberr(const char *format, ...);
|
|
bool same_as_oldmemcfg(const meminfo_vec_t &ranges) const;
|
|
void save_oldmemcfg(const meminfo_vec_t &ranges);
|
|
bool continue_after_last_event(bool handled = true);
|
|
lowcnd_t *get_failed_lowcnd(thid_t tid, ea_t ea);
|
|
page_bpts_t::iterator find_page_bpt(ea_t ea, int size=1);
|
|
bool del_page_bpt(ea_t ea, bpttype_t type);
|
|
void enable_page_bpts(bool enable);
|
|
ea_t calc_page_base(ea_t ea) { return align_down(ea, dbg_memory_page_size()); }
|
|
void log_exception(const debug_event_t *ev, const exception_info_t *ei);
|
|
uint64 probe_file_size(int fn, uint64 step);
|
|
void set_input_path(const char *input_path);
|
|
int read_bpt_orgbytes(bytevec_t *buf, ea_t ea, int len);
|
|
|
|
//------------------------------------
|
|
// Shared methods
|
|
//------------------------------------
|
|
virtual bool check_input_file_crc32(uint32 orig_crc);
|
|
virtual const exception_info_t *find_exception(int code);
|
|
virtual bool get_exception_name(int code, char *buf, size_t bufsize);
|
|
virtual drc_t idaapi dbg_get_processes(procinfo_vec_t *info, qstring *errbuf);
|
|
|
|
//------------------------------------
|
|
// Methods to be implemented
|
|
//------------------------------------
|
|
virtual void idaapi dbg_set_debugging(bool _debug_debugger) = 0;
|
|
virtual drc_t idaapi dbg_init(uint32_t *flags2, qstring *errbuf) = 0;
|
|
virtual void idaapi dbg_term(void) = 0;
|
|
virtual drc_t idaapi dbg_detach_process(void) = 0;
|
|
virtual drc_t idaapi dbg_start_process(
|
|
const char *path,
|
|
const char *args,
|
|
const char *startdir,
|
|
int flags,
|
|
const char *input_path,
|
|
uint32 input_file_crc32,
|
|
qstring *errbuf) = 0;
|
|
virtual gdecode_t idaapi dbg_get_debug_event(debug_event_t *event, int timeout_msecs) = 0;
|
|
virtual drc_t idaapi dbg_attach_process(pid_t process_id, int event_id, int flags, qstring *errbuf) = 0;
|
|
virtual drc_t idaapi dbg_prepare_to_pause_process(qstring *errbuf) = 0;
|
|
virtual drc_t idaapi dbg_exit_process(qstring *errbuf) = 0;
|
|
virtual drc_t idaapi dbg_continue_after_event(const debug_event_t *event) = 0;
|
|
virtual void idaapi dbg_set_exception_info(const exception_info_t *info, int qty);
|
|
virtual void idaapi dbg_stopped_at_debug_event(import_infos_t *infos, bool dlls_added, thread_name_vec_t *thr_names) = 0;
|
|
virtual drc_t idaapi dbg_thread_suspend(thid_t thread_id) = 0;
|
|
virtual drc_t idaapi dbg_thread_continue(thid_t thread_id) = 0;
|
|
virtual drc_t idaapi dbg_set_resume_mode(thid_t thread_id, resume_mode_t resmod) = 0;
|
|
virtual drc_t idaapi dbg_read_registers(
|
|
thid_t thread_id,
|
|
int clsmask,
|
|
regval_t *values,
|
|
qstring *errbuf) = 0;
|
|
virtual drc_t idaapi dbg_write_register(
|
|
thid_t thread_id,
|
|
int reg_idx,
|
|
const regval_t *value,
|
|
qstring *errbuf) = 0;
|
|
virtual drc_t idaapi dbg_thread_get_sreg_base(ea_t *ea, thid_t thread_id, int sreg_value, qstring *errbuf) = 0;
|
|
virtual ea_t idaapi map_address(ea_t ea, const regval_t *, int /* regnum */) { return ea; }
|
|
virtual drc_t idaapi dbg_get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) = 0;
|
|
virtual int idaapi dbg_get_scattered_image(scattered_image_t & /*si*/, ea_t /*base*/) { return -1; }
|
|
virtual bool idaapi dbg_get_image_uuid(bytevec_t * /*uuid*/, ea_t /*base*/) { return false; }
|
|
virtual ea_t idaapi dbg_get_segm_start(ea_t /*base*/, const qstring & /*segname*/) { return BADADDR; }
|
|
virtual ssize_t idaapi dbg_read_memory(ea_t ea, void *buffer, size_t size, qstring *errbuf) = 0;
|
|
virtual ssize_t idaapi dbg_write_memory(ea_t ea, const void *buffer, size_t size, qstring *errbuf) = 0;
|
|
virtual int idaapi dbg_is_ok_bpt(bpttype_t type, ea_t ea, int len) = 0;
|
|
// for swbpts, len may be -1 (unknown size, for example arm/thumb mode) or bpt opcode length
|
|
// dbg_add_bpt returns 2 if it adds a page bpt
|
|
virtual int idaapi dbg_add_bpt(bytevec_t *orig_bytes, bpttype_t type, ea_t ea, int len) = 0;
|
|
virtual int idaapi dbg_del_bpt(bpttype_t type, ea_t ea, const uchar *orig_bytes, int len) = 0;
|
|
virtual drc_t idaapi dbg_update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf);
|
|
virtual int idaapi dbg_add_page_bpt(bpttype_t /*type*/, ea_t /*ea*/, int /*size*/) { return 0; }
|
|
virtual bool idaapi dbg_enable_page_bpt(page_bpts_t::iterator /*p*/, bool /*enable*/) { return false; }
|
|
virtual drc_t idaapi dbg_update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf);
|
|
virtual drc_t idaapi dbg_eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf);
|
|
virtual int idaapi dbg_open_file(const char * /*file*/, uint64 * /*fsize*/, bool /*readonly*/) { return -1; }
|
|
virtual void idaapi dbg_close_file(int /*fn*/) {}
|
|
virtual ssize_t idaapi dbg_read_file(int /*fn*/, qoff64_t /*off*/, void * /*buf*/, size_t /*size*/) { return 0; }
|
|
virtual ssize_t idaapi dbg_write_file(int /*fn*/, qoff64_t /*off*/, const void * /*buf*/, size_t /*size*/) { return 0; }
|
|
virtual int idaapi handle_ioctl(
|
|
int /*fn*/,
|
|
const void * /*buf*/,
|
|
size_t /*size*/,
|
|
void ** /*outbuf*/,
|
|
ssize_t * /*outsize*/)
|
|
{
|
|
return 0;
|
|
}
|
|
virtual int idaapi get_system_specific_errno(void) const; // this code must be acceptable by winerr()
|
|
virtual drc_t idaapi dbg_update_call_stack(thid_t, call_stack_t *) { return DRC_NONE; }
|
|
virtual ea_t idaapi dbg_appcall(
|
|
ea_t /*func_ea*/,
|
|
thid_t /*tid*/,
|
|
int /*stkarg_nbytes*/,
|
|
const struct regobjs_t * /*regargs*/,
|
|
struct relobj_t * /*stkargs*/,
|
|
struct regobjs_t * /*retregs*/,
|
|
qstring *errbuf,
|
|
debug_event_t * /*event*/,
|
|
int /*flags*/);
|
|
virtual drc_t idaapi dbg_cleanup_appcall(thid_t /*tid*/);
|
|
virtual bool idaapi write_registers(
|
|
thid_t /*tid*/,
|
|
int /*start*/,
|
|
int /*count*/,
|
|
const regval_t * /*values*/)
|
|
{
|
|
return false;
|
|
}
|
|
// finalize appcall stack image
|
|
// input: stack image contains the return address at the beginning
|
|
virtual int finalize_appcall_stack(call_context_t &, regval_map_t &, bytevec_t &) { return 0; }
|
|
virtual ea_t calc_appcall_stack(const regvals_t ®vals);
|
|
virtual bool should_stop_appcall(thid_t tid, const debug_event_t *event, ea_t ea);
|
|
virtual bool should_suspend_at_exception(const debug_event_t *event, const exception_info_t *ei);
|
|
virtual bool preprocess_appcall_cleanup(thid_t, call_context_t &) { return true; }
|
|
virtual int get_regidx(const char *regname, int *clsmask) = 0;
|
|
virtual uint32 dbg_memory_page_size(void) { return 0x1000; }
|
|
virtual bool idaapi dbg_prepare_broken_connection(void) { return false; }
|
|
virtual bool idaapi dbg_continue_broken_connection(pid_t) { old_ranges.clear(); return true; }
|
|
virtual bool idaapi dbg_enable_trace(thid_t, bool, int) { return false; }
|
|
virtual bool idaapi dbg_is_tracing_enabled(thid_t, int) { return false; }
|
|
virtual int idaapi dbg_rexec(const char *cmdline);
|
|
virtual void adjust_swbpt(ea_t *, int *) {}
|
|
virtual void dbg_get_debapp_attrs(debapp_attrs_t *out_pattrs) const;
|
|
virtual bool idaapi dbg_get_srcinfo_path(qstring * /*path*/, ea_t /*base*/) const { return false; }
|
|
virtual bool import_dll(const import_request_t & /*req*/) { return false; }
|
|
virtual drc_t idaapi dbg_bin_search(
|
|
ea_t *ea,
|
|
ea_t start_ea,
|
|
ea_t end_ea,
|
|
const compiled_binpat_vec_t &ptns,
|
|
int srch_flags,
|
|
qstring *errbuf);
|
|
|
|
bool restore_broken_breakpoints(void);
|
|
void set_addr_size(int size) { debapp_attrs.addrsize = size; }
|
|
void set_endianness(bool is_be) { debapp_attrs.is_be = is_be; }
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
// Some functions, per OS implemented
|
|
//
|
|
bool init_subsystem();
|
|
bool term_subsystem();
|
|
debmod_t *create_debug_session(void *params);
|
|
|
|
//
|
|
// Processor specific init/term
|
|
//
|
|
void processor_specific_init(void);
|
|
void processor_specific_term(void);
|
|
|
|
// Perform an action on all existing debugger modules
|
|
struct debmod_visitor_t
|
|
{
|
|
virtual int visit(debmod_t *debmod) = 0;
|
|
};
|
|
int for_all_debuggers(debmod_visitor_t &v);
|
|
|
|
|
|
//
|
|
// Utility functions
|
|
//
|
|
|
|
// Common method between MacOS and Linux to launch a process
|
|
drc_t idaapi maclnx_launch_process(
|
|
debmod_t *debmod,
|
|
const char *path,
|
|
const char *args,
|
|
const char *startdir,
|
|
int flags,
|
|
const char *input_path,
|
|
uint32 input_file_crc32,
|
|
void **child_pid,
|
|
qstring *errbuf);
|
|
|
|
bool add_idc_funcs(const struct ext_idcfunc_t funcs[], size_t nfuncs, bool reg);
|
|
|
|
//
|
|
// Externs
|
|
//
|
|
extern debmod_t *idc_debmod;
|
|
extern thid_t idc_thread;
|
|
extern bool ignore_sigint;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// server.cpp
|
|
bool lock_begin();
|
|
bool lock_end();
|
|
|
|
// bool srv_lock_begin(void);
|
|
// bool srv_lock_end(void);
|
|
|
|
#endif
|