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.

676 lines
18 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. tls.cpp
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Deon Brewis (deonb) 2-Jun-2002
  9. Environment:
  10. User Mode.
  11. Kernel Mode.
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <time.h>
  17. #define TLS_ALL -2
  18. #define TLS_CURRENT -1
  19. // #define TLS_DBG
  20. #ifdef TLS_DBG
  21. #define trace dprintf
  22. #else
  23. #define trace __noop
  24. #endif
  25. EXTERN_C BOOL GetTeb32FromWowTeb(ULONG64 Teb, PULONG64 pTeb32); // implemented in peb.c
  26. EXTERN_C BOOL GetPeb32FromWowTeb(ULONG64 Teb, PULONG64 pPeb32); // implemented in peb.c
  27. BOOLEAN TestBit (
  28. IN PRTL_BITMAP BitMapHeader,
  29. IN ULONG BitNumber
  30. )
  31. {
  32. PCHAR ByteAddress;
  33. ULONG ShiftCount;
  34. ASSERT(BitNumber < BitMapHeader->SizeOfBitMap);
  35. ByteAddress = (PCHAR)BitMapHeader->Buffer + (BitNumber >> 3);
  36. ShiftCount = BitNumber & 0x7;
  37. return (BOOLEAN)((*ByteAddress >> ShiftCount) & 1);
  38. }
  39. ULONG64 GetPebForTarget()
  40. {
  41. ULONG64 pebAddress;
  42. ULONG64 peb;
  43. pebAddress = GetExpression("@$peb");
  44. ULONG64 tebAddress;
  45. tebAddress = GetExpression("@$teb");
  46. if (tebAddress)
  47. {
  48. if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress)
  49. {
  50. ULONG64 Peb32=0;
  51. if (GetPeb32FromWowTeb(tebAddress, &Peb32) && Peb32)
  52. {
  53. trace("Wow64 PEB32 at %lx\n", Peb32);
  54. pebAddress = Peb32;
  55. }
  56. }
  57. }
  58. if (pebAddress)
  59. {
  60. trace( "PEB at %p\n", pebAddress );
  61. peb = IsPtr64() ? pebAddress : (ULONG64)(LONG64)(LONG)pebAddress;
  62. }
  63. else
  64. {
  65. trace( "PEB NULL...\n" );
  66. peb = 0;
  67. }
  68. return peb;
  69. }
  70. ULONG64 GetTebForTarget(ULONG64 ulThread)
  71. {
  72. trace("GetTebForTarget %p\n", ulThread);
  73. ULONG64 tebAddress;
  74. ULONG64 teb;
  75. if (TLS_ALL == ulThread)
  76. {
  77. return 0;
  78. }
  79. if (TLS_CURRENT == ulThread)
  80. {
  81. tebAddress = GetExpression("@$teb");
  82. }
  83. else
  84. {
  85. tebAddress = ulThread; // GetTebForThread!!
  86. }
  87. if ( tebAddress )
  88. {
  89. if (TargetMachine == IMAGE_FILE_MACHINE_IA64 && tebAddress)
  90. {
  91. ULONG64 Teb32=0;
  92. if (GetTeb32FromWowTeb(tebAddress, &Teb32) && Teb32)
  93. {
  94. trace("Wow64 TEB32 at %p\n", Teb32);
  95. tebAddress = Teb32;
  96. trace("\n\nWow64 ");
  97. }
  98. }
  99. trace( "TEB at %p\n", tebAddress);
  100. }
  101. else
  102. {
  103. trace( "TEB NULL...\n" );
  104. teb = 0;
  105. }
  106. if (tebAddress)
  107. {
  108. teb = IsPtr64() ? tebAddress : (ULONG64)(LONG64)(LONG)tebAddress;
  109. }
  110. else
  111. {
  112. teb = 0;
  113. }
  114. return teb;
  115. }
  116. // Function: HrReadPRtlBitmap
  117. //
  118. // Arguments: Address [in] Location of RTL BITMAP
  119. // pRtlBitmap [out] RTL Bitmap. Free with LocalFree / not
  120. HRESULT HrReadPRtlBitmap(IN ULONG64 pAddress, OUT PRTL_BITMAP *ppRtlBitmap)
  121. {
  122. HRESULT hr = S_OK;
  123. if (!pAddress || !ppRtlBitmap)
  124. {
  125. return E_INVALIDARG;
  126. }
  127. ULONG64 Address;
  128. if (!ReadPointer(pAddress, &Address))
  129. {
  130. *ppRtlBitmap = NULL;
  131. return E_FAIL;
  132. }
  133. DWORD dwPtrSize;
  134. if (IsPtr64())
  135. {
  136. dwPtrSize = sizeof(DWORD64);
  137. }
  138. else
  139. {
  140. dwPtrSize = sizeof(DWORD);
  141. }
  142. ULONG SizeOfBitMap;
  143. if (ReadMemory(Address, &SizeOfBitMap, sizeof(SizeOfBitMap), NULL))
  144. {
  145. *ppRtlBitmap = reinterpret_cast<PRTL_BITMAP>(LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(RTL_BITMAP) + (SizeOfBitMap / 8) ));
  146. if (*ppRtlBitmap)
  147. {
  148. // Create an internal pointer into itself
  149. (*ppRtlBitmap)->Buffer = reinterpret_cast<PULONG>(reinterpret_cast<LPBYTE>(*ppRtlBitmap) + sizeof(RTL_BITMAP));
  150. (*ppRtlBitmap)->SizeOfBitMap = SizeOfBitMap;
  151. ULONG64 pBuffer = NULL;
  152. if (ReadPointer(Address + dwPtrSize, &pBuffer))
  153. {
  154. if (!ReadMemory(pBuffer, (*ppRtlBitmap)->Buffer, SizeOfBitMap / 8, NULL))
  155. {
  156. hr = E_FAIL;
  157. }
  158. }
  159. else
  160. {
  161. hr = E_FAIL;
  162. }
  163. if (FAILED(hr))
  164. {
  165. LocalFree(*ppRtlBitmap);
  166. *ppRtlBitmap = NULL;
  167. }
  168. }
  169. else
  170. {
  171. hr = E_OUTOFMEMORY;
  172. }
  173. }
  174. return hr;
  175. }
  176. #define return_msg(hr, msg) dprintf(msg); return hr;
  177. //
  178. // Function: DumpTls
  179. //
  180. // Arguments:
  181. // ulSlot [in] Slot id || TLS_ALL for all.
  182. // ulThread [in] Thread id || TLS_CURRENT for current || TLS_ALL for all
  183. //
  184. // Returns: S_OK is succeeded
  185. //
  186. HRESULT
  187. DumpTls (
  188. IN ULONG ulSlot,
  189. IN ULONG64 ulThread,
  190. IN LPCWSTR szThreadDescription
  191. )
  192. {
  193. HRESULT hr;
  194. trace("DUMPTLS: %p %p\n", ulSlot, ulThread);
  195. if ( (TLS_ALL != ulSlot) && (ulSlot > 1088) )
  196. {
  197. return_msg (E_INVALIDARG, "Slot must be 0 to 1088 (or -1 to dump slot 0)\n");
  198. }
  199. ULONG64 Peb = GetPebForTarget();
  200. if (!Peb)
  201. {
  202. return_msg (E_INVALIDARG, "Could not get Peb for target - check your symbols for nt!\n");
  203. }
  204. trace("Peb = %p\n", Peb);
  205. ULONG64 Teb = GetTebForTarget(ulThread);
  206. if (!Teb)
  207. {
  208. return_msg (E_INVALIDARG, "Could not get Teb for target - check your symbols for nt!\n");
  209. }
  210. trace("Teb = %p\n", Teb);
  211. WCHAR szOwnDescription[MAX_PATH];
  212. if ( (TLS_CURRENT == ulThread) && !szThreadDescription)
  213. {
  214. ULONG64 ethread = GetExpression("@$thread");
  215. if (ethread)
  216. {
  217. if (ERROR_SUCCESS == InitTypeRead(ethread, nt!_ETHREAD))
  218. {
  219. ULONG64 Cid_UniqueProcess = GetExpression("@$tpid");
  220. ULONG64 Cid_UniqueThread = GetExpression("@$tid");
  221. if (Cid_UniqueProcess && Cid_UniqueThread)
  222. {
  223. trace("%04x %1p.%1p\n", ulSlot, Cid_UniqueProcess, Cid_UniqueThread);
  224. swprintf(szOwnDescription, L"%I64x.%I64x", Cid_UniqueProcess, Cid_UniqueThread);
  225. szThreadDescription = szOwnDescription;
  226. }
  227. }
  228. }
  229. }
  230. if (TLS_ALL == ulSlot)
  231. {
  232. if (szThreadDescription)
  233. {
  234. dprintf("TLS slots on thread: %S\n", szThreadDescription);
  235. }
  236. else
  237. {
  238. dprintf("TLS slots on thread: %p\n", Teb);
  239. }
  240. }
  241. DWORD dwPtrSize;
  242. if (IsPtr64())
  243. {
  244. dwPtrSize = sizeof(DWORD64);
  245. }
  246. else
  247. {
  248. dwPtrSize = sizeof(DWORD);
  249. }
  250. hr = E_FAIL;
  251. PRTL_BITMAP pTlsBitmap = NULL;
  252. PRTL_BITMAP pTlsExpansionBitmap = NULL;
  253. ULONG TlsBitmap_Offset;
  254. GetFieldOffset("PEB", "TlsBitmap", &TlsBitmap_Offset);
  255. if (TlsBitmap_Offset)
  256. {
  257. ULONG TlsExpansionBitmap_Offset;
  258. GetFieldOffset("PEB", "TlsExpansionBitmap", &TlsExpansionBitmap_Offset);
  259. if (TlsExpansionBitmap_Offset)
  260. {
  261. hr = HrReadPRtlBitmap(Peb + TlsBitmap_Offset, &pTlsBitmap);
  262. if (SUCCEEDED(hr))
  263. {
  264. hr = HrReadPRtlBitmap(Peb + TlsExpansionBitmap_Offset, &pTlsExpansionBitmap);
  265. if (SUCCEEDED(hr))
  266. {
  267. trace("pTlsBitmap: %p\n", pTlsBitmap);
  268. trace("pTlsExpansionBitmap: %p\n", pTlsExpansionBitmap);
  269. }
  270. }
  271. }
  272. }
  273. if (FAILED(hr))
  274. {
  275. LocalFree(pTlsBitmap);
  276. LocalFree(pTlsExpansionBitmap);
  277. return_msg (E_FAIL, "Could not get read TlsBitmap or TlsExpansionBitmap in peb - check your symbols for nt!\n");
  278. }
  279. hr = E_FAIL;
  280. ULONG TlsSlots_Offset;
  281. ULONG TlsExpansionSlots_Offset;
  282. GetFieldOffset("TEB", "TlsSlots", &TlsSlots_Offset);
  283. if (TlsSlots_Offset)
  284. {
  285. GetFieldOffset("TEB", "TlsExpansionSlots", &TlsExpansionSlots_Offset);
  286. if (TlsExpansionSlots_Offset)
  287. {
  288. hr = S_OK;
  289. }
  290. }
  291. if (FAILED(hr))
  292. {
  293. LocalFree(pTlsBitmap);
  294. LocalFree(pTlsExpansionBitmap);
  295. return_msg (E_FAIL, "Could not get read TlsSlots or TlsExpansionSlots in teb - check your symbols for nt!\n");
  296. }
  297. if (TLS_ALL == ulSlot)
  298. {
  299. trace("All slots\n");
  300. LPBYTE arrTlsSlots = new BYTE[dwPtrSize * 1088];
  301. if (arrTlsSlots)
  302. {
  303. hr = E_FAIL;
  304. if (ReadMemory(Teb + TlsSlots_Offset, arrTlsSlots, 64 * dwPtrSize, NULL))
  305. {
  306. ULONG64 pTlsExpansionSlots;
  307. if (ReadPointer(Teb + TlsExpansionSlots_Offset, &pTlsExpansionSlots))
  308. {
  309. hr = S_OK;
  310. if (pTlsExpansionSlots)
  311. {
  312. if (!ReadMemory(pTlsExpansionSlots, arrTlsSlots + (64 * dwPtrSize), 1024, NULL))
  313. {
  314. hr = E_FAIL;
  315. }
  316. }
  317. }
  318. }
  319. if (FAILED(hr))
  320. {
  321. delete[] arrTlsSlots;
  322. LocalFree(pTlsBitmap);
  323. LocalFree(pTlsExpansionBitmap);
  324. return_msg (E_FAIL, "Could not read content of Tls Slots from teb - check your symbols for nt!\n");
  325. }
  326. BOOL bFound = FALSE;
  327. for (int x = 0; x < 1088; x++)
  328. {
  329. if (CheckControlC())
  330. {
  331. delete[] arrTlsSlots;
  332. LocalFree(pTlsBitmap);
  333. LocalFree(pTlsExpansionBitmap);
  334. return FALSE;
  335. }
  336. BOOL bSet = FALSE;
  337. if (x < TLS_MINIMUM_AVAILABLE)
  338. {
  339. if (!TestBit(pTlsBitmap, x))
  340. {
  341. continue;
  342. }
  343. else
  344. {
  345. bFound = TRUE;;
  346. }
  347. }
  348. else
  349. {
  350. if (!TestBit(pTlsExpansionBitmap, x - TLS_MINIMUM_AVAILABLE))
  351. {
  352. continue;
  353. }
  354. else
  355. {
  356. bFound = TRUE;;
  357. }
  358. }
  359. if ( sizeof(DWORD64) == dwPtrSize )
  360. {
  361. dprintf("0x%04x : %p\n", x, reinterpret_cast<DWORD64*>(arrTlsSlots)[x]);
  362. }
  363. else
  364. {
  365. dprintf("0x%04x : %p\n", x, reinterpret_cast<DWORD*>(arrTlsSlots)[x]);
  366. }
  367. }
  368. if (!bFound)
  369. {
  370. dprintf(" No TLS slots have been allocated for this process.\n");
  371. }
  372. delete[] arrTlsSlots;
  373. }
  374. }
  375. else
  376. {
  377. ULONG64 Tls_Location = 0;
  378. if (ulSlot < TLS_MINIMUM_AVAILABLE)
  379. {
  380. Tls_Location = Teb + TlsSlots_Offset + ulSlot * dwPtrSize;
  381. }
  382. else
  383. {
  384. if (ReadPointer(Teb + TlsExpansionSlots_Offset, &Tls_Location))
  385. {
  386. Tls_Location += (ulSlot * dwPtrSize);
  387. }
  388. }
  389. if (!Tls_Location)
  390. {
  391. LocalFree(pTlsBitmap);
  392. LocalFree(pTlsExpansionBitmap);
  393. return_msg (E_FAIL, "Could not read content TlsLocation from teb - check your symbols for nt!\n");
  394. }
  395. ULONG64 Tls_SlotX;
  396. if (ReadPointer(Tls_Location, &Tls_SlotX))
  397. {
  398. if (szThreadDescription)
  399. {
  400. dprintf("%S: %p\n", szThreadDescription, Tls_SlotX);
  401. }
  402. else
  403. {
  404. dprintf("%I64x: %p\n", Teb, szThreadDescription, Tls_SlotX);
  405. }
  406. }
  407. else
  408. {
  409. dprintf("Could not read TLS value from %p - check your symbols for nt!\n", Tls_Location);
  410. }
  411. }
  412. LocalFree(pTlsBitmap);
  413. LocalFree(pTlsExpansionBitmap);
  414. return TRUE;
  415. }
  416. HRESULT DumpThreadsUserMode(ULONG ulSlot)
  417. {
  418. ULONG ulOldThread;
  419. HRESULT hr = g_ExtSystem->GetCurrentThreadId(&ulOldThread);
  420. if (SUCCEEDED(hr))
  421. {
  422. ULONG ulNumThreads;
  423. hr = g_ExtSystem->GetNumberThreads(&ulNumThreads);
  424. if (SUCCEEDED(hr))
  425. {
  426. trace("Threads (current %d): %d\n", ulOldThread, ulNumThreads);
  427. PULONG pIds = new ULONG[ulNumThreads];
  428. if (pIds)
  429. {
  430. PULONG pSysIds = new ULONG[ulNumThreads];
  431. if (pSysIds)
  432. {
  433. hr = g_ExtSystem->GetThreadIdsByIndex(0, ulNumThreads, pIds, pSysIds);
  434. if (SUCCEEDED(hr))
  435. {
  436. if (TLS_ALL != ulSlot)
  437. {
  438. dprintf("Per-thread values for slot 0x%03x:\n", static_cast<DWORD>(ulSlot));
  439. }
  440. for (ULONG x = 0; x < ulNumThreads; x++)
  441. {
  442. hr = g_ExtSystem->SetCurrentThreadId(pIds[x]);
  443. if (SUCCEEDED(hr))
  444. {
  445. ULONG64 Cid_UniqueProcess = GetExpression("@$tpid");
  446. ULONG64 teb;
  447. g_ExtSystem->GetCurrentThreadTeb(&teb);
  448. WCHAR szThreadDescription[MAX_PATH];
  449. swprintf(szThreadDescription, L"%I64x.%1x", Cid_UniqueProcess, pSysIds[x]);
  450. trace("Thread: %d %d %x %x\n", x, pIds[x], pSysIds[x], teb);
  451. DumpTls (ulSlot, teb, szThreadDescription);
  452. }
  453. }
  454. }
  455. delete[] pSysIds;
  456. }
  457. delete[] pIds;
  458. }
  459. }
  460. g_ExtSystem->SetCurrentThreadId(ulOldThread);
  461. }
  462. return S_OK;
  463. }
  464. ULONG
  465. ThreadListCallback (
  466. PFIELD_INFO NextThrd,
  467. PVOID Context
  468. )
  469. {
  470. ULONG ulSlot = static_cast<ULONG>(reinterpret_cast<ULONG_PTR>(Context));
  471. ULONG64 RealThreadBase = NextThrd->address;
  472. if (!IsPtr64())
  473. {
  474. RealThreadBase = (ULONG64) (LONG64) (LONG) RealThreadBase;
  475. }
  476. trace("Reading %p\n", RealThreadBase);
  477. if (InitTypeRead(RealThreadBase, nt!_ETHREAD))
  478. {
  479. dprintf("*** Error in in reading nt!_ETHREAD @ %p\n", RealThreadBase);
  480. return TRUE;
  481. }
  482. ULONG64 Cid_UniqueProcess = ReadField(Cid.UniqueProcess);
  483. ULONG64 Cid_UniqueThread = ReadField(Cid.UniqueThread);
  484. ULONG64 Teb = ReadField(Tcb.Teb);
  485. trace("%04x %1p.%1p %1p\n", ulSlot, Cid_UniqueProcess, Cid_UniqueThread, Teb);
  486. WCHAR szThreadDescription[MAX_PATH];
  487. swprintf(szThreadDescription, L"%I64x.%I64x", Cid_UniqueProcess, Cid_UniqueThread);
  488. DumpTls (ulSlot, Teb, szThreadDescription);
  489. return FALSE;
  490. }
  491. HRESULT DumpThreadsKernelMode(ULONG ulSlot)
  492. {
  493. trace("DumpThreadsKernelMode %p %p\n", ulSlot);
  494. ULONG64 ThreadListHead_Flink = 0;
  495. ULONG64 process = GetExpression("@$proc");
  496. trace("Process is %p\n", process);
  497. GetFieldValue(process, "nt!_EPROCESS", "Pcb.ThreadListHead.Flink", ThreadListHead_Flink);
  498. trace("GetFieldValue returned %p\n", ThreadListHead_Flink);
  499. ULONG64 Next;
  500. if (!ReadPointer(ThreadListHead_Flink, &Next) ||
  501. (Next == ThreadListHead_Flink))
  502. {
  503. trace("Empty\n");
  504. return S_OK;
  505. }
  506. if (TLS_ALL != ulSlot)
  507. {
  508. dprintf("Per-thread values for slot 0x%03x:\n", static_cast<DWORD>(ulSlot));
  509. }
  510. ULONG ulList = ListType("nt!_ETHREAD", ThreadListHead_Flink, 1,
  511. "Tcb.ThreadListEntry.Flink", reinterpret_cast<LPVOID>(static_cast<ULONG_PTR>(ulSlot)), &ThreadListCallback);
  512. trace("ListType returned %x\n",ListType);
  513. return S_OK;
  514. }
  515. DECLARE_API( tls )
  516. {
  517. ULONG64 ulProcess = NULL;
  518. ULONG64 ulThread = NULL;
  519. ULONG64 ul64Slot = NULL;
  520. ULONG ulSlot = NULL;
  521. INIT_API();
  522. BOOL bKernelMode = FALSE;
  523. KDDEBUGGER_DATA64 kdd;
  524. if (GetDebuggerData('GBDK', &kdd, sizeof(kdd)))
  525. {
  526. bKernelMode = TRUE;
  527. }
  528. // Skip past leading spaces
  529. while (*args == ' ')
  530. {
  531. args++;
  532. }
  533. if (!GetExpressionEx(args, &ul64Slot, &args))
  534. {
  535. dprintf("Usage:\n"
  536. "tls <slot> [teb]\n"
  537. " slot: -1 to dump all allocated slots\n"
  538. " {0-1088} to dump specific slot\n"
  539. " teb: <empty> for current thread\n"
  540. " 0 for all threads in this process\n"
  541. " <teb address> (not threadid) to dump for specific thread.\n"
  542. );
  543. return S_OK;
  544. }
  545. ulSlot = static_cast<ULONG>(ul64Slot);
  546. if (ulSlot == -1)
  547. {
  548. ulSlot = TLS_ALL;
  549. }
  550. if (!GetExpressionEx(args, &ulThread, &args))
  551. {
  552. ulThread = TLS_CURRENT;
  553. }
  554. if (0 == ulThread)
  555. {
  556. if (bKernelMode)
  557. {
  558. DumpThreadsKernelMode(ulSlot);
  559. }
  560. else
  561. {
  562. DumpThreadsUserMode(ulSlot);
  563. }
  564. }
  565. else
  566. {
  567. DumpTls (ulSlot, ulThread, NULL);
  568. }
  569. EXIT_API();
  570. return S_OK;
  571. }