ETW Syscall Tracing

Hi All ,

I am learning how to use ETW for Syscall enter and exit. It would have been handy if syscall enter would have given me that name of the system call instead of virtual address of the system call , but it doesnt. How can I map system call address to syscall name like NTCreateFile.

Thanks in advance.

BR
Niladri

In general (non-ETW, that is), you could use one of the dbghelp, dbgeng or
dia (maybe others) API’s to map any address to a symbolic name (assuming
that is has one, of course); however, how this all works with ETW (or
whether it does), I really don’t know, and it’s certainly possible that
there is a better way to accomplish this.

docs:

  • dbgeng - see the windbg docs

  • dbghelp - see the file ‘/sdk/help/dbghelp.chm’

    - dia - see MSDN/VS docs

    src/tools:

    - dbgeng - the ‘/sdk/samples’ contains several examples of how
    to resolve an address to a name. I know that ‘dumpstk’ does this for sure,
    but I think that most if not all of them do as well, in some way, shape or
    form.

    - dbghelp - windbg includes ‘dbh,’ which can be used to dump all sorts of
    information about an exe/pdb. The source for this tool (or some version
    thereof), however, is part of the SDK, or at least was the last time that I
    looked.

    - dia - VS (from 2005 onward, I think) includes the source code (but no
    binary, if I recally correctly) for ‘dia2dump,’ which is basically does the
    same types of things as ‘dbh,’ but uses dia instead of dbghelp.

    Personally, I would go with dbghelp in this case, assuming that there isn’t
    something better that I haven’t considered:

    - I find it easier/more straightforward to use for simple, standalone stuff
    like (I think) that you’re proposing than dbgeng.

    - although DIA has (or at least documents as having) some capabilities that
    dbgeng/dbghelp do not (or at least aren’t documented as having - some
    extended type information, for example - I’ve never found that I need it and
    it has just the sort of
    gratuitous COM interface that I tend to hate because it makes things more
    complicated than necessary for no obvious benefit that I see.

    - although both the ‘dbh’ and ‘dia2dump’ samples are large and fairly
    confusing at first (imo), I find the latter much more so, especially for
    something that does basically the same thing as the former.

    - while all three have truly crappy documentation, I think that dbghelp’s
    is probably the best, and either way, in practice both of the other two
    generally require reading the dbghelp docs anyway (in the worst case, all
    three sometimes more or less require that you be familiar with codeview
    information formats). DbgEng’s is not complete, to put it mildly - lots of
    missing links and the TOC isn’t even alphabetized (very irritating). DIA’s
    is small and bewildering, because, in my opinion, in its efforts to hide
    details from you, it has created a set of interfaces that take the already
    messy codeview ‘spec’ and mangle them some more.

    Good luck,

    mm

    On Wed, Sep 22, 2010 at 9:41 AM, wrote:

    > Hi All ,
    >
    > I am learning how to use ETW for Syscall enter and exit. It would have been
    > handy if syscall enter would have given me that name of the system call
    > instead of virtual address of the system call , but it doesnt. How can I
    > map system call address to syscall name like NTCreateFile.
    >
    > Thanks in advance.
    >
    > BR
    > Niladri
    >
    > —
    > NTDEV is sponsored by OSR
    >
    > For our schedule of WDF, WDM, debugging and other seminars visit:
    > http://www.osr.com/seminars
    >
    > To unsubscribe, visit the List Server section of OSR Online at
    > http://www.osronline.com/page.cfm?name=ListServer
    >

Thanks so much ! Really appreciate it. I shall try this and post a solutions if it works.

Good luck.

mm

On Wed, Sep 22, 2010 at 2:25 PM, wrote:

> Thanks so much ! Really appreciate it. I shall try this and post a
> solutions if it works.
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Hi mm ,

I am using a code example that I found on the net as follows -

// dbgHelp_Symbol_By_address.cpp : Defines the entry point for the console application.
//

#include “stdafx.h”

///////////////////////////////////////////////////////////////////////////////
//
// SymFromAddr.cpp
//
// Author: Oleg Starodumov
//
//

///////////////////////////////////////////////////////////////////////////////
//
// Description:
//
// This example looks up a symbol by address 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 address (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 address
// * 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
// * Address of the symbol to search for
//

///////////////////////////////////////////////////////////////////////////////
// Include files
//

#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 \n”), argv[0] );
return 0;
}

