Call Stack.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. StackWalker can't support getting the context, and extracting the stack at a later time,
  6. because the stack is not included in the context (this was tested)
  7. /******************************************************************************/
  8. #if WINDOWS_OLD
  9. namespace StackWalker
  10. {
  11. #define SW_PROFILE 0
  12. #if SW_PROFILE
  13. Dbl d[16];
  14. struct Temp{~Temp(){Str s; FREPA(d)s.line()+=S+i+':'+d[i]; Exit(s);}}temp;
  15. #define SWP_START Dbl t=Time.curTime();
  16. #define SWP(x) {Dbl c=Time.curTime(); d[x]+=c-t; t=c;}
  17. #else
  18. #define SWP_START
  19. #define SWP(x)
  20. #endif
  21. #include "../ThirdPartyLibs/StackWalker/StackWalker.cpp"
  22. struct StackWalkerEx : StackWalker
  23. {
  24. Int i;
  25. Str *stack;
  26. virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
  27. {
  28. if(++i>2 // skip first 2 entries ("StackWalkerEx::ShowCallStack", "GetCallStack", "check" is inlined in release)
  29. // skip Windows stuff
  30. && !Equal(entry.name, "RtlUnicodeStringToInteger", true)
  31. && !Equal(entry.name, "RtlUserThreadStart" , true)
  32. && !Equal(entry.name, "BaseThreadInitThunk" , true)
  33. && !Equal(entry.name, "__scrt_common_main_seh" , true)
  34. && !Equal(entry.name, X64 ? "thread_start<unsigned int (__cdecl*)(void * __ptr64)>" : "thread_start<unsigned int (__stdcall*)(void *)>", true)
  35. )
  36. {
  37. SWP_START
  38. stack->line()+=entry.name;
  39. SWP(15)
  40. }
  41. }
  42. bool check(Str &stack)
  43. {
  44. i=0;
  45. T.stack=&stack;
  46. return ShowCallstack()!=0;
  47. }
  48. };
  49. } // namespace
  50. #endif
  51. /******************************************************************************/
  52. Bool GetCallStack(Str &stack)
  53. {
  54. stack.clear();
  55. #if WINDOWS_OLD
  56. StackWalker::StackWalkerEx sw; return sw.check(stack);
  57. #elif WEB
  58. int size=emscripten_get_callstack(EM_LOG_DEMANGLE|EM_LOG_NO_PATHS|EM_LOG_FUNC_PARAMS, null, 0)-1; // remove null-terminated char
  59. if( size>0)
  60. {
  61. Memt<Char8> temp; temp.setNum(size+64); // +64 for safety because of different line numbers than before
  62. Int got=emscripten_get_callstack(EM_LOG_DEMANGLE|EM_LOG_NO_PATHS|EM_LOG_FUNC_PARAMS, temp.data(), temp.elms())-1; // remove null-terminated char
  63. if( got>0)
  64. {
  65. stack.reserve(got); FREP(got)stack+=temp[i];
  66. return true;
  67. }
  68. }
  69. #endif
  70. return false;
  71. }
  72. Bool GetCallStackFast(Str &stack) // !! this function is not thread-safe !!
  73. {
  74. stack.clear();
  75. #if WINDOWS_OLD
  76. static StackWalker::StackWalkerEx *SW; if(!SW){New(SW); SW->fast=true;} return SW->check(stack);
  77. #elif WEB
  78. return GetCallStack(stack);
  79. #endif
  80. return false;
  81. }
  82. /******************************************************************************/
  83. } // namespace
  84. /******************************************************************************/