/*

    IDA trace: PIN tool to communicate with IDA's debugger

*/
#ifndef _IDADBG_H
#define _IDADBG_H

#include <vector>

using namespace std;

typedef unsigned int uint32;
typedef unsigned char uchar;

#define PIN_PROTOCOL_VERSION 1

#ifdef IDA_SDK_VERSION
// IDA specific declarations
#   define pin_strncpy  ::qstrncpy
#   define pin_snprintf ::qsnprintf
#   define addr_t         ea_t
#   define pin_thid       thid_t
#   define pin_size_t     size_t
#   define pin_pid_t      pid_t
#   define pin_event_id_t event_id_t
#   define pin_bpttype_t  bpttype_t
#ifdef __EA64__
#   define BITNESS 2
#   define PIN_64
#else
#   define BITNESS 1
#endif
#ifdef __X64__
#   define PIN_64
#endif
#else
// PIN specific declarations
#   define pin_strncpy  strncpy
#   define pin_snprintf snprintf
#   define addr_t ADDRINT
#   define ea_t addr_t
#   define pin_thid THREADID
#   define pin_size_t uint32
#   define pin_pid_t  uint32
#   define MAXSTR 1024
#   define BADADDR -1
#ifdef TARGET_IA32
#   define BITNESS    1
#   define HEX_FMT    "%x"
#   define HEX64_FMT  "%llx"
#   define HEX64T_FMT "%llux"
#else
#   define BITNESS   2
#   define PIN_64    1
#   define HEX_FMT   "%lx"
#   define HEX64_FMT "%llx"
#   define HEX64T_FMT "%lux"
#endif

// structures and definitions copied from IDA SDK (idd.hpp)

#define SEGPERM_EXEC  1 // Execute
#define SEGPERM_WRITE 2 // Write
#define SEGPERM_READ  4 // Read

enum pin_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_START  = 0x00000001, // New process has been started.
  PROCESS_EXIT   = 0x00000002, // Process has been stopped.
  THREAD_START   = 0x00000004, // New thread has been started.
  THREAD_EXIT    = 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.
  LIBRARY_LOAD   = 0x00000080, // New library has been loaded.
  LIBRARY_UNLOAD = 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.
  _SYSCALL       = 0x00000400, // Syscall (not used yet).
  WINMESSAGE     = 0x00000800, // Window message (not used yet).
  PROCESS_ATTACH = 0x00001000, // Successfully attached to running process.
  PROCESS_DETACH = 0x00002000, // Successfully detached from process.
  PROCESS_SUSPEND= 0x00004000, // 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     = 0x00008000, // The trace being recorded is full.
};

// Trace event types:
enum pin_tev_type_t
{
  tev_none = 0, // no event
  tev_insn,     // an instruction trace
  tev_call,     // a function call trace
  tev_ret,      // a function return trace
  tev_bpt,      // write, read/write, execution trace
  tev_mem,      // memory layout changed
  tev_event,    // debug event occurred
  tev_trace,    // a trace event (used for tracers like PIN)
  tev_max,      // first unused event type
};

// Hardware breakpoint types. Fire the breakpoint upon:
typedef int bpttype_t;
const bpttype_t
  BPT_OLD_EXEC = 0,             // (obsolute: execute instruction)
  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

#endif

//--------------------------------------------------------------------------
#pragma pack(push, 1)

struct pin_module_info_t
{
  char name[MAXSTR];    // full name of the module.
  ea_t base;            // module base address. if unknown pass BADADDR
  pin_size_t size;      // module size. if unknown pass 0
  ea_t rebase_to;       // if not BADADDR, then rebase the program to the specified address
};

struct pin_e_breakpoint_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.
};

struct pin_e_exception_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
  char info[MAXSTR];    // Exception message
};

//--------------------------------------------------------------------------
struct pin_debug_event_t
{
  pin_debug_event_t(void) : eid(NO_EVENT) {}
                           // The following fields must be filled for all events:
  uint32    eid;           // Event code (used to decipher 'info' union)
  pin_pid_t pid;           // Process where the event occured
  pin_thid tid;            // Thread where the event occured
  ea_t ea;                 // Address where the event occured
  bool handled;            // Is event handled by the debugger?
                           // (from the system's point of view)
                           // Meaningful for EXCEPTION events
  union
  {
    pin_module_info_t modinfo; // PROCESS_START, PROCESS_ATTACH, LIBRARY_LOAD
    int exit_code;             // PROCESS_EXIT, THREAD_EXIT
    char info[MAXSTR];         // LIBRARY_UNLOAD (unloaded library name)
                               // INFORMATION (will be displayed in the
                               //              messages window if not empty)
    pin_e_breakpoint_t bpt;    // BREAKPOINT
    pin_e_exception_t exc;     // EXCEPTION
  };
};

