reverse-debugging

reverse debugging - ¿Cómo funciona la depuración inversa?



reverse-debugging (7)

Así es como funciona otro depurador inverso llamado ODB. Extraer:

Omniscient Debugging es la idea de recopilar "marcas de tiempo" en cada "punto de interés" (establecer un valor, hacer una llamada a un método, lanzar / capturar una excepción) en un programa y luego permitir que el programador use esas marcas de tiempo para explorar el historial de ese programa ejecutado.

El ODB ... inserta código en las clases del programa a medida que se cargan y cuando el programa se ejecuta, los eventos se graban.

Supongo que el gdb funciona del mismo modo.

GDB tiene una nueva versión que admite la depuración inversa (consulte http://www.gnu.org/software/gdb/news/reversible.html ). Me pregunto cómo funciona eso.

Para que la depuración inversa funcione, me parece que necesita almacenar todo el estado de la máquina, incluida la memoria de cada paso. Esto haría que el rendimiento sea increíblemente lento, por no mencionar el uso de mucha memoria. ¿Cómo se resuelven estos problemas?


Aunque esta pregunta es antigua, la mayoría de las respuestas también lo son, y como reverse-debugging sigue siendo un tema interesante, publicaré una respuesta de 2015. Los capítulos 1 y 2 de mi tesis de maestría, que combina depuración inversa y programación en vivo para el pensamiento visual en programación informática , cubre algunos de los enfoques históricos para la depuración inversa (especialmente enfocados en el enfoque de instantáneas (o puntos de verificación) y repeticiones). explica la diferencia entre esto y la depuración omnisciente:

La computadora, después de haber ejecutado el programa hasta cierto punto, realmente debería ser capaz de proporcionarnos información al respecto. Tal mejora es posible, y se encuentra en lo que se denomina depuradores omniscientes. Generalmente se clasifican como depuradores inversos, aunque podrían describirse con mayor precisión como depuradores de "registro de historial", ya que simplemente registran la información durante la ejecución para verla o consultarla más tarde, en lugar de permitir al programador retroceder en el tiempo en un programa en ejecución . "Omnisciente" proviene del hecho de que toda la historia del estado del programa, una vez registrada, está disponible para el depurador después de la ejecución. Entonces no hay necesidad de volver a ejecutar el programa, y ​​no hay necesidad de instrumentación de código manual.

La depuración omnisciente basada en software comenzó con el sistema EXDAMS de 1969, donde se denominó "reproducción de historial en tiempo de depuración". El depurador de GNU, GDB, ha soportado la depuración omnisciente desde 2009, con su función ''grabar y reproducir el proceso''. TotalView, UndoDB y Chronon parecen ser los mejores depuradores omniscientes actualmente disponibles, pero son sistemas comerciales. TOD, para Java, parece ser la mejor alternativa de código abierto, que hace uso de la reproducción determinista parcial, así como la captura parcial de trazas y una base de datos distribuida para permitir el registro de los grandes volúmenes de información involucrados.

También existen los depuradores que no solo permiten la navegación de una grabación, sino que también pueden retroceder en el tiempo de ejecución. Se pueden describir con más precisión como depuradores de retroceso en el tiempo, de viaje en el tiempo, bidireccionales o inversos.

El primer sistema de este tipo fue el prototipo COPE 1981 ...


Durante una sesión de EclipseCon también preguntamos cómo lo hacen con Chronon Debugger para Java. Eso no le permite retroceder, pero puede reproducir una ejecución de programa grabada de tal manera que parezca una depuración inversa. (La principal diferencia es que no puede cambiar el programa en ejecución en el depurador Chronon, mientras que puede hacerlo en la mayoría de los otros depuradores de Java).

Si lo entendí correctamente, manipula el código de bytes del programa en ejecución, de modo que cada cambio de un estado interno del programa se registra. Los estados externos no necesitan registrarse adicionalmente. Si influyen en su programa de alguna manera, entonces debe tener una variable interna que coincida con ese estado externo (y, por lo tanto, esa variable interna es suficiente).

Durante el tiempo de reproducción, pueden básicamente recrear cada estado del programa en ejecución desde los cambios de estado grabados.

Curiosamente, los cambios de estado son mucho más pequeños de lo que cabría esperar al primer vistazo. Por lo tanto, si tiene una declaración condicional "si", pensaría que necesita al menos un bit para registrar si el programa tomó la instrucción then- o the else. En muchos casos, puede evitar incluso eso, como en el caso de que esas diferentes ramas contengan un valor de retorno. Luego es suficiente registrar solo el valor de retorno (que de todos modos sería necesario) y volver a calcular la decisión sobre la rama ejecutada a partir del valor de retorno.


La depuración inversa significa que puede ejecutar el programa hacia atrás, lo cual es muy útil para rastrear la causa de un problema.

No necesita almacenar el estado completo de la máquina para cada paso, solo los cambios. Es probable que todavía sea bastante caro.


Nathan Fellman escribió:

Pero, ¿la depuración inversa solo le permite revertir los comandos de próximo y paso que escribió, o le permite deshacer cualquier cantidad de instrucciones?

Puedes deshacer cualquier cantidad de instrucciones. No estás restringido, por ejemplo, solo parando en los puntos donde te detuviste cuando avanzaste. Puede establecer un nuevo punto de interrupción y ejecutarlo hacia atrás.

Por ejemplo, si configuro un punto de interrupción en una instrucción y la dejo funcionar hasta entonces, ¿puedo volver a la instrucción anterior, aunque me salté sobre ella?

Sí. Siempre y cuando haya activado el modo de grabación antes de ejecutar el punto de interrupción.


Soy un mantenedor de gdb y uno de los autores de la nueva depuración inversa. Estaría feliz de hablar sobre cómo funciona. Como varias personas han especulado, debe guardar suficiente estado de la máquina que pueda restaurar más tarde. Hay una serie de esquemas, uno de los cuales es simplemente guardar los registros o las ubicaciones de memoria que se modifican con cada instrucción de máquina. Luego, para "deshacer" esa instrucción, solo revierte los datos en esos registros o ubicaciones de memoria.

Sí, es caro, pero las CPU modernas son tan rápidas que cuando eres interactivo de todos modos (haciendo pasos o puntos de interrupción), realmente no te das cuenta de eso.


Tenga en cuenta que no debe olvidar el uso de simuladores, máquinas virtuales y grabadoras de hardware para implementar la ejecución inversa.

Otra solución para implementarlo es rastrear la ejecución en hardware físico, como lo hacen GreenHills y Lauterbach en sus depuradores basados ​​en hardware. En función de este rastro fijo de la acción de cada instrucción, puede moverse a cualquier punto de la traza eliminando los efectos de cada instrucción sucesivamente. Tenga en cuenta que esto supone que puede rastrear todas las cosas que afectan el estado visible en el depurador.

Otra forma es utilizar un método de punto de control + re-ejecución, que es utilizado por VmWare Workstation 6.5 y Virtutech Simics 3.0 (y posterior), y que parece venir con Visual Studio 2010. Aquí, usted usa una máquina virtual o un simulador para obtener un nivel de indirección en la ejecución de un sistema. Usted regularmente descarga todo el estado en el disco o la memoria, y luego confía en que el simulador pueda volver a ejecutar determinísticamente la misma ruta del programa.

Simplificado, funciona así: di que estás en el tiempo T en la ejecución de un sistema. Para ir al tiempo T-1, tomas un punto de control del punto t <T, y luego ejecutas (Tt-1) ciclos para terminar un ciclo antes de donde estabas. Esto se puede hacer para que funcione muy bien, y se aplique incluso para cargas de trabajo que hacen IO de disco, consisten en código de nivel de núcleo y realizan el trabajo del controlador de dispositivo. La clave es tener un simulador que contenga todo el sistema de destino, con todos sus procesadores, dispositivos, memorias e IO. Consulte la lista de distribución de gdb y la discusión siguiente en la lista de distribución de gdb para obtener más detalles. Utilizo este enfoque con bastante regularidad para depurar código engañoso, especialmente en los controladores de dispositivos y las primeras botas del sistema operativo.

Otra fuente de información es un libro blanco de Virtutech sobre puntos de control (que escribí, en revelación completa).