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)
52 ULONG_PTR Address
= 0, Flags
= 0;
61 if (!KdbpGetHexNumber(Argv
[1], &Address
))
63 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
71 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
73 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
78 /* Check if we got an address */
81 /* Get the base page */
82 PoolPage
= PAGE_ALIGN(Address
);
86 KdbpPrint("Heap is unimplemented\n");
90 /* No paging support! */
91 if (!MmIsAddressValid(PoolPage
))
93 KdbpPrint("Address not accessible!\n");
98 if ((Address
>= (ULONG_PTR
)MmPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmPagedPoolEnd
))
99 KdbpPrint("Allocation is from PagedPool region\n");
100 else if ((Address
>= (ULONG_PTR
)MmNonPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmNonPagedPoolEnd
))
101 KdbpPrint("Allocation is from NonPagedPool region\n");
104 KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID
)Address
);
108 /* Loop all entries of that page */
112 /* Check if the address is within that entry */
113 ThisOne
= ((Address
>= (ULONG_PTR
)Entry
) &&
114 (Address
< (ULONG_PTR
)(Entry
+ Entry
->BlockSize
)));
116 if (!(Flags
& 1) || ThisOne
)
119 KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
120 ThisOne
? '*' : ' ', Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
121 (Flags
& 0x80000000) ? "" : (Entry
->PoolType
? "(Allocated)" : "(Free) "),
122 (Flags
& 0x80000000) ? "" : (PCHAR
)&Entry
->PoolTag
);
127 Data
= (PULONG
)(Entry
+ 1);
128 KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
129 " %p %08lx %08lx %08lx %08lx\n",
130 &Data
[0], Data
[0], Data
[1], Data
[2], Data
[3],
131 &Data
[4], Data
[4], Data
[5], Data
[6], Data
[7]);
134 /* Go to next entry */
135 Entry
= POOL_BLOCK(Entry
, Entry
->BlockSize
);
137 while ((Entry
->BlockSize
!= 0) && ((ULONG_PTR
)Entry
< (ULONG_PTR
)PoolPage
+ PAGE_SIZE
));
144 ExpKdbgExtPoolUsedGetTag(PCHAR Arg
, PULONG Tag
, PULONG Mask
)
157 /* Generate the mask to have wildcards support */
158 for (i
= 0; i
< Len
; ++i
)
163 *Mask
|= (0xFF << i
* 8);
167 /* Get the tag in the ulong form */
168 *Tag
= *((PULONG
)Tmp
);
182 /* If we have 2+ args, easy: flags then tag */
185 ExpKdbgExtPoolUsedGetTag(Argv
[2], &Tag
, &Mask
);
186 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
188 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
193 /* Otherwise, try to find out whether that's flags */
194 if (strlen(Argv
[1]) == 1 ||
195 (strlen(Argv
[1]) == 3 && Argv
[1][0] == '0' && Argv
[1][1] == 'x'))
197 /* Fallback: if reading flags failed, assume it's a tag */
198 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
200 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
206 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
211 /* Call the dumper */
212 MiDumpPoolConsumers(TRUE
, Tag
, Mask
, Flags
);
219 ExpKdbgExtPoolFindLargePool(
225 KdbpPrint("Scanning large pool allocation table for Tag: %.4s (%p : %p)\n", (PCHAR
)&Tag
, &PoolBigPageTable
[0], &PoolBigPageTable
[PoolBigPageTableSize
- 1]);
227 for (i
= 0; i
< PoolBigPageTableSize
; i
++)
230 if ((ULONG_PTR
)PoolBigPageTable
[i
].Va
& POOL_BIG_TABLE_ENTRY_FREE
)
235 if ((PoolBigPageTable
[i
].Key
& Mask
) == (Tag
& Mask
))
238 KdbpPrint("%p: tag %.4s, size: %I64x\n",
239 PoolBigPageTable
[i
].Va
, (PCHAR
)&PoolBigPageTable
[i
].Key
,
240 PoolBigPageTable
[i
].NumberOfPages
<< PAGE_SHIFT
);
247 ExpKdbgExtValidatePoolHeader(
250 POOL_TYPE BasePoolTye
)
252 /* Block size cannot be NULL or negative and it must cover the page */
253 if (Entry
->BlockSize
<= 0)
257 if (Entry
->BlockSize
* 8 + (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
> PAGE_SIZE
)
263 * PreviousSize cannot be 0 unless on page begin
264 * And it cannot be bigger that our current
267 if (Entry
->PreviousSize
== 0 && BaseVa
!= Entry
)
271 if (Entry
->PreviousSize
* 8 > (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
)
276 /* Must be paged pool */
277 if (((Entry
->PoolType
- 1) & BASE_POOL_TYPE_MASK
) != BasePoolTye
)
283 if ((Entry
->PoolTag
& 0x00808080) != 0)
293 ExpKdbgExtPoolFindPagedPool(
296 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
297 PVOID CallbackContext
)
304 KdbpPrint("Searching Paged pool (%p : %p) for Tag: %.4s\n", MmPagedPoolStart
, MmPagedPoolEnd
, (PCHAR
)&Tag
);
307 * To speed up paged pool search, we will use the allocation bipmap.
308 * This is possible because we live directly in the kernel :-)
310 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, 0);
311 while (i
!= 0xFFFFFFFF)
313 BaseVa
= (PVOID
)((ULONG_PTR
)MmPagedPoolStart
+ (i
<< PAGE_SHIFT
));
316 /* Validate our address */
317 if ((ULONG_PTR
)BaseVa
> (ULONG_PTR
)MmPagedPoolEnd
|| (ULONG_PTR
)BaseVa
+ PAGE_SIZE
> (ULONG_PTR
)MmPagedPoolEnd
)
322 /* Check whether we are beyond expansion */
323 PointerPde
= MiAddressToPde(BaseVa
);
324 if (PointerPde
>= MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
)
329 /* Check if allocation is valid */
330 if (MmIsAddressValid(BaseVa
))
333 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
334 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
336 /* Try to find whether we have a pool entry */
337 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, PagedPool
))
342 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
344 if (FoundCallback
!= NULL
)
346 FoundCallback(Entry
, CallbackContext
);
351 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
352 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
353 Entry
->PoolType
? "(Allocated)" : "(Free) ",
354 (PCHAR
)&Entry
->PoolTag
);
360 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, i
+ 1);
366 ExpKdbgExtPoolFindNonPagedPool(
369 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
370 PVOID CallbackContext
)
375 KdbpPrint("Searching NonPaged pool (%p : %p) for Tag: %.4s\n", MmNonPagedPoolStart
, MmNonPagedPoolEnd0
, (PCHAR
)&Tag
);
377 /* Brute force search: start browsing the whole non paged pool */
378 for (BaseVa
= MmNonPagedPoolStart
;
379 (ULONG_PTR
)BaseVa
+ PAGE_SIZE
<= (ULONG_PTR
)MmNonPagedPoolEnd0
;
380 BaseVa
= (PVOID
)((ULONG_PTR
)BaseVa
+ PAGE_SIZE
))
384 /* Check whether we are beyond expansion */
385 if (BaseVa
>= MmNonPagedPoolExpansionStart
)
390 /* Check if allocation is valid */
391 if (!MmIsAddressValid(BaseVa
))
397 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
398 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
400 /* Try to find whether we have a pool entry */
401 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, NonPagedPool
))
406 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
408 if (FoundCallback
!= NULL
)
410 FoundCallback(Entry
, CallbackContext
);
415 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
416 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
417 Entry
->PoolType
? "(Allocated)" : "(Free) ",
418 (PCHAR
)&Entry
->PoolTag
);
432 ULONG PoolType
= NonPagedPool
;
436 KdbpPrint("Specify a tag string\n");
440 /* First arg is tag */
441 if (strlen(Argv
[1]) != 1 || Argv
[1][0] != '*')
443 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
446 /* Second arg might be pool to search */
449 PoolType
= strtoul(Argv
[2], NULL
, 0);
453 KdbpPrint("Only (non) paged pool are supported\n");
458 /* First search for large allocations */
459 ExpKdbgExtPoolFindLargePool(Tag
, Mask
);
461 if (PoolType
== NonPagedPool
)
463 ExpKdbgExtPoolFindNonPagedPool(Tag
, Mask
, NULL
, NULL
);
465 else if (PoolType
== PagedPool
)
467 ExpKdbgExtPoolFindPagedPool(Tag
, Mask
, NULL
, NULL
);
475 ExpKdbgExtIrpFindPrint(
480 BOOLEAN IsComplete
= FALSE
;
481 PIRP_FIND_CTXT FindCtxt
= Context
;
482 PIO_STACK_LOCATION IoStack
= NULL
;
483 PUNICODE_STRING DriverName
= NULL
;
484 ULONG_PTR SData
= FindCtxt
->SData
;
485 ULONG Criteria
= FindCtxt
->Criteria
;
487 /* Free entry, ignore */
488 if (Entry
->PoolType
== 0)
494 Irp
= (PIRP
)POOL_FREE_BLOCK(Entry
);
496 /* Bail out if not matching restart address */
497 if ((ULONG_PTR
)Irp
< FindCtxt
->RestartAddress
)
502 /* Avoid bogus IRP stack locations */
503 if (Irp
->CurrentLocation
<= Irp
->StackCount
+ 1)
505 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
507 /* Get associated driver */
508 if (IoStack
->DeviceObject
&& IoStack
->DeviceObject
->DriverObject
)
509 DriverName
= &IoStack
->DeviceObject
->DriverObject
->DriverName
;
516 /* Display if: no data, no criteria or if criteria matches data */
517 if (SData
== 0 || Criteria
== 0 ||
518 (Criteria
& 0x1 && IoStack
&& SData
== (ULONG_PTR
)IoStack
->DeviceObject
) ||
519 (Criteria
& 0x2 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.OriginalFileObject
) ||
520 (Criteria
& 0x4 && Irp
->MdlAddress
&& SData
== (ULONG_PTR
)Irp
->MdlAddress
->Process
) ||
521 (Criteria
& 0x8 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.Thread
) ||
522 (Criteria
& 0x10 && SData
== (ULONG_PTR
)Irp
->UserEvent
))
526 KdbpPrint("%p Thread %p current stack (%x, %x) belongs to %wZ\n", Irp
, Irp
->Tail
.Overlay
.Thread
, IoStack
->MajorFunction
, IoStack
->MinorFunction
, DriverName
);
530 KdbpPrint("%p Thread %p is complete (CurrentLocation %d > StackCount %d)\n", Irp
, Irp
->Tail
.Overlay
.Thread
, Irp
->CurrentLocation
, Irp
->StackCount
+ 1);
540 ULONG PoolType
= NonPagedPool
;
541 IRP_FIND_CTXT FindCtxt
;
546 PoolType
= strtoul(Argv
[1], NULL
, 0);
550 KdbpPrint("Only (non) paged pool are supported\n");
555 RtlZeroMemory(&FindCtxt
, sizeof(IRP_FIND_CTXT
));
557 /* Restart address */
560 if (!KdbpGetHexNumber(Argv
[2], &FindCtxt
.RestartAddress
))
562 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
563 FindCtxt
.RestartAddress
= 0;
569 if (!KdbpGetHexNumber(Argv
[4], &FindCtxt
.SData
))
575 if (strcmp(Argv
[3], "device") == 0)
577 FindCtxt
.Criteria
= 0x1;
579 else if (strcmp(Argv
[3], "fileobject") == 0)
581 FindCtxt
.Criteria
= 0x2;
583 else if (strcmp(Argv
[3], "mdlprocess") == 0)
585 FindCtxt
.Criteria
= 0x4;
587 else if (strcmp(Argv
[3], "thread") == 0)
589 FindCtxt
.Criteria
= 0x8;
591 else if (strcmp(Argv
[3], "userevent") == 0)
593 FindCtxt
.Criteria
= 0x10;
595 else if (strcmp(Argv
[3], "arg") == 0)
597 FindCtxt
.Criteria
= 0x1f;
602 if (PoolType
== NonPagedPool
)
604 ExpKdbgExtPoolFindNonPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
606 else if (PoolType
== PagedPool
)
608 ExpKdbgExtPoolFindPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
614 #endif // DBG && KDBG