Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem when using dbghelp.dll

1,667 views
Skip to first unread message

Ken Chen

unread,
Nov 12, 2007, 11:59:15 AM11/12/07
to
Hi,

I have hard time to use the functions in dbghelp.dll. Not sure if it is good place to put question.

I copy a sample from debuginfo.com, but i never get the code running correctly.

SymInitialize and SymLoadModule64 return correctly, but "SymGetModuleInfo64" Always return error ( the GetLastError() retun 87 The parameter is incorrect).
As soon as I change it to "SymGetModuleInfo" ,  it seems work. As document said SymGetModuleInfo64 is a supercede version of SymGetModuleInfo and SymGetModuleInfo only pass to SymGetModuleInfo64. I don't understand why it happens like that.
Furthermore, i never succeed to use "SymFromName" or other getsymbol functions . it always return error code 126 (The specified module could not be found)
I am using winxp sp2 and tried dbghelp5.1 and dbghelp 6.8.4.0. 
Does anyone have any clue or know why it happens like it? Thanks alot for any answer. I am attaching the source code here. ( i set the debug parameter of the programe to as 1st parameter to the path of my exe file and 2nd parameter to "ShowSymbolInfo".

thanks for help!

Ken.
 

///////////////////////////////////////////////////////////////////////////////

//

// SymFromName.cpp

//

// Author: Oleg Starodumov

//

//

 

///////////////////////////////////////////////////////////////////////////////

//

// Description:

//

// This example looks up a symbol by name and displays some simple information

// about it.

//

// This example shows how to:

//

// * Define _NO_CVCONST_H to be able to use various non-default declarations

// from DbgHelp.h (e.g. SymTagEnum enumeration)

// * Initialize DbgHelp

// * Load symbols for a module or from a .PDB file

// * Check what kind of symbols is loaded

// * Look up a symbol by name (supplied by the user)

// * Display simple information about the symbol

// * Unload symbols

// * Deinitialize DbgHelp

//

// Actions:

//

// * Enable debug option

// * Initialize DbgHelp

// * If symbols should be loaded from a .PDB file, determine its size

// * Load symbols

// * Obtain and display information about loaded symbols

// * Look up a symbol by name

// * Display simple information about the symbol

// * Unload symbols

// * Deinitialize DbgHelp

//

// Command line parameters:

//

// * Path to the module you want to load symbols for,

// or to a .PDB file to load the symbols from

// * Name of the symbol to search for

//

 

///////////////////////////////////////////////////////////////////////////////

// Include files

//

#include

"stdafx.h"

#include

<windows.h>

#include

<tchar.h>

// Now we have to define _NO_CVCONST_H to be able to access

// various declarations from DbgHelp.h, which are not available by default

#define

_NO_CVCONST_H

#include

<dbghelp.h>

#include

<stdio.h>

 

///////////////////////////////////////////////////////////////////////////////

// Directives

//

#pragma

comment( lib, "dbghelp.lib" )

 

///////////////////////////////////////////////////////////////////////////////

// Declarations

//

bool

GetFileParams( const TCHAR* pFileName, DWORD64& BaseAddr, DWORD& FileSize );

bool

GetFileSize( const TCHAR* pFileName, DWORD& FileSize );

void

ShowSymbolInfo( DWORD64 ModBase );

void

ShowSymbolDetails( SYMBOL_INFO& SymInfo );

const

TCHAR* TagStr( ULONG Tag );

 

///////////////////////////////////////////////////////////////////////////////

// CSymbolInfoPackage class declaration

//

// Wrapper for SYMBOL_INFO_PACKAGE structure

//

struct

CSymbolInfoPackage : public SYMBOL_INFO_PACKAGE

{

CSymbolInfoPackage()

{

si.SizeOfStruct = sizeof(SYMBOL_INFO);

si.MaxNameLen = sizeof(name);

}

};

 

///////////////////////////////////////////////////////////////////////////////

// main

//

int

_tmain( int argc, const TCHAR* argv[] )

{

BOOL bRet = FALSE;

 

// Check command line parameters

if( argc < 3 )

{

_tprintf( _T("Usage: %s <FilePathAndName> <SymbolName> \n"), argv[0] );

return 0;

}

const TCHAR* pSymName = argv[2];

 

// Set options

DWORD Options = SymGetOptions();

// SYMOPT_DEBUG option asks DbgHelp to print additional troubleshooting

// messages to debug output - use the debugger's Debug Output window

// to view the messages

Options |= SYMOPT_DEBUG;

::

SymSetOptions( Options );

 

// Initialize DbgHelp and load symbols for all modules of the current process

bRet = ::SymInitialize (

GetCurrentProcess(), // Process handle of the current process

NULL, // No user-defined search path -> use default

FALSE // Do not load symbols for modules in the current process

);

if( !bRet )

{

_tprintf(_T("Error: SymInitialize() failed. Error code: %u \n"), ::GetLastError());

return 0;

}

 

do

{

// Determine the base address and the file size

const TCHAR* pFileName = argv[1];

DWORD64 BaseAddr = 0;

DWORD FileSize = 0;

if( !GetFileParams( pFileName, BaseAddr, FileSize ) )

{

_tprintf( _T("Error: Cannot obtain file parameters (internal error).\n") );

break;

}

 

// Load symbols for the module

_tprintf( _T("Loading symbols for: %s ... \n"), pFileName );

DWORD64 ModBase = ::SymLoadModule64 (

GetCurrentProcess(), // Process handle of the current process

NULL, // Handle to the module's image file (not needed)

pFileName, // Path/name of the file

NULL, // User-defined short name of the module (it can be NULL)

BaseAddr, // Base address of the module (cannot be NULL if .PDB file is used, otherwise it can be NULL)

FileSize // Size of the file (cannot be NULL if .PDB file is used, otherwise it can be NULL)

);

if( ModBase == 0 )

{

_tprintf(_T("Error: SymLoadModule64() failed. Error code: %u \n"), ::GetLastError());

break;

}

_tprintf( _T("Load address: %I64x \n"), ModBase );

 

ShowSymbolInfo(ModBase);

// Look up symbol by name

_tprintf( _T("Looking for symbol %s ... \n"), pSymName );

CSymbolInfoPackage sip; // it contains SYMBOL_INFO structure plus additional

// space for the name of the symbol

bRet = ::SymFromName(

GetCurrentProcess(), // Process handle of the current process

pSymName, // Symbol name

&

sip.si // Address of the SYMBOL_INFO structure (inside "sip" object)

);

if( !bRet )

{

_tprintf( _T("Error: SymFromName() failed. Error code: %u \n"), ::GetLastError() );

}

else

{

// Display information about the symbol

_tprintf( _T("Symbol found: \n") );

ShowSymbolDetails( sip.si );

}

 

// Unload symbols for the module

bRet = ::SymUnloadModule64( GetCurrentProcess(), ModBase );

if( !bRet )

{

_tprintf( _T("Error: SymUnloadModule64() failed. Error code: %u \n"), ::GetLastError() );

}

}

while( 0 );

 

// Deinitialize DbgHelp

bRet = ::SymCleanup( GetCurrentProcess() );

if( !bRet )

{

_tprintf(_T("Error: SymCleanup() failed. Error code: %u \n"), ::GetLastError());

return 0;

}

 

// Complete

return 0;

}

 

///////////////////////////////////////////////////////////////////////////////

// Functions

//

bool

GetFileParams( const TCHAR* pFileName, DWORD64& BaseAddr, DWORD& FileSize )

{

// Check parameters

if( pFileName == 0 )

{

return false;

}

 

// Determine the extension of the file

TCHAR szFileExt[_MAX_EXT] = {0};

_tsplitpath( pFileName, NULL, NULL, NULL, szFileExt );

 

// Is it .PDB file ?

if( _tcsicmp( szFileExt, _T(".PDB") ) == 0 )

{

// Yes, it is a .PDB file

// Determine its size, and use a dummy base address

BaseAddr = 0x10000000; // it can be any non-zero value, but if we load symbols

// from more than one file, memory regions specified

// for different files should not overlap

// (region is "base address + file size")

if( !GetFileSize( pFileName, FileSize ) )

{

return false;

}

}

else

{

// It is not a .PDB file

// Base address and file size can be 0

BaseAddr = 0;

FileSize = 0;

}

 

// Complete

return true;

}

bool

GetFileSize( const TCHAR* pFileName, DWORD& FileSize )

{

// Check parameters

if( pFileName == 0 )

{

return false;

}

 

// Open the file

HANDLE hFile = ::CreateFile( pFileName, GENERIC_READ, FILE_SHARE_READ,

NULL, OPEN_EXISTING, 0, NULL );

if( hFile == INVALID_HANDLE_VALUE )

{

_tprintf( _T("CreateFile() failed. Error: %u \n"), ::GetLastError() );

return false;

}

 

// Obtain the size of the file

FileSize = ::GetFileSize( hFile, NULL );

if( FileSize == INVALID_FILE_SIZE )

{

_tprintf( _T("GetFileSize() failed. Error: %u \n"), ::GetLastError() );

// and continue ...

}

 

// Close the file

if( !::CloseHandle( hFile ) )

{

_tprintf( _T("CloseHandle() failed. Error: %u \n"), ::GetLastError() );

// and continue ...

}

 

// Complete

return ( FileSize != INVALID_FILE_SIZE );

}

void

ShowSymbolInfo( DWORD64 ModBase )

{

// Get module information

IMAGEHLP_MODULE64 ModuleInfo;

memset(&ModuleInfo, 0, sizeof(ModuleInfo) );

ModuleInfo.SizeOfStruct = sizeof(ModuleInfo);

BOOL bRet = ::SymGetModuleInfo64( GetCurrentProcess(), ModBase, &ModuleInfo );

if( !bRet )

{

_tprintf(_T("Error: SymGetModuleInfo64() failed. Error code: %u \n"), ::GetLastError());

return;

}

 

// Display information about symbols

// Kind of symbols

switch( ModuleInfo.SymType )

{

case SymNone:

_tprintf( _T("No symbols available for the module.\n") );

break;

case SymExport:

_tprintf( _T("Loaded symbols: Exports\n") );

break;

case SymCoff:

_tprintf( _T("Loaded symbols: COFF\n") );

break;

case SymCv:

_tprintf( _T("Loaded symbols: CodeView\n") );

break;

case SymSym:

_tprintf( _T("Loaded symbols: SYM\n") );

break;

case SymVirtual:

_tprintf( _T("Loaded symbols: Virtual\n") );

break;

case SymPdb:

_tprintf( _T("Loaded symbols: PDB\n") );

break;

case SymDia:

_tprintf( _T("Loaded symbols: DIA\n") );

break;

case SymDeferred:

_tprintf( _T("Loaded symbols: Deferred\n") ); // not actually loaded

break;

default:

_tprintf( _T("Loaded symbols: Unknown format.\n") );

break;

}

// Image name

if( _tcslen( ModuleInfo.ImageName ) > 0 )

{

_tprintf( _T("Image name: %s \n"), ModuleInfo.ImageName );

}

// Loaded image name

if( _tcslen( ModuleInfo.LoadedImageName ) > 0 )

{

_tprintf( _T("Loaded image name: %s \n"), ModuleInfo.LoadedImageName );

}

// Loaded PDB name

if( _tcslen( ModuleInfo.LoadedPdbName ) > 0 )

{

_tprintf( _T("PDB file name: %s \n"), ModuleInfo.LoadedPdbName );

}

// Is debug information unmatched ?

// (It can only happen if the debug information is contained

// in a separate file (.DBG or .PDB)

if( ModuleInfo.PdbUnmatched || ModuleInfo.DbgUnmatched )

{

_tprintf( _T("Warning: Unmatched symbols. \n") );

}

// Contents

// Line numbers available ?

_tprintf( _T("Line numbers: %s \n"), ModuleInfo.LineNumbers ? _T("Available") : _T("Not available") );

// Global symbols available ?

_tprintf( _T("Global symbols: %s \n"), ModuleInfo.GlobalSymbols ? _T("Available") : _T("Not available") );

// Type information available ?

_tprintf( _T("Type information: %s \n"), ModuleInfo.TypeInfo ? _T("Available") : _T("Not available") );

// Source indexing available ?

_tprintf( _T("Source indexing: %s \n"), ModuleInfo.SourceIndexed ? _T("Yes") : _T("No") );

// Public symbols available ?

_tprintf( _T("Public symbols: %s \n"), ModuleInfo.Publics ? _T("Available") : _T("Not available") );

 

}

void

ShowSymbolDetails( SYMBOL_INFO& SymInfo )

{

}

const

TCHAR* TagStr( ULONG Tag )

{

}

 

 
 

Jochen Kalmbach [MVP]

unread,
Nov 12, 2007, 2:04:30 PM11/12/07
to
Hi Ken!

> I have hard time to use the functions in dbghelp.dll. Not sure if it is
> good place to put question.

Have you tried by implementation of Stackwalker?
http://www.codeproject.com/threads/StackWalker.asp

Normaly you will get error 87 if symbols are not loaded correctly...

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/

Pat Styles [MSFT]

unread,
Nov 12, 2007, 6:35:22 PM11/12/07
to Ken Chen
Hello Ken.

I compiled your code. When I ran it, I had not trouble with the call to
SymGetModuleInfo64(). I suspect that you are running this code against
and older and unmatched version of dbghelp.dll - like say the one in
your system directory.

The pSymName parameter to SymFromName() is completely malformed. You
are passing in the name of the pdb. I would suggest you pass in a
symbol name with a module specifier. Something like "SymFromName!main".

.pat styles [microsoft]

> &sip.si // Address of the SYMBOL_INFO structure (inside "sip" object)

Ken Chen

unread,
Nov 13, 2007, 5:47:32 PM11/13/07
to
Hello Jochen and Pat,
 
Thanks for the help!  I succeed to run Jochen's stack walker and figure out the reason.  Pat you are right about mismatched dbghelp.dll version.  The tricky thing is:  I did put latest dbghelp.lib & dbghelp.dll (from c:\\program files\\Debugging Tools for Windows)into my working directory. But it looks like the sym function in program still call the old version dbghelp.dll and fail.  While getting function address (by doing GetProcAddress)from the c:\\program files\\Debugging Tools for Windows\\dbghelp.dll works fine. (as stackwalker did).  
 
I think the reason is though the program get the latest dbghelp.lib and dbghelp.dll in working directory, when it looks for function address, since old system dbghelp.dll is always there and have the same function name, it just get the function address from the old dll...  So program always fail...  That means we should get every function from dbghelp.dll specificly. Correct me if i am wrong please.
 
 
Ken
 
 
 
"Jochen Kalmbach [MVP]" <nospam-Joch...@holzma.de> wrote in message news:uQZvb7VJ...@TK2MSFTNGP04.phx.gbl...

Avi Cohen Stuart

unread,
Nov 14, 2007, 8:25:50 AM11/14/07
to
Most of the time when we use dbghelp.dll we distribute it and load it by ourself with LoadLibrary() or place the last version of dbghelp.dll in the same directory as where the executable is. The '.' directory is searched first.
 
Avi.

Garfield Lewis

unread,
Nov 14, 2007, 9:19:10 AM11/14/07
to
Have you thought about providing a private manifest with the app that will make it use the version of dbghelp.dll you provide regardless of what is in the path on the system?

--
Garfield A. Lewis
DB2 UDB Development,
IBM Canada Laboratory
 
 

Ken Chen

unread,
Nov 14, 2007, 10:22:06 AM11/14/07
to
Thanks all. I did more test about static loading dbghelp.dll (static loading of DLL, put lib&dll in corresponding directory,specify dbghelp.lib in project property, load dll in linking time).  Putting latest dbghelp.dll in exe directory works well while putting it in current directory will load the dll under system path.
 
So it is all about searching path order of dll handled by windows.  ----  which one have higher priority:  Current directory or system path?
 
 
Apparently there is legacy confliction information in MSDN document about the search order of dll:
 
one part of msdn is saying:
 
 
Search Path Used by Windows to Locate a DLL 

With both implicit and explicit linking, Windows first searches for "known DLLs", such as Kernel32.dll and User32.dll. Windows then searches for the DLLs in the following sequence:

  1. The directory where the executable module for the current process is located.

  2. The current directory.

  3. The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.

  4. The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.

  5. The directories listed in the PATH environment variable.

 

another part of msdn is saying:

http://msdn2.microsoft.com/en-us/library/ms682586.aspx

Standard Search Order

The dynamic-link library (DLL) search order used by the system depends on whether safe DLL search mode is enabled or disabled.

Windows Vista, Windows Server 2003, and Windows XP SP2:  Safe DLL search mode is enabled by default. To disable this feature, create the HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode registry value and set it to 0. Calling the SetDllDirectory function effectively disables SafeDllSearchMode while the specified directory is in the search path and changes the search order as described in this topic.
Windows XP and Windows 2000 SP4:  Safe DLL search mode is disabled by default. To enable this feature, create the SafeDllSearchMode registry value and set it to 1.

If SafeDllSearchMode is enabled, the search order is as follows:

  1. The directory from which the application loaded.
  2. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  3. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  4. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  5. The current directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key.

If SafeDllSearchMode is disabled, the search order is as follows:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The system directory. Use the GetSystemDirectory function to get the path of this directory.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable. Note that this does not include the per-application path specified by the App Paths registry key.

 

Which means system path is searched before current directory on windows xp sp2.  That should be the correct answer, and that explains every matter i met.

 

And another old version (2005) of MSDN,(which i am using) said windows xp set SafeDllSearchMode to 0 by default and windows server 2003 set it to 1 by default, which means current directory first for windows xp.     Crying........................

 

Ken.

 

 
 
0 new messages