#include <loader.hpp>

//--------------------------------------------------------------------------
static int idaapi start_process(const char *path,
                                const char *args,
                                const char *startdir,
                                ulong input_file_crc32)
{
  // check that the host application has been specified
  if ( is_dll && strcmp(path, get_input_file_path()) == 0 )
  {
    warning("AUTOHIDE NONE\n"
            "Please specify the host application first (Debugger, Process options)");
    return 0;
  }
  bool is_gui = callui(ui_get_hwnd).vptr != NULL;
  return r_start_process(path, args, startdir, is_gui, input_file_crc32);
}

//--------------------------------------------------------------------------
static void idaapi stopped_at_debug_event(const debug_event_t *event, bool dlls_added)
{
  if ( dlls_added )
    r_stopped_at_debug_event(event);
}

//--------------------------------------------------------------------------
static bool idaapi init_debugger(const char *hostname, int port_num, const char *password)
{
  if ( !open_remote(hostname, port_num, password) )
    return false;
  fix_exception_table(inf.beginEA);
  int code = r_init(is_dll,
                    (debug & IDA_DEBUG_DEBUGGER) != 0,
                    inf.beginEA,
                    is_temp_database() ? "" : get_input_file_path());
  if ( code < 0 )
  {
    close_remote();
    return false;
  }
  debugger.process_get_info = (code & 1) ? r_process_get_info : NULL;
  debugger.detach_process   = (code & 2) ? r_detach_process : NULL;
  inited = true;
  return true;
}

//--------------------------------------------------------------------------
static bool idaapi term_debugger(void)
{
  if ( inited )
  {
    inited = false;
    return close_remote();
  }
  return false;
}

//--------------------------------------------------------------------------
// Initialize debugger plugin
static int idaapi init(void)
{
  if ( init_plugin() )
  {
    dbg = &debugger;
    return PLUGIN_KEEP;
  }
  return PLUGIN_SKIP;
}

//--------------------------------------------------------------------------
// Terminate debugger plugin
static void idaapi term(void)
{
  if ( inited )
    r_term();
}

//--------------------------------------------------------------------------
// The plugin method - is not used for debugger plugins
static void idaapi run(int /*arg*/)
{
}

//--------------------------------------------------------------------------
//
//      DEBUGGER DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------

debugger_t debugger =
{
  IDD_INTERFACE_VERSION,
  DEBUGGER_NAME,
  DEBUGGER_ID,
  DEBUGGER_FLAGS,

  register_classes,
  RC_GENERAL,
  registers,
  qnumber(registers),

  MEMORY_PAGE_SIZE,

  debug_instruction,
  qnumber(debug_instruction),

  init_debugger,
  term_debugger,

  NULL, // process_get_info: patched at runtime if ToolHelp functions are available
  start_process,
  r_attach_process,
  NULL, // detach_process:   patched at runtime if Windows XP/2K3
  rebase_if_required_to,
  r_prepare_to_pause_process,
  r_exit_process,

  r_get_debug_event,
  r_continue_after_event,
  r_set_exception_info,
  stopped_at_debug_event,

  r_thread_suspend,
  r_thread_continue,
  r_thread_set_step,
  thread_read_registers,
  thread_write_register,
  r_thread_get_sreg_base,

  r_get_memory_info,
  r_read_memory,
  r_write_memory,

  is_ok_bpt,
  add_bpt,
  r_del_bpt,
#ifdef REMOTE_DEBUGGER
  rpc_open_file,
  rpc_close_file,
  rpc_read_file,
#endif
};

//--------------------------------------------------------------------------
//
//      PLUGIN DESCRIPTION BLOCK
//
//--------------------------------------------------------------------------
plugin_t PLUGIN =
{
  IDP_INTERFACE_VERSION,
  PLUGIN_HIDE|PLUGIN_DBG, // plugin flags

  init,                 // initialize

  term,                 // terminate. this pointer may be NULL.

  run,                  // invoke plugin

  comment,              // long comment about the plugin
                        // it could appear in the status line
                        // or as a hint

  help,                 // multiline help about the plugin

  wanted_name,          // the preferred short name of the plugin
  ""                    // the preferred hotkey to run the plugin
};
