天天看點

windbg調試ACPI ASL Code 執行個體一則

準備工作:搭建ACPI調試環境請移步至:《​​搭建Win7調試ACPI的環境​​》裡面有Checked Build ACPI.sys

本文中OS為Win7 x86(鏡像:en_windows_7_ultimate_x86_dvd_X15-65921.iso)

kd> vertarget 
;記得OS一定要和ACPI.sys比對,否則替換ACPI後OS可能無法啟動。
;我的OS版本資訊如下
Windows 7 Kernel Version 7600 MP (1 procs) Free x86 compatible
Built by: 7600.16385.x86fre.win7_rtm.090713-1255      

這次調試對象為vmware中序列槽裝置COM1,如下圖,目标是在裝置管理中執行Disable Com1時,跟蹤COM1所執行的AML代碼(即,Method(_DIS))。

windbg調試ACPI ASL Code 執行個體一則

這是要跟蹤的COM1 ACPI Method:

kd> !amli dns /s \_sb.pci0.isa.sio.COMA._DIS
;!amli dns /s查找ACPI命名空間中的命名對象
ACPI Name Space: \_SB.PCI0.ISA.SIO.COMA._DIS (ffffffff85172318)
Method(_DIS:Flags=0x0,CodeBuff=85172375,Len=7)      

我停用COM1前,設定裝置管理器的列出裝置的方式為"Devices by connection",這為了友善确認COM裝置在裝置樹中的總線路徑。根據上圖顯示,初步斷定裝置COM1在ACPI命名空間中的路徑是:\_SB.PCI0.ISA.SIO.COMA。确認一下我的猜測是否正确:

kd> !amli find COMA
\_SB.PCI0.ISA.SIO.COMA      

!amli find将輸出比對的ACPI命名對象在ACPI命名空間中的完整路徑。在不同域下會有同名ACPI對象,是以find的輸出可能不唯一。比如,很多裝置(畢竟Device(){}會在ACPI命名空間中建立一個新的域)都有Method(_DIS)這個函數,是以,執行!amli find _DIS可能會得到這樣的輸出:

windbg調試ACPI ASL Code 執行個體一則

如果不确定上述輸出中哪個是調試目标,可以在windbg開啟ACPI日志輸出,然後執行對應的ACPI Method(如停用/啟用裝置)。在啟停過程中,windbg将輸出ACPI Object及相應Method執行的資訊:

kd> !amli set spewon verboseon traceon
;開啟ACPI Log輸出
kd> g ;執行該指令後,在裝置管理中停用COM1,得到如下輸出
AMLI: 85409D48: EvalNameSpaceObject(\_SB.PCI0.ISA.SIO.COMA._STA)

AMLI: 85409D48: \_SB.PCI0.ISA.SIO.COMA._STA()

