//--------------------------------------------------------------------------
// ObjectWindows                                                          //
// Copyright (c) 1993, 1996 by Borland International
// All Rights Reserved.
// Copyright (c) 1998  by Yura Bidus                                        //
//                                                                        //
//------------------------------------------------------------------------//
 
#include <owl/pch.h>
 
#if defined(BI_COMP_BORLANDC)
#  pragma hdrstop
#endif
 
#if __DEBUG == 2
#  define USE_MEMCHECK
#endif
#ifdef _DEBUG
#  if !defined(USE_MEMCHECK)
#    define USE_MEMCHECK
#  endif
#endif
 
 
#include <owl/private/dumpstack.h>
 
#include <owl/module.h>
#include <owl/template.h>
#include <owl/contain.h>
 
namespace owl {
 
using namespace std;
 
//-----------------------------------------------------------------------------
 
/// \cond NoSuppressDoxygenWarning
# if ((__GNUC__ != 3) || ((__GNUC_MINOR__ != 3) && (__GNUC_MINOR__ != 2)))
#if !defined(_WINTRUST_) && !defined(WINTRUST_H)
#     include <wintrust.h>
#   endif   // !defined(_WINTRUST_) && !defined(WINTRUST_H)
# endif   // ((__GNUC__ != 3) || ((__GNUC_MINOR__ != 3) && (__GNUC_MINOR__ != 2)))
/// \endcond
 
//
// Disable warnings in header "imagehlp.h".
//
#if defined(BI_COMP_MSC)
#pragma warning(push)
#pragma warning(disable:4091) // warning C4091: 'typedef ': ignored on left of '' when no variable is declared
#endif
 
/// \cond NoSuppressDoxygenWarning
#include <imagehlp.h>
/// \endcond
 
#if defined(BI_COMP_MSC)
#pragma warning(pop)
#endif
 
//#pragma comment(lib, "imagehlp.lib")
 
static const tchar imgHlpStr[]                = _T("imagehlp.dll");
static const char SymFunctionTableAccessStr[]  = "SymFunctionTableAccess";
static const char SymGetModuleInfoStr[]        = "SymGetModuleInfo";
static const char SymLoadModuleStr[]          = "SymLoadModule";
static const char SymGetSymFromAddrStr[]      = "SymGetSymFromAddr";
static const char UnDecorateSymbolNameStr[]    = "UnDecorateSymbolName";
static const char SymUnDNameStr[]              = "SymUnDName";
static const char SymInitializeStr[]          = "SymInitialize";
static const char SymGetOptionsStr[]          = "SymGetOptions";
static const char SymSetOptionsStr[]          = "SymSetOptions";
static const char StackWalkStr[]              = "StackWalk";
//static const char Str[]        = "";
//static const char Str[]        = "";
//static const char Str[]        = "";
 
//-----------------------------------------------------------------------------
// class IMAGEHLP
// ~~~~~ ~~~~~~~~
//
// delay loading IMAGEHLP.DLL
class TImageHelp {
  public:
    static  TModule&  GetModule();
 
