StackTrace.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * Copyright (c) 2006 Michael Eddington
  3. * Copyright (c) 2001 Jani Kajala
  4. *
  5. * Permission to use, copy, modify, distribute and sell this
  6. * software and its documentation for any purpose is hereby
  7. * granted without fee, provided that the above copyright notice
  8. * appear in all copies and that both that copyright notice and
  9. * this permission notice appear in supporting documentation.
  10. * Jani Kajala makes no representations about the suitability
  11. * of this software for any purpose. It is provided "as is"
  12. * without express or implied warranty.
  13. */
  14. #include "StackTrace.h"
  15. #include "MapFile.h"
  16. #include "MapFileEntry.h"
  17. #include <string.h>
  18. #include <stdio.h>
  19. //-----------------------------------------------------------------------------
  20. static const char* internalFunctions[] = {
  21. "__duma_malloc",
  22. "__duma_calloc",
  23. "__duma_realloc",
  24. "__duma_valloc",
  25. "__duma_allocate",
  26. "_printStackTrace",
  27. 0
  28. };
  29. #define MAX_DEPTH 32
  30. //-----------------------------------------------------------------------------
  31. namespace dev
  32. {
  33. static int IsInternalFunction(const char* func)
  34. {
  35. for(int i=0; internalFunctions[i]; i++)
  36. {
  37. if(!strcmp(func, internalFunctions[i]))
  38. return 1;
  39. }
  40. return 0;
  41. }
  42. /*
  43. EBP points to stack frame (at least 2 DWORDs) which looks something like this:
  44. DWORD[EBP+4] = return address (=calling function)
  45. DWORD[EBP+0] = calling function stack frame
  46. So we
  47. 1) get the EBP to EBX
  48. 2) take calling function address to EAX
  49. 3) parent stack frame to EBX and
  50. 4) loop 2,3,4 until desired level in calling stack is reached.
  51. Beware that compiler does not always make stack frame (at least if s.c. "omit stack frame"
  52. optimization is enabled), so at least I'd use this code only in debug build.
  53. */
  54. static long getCaller( int index )
  55. {
  56. #if defined(_DEBUG) && defined(_MSC_VER) && defined(_M_IX86)
  57. // Changed a couple things here to prevent some
  58. // access violations, esp with release code that
  59. // doesn't always have a stack frame.
  60. //
  61. // 1. Check next frame to see if we are below 10000
  62. // 2. If we are forcing a stop make the return addr 0
  63. long caller = 0;
  64. __asm
  65. {
  66. mov ebx, ebp
  67. mov ecx, index
  68. inc ecx
  69. xor eax, eax
  70. StackTrace_getCaller_next:
  71. mov eax, [ebx+4]
  72. mov ebx, [ebx]
  73. cmp ebx, 10000
  74. jb StackTrace_getCaller_stop
  75. dec ecx
  76. jnz StackTrace_getCaller_next
  77. jmp StackTrace_getCaller_end
  78. StackTrace_getCaller_stop:
  79. mov eax, 0
  80. StackTrace_getCaller_end:
  81. mov caller, eax
  82. }
  83. return caller;
  84. #else
  85. return 0;
  86. #endif
  87. }
  88. int StackTrace::printStackTrace( MapFile** map, int maps,
  89. int initLevel, int maxDepth, char* buffer, int bufferSize )
  90. {
  91. if ( maxDepth > MAX_DEPTH )
  92. maxDepth = MAX_DEPTH;
  93. // list callers
  94. long callersAddr[MAX_DEPTH];
  95. MapFileEntry* callersEntry[MAX_DEPTH];
  96. int callers;
  97. int i;
  98. int entry;
  99. long addr = -1;
  100. int flag = 0;
  101. int j;
  102. for (callers = 0, i = initLevel ; i < maxDepth && addr ; i++)
  103. {
  104. addr = getCaller( i );
  105. callersEntry[callers] = NULL;
  106. for (entry = -1, j = 0 ; j < maps ; ++j )
  107. {
  108. entry = map[j]->findEntry( addr );
  109. if ( entry != -1 )
  110. {
  111. callersEntry[callers] = map[j]->getEntry(entry);
  112. break;
  113. }
  114. }
  115. if(entry == -1)
  116. continue;
  117. callersAddr[callers] = addr;
  118. callers++;
  119. }
  120. // output call stack
  121. if ( bufferSize > 0 )
  122. *buffer = 0;
  123. int needed = 0;
  124. for ( i = 1 ; i <= callers ; ++i )
  125. {
  126. addr = callersAddr[callers-i];
  127. if(IsInternalFunction(callersEntry[callers-i]->name()))
  128. continue;
  129. // format entry to tempory buf
  130. char buf[MapFileEntry::MAX_NAME+MAX_DEPTH+20]; // name + margin + hex number
  131. buf[0] = 0;
  132. for ( int k = initLevel-1 ; k < i ; ++k )
  133. strcat( buf, " " );
  134. if ( callersEntry[callers-i] == NULL )
  135. sprintf( buf+strlen(buf), "0x%x\n", addr );
  136. else
  137. sprintf( buf+strlen(buf), "%s (%x)\n", callersEntry[callers-i]->name(), addr );
  138. // append temporary buf to output buffer if space left
  139. needed += (int)strlen( buf );
  140. if ( needed < bufferSize )
  141. strcat( buffer, buf );
  142. }
  143. // terminate output buffer
  144. if ( needed < bufferSize )
  145. buffer[needed] = 0;
  146. else if ( bufferSize > 0 )
  147. buffer[bufferSize-1] = 0;
  148. return needed;
  149. }
  150. } // dev