2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/kdbg.c
5 * PURPOSE: ARM Memory Manager Kernel Debugger routines
6 * PROGRAMMERS: ReactOS Portable Systems Group
10 /* INCLUDES *******************************************************************/
16 #define MODULE_INVOLVED_IN_ARM3
17 #include <mm/ARM3/miarm.h>
19 /* GLOBALS ********************************************************************/
21 typedef struct _IRP_FIND_CTXT
23 ULONG_PTR RestartAddress
;
26 } IRP_FIND_CTXT
, *PIRP_FIND_CTXT
;
28 extern PVOID MmNonPagedPoolEnd0
;
29 extern SIZE_T PoolBigPageTableSize
;
30 extern PPOOL_TRACKER_BIG_PAGES PoolBigPageTable
;
32 #define POOL_BIG_TABLE_ENTRY_FREE 0x1
34 /* Pool block/header/list access macros */
35 #define POOL_ENTRY(x) (PPOOL_HEADER)((ULONG_PTR)(x) - sizeof(POOL_HEADER))
36 #define POOL_FREE_BLOCK(x) (PLIST_ENTRY)((ULONG_PTR)(x) + sizeof(POOL_HEADER))
37 #define POOL_BLOCK(x, i) (PPOOL_HEADER)((ULONG_PTR)(x) + ((i) * POOL_BLOCK_SIZE))
38 #define POOL_NEXT_BLOCK(x) POOL_BLOCK((x), (x)->BlockSize)
39 #define POOL_PREV_BLOCK(x) POOL_BLOCK((x), -((x)->PreviousSize))
41 VOID
MiDumpPoolConsumers(BOOLEAN CalledFromDbg
, ULONG Tag
, ULONG Mask
, ULONG Flags
);
43 /* PRIVATE FUNCTIONS **********************************************************/
45 #if DBG && defined(KDBG)
54 ULONG_PTR Address
= 0, Flags
= 0;
63 if (!KdbpGetHexNumber(Argv
[1], &Address
))
65 KdbpPrint("Invalid parameter: %s\n", Argv
[1]);
73 if (!KdbpGetHexNumber(Argv
[2], &Flags
))
75 KdbpPrint("Invalid parameter: %s\n", Argv
[2]);
80 /* Check if we got an address */
83 /* Get the base page */
84 PoolPage
= PAGE_ALIGN(Address
);
88 KdbpPrint("Heap is unimplemented\n");
92 /* No paging support! */
93 if (!MmIsAddressValid(PoolPage
))
95 KdbpPrint("Address not accessible!\n");
100 if ((Address
>= (ULONG_PTR
)MmPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmPagedPoolEnd
))
101 KdbpPrint("Allocation is from PagedPool region\n");
102 else if ((Address
>= (ULONG_PTR
)MmNonPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmNonPagedPoolEnd
))
103 KdbpPrint("Allocation is from NonPagedPool region\n");
106 KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID
)Address
);
110 /* Loop all entries of that page */
114 /* Check if the address is within that entry */
115 ThisOne
= ((Address
>= (ULONG_PTR
)Entry
) &&
116 (Address
< (ULONG_PTR
)(Entry
+ Entry
->BlockSize
)));
118 if (!(Flags
& 1) || ThisOne
)
121 KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
122 ThisOne
? '*' : ' ', Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
123 (Flags
& 0x80000000) ? "" : (Entry
->PoolType
? "(Allocated)" : "(Free) "),
124 (Flags
& 0x80000000) ? "" : (PCHAR
)&Entry
->PoolTag
);
129 Data
= (PULONG
)(Entry
+ 1);
130 KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
131 " %p %08lx %08lx %08lx %08lx\n",
132 &Data
[0], Data
[0], Data
[1], Data
[2], Data
[3],
133 &Data
[4], Data
[4], Data
[5], Data
[6], Data
[7]);
136 /* Go to next entry */
137 Entry
= POOL_BLOCK(Entry
, Entry
->BlockSize
);
139 while ((Entry
->BlockSize
!= 0) && ((ULONG_PTR
)Entry
< (ULONG_PTR
)PoolPage
+ PAGE_SIZE
));
146 ExpKdbgExtPoolUsedGetTag(PCHAR Arg
, PULONG Tag
, PULONG Mask
)
159 /* Generate the mask to have wildcards support */
160 for (i
= 0; i
< Len
; ++i
)
165 *Mask
|= (0xFF << i
* 8);
169 /* Get the tag in the ulong form */
170 *Tag
= *((PULONG
)Tmp
);
184 /* If we have 2+ args, easy: flags then tag */
187 ExpKdbgExtPoolUsedGetTag(Argv
[2], &Tag
, &Mask
);
188 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
190 KdbpPrint("Invalid parameter: %s\n", Argv
[1]);
195 /* Otherwise, try to find out whether that's flags */
196 if (strlen(Argv
[1]) == 1 ||
197 (strlen(Argv
[1]) == 3 && Argv
[1][0] == '0' && (Argv
[1][1] == 'x' || Argv
[1][1] == 'X')))
199 /* Fallback: if reading flags failed, assume it's a tag */
200 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
202 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
208 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
213 /* Call the dumper */
214 MiDumpPoolConsumers(TRUE
, Tag
, Mask
, Flags
);
221 ExpKdbgExtPoolFindLargePool(
224 VOID (NTAPI
* FoundCallback
)(PPOOL_TRACKER_BIG_PAGES
, PVOID
),
225 PVOID CallbackContext
)
229 KdbpPrint("Scanning large pool allocation table for Tag: %.4s (%p : %p)\n", (PCHAR
)&Tag
, &PoolBigPageTable
[0], &PoolBigPageTable
[PoolBigPageTableSize
- 1]);
231 for (i
= 0; i
< PoolBigPageTableSize
; i
++)
234 if ((ULONG_PTR
)PoolBigPageTable
[i
].Va
& POOL_BIG_TABLE_ENTRY_FREE
)
239 if ((PoolBigPageTable
[i
].Key
& Mask
) == (Tag
& Mask
))
241 if (FoundCallback
!= NULL
)
243 FoundCallback(&PoolBigPageTable
[i
], CallbackContext
);
248 KdbpPrint("%p: tag %.4s, size: %I64x\n",
249 PoolBigPageTable
[i
].Va
, (PCHAR
)&PoolBigPageTable
[i
].Key
,
250 PoolBigPageTable
[i
].NumberOfPages
<< PAGE_SHIFT
);
258 ExpKdbgExtValidatePoolHeader(
261 POOL_TYPE BasePoolTye
)
263 /* Block size cannot be NULL or negative and it must cover the page */
264 if (Entry
->BlockSize
<= 0)
268 if (Entry
->BlockSize
* 8 + (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
> PAGE_SIZE
)
274 * PreviousSize cannot be 0 unless on page begin
275 * And it cannot be bigger that our current
278 if (Entry
->PreviousSize
== 0 && BaseVa
!= Entry
)
282 if (Entry
->PreviousSize
* 8 > (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
)
287 /* Must be paged pool */
288 if (((Entry
->PoolType
- 1) & BASE_POOL_TYPE_MASK
) != BasePoolTye
)
294 if ((Entry
->PoolTag
& 0x00808080) != 0)
304 ExpKdbgExtPoolFindPagedPool(
307 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
308 PVOID CallbackContext
)
315 KdbpPrint("Searching Paged pool (%p : %p) for Tag: %.4s\n", MmPagedPoolStart
, MmPagedPoolEnd
, (PCHAR
)&Tag
);
318 * To speed up paged pool search, we will use the allocation bipmap.
319 * This is possible because we live directly in the kernel :-)
321 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, 0);
322 while (i
!= 0xFFFFFFFF)
324 BaseVa
= (PVOID
)((ULONG_PTR
)MmPagedPoolStart
+ (i
<< PAGE_SHIFT
));
327 /* Validate our address */
328 if ((ULONG_PTR
)BaseVa
> (ULONG_PTR
)MmPagedPoolEnd
|| (ULONG_PTR
)BaseVa
+ PAGE_SIZE
> (ULONG_PTR
)MmPagedPoolEnd
)
333 /* Check whether we are beyond expansion */
334 PointerPde
= MiAddressToPde(BaseVa
);
335 if (PointerPde
>= MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
)
340 /* Check if allocation is valid */
341 if (MmIsAddressValid(BaseVa
))
344 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
345 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
347 /* Try to find whether we have a pool entry */
348 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, PagedPool
))
353 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
355 if (FoundCallback
!= NULL
)
357 FoundCallback(Entry
, CallbackContext
);
362 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
363 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
364 Entry
->PoolType
? "(Allocated)" : "(Free) ",
365 (PCHAR
)&Entry
->PoolTag
);
371 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, i
+ 1);
377 ExpKdbgExtPoolFindNonPagedPool(
380 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
381 PVOID CallbackContext
)
386 KdbpPrint("Searching NonPaged pool (%p : %p) for Tag: %.4s\n", MmNonPagedPoolStart
, MmNonPagedPoolEnd0
, (PCHAR
)&Tag
);
388 /* Brute force search: start browsing the whole non paged pool */
389 for (BaseVa
= MmNonPagedPoolStart
;
390 (ULONG_PTR
)BaseVa
+ PAGE_SIZE
<= (ULONG_PTR
)MmNonPagedPoolEnd0
;
391 BaseVa
= (PVOID
)((ULONG_PTR
)BaseVa
+ PAGE_SIZE
))
395 /* Check whether we are beyond expansion */
396 if (BaseVa
>= MmNonPagedPoolExpansionStart
)
401 /* Check if allocation is valid */
402 if (!MmIsAddressValid(BaseVa
))
408 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
409 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
411 /* Try to find whether we have a pool entry */
412 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, NonPagedPool
))
417 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
419 if (FoundCallback
!= NULL
)
421 FoundCallback(Entry
, CallbackContext
);
426 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
427 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
428 Entry
->PoolType
? "(Allocated)" : "(Free) ",
429 (PCHAR
)&Entry
->PoolTag
);
443 ULONG PoolType
= NonPagedPool
;
447 KdbpPrint("Specify a tag string\n");
451 /* First arg is tag */
452 if (strlen(Argv
[1]) != 1 || Argv
[1][0] != '*')
454 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
457 /* Second arg might be pool to search */
460 PoolType
= strtoul(Argv
[2], NULL
, 0);
464 KdbpPrint("Only (non) paged pool are supported\n");
469 /* First search for large allocations */
470 ExpKdbgExtPoolFindLargePool(Tag
, Mask
, NULL
, NULL
);
472 if (PoolType
== NonPagedPool
)
474 ExpKdbgExtPoolFindNonPagedPool(Tag
, Mask
, NULL
, NULL
);
476 else if (PoolType
== PagedPool
)
478 ExpKdbgExtPoolFindPagedPool(Tag
, Mask
, NULL
, NULL
);
486 ExpKdbgExtIrpFindPrint(
491 BOOLEAN IsComplete
= FALSE
;
492 PIRP_FIND_CTXT FindCtxt
= Context
;
493 PIO_STACK_LOCATION IoStack
= NULL
;
494 PUNICODE_STRING DriverName
= NULL
;
495 ULONG_PTR SData
= FindCtxt
->SData
;
496 ULONG Criteria
= FindCtxt
->Criteria
;
498 /* Free entry, ignore */
499 if (Entry
->PoolType
== 0)
505 Irp
= (PIRP
)POOL_FREE_BLOCK(Entry
);
507 /* Bail out if not matching restart address */
508 if ((ULONG_PTR
)Irp
< FindCtxt
->RestartAddress
)
513 /* Avoid bogus IRP stack locations */
514 if (Irp
->CurrentLocation
<= Irp
->StackCount
+ 1)
516 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
518 /* Get associated driver */
519 if (IoStack
->DeviceObject
&& IoStack
->DeviceObject
->DriverObject
)
520 DriverName
= &IoStack
->DeviceObject
->DriverObject
->DriverName
;
527 /* Display if: no data, no criteria or if criteria matches data */
528 if (SData
== 0 || Criteria
== 0 ||
529 (Criteria
& 0x1 && IoStack
&& SData
== (ULONG_PTR
)IoStack
->DeviceObject
) ||
530 (Criteria
& 0x2 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.OriginalFileObject
) ||
531 (Criteria
& 0x4 && Irp
->MdlAddress
&& SData
== (ULONG_PTR
)Irp
->MdlAddress
->Process
) ||
532 (Criteria
& 0x8 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.Thread
) ||
533 (Criteria
& 0x10 && SData
== (ULONG_PTR
)Irp
->UserEvent
))
537 KdbpPrint("%p Thread %p current stack (%x, %x) belongs to %wZ\n", Irp
, Irp
->Tail
.Overlay
.Thread
, IoStack
->MajorFunction
, IoStack
->MinorFunction
, DriverName
);
541 KdbpPrint("%p Thread %p is complete (CurrentLocation %d > StackCount %d)\n", Irp
, Irp
->Tail
.Overlay
.Thread
, Irp
->CurrentLocation
, Irp
->StackCount
+ 1);
551 ULONG PoolType
= NonPagedPool
;
552 IRP_FIND_CTXT FindCtxt
;
557 PoolType
= strtoul(Argv
[1], NULL
, 0);
561 KdbpPrint("Only (non) paged pool are supported\n");
566 RtlZeroMemory(&FindCtxt
, sizeof(IRP_FIND_CTXT
));
568 /* Restart address */
571 if (!KdbpGetHexNumber(Argv
[2], &FindCtxt
.RestartAddress
))
573 KdbpPrint("Invalid parameter: %s\n", Argv
[2]);
574 FindCtxt
.RestartAddress
= 0;
580 if (!KdbpGetHexNumber(Argv
[4], &FindCtxt
.SData
))
586 if (strcmp(Argv
[3], "device") == 0)
588 FindCtxt
.Criteria
= 0x1;
590 else if (strcmp(Argv
[3], "fileobject") == 0)
592 FindCtxt
.Criteria
= 0x2;
594 else if (strcmp(Argv
[3], "mdlprocess") == 0)
596 FindCtxt
.Criteria
= 0x4;
598 else if (strcmp(Argv
[3], "thread") == 0)
600 FindCtxt
.Criteria
= 0x8;
602 else if (strcmp(Argv
[3], "userevent") == 0)
604 FindCtxt
.Criteria
= 0x10;
606 else if (strcmp(Argv
[3], "arg") == 0)
608 FindCtxt
.Criteria
= 0x1f;
613 if (PoolType
== NonPagedPool
)
615 ExpKdbgExtPoolFindNonPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
617 else if (PoolType
== PagedPool
)
619 ExpKdbgExtPoolFindPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
625 #endif // DBG && defined(KDBG)