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.

563 lines
13 KiB

  1. /*++
  2. Module Name:
  3. regleaks.cxx
  4. Abstract:
  5. Debugger extensions for class store.
  6. Author:
  7. UShaji (Adapted from extensions, MarioGo, MazharM, JRoberts)
  8. --*/
  9. #include <stddef.h>
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <limits.h>
  13. #include "nt.h"
  14. #include "ntrtl.h"
  15. #include "nturtl.h"
  16. #include "windows.h"
  17. // #include "stkwalk.h"
  18. #include <imagehlp.h>
  19. #include "wdbgexts.h"
  20. #include "regexts.hxx"
  21. //
  22. // globals
  23. //
  24. WINDBG_EXTENSION_APIS ExtensionApis;
  25. USHORT SavedMajorVersion = 0;
  26. USHORT SavedMinorVersion = 0;
  27. HANDLE ProcessHandle = 0;
  28. BOOL fKernelDebug = FALSE;
  29. UEnvReadMemory ReadMemoryExt = ReadMemoryUserMode;
  30. UEnvReadMemory WriteMemoryExt = ReadMemoryUserMode;
  31. //
  32. // macros
  33. //
  34. /*
  35. #define ExtensionRoutinePrologue() if (!fKernelDebug) \
  36. { \
  37. ExtensionApis = *lpExtensionApis; \
  38. ReadMemoryExt = ReadMemoryUserMode; \
  39. WriteMemoryExt = WriteMemoryUserMode; \
  40. } \
  41. ULONG_PTR dwAddr = GetExpression(lpArgumentString); \
  42. */
  43. #define ALLOC_SIZE 500
  44. #define MAX_ARGS 4
  45. // define our own operators new and delete, so that we do not have to include the crt
  46. void * __cdecl
  47. ::operator new(unsigned int dwBytes)
  48. {
  49. void *p;
  50. p = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytes);
  51. return (p);
  52. }
  53. void __cdecl
  54. ::operator delete (void *p)
  55. {
  56. HeapFree(GetProcessHeap(), 0, p);
  57. }
  58. BOOL
  59. ReadMemoryUserMode( HANDLE hProcess, const void* pAddress, void* pBuffer, DWORD dwSize, DWORD* pdwRead )
  60. {
  61. return ReadProcessMemory( hProcess, pAddress, pBuffer, dwSize, pdwRead );
  62. }
  63. BOOL
  64. ReadMemoryKernelMode( HANDLE, const void* pAddress, void* pBuffer, DWORD dwSize, DWORD* pdwRead )
  65. {
  66. return ReadMemory( (ULONG) pAddress, pBuffer, dwSize, pdwRead );
  67. }
  68. BOOL
  69. WriteMemoryUserMode( HANDLE hProcess, const void* pAddress, void* pBuffer, DWORD dwSize, DWORD* pdwRead )
  70. {
  71. return WriteProcessMemory( hProcess, (void*) pAddress, pBuffer, dwSize, pdwRead );
  72. }
  73. BOOL
  74. WriteMemoryKernelMode( HANDLE, const void* pAddress, void* pBuffer, DWORD dwSize, DWORD* pdwRead )
  75. {
  76. return WriteMemory( (ULONG) pAddress, pBuffer, dwSize, pdwRead );
  77. }
  78. BOOL
  79. GetData(IN DWORD dwAddress, IN LPVOID ptr, IN ULONG size, IN PCSTR type )
  80. {
  81. BOOL b;
  82. ULONG BytesRead;
  83. ULONG count;
  84. if (!fKernelDebug)
  85. {
  86. return ReadMemoryExt(ProcessHandle, (LPVOID) dwAddress, ptr, size, 0);
  87. }
  88. else {
  89. }
  90. while( size > 0 )
  91. {
  92. count = MIN( size, 3000 );
  93. b = ReadMemoryExt(ProcessHandle, (LPVOID) dwAddress, ptr, count, &BytesRead );
  94. if (!b || BytesRead != count )
  95. {
  96. if (NULL == type)
  97. {
  98. type = "unspecified" ;
  99. }
  100. dprintf("Couldn't read memory with error %d\n", GetLastError());
  101. return FALSE;
  102. }
  103. dwAddress += count;
  104. size -= count;
  105. ptr = (LPVOID)((ULONG)ptr + count);
  106. }
  107. return TRUE;
  108. }
  109. #define MAX_MESSAGE_BLOCK_SIZE 1024
  110. #define BLOCK_SIZE 2
  111. // could have been bigger but hit the boundary case once.
  112. WCHAR *ReadProcessChar(
  113. unsigned short * Address
  114. )
  115. {
  116. DWORD dwAddr = (DWORD) Address;
  117. char block[BLOCK_SIZE];
  118. WCHAR *Block = (WCHAR *)&block;
  119. char *string_block = new char[MAX_MESSAGE_BLOCK_SIZE];
  120. WCHAR *String = (WCHAR *)string_block;
  121. int length = 0;
  122. int i = 0;
  123. BOOL b;
  124. BOOL end = FALSE;
  125. if (dwAddr == NULL) {
  126. return (L'\0');
  127. }
  128. for (length = 0; length < MAX_MESSAGE_BLOCK_SIZE/2; ) {
  129. b = GetData( dwAddr, &block, BLOCK_SIZE, NULL);
  130. if (b == FALSE) {
  131. dprintf("couldn't read address %x\n", dwAddr);
  132. return (L'\0');
  133. }
  134. for (i = 0; i < BLOCK_SIZE/2; i++) {
  135. if (Block[i] == L'\0') {
  136. end = TRUE;
  137. }
  138. String[length] = Block[i];
  139. length++;
  140. }
  141. if (end == TRUE) {
  142. break;
  143. }
  144. dwAddr += BLOCK_SIZE;
  145. }
  146. return (String);
  147. }
  148. PCHAR
  149. MapSymbol(DWORD dwAddr)
  150. {
  151. static CHAR Name[256];
  152. DWORD Displacement;
  153. GetSymbol((LPVOID)dwAddr, (UCHAR *)Name, &Displacement);
  154. strcat(Name, "+");
  155. PCHAR p = strchr(Name, '\0');
  156. _ltoa(Displacement, p, 16);
  157. return(Name);
  158. }
  159. DECLARE_API( help )
  160. {
  161. INIT_DPRINTF();
  162. if (lpArgumentString[0] == '\0') {
  163. dprintf("\n"
  164. "regexts help:\n\n"
  165. "\n"
  166. "!keys - Dumps stack for all open reg handles \n"
  167. "!version - Dumps the version numbers \n"
  168. );
  169. }
  170. }
  171. BOOL ChkTarget; // is debuggee a CHK build?
  172. #define VER_PRODUCTBUILD 10
  173. EXT_API_VERSION ApiVersion = { 3, 5, EXT_API_VERSION_NUMBER, 0 };
  174. VOID
  175. WinDbgExtensionDllInit(
  176. PWINDBG_EXTENSION_APIS lpExtensionApis,
  177. USHORT MajorVersion,
  178. USHORT MinorVersion
  179. )
  180. {
  181. fKernelDebug = TRUE;
  182. ReadMemoryExt = ReadMemoryKernelMode;
  183. WriteMemoryExt = WriteMemoryKernelMode;
  184. ExtensionApis = *lpExtensionApis ;
  185. SavedMajorVersion = MajorVersion;
  186. SavedMinorVersion = MinorVersion;
  187. ChkTarget = SavedMajorVersion == 0x0c ? TRUE : FALSE;
  188. }
  189. DECLARE_API( version )
  190. {
  191. #if DBG
  192. PCSTR kind = "Checked";
  193. #else
  194. PCSTR kind = "Free";
  195. #endif
  196. dprintf(
  197. "%s SMB Extension dll for Build %d debugging %s kernel for Build %d\n",
  198. kind,
  199. VER_PRODUCTBUILD,
  200. SavedMajorVersion == 0x0c ? "Checked" : "Free",
  201. SavedMinorVersion
  202. );
  203. }
  204. VOID
  205. CheckVersion(
  206. VOID
  207. )
  208. {
  209. }
  210. LPEXT_API_VERSION
  211. ExtensionApiVersion(
  212. VOID
  213. )
  214. {
  215. return &ApiVersion;
  216. }
  217. DECLARE_API( keys )
  218. {
  219. RegLeakTable* pLeakTable;
  220. INIT_DPRINTF();
  221. if (*lpArgumentString) {
  222. dprintf("Dump keys for table at %s\n", lpArgumentString);
  223. sscanf(lpArgumentString, "%lx", &pLeakTable);
  224. } else {
  225. dprintf("Dump keys for advapi32!gLeakTable\n");
  226. pLeakTable = (RegLeakTable*) GetExpression( "advapi32!gLeakTable" );
  227. if (!pLeakTable) {
  228. dprintf("Unable to resolve advapi32!gLeakTable\n"
  229. "Please fix symbols or specify the address of a leak table"
  230. "to !keys\n");
  231. return;
  232. }
  233. dprintf("Dump keys for table at 0x%x\n", pLeakTable);
  234. }
  235. RegLeakTableDump(pLeakTable);
  236. }
  237. void RegLeakTableDump(RegLeakTable* pLeakTable)
  238. {
  239. TrackObjectData* pData;
  240. DWORD ListHead;
  241. DWORD cKeys;
  242. DWORD KeysAddress;
  243. DWORD dwFlags;
  244. DWORD FlagsAddress;
  245. KeysAddress = ((DWORD) pLeakTable) + 4;
  246. FlagsAddress = ((DWORD) pLeakTable) + 8;
  247. if (!GetData(KeysAddress,
  248. &cKeys,
  249. sizeof(pLeakTable->cKeys),
  250. NULL)) {
  251. dprintf("Error reading key count at 0x%x\n", KeysAddress);
  252. return;
  253. }
  254. dprintf("\tKeys = 0x%x\n", cKeys);
  255. if (!GetData(FlagsAddress,
  256. &dwFlags,
  257. sizeof(pLeakTable->pHead),
  258. NULL)) {
  259. dprintf("Error reading list head at 0x%x\n", pLeakTable);
  260. return;
  261. }
  262. dprintf("\tFlags = 0x%x", dwFlags);
  263. switch (dwFlags)
  264. {
  265. case LEAK_TRACK_FLAG_NONE:
  266. dprintf("\tNo tracking\n");
  267. return;
  268. case LEAK_TRACK_FLAG_USER:
  269. dprintf("\tOnly subkeys of HKEY_USERS\n");
  270. break;
  271. case LEAK_TRACK_FLAG_ALL:
  272. dprintf("\tAll keys\n");
  273. break;
  274. default:
  275. dprintf("\tInvalid flag -- table corrupt\n");
  276. return;
  277. }
  278. if (!GetData((DWORD)pLeakTable,
  279. &ListHead,
  280. sizeof(pLeakTable->pHead),
  281. NULL)) {
  282. dprintf("Error reading list head at 0x%x\n", pLeakTable);
  283. return;
  284. }
  285. dprintf("\tList starts at 0x%x\n", ListHead);
  286. TrackObjectData* NextData;
  287. int ikey = 0;
  288. for (pData = (TrackObjectData*) ListHead;
  289. pData != NULL;
  290. pData = NextData)
  291. {
  292. dprintf("\tObject at 0x%x", pData);
  293. TrackObjectDataPrint(pData);
  294. if (!GetData((DWORD) pData, &NextData, sizeof(NextData), NULL)) {
  295. dprintf("Error reading next link for object at 0x%x\n", pData);
  296. return;
  297. }
  298. }
  299. }
  300. void TrackObjectDataPrint(TrackObjectData* pKeyData)
  301. {
  302. NTSTATUS Status;
  303. DWORD dwStackDepth;
  304. DWORD StackAddress;
  305. HKEY hKey;
  306. DWORD hKeyAddress;
  307. DWORD StackDepthAddress;
  308. PVOID* rgStack;
  309. DWORD pStack;
  310. hKeyAddress = ((DWORD) pKeyData) + 8;
  311. StackDepthAddress = ((DWORD) pKeyData) + 12;
  312. rgStack = NULL;
  313. if (!GetData(hKeyAddress, &hKey, sizeof(hKey), NULL)) {
  314. dprintf("Error reading hkey for object at 0x%x\n", pKeyData);
  315. return;
  316. }
  317. dprintf("Tracked key data for object 0x%x\n", hKey);
  318. if (!fKernelDebug)
  319. (void) PrintObjectInfo(hKey);
  320. else
  321. dprintf("!!!!!!Broken into kd. do '!handle 0x%x f' for details of the handle\n", hKey);
  322. if (!GetData(StackDepthAddress, &dwStackDepth, sizeof(dwStackDepth), NULL)) {
  323. dprintf("Error reading key object at 0x%x\n", pKeyData);
  324. return;
  325. }
  326. if (!dwStackDepth) {
  327. dprintf("\t\tNo stack data\n");
  328. return;
  329. }
  330. dprintf("\t\tStack depth 0x%x\n", dwStackDepth);
  331. StackAddress = ((DWORD) (pKeyData)) + 16;
  332. if (!GetData(StackAddress,
  333. &pStack,
  334. sizeof(PVOID),
  335. NULL)) {
  336. dprintf("Error reading stack frames at 0x%x\n", StackAddress);
  337. return;
  338. }
  339. dprintf("\t\tStack frames at 0x%x\n", pStack);
  340. rgStack = (PVOID*) RtlAllocateHeap(
  341. RtlProcessHeap(),
  342. 0,
  343. sizeof(*rgStack) * dwStackDepth);
  344. if (!rgStack) {
  345. return;
  346. }
  347. if (!GetData(pStack,
  348. rgStack,
  349. sizeof(*rgStack) * dwStackDepth,
  350. NULL)) {
  351. dprintf("Error reading stack frames at 0x%x\n", StackAddress);
  352. RtlFreeHeap(RtlProcessHeap(), 0, rgStack);
  353. return;
  354. }
  355. for (int iFrame = 0; iFrame < dwStackDepth; iFrame++)
  356. {
  357. UCHAR Symbol[MAX_SYMBOL_LENGTH];
  358. DWORD_PTR Displacement;
  359. *Symbol = L'\0';
  360. GetSymbol(
  361. rgStack[iFrame],
  362. Symbol,
  363. &Displacement);
  364. dprintf("\t\t0x%x", rgStack[iFrame]);
  365. if (*Symbol) {
  366. dprintf("\t %s", Symbol);
  367. if (Displacement) {
  368. dprintf("+0x%x", Displacement);
  369. }
  370. } else {
  371. dprintf("\t ????????");
  372. }
  373. dprintf("\n");
  374. }
  375. if (rgStack) {
  376. RtlFreeHeap(RtlProcessHeap(), 0, rgStack);
  377. }
  378. dprintf("\n");
  379. }
  380. NTSTATUS PrintObjectInfo(HANDLE Handle)
  381. {
  382. POBJECT_NAME_INFORMATION pNameInfo;
  383. BYTE rgNameInfoBuf[512];
  384. NTSTATUS Status;
  385. HKEY hkDup;
  386. DWORD dwRequired;
  387. Status = NtDuplicateObject(
  388. ProcessHandle,
  389. Handle,
  390. NtCurrentProcess(),
  391. (PHANDLE) &hkDup,
  392. 0,
  393. FALSE,
  394. DUPLICATE_SAME_ACCESS);
  395. if (!NT_SUCCESS(Status)) {
  396. dprintf("Unable to duplicate handle 0x%x from process handle 0x%x, error 0x%x\n",
  397. Handle,
  398. ProcessHandle,
  399. Status);
  400. return Status;
  401. }
  402. pNameInfo = (POBJECT_NAME_INFORMATION) rgNameInfoBuf;
  403. Status = NtQueryObject(
  404. hkDup,
  405. ObjectNameInformation,
  406. pNameInfo,
  407. sizeof(pNameInfo),
  408. &dwRequired);
  409. if (!NT_SUCCESS(Status)) {
  410. if (STATUS_INFO_LENGTH_MISMATCH == Status) {
  411. Status = STATUS_NO_MEMORY;
  412. pNameInfo = (POBJECT_NAME_INFORMATION) RtlAllocateHeap(
  413. RtlProcessHeap(),
  414. 0,
  415. dwRequired);
  416. if (pNameInfo) {
  417. Status = NtQueryObject(
  418. hkDup,
  419. ObjectNameInformation,
  420. pNameInfo,
  421. dwRequired,
  422. &dwRequired);
  423. }
  424. }
  425. }
  426. if (!NT_SUCCESS(Status)) {
  427. dprintf("Unable to query object information for object error 0x%x\n",
  428. Status);
  429. } else {
  430. dprintf("Object 0x%x\n\tName: %S\n", Handle, pNameInfo->Name.Buffer);
  431. }
  432. NtClose(hkDup);
  433. if ((PBYTE) pNameInfo != rgNameInfoBuf) {
  434. RtlFreeHeap(RtlProcessHeap(), 0, pNameInfo);
  435. }
  436. return STATUS_SUCCESS;
  437. }