ffffffff851723e5: {
ffffffff851723e5: | If(And(SIOC=0xf,0x2,)=0x2)
ffffffff851723ef: | {
ffffffff851723ef: | | If(FCMA=0x0)
ffffffff851723f8: | | If(S1BL=0xfe)
ffffffff851723fe: | | {
ffffffff851723fe: | | | Return(0xd)
ffffffff85172401: | | }
ffffffff85172401: | }      

我們在裝置管理器中看到的COM裝置名是COM1,為什麼在ACPI輸出中看到的裝置名是\_SB.PCI0.ISA.SIO.COMA (RW Utility中在\_SB.PCI0.ISA下也找不到COM1這樣的裝置)?來看下Device(COMA)的ASL Code:

kd> !amli dns /s \_SB.PCI0.ISA.SIO.COMA

ACPI Name Space: \_SB.PCI0.ISA.SIO.COMA (ffffffff85172020)
Device(COMA)
| Integer(_HID:Value=0x000000000105d041[17158209])
| Integer(_UID:Value=0x0000000000000001[1])
| String(_DDN:Str="COM1")
| Method(_CRS:Flags=0x8,CodeBuff=851721c1,Len=18)
| Method(_SRS:Flags=0x9,CodeBuff=8517223d,Len=89)
| Method(_PRS:Flags=0x0,CodeBuff=85172301,Len=10)
| Method(_DIS:Flags=0x0,CodeBuff=85172375,Len=7)
| Method(_STA:Flags=0x0,CodeBuff=851723e5,Len=46)      

ACPI Method是ACPI對象,ACPI Device也是ACPI對象,是以都可以用!amli dns /s指令檢視對象資訊。當然也可以RW Utility檢視Device(COMA)的實作:

windbg調試ACPI ASL Code 執行個體一則

檢視ACPI Spec,_DDN對象用于設定裝置DOS Device Name(是不是可以認為是裝置的别名?),可能這是我們在裝置管理器中看到COM1的原因。

找到了COMA的Method對象,試試單步跟蹤ACPI Method。根據前面的Log輸出可知在停用過程中會調用Method(_STA)&Method(_DIS)方法,就在他們身上下斷點吧:

kd> !amli bp  \_SB.PCI0.ISA.SIO.COMA._STA
kd> !amli bp  \_SB.PCI0.ISA.SIO.COMA._DIS      

停用裝置後,windbg會中斷到ACPI解釋器,(此時Windbg的Command框字首為"Input>",在Command框中直接輸入!amli的command即可,如bp \_SB.PCI0.ISA.SIO.COMA_STA,不用帶!amli),如圖:

windbg調試ACPI ASL Code 執行個體一則

之前下了2個ASL Code斷點,是以windbg中斷時,我們并不清楚中斷發生在哪個函數,可以用!amli lc指令檢視背景正在執行的ACPI Method:

Input> AMLI(? for help)-> lc
lc
*Ctxt=ffffffff85f56000, ThID=ffffffff85157998, Flgs=A--CR----, pbOp=ffffffff851723e5, Obj=\_SB.PCI0.ISA.SIO.COMA._STA
;每一行輸出代表正在執行的ACPI method;如果行首帶"*"表示該函數在執行過程中觸發了中斷      

執行完!amli lc後,可以順帶執行!amli r指令,檢視該函數執行的上下文(參數/局部變量等資訊):

Input> AMLI(? for help)-> r
r
Context=85f56000*, Queue=0, ResList=0
ThreadID=85f5600085157998, Flags=00000130, pbOp=ffffffff851723e5:[\_SB.PCI0.ISA.SIO.COMA._STA]
StackTop=ffffffff85f57ee8, UsedStackSize=280 bytes, FreeStackSize=7664 bytes
LocalHeap=85f560c4, CurrentHeap=ffffffff85f560c4, UsedHeapSize=52 bytes
Object=\_SB.PCI0.ISA.SIO.COMA._STA, Scope=\_SB.PCI0.ISA.SIO.COMA._STA, ObjectOwner=ffffffff85f560e8, SyncLevel=0
AsyncCallBack=ffffffff87c4ac82, CallBackData=ffffffff8555fee0, CallBackContext=ffffffff8555feb0

;ASL Method的局部變量
MethodObject=\_SB.PCI0.ISA.SIO.COMA._STA
ffffffff85f57f38: Local0=Unknown()
ffffffff85f57f50: Local1=Unknown()
ffffffff85f57f68: Local2=Unknown()
ffffffff85f57f80: Local3=Unknown()
ffffffff85f57f98: Local4=Unknown()
ffffffff85f57fb0: Local5=Unknown()
ffffffff85f57fc8: Local6=Unknown()
ffffffff85f57fe0: Local7=Unknown()
85f56040: RetObj=Unknown()

Next AML Pointer: ffffffff851723e5:[\_SB.PCI0.ISA.SIO.COMA._STA]

;ASL Method的實作
ffffffff851723e5 : If(And(SIOC, 0x2, ))
ffffffff851723ef : {
ffffffff851723ef : | If(FCMA)
ffffffff851723f5 : | {
ffffffff851723f5 : | | Return(0xf)
ffffffff851723f8 : | }
ffffffff851723f8 : | If(S1BL)      

最後,中斷到ASL Method中了,就可以用!amli t或者!amli p單步跟蹤Method執行:

Hit Breakpoint 1.

AMLI(? for help)-> t ;單步執行\_SB.PCI0.ISA.SIO.COMA._STA函數的ASL Code
t  ;單步1
If(And(SIOC=0xf,0x2,)=0x2
AMLI(? for help)-> t
t  ;單步2
)
ffffffff851723ef: | {
ffffffff851723ef: | | If(FCMA=0x0)
;!amli u反彙編即将執行的ASL Code
AMLI(? for help)-> u
u
ffffffff851723f8:[\_SB.PCI0.ISA.SIO.COMA._STA+0x13]
ffffffff851723f8 : If(S1BL)
ffffffff851723fe : {
ffffffff851723fe : | Return(0xd)
ffffffff85172401 : }
ffffffff85172401 : Store(Ones, S1BL)
ffffffff85172407 : If(S1BL)
ffffffff8517240d : {
ffffffff8517240d : | Return(0xd)
ffffffff85172410 : }
ffffffff85172410 : Return(AMLI_DBGERR: UnAsmDataObj: input buffer is too small
AMLI_DBGERR: Failed to unassemble scope at da317e2 (size=27)      

最後的最後,一些ACPI事件發生時,可以從ACPI解釋器退出到核心調試器(!amli q),檢視觸發該ACPI事件的DeviceObject及相應的IRP。以ACPI _PTS對象為例,根據ACPI Spec,當系統關機(進入S5)時會執行該對象。

kd> !amli bp \_PTS
kd> g ;執行後馬上關機,windbg中斷到ACPI解釋器
AMLI(? for help)-> q      
windbg調試ACPI ASL Code 執行個體一則
kd> kb
 # ChildEBP RetAddr  Args to Child              
00 8078fac8 87cad6f4 00000000 00000000 00000000 ACPI!DebugQuit+0x24
01 8078faf8 87cad875 87cc5128 8078fc1c 873c29e0 ACPI!DbgExecuteCmd+0xaf
02 8078fe34 87c9c1fa 87cc5128 87cb8854 8078fe64 ACPI!Debugger+0x104
03 8078fe44 87c9a145 00000000 873c29e0 873c29d8 ACPI!AMLIDebugger+0x33
....
13 8a00fae0 82a5cd16 86390030 85181bf0 00000016 ACPI!ACPIDispatchIrp+0x1dc
14 8a00faf8 82a8d4ae 8746fb2c 86390030 8a00fb10 nt!IopPoHandleIrp+0x28
15 8a00fb08 82a5f049 8a00fb30 87c53b57 86390030 nt!IofCallDriver+0x55
16 8a00fb10 87c53b57 86390030 8746fa58 87c5c398 nt!IoCallDriver+0x10      
kd> !object 86390030 
Object: 86390030  Type: (8521ebc8) Device
    ObjectHeader: 86390018 (new version)
    HandleCount: 0  PointerCount: 7
    Directory Object: 88e0f638  Name: 0000004a
kd> !devstack 86390030 
  !DevObj   !DrvObj            !DevExt   ObjectName
  86667e10  \Driver\intelppm   866665d0  
> 86390030  \Driver\ACPI       85181bf0  0000004a
!DevNode 860dba18 :
  DeviceInst is "ACPI\GenuineIntel_-_x86_Family_6_Model_94_-_Intel(R)_Core(TM)_i5-6300HQ_CPU_@_2.30GHz\_0"
  ServiceName is "intelppm"