/* ----------------------------------------------------------------------------

Copyright (C) Siemens AG 1994-2001 * ALL RIGHTS RESERVED

  This software is protected by the inclusion of the above copyright
  notice. This software may not be provided or otherwise made available
  to, or used by, any other person. No title to or ownership of the
  software is  hereby  transferred.
  The information contained in this document is considered the
  CONFIDENTIAL and PROPRIETARY information of Siemens AG and may
  not be disclosed or discussed with anyone who is not employed by
  Siemens AG, unless the individual / company
  (i) has an express need to know such information, and
  (ii) disclosure of information is subject to the terms of a duly
  executed Confidentiality and Non-Disclosure Agreement between
  Siemens AG and the individual / company.

.AUTHOR        Peter Hagenguth

.FILENAME      mlf_callstack.c

.VERSION       00.01.01

.DATE          2005-06-28

.SHORT_DESCR:  converting a callstack address to a readable text info for memory leakfinder tooling

.SW_COMPONENT: c_mobsim/plugin 

.SW_TYPE       OPERATING SYSTEM

.EXIT_CODES

.CHANGE_CONTROL 
Version  Date        Changed by
         Reason of change
--------------------------------------------------------------------------------
00.01.01 2004-02-11  P. Hagenguth (KLF)
         initial version
------------------------------------------------------------------------------*/

/* -----------------------------------------------------------------------------
    INCLUDES
------------------------------------------------------------------------------*/
#include <global.h>
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "dbghelp.h"

/*----------------------------------------------------------------------------*/
/* globals                                                                    */
/*----------------------------------------------------------------------------*/
BOOL (__stdcall *pSymCleanup) (HANDLE hProcess);
BOOL (__stdcall *pSymGetLineFromAddr) (HANDLE hProcess,DWORD dwAddr,PDWORD pdwDisplacement,PIMAGEHLP_LINE Line);
DWORD (__stdcall *pUnDecorateSymbolName)  (LPCSTR DecoratedName,LPSTR UnDecoratedName,DWORD UndecoratedLength,DWORD Flags);
BOOL (__stdcall *pSymGetSymFromAddr) (HANDLE hProcess,DWORD Address,LPDWORD Displacement,PIMAGEHLP_SYMBOL Symbol);
BOOL (__stdcall *pSymInitialize) (HANDLE hProcess,LPSTR UserSearchPath,BOOL fInvadeProcess);
DWORD (__stdcall *pSymSetOptions) (DWORD SymOptions);
DWORD (__stdcall *pSymGetOptions) (VOID);

#ifndef MAXNAMELENGTH
  #define MAXNAMELENGTH       256
  #endif

char              MLF_strCallstackText[500];
bool              MLF_DbgHelpDLLAlreadyLoaded=FALSE;            // load dll on startup/first run
HANDLE            MLF_ProcessHandle;
HMODULE           MLF_DbgHelpDLL;

/*------------------------------------------------------------------------------------------------*/
/* This function loads the dbghelp.dll and determines all required function pointer               */
/*------------------------------------------------------------------------------------------------*/
static HMODULE LoadDbgHelpDLL (void)
{   HINSTANCE DbgHelpDLL;

    if ((DbgHelpDLL = LoadLibrary ("dbghelp.dll")) == NULL)
    {
        return NULL;
    }

    if ((pSymCleanup = (void*) GetProcAddress (DbgHelpDLL,"SymCleanup")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pSymGetLineFromAddr = (void*) GetProcAddress (DbgHelpDLL,"SymGetLineFromAddr")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pUnDecorateSymbolName = (void*) GetProcAddress (DbgHelpDLL,"UnDecorateSymbolName")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pSymGetSymFromAddr = (void*) GetProcAddress (DbgHelpDLL,"SymGetSymFromAddr")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pSymInitialize = (void*) GetProcAddress (DbgHelpDLL,"SymInitialize")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pSymSetOptions = (void*) GetProcAddress (DbgHelpDLL,"SymSetOptions")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }
    if ((pSymGetOptions = (void*) GetProcAddress (DbgHelpDLL,"SymGetOptions")) == NULL)
    {
        FreeLibrary (DbgHelpDLL);
        return NULL;
    }

    return DbgHelpDLL;
}

//#######################################################################################
//#######################################################################################
//#######################################################################################

char *CallstackConverter(unsigned long address_of_callstack)
  {
  DWORD             displacement,options;
  IMAGEHLP_SYMBOL   *symbol;
  IMAGEHLP_LINE     FileAndLine;
  char              s1[500];
  //
  //
  if (address_of_callstack!=0)
    {
    //
    // load *.dll which has the cleartext inside
    if (MLF_DbgHelpDLLAlreadyLoaded==FALSE)
      {
      if ((MLF_DbgHelpDLL = LoadDbgHelpDLL ()) == NULL)
        {
        strcpy(MLF_strCallstackText,"Could not load 'dbghelp.dll'.");
        return (MLF_strCallstackText);
        }
      //
      MLF_ProcessHandle = GetCurrentProcess ();
      //
      // initialize symbol table options
      options = pSymGetOptions ();
      options &= ~SYMOPT_UNDNAME;
      options |= SYMOPT_LOAD_LINES;
      options |= SYMOPT_OMAP_FIND_NEAREST;
      pSymSetOptions (options);
      //
      // Init ProcessHandle
      if ( pSymInitialize(MLF_ProcessHandle,NULL,TRUE) == FALSE)
        {
        strcpy(MLF_strCallstackText,"Could not MySymInitialize 'dbghelp.dll'.");
        return (MLF_strCallstackText);
        }
      // load it only once
      MLF_DbgHelpDLLAlreadyLoaded=TRUE;
      }
    //
    // initalize symbol information storage
    symbol = (IMAGEHLP_SYMBOL*) malloc( sizeof (IMAGEHLP_SYMBOL) + MAXNAMELENGTH ) ;
    memset (symbol,0,sizeof (IMAGEHLP_SYMBOL) + MAXNAMELENGTH);
    symbol->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
    symbol->MaxNameLength = MAXNAMELENGTH;
    //
    // initalize line information storage
    memset (&FileAndLine,0,sizeof (FileAndLine));
    FileAndLine.SizeOfStruct = sizeof (FileAndLine);
    //
    // get symbol information (procedure) for callstack 
    displacement = 0;
		if (pSymGetSymFromAddr (MLF_ProcessHandle,address_of_callstack,&displacement,symbol))
      pUnDecorateSymbolName (symbol->Name,s1,sizeof (s1),UNDNAME_NAME_ONLY);
    else
      sprintf (s1,"-");
    //
    // get symbol information (file + line) for callstack 
    displacement = 0;
    pSymGetLineFromAddr (MLF_ProcessHandle,address_of_callstack,&displacement,&FileAndLine);
    //
    //
    // build return string (strCallstackText)
    sprintf (MLF_strCallstackText,"Proc: %32s, Line: %5d of file: %s",s1,FileAndLine.LineNumber,FileAndLine.FileName);
    //
    // clean up
    GlobalFree (symbol);
    //
    }
  else//  (address_of_callstack==0)
    {
    // unload dll, and nothing to return
    if (MLF_DbgHelpDLLAlreadyLoaded==TRUE)
      {
      pSymCleanup (MLF_ProcessHandle);
      FreeLibrary (MLF_DbgHelpDLL);
      MLF_DbgHelpDLLAlreadyLoaded=FALSE;
      }
    //
    strcpy(MLF_strCallstackText," ");
    }
  return (MLF_strCallstackText);
  }

//#######################################################################################
