tools script portable para microsoft for debugger debug c++ windows debugging windbg

c++ - script - windbg portable



¿Cuál es tu consejo/truco Windbg favorito? (13)

Me he dado cuenta de que Windbg es un depurador muy potente para la plataforma de Windows y aprendo algo nuevo al respecto de vez en cuando. ¿Pueden los usuarios de Windbg compartir algunas de sus locas habilidades?

ps: no estoy buscando un comando ingenioso, esos se pueden encontrar en la documentación. ¿Qué tal si compartimos consejos sobre cómo hacer algo que de otro modo no podríamos imaginar con windbg? Por ejemplo, alguna forma de generar estadísticas sobre las asignaciones de memoria cuando un proceso se ejecuta bajo windbg.


Cadena de volcado independiente de la plataforma para código administrado que funcionará para x86 / x64:

j $ptrsize = 8 ''aS !ds .printf "%mu /n", c+'';''aS !ds .printf "%mu /n", 10+''

Aquí hay un uso de muestra:

0:000> !ds 00000000023620b8 MaxConcurrentInstances


Casi el 60% de los comandos que uso todos los días ...

dv /i /t ?? this kM (kinda undocumented) generates links to frames .frame x !analyze -v !lmi ~


El "consejo" que uso con más frecuencia es uno que le evitará tener que tocar ese molesto mouse con tanta frecuencia: Alt + 1

Alt + 1 colocará el foco en la ventana de comandos para que pueda escribir un comando y para que la flecha hacia arriba realmente se desplace por el historial de comandos. Sin embargo, no funciona si su enfoque ya está en el historial de comandos desplazables.

Peeve: ¿Por qué diablos se ignoran las pulsaciones de teclas mientras el foco está en una ventana de fuente? No es como si pudieras editar el código fuente desde dentro de WinDbg. Alt + 1 al rescate.


El siguiente comando es muy útil cuando se busca en la pila objetos de C ++ con tablas virtuales, especialmente cuando se trabaja con compilaciones de lanzamiento cuando se optimizan bastantes cosas.

Gama dpp esp


Ser capaz de cargar un archivo PE arbitrario como volcado está limpio:

windbg -z mylib.dll


Consulta GetLastError () con:

! gle


Esto ayuda a decodificar códigos de error comunes:

! error error_number

Me gusta usar comandos avanzados de punto de interrupción, como el uso de puntos de interrupción para crear nuevos puntos de interrupción de un solo disparo.


No use el comando .heap -stat -stat de .heap -stat . A veces le dará salida incorrecta. En su lugar, use informes de memoria DebugDiags.

Con los números correctos, puede usar el comando .heap -flt ... .


Otra respuesta mencionó la ventana de comandos y Alt + 1 para enfocar la ventana de entrada del comando. ¿Alguien tiene dificultades para desplazarse por la ventana de salida del comando sin usar el mouse?

Bueno, recientemente he usado AutoHotkey para desplazar la ventana de salida del comando usando el teclado y sin salir de la ventana de entrada del comando.

; WM_VSCROLL = 0x115 (277) ScrollUp(control="") { SendMessage, 277, 0, 0, %control%, A } ScrollDown(control="") { SendMessage, 277, 1, 0, %control%, A } ScrollPageUp(control="") { SendMessage, 277, 2, 0, %control%, A } ScrollPageDown(control="") { SendMessage, 277, 3, 0, %control%, A } ScrollToTop(control="") { SendMessage, 277, 6, 0, %control%, A } ScrollToBottom(control="") { SendMessage, 277, 7, 0, %control%, A } #IfWinActive, ahk_class WinDbgFrameClass ; For WinDbg, when the child window is attached to the main window !UP::ScrollUp("RichEdit50W1") ^k::ScrollUp("RichEdit50W1") !DOWN::ScrollDown("RichEdit50W1") ^j::ScrollDown("RichEdit50W1") !PGDN::ScrollPageDown("RichEdit50W1") !PGUP::ScrollPageUp("RichEdit50W1") !HOME::ScrollToTop("RichEdit50W1") !END::ScrollToBottom("RichEdit50W1") #IfWinActive, ahk_class WinBaseClass ; Also for WinDbg, when the child window is a separate window !UP::ScrollUp("RichEdit50W1") !DOWN::ScrollDown("RichEdit50W1") !PGDN::ScrollPageDown("RichEdit50W1") !PGUP::ScrollPageUp("RichEdit50W1") !HOME::ScrollToTop("RichEdit50W1") !END::ScrollToBottom("RichEdit50W1")

