/* ====================================================================
 * Copyright (c) 2003-2006, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "Stacktrace.h"
#include "StackWalk.h"
#include "StdException.h"
#include "util/apr.h"

// apr
#include <apr_time.h>
#include <apr_strings.h>
#include <apr_file_io.h>

// sys
#include <windows.h>
#include <eh.h>
#include <dbghelp.h>


// exception handler
void __cdecl handleException( unsigned int e, EXCEPTION_POINTERS* pExp )
{
  sc::String dump( "no dump" );

  if( true/*Stacktrace::getDump()*/ )
  {
    apr::Pool  pool;
    apr_time_t   now     = apr_time_now();
    char*        nowstr  = apr_psprintf( pool, "%" APR_TIME_T_FMT, now );
    const char*  tempdir = 0;
    apr_status_t status  = apr_temp_dir_get( &tempdir, pool );
    char*        tempout = apr_pstrcat( pool, tempdir, "\\sc-", nowstr, ".dmp", 0 );

    HANDLE file = CreateFile( tempout, FILE_ALL_ACCESS, 0, 0, CREATE_ALWAYS,
      FILE_ATTRIBUTE_NORMAL, 0 );

    if( file != INVALID_HANDLE_VALUE )
    {
      MINIDUMP_EXCEPTION_INFORMATION mee;
      mee.ThreadId          = GetCurrentThreadId();
      mee.ExceptionPointers = pExp;
      mee.ClientPointers    = TRUE;

      BOOL success = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
        file, (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithoutOptionalData |
        MiniDumpWithProcessThreadData), &mee, 0, 0 );

      // get a clean path without ~ parts.
      char buf[1025] = {};
      GetLongPathName( tempout, buf, 1024 );
      dump = buf;

      CloseHandle(file);
    }
  }

  Stackwalk stack(pExp);
  stack.walk();

  throw StdException(e,stack.getFrames(),dump);
}


// member
bool Stacktrace::_dump = false;


void Stacktrace::setupProcess()
{
  SymSetOptions(
    SYMOPT_IGNORE_NT_SYMPATH
    | SYMOPT_AUTO_PUBLICS
    | SYMOPT_CASE_INSENSITIVE
    | SYMOPT_DEFERRED_LOADS
    | SYMOPT_LOAD_LINES
    | SYMOPT_UNDNAME
    );

  if( ! SymInitialize( GetCurrentProcess(),0,true) )
  {
    // error handling?
  }

  setupThread();
}

void Stacktrace::shutdownProcess()
{
  if( ! SymCleanup(GetCurrentProcess()) )
  {
    // error handling?
  }

  shutdownThread();
}

void Stacktrace::setupThread()
{
  _set_se_translator(handleException);
}

void Stacktrace::shutdownThread()
{
   _set_se_translator(0);
}

void Stacktrace::setDump( bool dump )
{
  _dump = dump;
}

bool Stacktrace::getDump()
{
  return _dump;
}


syntax highlighted by Code2HTML, v. 0.9.1