Me sigo preguntando cómo funciona un depurador. Particularmente el que se puede 'adjuntar' al ejecutable que ya se está ejecutando. Entiendo que el compilador traduce el código al lenguaje de máquina, pero ¿cómo "sabe" el depurador a qué se adjunta?
170
Respuestas:
Los detalles de cómo funciona un depurador dependerán de lo que esté depurando y del sistema operativo. Para la depuración nativa en Windows, puede encontrar algunos detalles sobre MSDN: API de depuración de Win32 .
El usuario le dice al depurador a qué proceso adjuntar, ya sea por nombre o por ID de proceso. Si es un nombre, el depurador buscará la ID del proceso e iniciará la sesión de depuración a través de una llamada al sistema; bajo Windows esto sería DebugActiveProcess .
Una vez conectado, el depurador entrará en un bucle de eventos similar a cualquier interfaz de usuario, pero en lugar de eventos que provienen del sistema de ventanas, el sistema operativo generará eventos en función de lo que sucede en el proceso que se está depurando, por ejemplo, una excepción. Ver WaitForDebugEvent .
El depurador puede leer y escribir la memoria virtual del proceso de destino, e incluso ajustar sus valores de registro a través de las API proporcionadas por el sistema operativo. Consulte la lista de funciones de depuración para Windows.
El depurador puede usar información de archivos de símbolos para traducir de direcciones a nombres de variables y ubicaciones en el código fuente. La información del archivo de símbolos es un conjunto separado de API y no es una parte central del sistema operativo como tal. En Windows, esto es a través del SDK de acceso a la interfaz de depuración .
Si está depurando un entorno administrado (.NET, Java, etc.), el proceso generalmente se verá similar, pero los detalles son diferentes, ya que el entorno de la máquina virtual proporciona la API de depuración en lugar del sistema operativo subyacente.
fuente
Según lo entiendo:
Para puntos de interrupción de software en x86, el depurador reemplaza el primer byte de la instrucción con
CC
(int3
). Esto se hace conWriteProcessMemory
Windows. Cuando la CPU llega a esa instrucción y ejecuta laint3
, esto hace que la CPU genere una excepción de depuración. El sistema operativo recibe esta interrupción, se da cuenta de que el proceso se está depurando y notifica al proceso del depurador que se alcanzó el punto de interrupción.Después de alcanzar el punto de interrupción y detener el proceso, el depurador busca en su lista de puntos de interrupción y reemplaza el
CC
con el byte que estaba allí originalmente. El depurador estableceTF
, el indicador de captura enEFLAGS
(modificando elCONTEXT
), y continúa el proceso. El indicador de captura hace que la CPU genere automáticamente una excepción de un solo paso (INT 1
) en la siguiente instrucción.Cuando el proceso que se está depurando se detiene la próxima vez, el depurador reemplaza nuevamente el primer byte de la instrucción de punto de interrupción
CC
y el proceso continúa.No estoy seguro de si esta es exactamente la forma en que lo implementan todos los depuradores, pero he escrito un programa Win32 que logra depurarse utilizando este mecanismo. Completamente inútil, pero educativo.
fuente
En Linux, la depuración de un proceso comienza con la llamada al sistema ptrace (2) . Este artículo tiene un gran tutorial sobre cómo usar
ptrace
para implementar algunas construcciones de depuración simples.fuente
(2)
Nos dice algo más (o menos) que "ptrace es una llamada al sistema"?(2)
es el número de sección manual. Ver en.wikipedia.org/wiki/Man_page#Manual_sections para una descripción de las secciones del manual.ptrace
es una llamada al sistema.(2)
nos dice que podemos escribirman 2 ptrace
y obtener la página de manual correcta, no es importante aquí porque no hay otroptrace
para desambiguar, sino para compararman printf
conman 3 printf
Linux.Si está en un sistema operativo Windows, un gran recurso para esto sería "Depuración de aplicaciones para Microsoft .NET y Microsoft Windows" de John Robbins:
(o incluso la edición anterior: "Depuración de aplicaciones" )
El libro tiene un capítulo sobre cómo funciona un depurador que incluye código para un par de depuradores simples (pero que funcionan).
Como no estoy familiarizado con los detalles de la depuración de Unix / Linux, es posible que esto no se aplique en absoluto a otros sistemas operativos. Pero supongo que, como introducción a un tema muy complejo, los conceptos, si no los detalles y las API, deberían 'portarse' a la mayoría de los sistemas operativos.
fuente
Otra fuente valiosa para comprender la depuración es el manual de la CPU Intel (Intel® 64 y el Manual del desarrollador de software de arquitecturas IA-32). En el volumen 3A, capítulo 16, introdujo el soporte de hardware para la depuración, como excepciones especiales y registros de depuración de hardware. Lo siguiente es de ese capítulo:
Indicador T (trampa), TSS: genera una excepción de depuración (#DB) cuando se intenta cambiar a una tarea con el indicador T establecido en su TSS.
No estoy seguro de si Windows o Linux usan esta bandera o no, pero es muy interesante leer ese capítulo.
Espero que esto ayude a alguien.
fuente
Creo que hay dos preguntas principales para responder aquí:
1. ¿Cómo sabe el depurador que ocurrió una excepción?
Cuando se produce una excepción en un proceso que se está depurando, el depurador recibe una notificación del sistema operativo antes de que cualquier controlador de excepciones de usuario definido en el proceso de destino tenga la oportunidad de responder a la excepción. Si el depurador elige no manejar esta notificación de excepción (de primera oportunidad), la secuencia de despacho de excepción continúa y el hilo objetivo tiene la oportunidad de manejar la excepción si así lo desea. Si el proceso de destino no maneja la excepción de SEH, se envía al depurador otro evento de depuración, llamado notificación de segunda oportunidad, para informarle que ocurrió una excepción no controlada en el proceso de destino. Fuente
2. ¿Cómo sabe el depurador cómo detenerse en un punto de interrupción?
La respuesta simplificada es: cuando coloca un punto de interrupción en el programa, el depurador reemplaza su código en ese punto con una instrucción int3 que es una interrupción de software . Como efecto, el programa se suspende y se llama al depurador.
fuente
Entiendo que cuando compila una aplicación o un archivo DLL, lo que sea que compila contiene símbolos que representan las funciones y las variables.
Cuando tiene una compilación de depuración, estos símbolos son mucho más detallados que cuando se trata de una compilación de lanzamiento, lo que le permite al depurador brindarle más información. Cuando adjunta el depurador a un proceso, observa a qué funciones se está accediendo actualmente y resuelve todos los símbolos de depuración disponibles desde aquí (dado que sabe cómo son las partes internas del archivo compilado, puede determinar lo que podría estar en la memoria , con contenidos de int, flotadores, cadenas, etc.). Como decía el primer póster, esta información y cómo funcionan estos símbolos depende en gran medida del entorno y el idioma.
fuente