windbg sos

Obtener el nombre del método del delegado con WinDbg



sos (5)

Con la ayuda de ClrMd, estoy trabajando en una tool para explorar .Net dump file con una GUI fácil de usar. Hay una feature para encontrar delegados y mostrar su lista de invocaciones y nombres de métodos.

Tengo el siguiente volcado de objeto delegado:

Name: MyEventHandler MethodTable: 132648fc EEClass: 1319e2b4 Size: 32(0x20) bytes Fields: MT Field Offset Type VT Attr Value Name 790fd0f0 40000ff 4 System.Object 0 instance 014037a4 _target 7910ebc8 4000100 8 ...ection.MethodBase 0 instance 00000000 _methodBase 791016bc 4000101 c System.IntPtr 1 instance 2ef38748 _methodPtr 791016bc 4000102 10 System.IntPtr 1 instance 0 _methodPtrAux 790fd0f0 400010c 14 System.Object 0 instance 00000000 _invocationList 791016bc 400010d 18 System.IntPtr 1 instance 0 _invocationCount

¿Cómo puedo obtener el nombre del método, señalado por el delegado?


Creo que puedes usar! Ip2md en el valor de methodPtr. Eso debería dar la descripción del método.


En mi experiencia, la sugerencia ofrecida por hakan no funciona. Esto es lo que hago.

La salida muestra que el controlador adjunto es un miembro del objeto apuntado por _target . Al volcar eso obtendrás su tabla de métodos.

He construido un ejemplo similar, para ilustrar:

0:000> !do 02844de4 Name: System.EventHandler MethodTable: 0067afa4 EEClass: 0052ef88 Size: 32(0x20) bytes (C:/windows/assembly/GAC_32/mscorlib/2.0.0.0__b77a5c561934e089/mscorlib.dll) Fields: MT Field Offset Type VT Attr Value Name 002e6d58 40000ff 4 System.Object 0 instance 02842d20 _target 0058df70 4000100 8 ...ection.MethodBase 0 instance 00000000 _methodBase 0058743c 4000101 c System.IntPtr 1 instance 2cc060 _methodPtr 0058743c 4000102 10 System.IntPtr 1 instance 0 _methodPtrAux 002e6d58 400010c 14 System.Object 0 instance 00000000 _invocationList 0058743c 400010d 18 System.IntPtr 1 instance 0 _invocationCount

En este caso, miraré el objeto en 02842d20 .

0:000> !do 02842d20 Name: app.Foo MethodTable: 002c30bc EEClass: 002c13d4 Size: 12(0xc) bytes (C:/workspaces/TestBench/app/bin/x86/Debug/app.exe) Fields: None

Así que el tipo de destino es app.Foo . Vamos a volcar los métodos para este tipo.

0:000> !dumpmt -md 002c30bc EEClass: 002c13d4 Module: 002c2c5c Name: app.Foo mdToken: 02000002 (C:/workspaces/TestBench/app/bin/x86/Debug/app.exe) BaseSize: 0xc ComponentSize: 0x0 Number of IFaces in IFaceMap: 0 Slots in VTable: 6 -------------------------------------- MethodDesc Table Entry MethodDesc JIT Name 002ec015 002e6cbc NONE System.Object.ToString() 002ec019 002e6cc4 NONE System.Object.Equals(System.Object) 002ec029 002e6cf4 NONE System.Object.GetHashCode() 005f4930 002e6d1c JIT System.Object.Finalize() 005f8238 002c30b4 JIT app.Foo..ctor() 005f8270 002c30a8 JIT app.Foo.Bar(System.Object, System.EventArgs)

Compare los valores de la tabla MethodDesc con el valor original de _methodPtr . No hay coincidencia aparente.

_methodPtr apunta a un fragmento de código que hace un jmp a la dirección de la función en cuestión o llama a una rutina de reparación, por lo que el siguiente paso es usar el comando !u en el valor de _methodPtr . Si vemos una instrucción jmp , tenemos la dirección y al usar !u en eso, obtenemos el método.

Si, por otro lado, vemos una call a clr!PrecodeFixupThunk , podemos obtener MethodDesc descargando la memoria apuntada por _methodPtr como esta

0:000> dd 2cc060 002cc060 7e5d65e8 00005e6e 002c30a8 00000000 002cc070 00000000 00000000 00000000 00000000 002cc080 00000000 00000000 00000000 00000000

Vemos algo que se parece a una entrada de la tabla de métodos como el tercer DWORD. Al comparar el valor 002c30a8 con la tabla de métodos anterior, vemos que el nombre del método es app.Foo.Bar .

Dado que este es un ejemplo construido, sé que he encontrado el método que estaba buscando en este caso.

En realidad, puede ser un poco más complicado que el ejemplo anterior, ya que los campos se utilizan de manera diferente según el uso real del evento. Sin embargo, en mi experiencia, el enfoque anterior funcionará en el escenario general del editor / suscriptor.

Para obtener más detalles sobre los detalles de la implementación, consulte el archivo comdelegate.cpp de la CLI de origen compartido.


He creado un pequeño script Windbg para resolver el método almacenado directamente desde un valor de methodPtr. Puedes leer más sobre here .

El Script es:

r $t0 = ${$arg1}+5 r $t1 = $t0 + 8*by($t0+2) + 3 r $t2 = 8*by($t0+1) r $t3 = poi($t1) + $t2 !DumpMD $t3

Guárdelo en un archivo y ejecútelo con el valor _methodPtr de su delegado como

$$>a< "c:/source/DelegateTest/Resolve.txt" 2ef38748

Eso debería hacer el truco en todas las plataformas y para .NET 2.0 hasta .NET 4.5.


Otra forma es desmontar los datos en _methodPtr.

Digamos que nuestro EventHandler se ve así:

MT Field Offset Type VT Attr Value Name 6da484dc 40000ff 4 System.Object 0 instance 02d8ff64 _target 6da4d0ac 4000100 8 ...ection.MethodBase 0 instance 00000000 _methodBase 6da4b188 4000101 c System.IntPtr 1 instance d955840 _methodPtr

Veamos el desmontaje del d955840.

!U d955840 Unmanaged code 08577a50 b884f8a007 mov eax,7A0F884h 08577a55 90 nop 08577a56 e855b4d665 call mscorwks+0x2eb0 (6e2e2eb0) 08577a5b e9ac8de4f7 jmp 003c080c 08577a60 b8d4f9a007 mov eax,7A0F9D4h 08577a65 90 nop 08577a66 e845b4d665 call mscorwks+0x2eb0 (6e2e2eb0) 08577a6b e99c8de4f7 jmp 003c080c 08577a70 00b000eb0cb0 add byte ptr [eax-4FF31500h],dh 08577a76 03eb add ebp,ebx

Aquí vemos un traslado al 7A0F884, por lo que este podría ser el método que estamos buscando:

!dumpmd 7A0F884 Method Name: DemoClass.OnDemoEvent(System.Object, System.EventArgs) Class: 07c079e8 MethodTable: 07c10034 mdToken: 060010ee Module: 07a0b7ac IsJitted: no CodeAddr: ffffffff

¡bingo!

Hay diferentes maneras de obtener el nombre del método, y no todas funcionarán en todas las situaciones