CHAPTER 3: System Mechanisms

advertisement
CHAPTER 3: System Mechanisms
92
95
97
102
111
117
119
122
125
131
138
141
146
148
152
157
165
168
170
169
Viewing the IDT
Viewing the PIC and APIC
Viewing the IRQL
Using Kernel Profiler to Profile Execution
Monitoring Interrupt and DPC Activity
Viewing the Real User Start Address for Win32 Threads
Unhandled Exceptions
Viewing System Service Activity
Exploring the Object Manager
Viewing the Type Objects
Viewing Open Handles with Nthandle
Viewing the Handle Table with the Kernel Debugger
Viewing Process Quotas
Looking at the Base Named Objects
Viewing Namespace Instancing
Viewing Queued Spinlocks
Looking at Wait Queues
Listing System Worker Threads
Enabling Image Loader Tracing and Viewing NtGlobalFlag
Viewing LPC Port Objects
EXPERIMENT
Viewing the IDT
You can view the contents of the IDT, including information on what trap handlers
Windows 2000 has assigned to interrupts (including exceptions and IRQs), using the !idt
command implemented in the Kdex2x86.dll debugger extension library. Passing the !idt
command a 0 flag shows device driver ISRs that are registered for hardware device
interrupts.
The following example shows how you load the Kdex2x86.dll debugger extension library
and what the output of the !idt command looks like:
kd> .load kdex2x86
Loaded kdex2x86 extension DLL
kd> !idt 0
00: 80463440 (ntkrnlmp!KiTrap00)
01: 80463590 (ntkrnlmp!KiTrap01)
02: 0000144e
03: 8046386c (ntkrnlmp!KiTrap03)
04: 804639d4 (ntkrnlmp!KiTrap04)
05: 80463b18 (ntkrnlmp!KiTrap05)
06: 80463c78 (ntkrnlmp!KiTrap06)
07: 804641bc (ntkrnlmp!KiTrap07)
08: 000014a8
09:
0a:
0b:
0c:
0d:
0e:
0f:
10:
11:
12:
80464558
80464660
8046478c
80464a90
80464c9c
80465708
80465aac
80465bb4
80465cd8
80465aac
(ntkrnlmp!KiTrap09)
(ntkrnlmp!KiTrap0A)
(ntkrnlmp!KiTrap0B)
(ntkrnlmp!KiTrap0C)
(ntkrnlmp!KiTrap0D)
(ntkrnlmp!KiTrap0E)
(ntkrnlmp!KiTrap0F)
(ntkrnlmp!KiTrap10)
(ntkrnlmp!KiTrap11)
(ntkrnlmp!KiTrap0F)
29:
2a:
2b:
2c:
2d:
2e:
2f:
30:
00000000
804628fe
804629f0
80462b10
8046375c
80462420
80465aac
80461a50
(ntkrnlmp!KiGetTickCount)
(ntkrnlmp!KiCallbackReturn)
(ntkrnlmp!KiSetLowWaitHighThread)
(ntkrnlmp!KiDebugService)
(ntkrnlmp!KiSystemService)
(ntkrnlmp!KiTrap0F)
(ntkrnlmp!KiStartUnexpectedRange)
51: 80461b9a (ntkrnlmp!KiUnexpectedInterrupt33)
52: 813dbbe4 (Vector:52,Irql:4,SyncIrql:5,Connected:TRUE, ¬
No:0,ShareVector:FALSE,Mode:Latched,
¬
ISR:i8042prt!I8042KeyboardInterruptService(f04b10cc))
53: 80461bae (ntkrnlmp!KiUnexpectedInterrupt35)
54: 80461bb8 (ntkrnlmp!KiUnexpectedInterrupt36)
d0: 80462090 (ntkrnlmp!KiUnexpectedInterrupt160)
d1: 800638d4 (halmps!HalpClockInterrupt)
d2: 804620a4 (ntkrnlmp!KiUnexpectedInterrupt162)
Some of the interrupt numbers of interest in the example are in the range 0x0 to 0x10,
which includes x86 exception interrupts (for example, a page fault, which is exception
0xe, is handled by KiTrap0E) and the range 0x2a to 0x2e, which includes the system
service dispatcher and other software interrupts that the kernel uses internally as fast
entry points into the kernel from environment subsystems. On the system used to provide
the output for this experiment, the clock interrupt handler is at interrupt number 0xd1 and
the keyboard device driver's (I8042prt.sys) keyboard ISR is at interrupt number 0x52.
EXPERIMENT
Viewing the PIC and APIC
You can view the configuration of the PIC on a uniprocessor and the APIC on a
multiprocessor by using the !pic and !apic I386kd (or Kd) commands, respectively. (You
can't use LiveKd for this experiment because LiveKd can't access hardware.) Here's the
output of the !pic command on a uniprocessor. (Note that the !pic command doesn't work
if your system is using an APIC HAL.)
kd> !pic
----- IRQ Number ----- 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
Physically in service: . . . . . . . . . . . . . . . .
Physically masked:
. . . . Y . Y Y . Y Y Y . Y . Y
Physically requested:
Y . . . . . . . . . . . . . . .
Here's the output of the !apic command on a system running with the MPS HAL. The
"0:" prefix for the I386kd prompt indicates that commands are running on processor 0, so
this is the I/O APIC for processor 0:
0: kd> !apic
Apic @ fffe0000 ID:1 (40011) LogDesc:01000000 DestFmt:ffffffff
TimeCnt: 03f66780clk SpurVec:1f FaultVec:e3 error:80
Ipi Cmd: 000008e1 Vec:E1 FixedDel Lg:02000000
edg
Timer..: 000300fd Vec:FD FixedDel
Dest=Self
edg
Linti0.: 0001001f Vec:1F FixedDel
Dest=Self
edg
Linti1.: 000084ff Vec:FF NMI
Dest=Self
lvl
TMR: 93, a3
IRR: 41, d1, e3
ISR: d1
TPR FF
masked
masked
The following output is for the !ioapic command, which displays the configuration of the
I/O APIC, the interrupt controller component connected to devices.
0: kd> !ioapic
IoApic @ ffd02000
Inti00.: 000100ff
Inti01.: 00000962
Inti02.: 000100ff
Inti03.: 00000971
Inti04.: 000100ff
Inti05.: 00000961
Inti06.: 00010982
Inti07.: 000100ff
Inti08.: 000008d1
Inti09.: 000100ff
Inti0A.: 000100ff
Inti0B.: 000100ff
Inti0C.: 00000972
Inti0D.: 000100ff
Inti0E.: 00000992
Inti0F.: 000100ff
Inti10.: 000100ff
Inti11.: 000100ff
Inti12.: 000100ff
Inti13.: 000100ff
Inti14.: 0000a9a3
Inti15.: 0000a993
Inti16.: 000100ff
Inti17.: 000100ff
ID:8 (11) Arb:0
Vec:FF FixedDel
Vec:62 LowestDl
Vec:FF FixedDel
Vec:71 LowestDl
Vec:FF FixedDel
Vec:61 LowestDl
Vec:82 LowestDl
Vec:FF FixedDel
Vec:D1 FixedDel
Vec:FF FixedDel
Vec:FF FixedDel
Vec:FF FixedDel
Vec:72 LowestDl
Vec:FF FixedDel
Vec:92 LowestDl
Vec:FF FixedDel
Vec:FF FixedDel
Vec:FF FixedDel
Vec:FF FixedDel
Vec:FF FixedDel
Vec:A3 LowestDl
Vec:93 LowestDl
Vec:FF FixedDel
Vec:FF FixedDel
PhysDest:00
Lg:03000000
PhysDest:00
Lg:03000000
PhysDest:00
Lg:03000000
Lg:02000000
PhysDest:00
Lg:01000000
PhysDest:00
PhysDest:00
PhysDest:00
Lg:03000000
PhysDest:00
Lg:03000000
PhysDest:00
PhysDest:00
PhysDest:00
PhysDest:00
PhysDest:00
Lg:03000000
Lg:03000000
PhysDest:00
PhysDest:00
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
edg
lvl
lvl
edg
edg
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
masked
EXPERIMENT
Viewing the IRQL
A data structure called the processor control region (PCR) and its extension the
processor control block (PRCB) contain information about the state of each processor in
the system, such as the current IRQL, a pointer to the hardware IDT, the currently
running thread, and the next thread selected to run. The kernel and the HAL use this
information to perform architecture-specific and machine-specific actions. Portions of the
PCR and PRCB structures are defined publicly in the Windows 2000 Device Driver Kit
(DDK) header file Ntddk.h, so examine that file if you want a complete definition of
these structures.
You can view the contents of the PCR with the kernel debugger by using the !pcr
command:
kd> !pcr
PCR Processor 0 @ffdff000
NtTib.ExceptionList:
NtTib.StackBase:
NtTib.StackLimit:
NtTib.SubSystemTib:
NtTib.Version:
NtTib.UserPointer:
NtTib.SelfTib:
f8effc68
f8effdf0
f8efd000
00000000
00000000
00000000
7ffde000
SelfPcr:
Prcb:
Irql:
IRR:
IDR:
InterruptMode:
IDT:
GDT:
TSS:
ffdff000
ffdff120
00000000
00000000
ffff28e8
00000000
80036400
80036000
802b5000
CurrentThread: 81638020
NextThread: 00000000
IdleThread: 8046bdf0
EXPERIMENT
Using Kernel Profiler to Profile Execution
You can use the Kernel Profiler tool that comes with the Windows 2000 resource kits to
enable the system profiling timer, collect samples of the code that is executing when the
timer fires, and display a summary showing the frequency distribution across image files
and functions. Kernel Profiler is most useful in situations in which performance-critical
code is running in a repeatable manner and you want to obtain a breakdown of where the
system is spending time when the code executes. For the output to be useful, Kernel
Profiler requires that the Windows 2000 symbols be installed on your system. Below is
sample output from Kernel Profiler after collecting information for 30 seconds on a
system that was relatively idle. (Notice that the majority of the samples were in
KiIdleLoop, the idle thread loop, which is explained in Chapter 6.)
C:\kernprof -a -d -x -p -v -t 5 30
Symbols loaded: 80400000 ntoskrnl.exe
delaying for 30 seconds... report on values with 5 hits
end of delay
Processor 0: 30404 Total hits
30404 Total hits
PROCESSOR 0
28708
5
5
6
79
8
6
6
28384
9
6
5
5
0
0
0
0
0
0
0
0
0
0
0
0
ntoskrnl.exe --Total Hits-ntoskrnl.exe memmove 0x08045AEF0 0 3
ntoskrnl.exe ExAcquireResourceExclusiveLite 0x080413A00 0 3
ntoskrnl.exe ExReleaseResourceLite 0x080413E5E 0 3
ntoskrnl.exe KiXMMIZeroPageNoSave 0x080430B88 0 3
ntoskrnl.exe MiInsertPageInList 0x080442E1E 0 3
ntoskrnl.exe MiRemovePageByColor 0x080443756 0 3
ntoskrnl.exe ObReferenceObjectByHandle 0x08044986C 0 3
ntoskrnl.exe KiIdleLoop 0x08045E98C 0 3
ntoskrnl.exe KiSystemService 0x08045F4A0 0 3
ntoskrnl.exe ExAllocatePoolWithTag 0x080465080 0 3
ntoskrnl.exe SepPrivilegeCheck 0x0804F7638 0 3
ntoskrnl.exe IopParseDevice 0x0804B8F20 0 3
563
5
22
0
0
hal.dll --Total Hits-hal.dll KfRaiseIrql 0x080062E90 0 2
hal.dll KfLowerIrql 0x080062F00 0 2
5
14
503
0
0
0
hal.dll READ_PORT_UCHAR 0x080067960 0 2
hal.dll WRITE_PORT_UCHAR 0x0800679C8 0 2
hal.dll HalAcpiC1Idle 0x080068334 0 2
6
atapi.sys --Total Hits--
15
Fastfat.sys --Total Hits--
109
6
15
7
7
0
0
0
0
8
229
22
Ntfs.SYS
Ntfs.SYS
Ntfs.SYS
Ntfs.SYS
Ntfs.sys --Total Hits-NtfsInitializeIrpContext 0x0F99CE432 0 2
NtfsCommonWrite 0x0F99CF480 0 2
NtfsCommonCleanup 0x0F99D6190 0 2
NtfsQueryDirectory 0x0F99DC430 0 2
win32k.sys --Total Hits-0
ntdll.dll --Total Hits-ntdll.dll RtlIsValidHandle 0x077F9ADEE 0 2
5
14
17
7
8
8
8
24
17
33
21
5
0
0
0
0
0
0
0
0
0
0
0
0
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
ntdll.dll
756
ZwReleaseSemaphore 0x077F8872C 0 2
RtlpFreeToHeapLookaside 0x077FB0358 0 2
RtlpInterlockedPushEntrySList 0x077FB7620 0 2
RtlTimeToTimeFields 0x077FA7BFE 0 2
RtlEnterCriticalSection 0x077F87B30 0 2
wcslen 0x077FB3D6E 0 2
RtlpAllocateFromHeapLookaside 0x077FB02E4 0 2
RtlpInterlockedPopEntrySList 0x077FB75FC 0 2
RtlpFindAndCommitPages 0x077FC8DF6 0 2
RtlAllocateHeap 0x077FC6BF8 0 2
RtlFreeHeap 0x077FC7426 0 2
RtlAllocateHeap 0x077FC6BF8 0 2
User Mode --Total Hits-- (NO SYMBOLS)
Context Switch Information
Find any processor
Find last processor
Idle any processor
Idle current processor
Idle last processor
Preempt any processor
Preempt current processor
Preempt last processor
Switch to idle
Total context switches
0
0
0
0
0
0
0
0
0
3255
EXPERIMENT
Monitoring Interrupt and DPC Activity
Using the Windows 2000 Performance tool, you can watch the percentage of time your
system spends on handling interrupts and DPCs. The Processor object has % Interrupt
Time and % DPC Time counters, including Total and per-processor instances, which
means you can monitor the activity on a per-CPU or a systemwide basis. These objects
also have counters to measure the number of interrupts and DPCs per second.
One situation in which you might want to look at these counters is if your system is
spending an inordinate amount of time in kernel mode and you can't attribute all the
kernel-mode CPU time to processes. If total kernel-mode CPU time is greater than the
total kernel-mode CPU time of all processes, the remaining time has to be interrupts or
DPCs because time spent at interrupt level and DPC level isn't charged to any thread's
CPU time performance counter. Be aware that there are inherent inaccuracies in the way
Windows 2000 accounts for CPU time, inaccuracies that relate to the granularity of the
system timer. (See the section "Quantum Accounting" in Chapter 6 for an explanation of
how time accounting works.)
EXPERIMENT
Viewing the Real User Start Address for Win32 Threads
The fact that each Win32 thread begins execution in a system-supplied function (and not
the user-supplied function) explains why the start address for thread 0 is the same for
every Win32 process in the system (and why the start addresses for secondary threads are
also the same). The start address for thread 0 in Win32 processes is the Win32 start-ofprocess function; the start address for any other threads would be the Win32 start-ofthread function. To see the user-supplied function address, use the Tlist utility in the
Windows 2000 Support Tools. Type tlist process-name or tlist process-id to get the
detailed process output that includes this information. For example, compare the thread
start addresses for the Windows Explorer process as reported by Pstat (in the Platform
SDK) and Tlist:
C:\> pstat
pid:3f8 pri: 8 Hnd: 329 Pf: 80043 Ws:
tid pri Ctx Swtch StrtAddr
User Time
7c
9
16442 77E878C1 0:00:01.241
42c 11
157888 77E92C50 0:00:07.110
44c
8
6357 77E92C50 0:00:00.070
1cc
8
3318 77E92C50 0:00:00.030
4620K explorer.exe
Kernel Time State
0:00:01.251 Wait:UserRequest
0:00:34.309 Wait:UserRequest
0:00:00.140 Wait:UserRequest
0:00:00.070 Wait:DelayExecution
C:\> tlist explorer
1016 explorer.exe
Program Manager
CWD:
C:\
CmdLine: Explorer.exe
VirtualSize:
25348 KB
PeakVirtualSize:
31052 KB
WorkingSetSize: 1804 KB
PeakWorkingSetSize: 3276 KB
NumberOfThreads: 4
149 Win32StartAddr:0x01009dbd LastErr:0x0000007e State:Waiting
86 Win32StartAddr:0x77c5d4a5 LastErr:0x00000000 State:Waiting
62 Win32StartAddr:0x00000977 LastErr:0x00000000 State:Waiting
179 Win32StartAddr:0x0100d8d4 LastErr:0x00000002 State:Waiting
The start address of thread 0 reported by Pstat is the internal Win32 start-of-process
function; the start addresses for threads 1 through 3 are the internal Win32 start-of-thread
functions. Tlist, on the other hand, shows the user-supplied Win32 start address (the user
function called by the internal Win32 start function).
EXPERIMENT
Unhandled Exceptions
To see an example Dr. Watson log file, run the program \Tools\Accvio.exe from this
book's companion CD. This program generates a memory access violation by attempting
to write to address 0, which is always an invalid address in Win32 processes. (See Table
7-6 in Chapter 7.)
1. Run the Registry Editor, and locate HKLM\SOFTWARE\
Microsoft\Windows NT\CurrentVersion\AeDebug.
2. If the Debugger value is "drwtsn32 -p %ld -e %ld -g," your system is set
up to run Dr. Watson as the default debugger. Proceed to step 4.
3. If the value of Debugger was not set up to run Drwtsn32.exe, you can still
test Dr. Watson by temporarily installing it and then restoring your
previous debugger settings:
o Save the current value somewhere (for example, in a Notepad file
or in the current paste buffer).
o Select Run from the taskbar Start menu, and then enter drwtsn32 i. (This initializes the Debugger field to run Dr. Watson.)
4. Run the test program \Tools\Accvio.exe.
5. The Program Error message box should come up—when the log file and
crash dump have been created, the button will change from Cancel to OK.
(Note: This error message occurs by default only on Windows 2000
Professional installations of Dr. Watson—Windows 2000 Server by
default will not show a message box, but the dump files will still be
created. You also might see a different error message if Dr. Watson is not
your default debugger.)
6. Click OK to dismiss the message box.
7. Run Drwtsn32.exe. (Select Run from the Start menu, and then enter
drwtsn32.)
8. In the list of Application Errors, click on the last entry and then click the
View button—the portion of the Dr. Watson log file containing the details
of the access violation from Accvio.exe will be displayed. (For details on
the log file format, press Help in the Dr. Watson For Windows 2000
dialog box and select Dr. Watson Log File Overview.)
9. If the original value of Debugger wasn't the default Dr. Watson settings,
restore the saved value from step 1.
As another experiment, try changing the value of Debugger to another program, such as
Notepad.exe (Notepad editor) or Sol.exe (Solitaire). Rerun Accvio.exe, and notice that
whatever program is specified in the Debugger value is run—that is, there's no validation
that the program defined in Debugger is actually a debugger. Make sure you restore your
registry settings. (As noted in step 3b, to reset to the system default Dr. Watson settings,
type drwtsn32 -i in the Run dialog box or at a command prompt.)
EXPERIMENT
Viewing System Service Activity
You can monitor system service activity by watching the System Calls/Sec performance
counter in the System object. Run the Performance tool, and in chart view, click the Add
button to add a counter to the chart; select the System object, select the System Calls/Sec
counter, and then click the Add button to add the counter to the chart.
EXPERIMENT
Exploring the Object Manager
Throughout this section, you'll find experiments that show you how to peer into the
object manager database. These experiments use the following tools, which you should
become familiar with if you aren't already:



