2005/5/9

     
 

core_winimage.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/sys/core_winimage.cpp,v 1.21 2005/04/28 15:02:26 kommer Exp $
#include "../../Config.h"
#include "../../Platform.h"

#if defined(ACDK_OS_WIN32) && !defined(ACDK_OS_CYGWIN32)
#include "core_winimage.h"
#endif
/FONT>
#include <algorithm>
#include <string.h>
#if defined(ACDK_OS_WIN32) && !defined(ACDK_OS_CYGWIN32)


#include <acdk.h>

//#include <algorithm>
namespace acdk {
namespace lang {
namespace sys {

//#define ACDK_USE_PURIFY

core_winimage::core_winimage() throw()
: inited(false)
{
   inited = initLib();
}

core_winimage::~core_winimage() throw()
{
}

bool core_winimage::initLib()
{
#if defined(ACDK_USE_PURIFY)
  return false;
#endif
/FONT>
  HMODULE hModImagehlp = LoadLibrary(_T("IMAGEHLP.DLL"));
  
  if ( !hModImagehlp )        
    return false;
  
  _SymInitialize = (SYMINITIALIZEPROC)GetProcAddress( hModImagehlp,
    "SymInitialize" );
  if ( !_SymInitialize )        
    return false;
  _SymCleanup = (SYMCLEANUPPROC)GetProcAddress( hModImagehlp, "SymCleanup" );
  if ( !_SymCleanup )        
    return false;
  _StackWalk = (STACKWALKPROC)GetProcAddress( hModImagehlp, "StackWalk" );
  if ( !_StackWalk )        
    return false;
  _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC)
    GetProcAddress( hModImagehlp, "SymFunctionTableAccess" );
  if ( !_SymFunctionTableAccess )        
    return false;
  _SymGetModuleBase=(SYMGETMODULEBASEPROC)GetProcAddress( hModImagehlp,
    "SymGetModuleBase");
  if ( !_SymGetModuleBase )
    return false;
  _SymGetSymFromAddr=(SYMGETSYMFROMADDRPROC)GetProcAddress( hModImagehlp,
    "SymGetSymFromAddr" );
  if ( !_SymGetSymFromAddr )        
    return false;
  
  _SymGetOptions = (SYMGETOPTIONSPROC)GetProcAddress( hModImagehlp,
    "SymGetOptions");
  if ( !_SymGetOptions )
    return false;
  
  _SymSetOptions = (SYMSETOPTIONSPROC)GetProcAddress( hModImagehlp,
    "SymSetOptions");
  if ( !_SymSetOptions )
    return false;
  
  _UnDecorateSymbolName = (UNDECORATESYMBOLNAME)GetProcAddress( hModImagehlp,
    "UnDecorateSymbolName");
  if ( !_UnDecorateSymbolName )
    return false;
  _SymGetLineFromAddr = (SYMGETLINEFROMADDR)GetProcAddress( hModImagehlp, "SymGetLineFromAddr");
  if ( !_SymGetLineFromAddr)
    return false;
  const size_t TTBUFLEN = 4096;
  TCHAR *tt = new TCHAR[TTBUFLEN]; // this is a _sample_. you can do the error checking yourself.
  StringBuffer symSearchPath;
  if (GetCurrentDirectory(TTBUFLEN, tt )) 
  {
    symSearchPath.append(tt);
    symSearchPath.append(";");
  }
  

  if (GetModuleFileName( 0, tt, TTBUFLEN)) 
  {
    TCHAR *p;
    for ( p = tt + tstrlen( tt ) - 1; p >= tt; -- p )
    {
      if ( *p == '\\' || *p == '/' || *p == ':' )
        break;
    }
    if ( p != tt ){ 
      if ( *p == ':' )
        ++ p;
      *p = '\0';
      symSearchPath.append(tt);symSearchPath.append(";");
    }
  }
  
  
  if (GetEnvironmentVariable( _T("_NT_SYMBOL_PATH"), tt, TTBUFLEN)) 
  {
    symSearchPath.append(tt); symSearchPath.append(";");
  }

  
  if (GetEnvironmentVariable( _T("_NT_ALTERNATE_SYMBOL_PATH"), tt, TTBUFLEN)) 
  {
    symSearchPath.append(tt); symSearchPath.append(";");
  }
  

  if (GetEnvironmentVariable( _T("SYSTEMROOT"), tt, TTBUFLEN)) 
  {
    symSearchPath.append(tt); symSearchPath.append(";");
  }
  
  if (symSearchPath.length() > 0)
    symSearchPath = symSearchPath.substring(0, symSearchPath.length() - 1);
  
  
  RString nsmp = symSearchPath.toString()->convert(CCAscii);
  //printf("symbol search path: %s\n", tt);
  bool symInitialized = _SymInitialize( GetCurrentProcess(), (char*)nsmp->c_str(), TRUE ) != 0 ? true : false;;
  delete[] tt;
  
  if( ! symInitialized )
    return false;
  
  DWORD symOptions = _SymGetOptions();
  symOptions &= ~SYMOPT_UNDNAME;
  _SymSetOptions( symOptions );
  
