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
;
30 /* Pool block/header/list access macros */
31 #define POOL_ENTRY(x) (PPOOL_HEADER)((ULONG_PTR)(x) - sizeof(POOL_HEADER))
32 #define POOL_FREE_BLOCK(x) (PLIST_ENTRY)((ULONG_PTR)(x) + sizeof(POOL_HEADER))
33 #define POOL_BLOCK(x, i) (PPOOL_HEADER)((ULONG_PTR)(x) + ((i) * POOL_BLOCK_SIZE))
34 #define POOL_NEXT_BLOCK(x) POOL_BLOCK((x), (x)->BlockSize)
35 #define POOL_PREV_BLOCK(x) POOL_BLOCK((x), -((x)->PreviousSize))
37 VOID
MiDumpPoolConsumers(BOOLEAN CalledFromDbg
, ULONG Tag
, ULONG Mask
, ULONG Flags
);
39 /* PRIVATE FUNCTIONS **********************************************************/
41 #if DBG && defined(KDBG)
48 ULONG_PTR Address
= 0, Flags
= 0;
57 if (!KdbpGetHexNumber(Argv
[1], &Address
))
59 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
67 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
69 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
74 /* Check if we got an address */
77 /* Get the base page */
78 PoolPage
= PAGE_ALIGN(Address
);
82 KdbpPrint("Heap is unimplemented\n");
86 /* No paging support! */
87 if (!MmIsAddressValid(PoolPage
))
89 KdbpPrint("Address not accessible!\n");
94 if ((Address
>= (ULONG_PTR
)MmPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmPagedPoolEnd
))
95 KdbpPrint("Allocation is from PagedPool region\n");
96 else if ((Address
>= (ULONG_PTR
)MmNonPagedPoolStart
) && (Address
<= (ULONG_PTR
)MmNonPagedPoolEnd
))
97 KdbpPrint("Allocation is from NonPagedPool region\n");
100 KdbpPrint("Address 0x%p is not within any pool!\n", (PVOID
)Address
);
104 /* Loop all entries of that page */
108 /* Check if the address is within that entry */
109 ThisOne
= ((Address
>= (ULONG_PTR
)Entry
) &&
110 (Address
< (ULONG_PTR
)(Entry
+ Entry
->BlockSize
)));
112 if (!(Flags
& 1) || ThisOne
)
115 KdbpPrint("%c%p size: %4d previous size: %4d %s %.4s\n",
116 ThisOne
? '*' : ' ', Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
117 (Flags
& 0x80000000) ? "" : (Entry
->PoolType
? "(Allocated)" : "(Free) "),
118 (Flags
& 0x80000000) ? "" : (PCHAR
)&Entry
->PoolTag
);
123 Data
= (PULONG
)(Entry
+ 1);
124 KdbpPrint(" %p %08lx %08lx %08lx %08lx\n"
125 " %p %08lx %08lx %08lx %08lx\n",
126 &Data
[0], Data
[0], Data
[1], Data
[2], Data
[3],
127 &Data
[4], Data
[4], Data
[5], Data
[6], Data
[7]);
130 /* Go to next entry */
131 Entry
= POOL_BLOCK(Entry
, Entry
->BlockSize
);
133 while ((Entry
->BlockSize
!= 0) && ((ULONG_PTR
)Entry
< (ULONG_PTR
)PoolPage
+ PAGE_SIZE
));
140 ExpKdbgExtPoolUsedGetTag(PCHAR Arg
, PULONG Tag
, PULONG Mask
)
153 /* Generate the mask to have wildcards support */
154 for (i
= 0; i
< Len
; ++i
)
159 *Mask
|= (0xFF << i
* 8);
163 /* Get the tag in the ulong form */
164 *Tag
= *((PULONG
)Tmp
);
178 /* If we have 2+ args, easy: flags then tag */
181 ExpKdbgExtPoolUsedGetTag(Argv
[2], &Tag
, &Mask
);
182 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
184 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
189 /* Otherwise, try to find out whether that's flags */
190 if (strlen(Argv
[1]) == 1 ||
191 (strlen(Argv
[1]) == 3 && Argv
[1][0] == '0' && Argv
[1][1] == 'x'))
193 /* Fallback: if reading flags failed, assume it's a tag */
194 if (!KdbpGetHexNumber(Argv
[1], &Flags
))
196 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
202 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
207 /* Call the dumper */
208 MiDumpPoolConsumers(TRUE
, Tag
, Mask
, Flags
);
215 ExpKdbgExtValidatePoolHeader(
218 POOL_TYPE BasePoolTye
)
220 /* Block size cannot be NULL or negative and it must cover the page */
221 if (Entry
->BlockSize
<= 0)
225 if (Entry
->BlockSize
* 8 + (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
> PAGE_SIZE
)
231 * PreviousSize cannot be 0 unless on page begin
232 * And it cannot be bigger that our current
235 if (Entry
->PreviousSize
== 0 && BaseVa
!= Entry
)
239 if (Entry
->PreviousSize
* 8 > (ULONG_PTR
)Entry
- (ULONG_PTR
)BaseVa
)
244 /* Must be paged pool */
245 if (((Entry
->PoolType
- 1) & BASE_POOL_TYPE_MASK
) != BasePoolTye
)
251 if ((Entry
->PoolTag
& 0x00808080) != 0)
261 ExpKdbgExtPoolFindPagedPool(
264 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
265 PVOID CallbackContext
)
272 KdbpPrint("Searching Paged pool (%p : %p) for Tag: %.4s\n", MmPagedPoolStart
, MmPagedPoolEnd
, (PCHAR
)&Tag
);
275 * To speed up paged pool search, we will use the allocation bipmap.
276 * This is possible because we live directly in the kernel :-)
278 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, 0);
279 while (i
!= 0xFFFFFFFF)
281 BaseVa
= (PVOID
)((ULONG_PTR
)MmPagedPoolStart
+ (i
<< PAGE_SHIFT
));
284 /* Validate our address */
285 if ((ULONG_PTR
)BaseVa
> (ULONG_PTR
)MmPagedPoolEnd
|| (ULONG_PTR
)BaseVa
+ PAGE_SIZE
> (ULONG_PTR
)MmPagedPoolEnd
)
290 /* Check whether we are beyond expansion */
291 PointerPde
= MiAddressToPde(BaseVa
);
292 if (PointerPde
>= MmPagedPoolInfo
.NextPdeForPagedPoolExpansion
)
297 /* Check if allocation is valid */
298 if (MmIsAddressValid(BaseVa
))
301 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
302 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
304 /* Try to find whether we have a pool entry */
305 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, PagedPool
))
310 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
312 if (FoundCallback
!= NULL
)
314 FoundCallback(Entry
, CallbackContext
);
319 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
320 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
321 Entry
->PoolType
? "(Allocated)" : "(Free) ",
322 (PCHAR
)&Entry
->PoolTag
);
328 i
= RtlFindSetBits(MmPagedPoolInfo
.PagedPoolAllocationMap
, 1, i
+ 1);
334 ExpKdbgExtPoolFindNonPagedPool(
337 VOID (NTAPI
* FoundCallback
)(PPOOL_HEADER
, PVOID
),
338 PVOID CallbackContext
)
343 KdbpPrint("Searching NonPaged pool (%p : %p) for Tag: %.4s\n", MmNonPagedPoolStart
, MmNonPagedPoolEnd0
, (PCHAR
)&Tag
);
345 /* Brute force search: start browsing the whole non paged pool */
346 for (BaseVa
= MmNonPagedPoolStart
;
347 (ULONG_PTR
)BaseVa
+ PAGE_SIZE
<= (ULONG_PTR
)MmNonPagedPoolEnd0
;
348 BaseVa
= (PVOID
)((ULONG_PTR
)BaseVa
+ PAGE_SIZE
))
352 /* Check whether we are beyond expansion */
353 if (BaseVa
>= MmNonPagedPoolExpansionStart
)
358 /* Check if allocation is valid */
359 if (!MmIsAddressValid(BaseVa
))
365 (ULONG_PTR
)Entry
+ sizeof(POOL_HEADER
) < (ULONG_PTR
)BaseVa
+ PAGE_SIZE
;
366 Entry
= (PVOID
)((ULONG_PTR
)Entry
+ 8))
368 /* Try to find whether we have a pool entry */
369 if (!ExpKdbgExtValidatePoolHeader(BaseVa
, Entry
, NonPagedPool
))
374 if ((Entry
->PoolTag
& Mask
) == (Tag
& Mask
))
376 if (FoundCallback
!= NULL
)
378 FoundCallback(Entry
, CallbackContext
);
383 KdbpPrint("%p size: %4d previous size: %4d %s %.4s\n",
384 Entry
, Entry
->BlockSize
, Entry
->PreviousSize
,
385 Entry
->PoolType
? "(Allocated)" : "(Free) ",
386 (PCHAR
)&Entry
->PoolTag
);
400 ULONG PoolType
= NonPagedPool
;
404 KdbpPrint("Specify a tag string\n");
408 /* First arg is tag */
409 if (strlen(Argv
[1]) != 1 || Argv
[1][0] != '*')
411 ExpKdbgExtPoolUsedGetTag(Argv
[1], &Tag
, &Mask
);
414 /* Second arg might be pool to search */
417 PoolType
= strtoul(Argv
[2], NULL
, 0);
421 KdbpPrint("Only (non) paged pool are supported\n");
426 /* FIXME: What about large pool? */
428 if (PoolType
== NonPagedPool
)
430 ExpKdbgExtPoolFindNonPagedPool(Tag
, Mask
, NULL
, NULL
);
432 else if (PoolType
== PagedPool
)
434 ExpKdbgExtPoolFindPagedPool(Tag
, Mask
, NULL
, NULL
);
442 ExpKdbgExtIrpFindPrint(
447 BOOLEAN IsComplete
= FALSE
;
448 PIRP_FIND_CTXT FindCtxt
= Context
;
449 PIO_STACK_LOCATION IoStack
= NULL
;
450 PUNICODE_STRING DriverName
= NULL
;
451 ULONG_PTR SData
= FindCtxt
->SData
;
452 ULONG Criteria
= FindCtxt
->Criteria
;
454 /* Free entry, ignore */
455 if (Entry
->PoolType
== 0)
461 Irp
= (PIRP
)POOL_FREE_BLOCK(Entry
);
463 /* Bail out if not matching restart address */
464 if ((ULONG_PTR
)Irp
< FindCtxt
->RestartAddress
)
469 /* Avoid bogus IRP stack locations */
470 if (Irp
->CurrentLocation
<= Irp
->StackCount
+ 1)
472 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
474 /* Get associated driver */
475 if (IoStack
->DeviceObject
&& IoStack
->DeviceObject
->DriverObject
)
476 DriverName
= &IoStack
->DeviceObject
->DriverObject
->DriverName
;
483 /* Display if: no data, no criteria or if criteria matches data */
484 if (SData
== 0 || Criteria
== 0 ||
485 (Criteria
& 0x1 && IoStack
&& SData
== (ULONG_PTR
)IoStack
->DeviceObject
) ||
486 (Criteria
& 0x2 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.OriginalFileObject
) ||
487 (Criteria
& 0x4 && Irp
->MdlAddress
&& SData
== (ULONG_PTR
)Irp
->MdlAddress
->Process
) ||
488 (Criteria
& 0x8 && SData
== (ULONG_PTR
)Irp
->Tail
.Overlay
.Thread
) ||
489 (Criteria
& 0x10 && SData
== (ULONG_PTR
)Irp
->UserEvent
))
493 KdbpPrint("%p Thread %p current stack belongs to %wZ\n", Irp
, Irp
->Tail
.Overlay
.Thread
, DriverName
);
497 KdbpPrint("%p Thread %p is complete (CurrentLocation %d > StackCount %d)\n", Irp
, Irp
->Tail
.Overlay
.Thread
, Irp
->CurrentLocation
, Irp
->StackCount
+ 1);
507 ULONG PoolType
= NonPagedPool
;
508 IRP_FIND_CTXT FindCtxt
;
513 PoolType
= strtoul(Argv
[1], NULL
, 0);
517 KdbpPrint("Only (non) paged pool are supported\n");
522 RtlZeroMemory(&FindCtxt
, sizeof(IRP_FIND_CTXT
));
524 /* Restart address */
527 if (!KdbpGetHexNumber(Argv
[2], &FindCtxt
.RestartAddress
))
529 KdbpPrint("Invalid parameter: %s\n", Argv
[0]);
530 FindCtxt
.RestartAddress
= 0;
536 if (!KdbpGetHexNumber(Argv
[4], &FindCtxt
.SData
))
542 if (strcmp(Argv
[3], "device") == 0)
544 FindCtxt
.Criteria
= 0x1;
546 else if (strcmp(Argv
[3], "fileobject") == 0)
548 FindCtxt
.Criteria
= 0x2;
550 else if (strcmp(Argv
[3], "mdlprocess") == 0)
552 FindCtxt
.Criteria
= 0x4;
554 else if (strcmp(Argv
[3], "thread") == 0)
556 FindCtxt
.Criteria
= 0x8;
558 else if (strcmp(Argv
[3], "userevent") == 0)
560 FindCtxt
.Criteria
= 0x10;
562 else if (strcmp(Argv
[3], "arg") == 0)
564 FindCtxt
.Criteria
= 0x1f;
569 if (PoolType
== NonPagedPool
)
571 ExpKdbgExtPoolFindNonPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
573 else if (PoolType
== PagedPool
)
575 ExpKdbgExtPoolFindPagedPool(TAG_IRP
, 0xFFFFFFFF, ExpKdbgExtIrpFindPrint
, &FindCtxt
);
581 #endif // DBG && KDBG