    //  Environmental
    static  LPVOID  SymFunctionTableAccess(HANDLE hProcess, DWORD  AddrBase);
    static  BOOL    SymGetModuleInfo(HANDLE hProcess, DWORD dwAddr, PIMAGEHLP_MODULE ModuleInfo);
    static  BOOL    SymLoadModule(HANDLE hProcess, HANDLE hFile, PSTR ImageName, PSTR ModuleName, DWORD BaseOfDll, DWORD SizeOfDll);
    static  BOOL    SymGetSymFromAddr(HANDLE hProcess, DWORD dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_SYMBOL Symbol);
    static  DWORD   UnDecorateSymbolName(LPCSTR DecoratedName, LPSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags);
    static  BOOL    SymUnDName(PIMAGEHLP_SYMBOL sym, LPSTR UnDecName, DWORD UnDecNameLength);
    static  BOOL    SymInitialize(HANDLE hProcess, LPSTR UserSearchPath, BOOL fInvadeProcess);
    static  DWORD   SymGetOptions();
    static  DWORD   SymSetOptions(DWORD SymOptions);
    static  BOOL    StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME StackFrame,
                              LPVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
                              PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
                              PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
                              PTRANSLATE_ADDRESS_ROUTINE TranslateAddress);
 
};
//-----------------------------------------------------------------------------
TModule&
TImageHelp::GetModule()
{
  static TModule imgModule(imgHlpStr, true, true, false);
  return imgModule;
}
//-----------------------------------------------------------------------------
#  if defined(BI_COMP_BORLANDC)
#    pragma warn -inl
#  endif
LPVOID TImageHelp::SymFunctionTableAccess(HANDLE p1, DWORD p2)
{
  static TModuleProc2<LPVOID, HANDLE, DWORD>
         symFunctionTableAccess(GetModule(), SymFunctionTableAccessStr);
  return symFunctionTableAccess(p1,p2);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::SymGetModuleInfo(HANDLE p1, DWORD p2, PIMAGEHLP_MODULE p3)
{
  static TModuleProc3<BOOL, HANDLE,DWORD,PIMAGEHLP_MODULE>
         symGetModuleInfo(GetModule(), SymGetModuleInfoStr);
  return symGetModuleInfo(p1,p2,p3);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::SymLoadModule(HANDLE p1, HANDLE p2, PSTR p3,PSTR p4, DWORD p5,
                               DWORD p6)
{
  static TModuleProc6<BOOL,HANDLE,HANDLE,PSTR,PSTR,DWORD, DWORD>
         symLoadModule(GetModule(), SymLoadModuleStr);
  return symLoadModule(p1,p2,p3,p4,p5,p6);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::SymGetSymFromAddr(HANDLE p1, DWORD p2, PDWORD p3,
                                   PIMAGEHLP_SYMBOL p4)
{
  static TModuleProc4<BOOL,HANDLE,DWORD,PDWORD, PIMAGEHLP_SYMBOL>
         symGetSymFromAddr(GetModule(), SymGetSymFromAddrStr);
  return symGetSymFromAddr(p1,p2,p3,p4);
}
//-----------------------------------------------------------------------------
DWORD TImageHelp::UnDecorateSymbolName(LPCSTR p1, LPSTR p2, DWORD p3, DWORD p4)
{
  static TModuleProc4<DWORD,LPCSTR,LPSTR,DWORD,DWORD>
         unDecorateSymbolName(GetModule(), UnDecorateSymbolNameStr);
  return unDecorateSymbolName(p1,p2,p3,p4);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::SymUnDName(PIMAGEHLP_SYMBOL p1, LPSTR p2, DWORD p3)
{
  static TModuleProc3<BOOL,PIMAGEHLP_SYMBOL,LPSTR,DWORD>
         symUnDName(GetModule(), SymUnDNameStr);
  return symUnDName(p1,p2,p3);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::SymInitialize(HANDLE p1, LPSTR p2, BOOL p3)
{
  static TModuleProc3<BOOL,HANDLE,LPSTR,BOOL>
         symInitialize(GetModule(), SymInitializeStr);
  return symInitialize(p1,p2,p3);
}
//-----------------------------------------------------------------------------
DWORD TImageHelp::SymGetOptions()
{
  static TModuleProc0<DWORD>
         symGetOptions(GetModule(), SymGetOptionsStr);
  return symGetOptions();
}
//-----------------------------------------------------------------------------
DWORD TImageHelp::SymSetOptions(DWORD p1)
{
  static TModuleProc1<DWORD,DWORD>
         symSetOptions(GetModule(), SymSetOptionsStr);
  return symSetOptions(p1);
}
//-----------------------------------------------------------------------------
BOOL TImageHelp::StackWalk(DWORD p1, HANDLE p2, HANDLE p3, LPSTACKFRAME p4,
                           LPVOID p5, PREAD_PROCESS_MEMORY_ROUTINE p6,
                           PFUNCTION_TABLE_ACCESS_ROUTINE p7,
                           PGET_MODULE_BASE_ROUTINE p8,
                           PTRANSLATE_ADDRESS_ROUTINE p9)
{
  static TModuleProc9<BOOL,DWORD,HANDLE,HANDLE,LPSTACKFRAME,LPVOID,
                      PREAD_PROCESS_MEMORY_ROUTINE,PFUNCTION_TABLE_ACCESS_ROUTINE,
                      PGET_MODULE_BASE_ROUTINE, PTRANSLATE_ADDRESS_ROUTINE>
         stackWalk(GetModule(), StackWalkStr);
  return stackWalk(p1,p2,p3,p4,p5,p6,p7,p8,p9);
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////////////
// Routine to produce stack dump
#if !defined(UNIX) //JJH we do not need this stuff in unix
static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD dwPCAddress);
static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress);
#endif ///defined(UNIX)
 
#define MODULE_NAME_LEN 64
#define SYMBOL_NAME_LEN 128
 
#if defined(_DEF_DECLARED)
 
#define TRACE_STACK(m)\
  do{\
    if(__OwlDiagGroupDef.IsEnabled()){\
      tostringstream out; out << m;\
      __OwlDiagGroupDef.Trace(out.str().c_str(), 0, __FILE__, __LINE__);\
    }\
  }while(0)
 
#else //no _DEF_DECLARED
  #define TRACE_STACK(m)
#endif //_DEF_DECLARED
 
/// \cond
struct OWL_SYMBOL_INFO{
  DWORD dwAddress;
  DWORD dwOffset;
  CHAR  szModule[MODULE_NAME_LEN];
  CHAR  szSymbol[SYMBOL_NAME_LEN];
};
/// \endcond
 
#if !defined(UNIX) //JJH see OwlDumpStack below...
static LPVOID __stdcall FunctionTableAccess(HANDLE hProcess, DWORD dwPCAddress)
{
  return TImageHelp::SymFunctionTableAccess(hProcess, dwPCAddress);
}
 
static DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress)
{
  IMAGEHLP_MODULE moduleInfo;
 
  if (TImageHelp::SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))
    return moduleInfo.BaseOfImage;
  else{
    MEMORY_BASIC_INFORMATION memoryBasicInfo;
 
    if (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,
        &memoryBasicInfo, sizeof(memoryBasicInfo))){
 
      char szFile[MAX_PATH] = { 0 };
      DWORD cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,
                                    szFile, MAX_PATH);
 
      // Ignore the return code since we can't do anything with it.
      if(!TImageHelp::SymLoadModule(hProcess,NULL, ((cch) ? szFile : NULL),
                       NULL, (DWORD) memoryBasicInfo.AllocationBase, 0)){
        TRACE_STACK(_T("Error: ") << GetLastError());
      }
      return (DWORD) memoryBasicInfo.AllocationBase;
    }
    else{
      TRACE_STACK(_T("Error is ") << GetLastError());
    }
  }
  return 0;
}
 
