Leaked source code of windows server 2003
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.

418 lines
11 KiB

  1. #include <ole2int.h>
  2. #include "stackwlk.hxx"
  3. char * mystrdup(const char * sz)
  4. {
  5. int nLen = lstrlenA(sz) + 1;
  6. char * tmp = new char[nLen];
  7. lstrcpyA(tmp, sz);
  8. return tmp;
  9. }
  10. StackWalker::SymGetModuleInfoFunc StackWalker::_SymGetModuleInfo;
  11. StackWalker::SymGetSymFromAddrFunc StackWalker::_SymGetSymFromAddr;
  12. StackWalker::SymLoadModuleFunc StackWalker::_SymLoadModule;
  13. StackWalker::StackWalkFunc StackWalker::_StackWalk;
  14. StackWalker::UndecorateSymbolNameFunc StackWalker::_UndecorateSymbolName;
  15. PFUNCTION_TABLE_ACCESS_ROUTINE StackWalker::_SymFunctionTableAccess;
  16. StackWalker::StackWalker(HANDLE hProcess)
  17. : _imageHlpDLL(NULL),
  18. _hProcess(hProcess)
  19. {
  20. _imageHlpDLL = LoadLibrary(L"imagehlp.dll");
  21. if (_imageHlpDLL != NULL) {
  22. // Get commonly used Sym* functions.
  23. if (_StackWalk == NULL) {
  24. // If one of them are null, assume
  25. // they all are. Benign race here.
  26. _StackWalk = (StackWalkFunc)GetProcAddress(_imageHlpDLL, "StackWalk");
  27. if (_StackWalk == NULL)
  28. return;
  29. _SymGetModuleInfo = (SymGetModuleInfoFunc)GetProcAddress(_imageHlpDLL,
  30. "SymGetModuleInfo");
  31. if (_SymGetModuleInfo == NULL)
  32. return;
  33. _SymGetSymFromAddr = (SymGetSymFromAddrFunc)GetProcAddress(_imageHlpDLL,
  34. "SymGetSymFromAddr");
  35. if (_SymGetSymFromAddr == NULL)
  36. return;
  37. _SymLoadModule = (SymLoadModuleFunc)GetProcAddress(_imageHlpDLL,
  38. "SymLoadModule");
  39. if (_SymLoadModule == NULL)
  40. return;
  41. _UndecorateSymbolName = (UndecorateSymbolNameFunc)GetProcAddress(_imageHlpDLL,
  42. "UnDecorateSymbolName");
  43. if (_UndecorateSymbolName == NULL)
  44. return;
  45. _SymFunctionTableAccess = (PFUNCTION_TABLE_ACCESS_ROUTINE)GetProcAddress(_imageHlpDLL,
  46. "SymFunctionTableAccess");
  47. if (_SymFunctionTableAccess == NULL)
  48. return;
  49. }
  50. // Sym* functions that we're only going to use locally.
  51. typedef BOOL (__stdcall *SymInitializeFunc)(HANDLE hProcess,
  52. LPSTR path,
  53. BOOL invadeProcess);
  54. typedef DWORD (__stdcall *SymSetOptionsFunc)(DWORD);
  55. SymInitializeFunc SymInitialize = (SymInitializeFunc)GetProcAddress(_imageHlpDLL,
  56. "SymInitialize");
  57. if (SymInitialize == NULL)
  58. return;
  59. SymSetOptionsFunc SymSetOptions = (SymSetOptionsFunc)GetProcAddress(_imageHlpDLL,
  60. "SymSetOptions");
  61. if (SymSetOptions == NULL)
  62. return;
  63. if (SymInitialize(hProcess, NULL, FALSE))
  64. SymSetOptions(0);
  65. }
  66. }
  67. StackWalker::~StackWalker() {
  68. if (_imageHlpDLL != NULL) {
  69. typedef BOOL (__stdcall *SymCleanupFunc)(HANDLE hProcess);
  70. SymCleanupFunc SymCleanup = (SymCleanupFunc)GetProcAddress(_imageHlpDLL,
  71. "SymCleanup");
  72. if (SymCleanup != NULL)
  73. SymCleanup(_hProcess);
  74. FreeLibrary(_imageHlpDLL);
  75. }
  76. }
  77. DWORD_PTR StackWalker::LoadModule(HANDLE hProcess, DWORD_PTR address) {
  78. MEMORY_BASIC_INFORMATION mbi;
  79. if (VirtualQueryEx(hProcess, (void*)address, &mbi, sizeof mbi)) {
  80. if (mbi.Type & MEM_IMAGE) {
  81. char module[MAX_PATH];
  82. DWORD cch = GetModuleFileNameA((HINSTANCE)mbi.AllocationBase,
  83. module,
  84. MAX_PATH);
  85. // Ignore the return code since we can't do anything with it.
  86. (void)_SymLoadModule(hProcess,
  87. NULL,
  88. ((cch) ? module : NULL),
  89. NULL,
  90. (DWORD_PTR) mbi.AllocationBase,
  91. 0);
  92. return (DWORD_PTR) mbi.AllocationBase;
  93. }
  94. }
  95. return 0;
  96. }
  97. Symbol* StackWalker::ResolveAddress(DWORD_PTR addr) {
  98. if (_imageHlpDLL == NULL)
  99. return NULL;
  100. // Find out what module the address lies in.
  101. char* module = NULL;
  102. IMAGEHLP_MODULE moduleInfo;
  103. moduleInfo.SizeOfStruct = sizeof moduleInfo;
  104. if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo)) {
  105. module = moduleInfo.ModuleName;
  106. }
  107. else {
  108. // First attempt failed, load the module info.
  109. LoadModule(_hProcess, addr);
  110. if (_SymGetModuleInfo(_hProcess, addr, &moduleInfo))
  111. module = moduleInfo.ModuleName;
  112. }
  113. char* symbolName = NULL;
  114. char undecoratedName[512];
  115. IMAGEHLP_SYMBOL* symbolInfo = (IMAGEHLP_SYMBOL*)_alloca(sizeof(IMAGEHLP_SYMBOL) + 512);
  116. symbolInfo->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL) + 512;
  117. symbolInfo->MaxNameLength = 512;
  118. DWORD_PTR displacement = 0;
  119. if (_SymGetSymFromAddr(_hProcess, addr, &displacement, symbolInfo)) {
  120. DWORD flags = UNDNAME_NO_MS_KEYWORDS
  121. | UNDNAME_NO_ACCESS_SPECIFIERS
  122. | UNDNAME_NO_FUNCTION_RETURNS
  123. | UNDNAME_NO_MEMBER_TYPE;
  124. if (_UndecorateSymbolName(symbolInfo->Name, undecoratedName, 512, flags))
  125. symbolName = undecoratedName;
  126. else
  127. symbolName = symbolInfo->Name;
  128. }
  129. else {
  130. displacement = addr - moduleInfo.BaseOfImage;
  131. }
  132. return new Symbol(module, symbolName, displacement);
  133. }
  134. DWORD_PTR __stdcall StackWalker::GetModuleBase(HANDLE hProcess, DWORD_PTR address) {
  135. IMAGEHLP_MODULE moduleInfo;
  136. moduleInfo.SizeOfStruct = sizeof moduleInfo;
  137. if (_SymGetModuleInfo(hProcess, address, &moduleInfo))
  138. return moduleInfo.BaseOfImage;
  139. else
  140. return LoadModule(hProcess, address);
  141. }
  142. Symbol* StackWalker::CreateStackTrace(CONTEXT* context) {
  143. if (_imageHlpDLL == NULL)
  144. return NULL;
  145. HANDLE hThread = GetCurrentThread();
  146. DWORD dwMachineType;
  147. STACKFRAME frame = {0};
  148. frame.AddrPC.Mode = AddrModeFlat;
  149. #if defined(_M_IX86)
  150. dwMachineType = IMAGE_FILE_MACHINE_I386;
  151. frame.AddrPC.Offset = context->Eip; // Program Counter
  152. frame.AddrStack.Offset = context->Esp; // Stack Pointer
  153. frame.AddrStack.Mode = AddrModeFlat;
  154. frame.AddrFrame.Offset = context->Ebp; // Frame Pointer
  155. #elif defined(_M_AMD64)
  156. dwMachineType = IMAGE_FILE_MACHINE_AMD64;
  157. frame.AddrPC.Offset = context->Rip;
  158. frame.AddrPC.Mode = AddrModeFlat;
  159. frame.AddrStack.Offset = context->Rsp;
  160. frame.AddrStack.Mode = AddrModeFlat;
  161. #elif defined(_M_IA64)
  162. dwMachineType = IMAGE_FILE_MACHINE_IA64;
  163. frame.AddrPC.Offset = context->StIIP;
  164. frame.AddrPC.Mode = AddrModeFlat;
  165. frame.AddrStack.Offset = context->IntSp;
  166. frame.AddrStack.Mode = AddrModeFlat;
  167. #else
  168. #error Unknown Target Machine
  169. #endif
  170. // These variables are used to count the number of consecutive frames
  171. // with the exact same PC returned by StackWalk(). On the Alpha infinite
  172. // loops (and infinite lists!) were being caused by StackWalk() never
  173. // returning FALSE (see Raid Bug #8354 for details).
  174. const DWORD dwMaxNumRepetitions = 40;
  175. DWORD dwRepetitions = 0;
  176. ADDRESS addrRepeated = {0, 0, AddrModeFlat};
  177. // Walk the stack...
  178. Symbol* prev = NULL;
  179. Symbol* head = NULL;
  180. for (;;) {
  181. if (!_StackWalk(dwMachineType,
  182. _hProcess,
  183. hThread,
  184. &frame,
  185. &context,
  186. NULL,
  187. _SymFunctionTableAccess,
  188. GetModuleBase,
  189. NULL))
  190. break;
  191. if (frame.AddrPC.Offset == 0)
  192. break;
  193. // Check for repeated addresses; if dwMaxNumRepetitions are found,
  194. // then we break out of the loop and exit the stack walk
  195. if (addrRepeated.Offset == frame.AddrPC.Offset &&
  196. addrRepeated.Mode == frame.AddrPC.Mode) {
  197. dwRepetitions ++;
  198. if (dwRepetitions == dwMaxNumRepetitions) {
  199. break;
  200. }
  201. } else {
  202. dwRepetitions = 0;
  203. addrRepeated.Offset = frame.AddrPC.Offset;
  204. addrRepeated.Mode = frame.AddrPC.Mode;
  205. }
  206. // There have been reports of StackWalk returning an offset of
  207. // -1, which SymLoadModule later av's on. If this happens,
  208. // we simply skip that frame.
  209. if (frame.AddrPC.Offset == -1)
  210. continue;
  211. Symbol* sym = ResolveAddress(frame.AddrPC.Offset);
  212. if (sym == NULL)
  213. break;
  214. // Append this symbol to the previous one, if any.
  215. if (prev == NULL) {
  216. prev = sym;
  217. head = sym;
  218. }
  219. else {
  220. prev->Append(sym);
  221. prev = sym;
  222. }
  223. }
  224. return head;
  225. }
  226. SIZE_T StackWalker::GetCallStackSize(Symbol* symbol)
  227. {
  228. SIZE_T nSize = 2; // Start with a "\r\n".
  229. const char* module = NULL;
  230. const char* symbolName = NULL;
  231. Symbol * sym = symbol;
  232. while (sym != NULL)
  233. {
  234. module = sym->moduleName();
  235. symbolName = sym->symbolName();
  236. nSize += lstrlenA(module);
  237. nSize += lstrlenA(symbolName);
  238. nSize += 32; // displacement, spaces, etc.
  239. sym = sym -> next();
  240. }
  241. return nSize;
  242. }
  243. BOOL StackWalker::GetCallStack(Symbol * symbol, SIZE_T nChars, WCHAR * sz, SIZE_T nMaxLines)
  244. {
  245. if (!symbol || !nChars)
  246. return FALSE;
  247. Symbol* sym = symbol;
  248. // for (int i=0;i<3;i++)
  249. // {
  250. // Symbol* tmp = sym;
  251. // sym = sym->next();
  252. // delete tmp;
  253. // if (!sym)
  254. // break;
  255. // }
  256. const char* module = NULL;
  257. const char* symbolName = NULL;
  258. char * szStack = (char * )PrivMemAlloc(nChars);
  259. ZeroMemory(szStack, nChars);
  260. lstrcpyA(szStack, "\r\n"); // Start with a CR-LF.
  261. Symbol* tmp = NULL;
  262. while (sym != NULL && nMaxLines-- > 0)
  263. {
  264. module = sym->moduleName();
  265. symbolName = sym->symbolName();
  266. if (module != NULL)
  267. {
  268. lstrcatA(szStack, module);
  269. if (symbolName != NULL)
  270. lstrcatA(szStack, "!");
  271. }
  272. if (symbolName != NULL)
  273. lstrcatA(szStack, symbolName);
  274. sym -> AppendDisplacement(szStack);
  275. lstrcatA(szStack, "\r\n");
  276. tmp = sym;
  277. sym = sym->next();
  278. delete tmp;
  279. }
  280. SIZE_T nLen = lstrlenA(szStack);
  281. nLen++;
  282. MultiByteToWideChar(CP_ACP, 0, szStack, (int) nLen, sz, (int) nLen);
  283. PrivMemFree(szStack);
  284. return TRUE;
  285. }
  286. Symbol::Symbol(const char* moduleName, const char* symbolName, DWORD_PTR displacement)
  287. : _moduleName(NULL),
  288. _symbolName(NULL),
  289. _displacement(displacement),
  290. _next(NULL)
  291. {
  292. if (moduleName != NULL)
  293. _moduleName = mystrdup(moduleName);
  294. if (symbolName != NULL)
  295. _symbolName = mystrdup(symbolName);
  296. }
  297. Symbol::~Symbol() {
  298. delete [] _moduleName;
  299. delete [] _symbolName;
  300. }
  301. void Symbol::Append(Symbol* sym) {
  302. _next = sym;
  303. }
  304. #if 0
  305. #include <iostream.h>
  306. DWORD filter(EXCEPTION_POINTERS* exp) {
  307. StackWalker resolver(GetCurrentProcess());
  308. Symbol* symbol = resolver.CreateStackTrace(exp->ContextRecord);
  309. if (symbol == NULL) {
  310. cout << "Couldn't get stack trace" << endl;
  311. }
  312. else {
  313. cout << "Stack trace:" << endl;
  314. Symbol* sym = symbol;
  315. while (sym != NULL) {
  316. const char* module = sym->moduleName();
  317. const char* symbolName = sym->symbolName();
  318. if (module != NULL) {
  319. cout << module;
  320. if (symbolName != NULL)
  321. cout << '!';
  322. }
  323. if (symbolName != NULL)
  324. cout << symbolName;
  325. cout << "+0x" << hex << sym->displacement() << dec << endl;
  326. Symbol* tmp = sym;
  327. sym = sym->next();
  328. delete tmp;
  329. }
  330. }
  331. return EXCEPTION_EXECUTE_HANDLER;
  332. }
  333. int bar(int x, int* p) {
  334. *p = x;
  335. return 5;
  336. }
  337. void foo(int* p) {
  338. bar(5, p);
  339. }
  340. int main() {
  341. __try {
  342. int* p = (int*)0xdeadbeef;
  343. foo(p);
  344. }
  345. __except (filter(GetExceptionInformation())) {
  346. }
  347. return 0;
  348. }
  349. #endif