Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
7.2 KiB

  1. //========= Copyright � 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Tools for grabbing/dumping the stack at runtime
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef TIER0_STACKTOOLS_H
  8. #define TIER0_STACKTOOLS_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "tier0/platform.h"
  13. #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)
  14. # 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
  15. #endif
  16. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  17. //#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
  18. # if defined( ENABLE_THREAD_PARENT_STACK_TRACING )
  19. # define THREAD_PARENT_STACK_TRACE_LENGTH 32
  20. # endif
  21. #endif
  22. PLATFORM_INTERFACE int GetCallStack( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
  23. //ONLY WORKS IF THE CRAWLED PORTION OF THE STACK DISABLES FRAME POINTER OMISSION (/Oy-) "vpc /nofpo"
  24. PLATFORM_INTERFACE int GetCallStack_Fast( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
  25. typedef int (*FN_GetCallStack)( void **pReturnAddressesOut, int iArrayCount, int iSkipCount );
  26. //where we'll find our PDB's for win32.
  27. PLATFORM_INTERFACE void SetStackTranslationSymbolSearchPath( const char *szSemicolonSeparatedList = NULL );
  28. PLATFORM_INTERFACE void StackToolsNotify_LoadedLibrary( const char *szLibName );
  29. //maximum output sample "tier0.dll!TranslateStackInfo - u:\Dev\L4D\src\tier0\stacktools.cpp(162) + 4 bytes"
  30. enum TranslateStackInfo_StyleFlags_t
  31. {
  32. TSISTYLEFLAG_NONE = 0,
  33. TSISTYLEFLAG_MODULENAME = (1<<0), //start with module Sample: "tier0.dll!"
  34. TSISTYLEFLAG_SYMBOLNAME = (1<<1), //include the symbol name Sample: "TranslateStackInfo"
  35. TSISTYLEFLAG_FULLPATH = (1<<2), //include full path Sample: "u:\Dev\L4D\src\tier0\stacktools.cpp"
  36. TSISTYLEFLAG_SHORTPATH = (1<<3), //only include 2 directories Sample: "\src\tier0\stacktools.cpp"
  37. TSISTYLEFLAG_LINE = (1<<4), //file line number Sample: "(162)"
  38. TSISTYLEFLAG_LINEANDOFFSET = (1<<5), //file line + offset Sample: "(162) + 4 bytes"
  39. TSISTYLEFLAG_LAST = TSISTYLEFLAG_LINEANDOFFSET,
  40. TSISTYLEFLAG_DEFAULT = (TSISTYLEFLAG_MODULENAME | TSISTYLEFLAG_SYMBOLNAME | TSISTYLEFLAG_FULLPATH | TSISTYLEFLAG_LINEANDOFFSET), //produces sample above
  41. };
  42. //Generates a formatted list of function information, returns number of translated entries
  43. //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.
  44. PLATFORM_INTERFACE int TranslateStackInfo( const void * const *pCallStack, int iCallStackCount, tchar *szOutput, int iOutBufferSize, const tchar *szEntrySeparator, TranslateStackInfo_StyleFlags_t style = TSISTYLEFLAG_DEFAULT );
  45. 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.
  46. PLATFORM_INTERFACE bool GetFileAndLineFromAddress( const void *pAddress, tchar *pFileNameOut, int iMaxFileNameLength, uint32 &iLineNumberOut, uint32 *pDisplacementOut = NULL );
  47. PLATFORM_INTERFACE bool GetSymbolNameFromAddress( const void *pAddress, tchar *pSymbolNameOut, int iMaxSymbolNameLength, uint64 *pDisplacementOut = NULL );
  48. PLATFORM_INTERFACE bool GetModuleNameFromAddress( const void *pAddress, tchar *pModuleNameOut, int iMaxModuleNameLength );
  49. 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
  50. {
  51. public:
  52. CCallStackStorage( FN_GetCallStack GetStackFunction = GetCallStack, uint32 iSkipCalls = 0 );
  53. CCallStackStorage( const CCallStackStorage &copyFrom )
  54. {
  55. iValidEntries = copyFrom.iValidEntries;
  56. memcpy( pStack, copyFrom.pStack, sizeof( void * ) * copyFrom.iValidEntries );
  57. }
  58. 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
  59. uint32 iValidEntries;
  60. };
  61. //Hold onto one of these to denote the top of a functional stack trace. Also allows us to string together threads to their parents
  62. class PLATFORM_CLASS CStackTop_Base
  63. {
  64. protected:
  65. #if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
  66. CStackTop_Base *m_pPrevTop;
  67. void *m_pStackBase;
  68. void *m_pReplaceAddress;
  69. void * const *m_pParentStackTrace;
  70. int m_iParentStackTraceLength;
  71. #endif
  72. };
  73. //makes a copy of the parent stack
  74. class PLATFORM_CLASS CStackTop_CopyParentStack : public CStackTop_Base
  75. {
  76. public:
  77. CStackTop_CopyParentStack( void * const * pParentStackTrace, int iParentStackTraceLength );
  78. ~CStackTop_CopyParentStack( void );
  79. };
  80. //just references the parent stack. Assuming that you'll keep that memory around as long as you're keeping this Stack Top marker.
  81. class PLATFORM_CLASS CStackTop_ReferenceParentStack : public CStackTop_Base
  82. {
  83. public:
  84. CStackTop_ReferenceParentStack( void * const * pParentStackTrace = NULL, int iParentStackTraceLength = 0 );
  85. ~CStackTop_ReferenceParentStack( void );
  86. void ReleaseParentStackReferences( void ); //in case you need to delete the parent stack trace before this class goes out of scope
  87. };
  88. //Encodes data so that every byte's most significant bit is a 1. Ensuring no null terminators.
  89. //This puts the encoded data in the 128-255 value range. Leaving all standard ascii characters for control.
  90. //Returns string length (not including the written null terminator as is standard).
  91. //Or if the buffer is too small. Returns negative of necessary buffer size (including room needed for null terminator)
  92. PLATFORM_INTERFACE int EncodeBinaryToString( const void *pToEncode, int iDataLength, char *pEncodeOut, int iEncodeBufferSize );
  93. //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.
  94. //Returns:
  95. // >= 0 is the decoded data size
  96. // INT_MIN (most negative value possible) indicates an improperly formatted string (not our data)
  97. // all other negative values are the negative of how much dest buffer size is necessary.
  98. PLATFORM_INTERFACE int DecodeBinaryFromString( const char *pString, void *pDestBuffer, int iDestBufferSize, char **ppParseFinishOut = NULL );
  99. // 360<->VXConsole specific communication definitions
  100. #define XBX_CALLSTACKDECODEPREFIX ":CSDECODE["
  101. enum StackTranslation_BinaryHandler_Command_t
  102. {
  103. ST_BHC_LOADEDLIBARY,
  104. ST_BHC_GETTRANSLATIONINFO,
  105. };
  106. #pragma pack(push)
  107. #pragma pack(1)
  108. struct FullStackInfo_t
  109. {
  110. const void *pAddress;
  111. char szModuleName[24];
  112. char szFileName[MAX_PATH/2];
  113. char szSymbol[64];
  114. uint32 iLine;
  115. uint32 iSymbolOffset;
  116. };
  117. #pragma pack(pop)
  118. #endif //#ifndef TIER0_STACKTOOLS_H