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(
222 VOID (NTAPI
* FoundCallback
)(PPOOL_TRACKER_BIG_PAGES
, PVOID
),
223 PVOID CallbackContext
)
227 KdbpPrint("Scanning large pool allocation table for Tag: %.4s (%p : %p)\n", (PCHAR
)&Tag
, &PoolBigPageTable
[0], &PoolBigPageTable
[PoolBigPageTableSize
- 1]);
229 for (i
= 0; i
< PoolBigPageTableSize
; i
++)
232 if ((ULONG_PTR
)PoolBigPageTable
[i
].Va
& POOL_BIG_TABLE_ENTRY_FREE
)
237 if ((PoolBigPageTable
[i
].Key
& Mask
) == (Tag
& Mask
))
239 if (FoundCallback
!= NULL
)
241 FoundCallback(&PoolBigPageTable
[i
], CallbackContext
);
246 KdbpPrint("%p: tag %.4s, size: %I64x\n",
247 PoolBigPageTable
[i
].Va
, (PCHAR
)&PoolBigPageTable
[i
].Key
,
248 PoolBigPageTable
[i
].NumberOfPages
<< PAGE_SHIFT
);
256 ExpKdbgExtValidatePoolHeader(
259 POOL_TYPE BasePoolTye
)
261 /* Block size cannot be NULL or negative and it must cover the page */
262 if (Entry
->BlockSize
<= 0)
266 if (Entry
->BlockSize
* 8 + (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
> PAGE_SIZE
)
272 * PreviousSize cannot be 0 unless on page begin
273 * And it cannot be bigger that our current
276 if (Entry
->PreviousSize
== 0 && BaseVa
!= Entry
)
280 if (Entry
->PreviousSize
* 8 > (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
)
285 /* Must be paged pool */
286 if (((Entry
->PoolType
- 1) & BASE_POOL_TYPE_MASK
) != BasePoolTye
)
292 if ((Entry
->PoolTag
& 0x00808080) != 0)
302 ExpKdbgExtPoolFindPagedPool(
305 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
306 PVOID CallbackContext
)
313 KdbpPrint("Searching Paged pool (%p : %p) for Tag: %.4s\n", MmPagedPoolStart
, MmPagedPoolEnd
, (PCHAR
)&Tag
);
316 * To speed up paged pool search, we will use the allocation bipmap.
317 * This is possible because we live directly in the kernel :-)
319 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, 0);
320 while (i
!= 0xFFFFFFFF)
322 BaseVa
= (PVOID
)((ULONG_PTR
)MmPagedPoolStart
+ (i
<< PAGE_SHIFT
));
325 /* Validate our address */
326 if ((ULONG_PTR
)BaseVa
> (ULONG_PTR
)MmPagedPoolEnd
|| (ULONG_PTR
)BaseVa
+ PAGE_SIZE
> (ULONG_PTR
)MmPagedPoolEnd
)
331 /* Check whether we are beyond expansion */
332 PointerPde
= MiAddressToPde(BaseVa
);
333 if (PointerPde
>= MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
)
338 /* Check if allocation is valid */
339 if (MmIsAddressValid(BaseVa
))
342 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
343 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
345 /* Try to find whether we have a pool entry */
346 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, PagedPool
))
351 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
353 if (FoundCallback
!= NULL
)
355 FoundCallback(Entry
, CallbackContext
);
360 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
361 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
362 Entry
->PoolType
? "(Allocated)" : "(Free) ",
363 (PCHAR
)&Entry
->PoolTag
);
369 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, i
+ 1);
375 ExpKdbgExtPoolFindNonPagedPool(
378 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
379 PVOID CallbackContext
)
384 KdbpPrint("Searching NonPaged pool (%p : %p) for Tag: %.4s\n", MmNonPagedPoolStart
, MmNonPagedPoolEnd0
, (PCHAR
)&Tag
);
386 /* Brute force search: start browsing the whole non paged pool */
387 for (BaseVa
= MmNonPagedPoolStart
;
388 (ULONG_PTR
)BaseVa
+ PAGE_SIZE
<= (ULONG_PTR
)MmNonPagedPoolEnd0
;
389 BaseVa
= (PVOID
)((ULONG_PTR
)BaseVa
+ PAGE_SIZE
))
393 /* Check whether we are beyond expansion */
394 if (BaseVa
>= MmNonPagedPoolExpansionStart
)
399 /* Check if allocation is valid */
400 if (!MmIsAddressValid(BaseVa
))
406 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
407 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
409 /* Try to find whether we have a pool entry */
410 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, NonPagedPool
))
415 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
417 if (FoundCallback
!= NULL
)
419 FoundCallback(Entry
, CallbackContext
);
424 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
425 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
426 Entry
->PoolType
? "(Allocated)" : "(Free) ",
427 (PCHAR
)&Entry
->PoolTag
);
441 ULONG PoolType
= NonPagedPool
;
445 KdbpPrint("Specify a tag string\n");
449 /* First arg is tag */
450 if (strlen(Argv
[1]) != 1 || Argv
[1][0] != '*')
452 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
455 /* Second arg might be pool to search */
458 PoolType
= strtoul(Argv
[2], NULL
, 0);
462 KdbpPrint("Only (non) paged pool are supported\n");
467 /* First search for large allocations */
468 ExpKdbgExtPoolFindLargePool(Tag
, Mask
, NULL
, NULL
);
470 if (PoolType
== NonPagedPool
)
472 ExpKdbgExtPoolFindNonPagedPool(Tag
, Mask
, NULL
, NULL
);
474 else if (PoolType
== PagedPool
)
476 ExpKdbgExtPoolFindPagedPool(Tag
, Mask
, NULL
, NULL
);
484 ExpKdbgExtIrpFindPrint(
489 BOOLEAN IsComplete
= FALSE
;
490 PIRP_FIND_CTXT FindCtxt
= Context
;
491 PIO_STACK_LOCATION IoStack
= NULL
;
492 PUNICODE_STRING DriverName
= NULL
;
493 ULONG_PTR SData
= FindCtxt
->SData
;
494 ULONG Criteria
= FindCtxt
->Criteria
;
496 /* Free entry, ignore */
497 if (Entry
->PoolType
== 0)
503 Irp
= (PIRP
)POOL_FREE_BLOCK(Entry
);
505 /* Bail out if not matching restart address */
506 if ((ULONG_PTR
)Irp
< FindCtxt
->RestartAddress
)
511 /* Avoid bogus IRP stack locations */
512 if (Irp
->CurrentLocation
<= Irp
->StackCount
+ 1)
514 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
516 /* Get associated driver */
517 if (IoStack
->DeviceObject
&& IoStack
->DeviceObject
->DriverObject
)
518 DriverName
= &IoStack
->DeviceObject
->DriverObject
->DriverName
;
525 /* Display if: no data, no criteria or if criteria matches data */
526 if (SData
== 0 || Criteria
== 0 ||
527 (Criteria
& 0x1 && IoStack
&& SData
== (ULONG_PTR
)IoStack
->DeviceObject
) ||
528 (Criteria
& 0x2 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.OriginalFileObject
) ||
529 (Criteria
& 0x4 && Irp
->MdlAddress
&& SData
== (ULONG_PTR
)Irp
->MdlAddress
->Process
) ||
530 (Criteria
& 0x8 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.Thread
) ||
531 (Criteria
& 0x10 && SData
== (ULONG_PTR
)Irp
->UserEvent
))
535 KdbpPrint("%p Thread %p current stack (%x, %x) belongs to %wZ\n", Irp
, Irp
->Tail
.Overlay
.Thread
, IoStack
->MajorFunction
, IoStack
->MinorFunction
, DriverName
);
539 KdbpPrint("%p Thread %p is complete (CurrentLocation %d > StackCount %d)\n", Irp
, Irp
->Tail
.Overlay
.Thread
, Irp
->CurrentLocation
, Irp
->StackCount
+ 1);
549 ULONG PoolType
= NonPagedPool
;
550 IRP_FIND_CTXT FindCtxt
;
555 PoolType
= strtoul(Argv
[1], NULL
, 0);
559 KdbpPrint("Only (non) paged pool are supported\n");
564 RtlZeroMemory(&FindCtxt
, sizeof(IRP_FIND_CTXT
));
566 /* Restart address */
569 if (!KdbpGetHexNumber(Argv
[2], &FindCtxt
.RestartAddress
))
571 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
572 FindCtxt
.RestartAddress
= 0;
578 if (!KdbpGetHexNumber(Argv
[4], &FindCtxt
.SData
))
584 if (strcmp(Argv
[3], "device") == 0)
586 FindCtxt
.Criteria
= 0x1;
588 else if (strcmp(Argv
[3], "fileobject") == 0)
590 FindCtxt
.Criteria
= 0x2;
592 else if (strcmp(Argv
[3], "mdlprocess") == 0)
594 FindCtxt
.Criteria
= 0x4;
596 else if (strcmp(Argv
[3], "thread") == 0)
598 FindCtxt
.Criteria
= 0x8;
600 else if (strcmp(Argv
[3], "userevent") == 0)
602 FindCtxt
.Criteria
= 0x10;
604 else if (strcmp(Argv
[3], "arg") == 0)
606 FindCtxt
.Criteria
= 0x1f;
611 if (PoolType
== NonPagedPool
)
613 ExpKdbgExtPoolFindNonPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
615 else if (PoolType
== PagedPool
)
617 ExpKdbgExtPoolFindPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
623 #endif // DBG && KDBG