¿Cómo pausa GDB una ejecución?


16

Como sabrán, podemos usar GDB y establecer puntos de interrupción en nuestro código para pausar la ejecución para la depuración.

Mi pregunta es cómo GDB detiene un proceso y le permite ver el contenido de los registros utilizando, i rpor ejemplo. ¿No están los registros utilizados por otros procesos del sistema operativo constantemente? ¿Cómo no se sobrescriben?

¿Es solo una instantánea del contenido y no datos en vivo?


2
¿Cómo es que no se sobrescriben todos los registros cuando el sistema operativo decide pausar su programa por un momento y ejecutar uno diferente?
user253751

CppCon 2018: Simon Brand "Cómo funcionan los depuradores de C ++" youtube.com/watch?v=0DDrseUomfU
Robert Andrzejuk

Respuestas:


24

Varía ligeramente con la arquitectura, pero los puntos importantes se aplican casi universalmente:

  • El servicio de interrupción hace que el estado de la CPU (incluidos los registros) se guarde en la memoria antes de ejecutar el ISR y se restaure a medida que el ISR sale.

  • Si una rutina de servicio de interrupción intercambia el contenido de la ubicación de memoria donde se guardan esos registros, puede realizar un cambio de contexto . Cada hilo tiene una región de memoria donde se guardan sus registros cuando el hilo no se está ejecutando.

  • El cambio de contexto está controlado por un planificador de subprocesos que tiene en cuenta si un subproceso está esperando E / S, sincronización, cuál es su prioridad, entrega de señal, etc. A menudo hay un recuento de suspensión que se tiene en cuenta.

  • El depurador puede incrementar el recuento de suspensión, lo que garantiza que el hilo no sea ejecutable. Luego puede inspeccionar (y cambiar) la copia guardada de los registros del hilo.


14

Además de la gran información de @BenVoigt, permítame hacer algunas adiciones:

El depurador establece un punto de interrupción al reemplazar un valor de código de máquina (una instrucción o parte de una instrucción) en el proceso que se está depurando con una instrucción de captura particular en la ubicación en el código que corresponde a la línea (fuente) deseada para romper. Esta instrucción de captura en particular está diseñada para usarse como un punto de interrupción: el depurador lo sabe y el sistema operativo también.

Cuando el proceso / subproceso que se está depurando llega a la instrucción trap, se activa el proceso que @Ben está describiendo, que incluye la mitad de un intercambio de contexto que suspende el subproceso que se está ejecutando actualmente (que incluye guardar su estado de CPU en la memoria) para una posible reanudación posterior. Dado que esta trampa es una trampa de punto de interrupción, el sistema operativo mantiene el proceso que se está depurando suspendido utilizando quizás un mecanismo que @Ben describe, y notifica y finalmente reanuda el depurador.

El depurador usa llamadas del sistema, entonces, para acceder al estado guardado del proceso / hilo suspendido que se está depurando.

Para ejecutar (reanudar) la línea de código que se rompió (que ahora tiene la instrucción de captura particular), el depurador restaurará el valor del código de máquina original que sobrescribió con la instrucción de captura de punto de interrupción, posiblemente establezca otra trampa en otro lugar (por ejemplo, si se realiza un solo paso, o el usuario crea nuevos puntos de interrupción), y marca el proceso / hilo como ejecutable, tal vez usando un mecanismo como lo describe @Ben.

Los detalles reales pueden ser más complicados, ya que mantener un punto de interrupción de larga duración que se alcanza significa hacer algo como cambiar la trampa del punto de interrupción por código real para que la línea pueda ejecutarse, y luego volver a cambiar el punto de interrupción nuevamente ...

¿No están los registros usados ​​constantemente por otros procesos del sistema operativo? ¿Cómo no se sobrescriben?

Como @Ben describe, el uso de la función de suspensión / reanudación de subprocesos ya existente (el cambio de contexto / intercambio de multitarea ) que permite que los procesadores sean compartidos por múltiples procesos / subprocesos utilizando el corte de tiempo.

¿Es solo una instantánea del contenido y no datos en vivo?

Son ambos. Dado que el subproceso que alcanzó el punto de interrupción se suspende, es una instantánea de los datos en vivo (registros de la CPU, etc.) en el momento de la suspensión, y el maestro autorizado de los valores de registro de la CPU para restaurar en el procesador si se reanuda el subproceso . Si utiliza la interfaz de usuario del depurador para leer y / o cambiar los registros de la CPU (del proceso que se está depurando), leerá y / o cambiará esta instantánea / maestra usando las llamadas al sistema.


1
Bueno, la mayoría de las arquitecturas de procesador admiten trampas de depuración que, por ejemplo, se activan cuando la IP (puntero de instrucción) es igual a la dirección almacenada en un registro de punto de interrupción, lo que ahorra la necesidad de reescribir el código. (Al hacer coincidir registros que no sean IP, puede obtener puntos de interrupción de datos y al atrapar después de cada instrucción, puede obtener un solo paso) Lo que describió también es posible, por supuesto, siempre que el código no esté en una memoria de solo lectura.
Ben Voigt

Re "Si altera los registros de la CPU ..." en el último párrafo, creo que quiere decir "Si altera la copia guardada de los registros de la CUP ..." Luego, cuando el sistema operativo reanuda el proceso, los datos alterados se vuelven a escribir a los registros reales.
jamesqf

@jamesqf, sí, gracias!
Erik Eidt

@BenVoigt, de acuerdo. aunque mientras los depuradores pueden manejar un número ilimitado de puntos de interrupción, el hardware puede manejar cero o unos pocos, por lo que el depurador debe hacer algunos malabarismos.
Erik Eidt

@jamesqf: describir eso como una copia es un poco engañoso. Es el almacenamiento oficial para el estado del hilo mientras el hilo no se está ejecutando.
Ben Voigt

5

Estrictamente hablando, al menos en la mayoría de los casos típicos, gdb en sí mismo no detiene la ejecución. Por el contrario, gdb pregunta al sistema operativo, y el sistema operativo detiene la ejecución.

Inicialmente, eso podría parecer una distinción sin una diferencia, pero honestamente, realmente hay una diferencia. La diferencia es esta: esa capacidad ya está integrada en el sistema operativo típico, porque tiene que poder pausar y reiniciar la ejecución del hilo de todos modos, cuando un hilo no está programado para ejecutarse (por ejemplo, necesita algún recurso que no está disponible actualmente) el sistema operativo debe pausarlo hasta que se pueda programar para ejecutarse.

Para hacer eso, el sistema operativo generalmente tiene un bloque de memoria reservado para cada subproceso para guardar el estado actual de la máquina. Cuando necesita pausar un hilo, el estado actual de la máquina se guarda en esa área. Cuando necesita reanudar un subproceso, el estado de la máquina se restaura desde esa área.

Cuando el depurador necesita pausar un subproceso, tiene el sistema operativo pausa ese subproceso exactamente de la misma manera que lo haría por otras razones. Luego, para leer el estado del hilo en pausa, el depurador mira el estado guardado del hilo. Si modifica el estado, el depurador escribe en el estado guardado, cuando surta efecto cuando se reanude el subproceso.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.