|
|
|
|
//========= Copyright <EFBFBD> 1996-2008, Valve Corporation, All rights reserved. ============//
|
|
|
|
|
//
|
|
|
|
|
// Purpose: Tools for grabbing/dumping the stack at runtime
|
|
|
|
|
//
|
|
|
|
|
// $NoKeywords: $
|
|
|
|
|
//=============================================================================//
|
|
|
|
|
|
|
|
|
|
#ifndef TIER0_STACKTOOLS_H
|
|
|
|
|
#define TIER0_STACKTOOLS_H
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#pragma once
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "tier0/platform.h"
|
|
|
|
|
|
|
|
|
|
#if (defined( PLATFORM_WINDOWS ) || defined( PLATFORM_X360 )) && !defined( STEAM ) && !defined( _CERT ) && defined( TCHAR_IS_CHAR ) //designed for windows/x360, not built/tested with wide characters, not intended for release builds (but probably wouldn't damage anything)
|
|
|
|
|
# define ENABLE_RUNTIME_STACK_TRANSLATION //uncomment to enable runtime stack translation tools. All of which use on-demand loading of necessary dll's and pdb's
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
|
|
|
|
|
//#define ENABLE_THREAD_PARENT_STACK_TRACING 1 //uncomment to actually enable tracking stack traces from threads and jobs to their parent thread. Must also define THREAD_PARENT_STACK_TRACE_SUPPORTED in threadtools.h
|
|
|
|
|
# if defined( ENABLE_THREAD_PARENT_STACK_TRACING )
|
|
|
|
|
# define THREAD_PARENT_STACK_TRACE_LENGTH 32
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PLATFORM_INTERFACE int GetCallStack( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
|
|
|
|
|
|
|
|
|
|
//ONLY WORKS IF THE CRAWLED PORTION OF THE STACK DISABLES FRAME POINTER OMISSION (/Oy-) "vpc /nofpo"
|
|
|
|
|
PLATFORM_INTERFACE int GetCallStack_Fast( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
|
|
|
|
|
|
|
|
|
|
typedef int (*FN_GetCallStack)( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
|
|
|
|
|
|
|
|
|
|
//where we'll find our PDB's for win32.
|
|
|
|
|
PLATFORM_INTERFACE void SetStackTranslationSymbolSearchPath( const char *szSemicolonSeparatedList = NULL );
|
|
|
|
|
PLATFORM_INTERFACE void StackToolsNotify_LoadedLibrary( const char *szLibName );
|
|
|
|
|
|
|
|
|
|
//maximum output sample "tier0.dll!TranslateStackInfo - u:\Dev\L4D\src\tier0\stacktools.cpp(162) + 4 bytes"
|
|
|
|
|
enum TranslateStackInfo_StyleFlags_t
|
|
|
|
|
{
|
|
|
|
|
TSISTYLEFLAG_NONE = 0,
|
|
|
|
|
TSISTYLEFLAG_MODULENAME = (1<<0), //start with module Sample: "tier0.dll!"
|
|
|
|
|
TSISTYLEFLAG_SYMBOLNAME = (1<<1), //include the symbol name Sample: "TranslateStackInfo"
|
|
|
|
|
TSISTYLEFLAG_FULLPATH = (1<<2), //include full path Sample: "u:\Dev\L4D\src\tier0\stacktools.cpp"
|
|
|
|
|
TSISTYLEFLAG_SHORTPATH = (1<<3), //only include 2 directories Sample: "\src\tier0\stacktools.cpp"
|
|
|
|
|
TSISTYLEFLAG_LINE = (1<<4), //file line number Sample: "(162)"
|
|
|
|
|
TSISTYLEFLAG_LINEANDOFFSET = (1<<5), //file line + offset Sample: "(162) + 4 bytes"
|
|
|
|
|
TSISTYLEFLAG_LAST = TSISTYLEFLAG_LINEANDOFFSET,
|
|
|
|
|
TSISTYLEFLAG_DEFAULT = (TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_FULLPATH | TSISTYLEFLAG_LINEANDOFFSET), //produces sample above
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//Generates a formatted list of function information, returns number of translated entries
|
|
|
|
|
//On 360 this generates a string that can be decoded by VXConsole in print functions. Optimal path for translation because it's one way. Other paths require multiple transactions.
|
|
|
|
|
PLATFORM_INTERFACE int TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT );
|
|
|
|
|
|
|
|
|
|
PLATFORM_INTERFACE void PreloadStackInformation( void * const *pAddresses, int iAddressCount ); //caches data and reduces communication with VXConsole to speed up 360 decoding when using any of the Get***FromAddress() functions. Nop on PC.
|
|
|
|
|
PLATFORM_INTERFACE bool GetFileAndLineFromAddress( const void *pAddress, tchar *pFileNameOut, int iMaxFileNameLength, uint32 &iLineNumberOut, uint32 *pDisplacementOut = NULL );
|
|
|
|
|
PLATFORM_INTERFACE bool GetSymbolNameFromAddress( const void *pAddress, tchar *pSymbolNameOut, int iMaxSymbolNameLength, uint64 *pDisplacementOut = NULL );
|
|
|
|
|
PLATFORM_INTERFACE bool GetModuleNameFromAddress( const void *pAddress, tchar *pModuleNameOut, int iMaxModuleNameLength );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PLATFORM_CLASS CCallStackStorage //a helper class to grab a stack trace as close to the leaf code surface as possible, then pass it on to deeper functions intact with less unpredictable inlining pollution
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CCallStackStorage( FN_GetCallStack GetStackFunction = GetCallStack, uint32 iSkipCalls = 0 );
|
|
|
|
|
CCallStackStorage( const CCallStackStorage ©From )
|
|
|
|
|
{
|
|
|
|
|
iValidEntries = copyFrom.iValidEntries;
|
|
|
|
|
memcpy( pStack, copyFrom.pStack, sizeof( void * ) * copyFrom.iValidEntries );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *pStack[128]; //probably too big, possibly too small for some applications. Don't want to spend the time figuring out how to generalize this without templatizing pollution or mallocs
|
|
|
|
|
uint32 iValidEntries;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Hold onto one of these to denote the top of a functional stack trace. Also allows us to string together threads to their parents
|
|
|
|
|
class PLATFORM_CLASS CStackTop_Base
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
|
|
|
|
|
CStackTop_Base *m_pPrevTop;
|
|
|
|
|
void *m_pStackBase;
|
|
|
|
|
void *m_pReplaceAddress;
|
|
|
|
|
|
|
|
|
|
void * const *m_pParentStackTrace;
|
|
|
|
|
int m_iParentStackTraceLength;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//makes a copy of the parent stack
|
|
|
|
|
class PLATFORM_CLASS CStackTop_CopyParentStack : public CStackTop_Base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CStackTop_CopyParentStack( void * const * pParentStackTrace, int iParentStackTraceLength );
|
|
|
|
|
~CStackTop_CopyParentStack( void );
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//just references the parent stack. Assuming that you'll keep that memory around as long as you're keeping this Stack Top marker.
|
|
|
|
|
class PLATFORM_CLASS CStackTop_ReferenceParentStack : public CStackTop_Base
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CStackTop_ReferenceParentStack( void * const * pParentStackTrace = NULL, int iParentStackTraceLength = 0 );
|
|
|
|
|
~CStackTop_ReferenceParentStack( void );
|
|
|
|
|
void ReleaseParentStackReferences( void ); //in case you need to delete the parent stack trace before this class goes out of scope
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Encodes data so that every byte's most significant bit is a 1. Ensuring no null terminators.
|
|
|
|
|
//This puts the encoded data in the 128-255 value range. Leaving all standard ascii characters for control.
|
|
|
|
|
//Returns string length (not including the written null terminator as is standard).
|
|
|
|
|
//Or if the buffer is too small. Returns negative of necessary buffer size (including room needed for null terminator)
|
|
|
|
|
PLATFORM_INTERFACE int EncodeBinaryToString( const void *pToEncode, int iDataLength, char *pEncodeOut, int iEncodeBufferSize );
|
|
|
|
|
|
|
|
|
|
//Decodes a string produced by EncodeBinaryToString(). Safe to decode in place if you don't mind trashing your string, binary byte count always less than string byte count.
|
|
|
|
|
//Returns:
|
|
|
|
|
// >= 0 is the decoded data size
|
|
|
|
|
// INT_MIN (most negative value possible) indicates an improperly formatted string (not our data)
|
|
|
|
|
// all other negative values are the negative of how much dest buffer size is necessary.
|
|
|
|
|
PLATFORM_INTERFACE int DecodeBinaryFromString( const char *pString, void *pDestBuffer, int iDestBufferSize, char **ppParseFinishOut = NULL );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 360<->VXConsole specific communication definitions
|
|
|
|
|
#define XBX_CALLSTACKDECODEPREFIX ":CSDECODE["
|
|
|
|
|
|
|
|
|
|
enum StackTranslation_BinaryHandler_Command_t
|
|
|
|
|
{
|
|
|
|
|
ST_BHC_LOADEDLIBARY,
|
|
|
|
|
ST_BHC_GETTRANSLATIONINFO,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#pragma pack(push)
|
|
|
|
|
#pragma pack(1)
|
|
|
|
|
struct FullStackInfo_t
|
|
|
|
|
{
|
|
|
|
|
const void *pAddress;
|
|
|
|
|
char szModuleName[24];
|
|
|
|
|
char szFileName[MAX_PATH/2];
|
|
|
|
|
char szSymbol[64];
|
|
|
|
|
uint32 iLine;
|
|
|
|
|
uint32 iSymbolOffset;
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
|
|
#endif //#ifndef TIER0_STACKTOOLS_H
|