//--------------------------------------------------------------------------
enum packet_type_t
{
  PTT_ACK = 0,
  PTT_ERROR,
  PTT_HELLO,
  PTT_EXIT_PROCESS,
  PTT_START_PROCESS,
  PTT_DEBUG_EVENT,
  PTT_READ_EVENT,
  PTT_MEMORY_INFO,
  PTT_READ_MEMORY,
  PTT_DETACH,
  PTT_COUNT_TRACE,
  PTT_READ_TRACE,
  PTT_CLEAR_TRACE,
  PTT_PAUSE,
  PTT_RESUME,
  PTT_RESUME_START,
  PTT_ADD_BPT,
  PTT_DEL_BPT,
  PTT_RESUME_BPT,
  PTT_CAN_READ_REGS,
  PTT_READ_REGS,
  PTT_SET_TRACE,
  PTT_SET_OPTIONS,
  PTT_END
};

//--------------------------------------------------------------------------
struct idapin_packet_t
{
  packet_type_t code;
  pin_size_t size;
  addr_t data;

  idapin_packet_t() : code(PTT_ACK), size(0), data(BADADDR)
  {
  }
};

//--------------------------------------------------------------------------
struct memimages_pkt_t
{
  packet_type_t code;
  pin_size_t size;
  
  memimages_pkt_t(packet_type_t _code, pin_size_t _size) : code(_code), size(_size)
  {
  }
  
  memimages_pkt_t() : code(PTT_ACK), size(0)
  {
  }
};

//--------------------------------------------------------------------------
struct pin_memory_info_t
{
  ea_t   startEA;
  ea_t   endEA;
  pin_size_t name_size;            // Size of the memory area name
  char   name[MAXSTR];         // Memory area name
  uchar  bitness;              // Number of bits in segment addresses (0-16bit, 1-32bit, 2-64bit)
  uchar  perm;                 // Memory area permissions (0-no information): see segment.hpp
};
typedef vector<pin_memory_info_t> pin_meminfo_vec_t;

//--------------------------------------------------------------------------

enum mem_actions_t
{
  MA_READ=0,
  MA_WRITE
};

struct idamem_packet_t
{
  mem_actions_t action;               // 0-Read, 1-Write
  ea_t address;
  pin_size_t size;
};

#define MEM_CHUNK_SIZE 1024
struct idamem_response_pkt_t
{
  packet_type_t code;
  pin_size_t size;
  unsigned char buf[MEM_CHUNK_SIZE];
};

#define TRACE_EVENTS_SIZE 1000

struct idapin_registers_t
{
  addr_t eax;
  addr_t ebx;
  addr_t ecx;
  addr_t edx;
  addr_t esi;
  addr_t edi;
  addr_t ebp;
  addr_t esp;
  addr_t eip;
#if defined(PIN_64)
  addr_t r8;
  addr_t r9;
  addr_t r10;
  addr_t r11;
  addr_t r12;
  addr_t r13;
  addr_t r14;
  addr_t r15;
#endif
  addr_t eflags;
  addr_t cs;
  addr_t ds;
  addr_t es;
  addr_t fs;
  addr_t gs;
  addr_t ss;
};

struct idatrace_data_t
{
  addr_t   ea;
  pin_thid tid;
  uint32   type;
  idapin_registers_t registers;
};

struct idatrace_events_t
{
  packet_type_t code;
  pin_size_t size;
  idatrace_data_t trace[TRACE_EVENTS_SIZE];
};

struct idabpt_packet_t
{
  bpttype_t type;
  addr_t ea;
  pin_size_t size;
};

// we don't really need it to be an enum
enum trace_flags_t
{
  TF_TRACE_STEP     = 0x01,
  TF_TRACE_INSN     = 0x02,
  TF_TRACE_BBLOCK   = 0x04,
  TF_TRACE_ROUTINE  = 0x08,
  TF_REGISTERS      = 0x10
};

struct idalimits_packet_t
{
  // name (and possibly path) of the image to trace, '\0' if we want to
  // trace everything (library calls, etc...)
  char image_name[MAXSTR];
  // maximum number of tevs to enqueue
  uint32 trace_limit;
  // bytes of memory to save if enabled
  pin_size_t bytes;
  // only record new instructions?
  bool only_new;
};

#pragma pack(pop)

#endif
