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.

683 lines
19 KiB

  1. // Ruler
  2. // 1 2 3 4 5 6 7 8
  3. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  4. /********************************************************************/
  5. /* */
  6. /* The standard layout. */
  7. /* */
  8. /* The standard layout for 'cpp' files in this code is as */
  9. /* follows: */
  10. /* */
  11. /* 1. Include files. */
  12. /* 2. Constants local to the class. */
  13. /* 3. Data structures local to the class. */
  14. /* 4. Data initializations. */
  15. /* 5. Static functions. */
  16. /* 6. Class functions. */
  17. /* */
  18. /* The constructor is typically the first function, class */
  19. /* member functions appear in alphabetical order with the */
  20. /* destructor appearing at the end of the file. Any section */
  21. /* or function this is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "LibraryPCH.hpp"
  25. #ifndef DISABLE_DEBUG_HELP
  26. #include <dbghelp.h>
  27. #endif
  28. #include "CallStack.hpp"
  29. /********************************************************************/
  30. /* */
  31. /* Compiler options. */
  32. /* */
  33. /* Ensure that the last function call(s) before 'StackWalk' */
  34. /* are not FPO-optimized. */
  35. /* */
  36. /********************************************************************/
  37. #pragma optimize("y", off)
  38. /********************************************************************/
  39. /* */
  40. /* Constants local to the class. */
  41. /* */
  42. /* The constants supplied here control the debug buffer size. */
  43. /* */
  44. /********************************************************************/
  45. CONST SBIT32 MaxBufferSize = 512;
  46. CONST SBIT32 SymbolNameLength = 512;
  47. /********************************************************************/
  48. /* */
  49. /* Static member initialization. */
  50. /* */
  51. /* Static member initialization sets the initial value for all */
  52. /* static members. */
  53. /* */
  54. /********************************************************************/
  55. BOOLEAN CALL_STACK::Active = False;
  56. SBIT32 CALL_STACK::Activations = 0;
  57. HANDLE CALL_STACK::Process = NULL;
  58. SPINLOCK CALL_STACK::Spinlock = NULL;
  59. /********************************************************************/
  60. /* */
  61. /* Class constructor. */
  62. /* */
  63. /* Create a call stack class and initialize it. This call is */
  64. /* not thread safe and should only be made in a single thread */
  65. /* environment. */
  66. /* */
  67. /********************************************************************/
  68. CALL_STACK::CALL_STACK( VOID )
  69. {
  70. //
  71. // Claim a lock to prevent multiple threads
  72. // from using the symbol lookup mechanism.
  73. //
  74. Spinlock.ClaimLock();
  75. #ifndef DISABLE_DEBUG_HELP
  76. //
  77. // We will activate the symbols if they are
  78. // not already available.
  79. //
  80. if ( ! Active )
  81. {
  82. //
  83. // Setup the process handle, load image help
  84. // and then load any available symbols.
  85. //
  86. Process = GetCurrentProcess();
  87. //
  88. // Setup the image help library.
  89. //
  90. if ( ! (Active = ((BOOLEAN) SymInitialize( Process,NULL,TRUE ))) )
  91. {
  92. //
  93. // We only issue the warning message once
  94. // when we fail to load the symbols.
  95. //
  96. if ( Activations == 0 )
  97. {
  98. //
  99. // Format the error message and output it
  100. // to the debug stream.
  101. //
  102. DebugPrint
  103. (
  104. "Missing or mismatched symbols files: %x\n",
  105. HRESULT_FROM_WIN32( GetLastError() )
  106. );
  107. }
  108. }
  109. }
  110. //
  111. // We keep track of the number of activations
  112. // so we can delete the symbols at the
  113. // required point.
  114. //
  115. Activations ++;
  116. #endif
  117. //
  118. // Release the lock.
  119. //
  120. Spinlock.ReleaseLock();
  121. //
  122. // Update the available symbols.
  123. //
  124. UpdateSymbols();
  125. }
  126. /********************************************************************/
  127. /* */
  128. /* Extract the current call stack. */
  129. /* */
  130. /* Extract the current call stack and return it to the caller */
  131. /* so it can be used later. */
  132. /* */
  133. /********************************************************************/
  134. SBIT32 CALL_STACK::GetCallStack
  135. (
  136. VOID *Frames[],
  137. SBIT32 MaxFrames,
  138. SBIT32 SkipFrames
  139. )
  140. {
  141. REGISTER SBIT32 Count = 0;
  142. #ifndef DISABLE_DEBUG_HELP
  143. //
  144. // We can only examine the symbol information if
  145. // we were able to load image help.
  146. //
  147. if ( Active )
  148. {
  149. REGISTER CONTEXT Context;
  150. REGISTER HANDLE Thread;
  151. REGISTER SBIT32 MachineType;
  152. REGISTER STACKFRAME StackFrame;
  153. //
  154. // Zero all the data structures to make
  155. // sure they are clean.
  156. //
  157. ZeroMemory( & Context,sizeof(CONTEXT) );
  158. ZeroMemory( & StackFrame,sizeof(STACKFRAME) );
  159. //
  160. // Setup the necessary flags and extract
  161. // the thread context.
  162. //
  163. Context.ContextFlags = CONTEXT_FULL;
  164. MachineType = IMAGE_FILE_MACHINE_I386;
  165. Thread = GetCurrentThread();
  166. GetThreadContext( Thread,& Context );
  167. //
  168. // Extract the details of the current
  169. // stack frame.
  170. //
  171. _asm
  172. {
  173. mov StackFrame.AddrStack.Offset, esp
  174. mov StackFrame.AddrFrame.Offset, ebp
  175. mov StackFrame.AddrPC.Offset, offset DummyLabel
  176. DummyLabel:
  177. }
  178. StackFrame.AddrPC.Mode = AddrModeFlat;
  179. StackFrame.AddrStack.Mode = AddrModeFlat;
  180. StackFrame.AddrFrame.Mode = AddrModeFlat;
  181. //
  182. // Claim a lock to prevent multiple threads
  183. // from using the symbol lookup mechanism.
  184. //
  185. Spinlock.ClaimLock();
  186. //
  187. // Walk the stack frames extracting the
  188. // details from each frame examined.
  189. //
  190. while ( Count < MaxFrames )
  191. {
  192. //
  193. // Walk the each stack frame.
  194. //
  195. if
  196. (
  197. StackWalk
  198. (
  199. MachineType,
  200. Process,
  201. Thread,
  202. & StackFrame,
  203. & Context,
  204. NULL,
  205. SymFunctionTableAccess,
  206. SymGetModuleBase,
  207. NULL
  208. )
  209. )
  210. {
  211. //
  212. // Examine and process the current
  213. // stack frame.
  214. //
  215. if ( SkipFrames <= 0 )
  216. {
  217. //
  218. // Collect the current function
  219. // address and store it.
  220. //
  221. Frames[ (Count ++) ] =
  222. ((VOID*) StackFrame.AddrPC.Offset);
  223. }
  224. else
  225. { SkipFrames --; }
  226. }
  227. else
  228. { break; }
  229. }
  230. //
  231. // Release the lock.
  232. //
  233. Spinlock.ReleaseLock();
  234. }
  235. #endif
  236. return Count;
  237. }
  238. /********************************************************************/
  239. /* */
  240. /* Format a call stack. */
  241. /* */
  242. /* We format an entire call stack into a single string ready */
  243. /* for output. */
  244. /* */
  245. /********************************************************************/
  246. VOID CALL_STACK::FormatCallStack
  247. (
  248. CHAR *Buffer,
  249. VOID *Frames[],
  250. SBIT32 MaxBuffer,
  251. SBIT32 MaxFrames
  252. )
  253. {
  254. #ifndef DISABLE_DEBUG_HELP
  255. //
  256. // We can only examine the symbol information if
  257. // we were able to load image help.
  258. //
  259. if ( Active )
  260. {
  261. REGISTER SBIT32 Count;
  262. //
  263. // Delete any existing string.
  264. //
  265. strcpy( Buffer,"" );
  266. //
  267. // Format each frame and then update the
  268. // main buffer.
  269. //
  270. for ( Count=0;Count < MaxFrames;Count ++ )
  271. {
  272. AUTO CHAR NewSymbol[ MaxBufferSize ];
  273. REGISTER SBIT32 Size;
  274. //
  275. // Format the symbol.
  276. //
  277. FormatSymbol( Frames[ Count ],NewSymbol,MaxBufferSize );
  278. //
  279. // Make sure there is enough space in the
  280. // output buffer.
  281. //
  282. if ( ((Size = strlen( NewSymbol )) + 1) < MaxBuffer)
  283. {
  284. //
  285. // Copy the symbol into the buffer.
  286. //
  287. strcpy( Buffer,NewSymbol );
  288. Buffer += Size;
  289. strcpy( Buffer ++,"\n" );
  290. MaxBuffer -= (Size + 1);
  291. }
  292. else
  293. { break; }
  294. }
  295. }
  296. else
  297. { strcpy( Buffer,"" ); }
  298. #else
  299. strcpy( Buffer,"" );
  300. #endif
  301. }
  302. #ifndef DISABLE_DEBUG_HELP
  303. /********************************************************************/
  304. /* */
  305. /* Format a single symbol. */
  306. /* */
  307. /* We format a single simple converting it from an address to */
  308. /* a text string. */
  309. /* */
  310. /********************************************************************/
  311. BOOLEAN CALL_STACK::FormatSymbol
  312. (
  313. VOID *Address,
  314. CHAR *Buffer,
  315. SBIT32 MaxBuffer
  316. )
  317. {
  318. AUTO CHAR SymbolBuffer[ (sizeof(IMAGEHLP_SYMBOL) + SymbolNameLength) ];
  319. AUTO IMAGEHLP_MODULE Module = { 0 };
  320. REGISTER BOOLEAN Result = True;
  321. REGISTER PIMAGEHLP_SYMBOL Symbol = ((PIMAGEHLP_SYMBOL) SymbolBuffer);
  322. //
  323. // Setup values ready for main symbol
  324. // extraction function body.
  325. //
  326. Module.SizeOfStruct = sizeof(IMAGEHLP_MODULE);
  327. ZeroMemory( Symbol,(sizeof(IMAGEHLP_SYMBOL) + SymbolNameLength) );
  328. Symbol -> SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
  329. Symbol -> MaxNameLength = SymbolNameLength;
  330. //
  331. // Claim a lock to prevent multiple threads
  332. // from using the symbol lookup mechanism.
  333. //
  334. Spinlock.ClaimLock();
  335. //
  336. // Extract the module information for the
  337. // symbol and format it.
  338. //
  339. if ( SymGetModuleInfo( Process,((DWORD) Address),& Module ) )
  340. {
  341. REGISTER SBIT32 Size;
  342. //
  343. // Make sure there is enough space in the
  344. // output buffer.
  345. //
  346. if ( ((Size = strlen( Module.ModuleName )) + 1) < MaxBuffer)
  347. {
  348. //
  349. // Copy the module name into the buffer.
  350. //
  351. strcpy( Buffer,Module.ModuleName );
  352. Buffer += Size;
  353. strcpy( Buffer ++,"!" );
  354. MaxBuffer -= (Size + 1);
  355. }
  356. }
  357. else
  358. {
  359. REGISTER SBIT32 Size;
  360. //
  361. // Make sure there is enough space in the
  362. // output buffer.
  363. //
  364. if ( (Size = strlen( "None!" )) < MaxBuffer)
  365. {
  366. //
  367. // Copy the module name into the buffer.
  368. //
  369. strcpy( Buffer,"None!" );
  370. Buffer += Size;
  371. MaxBuffer -= Size;
  372. }
  373. //
  374. // We failed to extract the module name.
  375. //
  376. Result = False;
  377. }
  378. //
  379. // We will not even bother to try to decode
  380. // the symbol if we can't decode the module.
  381. //
  382. if ( Result )
  383. {
  384. AUTO CHAR SymbolName[ SymbolNameLength ];
  385. AUTO DWORD Offset = 0;
  386. //
  387. // Try to convert the symbol from an
  388. // address to a name.
  389. //
  390. if
  391. (
  392. SymGetSymFromAddr
  393. (
  394. Process,
  395. ((DWORD) Address),
  396. & Offset,
  397. Symbol
  398. )
  399. )
  400. {
  401. REGISTER SBIT32 Size;
  402. //
  403. // Try to undecorate the name. If
  404. // this fails just use the decorated
  405. // name is it is better than nothing.
  406. //
  407. if ( ! SymUnDName( Symbol,SymbolName,sizeof(SymbolName) ) )
  408. { lstrcpynA( SymbolName,& Symbol->Name[1],sizeof(SymbolName) ); }
  409. //
  410. // Make sure there is enough space in the
  411. // output buffer.
  412. //
  413. if ( (Size = strlen( SymbolName )) < MaxBuffer)
  414. {
  415. //
  416. // Copy the symbol name into the buffer.
  417. //
  418. strcpy( Buffer,SymbolName );
  419. Buffer += Size;
  420. MaxBuffer -= Size;
  421. }
  422. //
  423. // Format the offset if is is non-zero.
  424. //
  425. if ( Offset != 0 )
  426. {
  427. //
  428. // Format the symbol offset.
  429. //
  430. sprintf( SymbolName,"+0x%x",Offset );
  431. //
  432. // Make sure there is enough space in the
  433. // output buffer.
  434. //
  435. if ( (Size = strlen( SymbolName )) < MaxBuffer)
  436. {
  437. //
  438. // Copy the symbol name into the buffer.
  439. //
  440. strcpy( Buffer,SymbolName );
  441. Buffer += Size;
  442. MaxBuffer -= Size;
  443. }
  444. }
  445. }
  446. else
  447. {
  448. REGISTER SBIT32 Size;
  449. //
  450. // Format the symbol address.
  451. //
  452. sprintf( SymbolName,"0x%p",Address );
  453. //
  454. // Make sure there is enough space in the
  455. // output buffer.
  456. //
  457. if ( (Size = strlen( SymbolName )) < MaxBuffer)
  458. {
  459. //
  460. // Copy the symbol name into the buffer.
  461. //
  462. strcpy( Buffer,SymbolName );
  463. Buffer += Size;
  464. MaxBuffer -= Size;
  465. }
  466. //
  467. // We failed to extract the symbol name.
  468. //
  469. Result = False;
  470. }
  471. }
  472. else
  473. {
  474. AUTO CHAR SymbolName[ SymbolNameLength ];
  475. REGISTER SBIT32 Size;
  476. //
  477. // Format the symbol address.
  478. //
  479. sprintf( SymbolName,"0x%p",Address );
  480. //
  481. // Make sure there is enough space in the
  482. // output buffer.
  483. //
  484. if ( (Size = strlen( SymbolName )) < MaxBuffer)
  485. {
  486. //
  487. // Copy the symbol name into the buffer.
  488. //
  489. strcpy( Buffer,SymbolName );
  490. Buffer += Size;
  491. MaxBuffer -= Size;
  492. }
  493. }
  494. //
  495. // Release the lock.
  496. //
  497. Spinlock.ReleaseLock();
  498. return Result;
  499. }
  500. /********************************************************************/
  501. /* */
  502. /* Load symbols callback. */
  503. /* */
  504. /* When we load the symbols we get a callback for every module */
  505. /* that is currently loaded into the application. */
  506. /* */
  507. /********************************************************************/
  508. BOOL STDCALL CALL_STACK::UpdateSymbolCallback
  509. (
  510. PSTR Module,
  511. ULONG_PTR BaseOfDLL,
  512. ULONG SizeOfDLL,
  513. VOID *Context
  514. )
  515. {
  516. if ( SymGetModuleBase( Process,BaseOfDLL ) == 0 )
  517. { SymLoadModule( Process,NULL,Module,NULL,BaseOfDLL,SizeOfDLL ); }
  518. return TRUE;
  519. }
  520. #endif
  521. /********************************************************************/
  522. /* */
  523. /* Load the symbols. */
  524. /* */
  525. /* Load the symbols for the current process so we can translate */
  526. /* code addresses into names. */
  527. /* */
  528. /********************************************************************/
  529. BOOLEAN CALL_STACK::UpdateSymbols( VOID )
  530. {
  531. REGISTER BOOLEAN Result = True;
  532. #ifndef DISABLE_DEBUG_HELP
  533. //
  534. // We can only examine the symbol information if
  535. // we were able to load image help.
  536. //
  537. if ( Active )
  538. {
  539. //
  540. // Claim a lock to prevent multiple threads
  541. // from using the symbol lookup mechanism.
  542. //
  543. Spinlock.ClaimLock();
  544. //
  545. // Enumaerate all of the loaded modules and
  546. // cascade load all of the symbols.
  547. //
  548. if ( ! EnumerateLoadedModules( Process,UpdateSymbolCallback,NULL ) )
  549. {
  550. //
  551. // Format the error message and output it
  552. // to the debug window.
  553. //
  554. DebugPrint
  555. (
  556. "EnumerateLoadedModules returned: %x\n",
  557. HRESULT_FROM_WIN32( GetLastError() )
  558. );
  559. Result = False;
  560. }
  561. //
  562. // Release the lock.
  563. //
  564. Spinlock.ReleaseLock();
  565. }
  566. #endif
  567. return Result;
  568. }
  569. /********************************************************************/
  570. /* */
  571. /* Class destructor. */
  572. /* */
  573. /* Destory the call stack. This call is not thread safe and */
  574. /* should only be made in a single thread environment. */
  575. /* */
  576. /********************************************************************/
  577. CALL_STACK::~CALL_STACK( VOID )
  578. {
  579. //
  580. // Claim a lock to prevent multiple threads
  581. // from using the symbol lookup mechanism.
  582. //
  583. Spinlock.ClaimLock();
  584. #ifndef DISABLE_DEBUG_HELP
  585. //
  586. // Cleanup the symbol library.
  587. //
  588. if ( ((-- Activations) == 0) && (Active) )
  589. {
  590. Active = False;
  591. //
  592. // I don't understand why this does not work at
  593. // the moment so I will fix it later.
  594. //
  595. // SymCleanup( Process );
  596. //
  597. // Just to be neat lets zero everything.
  598. //
  599. Process = NULL;
  600. }
  601. #endif
  602. //
  603. // Release the lock.
  604. //
  605. Spinlock.ReleaseLock();
  606. }