Object viewer There are two versions of this tool: the version from
www.sysinternals.com (on this book's companion CD as
\Sysint\Winobj.exe) and a different version in (the Platform SDK (in
\Program Files\Microsoft Platform SDK\Bin\ Winnt\Winobj.exe). The
object viewer from www.sysinternals.com displays more accurate
information about objects (such as the reference count, the number of open
handles, security descriptors, and so forth) than the object viewer in the
Platform SDK does.
Open handles Two tools from www.sysinternals.com show open handles:
a GUI tool (on this book's companion CD in \Sysint\Handleex.exe) and a
command-line tool (on the companion CD in \Sysint\Nthandle.exe). The
Windows 2000 resource kits include another tool that shows open handles,
called Oh.exe.
The kernel debugger !handle command.
The object viewer provides a way to traverse the namespace that the object manager
maintains. (As we'll explain later, not all objects have names.) Try running the WinObj
object manager utility from the companion CD and examining the layout, shown here:
In the Windows 2000 Resource Kit Tools Help for OH, you'll find out that if object
tracking—an internal debugging feature in the executive—isn't enabled, OH will enable
it by setting a Windows 2000 global flag in the registry and then rebooting your system.
Neither Nthandle nor Handleex from the companion CD require object tracking. (You
can enable object tracking by manually setting the flag and rebooting your system. See
the section "Windows 2000 Global Flags" for more on global flags.) Because this flag
uses additional memory to track object usage information, you should disable it with the
Gflags utility after you've experimented with OH and then reboot your system again.
EXPERIMENT
Viewing the Type Objects
You can see the list of type objects declared to the object manager with the Object
Viewer utility on this book's companion CD. Just run \Sysint\Winobj.exe, and then in the
Winobj object manager open the \ObjectTypes directory, as shown here:
EXPERIMENT
Viewing Open Handles with Nthandle
As shown in the following example, the Nthandle tool (\Sysint\ Nthandle.exe, which
you'll find on this book's companion CD) can display the handles open by any or all
processes:
C:\>nthandle -a -p system
Handle V1.2
Copyright (C) 1997-2000 Mark Russinovich
Systems Internals - http://www.sysinternals.com
------------------------------------------------------------------System pid: 8
4: Process
8: Key
\REGISTRY
c: Thread
10: Key
HKLM\SYSTEM\ControlSet003\Control\ProductOptions
14: Key
HKLM\SYSTEM\Setup
18: Key
HKLM\SYSTEM\ControlSet003\Control\IDConfigDB\CurrentDockInfo
1c: Key
HKLM\SYSTEM\ControlSet003\Hardware Profiles\Current
20: Key
HKLM\HARDWARE\DESCRIPTION\SYSTEM\MultifunctionAdapter
The display above shows the first eight open handles in the System process. The process
name and ID are displayed first, followed by a line for each handle. The handle value,
object type, and object name are shown for each handle. Because we specified the -a flag,
handles to objects that don't have names (handle numbers 0x4, 0xc, and 0x18) are
included.
EXPERIMENT
Viewing the Handle Table with the Kernel Debugger
The !handle command in the kernel debugger takes three arguments:
!handle <handle index> <flags> <processid>
The handle index identifies the handle entry in the handle table. (Zero means display all
handles.) The first handle is index 4, the second 8, and so on. For example, typing
!handle 4 will show the first handle for the current process.
The flags you can specify are a bitmask, where bit 0 means display only the information
in the handle entry, bit 1 means display free handles (not just used handles), and bit 2
means display information about the object that the handle refers to. The following
command displays full details about the handle table for process ID 0x408:
kd> !handle 0 7 408
processor number 0
Searching for Process with Cid == 408
PROCESS 865f0790 SessionId: 0 Cid: 0408 Peb: 7ffdf000 ParentCid: 01dc
DirBase: 04fd3000 ObjectTable: 856ca888 TableSize: 21.
Image: i386kd.exe
Handle Table at e2125000 with 21 Entries in use
0000: free handle
0004: Object: e20da2e0 GrantedAccess: 000f001f
Object: e20da2e0 Type: (81491b80) Section
ObjectHeader: e20da2c8
HandleCount: 1 PointerCount: 1
0008: Object: 80b13330 GrantedAccess: 00100003
Object: 80b13330 Type: (81495100) Event
ObjectHeader: 80b13318
HandleCount: 1 PointerCount: 1
EXPERIMENT
Viewing Process Quotas
You can view the paged pool, nonpaged pool, and page file current usage, peak usage,
and quota (limit) for a process with the Process Explode utility, Pview.exe, available on
www.reskit.com. (The Performance tool displays only the usage information, not the
quotas.) In the following example, the process selected has a peak paged pool usage of
1062 KB, current usage of 1028 KB, and a quota of 1504 KB:
EXPERIMENT
Looking at the Base Named Objects
You can see the list of base objects that have names with the Object Viewer utility on this
book's companion CD. (Another version of this utility is also available with the Platform
SDK.) Run \Sysint\Winobj.exe, and click on \BaseNamedObjects, as shown here:
The named objects are shown on the right. The icons indicate the object type.





Mutexes are indicated with a stop sign.
Sections (Win32 file mapping objects) are shown as memory chips.
Events are shown as exclamation points.
Semaphores are indicated with an icon that resembles a traffic signal.
Symbolic links have icons that are curved arrows.
EXPERIMENT
Viewing Namespace Instancing
You can see the object manager instance the namespace on a Windows 2000 Server,
Advanced Server, or Datacenter Server system on which you install Terminal Services.
Logon to the server using the Terminal Services client, and run the \Sysint\Winobj.exe
utility from this book's companion CD.
Click on the \Sessions directory, and you'll see a subdirectory with a numeric name for
each active remote session. If you open one of these directories, you'll see subdirectories
named \DosDevices, \Windows, and \BaseNamedObjects, which are the local namespace
subdirectories of the session. The following screen shot shows a local namespace:
EXPERIMENT
Viewing Queued Spinlocks
You can view the state of queued spinlocks by using the !qlock kernel debugger
command. This command is meaningful only on a multiprocessor system because
uniprocessor HALs don't implement spinlocks. In the following example, the dispatcher
database queued spinlock is held by processor 1, and the other queued spinlocks are not
acquired. (The dispatcher database is described in Chapter 6.)
kd> !qlocks
Key: O = Owner, 1n = Wait order, blank = not owned/waiting, C = Corrupt
Lock Name
KE
KE
MM
MM
CC
CC
-
Dispatcher
Context Swap
PFN
System Space
Vacb
Master
0
1
O
Processor Number
2 3 4 5 6 7
8
9 10 11 12 13 14 15
EXPERIMENT
Looking at Wait Queues
Although many process viewer utilities indicate whether a thread is in a wait state (and if
so, what kind of wait), you can see the list of objects a thread is waiting on only with the
kernel debugger !thread command. For example, the following excerpt from the output of
a !process command shows that the thread is waiting on an event object:
kd> !process
THREAD 80618030 Cid 97.7f Teb: 7ffde000 Win32Thread: e199cea8
WAIT: (WrUserRequest) UserMode Non-Alertable
805b4ab0 SynchronizationEvent
Although the kernel debugger doesn't have a command for formatting the contents of a
dispatcher header, we know the layout (described in the previous section "Data
Structures") so we can interpret its contents manually:
kd> dd 805b4ab0
0x805B4AB0 00040001 00000000 8061809c 8061809c ..........a...a.
From this, we can ascertain that no other threads are waiting on this event object because
the wait list head forward and backward pointers (the third and fourth 32-bit values) point
to the same location (a single wait block). Dumping the wait block (at address
0x8061809c) yields the following:
kd> dd 8061809c
0x8061809C 805b4ab8 805b4ab8 80618030 805b4ab0 .J[..J[.0.a..J[.
0x806180AC 8061809c 00010000 00000000 00000000 ..a.............
The first two 32-bit values point to the list head of the wait blocks in the dispatcher
header. The third 32-bit value is the pointer to the thread object. The fourth value points
to the dispatcher object itself. The fifth value (0x8061809c) is the pointer to the next wait
block. From this, we can conclude that the thread is not waiting on any other objects,
since the next wait block field points to the wait block itself.
EXPERIMENT
Listing System Worker Threads
You can use the !exqueue kernel debugger command to see a listing of system worker
threads classified by their type:
kd> !exqueue
Dumping ExWorkerQueue: 8046A5C0
**** Critical WorkQueue( current = 0 maximum = 1 )
THREAD 818a2d40 Cid 8.c
Teb: 00000000 Win32Thread:
THREAD 818a2ac0 Cid 8.10 Teb: 00000000 Win32Thread:
THREAD 818a2840 Cid 8.14 Teb: 00000000 Win32Thread:
THREAD 818a25c0 Cid 8.18 Teb: 00000000 Win32Thread:
THREAD 818a2340 Cid 8.1c Teb: 00000000 Win32Thread:
**** Delayed WorkQueue( current
THREAD 818a20c0 Cid 8.20 Teb:
THREAD 818a1020 Cid 8.24 Teb:
THREAD 818a1da0 Cid 8.28 Teb:
00000000
00000000
00000000
00000000
00000000
WAIT
WAIT
WAIT
WAIT
WAIT
= 0 maximum = 1 )
00000000 Win32Thread: 00000000 WAIT
00000000 Win32Thread: 00000000 WAIT
00000000 Win32Thread: 00000000 WAIT
**** HyperCritical WorkQueue( current = 0 maximum = 1 )
THREAD 818a1b20 Cid 8.2c Teb: 00000000 Win32Thread: 00000000 WAIT
EXPERIMENT
Enabling Image Loader Tracing and Viewing NtGlobalFlag
To see an example of the detailed tracing information you can obtain by setting global
flags, try running Gflags on a system booted with the kernel debugger that is connected to
a host system running Kd or Windbg, or that is running LiveKd.
As an example, try enabling the Show Loader Snaps flag. To do this, select Kernel Mode,
click the Show Loader Snaps check box, and click the Apply button. Then run an image
on this machine, and in the kernel debugger you'll see volumes of output like the
following:
LDR: PID: 0xb8 started - 'notepad'
LDR: NEW PROCESS
Image Path: C:\WINNT\system32\notepad.exe (notepad.exe)
Current Directory: C:\ddk\bin
Search Path: C:\WINNT\System32;C:\WINNT\system;C:\WINNT
LDR: notepad.exe bound to comdlg32.dll
LDR: ntdll.dll used by comdlg32.dll
LDR: Snapping imports for comdlg32.dll from ntdll.dll
LDR: KERNEL32.dll loaded. - Calling init routine at 77f01000
LDR: RPCRT4.dll loaded. - Calling init routine at 77e1b6d5
LDR: ADVAPI32.dll loaded. - Calling init routine at 77dc1000
LDR: USER32.dll loaded. - Calling init routine at 77e78037
You can use the !gflags and !gflag kernel debugger commands to view the state of the
NtGlobalFlag kernel variable. The !gflags command lists all the flags, indicating which
ones are enabled, whereas !gflag reports only the flags that are enabled.
kd> !gflags
NT!NtGlobalFlag 0x4400
STOP_ON_EXCEPTION
DEBUG_INITIAL_COMMAND
HEAP_ENABLE_TAIL_CHECK
HEAP_VALIDATE_PARAMETERS
*POOL_ENABLE_TAGGING
USER_STACK_TRACE_DB
*MAINTAIN_OBJECT_TYPELIST
ENABLE_CSRDEBUG
DISABLE_PAGE_KERNEL_STACKS
ENABLE_CLOSE_EXCEPTIONS
ENABLE_HANDLE_TYPE_TAGGING
DEBUG_INITIAL_COMMAND_EX
SHOW_LDR_SNAPS
STOP_ON_HUNG_GUI
HEAP_ENABLE_FREE_CHECK
HEAP_VALIDATE_ALL
HEAP_ENABLE_TAGGING
KERNEL_STACK_TRACE_DB
HEAP_ENABLE_TAG_BY_DLL
ENABLE_KDEBUG_SYMBOL_LOAD
HEAP_DISABLE_COALESCING
ENABLE_EXCEPTION_LOGGING
HEAP_PAGE_ALLOCS
DISABLE_DBGPRINT
kd> !gflag
NtGlobalFlag at 8046a164
Current NtGlobalFlag contents: 0x00004400
ptg - Enable pool tagging
otl - Maintain a list of objects for each type
EXPERIMENT
Viewing LPC Port Objects
You can see named LPC port objects with the Object Viewer utility included on this
book's companion CD. Run \Sysint\Winobj.exe, and select the root directory. A plug icon
identifies the port objects, as shown here:
To see the LPC port objects used by RPC, select the \RPC Control directory, as shown
here:
You can also view LPC port objects by using the !lpc kernel debugger command. The
command accepts parameters that direct it to show LPC ports, LPC messages, and
threads that are waiting or sending LPC messages. To view the Lsass authentication port
(the port that Winlogon sends logon requests to), first obtain a list of the ports on the
system:
kd> !lpc
Usage:
!lpc
- Display this help
!lpc message [MessageId] - Display the message with a
given ID and all related
information
If MessageId is not
specified, dump all messages
!lpc port [PortAddress] - Display the port information
!lpc scan PortAddress
- Search this port and any
connected port
!lpc thread [ThreadAddr] - Search the thread in rundown
port queues and display the
port info
If ThreadAddr is missing,
display all threads marked
as doing some lpc operations
kd> !lpc port
Scanning 206 objects
1 Port: 0xe1360320 Connection: 0xe1360320
Communication: 0x00000000 'SeRmCommandPort'
1 Port: 0xe136bc20 Connection: 0xe136bc20
Communication: 0x00000000 'SmApiPort'
1 Port: 0xe133ba80 Connection: 0xe133ba80
Communication: 0x00000000 'DbgSsApiPort'
1 Port: 0xe13606e0 Connection: 0xe13606e0
Communication: 0x00000000 'DbgUiApiPort'
1
Port: 0xe205f040 Connection: 0xe205f040
Communication: 0x00000000 'LsaAuthenticationPort'
Locate the port named LsaAuthenticationPort in the output and then examine it by
passing its address to the !lpc command:
kd> !lpc port 0xe205f040
Server connection port e205f040 Name: LsaAuthenticationPort
Handles: 1
References: 37
Server process : ff7d56c0 (lsass.exe)
Queue semaphore : ff7bfcc8
Semaphore state 0 (0x0)
The message queue is empty
The LpcDataInfoChainHead queue is empty
Download