DWORD64 SymAddr = 0;

if( _stscanf( argv[2], _T(“%I64x”), &SymAddr ) != 1 )
{
_tprintf( _T(“Usage: %s \n”), argv[0] );
return 0;
}

// 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 );

// Look up symbol by address

_tprintf( _T(“Looking for symbol at address %I64x … \n”), SymAddr );

CSymbolInfoPackage sip; // it contains SYMBOL_INFO structure plus additional
// space for the name of the symbol

DWORD64 Displacement = 0;

bRet = ::SymFromAddr(
GetCurrentProcess(), // Process handle of the current process
SymAddr, // Symbol address
&Displacement, // Address of the variable that will receive the displacement
&sip.si // Address of the SYMBOL_INFO structure (inside “sip” object)
);

if( !bRet )
{
_tprintf( _T(“Error: SymFromAddr() 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 )
{
// Kind of symbol (tag)

_tprintf( _T("Symbol: %s "), TagStr(SymInfo.Tag) );

// Address

_tprintf( _T(“Address: %I64x “), SymInfo.Address );

// Size

_tprintf( _T(“Size: %u “), SymInfo.Size );

// Name

_tprintf( _T(“Name: %s”), SymInfo.Name );

_tprintf( _T(”\n”) );

}

const TCHAR* TagStr( ULONG Tag )
{
switch( Tag )
{
case SymTagNull:
return _T(“Null”);
case SymTagExe:
return _T(“Exe”);
case SymTagCompiland:
return _T(“Compiland”);
case SymTagCompilandDetails:
return _T(“CompilandDetails”);
case SymTagCompilandEnv:
return _T(“CompilandEnv”);
case SymTagFunction:
return _T(“Function”);
case SymTagBlock:
return _T(“Block”);
case SymTagData:
return _T(“Data”);
case SymTagAnnotation:
return _T(“Annotation”);
case SymTagLabel:
return _T(“Label”);
case SymTagPublicSymbol:
return _T(“PublicSymbol”);
case SymTagUDT:
return _T(“UDT”);
case SymTagEnum:
return _T(“Enum”);
case SymTagFunctionType:
return _T(“FunctionType”);
case SymTagPointerType:
return _T(“PointerType”);
case SymTagArrayType:
return _T(“ArrayType”);
case SymTagBaseType:
return _T(“BaseType”);
case SymTagTypedef:
return _T(“Typedef”);
case SymTagBaseClass:
return _T(“BaseClass”);
case SymTagFriend:
return _T(“Friend”);
case SymTagFunctionArgType:
return _T(“FunctionArgType”);
case SymTagFuncDebugStart:
return _T(“FuncDebugStart”);
case SymTagFuncDebugEnd:
return _T(“FuncDebugEnd”);
case SymTagUsingNamespace:
return _T(“UsingNamespace”);
case SymTagVTableShape:
return _T(“VTableShape”);
case SymTagVTable:
return _T(“VTable”);
case SymTagCustom:
return _T(“Custom”);
case SymTagThunk:
return _T(“Thunk”);
case SymTagCustomType:
return _T(“CustomType”);
case SymTagManagedType:
return _T(“ManagedType”);
case SymTagDimension:
return _T(“Dimension”);
default:
return _T(“Unknown”);
}

return _T(””);

}

Now this takes two parameters
1) the module name to load-I have set to C:\Windows\System32\ntoskrnl.exe (as the address passed is supposed in SSDT(KilServiceTable for X64 systems).
2) the address to find - 0xfffff800019ed5c0.

The run for this program gives error - 126 (module not found ) for SymFromAddr function. Output of the run -

C:\Users\Niladri>“C:\Users\Niladri\Documents\Visual Studio 2008\Projects\dbgHelp
_Symbol_By_address\Debug\dbgHelp_Symbol_By_address.exe” C:\Windows\System32\nto
skrnl.exe 0xfffff800019ed5c0
Loading symbols for: C:\Windows\System32\ntoskrnl.exe …
Load address: 400000
Looking for symbol at address fffff800019ed5c0 …
Error: SymFromAddr() failed. Error code: 126

Can this library be used for kernel land addresses and symbols ( the address passed is for NTClose).
Is there special settings in dbghelp for kernel land?

Thanks
Niladri</stdio.h></dbghelp.h></tchar.h></windows.h>

If you also want to resolve routine addresses to functions which are not
exported , you will need to download the appropriate PDB file corresponding
to your version of ntoskrnl.exe from the symbols server and extract the
information from the PDB file.

Check out the function call SymSrvGetFileIndexes to get a PDB file from an
existing binary.
Check out the sample dia2dump to extract information from a PDB file.

//Daniel

wrote in message news:xxxxx@ntdev…
> Hi All ,
>
> I am learning how to use ETW for Syscall enter and exit. It would have
> been handy if syscall enter would have given me that name of the system
> call instead of virtual address of the system call , but it doesnt. How
> can I map system call address to syscall name like NTCreateFile.
>
> Thanks in advance.
>
> BR
> Niladri
>

No, nothing special is required for kernel modules, at least not that I know
of.

However, the address you are entering assumes that DbgHelp is using the same
base address as whatever your target system is using. In order for this to
be the case you need to pass the base address for ntoskrnl on your target as
‘BaseOfDll’ to SymLoadModule64.

DWORD64 WINAPI SymLoadModule64(
__in HANDLE hProcess,
__in HANDLE hFile,
__in PCSTR ImageName,
__in PCSTR ModuleName,
__in DWORD64 BaseOfDll,
__in DWORD SizeOfDll
);

In particular:

BaseOfDll
The load address of the module. If the value is zero, the library obtains
the load address from the symbol file. The load address contained in the
symbol file is not necessarily the actual load address. Debuggers and other
applications having an actual load address should use the real load address
when calling this function.

If the image is a .pdb file, this parameter cannot be zero.

So, according to that, you would need to pass the actual base address for
BaseOfDll; however, the sample you are using, doesn’t seem to accept a base
address as a command line argument, so that means that in order to use it,
you would need to (a) convert it yourself; (b) modify the sample to accept
the actual base address as a command line argument and get that argument to
BaseOfDll; or (c) not use the sample and write the code yourself.

Personally, I think that (c) would be the easiest route. All you really
need is to call SymLoadModule64() and then SymFromAddr().

Good luck,

mm

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@napier.ac.uk
Sent: Thursday, September 23, 2010 7:14 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] ETW Syscall Tracing