  return true;        
}

bool core_winimage::initStackWalk(CONTEXT *context, 
                                 STACKFRAME *stack, 
                                 bool determineContext)
{
  if (inited == false)
    return false;
        HANDLE ht = GetCurrentThread();
        memset(stack, 0, sizeof(STACKFRAME));

   if(determineContext) 
   {
      context->ContextFlags = CONTEXT_FULL; 
      if (GetThreadContext(ht, context) == FALSE)
         return false; 
   }

   stack->AddrPC.Offset       = context->Eip;
   stack->AddrPC.Mode         = AddrModeFlat;
   stack->AddrStack.Offset    = context->Esp;
   stack->AddrStack.Mode      = AddrModeFlat;
   stack->AddrFrame.Offset    = context->Ebp;
   stack->AddrFrame.Mode      = AddrModeFlat;

   return true;
}

bool core_winimage::stackWalk(CONTEXT *context, STACKFRAME *stack)
{
  if (inited == false)
    return false;

  stack->AddrPC.Offset = 0;
  HANDLE hp = GetCurrentProcess();
  HANDLE ht = GetCurrentThread();

   bool ret = _StackWalk(IMAGE_FILE_MACHINE_I386, 
                         hp,
                         ht,
                         stack,
                         context,
                         NULL,
                         _SymFunctionTableAccess,
                         _SymGetModuleBase,
                         NULL) == TRUE;
  /*
   if (ret == false) 
   {

     LPVOID lpMsgBuf;
     DWORD le = GetLastError();
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                  NULL,
                  le,
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                  (LPTSTR) &lpMsgBuf, 0, NULL );
    
      printf("GetLastError() = %d = %s\n", le, (char*)lpMsgBuf);
      LocalFree( lpMsgBuf );
   }
   */
   return ret;
}



void
core_winimage::getFallbackInfo(void *addr, core_winimage::FallbackInfoResult& res)
{
  DWORD section = 0;
  DWORD offset = 0;
  TCHAR szModule[MAX_PATH];
  szModule[0] = 0;
  GetLogicalAddress(addr, szModule, sizeof(szModule), section, offset );
  String s((uc2char*)szModule);
   int idx = s.lastIndexOf('\\');
   if(idx >= 0 && idx < s.length())  {
      idx++;
   } else {
      idx = 0;
   }

   res.module = new String((uc2char*)&szModule[idx]);
   res.section = section;
   res.offset = offset;
}

core_winimage::SymbolResult 
core_winimage::getSymbol(void *addr)
{
   
   BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + SymbolMaxLength];
   memset(symbolBuffer, 0, sizeof(symbolBuffer));

   
   PIMAGEHLP_SYMBOL pSymbol = reinterpret_cast<PIMAGEHLP_SYMBOL>(symbolBuffer);
   pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
   pSymbol->MaxNameLength = SymbolMaxLength;                        
   
   DWORD symDisplacement = 0;  // Displacement of the input address,
   
   if ( _SymGetSymFromAddr(GetCurrentProcess(), 
                           reinterpret_cast<DWORD>(addr),
                           &symDisplacement, 
                           pSymbol) ) {
      SymbolResult res;
      res.result = true;
      
      char buf[4096];
      if(_UnDecorateSymbolName( pSymbol->Name, buf, sizeof(buf), 
                                UNDNAME_COMPLETE | UNDNAME_32_BIT_DECODE)) {
         res.symbol = SCS(buf);
      } else  {
         res.symbol = SCS(pSymbol->Name);
      }
      res.displacement = symDisplacement;
      return res;
   } else {
      SymbolResult res;
      res.result = false;
      return res;
   }
}

bool core_winimage::GetLogicalAddress(PVOID addr, 
                                     PTSTR szModule, 
                                     DWORD len, 
                                     DWORD& section, 
                                     DWORD& offset)
{
   
   MEMORY_BASIC_INFORMATION mbi;

   if (!VirtualQuery( addr, &mbi, sizeof(mbi)))
      return false;

   DWORD hMod = (DWORD)mbi.AllocationBase;
   if (!GetModuleFileName( (HMODULE)hMod, szModule, len ))
      return false;    

   PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
   
   
   PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
   PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr );
   DWORD rva = (DWORD)addr - hMod; 
   
   for ( unsigned i = 0; i < pNtHdr->FileHeader.NumberOfSections; i++, pSection++ )    
   {
      DWORD sectionStart = pSection->VirtualAddress;
      DWORD sectionEnd = sectionStart + 
        (pSection->SizeOfRawData < pSection->Misc.VirtualSize ? pSection->Misc.VirtualSize : pSection->SizeOfRawData);
      if ((rva >= sectionStart) && (rva <= sectionEnd)) {
         offset = rva - sectionStart;            
         return true;        
      }    
   }
   return false;   
}

class ToolHelp32Wrapper
{
  
};

bool 
core_winimage::getSourceLine(void* ptr, OUT(RString) source, OUT(int) line)
{

  IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
  DWORD dwLineDisplacement;
  if (_SymGetLineFromAddr(GetCurrentProcess(), (unsigned long)ptr,&dwLineDisplacement, &lineInfo ))
  {
    source = SCS(lineInfo.FileName);
    line = lineInfo.LineNumber;
    return true;
  }
  return false;
}

} // namespace sys 
} // namespace lang 
} // namespace acdk 

#endif