static BOOL ResolveSymbol(HANDLE hProcess, DWORD dwAddress, OWL_SYMBOL_INFO& siSymbol)
{
  BOOL fRetval = TRUE;
 
  siSymbol.dwAddress = dwAddress;
 
  union __SYMB{
    CHAR rgchSymbol[sizeof(IMAGEHLP_SYMBOL) + 255];
    IMAGEHLP_SYMBOL  sym;
  } u;
 
  CHAR szUndec[256];
  CHAR szWithOffset[256];
  LPCSTR pszSymbol;
  IMAGEHLP_MODULE mi;
 
  memset(&siSymbol, 0, sizeof(OWL_SYMBOL_INFO));
  mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
 
  if (!TImageHelp::SymGetModuleInfo(hProcess, dwAddress, &mi))
    lstrcpyA(siSymbol.szModule, "<no module>");
  else{
    LPSTR pszModule = strchr(mi.ImageName, '\\');
    if (pszModule == NULL)
      pszModule = mi.ImageName;
    else
      pszModule++;
 
    lstrcpynA(siSymbol.szModule, pszModule, COUNTOF(siSymbol.szModule));
    lstrcatA(siSymbol.szModule, "! ");
  }
 
  __try
  {
    u.sym.SizeOfStruct  = sizeof(IMAGEHLP_SYMBOL);
    u.sym.Address        = dwAddress;
    u.sym.MaxNameLength = 255;
 
    if (TImageHelp::SymGetSymFromAddr(hProcess, dwAddress,
                                      &(siSymbol.dwOffset), &u.sym)){
      pszSymbol = u.sym.Name;
      if (TImageHelp::UnDecorateSymbolName(u.sym.Name, szUndec, COUNTOF(szUndec),
                      UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS)){
        pszSymbol = szUndec;
      }
      else if (TImageHelp::SymUnDName(&u.sym, szUndec, COUNTOF(szUndec))){
        pszSymbol = szUndec;
      }
 
      if(siSymbol.dwOffset != 0){
        wsprintfA(szWithOffset, "%s + %d bytes", pszSymbol, siSymbol.dwOffset);
        pszSymbol = szWithOffset;
      }
    }
    else
      pszSymbol = "<no symbol>";
  }
  __except(true) 
  {
    pszSymbol = "<EX: no symbol>";
    siSymbol.dwOffset = dwAddress - mi.BaseOfImage;
  }
 
  lstrcpynA(siSymbol.szSymbol, pszSymbol, COUNTOF(siSymbol.szSymbol));
  return fRetval;
}
 
