天天看點

用windbg尋找裝置樹根節點

    用ReactOS上明确說過,Pnp管理器對每種裝置都會建立一個虛拟root device用于建構裝置樹;同時這個新建立的root device又作為一個裝置棧的棧底,往上形成完整的裝置棧。用windbg調試時,可以看到這個虛拟裝置屬于/driver/pnpmanager驅動。

    昨天出于好奇想看下裝置樹,結果發現隻有虛拟裝置attach在/driver/pnpmanger建立的裝置上,而類似pci/usb裝置的裝置棧棧底根本不是/driver/pnpmanager裝置,這讓我很是懷疑,M$到底怎樣形成以root為根節點的裝置樹。

如mssmbios.sys位于裝置管理器system裝置類下,系統資料庫路徑為:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\0002

用windbg檢視裝置堆棧,可以看到這個裝置attach在/driver/pnpmanger根節點上:

kd> !drvobj mssmbios
Driver object (81f81da0) is for:
 \Driver\mssmbios
Driver Extension List: (id , addr)

Device Object list:
81c8e408  
kd> !devstack 81c8e408  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 81c8e408  \Driver\mssmbios   81c8e4c0  
  821e73d0  \Driver\PnpManager 821e7488  00000034 
!DevNode 821e7288 :
  DeviceInst is "Root\SYSTEM\0002"
  ServiceName is "mssmbios"      

又如DDK樣例toaster的虛拟總線裝置busenum同樣位于system裝置類下,系統資料庫路徑為:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\0003

其裝置棧為:,亦可看到棧底pnpmanager裝置

kd> !drvobj busenum
Driver object (81f81030) is for:
 \Driver\busenum
Driver Extension List: (id , addr)

Device Object list:
81ff3030  
kd> !devstack 81ff3030  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 81ff3030  \Driver\busenum    81ff30e8  
  821e7190  \Driver\PnpManager 821e7248  00000035
!DevNode 821a0008 :
  DeviceInst is "Root\SYSTEM\0003"
  ServiceName is "busenum"      

    然而,對于一些總線裝置根本找不到pnpmanager,如PCI總線和USB總線:

kd> !drvobj pci
Driver object (82189218) is for:
 \Driver\PCI
Driver Extension List: (id , addr)

Device Object list:
82127c70  82127e50  82127030  821e03a0
...
8219cb98  821e5370  821ba160  
kd> !devstack 82127c70  
  !DevObj   !DrvObj            !DevExt   ObjectName
  81d34028  \Driver\usbehci    81d340e0  USBFDO-1
  82127790  \Driver\ACPI       82187810  00000064
> 82127c70  \Driver\PCI        82127d28  NTPNP_PCI0043
!DevNode 821272e8 :
  DeviceInst is "PCI\VEN_15AD&DEV_0770&SUBSYS_077015AD&REV_00\4&47b7341&0&1888"
  ServiceName is "usbehci"      
kd> !drvobj usbhub
Driver object (820de2c0) is for:
 \Driver\usbhub
Driver Extension List: (id , addr)

Device Object list:
81c74c98  81d542f0  820f1b70  81fcac98
81c7ac98  
kd> !devstack  81c74c98  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 81c74c98  \Driver\usbhub     81c74d50  00000079
  81d542f0  \Driver\usbhub     81d543a8  USBPDO-3
!DevNode 81c82c48 :
  DeviceInst is "USB\Vid_0e0f&Pid_0002\6&2edefd9b&0&2"
  ServiceName is "usbhub"      

    對此,我百思不得解,pnpmanager去哪了?經過周AM指點,搞明白一件事:用!drvobj PCI列出pci裝置中,除了最後一個是Fdo,其他都是Pdo(這裡Fdo裝置的意思是由PCI總線驅動AddDevice函數建立的裝置,附加在底層的ACPI總線上,而Pdo裝置是PCI總線探測到總線上接入了新裝置,進而為這個新裝置建立了一個Pdo以形成裝置棧)。這些Fdo本身是由PCI總線建立,是以并不會attach在pnpmanager上,而通過查找Fdo裝置的裝置棧,才能找出棧底Pnpmanager。

    順着周AM的思路,我重新調試了一遍,的确找到了PCI總線所在的Pnpmanager,以上面的環境為例,

