Windows/C++: ¿Es posible encontrar la línea de código donde se lanzó la excepción que tiene “Compensación de excepción”?

6 minutos de lectura

Uno de nuestros usuarios tiene una excepción en el inicio de nuestro producto. Nos ha enviado el siguiente mensaje de error desde Windows:

  Problem Event Name:                        APPCRASH
  Application Name:                          program.exe
  Application Version:                       1.0.0.1
  Application Timestamp:                     4ba62004
  Fault Module Name:                         agcutils.dll
  Fault Module Version:                      1.0.0.1
  Fault Module Timestamp:                    48dbd973
  Exception Code:                            c0000005
  Exception Offset:                          000038d7
  OS Version:                                6.0.6002.2.2.0.768.2
  Locale ID:                                 1033
  Additional Information 1:                  381d
  Additional Information 2:                  fdf78cd6110fd6ff90e9fff3d6ab377d
  Additional Information 3:                  b2df
  Additional Information 4:                  a3da65b92a4f9b2faa205d199b0aa9ef

¿Es posible ubicar el lugar exacto en el código fuente donde se ha producido la excepción teniendo esta información?

¿Cuál es la técnica común para que los programadores de C++ en Windows ubiquen el lugar de un error que ocurrió en la computadora del usuario?

Nuestro proyecto se compila con la configuración de lanzamiento, se genera un archivo PDB.

Espero que mi pregunta no sea demasiado ingenua.

Windows/C++: ¿Es posible encontrar la línea de código donde se lanzó la excepción que tiene "Compensación de excepción"?
Hans Passant

Sí, eso es posible. Comience a depurar con exactamente los mismos archivos binarios que ejecutó su usuario, asegúrese de que la DLL esté cargada y de que tenga un archivo PDB coincidente. Busque en Depuración + Windows + Módulos la dirección base de la DLL. Agregue el desplazamiento. Depuración + Windows + Desmontaje e ingrese la dirección calculada en el campo Dirección (prefijo con 0x). Eso le muestra la instrucción de código de máquina exacta que causó la excepción. Haga clic con el botón derecho + Ir al código fuente para ver la línea de código fuente coincidente.

Si bien eso le muestra la declaración, esto no suele ser lo suficientemente bueno para diagnosticar la causa. La excepción 0xc0000005 es una infracción de acceso, tiene muchas causas posibles. A menudo, ni siquiera obtiene ningún código, el programa puede haber caído en el olvido debido a una pila dañada. O el problema real está ubicado muy lejos, alguna manipulación del puntero que corrompió el montón. Por lo general, también necesita un seguimiento de la pila que le muestre cómo terminó el programa en la declaración que bombardeó.

Lo que necesitas es un minivolcado. Puede obtener uno fácilmente de su usuario si ejecuta Vista o Win7. Inicie TaskMgr.exe, pestaña Procesos, seleccione el programa bombardeado mientras aún muestra el cuadro de diálogo de bloqueo. Haga clic con el botón derecho en él y cree un archivo de volcado.

Para que esto sea sencillo, realmente desea automatizar este procedimiento. Encontrarás pistas en mi respuesta en este hilo.

  • Una buena manera de hacer un minivolcado cuando el problema realmente ocurre, puede usar “SetUnhandledExceptionFilter()” para decirle al sistema operativo que llame a otra función que defina en caso de “evento catastrófico, como una violación de acceso”. En esta función puede cargar (dinámicamente usando LoadLibrary/GetProcAdderss) la función MiniDumpWriteDump() de dbghelp.dll y escribe el minidump antes de que la aplicación muera horriblemente :-). Más tarde puedes cargar el minidump. ¡Es una ayuda increíble!

    – TCS

    17 mayo 2013 en 20:46

  • offtopic – En C# Dll he usado ildasm tal como se describe aquí (mientras que el archivo Pdb está en el mismo directorio)

    – itsho

    29 abr. 14 en 12:40


Si tiene un minivolcado, ábralo en Visual Studio, configure MODPATH en las carpetas apropiadas con los archivos binarios y PDB originales, y dígale que se “ejecute”. Es posible que también deba indicarle que cargue símbolos de los servidores de símbolos de Microsoft. Mostrará la pila de llamadas en la ubicación del error. Si intenta ver el código fuente de una ubicación de pila en particular, es posible que le pregunte dónde está la fuente; si es así, seleccione la carpeta de origen adecuada. MODPATH se establece en las propiedades de la línea de comandos de depuración para el “proyecto” que tiene el nombre del archivo de minivolcado.

Sé que este hilo es muy antiguo, pero esta fue una de las principales respuestas de Google, así que quería agregar mi $.02.

Aunque un minivolcado es muy útil, siempre que haya compilado su código con los símbolos habilitados (simplemente envíe el archivo sin el .pdb y conserve el .pdb). Puede buscar qué línea estaba utilizando el Depurador de MSVC o Depurador de Windows. Artículo de MSN sobre eso:

http://blogs.msdn.com/b/danielvl/archive/2010/03/03/getting-the-line-number-for-a-faulting-application-error.aspx

  • La URL menciona el comando windbg -z <executable> mientras -z solo se debe usar para vertederos. Enlace inútil.

    – Dominique

    14 dic. 17 en 14:24

La información del código fuente no se conserva en el código C++ compilado, a diferencia de los lenguajes que reconocen los metadatos basados ​​en el tiempo de ejecución (como .NET o Java). El archivo PDB es un índice de símbolos que puede ayudar a un depurador a mapear el código compilado hacia atrás a la fuente, pero debe hacerse durante la ejecución del programa, no desde un volcado de memoria. Incluso con un PDB, el código compilado de la versión está sujeto a una serie de optimizaciones que pueden evitar que el depurador identifique el código fuente.

La depuración de problemas que solo se manifiestan en las máquinas de los usuarios finales suele ser una cuestión de registro de estado cuidadoso y mucho tiempo y esfuerzo orientados a los detalles para revisar la fuente. Según su relación con el usuario (por ejemplo, si es un desarrollador de TI corporativo interno), es posible que pueda crear una imagen de máquina virtual de la máquina del usuario y usarla para la depuración, lo que puede ayudar a acelerar enormemente el proceso al replicar el software instalado y los procesos estándar en ejecución en la estación de trabajo del usuario.

Hay varias formas de encontrar la ubicación del accidente después del hecho.

  1. Usa un minivolcado. Vea las respuestas anteriores.
  2. Use el ejecutable existente en un depurador. Vea las respuestas anteriores.
  3. Si tiene archivos PDB (Visual Studio, Visual Basic 6), use DbgHelpNavegador para cargar el archivo PDB y consultar la ubicación del bloqueo.
  4. Si tiene archivos TDS (archivo TDS separado o incrustado en el exe, Delphi, C ++ Builder de 32 bits), use Navegador TDS para cargar el archivo TDS/DLL/EXE y consultar la ubicación del bloqueo.
  5. Si tiene símbolos DWARF (incrustados en EXE, C++ Builder de 64 bits, gcc, g++), utilice Navegador ENANO para cargar el archivo DLL/EXE y consultar la ubicación del bloqueo.
  6. Si tiene archivos MAP, use Navegador de archivos MAP para cargar el archivo MAP y consultarlo para la ubicación del accidente.

Escribí estas herramientas para usar en casa. Los hemos puesto a disposición de forma gratuita.

.

¿Ha sido útil esta solución?