2010-09-08 16 views
21

tengo el siguiente volcado del objeto delegado:Obtener el nombre del método de delegado con WinDbg

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?

Respuesta

32

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 eliminar 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, voy a ver 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 

lo tanto, 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) 

comparar los valores de la tabla MethodDesc con el valor original de _methodPtr. Sin aparente coincidencia.

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

Si, por el contrario, vemos una call-clr!PrecodeFixupThunk podemos obtener el MethodDesc por vertimiento de la memoria apuntada por _methodPtr como esto

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 tabla de métodos de 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 encontré 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 información sobre los detalles de implementación, consulte el archivo comdelegate.cpp de la CLI de origen compartido.

+0

En lugar de comparar manualmente con la tabla de métodos, también puede usar el comando! DumpMD con el descriptor de método. – kicsit

+0

Se ve mal en x64, solo un salto a un registro –

3

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

+0

Eso no siempre funcionará. Pero en mi experiencia, ningún método funciona todo el tiempo, así que debes conocer y probar diferentes técnicas para obtener el nombre del método – sloth

+0

Probablemente tengas razón, Google rápido demostró que esto podría no funcionar si el método aún no está JITted. Pero aún así primero probaría esto y si no funciona, otros enfoques. La solución de Brian, volcar los métodos del objeto objetivo, parece realmente muy conveniente. – hakan

2

Otra forma es desmontar los datos en _methodPtr.

permite decir nuestro manejador de sucesos 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 

Vemos un mov a 7A0F884 aquí, por lo que este podría ser el método que estamos buscando para:

!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 todos van a trabajar en todas las situaciones

3

He creatd una secuencia de comandos WinDbg Littel para resolver el método almacenado directamente desde un valor methodPtr. Puede leer más sobre here.

El guión 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 

almacenarlo en un archivo y lo ejecuta con el valor _methodPtr de su delegado como

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

Que debe hacer el truco en todas las plataformas y para .NET 2.0 hasta .NET 4.5.

+0

¡Funciona! Muchas gracias por la respuesta y por el enlace – 6opuc

+0

¿Cómo encontraste ese truco con la aritmética del puntero mágico? – 6opuc

+0

Observando el código ensamblador generado. Es tan fácil como eso. Debo notar que en realidad hay dos tipos de llamadas de delegado. Acción, Func, ... son rápidos. Sin embargo, las entregas de paquetes "antiguas" que declara explícitamente que entran en una ruta de código muy diferente (por ejemplo, MethodInvoker para delegados de WndProc) son bastante comunes. –

0

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

+1

No publique enlaces aquí, pero copie el código correspondiente. –

Cuestiones relacionadas