Después de ejecutar este script, puede usar Alt + arriba / abajo para desplazarse por una línea de la ventana de salida del comando, Alt + PgDn / RePág para desplazarse por una pantalla.

Nota: parece que las diferentes versiones de WinDbg tendrán diferentes nombres de clase para la ventana y los controles, por lo que es posible que desee utilizar la herramienta de ventana de espionaje proporcionada por AutoHotkey para encontrar primero los nombres de las clases reales.


Para investigar una pérdida de memoria en un volcado de emergencia (ya que prefiero con diferencia UMDH para procesos en vivo). La estrategia es que todos los objetos del mismo tipo están asignados con el mismo tamaño.

  • Alimente el comando !heap -h 0 a la versión de línea de comandos de WinDbg cdb.exe (para una mayor velocidad) para obtener todas las asignaciones de almacenamiento dinámico:

"C:/Program Files/Debugging Tools for Windows/cdb.exe" -c "!heap -h 0;q" -z [DumpPath] > DumpHeapEntries.log

  • Use Cygwin para grep la lista de asignaciones, agrupándolas por tamaño:

grep "busy ([[:alnum:]]/+)" DumpHeapEntries.log / | gawk ''{ str = $8; gsub(//(|/)/, "", str); print "0x" str " 0x" $4 }'' / | sort / | uniq -c / | gawk ''{ printf "%10.2f %10d %10d ( %s = %d )/n", $1*strtonum($3)/1024, $1, strtonum($3), $2, strtonum($2) }'' / | sort > DumpHeapEntriesStats.log

  • Obtiene una tabla que se ve así, por ejemplo, nos dice que 25529270 asignaciones de 0x24 bytes toman casi 1,2 GB de memoria.

8489.52 707 12296 ( 0x3000 = 12288 ) 11894.28 5924 2056 ( 0x800 = 2048 ) 13222.66 846250 16 ( 0x2 = 2 ) 14120.41 602471 24 ( 0x2 = 2 ) 31539.30 2018515 16 ( 0x1 = 1 ) 38902.01 1659819 24 ( 0x1 = 1 ) 40856.38 817 51208 ( 0xc800 = 51200 ) 1196684.53 25529270 48 ( 0x24 = 36 )

  • Luego, si sus objetos tienen tablas virtuales, simplemente use el comando dps para buscar algunas de las asignaciones de heap de 0x24 bytes en DumpHeapEntries.log para conocer el tipo de objetos que están tomando toda la memoria.

0:075> dps 3be7f7e8 3be7f7e8 00020006 3be7f7ec 090c01e7 3be7f7f0 0b40fe94 SomeDll!SomeType::`vftable'' 3be7f7f4 00000000 3be7f7f8 00000000

Es cursi pero funciona :)


Para rutinas de comando y sencillas (estáticas o automatizables) donde se usa el depurador, es genial poder ejecutar todos los comandos del depurador en un archivo de comando de texto y ejecutar eso como entrada a través de kd.exe o cdb.exe , invocable a través de un script por lotes, etc.

Ejecuta eso siempre que necesites hacer la misma rutina anterior, sin tener que iniciar WinDbg y hacer las cosas manualmente. Lástima que esto no funciona cuando no está seguro de lo que está buscando, o algunos parámetros de comando necesitan un análisis manual para encontrar / obtener.


Script para cargar SOS basado en la versión .NET framework (v2.0 / v4.0):

!for_each_module .if(($sicmp( "@#ModuleName" , "mscorwks") = 0) ) {.loadby sos mscorwks} .elsif ($sicmp( "@#ModuleName" , "clr") = 0) {.loadby sos clr}


Una palabra (bueno, vale, tres): DML , es decir, Lenguaje de marcado del depurador .

Esta es una adición bastante reciente a WinDbg, y no está documentada en el archivo de ayuda. Sin embargo, hay documentación en "dml.doc" en el directorio de instalación de las herramientas de depuración para Windows.

Básicamente, esta es una sintaxis similar a HTML que puede agregar a sus scripts de depurador para formatear y, lo que es más importante, vincular. Puede usar enlaces para llamar a otros scripts, o incluso al mismo script.

Mi trabajo diario implica el mantenimiento de un metamodelador que proporciona objetos genéricos y la relación entre objetos para una gran parte del software C ++. Al principio, para facilitar la depuración, había escrito un simple script de volcado que extraía información relevante de estos objetos.

Ahora, con DML, he podido agregar enlaces a la salida, permitiendo que se vuelva a llamar al mismo script en objetos relacionados. Esto permite una exploración mucho más rápida de un modelo.

Aquí hay un ejemplo simplificado. Supongamos que el objeto bajo introspección tiene una relación llamada "referencia" a otro objeto. r @ $ t0 = $ arg1 $$ arg1 es la dirección de un objeto para examinar

$$ dump some information from $t0 $$ allow the user to examine our reference aS /x myref @@(&((<C++ type of the reference>*)@$t0)->reference ) .block { .printf /D "<link cmd=/"$$>a< <full path to this script> ${myref}/">dump Ref</link> " }

Obviamente, este es un bonito ejemplo enlatado, pero esto es realmente invaluable para mí. En lugar de buscar objetos muy complejos para los miembros de datos correctos (que generalmente demoraban un minuto y varios trucos de fundición y desreferenciación), ¡todo se automatiza con un solo clic!


Mi favorito es el comando .cmdtree <file> (no documentado, pero al que se hace referencia en notas de la versión anterior). Esto puede ayudar a mostrar otra ventana (que se puede acoplar) para mostrar los comandos útiles o de uso común. Esto puede ayudar a que el usuario sea mucho más productivo al usar la herramienta.

Inicialmente se habló aquí, con un ejemplo para el parámetro <file> : http://blogs.msdn.com/debuggingtoolbox/archive/2008/09/17/special-command-execute-commands-from-a-customized-user-interface-with-cmdtree.aspx

Ejemplo: texto alternativo http://blogs.msdn.com/photos/debuggingtoolbox/images/8954736/original.aspx


  • .prefer_dml 1

    Esto modifica muchos de los comandos integrados (por ejemplo, lm ) para mostrar la salida DML que le permite hacer clic en enlaces en lugar de ejecutar comandos. Muy útil ...

  • .reload /f /o file.dll (el /o sobrescribirá la copia actual del símbolo que tiene)

  • .enable_unicode 1 // .enable_unicode 1 el depurador en predeterminado para Unicode para cadenas, ya que todos los componentes de Windows usan Unicode internamente, esto es bastante útil.

  • .ignore_missing_pages 1 // Si realiza una gran cantidad de análisis de volcado de kernel, verá una gran cantidad de errores con respecto a la memoria que se paginación. Este comando le indicará al depurador que deje de lanzar esta advertencia.

alias alias alias ...

Ahórrese un tiempo en el depurador. Aquí hay algunos míos:

aS !p !process; aS !t !thread; aS .f .frame; aS .p .process /p /r aS .t .thread /p /r aS dv dv /V /i /t //make dv do your favorite options by default aS f !process 0 0 //f for find, e.g. f explorer.exe