#endif //if !defined(UNIX)
 
/// \cond
 
class __TTraceClipboardData{
  public:
    __TTraceClipboardData(uint32 target);
    ~__TTraceClipboardData();
    void SendOut(LPCSTR pszData);
  private:
    HGLOBAL  Memory;
    uint32  Size;
    uint32  Used;
    uint32  Target;
 
};
 
__TTraceClipboardData::__TTraceClipboardData(uint32 target)
:
  Memory(0)
  ,Size(0)
  ,Used(0)
  ,Target(target)
{
}
 
__TTraceClipboardData::~__TTraceClipboardData()
{
  if (Memory){
    // chuck it onto the clipboard
    // don't free it unless there's an error
 
    if(!OpenClipboard(NULL))
      GlobalFree(Memory);
    else if (!EmptyClipboard() || SetClipboardData(CF_TEXT, Memory) == NULL){
      GlobalFree(Memory);
    }
    else
      CloseClipboard();
  }
}
 
void __TTraceClipboardData::SendOut(LPCSTR pszData)
{
  int nLength;
  if (pszData == NULL || (nLength = lstrlenA(pszData)) == 0)
    return;
 
  // send it to TRACE (can be redirected)
  if (Target & OWL_STACK_DUMP_TARGET_TRACE){
    TRACE_STACK(pszData);
  }
 
  // send it to OutputDebugString() (can't redirect)
  if (Target & OWL_STACK_DUMP_TARGET_ODS)
    OutputDebugStringA(pszData);
 
  // build a buffer for the clipboard
  if (Target & OWL_STACK_DUMP_TARGET_CLIPBOARD){
    if(!Memory){
       Memory = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1024);
      if(!Memory){
        //TRACE("OwlDumpStack Error: No memory available for clipboard");
        Target &= ~OWL_STACK_DUMP_TARGET_CLIPBOARD;
      }
      else{
        Used = nLength;
        Size = 1024;
        LPSTR pstr = (LPSTR)GlobalLock(Memory);
        if (pstr){
          lstrcpyA(pstr, pszData);
          GlobalUnlock(Memory);
        }
        else{
          //TRACE("OwlDumpStack Error: Couldn't lock memory!");
          GlobalFree(Memory);
          Memory = 0;
          Target &= ~OWL_STACK_DUMP_TARGET_CLIPBOARD;
        }
      }
    }
    else{
      if ((Used + nLength + 1) >= Size){
        // grow by leaps and bounds
        Size *= 2;
        if(Size > (1024L*1024L)){
          //TRACE("OwlDumpStack Error: more than one megabyte on clipboard.");
          Target &= ~OWL_STACK_DUMP_TARGET_CLIPBOARD;
        }
 
        HGLOBAL hMemory = GlobalReAlloc(Memory, Size, GMEM_MOVEABLE);
        if (!hMemory){
          //TRACE(_T("OwlDumpStack Error: Couldn't get ") << Size << _T("bytes!"));
          Target &= ~OWL_STACK_DUMP_TARGET_CLIPBOARD;
        }
        else
          Memory = hMemory;
      }
 
      LPSTR pstr = (LPSTR) GlobalLock(Memory);
      if (pstr){
        lstrcpyA(pstr + Used, pszData);
        Used += nLength;
        GlobalUnlock(Memory);
      }
      else{
        //TRACE("OwlDumpStack Error: Couldn't lock memory!");
        Target &= ~OWL_STACK_DUMP_TARGET_CLIPBOARD;
      }
    }
  }
  return;
}
 
/// \endcond
 
