Source code of Windows XP (NT5)
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.

434 lines
12 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_MRX000)
  156. dwMachineType = IMAGE_FILE_MACHINE_R4000;
  157. frame.AddrPC.Offset = context->Fir; // Program Counter
  158. #elif defined(_M_ALPHA)
  159. dwMachineType = IMAGE_FILE_MACHINE_ALPHA;
  160. frame.AddrPC.Offset = (DWORD_PTR) context->Fir; // Program Counter
  161. frame.AddrStack.Offset = (DWORD_PTR) context->IntSp; // Stack Pointer
  162. frame.AddrFrame.Offset = (DWORD_PTR) context->IntFp; // Frame Pointer
  163. #elif defined(_M_PPC)
  164. dwMachineType = IMAGE_FILE_MACHINE_POWERPC;
  165. frame.AddrPC.Offset = context->Iar; // Program Counter
  166. #elif defined(_M_IA64) // BUGBUG: check for correctness
  167. dwMachineType = IMAGE_FILE_MACHINE_IA64;
  168. frame.AddrPC.Offset = context->StIIP; // Program Counter
  169. frame.AddrStack.Offset = context->IntSp; //Stack Pointer
  170. frame.AddrStack.Mode = AddrModeFlat;
  171. // No Frame pointer information for IA64 (per Intel folks)
  172. //frame.AddrFrame.Offset = context->Ebp; // Frame Pointer
  173. #elif defined(_M_AXP64) // BUGBUG: check for correctness
  174. dwMachineType = IMAGE_FILE_MACHINE_AXP64;
  175. frame.AddrPC.Offset = (DWORD_PTR) context->Fir; // Program Counter
  176. frame.AddrStack.Offset = (DWORD_PTR) context->IntSp; // Stack Pointer
  177. frame.AddrFrame.Offset = (DWORD_PTR) context->IntFp; // Frame Pointer
  178. #elif defined(_M_AMD64)
  179. dwMachineType = IMAGE_FILE_MACHINE_AMD64;
  180. frame.AddrPC.Offset = (ULONG64) context->Rip; // Program Counter
  181. frame.AddrStack.Offset = (ULONG64) context->Rsp; // Stack Pointer
  182. frame.AddrFrame.Offset = (ULONG64) context->Rbp; // Frame Pointer
  183. #else
  184. #error Unknown Target Machine
  185. #endif
  186. // These variables are used to count the number of consecutive frames
  187. // with the exact same PC returned by StackWalk(). On the Alpha infinite
  188. // loops (and infinite lists!) were being caused by StackWalk() never
  189. // returning FALSE (see Raid Bug #8354 for details).
  190. const DWORD dwMaxNumRepetitions = 40;
  191. DWORD dwRepetitions = 0;
  192. ADDRESS addrRepeated = {0, 0, AddrModeFlat};
  193. // Walk the stack...
  194. Symbol* prev = NULL;
  195. Symbol* head = NULL;
  196. for (;;) {
  197. if (!_StackWalk(dwMachineType,
  198. _hProcess,
  199. hThread,
  200. &frame,
  201. &context,
  202. NULL,
  203. _SymFunctionTableAccess,
  204. GetModuleBase,
  205. NULL))
  206. break;
  207. if (frame.AddrPC.Offset == 0)
  208. break;
  209. // Check for repeated addresses; if dwMaxNumRepetitions are found,
  210. // then we break out of the loop and exit the stack walk
  211. if (addrRepeated.Offset == frame.AddrPC.Offset &&
  212. addrRepeated.Mode == frame.AddrPC.Mode) {
  213. dwRepetitions ++;
  214. if (dwRepetitions == dwMaxNumRepetitions) {
  215. break;
  216. }
  217. } else {
  218. dwRepetitions = 0;
  219. addrRepeated.Offset = frame.AddrPC.Offset;
  220. addrRepeated.Mode = frame.AddrPC.Mode;
  221. }
  222. // There have been reports of StackWalk returning an offset of
  223. // -1, which SymLoadModule later av's on. If this happens,
  224. // we simply skip that frame.
  225. if (frame.AddrPC.Offset == -1)
  226. continue;
  227. Symbol* sym = ResolveAddress(frame.AddrPC.Offset);
  228. if (sym == NULL)
  229. break;
  230. // Append this symbol to the previous one, if any.
  231. if (prev == NULL) {
  232. prev = sym;
  233. head = sym;
  234. }
  235. else {
  236. prev->Append(sym);
  237. prev = sym;
  238. }
  239. }
  240. return head;
  241. }
  242. SIZE_T StackWalker::GetCallStackSize(Symbol* symbol)
  243. {
  244. SIZE_T nSize = 2; // Start with a "\r\n".
  245. const char* module = NULL;
  246. const char* symbolName = NULL;
  247. Symbol * sym = symbol;
  248. while (sym != NULL)
  249. {
  250. module = sym->moduleName();
  251. symbolName = sym->symbolName();
  252. nSize += lstrlenA(module);
  253. nSize += lstrlenA(symbolName);
  254. nSize += 32; // displacement, spaces, etc.
  255. sym = sym -> next();
  256. }
  257. return nSize;
  258. }
  259. BOOL StackWalker::GetCallStack(Symbol * symbol, SIZE_T nChars, WCHAR * sz, SIZE_T nMaxLines)
  260. {
  261. if (!symbol || !nChars)
  262. return FALSE;
  263. Symbol* sym = symbol;
  264. // for (int i=0;i<3;i++)
  265. // {
  266. // Symbol* tmp = sym;
  267. // sym = sym->next();
  268. // delete tmp;
  269. // if (!sym)
  270. // break;
  271. // }
  272. const char* module = NULL;
  273. const char* symbolName = NULL;
  274. char * szStack = (char * )PrivMemAlloc(nChars);
  275. ZeroMemory(szStack, nChars);
  276. lstrcpyA(szStack, "\r\n"); // Start with a CR-LF.
  277. Symbol* tmp = NULL;
  278. while (sym != NULL && nMaxLines-- > 0)
  279. {
  280. module = sym->moduleName();
  281. symbolName = sym->symbolName();
  282. if (module != NULL)
  283. {
  284. lstrcatA(szStack, module);
  285. if (symbolName != NULL)
  286. lstrcatA(szStack, "!");
  287. }
  288. if (symbolName != NULL)
  289. lstrcatA(szStack, symbolName);
  290. sym -> AppendDisplacement(szStack);
  291. lstrcatA(szStack, "\r\n");
  292. tmp = sym;
  293. sym = sym->next();
  294. delete tmp;
  295. }
  296. SIZE_T nLen = lstrlenA(szStack);
  297. nLen++;
  298. MultiByteToWideChar(CP_ACP, 0, szStack, (int) nLen, sz, (int) nLen);
  299. PrivMemFree(szStack);
  300. return TRUE;
  301. }
  302. Symbol::Symbol(const char* moduleName, const char* symbolName, DWORD_PTR displacement)
  303. : _moduleName(NULL),
  304. _symbolName(NULL),
  305. _displacement(displacement),
  306. _next(NULL)
  307. {
  308. if (moduleName != NULL)
  309. _moduleName = mystrdup(moduleName);
  310. if (symbolName != NULL)
  311. _symbolName = mystrdup(symbolName);
  312. }
  313. Symbol::~Symbol() {
  314. delete [] _moduleName;
  315. delete [] _symbolName;
  316. }
  317. void Symbol::Append(Symbol* sym) {
  318. _next = sym;
  319. }
  320. #if 0
  321. #include <iostream.h>
  322. DWORD filter(EXCEPTION_POINTERS* exp) {
  323. StackWalker resolver(GetCurrentProcess());
  324. Symbol* symbol = resolver.CreateStackTrace(exp->ContextRecord);
  325. if (symbol == NULL) {
  326. cout << "Couldn't get stack trace" << endl;
  327. }
  328. else {
  329. cout << "Stack trace:" << endl;
  330. Symbol* sym = symbol;
  331. while (sym != NULL) {
  332. const char* module = sym->moduleName();
  333. const char* symbolName = sym->symbolName();
  334. if (module != NULL) {
  335. cout << module;
  336. if (symbolName != NULL)
  337. cout << '!';
  338. }
  339. if (symbolName != NULL)
  340. cout << symbolName;
  341. cout << "+0x" << hex << sym->displacement() << dec << endl;
  342. Symbol* tmp = sym;
  343. sym = sym->next();
  344. delete tmp;
  345. }
  346. }
  347. return EXCEPTION_EXECUTE_HANDLER;
  348. }
  349. int bar(int x, int* p) {
  350. *p = x;
  351. return 5;
  352. }
  353. void foo(int* p) {
  354. bar(5, p);
  355. }
  356. int main() {
  357. __try {
  358. int* p = (int*)0xdeadbeef;
  359. foo(p);
  360. }
  361. __except (filter(GetExceptionInformation())) {
  362. }
  363. return 0;
  364. }
  365. #endif