Hi mm ,

I am using a code example that I found on the net as follows -

// dbgHelp_Symbol_By_address.cpp : Defines the entry point for the console
application.
//

#include “stdafx.h”

////////////////////////////////////////////////////////////////////////////
///
//
// SymFromAddr.cpp
//
// Author: Oleg Starodumov
//
//

////////////////////////////////////////////////////////////////////////////
///
//
// Description:
//
// This example looks up a symbol by address 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 address (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 address
// * 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
// * Address of the symbol to search for
//

////////////////////////////////////////////////////////////////////////////
///
// Include files
//

#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
\n”), argv[0] );
return 0;
}

DWORD64 SymAddr = 0;

if( _stscanf( argv[2], _T(“%I64x”), &SymAddr ) != 1 )
{
_tprintf( _T(“Usage: %s
\n”), argv[0] );
return 0;
}

// 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 );

// Look up symbol by address

_tprintf( _T(“Looking for symbol at address %I64x … \n”),
SymAddr );

CSymbolInfoPackage sip; // it contains SYMBOL_INFO structure
plus additional
// space for the name of the symbol

DWORD64 Displacement = 0;

bRet = ::SymFromAddr(

GetCurrentProcess(), // Process handle of the current process
SymAddr,
// Symbol address

&Displacement, // Address of the variable that will receive the
displacement
&sip.si
// Address of the SYMBOL_INFO structure (inside “sip” object)
);