/////////////////////////////////////////////////////////////////////////////
// OwlDumpStack API
_OWLFUNC(void)
OwlDumpStack(uint32 target /* = OWL_STACK_DUMP_TARGET_DEFAULT */)
{
#if !defined(UNIX)
 
  __TTraceClipboardData clipboardData(target);
 
  clipboardData.SendOut("=== begin OwlDumpStack output ===\r\n");
 
  TUint32Array adwAddress;
  HANDLE hProcess = ::GetCurrentProcess();
  if (TImageHelp::SymInitialize(hProcess, NULL, FALSE)){
    // force undecorated names to get params
    DWORD dw = TImageHelp::SymGetOptions();
    dw &= ~SYMOPT_UNDNAME;
    TImageHelp::SymSetOptions(dw);
 
    HANDLE hThread = ::GetCurrentThread();
    CONTEXT threadContext;
 
    threadContext.ContextFlags = CONTEXT_FULL;
 
    if (::GetThreadContext(hThread, &threadContext))
    {
      STACKFRAME stackFrame;
      memset(&stackFrame, 0, sizeof(stackFrame));
      stackFrame.AddrPC.Mode = AddrModeFlat;
 
      DWORD dwMachType;
 
#if defined(_M_IX86)
      dwMachType                  = IMAGE_FILE_MACHINE_I386;
 
      // program counter, stack pointer, and frame pointer
      stackFrame.AddrPC.Offset    = threadContext.Eip;
      stackFrame.AddrStack.Offset = threadContext.Esp;
      stackFrame.AddrStack.Mode   = AddrModeFlat;
      stackFrame.AddrFrame.Offset = threadContext.Ebp;
      stackFrame.AddrFrame.Mode   = AddrModeFlat;
#elif defined(_M_MRX000)
      // only program counter
      dwMachType                  = IMAGE_FILE_MACHINE_R4000;
      stackFrame.AddrPC. Offset    = treadContext.Fir;
#elif defined(_M_ALPHA)
      // only program counter
      dwMachType                  = IMAGE_FILE_MACHINE_ALPHA;
      stackFrame.AddrPC.Offset    = (unsigned long) threadContext.Fir;
#elif defined(_M_PPC)
      // only program counter
      dwMachType                  = IMAGE_FILE_MACHINE_POWERPC;
      stackFrame.AddrPC.Offset    = threadContext.Iar;
#else
#error Unknown Target Machine
#endif
 
      for (int nFrame = 0; nFrame < 1024; nFrame++){
        if (!TImageHelp::StackWalk(dwMachType, hProcess, hProcess,&stackFrame,
             &threadContext, NULL,FunctionTableAccess, GetModuleBase, NULL)){
          break;
        }
        adwAddress.AddAt(stackFrame.AddrPC.Offset, nFrame);
      }
    }
  }
  else{
    DWORD dw = GetLastError();
    char sz[100];
    wsprintfA(sz,
      "OwlDumpStack Error: IMAGEHLP.DLL wasn't found. "
      "GetLastError() returned 0x%8.8X\r\n", dw);
    clipboardData.SendOut(sz);
  }
 
  // dump it out now
  int nAddress;
  int cAddresses = adwAddress.Size();
  for (nAddress = 0; nAddress < cAddresses; nAddress++){
    OWL_SYMBOL_INFO info;
    DWORD dwAddress = adwAddress[nAddress];
 
    char sz[20];
    wsprintfA(sz, "%8.8X: ", dwAddress);
    clipboardData.SendOut(sz);
 
    if (ResolveSymbol(hProcess, dwAddress, info)){
      clipboardData.SendOut(info.szModule);
      clipboardData.SendOut(info.szSymbol);
    }
    else
      clipboardData.SendOut("symbol not found");
    clipboardData.SendOut("\r\n");
  }
 
  clipboardData.SendOut("=== end OwlDumpStack() output ===\r\n");
#endif //(ifdef UNIX)
}
#  if defined(BI_COMP_BORLANDC)
#    pragma warn .inl
#  endif
 
 
} // OWL namespace
/* ========================================================================== */
 

V205 Explicit conversion of pointer type to 32-bit integer type: (DWORD) memoryBasicInfo.AllocationBase

V205 Explicit conversion of pointer type to 32-bit integer type: (DWORD) memoryBasicInfo.AllocationBase

V576 Incorrect format. Consider checking the fourth actual argument of the 'wsprintfA' function. The SIGNED integer type argument is expected.

V811 Decreased performance. Excessive type casting: string -> char * -> string. Consider inspecting first argument of the function Trace.

V811 Decreased performance. Excessive type casting: string -> char * -> string. Consider inspecting first argument of the function Trace.

V811 Decreased performance. Excessive type casting: string -> char * -> string. Consider inspecting first argument of the function Trace.