kd> !drvobj pci
Driver object (82189218) is for:
 \Driver\PCI
Driver Extension List: (id , addr)

Device Object list:
82127c70  82127e50  82127030  821e03a0
...
8219cb98  821e5370  821ba160      

Pci總線驅動建立的裝置0x821ba160就是Fdo(為什麼Fdo位于最後?因為這是PCI!AddDevice建立的第一個裝置對象,之後建立的裝置對象都通過InsertListTail插入到裝置隊列頭部,是以周遊裝置隊列時,Fdo是最後被周遊到的),檢視它的裝置棧:

kd> !devstack 821ba160
  !DevObj   !DrvObj            !DevExt   ObjectName
> 821ba160  \Driver\PCI        821ba218  
  821731a8  \Driver\ACPI       821e2940  00000038
!DevNode 821de178 :
  DeviceInst is "ACPI\PNP0A03\2&daba3ff&0"
  ServiceName is "pci"      

    PCI裝置堆疊在ACPI的Pdo上,怪不得找不到在PCI的裝置棧中找不到Pnpmanager。繼續尋祖,查找ACPI驅動建立的Fdo:

kd> !drvobj ACPI
Driver object (8219ca10) is for:
 \Driver\ACPI
Driver Extension List: (id , addr)

Device Object list:
8212c628  8212c740  8212c858  82126538
...
821731a8  8219c8f8  
kd> !devstack 8219c8f8  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 8219c8f8  \Driver\ACPI       821e2ea0  
  821a0aa8  \Driver\ACPI_HAL   821a0b60  00000037
!DevNode 8219cd50 :
  DeviceInst is "ACPI_HAL\PNP0C08\0"
  ServiceName is "ACPI"      

    同樣ACPI的Fdo堆疊在ACPI_HAL驅動的Pdo上,繼續尋祖,這次找ACPI_HAL的堆疊情況:

kd> !drvobj ACPI_HAL
Driver object (821a0f38) is for:
 \Driver\ACPI_HAL
Driver Extension List: (id , addr)

Device Object list:
821a0aa8  821a0bc8  
kd> !devstack 821a0bc8  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 821a0bc8  \Driver\ACPI_HAL   821a0c80  
  821a4c68  \Driver\PnpManager 821a4d20  00000001
!DevNode 821a4b20 :
  DeviceInst is "Root\ACPI_HAL\0000"      

    終于在ACPI_HAL驅動的Fdo裝置棧中找到了Pnpmanager。這和Windows核心原理與實作書中提供的裝置樹的結構完全相似

    如果此時再深究一下PnpManager驅動建立的裝置對象,會發現系統中果真隻有一個根裝置節點,而其他的PnpManager裝置對象都是為了擴充裝置樹一點一點生長出來的:

kd> !drvobj PnpManager
Driver object (821eb2e8) is for:
 \Driver\PnpManager
Driver Extension List: (id , addr)

Device Object list:
821e7190  821e73d0  821e7610  821e7850
...
821a4c68  821a4020  
kd> !devstack  821a4020  
  !DevObj   !DrvObj            !DevExt   ObjectName
> 821a4020  \Driver\PnpManager 821a40d8  
!DevNode 821a4ee8 :
  DeviceInst is "HTREE\ROOT\0" <----從名字能感覺出這是根裝置節點
kd> !devstack 821a4c68  
  !DevObj   !DrvObj            !DevExt   ObjectName
  821a0bc8  \Driver\ACPI_HAL   821a0c80  
> 821a4c68  \Driver\PnpManager 821a4d20  00000001  <----<span style="font-family: Arial, Helvetica, sans-serif;">名字看着這麼沒個性,肯定不是根裝置節點了</span>
!DevNode 821a4b20 :
  DeviceInst is "Root\ACPI_HAL\0000"