/* * Interactive disassembler (IDA). * Copyright (c) 1990-2021 Hex-Rays * ALL RIGHTS RESERVED. * */ #ifndef _IDD_HPP #define _IDD_HPP #include #include #include /*! \file idd.hpp \brief Contains definition of the interface to IDD modules. The interface consists of structures describing the target debugged processor and a debugging API. */ /// The IDD interface version number #define IDD_INTERFACE_VERSION 27 class idc_value_t; class tinfo_t; //==================================================================== // // Process and Threads // typedef int pid_t; ///< process id typedef int thid_t; ///< thread id #define NO_PROCESS pid_t(-1) ///< No process #define NO_THREAD 0 ///< No thread. ///< in ::PROCESS_STARTED this value ///< can be used to specify that ///< the main thread has not been created. ///< It will be initialized later ///< by a ::THREAD_STARTED event. /// Process information struct process_info_t { pid_t pid; ///< process id qstring name; ///< process name }; DECLARE_TYPE_AS_MOVABLE(process_info_t); typedef qvector procinfo_vec_t; //-------------------------------------------------------------------- /// Runtime attributes of the debugger/process. /// It is guaranteed that these attributes are really valid after start/attach process struct debapp_attrs_t { int32 cbsize; ///< control field: size of this structure /// address size of the process. /// Since 64-bit debuggers usually can debug 32-bit applications, we cannot /// rely on sizeof(ea_t) to detect the current address size. The following /// variable should be used instead. It is initialized with 8 for 64-bit /// debuggers but they should adjust it as soon as they learn that a /// 32-bit application is being debugged. /// For 32-bit debuggers it is initialized with 4. int addrsize; qstring platform; ///< platform name process is running/debugging under. ///< (is used as a key value in exceptions.cfg) /// \def{DEF_ADDRSIZE, Default address size - see debapp_attrs_t::addrsize} #ifdef __EA64__ #define DEF_ADDRSIZE 8 #else #define DEF_ADDRSIZE 4 #endif int is_be; /// Constructor - initialize with #DEF_ADDRSIZE debapp_attrs_t() : cbsize(sizeof(debapp_attrs_t)), addrsize(DEF_ADDRSIZE), is_be(-1) {} }; //==================================================================== // // Registers // typedef unsigned char register_class_t; ///< Each register is associated to ///< a register class. ///< example: "segment", "mmx", ... /// Debuggee register information struct register_info_t { const char *name; ///< Register name. uint32 flags; ///< \ref REGISTER_ /// \defgroup REGISTER_ Register info attribute flags /// Used by register_info_t::flags //@{ #define REGISTER_READONLY 0x0001 ///< the user can't modify the current value of this register #define REGISTER_IP 0x0002 ///< instruction pointer #define REGISTER_SP 0x0004 ///< stack pointer #define REGISTER_FP 0x0008 ///< frame pointer #define REGISTER_ADDRESS 0x0010 ///< may contain an address #define REGISTER_CS 0x0020 ///< code segment #define REGISTER_SS 0x0040 ///< stack segment #define REGISTER_NOLF 0x0080 ///< displays this register without returning to the next line ///< allowing the next register to be displayed to its right (on the same line) #define REGISTER_CUSTFMT 0x0100 ///< register should be displayed using a custom data format. ///< the format name is in bit_strings[0] ///< the corresponding ::regval_t will use ::bytevec_t //@} register_class_t register_class; ///< segment, mmx, etc. op_dtype_t dtype; ///< Register size (see \ref dt_) const char *const *bit_strings; ///< strings corresponding to each bit of the register. ///< (NULL = no bit, same name = multi-bits mask) uval_t default_bit_strings_mask; ///< mask of default bits }; DECLARE_TYPE_AS_MOVABLE(register_info_t); typedef qvector register_info_vec_t; //-------------------------------------------------------------------------- struct dynamic_register_set_t { typedef qvector const_char_vec_t; register_info_vec_t ri_vec; qstrvec_t strvec; const_char_vec_t classname_ptrs; qvector bit_strings_ptrs_vec; void clear(void) { ri_vec.clear(); strvec.clear(); classname_ptrs.clear(); bit_strings_ptrs_vec.clear(); } void add_register( const char *name, int flags, op_dtype_t dtype, register_class_t register_class, const char *const *bit_strings, uval_t bits_mask) { // Allocate bit_strings. if ( bit_strings != nullptr ) { size_t num_bits = (flags & REGISTER_CUSTFMT) != 0 ? 1 : dtype == dt_word ? 16 : dtype == dt_dword ? 32 : dtype == dt_qword ? 64 : 0; QASSERT(1795, num_bits != 0); const_char_vec_t &ptrvec = bit_strings_ptrs_vec.push_back(); ptrvec.resize(num_bits, nullptr); for ( size_t i = 0; i < num_bits; i++ ) { if ( bit_strings[i] != nullptr ) { qstring &field_name = strvec.push_back(); field_name = bit_strings[i]; ptrvec[i] = field_name.c_str(); } } bit_strings = ptrvec.begin(); } // Allocate name. qstring ®name = strvec.push_back(); regname = name; // Add entry for register. register_info_t &ri = ri_vec.push_back(); ri.name = regname.c_str(); ri.flags = flags; ri.dtype = dtype; ri.register_class = register_class; ri.bit_strings = bit_strings; ri.default_bit_strings_mask = bits_mask; } void set_regclasses(const char **register_classes) { while ( *register_classes != nullptr ) { qstring ®ister_class = strvec.push_back(); register_class = *register_classes++; classname_ptrs.push_back(register_class.begin()); } classname_ptrs.push_back(nullptr); } // Values for debugger_t. size_t nregs(void) { return ri_vec.size(); } register_info_t *registers(void) { return ri_vec.begin(); } const char **regclasses(void) { return classname_ptrs.begin(); } }; // helper functions: idaman THREAD_SAFE void ida_export serialize_dynamic_register_set( bytevec_t *buf, dynamic_register_set_t &idaregs); idaman THREAD_SAFE void ida_export deserialize_dynamic_register_set( dynamic_register_set_t *idaregs, memory_deserializer_t &mmdsr); //==================================================================== // // Memory // /// Used by debugger modules to report memory are information to IDA kernel. /// It is ok to return empty fields if information is not available. struct memory_info_t : public range_t { qstring name; ///< Memory range name qstring sclass; ///< Memory range class name ea_t sbase; ///< Segment base (meaningful only for segmented architectures, e.g. 16-bit x86) ///< The base is specified in paragraphs (i.e. shifted to the right by 4) uchar bitness; ///< Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit) uchar perm; ///< Memory range permissions (0-no information): see segment.hpp memory_info_t(void) : sbase(0),bitness(0),perm(0) {} bool operator ==(const memory_info_t &r) const { return start_ea == r.start_ea && end_ea == r.end_ea && name == r.name && sclass == r.sclass && sbase == r.sbase && bitness == r.bitness && perm == r.perm; } bool operator !=(const memory_info_t &r) const { return !(*this == r); } }; DECLARE_TYPE_AS_MOVABLE(memory_info_t); typedef qvector meminfo_vec_t; ///< vector of memory info objects /// Used by debugger modules to keep track of images that are not mapped uniformly into memory. struct scattered_segm_t : public range_t { qstring name; ///< name of the segment }; DECLARE_TYPE_AS_MOVABLE(scattered_segm_t); typedef qvector scattered_image_t; ///< vector of scattered segments //==================================================================== // // Debug events // /// Debug event codes enum event_id_t { NO_EVENT = 0x00000000, ///< Not an interesting event. This event can be ///< used if the debugger module needs to return ///< an event but there are no valid events. PROCESS_STARTED = 0x00000001, ///< New process has been started. PROCESS_EXITED = 0x00000002, ///< Process has been stopped. THREAD_STARTED = 0x00000004, ///< New thread has been started. THREAD_EXITED = 0x00000008, ///< Thread has been stopped. BREAKPOINT = 0x00000010, ///< Breakpoint has been reached. IDA will complain ///< about unknown breakpoints, they should be reported ///< as exceptions. STEP = 0x00000020, ///< One instruction has been executed. Spurious ///< events of this kind are silently ignored by IDA. EXCEPTION = 0x00000040, ///< Exception. LIB_LOADED = 0x00000080, ///< New library has been loaded. LIB_UNLOADED = 0x00000100, ///< Library has been unloaded. INFORMATION = 0x00000200, ///< User-defined information. ///< This event can be used to return empty information ///< This will cause IDA to call get_debug_event() ///< immediately once more. PROCESS_ATTACHED = 0x00000400, ///< Successfully attached to running process. PROCESS_DETACHED = 0x00000800, ///< Successfully detached from process. PROCESS_SUSPENDED= 0x00001000, ///< Process has been suspended. ///< This event can be used by the debugger module ///< to signal if the process spontaneously gets ///< suspended (not because of an exception, ///< breakpoint, or single step). IDA will silently ///< switch to the 'suspended process' mode without ///< displaying any messages. TRACE_FULL = 0x00002000, ///< The trace buffer of the tracer module is full ///< and IDA needs to read it before continuing }; // helper functions: struct debug_event_t; idaman THREAD_SAFE void ida_export free_debug_event(debug_event_t *ev); idaman THREAD_SAFE void ida_export copy_debug_event(debug_event_t *ev, const debug_event_t &r); idaman THREAD_SAFE void ida_export set_debug_event_code(debug_event_t *ev, event_id_t id); /// Describes a module load event. /// (see ::PROCESS_STARTED, ::PROCESS_ATTACHED, ::LIB_LOADED) struct modinfo_t { qstring name; ///< full name of the module ea_t base; ///< module base address. if unknown pass #BADADDR asize_t size; ///< module size. if unknown pass 0 ea_t rebase_to; ///< if not #BADADDR, then rebase the program to the specified address }; DECLARE_TYPE_AS_MOVABLE(modinfo_t); typedef qvector modinfovec_t; /// Describes a breakpoint event. /// (see ::BREAKPOINT) struct bptaddr_t { ea_t hea; ///< Possible address referenced by hardware breakpoints ea_t kea; ///< Address of the triggered bpt from the kernel's point ///< of view. (for some systems with special memory mappings, ///< the triggered ea might be different from event ea). ///< Use to #BADADDR for flat memory model. bptaddr_t(): hea(BADADDR), kea(BADADDR) {} }; /// Describes an exception. /// (see ::EXCEPTION) struct excinfo_t { uint32 code; ///< Exception code bool can_cont; ///< Execution of the process can continue after this exception? ea_t ea; ///< Possible address referenced by the exception qstring info; ///< Exception message }; /// This structure is used only when detailed information /// about a debug event is needed. struct debug_event_t { pid_t pid; ///< Process where the event occurred thid_t tid; ///< Thread where the event occurred ea_t ea; ///< Address where the event occurred bool handled; ///< Is event handled by the debugger?. ///< (from the system's point of view) ///< Meaningful for ::EXCEPTION events private: event_id_t _eid; #ifndef SWIG char bytes[qmax(sizeof(modinfo_t), sizeof(excinfo_t))]; void check_usage(uint32 req) { QASSERT(1502, (_eid & req) != 0); } #endif public: debug_event_t(void) : pid(NO_PROCESS), tid(NO_THREAD), ea(BADADDR), handled(false), _eid(NO_EVENT) { memset(bytes, 0, sizeof(bytes)); } debug_event_t(const debug_event_t &r) : _eid(NO_EVENT) { copy(r); } ~debug_event_t(void) { clear(); } debug_event_t &operator =(const debug_event_t &r) { return copy(r); } debug_event_t ©(const debug_event_t &r) { copy_debug_event(this, r); return *this; } /// clear the dependent information (see below), set event code to NO_EVENT void clear(void) { free_debug_event(this); } void clear_all(void) { clear(); pid = NO_PROCESS; tid = NO_THREAD; ea = BADADDR; handled = false; } /// Event code event_id_t eid() const { return _eid; } /// Set event code. /// If the new event code is compatible with the old one /// then the dependent information (see below) will be preserved. /// Otherwise the event will be cleared and the new event code will be set. void set_eid(event_id_t id) { set_debug_event_code(this, id); } /// Information that depends on the event code: ///< ::PROCESS_STARTED, ::PROCESS_ATTACHED, ::LIB_LOADED modinfo_t &modinfo() { check_usage(PROCESS_STARTED | PROCESS_ATTACHED | LIB_LOADED); return *(modinfo_t *)bytes; } ///< ::PROCESS_EXITED, ::THREAD_EXITED int &exit_code() { check_usage(PROCESS_EXITED | THREAD_EXITED); return *(int *)bytes; } ///< ::THREAD_STARTED (thread name) ///< ::LIB_UNLOADED (unloaded library name) ///< ::INFORMATION (will be displayed in the output window if not empty) qstring &info() { check_usage(THREAD_STARTED | LIB_UNLOADED | INFORMATION); return *(qstring *)bytes; } ///< ::BREAKPOINT bptaddr_t &bpt() { check_usage(BREAKPOINT); return *(bptaddr_t *)bytes; } ///< ::EXCEPTION excinfo_t &exc() { check_usage(EXCEPTION); return *(excinfo_t *)bytes; } const modinfo_t &modinfo() const { return CONST_CAST(debug_event_t*)(this)->modinfo(); } const int &exit_code() const { return CONST_CAST(debug_event_t*)(this)->exit_code(); } const qstring &info() const { return CONST_CAST(debug_event_t*)(this)->info(); } const bptaddr_t &bpt() const { return CONST_CAST(debug_event_t*)(this)->bpt(); } const excinfo_t &exc() const { return CONST_CAST(debug_event_t*)(this)->exc(); } modinfo_t &set_modinfo(event_id_t id) { set_eid(id); return modinfo(); } void set_exit_code(event_id_t id, int code) { set_eid(id); exit_code() = code; } qstring &set_info(event_id_t id) { set_eid(id); return info(); } bptaddr_t &set_bpt(void) { set_eid(BREAKPOINT); return bpt(); } excinfo_t &set_exception(void) { set_eid(EXCEPTION); return exc(); } /// On some systems with special memory mappings the triggered ea might be /// different from the actual ea. Calculate the address to use. ea_t bpt_ea(void) const { return _eid == BREAKPOINT && bpt().kea != BADADDR ? bpt().kea : ea; } friend THREAD_SAFE void ida_export free_debug_event(debug_event_t *ev); friend THREAD_SAFE void ida_export copy_debug_event(debug_event_t *ev, const debug_event_t &r); friend THREAD_SAFE void ida_export set_debug_event_code(debug_event_t *ev, event_id_t id); }; DECLARE_TYPE_AS_MOVABLE(debug_event_t); typedef int bpttype_t; ///< hardware breakpoint type (see \ref BPT_H) /// \defgroup BPT_H Hardware breakpoint ids /// Fire the breakpoint upon one of these events //@{ const bpttype_t BPT_WRITE = 1, ///< Write access BPT_READ = 2, ///< Read access BPT_RDWR = 3, ///< Read/write access BPT_SOFT = 4, ///< Software breakpoint BPT_EXEC = 8, ///< Execute instruction BPT_DEFAULT = (BPT_SOFT|BPT_EXEC); ///< Choose bpt type automatically //@} /// Exception information struct exception_info_t { uint code; ///< exception code uint32 flags; ///< \ref EXC_ /// \defgroup EXC_ Exception info flags /// Used by exception_info_t::flags //@{ #define EXC_BREAK 0x0001 ///< break on the exception #define EXC_HANDLE 0x0002 ///< should be handled by the debugger? #define EXC_MSG 0x0004 ///< instead of a warning, log the exception to the output window #define EXC_SILENT 0x0008 ///< do not warn or log to the output window //@} /// Should we break on the exception? bool break_on(void) const { return (flags & EXC_BREAK) != 0; } /// Should we handle the exception? bool handle(void) const { return (flags & EXC_HANDLE) != 0; } qstring name; ///< Exception standard name qstring desc; ///< Long message used to display info about the exception exception_info_t(void) : code(0), flags(0) {} exception_info_t(uint _code, uint32 _flags, const char *_name, const char *_desc) : code(_code), flags(_flags), name(_name), desc(_desc) {} }; DECLARE_TYPE_AS_MOVABLE(exception_info_t); typedef qvector excvec_t; ///< vector of exception info objects /// Structure to hold a register value. /// Small values (up to 64-bit integers and floating point values) use /// #RVT_INT and #RVT_FLOAT types. For bigger values the bytes() vector is used. struct regval_t { /// \defgroup RVT_ Register value types /// Used by regval_t::rvtype //@{ #define RVT_INT (-1) ///< integer #define RVT_FLOAT (-2) ///< floating point #define RVT_UNAVAILABLE (-3) ///< unavailable ///< other values mean custom data type //@} int32 rvtype = RVT_INT; ///< one of \ref RVT_ #ifndef SWIG union { #endif uint64 ival; ///< 8: integer value fpvalue_t fval; ///< 12: floating point value in the internal representation (see ieee.h) #ifndef SWIG uchar reserve[sizeof(bytevec_t)]; ///< bytevec_t: custom data type (use bytes() to access it) }; #endif regval_t() : ival(~uint64(0)) {} ~regval_t() { clear(); } regval_t(const regval_t &r) { *this = r; } /// Assign this regval to the given value regval_t &operator = (const regval_t &r) { if ( this == &r ) return *this; if ( r.rvtype >= 0 ) { if ( rvtype >= 0 ) bytes() = r.bytes(); else new (&bytes()) bytevec_t(r.bytes()); } else // r.rvtype < 0 { if ( rvtype >= 0 ) bytes().~bytevec_t(); memcpy(&fval, &r.fval, sizeof(fval)); } rvtype = r.rvtype; return *this; } /// Clear register value void clear(void) { if ( rvtype >= 0 ) { bytes().~bytevec_t(); rvtype = RVT_INT; } } /// Compare two regvals with '==' bool operator == (const regval_t &r) const { if ( rvtype == r.rvtype ) { if ( rvtype == RVT_UNAVAILABLE ) return true; if ( rvtype == RVT_INT ) return ival == r.ival; return memcmp(get_data(), r.get_data(), get_data_size()) == 0; } return false; } /// Compare two regvals with '!=' bool operator != (const regval_t &r) const { return !(*this == r); } /// Set this = r and r = this void swap(regval_t &r) { qswap(*this, r); } /// Use set_int() void _set_int(uint64 x) { ival = x; } /// Use set_float() void _set_float(const fpvalue_t &x) { fval = x; rvtype = RVT_FLOAT; } /// Use set_bytes(const uchar *, size_t) void _set_bytes(const uchar *data, size_t size) { new (&bytes()) bytevec_t(data, size); rvtype = 0; } /// Use set_bytes(const bytevec_t &) void _set_bytes(const bytevec_t &v) { new (&bytes()) bytevec_t(v); rvtype = 0; } /// Use set_bytes(void) bytevec_t &_set_bytes(void) { new (&bytes()) bytevec_t; rvtype = 0; return bytes(); } /// Use set_unavailable(void) void _set_unavailable(void) { ival = 0; rvtype = RVT_UNAVAILABLE; } /// \name Setters /// These functions ensure that the previous value is cleared //@{ /// Set int value (ival) void set_int(uint64 x) { clear(); _set_int(x); } /// Set float value (fval) void set_float(const fpvalue_t &x) { clear(); _set_float(x); } /// Set custom regval with raw data void set_bytes(const uchar *data, size_t size) { clear(); _set_bytes(data, size); } /// Set custom value with existing bytevec void set_bytes(const bytevec_t &v) { clear(); _set_bytes(v); } /// Initialize this regval to an empty custom value bytevec_t &set_bytes(void) { clear(); _set_bytes(); return bytes(); } /// Mark as unavailable void set_unavailable(void) { clear(); _set_unavailable(); } //@} /// \name Getters //@{ /// Get custom value bytevec_t &bytes(void) { return *(bytevec_t *)reserve; } /// Get const custom value const bytevec_t &bytes(void) const { return *(bytevec_t *)reserve; } /// Get pointer to value void *get_data(void) { return rvtype >= 0 ? (void *)bytes().begin() : (void *)&fval; } /// Get const pointer to value const void *get_data(void) const { return rvtype >= 0 ? (void *)bytes().begin() : (void *)&fval; } /// Get size of value size_t get_data_size(void) const { if ( rvtype >= 0 ) return bytes().size(); if ( rvtype == RVT_INT ) return sizeof(ival); if ( rvtype == RVT_FLOAT ) return sizeof(fval); return 0; } //@} }; DECLARE_TYPE_AS_MOVABLE(regval_t); typedef qvector regvals_t; ///< vector register value objects /// Instruction operand information struct idd_opinfo_t { bool modified; ///< the operand is modified (written) by the instruction ea_t ea; ///< operand address (#BADADDR - no address) regval_t value; ///< operand value. custom data is represented by 'bytes'. int debregidx; ///< for custom data: index of the corresponding register in dbg->registers int value_size; ///< size of the value in bytes idd_opinfo_t(void) : modified(false), ea(BADADDR), debregidx(-1), value_size(0) {} }; /// Call stack trace information struct call_stack_info_t { ea_t callea; ///< the address of the call instruction. ///< for the 0th frame this is usually just the current value of EIP. ea_t funcea; ///< the address of the called function ea_t fp; ///< the value of the frame pointer of the called function bool funcok; ///< is the function present? bool operator==(const call_stack_info_t &r) const { return callea == r.callea && funcea == r.funcea && funcok == r.funcok && fp == r.fp; } bool operator!=(const call_stack_info_t &r) const { return !(*this == r); } }; DECLARE_TYPE_AS_MOVABLE(call_stack_info_t); struct call_stack_t : public qvector {}; ///< defined as struct so it can be forward-declared //------------------------------------------------------------------------- THREAD_SAFE inline void append_regval(bytevec_t &s, const regval_t &value) { s.pack_dd(value.rvtype+2); if ( value.rvtype == RVT_INT ) { s.pack_dq(value.ival+1); } else if ( value.rvtype == RVT_FLOAT ) { s.append(&value.fval, sizeof(value.fval)); } else if ( value.rvtype != RVT_UNAVAILABLE ) { const bytevec_t &b = value.bytes(); s.pack_dd(b.size()); s.append(b.begin(), b.size()); } } //------------------------------------------------------------------------- template THREAD_SAFE inline void extract_regval(regval_t *out, T &v) { out->clear(); out->rvtype = extract_dd(v) - 2; if ( out->rvtype == RVT_INT ) { out->ival = extract_dq(v) - 1; } else if ( out->rvtype == RVT_FLOAT ) { extract_obj(v, &out->fval, sizeof(out->fval)); } else if ( out->rvtype != RVT_UNAVAILABLE ) { bytevec_t &b = out->_set_bytes(); int size = extract_dd(v); b.resize(size); extract_obj(v, b.begin(), size); } } //------------------------------------------------------------------------- template THREAD_SAFE inline void extract_regvals( regval_t *values, int n, T &v, const uchar *regmap) { for ( int i=0; i < n && !v.eof(); i++ ) if ( regmap == NULL || test_bit(regmap, i) ) extract_regval(&values[i], v); } //-------------------------------------------------------------------------- THREAD_SAFE inline void unpack_regvals( regval_t *values, int n, const uchar *regmap, memory_deserializer_t &mmdsr) { extract_regvals(values, n, mmdsr, regmap); } /// Call a function from the debugged application. /// \param[out] r function return value /// - for #APPCALL_MANUAL, r will hold the new stack point value /// - for #APPCALL_DEBEV, r will hold the exception information upon failure /// and the return code will be eExecThrow /// \param func_ea address to call /// \param tid thread to use. #NO_THREAD means to use the current thread /// \param ptif pointer to type of the function to call /// \param argv array of arguments /// \param argnum number of actual arguments /// \return #eOk if successful, otherwise an error code idaman error_t ida_export dbg_appcall( idc_value_t *retval, ea_t func_ea, thid_t tid, const tinfo_t *ptif, idc_value_t *argv, size_t argnum); /// Cleanup after manual appcall. /// \param tid thread to use. #NO_THREAD means to use the current thread /// The application state is restored as it was before calling the last appcall(). /// Nested appcalls are supported. /// \return #eOk if successful, otherwise an error code idaman error_t ida_export cleanup_appcall(thid_t tid); /// Return values for get_debug_event() enum gdecode_t { GDE_ERROR = -1, ///< error GDE_NO_EVENT, ///< no debug events are available GDE_ONE_EVENT, ///< got one event, no more available yet GDE_MANY_EVENTS, ///< got one event, more events available }; /// Input argument for update_bpts() struct update_bpt_info_t { ea_t ea; ///< in: bpt address bytevec_t orgbytes; ///< in(del), out(add): original bytes (only for swbpts) bpttype_t type; ///< in: bpt type int size; ///< in: bpt size (only for hwbpts) uchar code; ///< in: 0. #BPT_SKIP entries must be skipped by the debugger module ///< out: \ref BPT_ pid_t pid; ///< in: process id thid_t tid; ///< in: thread id update_bpt_info_t() : ea(BADADDR), type(BPT_SOFT), size(0), code(0), pid(NO_PROCESS), tid(NO_THREAD) {} /// facilitate update_bpt_vec_t::find() bool operator==(const update_bpt_info_t &b) const { return ea == b.ea && type == b.type; } }; DECLARE_TYPE_AS_MOVABLE(update_bpt_info_t); typedef qvector update_bpt_vec_t; ///< vector of update breakpoint info objects /// Input argument for update_lowcnds(). /// Server-side low-level breakpoint conditions struct lowcnd_t { ea_t ea; ///< address of the condition qstring cndbody; ///< new condition. empty means 'remove condition' ///< the following fields are valid only if condition is not empty: bpttype_t type; ///< existing breakpoint type bytevec_t orgbytes; ///< original bytes (if type==#BPT_SOFT) insn_t cmd; ///< decoded instruction at 'ea' ///< (used for processors without single step feature, e.g. arm) bool compiled; ///< has 'cndbody' already been compiled? int size; ///< breakpoint size (if type!=#BPT_SOFT) }; typedef qvector lowcnd_vec_t; ///< vector of low-level breakpoint conditions /// Output argument for ev_suspended /// New thread names struct thread_name_t { thid_t tid; ///< thread qstring name; ///< new thread name }; typedef qvector thread_name_vec_t; ///< vector of thread names //==================================================================== /// How to resume the application. The corresponding bit for \ref DBG_FLAG_ /// must be set in order to use a resume mode. enum resume_mode_t { RESMOD_NONE, ///< no stepping, run freely RESMOD_INTO, ///< step into call (the most typical single stepping) RESMOD_OVER, ///< step over call RESMOD_OUT, ///< step out of the current function (run until return) RESMOD_SRCINTO, ///< until control reaches a different source line RESMOD_SRCOVER, ///< next source line in the current stack frame RESMOD_SRCOUT, ///< next source line in the previous stack frame RESMOD_USER, ///< step out to the user code RESMOD_HANDLE, ///< step into the exception handler RESMOD_MAX, }; //==================================================================== // Tracing bits #define STEP_TRACE 0x01 // lowest level trace. trace buffers are not maintained #define INSN_TRACE 0x02 // instruction tracing #define FUNC_TRACE 0x04 // function tracing #define BBLK_TRACE 0x08 // basic block tracing //==================================================================== /// Debugger return codes. /// Success if positive (> DRC_NONE). enum drc_t { DRC_EVENTS = 3, ///< success, there are pending events DRC_CRC = 2, ///< success, but the input file crc does not match DRC_OK = 1, ///< success DRC_NONE = 0, ///< reaction to the event not implemented DRC_FAILED = -1, ///< failed or false DRC_NETERR = -2, ///< network error DRC_NOFILE = -3, ///< file not found DRC_IDBSEG = -4, ///< use idb segmentation DRC_NOPROC = -5, ///< the process does not exist anymore DRC_NOCHG = -6, ///< no changes DRC_ERROR = -7, ///< unclassified error, may be complemented by errbuf }; //==================================================================== /// This structure describes a debugger API module. /// (functions needed to debug a process on a specific /// operating system). /// /// The address of this structure must be put into the ::dbg variable by /// the plugin_t::init() function of the debugger plugin. struct debugger_t { int version; ///< Expected kernel version, ///< should be #IDD_INTERFACE_VERSION const char *name; ///< Short debugger name like win32 or linux int id; ///< one of \ref DEBUGGER_ID_ /// \defgroup DEBUGGER_ID_ Debugger API module id /// Used by debugger_t::id //@{ #define DEBUGGER_ID_X86_IA32_WIN32_USER 0 ///< Userland win32 processes (win32 debugging APIs) #define DEBUGGER_ID_X86_IA32_LINUX_USER 1 ///< Userland linux processes (ptrace()) #define DEBUGGER_ID_X86_IA32_MACOSX_USER 3 ///< Userland MAC OS X processes #define DEBUGGER_ID_ARM_IPHONE_USER 5 ///< iPhone 1.x #define DEBUGGER_ID_X86_IA32_BOCHS 6 ///< BochsDbg.exe 32 #define DEBUGGER_ID_6811_EMULATOR 7 ///< MC6812 emulator (beta) #define DEBUGGER_ID_GDB_USER 8 ///< GDB remote #define DEBUGGER_ID_WINDBG 9 ///< WinDBG using Microsoft Debug engine #define DEBUGGER_ID_X86_DOSBOX_EMULATOR 10 ///< Dosbox MS-DOS emulator #define DEBUGGER_ID_ARM_LINUX_USER 11 ///< Userland arm linux #define DEBUGGER_ID_TRACE_REPLAYER 12 ///< Fake debugger to replay recorded traces #define DEBUGGER_ID_X86_PIN_TRACER 14 ///< PIN Tracer module #define DEBUGGER_ID_DALVIK_USER 15 ///< Dalvik #define DEBUGGER_ID_XNU_USER 16 ///< XNU Kernel #define DEBUGGER_ID_ARM_MACOS_USER 17 ///< Userland arm MAC OS //@} const char *processor; ///< Required processor name. ///< Used for instant debugging to load the correct ///< processor module uint32 flags; /// \ref DBG_FLAG_ uint32 flags2; /// \ref DBG_FLAG2_ /// may be set inside debugger_t::init_debugger() except of the severals /// \defgroup DBG_FLAG_ Debugger module features /// Used by debugger_t::flags //@{ #define DBG_FLAG_REMOTE 0x00000001 ///< Remote debugger (requires remote host name unless #DBG_FLAG_NOHOST) #define DBG_FLAG_NOHOST 0x00000002 ///< Remote debugger with does not require network params (host/port/pass). ///< (a unique device connected to the machine) #define DBG_FLAG_FAKE_ATTACH 0x00000004 ///< ::PROCESS_ATTACHED is a fake event ///< and does not suspend the execution #define DBG_FLAG_HWDATBPT_ONE 0x00000008 ///< Hardware data breakpoints are ///< one byte size by default #define DBG_FLAG_CAN_CONT_BPT 0x00000010 ///< Debugger knows to continue from a bpt. ///< This flag also means that the debugger module ///< hides breakpoints from ida upon read_memory #define DBG_FLAG_NEEDPORT 0x00000020 ///< Remote debugger requires port number (to be used with DBG_FLAG_NOHOST) #define DBG_FLAG_DONT_DISTURB 0x00000040 ///< Debugger can handle only ///< get_debug_event(), ///< request_pause(), ///< exit_process(). ///< when the debugged process is running. ///< The kernel may also call service functions ///< (file I/O, map_address, etc) #define DBG_FLAG_SAFE 0x00000080 ///< The debugger is safe (probably because it just emulates the application ///< without really running it) #define DBG_FLAG_CLEAN_EXIT 0x00000100 ///< IDA must suspend the application and remove ///< all breakpoints before terminating the application. ///< Usually this is not required because the application memory ///< disappears upon termination. #define DBG_FLAG_USE_SREGS 0x00000200 ///< Take segment register values into account (non flat memory) #define DBG_FLAG_NOSTARTDIR 0x00000400 ///< Debugger module doesn't use startup directory #define DBG_FLAG_NOPARAMETERS 0x00000800 ///< Debugger module doesn't use commandline parameters #define DBG_FLAG_NOPASSWORD 0x00001000 ///< Remote debugger doesn't use password #define DBG_FLAG_CONNSTRING 0x00002000 ///< Display "Connection string" instead of "Hostname" and hide the "Port" field #define DBG_FLAG_SMALLBLKS 0x00004000 ///< If set, IDA uses 256-byte blocks for caching memory contents. ///< Otherwise, 1024-byte blocks are used #define DBG_FLAG_MANMEMINFO 0x00008000 ///< If set, manual memory region manipulation commands ///< will be available. Use this bit for debugger modules ///< that cannot return memory layout information #define DBG_FLAG_EXITSHOTOK 0x00010000 ///< IDA may take a memory snapshot at ::PROCESS_EXITED event #define DBG_FLAG_VIRTHREADS 0x00020000 ///< Thread IDs may be shuffled after each debug event. ///< (to be used for virtual threads that represent cpus for windbg kmode) #define DBG_FLAG_LOWCNDS 0x00040000 ///< Low level breakpoint conditions are supported. #define DBG_FLAG_DEBTHREAD 0x00080000 ///< Supports creation of a separate thread in ida ///< for the debugger (the debthread). ///< Most debugger functions will be called from debthread (exceptions are marked below) ///< The debugger module may directly call only #THREAD_SAFE functions. ///< To call other functions please use execute_sync(). ///< The debthread significantly increases debugging ///< speed, especially if debug events occur frequently (to be tested) #define DBG_FLAG_DEBUG_DLL 0x00100000 ///< Can debug standalone DLLs. ///< For example, Bochs debugger can debug any snippet of code #define DBG_FLAG_FAKE_MEMORY 0x00200000 ///< get_memory_info()/read_memory()/write_memory() work with the idb. ///< (there is no real process to read from, as for the replayer module) ///< the kernel will not call these functions if this flag is set. ///< however, third party plugins may call them, they must be implemented. #define DBG_FLAG_ANYSIZE_HWBPT 0x00400000 ///< The debugger supports arbitrary size hardware breakpoints. #define DBG_FLAG_TRACER_MODULE 0x00800000 ///< The module is a tracer, not a full featured debugger module #define DBG_FLAG_PREFER_SWBPTS 0x01000000 ///< Prefer to use software breakpoints #define DBG_FLAG_LAZY_WATCHPTS 0x02000000 ///< Watchpoints are triggered before the offending instruction is executed. ///< The debugger must temporarily disable the watchpoint and single-step ///< before resuming. #define DBG_FLAG_FAST_STEP 0x04000000 ///< Do not refresh memory layout info after single stepping //@} /// \defgroup DBG_FLAG2_ Debugger module features /// Used by debugger_t::flags2 //@{ #define DBG_HAS_GET_PROCESSES 0x00000001 ///< supports ev_get_processes #define DBG_HAS_ATTACH_PROCESS 0x00000002 ///< supports ev_attach_process #define DBG_HAS_DETACH_PROCESS 0x00000004 ///< supports ev_detach_process #define DBG_HAS_REQUEST_PAUSE 0x00000008 ///< supports ev_request_pause #define DBG_HAS_SET_EXCEPTION_INFO \ 0x00000010 ///< supports ev_set_exception_info #define DBG_HAS_THREAD_SUSPEND 0x00000020 ///< supports ev_thread_suspend #define DBG_HAS_THREAD_CONTINUE 0x00000040 ///< supports ev_thread_continue #define DBG_HAS_SET_RESUME_MODE 0x00000080 ///< supports ev_set_resume_mode ///< cannot be set inside the debugger_t::init_debugger() #define DBG_HAS_THREAD_GET_SREG_BASE \ 0x00000100 ///< supports ev_thread_get_sreg_base #define DBG_HAS_CHECK_BPT 0x00000200 ///< supports ev_check_bpt #define DBG_HAS_OPEN_FILE 0x00000400 ///< supports ev_open_file, ev_close_file, ev_read_file, ev_write_file #define DBG_HAS_UPDATE_CALL_STACK \ 0x00000800 ///< supports ev_update_call_stack #define DBG_HAS_APPCALL 0x00001000 ///< supports ev_appcall, ev_cleanup_appcall #define DBG_HAS_REXEC 0x00002000 ///< supports ev_rexec #define DBG_HAS_MAP_ADDRESS 0x00004000 ///< supports ev_map_address, ///< avoid using this bit, especially together with DBG_FLAG_DEBTHREAD ///< because it may cause big slow downs //@} bool is_remote(void) const { return (flags & DBG_FLAG_REMOTE) != 0; } bool must_have_hostname(void) const { return (flags & (DBG_FLAG_REMOTE|DBG_FLAG_NOHOST)) == DBG_FLAG_REMOTE; } bool can_continue_from_bpt(void) const { return (flags & DBG_FLAG_CAN_CONT_BPT) != 0; } bool may_disturb(void) const { return (flags & DBG_FLAG_DONT_DISTURB) == 0; } bool is_safe(void) const { return (flags & DBG_FLAG_SAFE) != 0; } bool use_sregs(void) const { return (flags & DBG_FLAG_USE_SREGS) != 0; } size_t cache_block_size(void) const { return (flags & DBG_FLAG_SMALLBLKS) != 0 ? 256 : 1024; } bool use_memregs(void) const { return (flags & DBG_FLAG_MANMEMINFO) != 0; } bool may_take_exit_snapshot(void) const { return (flags & DBG_FLAG_EXITSHOTOK) != 0; } bool virtual_threads(void) const { return (flags & DBG_FLAG_VIRTHREADS) != 0; } bool supports_lowcnds(void) const { return (flags & DBG_FLAG_LOWCNDS) != 0; } bool supports_debthread(void) const { return (flags & DBG_FLAG_DEBTHREAD) != 0; } bool can_debug_standalone_dlls(void) const { return (flags & DBG_FLAG_DEBUG_DLL) != 0; } bool fake_memory(void) const { return (flags & DBG_FLAG_FAKE_MEMORY) != 0; } bool has_get_processes(void) const { return (flags2 & DBG_HAS_GET_PROCESSES) != 0; } bool has_attach_process(void) const { return (flags2 & DBG_HAS_ATTACH_PROCESS) != 0; } bool has_detach_process(void) const { return (flags2 & DBG_HAS_DETACH_PROCESS) != 0; } bool has_request_pause(void) const { return (flags2 & DBG_HAS_REQUEST_PAUSE) != 0; } bool has_set_exception_info(void) const { return (flags2 & DBG_HAS_SET_EXCEPTION_INFO) != 0; } bool has_thread_suspend(void) const { return (flags2 & DBG_HAS_THREAD_SUSPEND) != 0; } bool has_thread_continue(void) const { return (flags2 & DBG_HAS_THREAD_CONTINUE) != 0; } bool has_set_resume_mode(void) const { return (flags2 & DBG_HAS_SET_RESUME_MODE) != 0; } bool has_thread_get_sreg_base(void) const { return (flags2 & DBG_HAS_THREAD_GET_SREG_BASE) != 0; } bool has_check_bpt(void) const { return (flags2 & DBG_HAS_CHECK_BPT) != 0; } bool has_open_file(void) const { return (flags2 & DBG_HAS_OPEN_FILE) != 0; } bool has_update_call_stack(void) const { return (flags2 & DBG_HAS_UPDATE_CALL_STACK) != 0; } bool has_appcall(void) const { return (flags2 & DBG_HAS_APPCALL) != 0; } bool has_rexec(void) const { return (flags2 & DBG_HAS_REXEC) != 0; } bool has_map_address(void) const { return (flags2 & DBG_HAS_MAP_ADDRESS) != 0; } const char **regclasses; ///< Array of register class names int default_regclasses; ///< Mask of default printed register classes register_info_t *registers; ///< Array of registers. Use regs() to access it int nregs; ///< Number of registers // A function for accessing the 'registers' array inline register_info_t ®s(int idx) { return registers[idx]; } int memory_page_size; ///< Size of a memory page. Usually 4K const uchar *bpt_bytes; ///< A software breakpoint instruction uchar bpt_size; ///< Size of the software breakpoint instruction in bytes uchar filetype; ///< Input file type for the instant debugger. ///< This value will be used after attaching to a new process. ushort resume_modes; ///< \ref DBG_RESMOD_ /// \defgroup DBG_RESMOD_ Resume modes /// Used by debugger_t::resume_modes //@{ #define DBG_RESMOD_STEP_INTO 0x0001 ///< ::RESMOD_INTO is available #define DBG_RESMOD_STEP_OVER 0x0002 ///< ::RESMOD_OVER is available #define DBG_RESMOD_STEP_OUT 0x0004 ///< ::RESMOD_OUT is available #define DBG_RESMOD_STEP_SRCINTO 0x0008 ///< ::RESMOD_SRCINTO is available #define DBG_RESMOD_STEP_SRCOVER 0x0010 ///< ::RESMOD_SRCOVER is available #define DBG_RESMOD_STEP_SRCOUT 0x0020 ///< ::RESMOD_SRCOUT is available #define DBG_RESMOD_STEP_USER 0x0040 ///< ::RESMOD_USER is available #define DBG_RESMOD_STEP_HANDLE 0x0080 ///< ::RESMOD_HANDLE is available //@} bool is_resmod_avail(int resmod) const { return (resume_modes & (1 << (resmod - 1))) != 0; } #if !defined(_MSC_VER) // this compiler complains :( static const int default_port_number = 23946; #define DEBUGGER_PORT_NUMBER debugger_t::default_port_number #else #define DEBUGGER_PORT_NUMBER 23946 #endif /// Set debugger options (parameters that are specific to the debugger module). /// See the definition of ::set_options_t for arguments. /// See the convenience function in dbg.hpp if you need to call it. /// The kernel will generate this event after reading the debugger specific /// config file (arguments are: keyword="", type=#IDPOPT_STR, value="") /// This event is optional. /// This event is generated in the main thread const char *(idaapi *set_dbg_options)( const char *keyword, int pri, int value_type, const void *value); /// Callback notification codes. /// /// They are passed to notify() when certain events occur in the kernel, /// allowing the debugger plugin to take appropriate actions. /// /// Debugger plugins must implement the desired reaction to these events /// in the notify() function. /// /// The notify() function should not be called directly. See inline functions /// below. enum event_t { /// Initialize debugger. /// This event is generated in the main thread. /// \param hostname (const char *) /// \param portnum (int) /// \param password (const char *) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_FAILED ev_init_debugger, /// Terminate debugger. /// This event is generated in the main thread. /// \return ::DRC_OK, ::DRC_FAILED ev_term_debugger, /// Return information about the running processes. /// This event is generated in the main thread. /// Available if \ref DBG_HAS_GET_PROCESSES is set /// \param procs (::procinfo_vec_t *) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_get_processes, /// Start an executable to debug. /// This event is generated in debthread. /// Must be implemented. /// \param path (const char *) path to executable /// \param args (const char *) arguments to pass to executable /// \param startdir (const char *) initial working directory of new process /// \param dbg_proc_flags (uint32) \ref DBG_PROC_ /// \param input_path (const char *) path to the file that was used to create the idb file /// It is not always the same as 'path' - e.g. if we are analyzing /// a dll and want to launch an executable that loads it. /// \param input_file_crc32 (uint32) CRC value for 'input_path' /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_CRC, ::DRC_FAILED, ::DRC_NETERR, ::DRC_NOFILE ev_start_process, /// Attach to an existing running process. /// event_id should be equal to -1 if not attaching to a crashed process. /// This event is generated in debthread. /// Available if \ref DBG_HAS_ATTACH_PROCESS is set /// \param pid (::pid_t) process id to attach /// \param event_id (int) event to trigger upon attaching /// \param dbg_proc_flags (uint32) \ref DBG_PROC_ /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_attach_process, /// Detach from the debugged process. /// May be generated while the process is running or suspended. /// Must detach from the process in any case. /// The kernel will repeatedly call get_debug_event() until ::PROCESS_DETACHED is received. /// In this mode, all other events will be automatically handled and process will be resumed. /// This event is generated from debthread. /// Available if \ref DBG_HAS_DETACH_PROCESS is set /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_detach_process, /// Retrieve process- and debugger-specific runtime attributes. /// This event is generated in the main thread. /// \param out_pattrs (::debapp_attrs_t *) /// \return ::DRC_NONE, ::DRC_OK ev_get_debapp_attrs, /// Rebase database if the debugged program has been rebased by the system. /// This event is generated in the main thread. /// \param new_base (::ea_t) /// \return ::DRC_NONE, ::DRC_OK ev_rebase_if_required_to, /// Prepare to pause the process. /// Normally the next get_debug_event() will pause the process /// If the process is sleeping, /// then the pause will not occur until the process wakes up. /// If the debugger module does not react to this event, /// then it will be impossible to pause the program. /// This event is generated in debthread. /// Available if \ref DBG_HAS_REQUEST_PAUSE is set /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_request_pause, /// Stop the process. /// May be generated while the process is running or suspended. /// Must terminate the process in any case. /// The kernel will repeatedly call get_debug_event() until ::PROCESS_EXITED is received. /// In this mode, all other events will be automatically handled and process will be resumed. /// This event is generated in debthread. /// Must be implemented. /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_exit_process, /// Get a pending debug event and suspend the process. /// This event will be generated regularly by IDA. /// This event is generated in debthread. /// IMPORTANT: the BREAKPOINT/EXCEPTION/STEP events must be reported /// only after reporting other pending events for a thread. /// Must be implemented. /// \param code (::gdecode_t *) /// \param event (::debug_event_t *) /// \param timeout_ms (int) /// \retval ignored ev_get_debug_event, /// Continue after handling the event. /// This event is generated in debthread. /// Must be implemented. /// \param event (::debug_event_t *) /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_resume, /// Set exception handling. /// This event is generated in debthread or the main thread. /// Available if \ref DBG_HAS_SET_EXCEPTION_INFO is set /// \param info (::exception_info_t *) /// \param qty (int) /// \return ::DRC_NONE, ::DRC_OK ev_set_exception_info, /// This event will be generated by the kernel each time /// it has suspended the debugger process and refreshed the database. /// The debugger module may add information to the database if it wants. /// /// The reason for introducing this event is that when an event line /// LOAD_DLL happens, the database does not reflect the memory state yet /// and therefore we can't add information about the dll into the database /// in the get_debug_event() event. /// Only when the kernel has adjusted the database we can do it. /// Example: for imported PE DLLs we will add the exported event /// names to the database. /// /// This event is generated in the main thread. /// \param dlls_added (bool) /// \param thr_names (::thread_name_vec_t *) (for the kernel only, must be NULL) /// \return ::DRC_NONE, ::DRC_OK ev_suspended, /// \name Threads /// The following events manipulate threads. /// These events are generated in debthread. /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR //@{ /// Suspend a running thread /// Available if \ref DBG_HAS_THREAD_SUSPEND is set /// \param tid (::thid_t) ev_thread_suspend, /// Resume a suspended thread /// Available if \ref DBG_HAS_THREAD_CONTINUE is set /// \param tid (::thid_t) ev_thread_continue, /// Specify resume action /// Available if \ref DBG_HAS_SET_RESUME_MODE is set /// \param tid (::thid_t) /// \param resmod (::resume_mode_t) ev_set_resume_mode, //@} /// Read thread registers. /// This event is generated in debthread. /// Must be implemented. /// \param tid (::thid_t) thread id /// \param clsmask (int) bitmask of register classes to read /// \param values (::regval_t *) pointer to vector of regvals for all registers. /// regval must have debugger_t::nregs elements /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_read_registers, /// Write one thread register. /// This event is generated in debthread. /// Must be implemented. /// \param tid (::thid_t) thread id /// \param regidx (int) register index /// \param value (const ::regval_t *) new value of the register /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_write_register, /// Get information about the base of a segment register. /// Currently used by the IBM PC module to resolve references like fs:0. /// This event is generated in debthread. /// Available if \ref DBG_HAS_THREAD_GET_SREG_BASE is set /// \param answer (::ea_t *) pointer to the answer. can't be NULL. /// \param tid (::thid_t) thread id /// \param sreg_value (int) value of the segment register (returned by get_reg_val()) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_NONE, ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_thread_get_sreg_base, /// \name Memory manipulation /// The following events manipulate bytes in the memory. //@{ /// Get information on the memory ranges. /// The debugger module fills 'ranges'. The returned vector must be sorted. /// This event is generated in debthread. /// Must be implemented. /// \param ranges (::meminfo_vec_t *) /// \param errbuf (::qstring *) may be NULL /// \retval ::DRC_OK new memory layout is returned /// \retval ::DRC_FAILED, ::DRC_NETERR, ::DRC_NOPROC, ::DRC_NOCHG, ::DRC_IDBSEG ev_get_memory_info, /// Read process memory. /// This event is generated in debthread. /// \param nbytes (size_t *) number of read bytes /// \param ea (::ea_t) /// \param buffer (void *) /// \param size (::size_t) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NOPROC ev_read_memory, /// Write process memory. /// This event is generated in debthread. /// \param nbytes (size_t *) number of written bytes /// \param ea (::ea_t) /// \param buffer (const void *) /// \param size (::size_t) /// \param errbuf (::qstring *) may be NULL /// \retval ::DRC_OK, ::DRC_FAILED, ::DRC_NOPROC ev_write_memory, //@} /// Is it possible to set breakpoint? /// This event is generated in debthread or in the main thread if debthread /// is not running yet. /// It is generated to verify hardware breakpoints. /// Available if \ref DBG_HAS_CHECK_BPT is set /// \param bptvc (int *) breakpoint verification codes \ref BPT_ /// \param type (::bpttype_t) \ref BPT_H /// \param ea (::ea_t) /// \param len (int) /// \return ::DRC_OK, ::DRC_NONE ev_check_bpt, /// Add/del breakpoints. /// bpts array contains nadd bpts to add, followed by ndel bpts to del. /// This event is generated in debthread. /// \param nbpts (int *) number of updated breakpoints /// \param bpts (::update_bpt_info_t *) /// \param nadd (int) /// \param ndel (int) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NETERR ev_update_bpts, /// Update low-level (server side) breakpoint conditions. /// This event is generated in debthread. /// \param nupdated (int *) number of updated conditions /// \param lowcnds (const ::lowcnd_t *) /// \param nlowcnds (int) /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK, ::DRC_NETERR ev_update_lowcnds, /// \name Remote file /// Open/close/read/write a remote file. /// These events are generated in the main thread /// Available if \ref DBG_HAS_OPEN_FILE is set //@{ /// \param file (const char *) /// \param fsize (::uint64 *) /// \param readonly (bool) /// \param errbuf (::qstring *) may be NULL /// \retval (int) handle /// \retval -1 error ev_open_file, /// \param fn (int) handle /// \return ignored ev_close_file, /// \param fn (int) handle /// \param off (::qoff64_t) /// \param buf (void *) /// \param size (size_t) /// \param errbuf (::qstring *) may be NULL /// \retval number of read bytes ev_read_file, /// \param fn (int) handle /// \param off (::qoff64_t) /// \param buf (const void *) /// \param size (size_t) /// \param errbuf (::qstring *) may be NULL /// \retval number of written bytes ev_write_file, //@} /// Map process address. /// The debugger module may ignore this event. /// This event is generated in debthread. /// IDA will generate this event only if \ref DBG_HAS_MAP_ADDRESS is set. /// \param mapped (::ea_t *) mapped address or #BADADDR /// \param off (::ea_t) offset to map /// \param regs (const ::regval_t *) current register values. /// if regs == NULL, then perform global mapping, /// which is independent on used registers /// usually such a mapping is a trivial identity mapping /// \param regnum (int) required mapping. /// May be specified as a segment register number or a regular /// register number if the required mapping can be deduced from it. /// For example, esp implies that ss should be used. /// \return ::DRC_NONE, ::DRC_OK see MAPPED ev_map_address, /// Get pointer to debugger specific events. /// This event returns a pointer to a structure that holds pointers to /// debugger module specific events. For information on the structure /// layout, please check the corresponding debugger module. Most debugger /// modules return NULL because they do not have any extensions. Available /// extensions may be generated from plugins. /// This event is generated in the main thread. /// \param ext (void **) /// \return ::DRC_NONE, ::DRC_OK see EXT ev_get_debmod_extensions, /// Calculate the call stack trace for the given thread. /// This event is generated when the process is suspended and should fill the 'trace' object /// with the information about the current call stack. If this event returns DRC_NONE, IDA /// will try to invoke a processor-specific mechanism (see processor_t::ev_update_call_stack). /// If the current processor module does not implement stack tracing, then IDA will fall back /// to a generic algorithm (based on the frame pointer chain) to calculate the trace. /// This event is ideal if the debugging targets manage stack frames in a peculiar way, /// requiring special analysis. /// This event is generated in the main thread. /// Available if \ref DBG_HAS_UPDATE_CALL_STACK is set /// \param tid (::thid_t) /// \param trace (::call_stack_t *) /// \retval ::DRC_NONE false or not implemented /// \return ::DRC_OK success ev_update_call_stack, /// Call application function. /// This event calls a function from the debugged application. /// This event is generated in debthread /// Available if \ref HAS_APPCALL is set /// \param[out] blob_ea (::ea_t *) ea of stkargs blob, /// #BADADDR if failed and errbuf is filled /// \param func_ea (::ea_t) address to call /// \param tid (::thid_t) thread to use /// \param fti (const ::func_type_data_t *) type information for the generated event /// \param nargs (int) number of actual arguments /// \param regargs (const ::regobjs_t *) information about register arguments /// \param stkargs (::relobj_t *) memory blob to pass as stack arguments /// (usually contains pointed data) /// it must be relocated by the callback but not changed otherwise /// \param retregs (::regobjs_t *) event return registers. /// \param[out] errbuf (::qstring *) the error message. if empty on failure, see EVENT. /// should not be filled if an appcall exception /// happened but #APPCALL_DEBEV is set /// \param[out] event (::debug_event_t *) the last debug event that occurred during appcall execution /// filled only if the appcall execution fails and #APPCALL_DEBEV is set /// \param options (int) appcall options, usually taken from \inf{appcall_options}. /// possible values: combination of \ref APPCALL_ or 0 /// \retval ::DRC_NONE /// \retval ::DRC_OK, see BLOB_EA ev_appcall, /// Cleanup after appcall(). /// The debugger module must keep the stack blob in the memory until this event /// is generated. It will be generated by the kernel for each successful appcall(). /// There is an exception: if #APPCALL_MANUAL, IDA may not call cleanup_appcall. /// If the user selects to terminate a manual appcall, then cleanup_appcall will be generated. /// Otherwise, the debugger module should terminate the appcall when the generated /// event returns. /// This event is generated in debthread. /// Available if \ref HAS_APPCALL is set /// \param tid (::thid_t) /// \retval ::DRC_EVENTS success, there are pending events /// \retval ::DRC_OK success /// \retval ::DRC_FAILED failed /// \retval ::DRC_NETERR network error ev_cleanup_appcall, /// Evaluate a low level breakpoint condition at 'ea'. /// Other evaluation errors are displayed in a dialog box. /// This call is used by IDA when the process has already been temporarily /// suspended for some reason and IDA has to decide whether the process /// should be resumed or definitely suspended because of a breakpoint /// with a low level condition. /// This event is generated in debthread. /// \param tid (::thid_t) /// \param ea (::ea_t) /// \param errbuf (::qstring *) may be NULL /// \retval ::DRC_OK condition is satisfied /// \retval ::DRC_FAILED not satisfied /// \retval ::DRC_NETERR network error ev_eval_lowcnd, /// Perform a debugger-specific event. /// This event is generated in debthread /// \param fn (int) /// \param buf (const void *) /// \param size (size_t) /// \param poutbuf (void **) /// \param poutsize (ssize_t *) /// \param errbuf (::qstring *) may be NULL /// \retval DRC_... ev_send_ioctl, /// Enable/Disable tracing. /// The kernel will generated this event if the debugger plugin set DBG_FLAG_TRACER_MODULE. /// TRACE_FLAGS can be a set of #STEP_TRACE, #INSN_TRACE, #BBLK_TRACE or #FUNC_TRACE. /// This event is generated in the main thread. /// \param tid (::thid_t) /// \param enable (bool) /// \param trace_flags (int) /// \return ::DRC_OK, ::DRC_FAILED, ::DRC_NONE ev_dbg_enable_trace, /// Is tracing enabled? /// The kernel will generated this event if the debugger plugin set DBG_FLAG_TRACER_MODULE. /// TRACE_BIT can be one of the following: #STEP_TRACE, #INSN_TRACE, #BBLK_TRACE or #FUNC_TRACE /// \param tid (::thid_t) /// \param tracebit (int) /// \retval ::DRC_OK bit is set /// \retval ::DRC_NONE bit is not set or not implemented ev_is_tracing_enabled, /// Execute a command on the remote computer. /// Available if \ref DBG_HAS_REXEC is set /// \param cmdline (const char *) /// \return (int) exit code ev_rexec, /// Get the path to a file containing source debug info for the given module. /// This allows srcinfo providers to call into the debugger when looking for debug info. /// It is useful in certain cases like the iOS debugger, which is a remote debugger but /// the remote debugserver does not provide dwarf info. So, we allow the debugger client /// to decide where to look for debug info locally. /// \param path (qstring *) output path (file might not exist) /// \param base (::ea_t) base address of a module in the target process /// \return ::DRC_NONE, ::DRC_OK result stored in PATH ev_get_srcinfo_path, /// Search for a binary pattern in the program. /// \param out (::ea_t *) binary pattern address /// \param start_ea (::ea_t) linear address, start of range to search /// \param end_ea (::ea_t) linear address, end of range to search (exclusive) /// \param data (const ::compiled_binpat_vec_t *) /// the prepared data to search for (see parse_binpat_str()) /// \param srch_flags (int) combination of \ref BIN_SEARCH_ /// \param errbuf (::qstring *) may be NULL /// \return ::DRC_OK EA contains the binary pattern address /// \retval ::DRC_FAILED not found /// \retval ::DRC_NONE not implemented /// \retval ::DRC_NETERR, ::DRC_ERROR ev_bin_search, }; /// Event notification callback. /// It will be hooked to the HT_IDD notification point /// when the debugger is loaded and unhooked during /// the debugger unloading. /// The debugger plugin will be the last one /// who will receive the notification. hook_cb_t *callback; /// Event notification handler ssize_t notify(event_t event_code, ...) { va_list va; va_start(va, event_code); ssize_t code = invoke_callbacks(HT_IDD, event_code, va); va_end(va); return code; } drc_t notify_drc(event_t event_code, ...) { va_list va; va_start(va, event_code); drc_t code = drc_t(invoke_callbacks(HT_IDD, event_code, va)); va_end(va); return code; } /// \defgroup DBG_PROC_ Debug process flags /// Passed as 'dbg_proc_flags' parameter to debugger_t::start_process //@{ #define DBG_PROC_IS_DLL 0x01 ///< database contains a dll (not exe) #define DBG_PROC_IS_GUI 0x02 ///< using gui version of ida #define DBG_PROC_32BIT 0x04 ///< application is 32-bit #define DBG_PROC_64BIT 0x08 ///< application is 64-bit #define DBG_NO_TRACE 0x10 ///< do not trace the application (mac/linux) #define DBG_HIDE_WINDOW 0x20 ///< application should be hidden on startup (windows) #define DBG_SUSPENDED 0x40 ///< application should be suspended on startup (mac) //@} /// \defgroup BPT_ Breakpoint verification codes /// Return values for debugger_t::check_bpt //@{ #define BPT_OK 0 ///< breakpoint can be set #define BPT_INTERNAL_ERR 1 ///< interr occurred when verifying breakpoint #define BPT_BAD_TYPE 2 ///< bpt type is not supported #define BPT_BAD_ALIGN 3 ///< alignment is invalid #define BPT_BAD_ADDR 4 ///< ea is invalid #define BPT_BAD_LEN 5 ///< bpt len is invalid #define BPT_TOO_MANY 6 ///< reached max number of supported breakpoints #define BPT_READ_ERROR 7 ///< failed to read memory at bpt ea #define BPT_WRITE_ERROR 8 ///< failed to write memory at bpt ea #define BPT_SKIP 9 ///< update_bpts(): do not process bpt #define BPT_PAGE_OK 10 ///< update_bpts(): ok, added a page bpt //@} /// \defgroup APPCALL_ Appcall options /// Passed as 'options' parameter to debugger_t::appcall //@{ #define APPCALL_MANUAL 0x0001 ///< Only set up the appcall, do not run. ///< debugger_t::cleanup_appcall will not be generated by ida! #define APPCALL_DEBEV 0x0002 ///< Return debug event information #define APPCALL_TIMEOUT 0x0004 ///< Appcall with timeout. ///< If timed out, errbuf will contain "timeout". ///< See #SET_APPCALL_TIMEOUT and #GET_APPCALL_TIMEOUT /// Set appcall timeout in milliseconds #define SET_APPCALL_TIMEOUT(msecs) ((uint(msecs) << 16)|APPCALL_TIMEOUT) /// Timeout value is contained in high 2 bytes of 'options' parameter #define GET_APPCALL_TIMEOUT(options) (uint(options) >> 16) //@} // Notification helpers, should be used instead of direct dbg->notify(...) calls inline bool init_debugger(const char *hostname, int portnum, const char *password, qstring *errbuf=NULL); inline bool term_debugger(void); inline drc_t get_processes(procinfo_vec_t *procs, qstring *errbuf=NULL); inline drc_t start_process(const char *path, const char *args, const char *startdir, uint32 dbg_proc_flags, const char *input_path, uint32 input_file_crc32, qstring *errbuf=NULL); inline drc_t attach_process(pid_t pid, int event_id, uint32 dbg_proc_flags, qstring *errbuf=NULL); inline drc_t detach_process(qstring *errbuf=NULL); inline bool get_debapp_attrs(debapp_attrs_t *out_pattrs); inline void rebase_if_required_to(ea_t new_base); inline drc_t request_pause(qstring *errbuf=NULL); inline drc_t exit_process(qstring *errbuf=NULL); inline gdecode_t get_debug_event(debug_event_t *event, int timeout_ms); inline drc_t resume(const debug_event_t *event, qstring *errbuf=NULL); inline void set_exception_info(const exception_info_t *info, int qty); inline void suspended(bool dlls_added, thread_name_vec_t *thr_names=NULL); inline drc_t thread_suspend(thid_t tid, qstring *errbuf=NULL); inline drc_t thread_continue(thid_t tid, qstring *errbuf=NULL); inline drc_t set_resume_mode(thid_t tid, resume_mode_t resmod, qstring *errbuf=NULL); inline drc_t read_registers(thid_t tid, int clsmask, regval_t *values, qstring *errbuf=NULL); inline drc_t write_register(thid_t tid, int regidx, const regval_t *value, qstring *errbuf=NULL); inline drc_t thread_get_sreg_base(ea_t *answer, thid_t tid, int sreg_value, qstring *errbuf=NULL); inline drc_t get_memory_info(meminfo_vec_t &ranges, qstring *errbuf=NULL); inline drc_t read_memory(size_t *nbytes, ea_t ea, void *buffer, size_t size, qstring *errbuf=NULL); inline drc_t write_memory(size_t *nbytes, ea_t ea, const void *buffer, size_t size, qstring *errbuf=NULL); inline drc_t check_bpt(int *bptvc, bpttype_t type, ea_t ea, int len); inline drc_t update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf=NULL); inline drc_t update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf=NULL); inline int open_file(const char *file, uint64 *fsize, bool readonly, qstring *errbuf=NULL); inline void close_file(int fn); inline ssize_t read_file(int fn, qoff64_t off, void *buf, size_t size, qstring *errbuf=NULL); inline ssize_t write_file(int fn, qoff64_t off, const void *buf, size_t size, qstring *errbuf=NULL); inline ea_t map_address(ea_t off, const regval_t *regs, int regnum); inline const void *get_debmod_extensions(void); inline bool update_call_stack(thid_t tid, call_stack_t *trace); inline ea_t appcall( ea_t func_ea, thid_t tid, const struct func_type_data_t *fti, int nargs, const struct regobjs_t *regargs, struct relobj_t *stkargs, struct regobjs_t *retregs, qstring *errbuf, debug_event_t *event, int options); inline drc_t cleanup_appcall(thid_t tid); inline drc_t eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf=NULL); inline drc_t send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize, qstring *errbuf=NULL); inline bool dbg_enable_trace(thid_t tid, bool enable, int trace_flags); inline bool is_tracing_enabled(thid_t tid, int tracebit); inline int rexec(const char *cmdline); inline bool get_srcinfo_path(qstring *path, ea_t base); inline drc_t bin_search( ea_t *out, ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int srch_flags, qstring *errbuf=NULL); }; #ifndef __X86__ CASSERT(sizeof(debugger_t) == 104); #else CASSERT(sizeof(debugger_t) == 60); #endif #define RQ_MASKING 0x0001 // masking step handler: unless errors, tmpbpt handlers won't be generated // should be used only with request_internal_step() #define RQ_SUSPEND 0x0002 // suspending step handler: suspends the app // handle_debug_event: suspends the app #define RQ_NOSUSP 0x0000 // running step handler: continues the app #define RQ_IGNWERR 0x0004 // ignore breakpoint write failures #define RQ_SILENT 0x0008 // all: no dialog boxes #define RQ_VERBOSE 0x0000 // all: display dialog boxes #define RQ_SWSCREEN 0x0010 // handle_debug_event: switch screens #define RQ__NOTHRRF 0x0020 // handle_debug_event: do not refresh threads #define RQ_PROCEXIT 0x0040 // snapshots: the process is exiting #define RQ_IDAIDLE 0x0080 // handle_debug_event: ida is idle #define RQ_SUSPRUN 0x0100 // handle_debug_event: suspend at PROCESS_STARTED #define RQ_RESUME 0x0200 // handle_debug_event: resume application #define RQ_RESMOD 0xF000 // resume_mode_t #define RQ_RESMOD_SHIFT 12 #define RQ_INTO (RESMOD_INTO << RQ_RESMOD_SHIFT) inline bool debugger_t::init_debugger(const char *hostname, int portnum, const char *password, qstring *errbuf) { return notify_drc(ev_init_debugger, hostname, portnum, password, errbuf) == DRC_OK; } inline bool debugger_t::term_debugger(void) { return notify_drc(ev_term_debugger) == DRC_OK; } inline drc_t debugger_t::get_processes(procinfo_vec_t *procs, qstring *errbuf) { return notify_drc(ev_get_processes, procs, errbuf); } inline drc_t debugger_t::start_process( const char *path, const char *args, const char *startdir, uint32 dbg_proc_flags, const char *input_path, uint32 input_file_crc32, qstring *errbuf) { return notify_drc(ev_start_process, path, args, startdir, dbg_proc_flags, input_path, input_file_crc32, errbuf); } inline drc_t debugger_t::attach_process(pid_t pid, int event_id, uint32 dbg_proc_flags, qstring *errbuf) { return notify_drc(ev_attach_process, pid, event_id, dbg_proc_flags, errbuf); } inline drc_t debugger_t::detach_process(qstring *errbuf) { return notify_drc(ev_detach_process, errbuf); } inline bool debugger_t::get_debapp_attrs(debapp_attrs_t *out_pattrs) { return notify_drc(ev_get_debapp_attrs, out_pattrs) != DRC_NONE; } inline void debugger_t::rebase_if_required_to(ea_t new_base) { notify_drc(ev_rebase_if_required_to, new_base); } inline drc_t debugger_t::request_pause(qstring *errbuf) { return notify_drc(ev_request_pause, errbuf); } inline drc_t debugger_t::exit_process(qstring *errbuf) { return notify_drc(ev_exit_process, errbuf); } inline gdecode_t debugger_t::get_debug_event(debug_event_t *event, int timeout_ms) { gdecode_t code = GDE_ERROR; notify_drc(ev_get_debug_event, &code, event, timeout_ms); return code; } inline drc_t debugger_t::resume(const debug_event_t *event, qstring *errbuf) { return notify_drc(ev_resume, event, errbuf); } inline void debugger_t::set_exception_info(const exception_info_t *info, int qty) { notify_drc(ev_set_exception_info, info, qty); } inline void debugger_t::suspended(bool dlls_added, thread_name_vec_t *thr_names) { notify_drc(ev_suspended, dlls_added, thr_names); } inline drc_t debugger_t::thread_suspend(thid_t tid, qstring *errbuf) { return notify_drc(ev_thread_suspend, tid, errbuf); } inline drc_t debugger_t::thread_continue(thid_t tid, qstring *errbuf) { return notify_drc(ev_thread_continue, tid, errbuf); } inline drc_t debugger_t::set_resume_mode(thid_t tid, resume_mode_t resmod, qstring *errbuf) { return notify_drc(ev_set_resume_mode, tid, resmod, errbuf); } inline drc_t debugger_t::read_registers(thid_t tid, int clsmask, regval_t *values, qstring *errbuf) { return notify_drc(ev_read_registers, tid, clsmask, values, errbuf); } inline drc_t debugger_t::write_register(thid_t tid, int regidx, const regval_t *value, qstring *errbuf) { return notify_drc(ev_write_register, tid, regidx, value, errbuf); } inline drc_t debugger_t::thread_get_sreg_base(ea_t *answer, thid_t tid, int sreg_value, qstring *errbuf) { return notify_drc(ev_thread_get_sreg_base, answer, tid, sreg_value, errbuf); } inline drc_t debugger_t::get_memory_info(meminfo_vec_t &ranges, qstring *errbuf) { return notify_drc(ev_get_memory_info, &ranges, errbuf); } inline drc_t debugger_t::read_memory(size_t *nbytes, ea_t ea, void *buffer, size_t size, qstring *errbuf) { return notify_drc(ev_read_memory, nbytes, ea, buffer, size, errbuf); } inline drc_t debugger_t::write_memory(size_t *nbytes, ea_t ea, const void *buffer, size_t size, qstring *errbuf) { return notify_drc(ev_write_memory, nbytes, ea, buffer, size, errbuf); } inline drc_t debugger_t::check_bpt(int *bptvc, bpttype_t type, ea_t ea, int len) { return notify_drc(ev_check_bpt, bptvc, type, ea, len); } inline drc_t debugger_t::update_bpts(int *nbpts, update_bpt_info_t *bpts, int nadd, int ndel, qstring *errbuf) { return notify_drc(ev_update_bpts, nbpts, bpts, nadd, ndel, errbuf); } inline drc_t debugger_t::update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf) { return notify_drc(ev_update_lowcnds, nupdated, lowcnds, nlowcnds, errbuf); } inline int debugger_t::open_file(const char *file, uint64 *fsize, bool readonly, qstring *errbuf) { return int(notify(ev_open_file, file, fsize, readonly, errbuf)); } inline void debugger_t::close_file(int fn) { notify(ev_close_file, fn); } inline ssize_t debugger_t::read_file(int fn, qoff64_t off, void *buf, size_t size, qstring *errbuf) { return notify(ev_read_file, fn, off, buf, size, errbuf); } inline ssize_t debugger_t::write_file(int fn, qoff64_t off, const void *buf, size_t size, qstring *errbuf) { return notify(ev_write_file, fn, off, buf, size, errbuf); } inline ea_t debugger_t::map_address(ea_t off, const regval_t *rvs, int regnum) { ea_t mapped; return notify_drc(ev_map_address, &mapped, off, rvs, regnum) == DRC_OK ? mapped : off; } inline const void *debugger_t::get_debmod_extensions(void) { void *ext; if ( notify_drc(ev_get_debmod_extensions, &ext) != DRC_OK ) ext = NULL; return ext; } inline bool debugger_t::update_call_stack(thid_t tid, call_stack_t *trace) { return notify_drc(ev_update_call_stack, tid, trace) != DRC_NONE; } inline ea_t debugger_t::appcall( ea_t func_ea, thid_t tid, const struct func_type_data_t *fti, int nargs, const struct regobjs_t *regargs, struct relobj_t *stkargs, struct regobjs_t *retregs, qstring *errbuf, debug_event_t *event, int options) { ea_t blob_ea; if ( notify_drc(ev_appcall, &blob_ea, func_ea, tid, fti, nargs, regargs, stkargs, retregs, errbuf, event, options) != DRC_OK ) { blob_ea = BADADDR; if ( errbuf != NULL ) *errbuf = "Debugger plugin does not support an application function call"; } return blob_ea; } inline drc_t debugger_t::cleanup_appcall(thid_t tid) { return notify_drc(ev_cleanup_appcall, tid); } inline drc_t debugger_t::eval_lowcnd(thid_t tid, ea_t ea, qstring *errbuf) { return notify_drc(ev_eval_lowcnd, tid, ea, errbuf); } inline drc_t debugger_t::send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize, qstring *errbuf) { return notify_drc(ev_send_ioctl, fn, buf, size, poutbuf, poutsize, errbuf); } inline bool debugger_t::dbg_enable_trace(thid_t tid, bool enable, int trace_flags) { return notify_drc(ev_dbg_enable_trace, tid, enable, trace_flags) == DRC_OK; } inline bool debugger_t::is_tracing_enabled(thid_t tid, int tracebit) { return notify_drc(ev_is_tracing_enabled, tid, tracebit) == DRC_OK; } inline int debugger_t::rexec(const char *cmdline) { return int(notify(ev_rexec, cmdline)); } inline bool debugger_t::get_srcinfo_path(qstring *path, ea_t base) { return notify_drc(ev_get_srcinfo_path, path, base) == DRC_OK; } inline drc_t debugger_t::bin_search( ea_t *out, ea_t start_ea, ea_t end_ea, const compiled_binpat_vec_t &data, int srch_flags, qstring *errbuf) { return notify_drc(ev_bin_search, out, start_ea, end_ea, &data, srch_flags, errbuf); } #endif // _IDD_HPP