/*
 *      Interactive disassembler (IDA).
 *      Copyright (c) 1990-2025 Hex-Rays
 *      ALL RIGHTS RESERVED.
 *
 */

#ifndef _IDD_HPP
#define _IDD_HPP

#include <range.hpp>
#include <ua.hpp>

/*! \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   31

class idc_value_t;
struct fpvalue_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<process_info_t> 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 = sizeof(*this); ///< 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 = -1;

  debapp_attrs_t() : addrsize(DEF_ADDRSIZE) {}
};

//====================================================================
//
//                          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
///@}
  uchar register_class_mask;          ///< mask of register classes
  op_dtype_t dtype;                   ///< Register size (see \ref dt_)
  const char *const *bit_strings;     ///< strings corresponding to each bit of the register.
                                      ///< (nullptr = 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_t> register_info_vec_t;

//--------------------------------------------------------------------------
struct dynamic_register_set_t
{
  typedef qvector<const char *> const_char_vec_t;

  register_info_vec_t       ri_vec;
  qstrvec_t                 strvec;
  const_char_vec_t          classname_ptrs;
  qvector<const_char_vec_t> bit_strings_ptrs_vec;
  int default_regclasses = 1; ///< Mask of default printed register classes,
                              ///< 1 is the general register set

  void clear()
  {
    ri_vec.clear();
    strvec.clear();
    classname_ptrs.clear();
    bit_strings_ptrs_vec.clear();
  }

  void add_register(const register_info_t &ri)
  {
    add_register(ri.name,
                 ri.flags,
                 ri.dtype,
                 ri.register_class_mask,
                 ri.bit_strings,
                 ri.default_bit_strings_mask);
  }

  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 &regname = 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_mask      = register_class;
    ri.bit_strings              = bit_strings;
    ri.default_bit_strings_mask = bits_mask;
  }

  void set_regclasses(const char **register_classes, int default_regcls)
  {
    while ( *register_classes != nullptr )
    {
      qstring &register_class = strvec.push_back();
      register_class = *register_classes++;
      classname_ptrs.push_back(register_class.begin());
    }
    classname_ptrs.push_back(nullptr);
    default_regclasses = default_regcls;
  }

  // Values for debugger_t.
  bool empty() const           { return ri_vec.empty(); }
  size_t nregs() const         { return ri_vec.size(); }
  register_info_t *registers() { return ri_vec.begin(); }
  const char **regclasses()    { 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);
idaman THREAD_SAFE void ida_export serialize_insn(
        bytevec_t *s,
        const insn_t &insn);
idaman THREAD_SAFE void ida_export deserialize_insn(
        insn_t *insn,
        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 = 0;              ///< 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 = 0;           ///< Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit)
  uchar perm = 0;              ///< Memory range permissions (0-no information): see segment.hpp

  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);
struct meminfo_vec_t : public qvector<memory_info_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_segm_t> scattered_image_t; ///< vector of scattered segments

//====================================================================
//
//                         Debug events
//

/// Used by debugger modules to launching processes with environment variables
struct launch_env_t : public qstrvec_t
{
  bool merge = true;  // merge environment variables with system ones
                      // or replace it completely
};

/// Debug event codes
enum event_id_t
{
  NO_EVENT         =  0, ///< 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  =  1, ///< New process has been started.
  PROCESS_EXITED   =  2, ///< Process has been stopped.
  THREAD_STARTED   =  3, ///< New thread has been started.
  THREAD_EXITED    =  4, ///< Thread has been stopped.
  BREAKPOINT       =  5, ///< Breakpoint has been reached. IDA will complain
                         ///< about unknown breakpoints, they should be reported
                         ///< as exceptions.
  STEP             =  6, ///< One instruction has been executed. Spurious
                         ///< events of this kind are silently ignored by IDA.
  EXCEPTION        =  7, ///< Exception.
  LIB_LOADED       =  8, ///< New library has been loaded.
  LIB_UNLOADED     =  9, ///< Library has been unloaded.
  INFORMATION      = 10, ///< 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 = 11, ///< Successfully attached to running process.
  PROCESS_DETACHED = 12, ///< Successfully detached from process.
  PROCESS_SUSPENDED= 13, ///< 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       = 14, ///< The trace buffer of the tracer module is full
                         ///< and IDA needs to read it before continuing

  STATUS_MASK      = 0xF0000000, ///< additional info about process state
  BITNESS_CHANGED  = 0x80000000, ///< Debugger detected the process bitness changing.
};

// 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<modinfo_t> modinfovec_t;

/// Describes a breakpoint event.
/// (see ::BREAKPOINT)
struct bptaddr_t
{
  ea_t hea = BADADDR;   ///< Possible address referenced by hardware breakpoints
  ea_t kea = BADADDR;   ///< 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.
};

/// 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 = NO_PROCESS;  ///< Process where the event occurred
  thid_t tid = NO_THREAD;  ///< Thread where the event occurred
  ea_t ea = BADADDR;       ///< Address where the event occurred
  bool handled = false;    ///< Is event handled by the debugger?.
                           ///< (from the system's point of view)
                           ///< Meaningful for ::EXCEPTION events
private:
  event_id_t _eid = NO_EVENT;
#ifndef SWIG
  char bytes[qmax(sizeof(modinfo_t), sizeof(excinfo_t))];
#endif

public:
  debug_event_t() { memset(bytes, 0, sizeof(bytes)); }
  debug_event_t(const debug_event_t &r) { copy(r); }
  ~debug_event_t() { clear(); }
  debug_event_t &operator =(const debug_event_t &r) { return copy(r); }
  debug_event_t &copy(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() { free_debug_event(this); }

  void clear_all()
  {
    clear();
    pid = NO_PROCESS;
    tid = NO_THREAD;
    ea = BADADDR;
    handled = false;
  }

  /// Event code
  event_id_t eid() const { return event_id_t(_eid & ~STATUS_MASK); }

  /// 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); }

  /// process bitness
  bool is_bitness_changed() const { return (_eid & BITNESS_CHANGED) != 0; }
  void set_bitness_changed(bool on=true) { setflag(_eid, BITNESS_CHANGED, on); }

  /// Information that depends on the event code:

  ///< ::PROCESS_STARTED, ::PROCESS_ATTACHED, ::LIB_LOADED
  modinfo_t &modinfo()
  {
    QASSERT(3295, eid() == PROCESS_STARTED || eid() == PROCESS_ATTACHED || eid() == LIB_LOADED);
    return *(modinfo_t *)bytes;
  }
  ///< ::PROCESS_EXITED, ::THREAD_EXITED
  int &exit_code()
  {
    QASSERT(3296, eid() == PROCESS_EXITED || eid() == 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()
  {
    QASSERT(3297, eid() == THREAD_STARTED || eid() == LIB_UNLOADED || eid() == INFORMATION);
    return *(qstring *)bytes;
  }
  ///< ::BREAKPOINT
  bptaddr_t &bpt()
  {
    QASSERT(3298, eid() == BREAKPOINT);
    return *(bptaddr_t *)bytes;
  }
  ///< ::EXCEPTION
  excinfo_t &exc()
  {
    QASSERT(3299, eid() == 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()
  {
    set_eid(BREAKPOINT);
    return bpt();
  }

  excinfo_t &set_exception()
  {
    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() 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);

/// get debug event name
inline const char *get_debug_event_name(const debug_event_t &dev)
{
  switch ( dev.eid() )
  {
    case NO_EVENT:          return "NO_EVENT";
    case THREAD_STARTED:    return "THREAD_STARTED";
    case STEP:              return "STEP";
    case PROCESS_DETACHED:  return "PROCESS_DETACHED";
    case PROCESS_STARTED:   return "PROCESS_STARTED";
    case PROCESS_ATTACHED:  return "PROCESS_ATTACHED";
    case PROCESS_SUSPENDED: return "PROCESS_SUSPENDED";
    case LIB_LOADED:        return "LIB_LOADED";
    case PROCESS_EXITED:    return "PROCESS_EXITED";
    case THREAD_EXITED:     return "THREAD_EXITED";
    case BREAKPOINT:        return "BREAKPOINT";
    case EXCEPTION:         return "EXCEPTION";
    case LIB_UNLOADED:      return "LIB_UNLOADED";
    case INFORMATION:       return "INFORMATION";
    case TRACE_FULL:        return "TRACE_FULL";
    default: return "???";
  }
}

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 = 0;          ///< exception code
  uint32 flags = 0;       ///< \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() const { return (flags & EXC_BREAK) != 0; }

  /// Should we handle the exception?
  bool handle() 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() {}
  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<exception_info_t> 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_FLOAT       (-1)          ///< floating point
#define RVT_INT         (-2)          ///< integer
#define RVT_UNAVAILABLE (-3)          ///< unavailable;
                                      ///< other values mean custom data type
///@}
  int32 rvtype = RVT_INT;             ///< one of \ref RVT_
#ifndef SWIG
  // this union must be the last member (see memset below)
  union
  {
#endif
    uint64 ival;                      ///< RVT_INT
#ifndef SWIG
    uchar reserve[sizeof(bytevec_t)]; ///< bytevec_t: custom data type (use bytes() to access it)
                                      ///< RVT_FLOAT: floating point value in native CPU format
                                      ///< if there are more than one fpvalue formats with the
                                      ///< same length, use custom types to distinguish them
                                      ///< (only one of them can be RVT_FLOAT)
  };
#endif
  bool use_bytevec() const { return rvtype >= RVT_FLOAT; } // floating and custom types
  regval_t()
  {
    memset(reserve, 0, sizeof(regval_t) - qoffsetof(regval_t, reserve));
    ival = ~uint64(0);
  }
  regval_t(const regval_t &r)
  {
    memset(reserve, 0, sizeof(regval_t) - qoffsetof(regval_t, reserve));
    *this = r;
  }
  ~regval_t() { clear(); }

  /// Assign this regval to the given value
  regval_t &operator = (const regval_t &r)
  {
    if ( this == &r )
      return *this;
    if ( r.use_bytevec() )
    {
      if ( use_bytevec() )
        bytes() = r.bytes();
      else
        new (&bytes()) bytevec_t(r.bytes());
    }
    else
    {
      if ( use_bytevec() )
        bytes().~bytevec_t();
      ival = r.ival;
    }
    rvtype = r.rvtype;
    return *this;
  }

  /// Clear register value
  void clear()
  {
    if ( use_bytevec() )
    {
      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 bytes() == r.bytes();
    }
    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 bytevec_t &v) { new (&bytes()) bytevec_t(v); rvtype = RVT_FLOAT; }
  /// Use set_bytes(const uchar *, size_t)
  void _set_bytes(const uchar *data, size_t size, int _rvtype=0)
  {
    new (&bytes()) bytevec_t(data, size);
    rvtype = _rvtype;
    QASSERT(3214, use_bytevec());
  }
  /// Use set_bytes(const bytevec_t &)
  void _set_bytes(const bytevec_t &v, int _rvtype=0)
  {
    new (&bytes()) bytevec_t(v);
    rvtype = _rvtype;
    QASSERT(3215, use_bytevec());
  }
  /// Use set_bytes()
  bytevec_t &_set_bytes(int _rvtype)
  {
    new (&bytes()) bytevec_t;
    rvtype = _rvtype;
    QASSERT(3216, use_bytevec());
    return bytes();
  }
  /// Use set_unavailable()
  void _set_unavailable() { 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
  void set_float(const bytevec_t &v) { set_bytes(v, RVT_FLOAT); }
  /// Set custom regval with raw data
  void set_bytes(const uchar *data, size_t size, int _rvtype=0) { clear(); _set_bytes(data, size, _rvtype); }
  /// Set custom value with existing bytevec
  void set_bytes(const bytevec_t &v, int _rvtype=0) { clear(); _set_bytes(v, _rvtype); }
  /// Initialize this regval to an empty custom value
  bytevec_t &set_bytes(int _rvtype) { clear(); _set_bytes(_rvtype); return bytes(); }
  /// Mark as unavailable
  void set_unavailable() { clear(); _set_unavailable(); }

  ///@}

  /// \name Getters
  ///@{
  /// Get custom value
        bytevec_t &bytes()       { return *(bytevec_t *)reserve; }
  /// Get const custom value
  const bytevec_t &bytes() const { return *(bytevec_t *)reserve; }
  /// Get pointer to value
        void *get_data()       { return use_bytevec() ? (void *)bytes().begin() : (void *)&ival; }
  /// Get const pointer to value
  const void *get_data() const { return use_bytevec() ? (void *)bytes().begin() : (void *)&ival; }
  /// Get size of value
  size_t get_data_size() const
  {
    if ( use_bytevec() )
      return bytes().size();
    if ( rvtype == RVT_INT )
      return sizeof(ival);
    return 0;
  }
  ///@}
};
DECLARE_TYPE_AS_MOVABLE(regval_t);
typedef qvector<regval_t> regvals_t; ///< vector register value objects

/// Instruction operand information
struct idd_opinfo_t
{
  bool modified = false; ///< the operand is modified (written) by the instruction
  ea_t ea = BADADDR;     ///< operand address (#BADADDR - no address)
  regval_t value;        ///< operand value. custom data is represented by 'bytes'.
  int debregidx = -1;    ///< for custom data: index of the corresponding register in dbg->registers
  int value_size = 0;    ///< size of the value in bytes
};

/// 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<call_stack_info_t> {}; ///< 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+3);
  if ( value.rvtype == RVT_INT )
  {
    s.pack_dq(value.ival+1); // +1 to efficiently serialize 0xffffffff
  }
  else if ( value.rvtype != RVT_UNAVAILABLE )
  {
    const bytevec_t &b = value.bytes();
    s.pack_dd(b.size());
    s.append(b.begin(), b.size());
  }
}

//-------------------------------------------------------------------------
template <class T>
THREAD_SAFE inline void extract_regval(regval_t *out, T &v)
{
  out->clear();
  out->rvtype = extract_dd(v) - 3;
  if ( out->rvtype == RVT_INT )
  {
    out->ival = extract_dq(v) - 1;
  }
  else if ( out->rvtype != RVT_UNAVAILABLE )
  {
    bytevec_t &b = out->_set_bytes(out->rvtype);
    int size = extract_dd(v);
    b.resize(size);
    extract_obj(v, b.begin(), size);
  }
}

//-------------------------------------------------------------------------
template <class T>
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 == nullptr || 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] retval 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 = BADADDR;      ///< in: bpt address
  bytevec_t orgbytes;     ///< in(del), out(add): original bytes (only for swbpts)
  bpttype_t type = BPT_SOFT; ///< in: bpt type
  int size = 0;           ///< in: bpt size (only for hwbpts)
  uchar code = 0;         ///< in: 0. #BPT_SKIP entries must be skipped by the debugger module
                          ///< out: \ref BPT_
  pid_t pid = NO_PROCESS; ///< in: process id
  thid_t tid = NO_THREAD; ///< in: thread id

  /// 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_info_t> 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_t> 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_t> 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_BACKINTO, ///< step backwards into call (in time-travel debugging)
  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

  uint64 flags;           /// \ref DBG_FLAG_
                          /// 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         0x0000000000000001ULL  ///< Remote debugger (requires remote host name unless #DBG_FLAG_NOHOST)
  #define DBG_FLAG_NOHOST         0x0000000000000002ULL  ///< Remote debugger with does not require network params (host/port/pass).
                                                         ///< (a unique device connected to the machine)
  #define DBG_FLAG_FAKE_ATTACH    0x0000000000000004ULL  ///< ::PROCESS_ATTACHED is a fake event
                                                         ///< and does not suspend the execution
  #define DBG_FLAG_HWDATBPT_ONE   0x0000000000000008ULL  ///< Hardware data breakpoints are
                                                         ///< one byte size by default
  #define DBG_FLAG_CAN_CONT_BPT   0x0000000000000010ULL  ///< 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       0x0000000000000020ULL  ///< Remote debugger requires port number (to be used with DBG_FLAG_NOHOST)
  #define DBG_FLAG_DONT_DISTURB   0x0000000000000040ULL  ///< 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           0x0000000000000080ULL  ///< The debugger is safe (probably because it just emulates the application
                                                         ///< without really running it)
  #define DBG_FLAG_CLEAN_EXIT     0x0000000000000100ULL  ///< 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      0x0000000000000200ULL  ///< Take segment register values into account (non flat memory)
  #define DBG_FLAG_NOSTARTDIR     0x0000000000000400ULL  ///< Debugger module doesn't use startup directory
  #define DBG_FLAG_NOPARAMETERS   0x0000000000000800ULL  ///< Debugger module doesn't use commandline parameters
  #define DBG_FLAG_NOPASSWORD     0x0000000000001000ULL  ///< Remote debugger doesn't use password
  #define DBG_FLAG_CONNSTRING     0x0000000000002000ULL  ///< Display "Connection string" instead of "Hostname" and hide the "Port" field
  #define DBG_FLAG_SMALLBLKS      0x0000000000004000ULL  ///< If set, IDA uses 256-byte blocks for caching memory contents.
                                                         ///< Otherwise, 1024-byte blocks are used
  #define DBG_FLAG_MANMEMINFO     0x0000000000008000ULL  ///< 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     0x0000000000010000ULL  ///< IDA may take a memory snapshot at ::PROCESS_EXITED event
  #define DBG_FLAG_VIRTHREADS     0x0000000000020000ULL  ///< 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        0x0000000000040000ULL  ///< Low level breakpoint conditions are supported.
  #define DBG_FLAG_DEBTHREAD      0x0000000000080000ULL  ///< 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.
  #define DBG_FLAG_DEBUG_DLL      0x0000000000100000ULL  ///< Can debug standalone DLLs.
                                                         ///< For example, Bochs debugger can debug any snippet of code
  #define DBG_FLAG_FAKE_MEMORY    0x0000000000200000ULL  ///< 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  0x0000000000400000ULL  ///< The debugger supports arbitrary size hardware breakpoints.
  #define DBG_FLAG_TRACER_MODULE  0x0000000000800000ULL  ///< The module is a tracer, not a full featured debugger module
  #define DBG_FLAG_PREFER_SWBPTS  0x0000000001000000ULL  ///< Prefer to use software breakpoints
  #define DBG_FLAG_LAZY_WATCHPTS  0x0000000002000000ULL  ///< 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      0x0000000004000000ULL  ///< Do not refresh memory layout info after single stepping
  #define DBG_FLAG_ADD_ENVS       0x0000000008000000ULL  ///< The debugger supports launching processes with environment variables
  #define DBG_FLAG_MERGE_ENVS     0x0000000010000000ULL  ///< The debugger supports merge or replace setting for environment variables
                                                         ///< (only makes sense if DBG_FLAG_ADD_ENVS is set)
  #define DBG_FLAG_DISABLE_ASLR   0x0000000020000000ULL  ///< The debugger support ASLR disabling
                                                         ///< (Address space layout randomization)
  #define DBG_FLAG_TTD            0x0000000040000000ULL  ///< The debugger is a time travel debugger and supports continuing backwards
  #define DBG_FLAG_FULL_INSTR_BPT 0x0000000080000000ULL  ///< Setting a breakpoint in the middle of an instruction will also break
  #define DBG_HAS_GET_PROCESSES   0x0000000100000000ULL  ///< supports ev_get_processes
  #define DBG_HAS_ATTACH_PROCESS  0x0000000200000000ULL  ///< supports ev_attach_process
  #define DBG_HAS_DETACH_PROCESS  0x0000000400000000ULL  ///< supports ev_detach_process
  #define DBG_HAS_REQUEST_PAUSE   0x0000000800000000ULL  ///< supports ev_request_pause
  #define DBG_HAS_SET_EXCEPTION_INFO \
                                  0x0000001000000000ULL  ///< supports ev_set_exception_info
  #define DBG_HAS_THREAD_SUSPEND  0x0000002000000000ULL  ///< supports ev_thread_suspend
  #define DBG_HAS_THREAD_CONTINUE 0x0000004000000000ULL  ///< supports ev_thread_continue
  #define DBG_HAS_SET_RESUME_MODE 0x0000008000000000ULL  ///< supports ev_set_resume_mode.
                                                         ///< Cannot be set inside the debugger_t::init_debugger()
  #define DBG_HAS_THREAD_GET_SREG_BASE \
                                  0x0000010000000000ULL  ///< supports ev_thread_get_sreg_base
  #define DBG_HAS_CHECK_BPT       0x0000020000000000ULL  ///< supports ev_check_bpt
  #define DBG_HAS_OPEN_FILE       0x0000040000000000ULL  ///< supports ev_open_file, ev_close_file, ev_read_file, ev_write_file
  #define DBG_HAS_UPDATE_CALL_STACK \
                                  0x0000080000000000ULL  ///< supports ev_update_call_stack
  #define DBG_HAS_APPCALL         0x0000100000000000ULL  ///< supports ev_appcall, ev_cleanup_appcall
  #define DBG_HAS_REXEC           0x0000200000000000ULL  ///< supports ev_rexec
  #define DBG_HAS_MAP_ADDRESS     0x0000400000000000ULL  ///< supports ev_map_address.
                                                         ///< Avoid using this bit, especially together with DBG_FLAG_DEBTHREAD
                                                         ///< because it may cause big slow downs
  ///@}

  bool is_remote() const { return (flags & DBG_FLAG_REMOTE) != 0; }
  bool must_have_hostname() const
    { return (flags & (DBG_FLAG_REMOTE|DBG_FLAG_NOHOST)) == DBG_FLAG_REMOTE; }
  bool can_continue_from_bpt() const
    { return (flags & DBG_FLAG_CAN_CONT_BPT) != 0; }
  bool may_disturb() const
    { return (flags & DBG_FLAG_DONT_DISTURB) == 0; }
  bool is_safe() const
    { return (flags & DBG_FLAG_SAFE) != 0; }
  bool use_sregs() const
    { return (flags & DBG_FLAG_USE_SREGS) != 0; }
  size_t cache_block_size() const
    { return (flags & DBG_FLAG_SMALLBLKS) != 0 ? 256 : 1024; }
  bool use_memregs() const
    { return (flags & DBG_FLAG_MANMEMINFO) != 0; }
  bool may_take_exit_snapshot() const
    { return (flags & DBG_FLAG_EXITSHOTOK) != 0; }
  bool virtual_threads() const
    { return (flags & DBG_FLAG_VIRTHREADS) != 0; }
  bool supports_lowcnds() const
    { return (flags & DBG_FLAG_LOWCNDS) != 0; }
  bool supports_debthread() const
    { return (flags & DBG_FLAG_DEBTHREAD) != 0; }
  bool can_debug_standalone_dlls() const
    { return (flags & DBG_FLAG_DEBUG_DLL) != 0; }
  bool fake_memory() const
    { return (flags & DBG_FLAG_FAKE_MEMORY) != 0; }
  bool is_ttd() const
    { return (flags & DBG_FLAG_TTD) != 0; }

  bool has_get_processes() const
    { return (flags & DBG_HAS_GET_PROCESSES) != 0; }
  bool has_attach_process() const
    { return (flags & DBG_HAS_ATTACH_PROCESS) != 0; }
  bool has_detach_process() const
    { return (flags & DBG_HAS_DETACH_PROCESS) != 0; }
  bool has_request_pause() const
    { return (flags & DBG_HAS_REQUEST_PAUSE) != 0; }
  bool has_set_exception_info() const
    { return (flags & DBG_HAS_SET_EXCEPTION_INFO) != 0; }
  bool has_thread_suspend() const
    { return (flags & DBG_HAS_THREAD_SUSPEND) != 0; }
  bool has_thread_continue() const
    { return (flags & DBG_HAS_THREAD_CONTINUE) != 0; }
  bool has_set_resume_mode() const
    { return (flags & DBG_HAS_SET_RESUME_MODE) != 0; }
  bool has_thread_get_sreg_base() const
    { return (flags & DBG_HAS_THREAD_GET_SREG_BASE) != 0; }
  bool has_check_bpt() const
    { return (flags & DBG_HAS_CHECK_BPT) != 0; }
  bool has_open_file() const
    { return (flags & DBG_HAS_OPEN_FILE) != 0; }
  bool has_update_call_stack() const
    { return (flags & DBG_HAS_UPDATE_CALL_STACK) != 0; }
  bool has_appcall() const
    { return (flags & DBG_HAS_APPCALL) != 0; }
  bool has_rexec() const
    { return (flags & DBG_HAS_REXEC) != 0; }
  bool has_map_address() const
    { return (flags & DBG_HAS_MAP_ADDRESS) != 0; }
  bool has_soft_bpt() const
    { return bpt_bytes != nullptr && bpt_size > 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 nregisters;                            ///< Number of registers

  // A function for accessing the 'registers' array
  inline register_info_t &regs(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
  #define DBG_RESMOD_STEP_BACKINTO  0x0100   ///< ::RESMOD_BACKINTO 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

  /// 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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \param envs              (launch_env_t *) environment variables for debugged process
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 whether the debugger should continue backwards or forwards.
    /// This event is generated in debthread.
    /// Available if \ref DBG_FLAG_TTD is set
    ev_set_backwards,

    /// 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 debuggee process and refreshed the database.
    /// The debugger module may add information to the database if necessary.
    ///
    /// The reason for introducing this event is that when an event like
    /// 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() function.
    /// Only when the kernel has adjusted the database we can do it.
    /// Example: for loaded PE DLLs we can add the exported function
    /// names to the list of debug names (see set_debug_names()).
    ///
    /// 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 nullptr)
    /// \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::nregisters elements
    /// \param errbuf  (::qstring *) may be nullptr
    /// \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 nullptr
    /// \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 nullptr.
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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 == nullptr, 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 nullptr 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 nullptr
    /// \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 nullptr
    /// \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 nullptr
    /// \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,

    /// Ask debuger to send dynamic register set
    /// \param[out] regset    (::dynamic_register_set_t *) dynamic register set
    /// \return ::DRC_OK      REGSET is ready
    /// \retval ::DRC_NETERR, ::DRC_ERROR
    ev_get_dynamic_register_set,

    /// Set debugger options (parameters that are specific to the debugger module).
    /// \param[out] code   (const char **) one of \ref IDPOPT_RET,
    ///                     otherwise a pointer to an error message,
    ///                     may be nullptr
    /// \param keyword     (const char *) keyword encountered in IDA.CFG/user config file.
    ///                    if nullptr, then an interactive dialog form should be displayed
    /// \param pri         (int) option priority, one of \ref IDAOPT_PRIO values
    /// \param value_type  (int) type of value of the keyword - one of \ref IDPOPT_T
    /// \param value       (const void *) pointer to value
    /// \return ::DRC_OK   event is implemented
    /// \return ::DRC_NONE event is not implemented
    /// 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="")
    /// The kernel uses this event with keyword=" " to detect implementation.
    /// This event is optional.
    /// This event is generated in the main thread
    ev_set_dbg_options,
  };

  /// 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)
  #define DBG_NO_ASLR     0x80            ///< disable ASLR (linux)
  ///@}

  /// \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=nullptr);
  inline bool term_debugger();
  inline drc_t get_processes(procinfo_vec_t *procs, qstring *errbuf=nullptr);
  inline drc_t start_process(const char *path,
                             const char *args,
                             launch_env_t *envs,
                             const char *startdir,
                             uint32 dbg_proc_flags,
                             const char *input_path,
                             uint32 input_file_crc32,
                             qstring *errbuf=nullptr);
  inline drc_t attach_process(pid_t pid, int event_id, uint32 dbg_proc_flags, qstring *errbuf=nullptr);
  inline drc_t detach_process(qstring *errbuf=nullptr);
  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=nullptr);
  inline drc_t exit_process(qstring *errbuf=nullptr);
  inline gdecode_t get_debug_event(debug_event_t *event, int timeout_ms);
  inline drc_t resume(const debug_event_t *event, qstring *errbuf=nullptr);
  inline drc_t set_backwards(bool backwards);
  inline void set_exception_info(const exception_info_t *info, int qty);
  inline void suspended(bool dlls_added, thread_name_vec_t *thr_names=nullptr);
  inline drc_t thread_suspend(thid_t tid, qstring *errbuf=nullptr);
  inline drc_t thread_continue(thid_t tid, qstring *errbuf=nullptr);
  inline drc_t set_resume_mode(thid_t tid, resume_mode_t resmod, qstring *errbuf=nullptr);
  inline drc_t read_registers(thid_t tid, int clsmask, regval_t *values, qstring *errbuf=nullptr);
  inline drc_t write_register(thid_t tid, int regidx, const regval_t *value, qstring *errbuf=nullptr);
  inline drc_t thread_get_sreg_base(ea_t *answer, thid_t tid, int sreg_value, qstring *errbuf=nullptr);
  inline drc_t get_memory_info(meminfo_vec_t &ranges, qstring *errbuf=nullptr);
  inline drc_t read_memory(size_t *nbytes, ea_t ea, void *buffer, size_t size, qstring *errbuf=nullptr);
  inline drc_t write_memory(size_t *nbytes, ea_t ea, const void *buffer, size_t size, qstring *errbuf=nullptr);
  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=nullptr);
  inline drc_t update_lowcnds(int *nupdated, const lowcnd_t *lowcnds, int nlowcnds, qstring *errbuf=nullptr);
  inline int open_file(const char *file, uint64 *fsize, bool readonly, qstring *errbuf=nullptr);
  inline void close_file(int fn);
  inline ssize_t read_file(int fn, qoff64_t off, void *buf, size_t size, qstring *errbuf=nullptr);
  inline ssize_t write_file(int fn, qoff64_t off, const void *buf, size_t size, qstring *errbuf=nullptr);
  inline ea_t map_address(ea_t off, const regval_t *regs, int regnum);
  inline const void *get_debmod_extensions();
  inline drc_t 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=nullptr);
  inline drc_t send_ioctl(int fn, const void *buf, size_t size, void **poutbuf, ssize_t *poutsize, qstring *errbuf=nullptr);
  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=nullptr);
  inline bool get_dynamic_register_set(dynamic_register_set_t *regset);
  inline drc_t set_dbg_options(const char **res, const char *keyword, int pri, int value_type, const void *value);
  inline bool have_set_options() const;
};


#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)
#define RQ_BACKINTO (RESMOD_BACKINTO << 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()
{
  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,
        launch_env_t *envs,
        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, envs);
}
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 drc_t debugger_t::set_backwards(bool backwards)
{
  return notify_drc(ev_set_backwards, backwards);
}
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 *ext;
  if ( notify_drc(ev_get_debmod_extensions, &ext) != DRC_OK )
    ext = nullptr;
  return ext;
}
inline drc_t debugger_t::update_call_stack(thid_t tid, call_stack_t *trace)
{
  return notify_drc(ev_update_call_stack, tid, trace);
}
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 != nullptr )
      *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);
}
inline bool debugger_t::get_dynamic_register_set(dynamic_register_set_t *regset)
{
  return notify_drc(ev_get_dynamic_register_set, regset) == DRC_OK;
}
inline drc_t debugger_t::set_dbg_options(const char **res, const char *keyword, int pri, int value_type, const void *value)
{
  return notify_drc(ev_set_dbg_options, res, keyword, pri, value_type, value);
}
inline bool debugger_t::have_set_options() const
{
  return const_cast<debugger_t *>(this)->notify_drc(ev_set_dbg_options, nullptr, " ", 0, 0, nullptr) != DRC_NONE;
}

/// Convert a floating point number in CPU native format to IDA's internal format.
/// \param ieee_out output buffer
/// \param cpu_fpval floating point number in CPU native format
/// \param size size of cpu_fpval in bytes (size of the input buffer)
/// \return \ref REAL_ERROR_
idaman int ida_export cpu2ieee(fpvalue_t *ieee_out, const void *cpu_fpval, int size);

/// Convert a floating point number in IDA's internal format to CPU native format.
/// \param cpu_fpval_out output buffer
/// \param ieee floating point number of IDA's internal format
/// \param size size of cpu_fpval in bytes (size of the output buffer)
/// \return \ref REAL_ERROR_
idaman int ida_export ieee2cpu(void *cpu_fpval_out, const fpvalue_t &ieee, int size);

#endif // _IDD_HPP