if( !bRet )
{
_tprintf( _T(“Error: SymFromAddr() 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 )
{
// Kind of symbol (tag)

_tprintf( _T("Symbol: %s "), TagStr(SymInfo.Tag) );

// Address

_tprintf( _T(“Address: %I64x “), SymInfo.Address );

// Size

_tprintf( _T(“Size: %u “), SymInfo.Size );

// Name

_tprintf( _T(“Name: %s”), SymInfo.Name );

_tprintf( _T(”\n”) );

}

const TCHAR* TagStr( ULONG Tag )
{
switch( Tag )
{
case SymTagNull:
return _T(“Null”);
case SymTagExe:
return _T(“Exe”);
case SymTagCompiland:
return _T(“Compiland”);
case SymTagCompilandDetails:
return _T(“CompilandDetails”);
case SymTagCompilandEnv:
return _T(“CompilandEnv”);
case SymTagFunction:
return _T(“Function”);
case SymTagBlock:
return _T(“Block”);
case SymTagData:
return _T(“Data”);
case SymTagAnnotation:
return _T(“Annotation”);
case SymTagLabel:
return _T(“Label”);
case SymTagPublicSymbol:
return _T(“PublicSymbol”);
case SymTagUDT:
return _T(“UDT”);
case SymTagEnum:
return _T(“Enum”);
case SymTagFunctionType:
return _T(“FunctionType”);
case SymTagPointerType:
return _T(“PointerType”);
case SymTagArrayType:
return _T(“ArrayType”);
case SymTagBaseType:
return _T(“BaseType”);
case SymTagTypedef:
return _T(“Typedef”);
case SymTagBaseClass:
return _T(“BaseClass”);
case SymTagFriend:
return _T(“Friend”);
case SymTagFunctionArgType:
return _T(“FunctionArgType”);
case SymTagFuncDebugStart:
return _T(“FuncDebugStart”);
case SymTagFuncDebugEnd:
return _T(“FuncDebugEnd”);
case SymTagUsingNamespace:
return _T(“UsingNamespace”);
case SymTagVTableShape:
return _T(“VTableShape”);
case SymTagVTable:
return _T(“VTable”);
case SymTagCustom:
return _T(“Custom”);
case SymTagThunk:
return _T(“Thunk”);
case SymTagCustomType:
return _T(“CustomType”);
case SymTagManagedType:
return _T(“ManagedType”);
case SymTagDimension:
return _T(“Dimension”);
default:
return _T(“Unknown”);
}

return _T(””);

}

Now this takes two parameters
1) the module name to load-I have set to C:\Windows\System32\ntoskrnl.exe
(as the address passed is supposed in SSDT(KilServiceTable for X64 systems).

2) the address to find - 0xfffff800019ed5c0.

The run for this program gives error - 126 (module not found ) for
SymFromAddr function. Output of the run -

C:\Users\Niladri>“C:\Users\Niladri\Documents\Visual Studio
2008\Projects\dbgHelp
_Symbol_By_address\Debug\dbgHelp_Symbol_By_address.exe”
C:\Windows\System32\nto
skrnl.exe 0xfffff800019ed5c0
Loading symbols for: C:\Windows\System32\ntoskrnl.exe …
Load address: 400000
Looking for symbol at address fffff800019ed5c0 …
Error: SymFromAddr() failed. Error code: 126

Can this library be used for kernel land addresses and symbols ( the
address passed is for NTClose).
Is there special settings in dbghelp for kernel land?

Thanks
Niladri


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer</stdio.h></dbghelp.h></tchar.h></windows.h>

Thanks , I understand. I can easily find out the base address of ntoskrnl.exe in kernel land. Is there a way to find the base address from user land?

http://msdn.microsoft.com/en-us/library/ms682617(VS.85).aspx

Good luck,

mm

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@napier.ac.uk
Sent: Friday, September 24, 2010 10:48 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] ETW Syscall Tracing

Thanks , I understand. I can easily find out the base address of
ntoskrnl.exe in kernel land. Is there a way to find the base address from
user land?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer