release debug

// ReleaseTracer.cpp : コンソール アプリケーション用のエントリ ポイントの定義
//

/*
Main Function:
this programe catches the debug events and output the debug info.
this can works even for release version EXE files.
Any suggestion will be welcome.
*/

#include "stdafx.h"
#include "windows.h"
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

struct ExpName { DWORD ExpID; const char* ExpDescription; };
ExpName gExceptions[] =
   { { EXCEPTION_ACCESS_VIOLATION, "Access Violation." }
   , { EXCEPTION_BREAKPOINT, "Breakpoint was encountered" }
   , { EXCEPTION_DATATYPE_MISALIGNMENT, "Misaligned data access." }
   , { EXCEPTION_SINGLE_STEP, "Single-Step Instruction." }
   , { EXCEPTION_ARRAY_BOUNDS_EXCEEDED, "Array Index is Out Of Bounds" }
   , { EXCEPTION_FLT_DENORMAL_OPERAND, "Floating-Point op on Denormal value." }
   , { EXCEPTION_FLT_DIVIDE_BY_ZERO, "Floating-Point Divide by Zero" }
   , { EXCEPTION_FLT_INEXACT_RESULT, "Floating-Point Inexact Result" }
   , { EXCEPTION_FLT_INVALID_OPERATION, "Invalid Floating-Point Operation" }
   , { EXCEPTION_FLT_OVERFLOW, "Floating-Point Overflow" }
   , { EXCEPTION_FLT_STACK_CHECK, "Floating Point Stack Error" }
   , { EXCEPTION_FLT_UNDERFLOW, "Floating-Point Underflow" }
   , { EXCEPTION_INT_DIVIDE_BY_ZERO, "Integer Divide by Zero" }
   , { EXCEPTION_INT_OVERFLOW, "Integer Overflow" }
   , { EXCEPTION_PRIV_INSTRUCTION, "Attempt to execute Private Instruction" }
   , { EXCEPTION_NONCONTINUABLE_EXCEPTION, "Non-Continuable Exception" }
   , { 0x0eedfade, "Language Exception" } // at least this is what my compiler uses
   , { 0, "Unknown Exception" }
   };

const char* getExpDescription(DWORD code)
{
 ExpName* scan = gExceptions;
 while( scan->ExpID && scan->ExpID!=code ) ++scan;
 return scan->ExpDescription;
}

bool getProcessMem(HANDLE hProcess, const void* clientAddr, void* buf, int size)
{
 DWORD nRead;
 return ReadProcessMemory(hProcess, clientAddr, buf, size, &nRead) && nRead==(unsigned)size;
}

string getProcessCString(HANDLE hProcess, bool bUnicode, LPSTR clientAddr, int size=0)
{
 #define MAXSTRINGLEN 4096
 char buf[MAXSTRINGLEN];
 if( size<=0 || size>sizeof(buf)) size = sizeof(buf);
 DWORD nRead;
 if( !clientAddr || !ReadProcessMemory( hProcess, clientAddr, buf, size, &nRead )) return std::string();

 if( bUnicode )//not so good but fast
 {
  nRead /= 2;
  unsigned int i = 0;
  while( i!=nRead){
   buf[i] = buf[2*i];
   if (!buf[i])
   {
    break;
   }
   ++i;
  }
 }
 return buf;
}

int main(int argc, char* argv[])
{
 if(argc<=1) {
  cout<<"Usage:  ReleaseTracer XXX.exe -option(for example: ReleaseTracer Kaikei.exe -d)."<< endl;
  cout<<"Option:"<< endl;
  cout<<"        -d     Trace the DLL loading and unloading event."<< endl;
  cout<<"        -t     Trace the string output event."<< endl;
  cout<<"        -e     Trace the exception event."<< endl;
  return 1;
 }

 cout << "Starting up" << endl;

 LPTSTR lpstrcmd = argv[1];
/*
 LPTSTR lpstrcmd = GetCommandLine();
 while( isspace(*lpstrcmd) ) ++lpstrcmd;
 if( '"' == *lpstrcmd ) {
  do ++lpstrcmd; while( '"' != *lpstrcmd);
  ++lpstrcmd;
 }
 else do ++lpstrcmd; while( ! isspace(*lpstrcmd) );
 while( isspace(*lpstrcmd) ) ++lpstrcmd;
*/
 enum enumTrace {STRING,DLL,EXCEPT};
 enumTrace enumTraceType = STRING;
 if(argc == 3) {
  if(argv[2][1] == 't'||argv[2][1] == 'T') {
   enumTraceType = STRING;
  } else if(argv[2][1] == 'd'||argv[2][1] == 'D') {
   enumTraceType = DLL;
  } else if(argv[2][1] == 'e'||argv[2][1] == 'E') {
   enumTraceType = EXCEPT;
  }
 }

 STARTUPINFO si;
 ::memset(&si,0,sizeof(STARTUPINFO));
 si.cb = sizeof(si);
 ::GetStartupInfo(&si);
 si.cb          = sizeof(si);
 si.dwFlags     = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW;
 si.wShowWindow = SW_SHOWNORMAL;

 PROCESS_INFORMATION pi;
 ::memset(&pi,0,sizeof(PROCESS_INFORMATION));
 BOOL bCreateProcess = ::CreateProcess
                  ( 0, lpstrcmd, 0, 0, false
                  , DEBUG_ONLY_THIS_PROCESS
                  , 0, 0, &si, &pi
                  );

 if( !bCreateProcess ) {
  cout << "Process Launch failed." << endl;
  return -1;
 }

 cout << "Process Launched..." << endl;
 cout << setbase(16);
 int bRet = -1;


 DEBUG_EVENT de;
 while(::WaitForDebugEvent(&de, INFINITE), true )
 {
  bool cont = true;
  switch(de.dwDebugEventCode) {
   case EXCEPTION_DEBUG_EVENT:
    if(enumTraceType == EXCEPT){
     const DWORD xcode = de.u.Exception.ExceptionRecord.ExceptionCode;
     const bool nonCont = EXCEPTION_NONCONTINUABLE == de.u.Exception.ExceptionRecord.ExceptionFlags;
     const bool firstChance = !! de.u.Exception.dwFirstChance;
     cout<< "EXCEPTION " << (nonCont?"noncont":"cont")<<"-"<<(firstChance?"first":"final")
                  <<"@"<<de.u.Exception.ExceptionRecord.ExceptionAddress
                  <<":"<<getExpDescription(de.u.Exception.ExceptionRecord.ExceptionCode)<< endl;
     if( firstChance && xcode!=EXCEPTION_BREAKPOINT )
     cont = false;
     if( xcode == EXCEPTION_NONCONTINUABLE_EXCEPTION )
     {
      cout << "Unexpected error: programe to be terminated" << endl;
      TerminateProcess(pi.hProcess,(UINT)-1);
      bRet = 2;
     }
    }
    break;
     case OUTPUT_DEBUG_STRING_EVENT:
    if(enumTraceType == STRING){
     const OUTPUT_DEBUG_STRING_INFO& si = de.u.DebugString;
     cout << getProcessCString( pi.hProcess, !!si.fUnicode, si.lpDebugStringData, si.nDebugStringLength )
       << std::endl;
    }
    break;
     case CREATE_PROCESS_DEBUG_EVENT:
    {
     cout << "Process Created" << endl;
    }
    break;
     case CREATE_THREAD_DEBUG_EVENT:
    {
     cout << "Thread Created" << endl;
    }
    break;
     case EXIT_THREAD_DEBUG_EVENT:
    {
     cout << "Thread Exit: " << de.u.ExitProcess.dwExitCode << endl;
    }
    break;
     case EXIT_PROCESS_DEBUG_EVENT:
      {
    const DWORD exitValue = de.u.ExitThread.dwExitCode;
     cout << "Process Exit: " << exitValue << endl;
     if(bRet == -1)
     bRet = (exitValue==0) ? 0 : 1;
    }
     break;
     case LOAD_DLL_DEBUG_EVENT:
       if(enumTraceType == DLL)
    {
     LPSTR clientAddr;
     std::string sName;
     if(!!de.u.LoadDll.lpImageName&&getProcessMem(pi.hProcess, de.u.LoadDll.lpImageName, &clientAddr, sizeof(clientAddr))&&!!clientAddr)
      sName = getProcessCString(pi.hProcess, !! de.u.LoadDll.fUnicode , clientAddr, 128 );
     if( sName.empty() )
      sName = "<unknown>";
     cout << "DLL Loaded:  basePointer"<<de.u.LoadDll.lpBaseOfDll << " " <<sName << endl;
    }
    break;
     case UNLOAD_DLL_DEBUG_EVENT:
    if(enumTraceType == DLL)
    {
     cout << "DLL Unloaded: basePointer"<<de.u.LoadDll.lpBaseOfDll << " " <<endl;
    }
    break;
     default:
     cout << "Unknown Event Code: "<<de.dwDebugEventCode << endl;
     };

    if( bRet != -1 )
    break;

       BOOL bContinue = ContinueDebugEvent(de.dwProcessId, de.dwThreadId, cont?DBG_CONTINUE:DBG_EXCEPTION_NOT_HANDLED);
    if( !bContinue ) { cout << "Fail in ContinueDebugEvent"; break; }
   };

 cout << "Result: ";
 switch(bRet) {
  case 0: cout << "OK - Completed normally."; break;
  case 1: cout << "Warn - Non-zero error failure."; break;
  case 2: cout << "Fail - Fatal error,to be exterminated."; break;
  default: cout <<"Unexpected error."; break;
 }
 cout << endl;

 return bRet;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章