Acerca de la depuración de gdb: sus preguntas pueden encontrar respuestas aquí


1. Cómo conservar la información del símbolo de depuración

Si queremos poder ver claramente cada línea de código, información de la pila de llamadas, nombres de variables, nombres de funciones, etc. durante la depuración, podemos agregar la opción -g al compilar programas con gcc .


Ejemplo: con gcc -g hello.c -o hello1
información gdb ./hello1Después de la ejecución, la salida de información es la siguiente, y la última línea indica que gdb se cargó correctamente.
inserte la descripción de la imagen aquí



Ejemplo de contador: gcc hello.c -o hello2
Ejecutar gdb ./hello2, la salida de información es la siguiente, la última línea indica que gdb no se pudo cargar.
inserte la descripción de la imagen aquí


2. Cómo eliminar la información del símbolo de depuración

Hay dos formas: una se menciona en la Sección 1 anterior, sin agregar la opción -g al compilar ; la otra es usar el comando strip . Por ejemplo, se sabe que el programa ejecutable hello1 tiene información de símbolo de depuración, luego de ejecutarlo con el comando strip, ingrese a gdb depuración, y la información impresa es la siguiente:
inserte la descripción de la imagen aquí


3. ¿Cuáles son las formas de iniciar la depuración de gdb?

Depure el programa de destino
Inicie el programa directamente e ingrese al modo de depuración: gdb filename, comogdb ./hello


Depurar proceso adicional
Si desea depurar un programa en ejecución pero no desea reiniciarlo, puede usar sudo gdb attach pid
sudo para indicar el uso de la autorización de root y pid es el PID del proceso del programa de destino ( ps -ef | grep filenameque se puede obtener ).

Después de adjuntar el programa de destino con gdb, el depurador se detendrá.En este momento, puede usar continueel comando para permitir que el programa continúe ejecutándose, o agregar un punto de interrupción correspondiente para continuar ejecutando el programa.

Cuando desee finalizar la depuración después de depurar el programa sin afectar el trabajo normal del proceso actual, puede ingresar detachcomandos en la interfaz de línea de comandos de gdb para separar el programa del depurador de gdb.


Depuración del archivo central
El programa del servidor se bloquea repentinamente después de ejecutarse durante un período de tiempo. Puede localizar la causa depurando el archivo central generado por el programa bloqueado:gdb filename corefile

Ejemplo: testcore.c
inserte la descripción de la imagen aquí


Ejecute el programa y vea el archivo central generado después del bloqueo:
inserte la descripción de la imagen aquí


Use gdb testcore coreel comando para depurar la causa del bloqueo:
inserte la descripción de la imagen aquí



4. Cómo generar un archivo central cuando el programa falla

1) Verifique si el sistema ha habilitado el mecanismo de generación de archivos centrales para fallas del programa. Comando: El valor del parámetro de tamaño de archivo centralulimit -a
inserte la descripción de la imagen aquí
en la figura anterior es 0, lo que indica que el sistema no ha habilitado la generación de archivos centrales.



2) Encienda el mecanismo de bloqueo del programa para generar archivos principales, comando:, ulimit -c unlimitedilimitado significa tamaño ilimitado, pasos de operación:

Se ulimit -c unlimitedagregará a /etc/profile;
Ejecutar source /etc/profile;
Ejecutar ulimit -apara ver si tiene efecto.



5. Especifique el directorio de generación del archivo central

En circunstancias normales, de acuerdo con la configuración predeterminada del sistema, el núcleo generalmente se genera en el directorio de ejecución del programa después de que el programa falla; si es necesario para el proyecto, especifique el directorio de generación del archivo central y nosotros puede modificar /etc/sysctl.confel archivo paso:

1) Primero, agregue el directorio de generación del archivo principal en /etc/sysctl.conf: kernel.core_pattern=/home/myubuntu/myfile/core_dump/core-%e-%p-%t
inserte la descripción de la imagen aquí
descripción del parámetro:

%%: Equivalente a %
%p: Equivalente a
%u: Equivalente
a %g: Equivalente a
%s: Equivalente al número de la señal que provocó el volcado
%t: Equivalente a la hora del volcado
%e: Equivalente a el nombre del ejecutable
% h: Equivalente a hostname


2) Luego, ejecuta sudo sysctl -p /etc/sysctl.confel comando para que surta efecto.
inserte la descripción de la imagen aquí

3) Comprobar si ha surtido efecto:cat /proc/sys/kernel/core_pattern
inserte la descripción de la imagen aquí


4) Genere el archivo central y confirme si se ha generado en el directorio especificado
inserte la descripción de la imagen aquí



6. Descripción de los comandos comunes

inserte la descripción de la imagen aquí



7. Funcionamiento práctico de los comandos comunes

Tome hello.c como ejemplo

#include <stdio.h>
int main()
{
    
    
	int i = 1;
	int j = 2;
	int m = i+j;
	for(int k = 0; k < 100; k++)
	{
    
    
		printf("number:%d\n");
	}
	printf("hello world!\n");
	return 0;
}

7.1 ejecutar comando

De forma predeterminada, después de ejecutar gdb filename , el programa en realidad no comienza a ejecutarse, debe usar el comando ejecutar para iniciarlo.
inserte la descripción de la imagen aquí

7.2 Pausar y continuar comandos

El comando ctrl+c puede pausar el programa:
inserte la descripción de la imagen aquí


El programa puede continuar ejecutándose con el comando continuar :
inserte la descripción de la imagen aquí

7.3 Comando romper añadir punto de interrupción

Hay varias formas de agregar un punto de interrupción:
1) break functionname : significa agregar un punto de interrupción en la entrada del nombre de la función;
2) break LineNo : agrega un punto de interrupción en el número de línea del archivo actual en LineNo;
3) break filename: LineNo : agregue un punto de interrupción en el número de línea del archivo de nombre de archivo LineNo.
inserte la descripción de la imagen aquí


7.4 Interrupción de información, habilitar, deshabilitar, eliminar el comando de operación de punto de interrupción

1) información de punto de interrupción de consulta de ruptura de información
inserte la descripción de la imagen aquí


2) deshabilitar número deshabilitar punto de interrupción
inserte la descripción de la imagen aquí

3) habilitar número habilitar punto de interrupción
inserte la descripción de la imagen aquí

4) eliminar número eliminar punto de interrupción
inserte la descripción de la imagen aquí

7.4 rastreo inverso, operación de apilamiento de cuadros

1) retroceder para ver la pila de llamadas actual
inserte la descripción de la imagen aquí

2) el marco cambia a la pila especificada
inserte la descripción de la imagen aquí


7.5 imprimir Imprimir valor variable

1) Imprimir el valor de la variable en la posición actual
inserte la descripción de la imagen aquí

2) Cambiar a otras pilas e imprimir los valores de las variables de esa pila
inserte la descripción de la imagen aquí

3) El comando de impresión no solo puede mostrar valores de variables, sino también mostrar los valores de resultados de cálculo de expresiones que realizan ciertas operaciones, e incluso mostrar los valores de resultados de ejecución de algunas funciones.

Por ejemplo, entrada: p &iel valor de la dirección de la variable i se puede generar
inserte la descripción de la imagen aquí

También puede p i+j+mimprimir
inserte la descripción de la imagen aquí


7.6 código de visualización de lista

1) La lista muestra el código cercano que está ejecutando el código
inserte la descripción de la imagen aquí


2) lista: muestra el código que se ejecuta antes de su código
inserte la descripción de la imagen aquí


3) la ubicación de la lista muestra los códigos cercanos del código de ubicación especificado

  • list lineno , como list 11, muestra el código fuente cerca del número de línea 11
    inserte la descripción de la imagen aquí
  • list filename:lineno , como list kafkaconsumer.c:101 muestra el código cerca de la línea 101 en el archivo kafkaconsumer.c
  • list functionname , como list main enumera los códigos cerca de la función principal en el archivo de código actual
  • list filename:functionname , como list kafkaconsumer.c:dealdata muestra el código cerca de la función dealdata en el archivo kafkaconsumer.c
  • Enumere primero, último , especifique el rango específico de códigos mostrados.


4) establezca el conteo de tamaño de lista para establecer el número de líneas de código mostradas

list muestra 10 líneas de código de forma predeterminada, que se pueden configurar con el comando set listsize count .
inserte la descripción de la imagen aquí

5) mostrar tamaño de lista para ver el número de líneas de código mostradas
inserte la descripción de la imagen aquí


7.7 funciones de información muestra los nombres de todas las funciones

El comando de funciones de información mostrará los nombres de todas las funciones en el programa, formatos de parámetros, tipos de valores devueltos y en qué
archivo de código se encuentran las funciones.
inserte la descripción de la imagen aquí

7.8 ptype genera el tipo de una variable

1) Salida del tipo de una variable
inserte la descripción de la imagen aquí

2) Si la variable es un tipo de estructura, ptype no solo puede enumerar el tipo de esta variable, sino también enumerar los nombres de campo de cada variable miembro en detalle
inserte la descripción de la imagen aquí


El comando de subproceso 7.9 se puede usar para depurar subprocesos múltiples

1) subproceso de información para ver el estado de ejecución de todos los subprocesos del proceso actual

inserte la descripción de la imagen aquí


2) Número de subproceso cambia a otros subprocesos.
Por ejemplo, al cambiar al subproceso 2, se agrega un asterisco delante del subproceso 2 (a qué subproceso se cambia, qué subproceso tendrá un asterisco)

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí


7.10 next Ejecuta la siguiente instrucción

El siguiente comando se llama "pasar por encima" en términos de depuración, es decir, salta directamente cuando encuentra una llamada de función y no ingresa al cuerpo de la función. Si presiona directamente la tecla Intro en la interfaz de línea de comandos de GDB, el valor predeterminado es volver a ejecutar el último comando. Por lo tanto, cuando use el siguiente comando para depurar paso a paso, no necesita ingresar el comando n repetidamente, simplemente presione Entrar directamente .

inserte la descripción de la imagen aquí


7.11 paso ejecuta la siguiente instrucción

El comando de paso (abreviado como s) es "entrar en" (entrar), como sugiere el nombre, es encontrar una llamada de función e ingresar al interior de la función.

inserte la descripción de la imagen aquí


7.12 volver y terminar ejecutar la función actual

inserte la descripción de la imagen aquí


1) La función del comando de retorno es finalizar la ejecución de la función actual
inserte la descripción de la imagen aquí


2) El comando de finalización ejecutará la función hasta que salga de la función normalmente. Si quedan códigos en la función actual que no se han ejecutado
, no se ejecutarán.

inserte la descripción de la imagen aquí


7.13 hasta correr a una línea especificada

La siguiente figura usa la instrucción hasta para hacer que el programa se ejecute directamente desde el punto de interrupción de 18 líneas hasta las 23 líneas especificadas.
inserte la descripción de la imagen aquí

7.14 salto Saltar a la posición especificada

Sintaxis básica: saltar <ubicación>

jump lineno , salta al número de línea ejecutado - posición absoluta, como jump 29

inserte la descripción de la imagen aquí


7.15 desmontar Ver código de montaje

desensamblar Al realizar una depuración avanzada, es posible que deba consultar las instrucciones de ensamblaje de una determinada pieza de código para solucionar problemas, o
al depurar algunos programas de versión de lanzamiento sin información de depuración, puede usar el código desensamblado para localizar el problema.

inserte la descripción de la imagen aquí


7.16 establecer argumentos y mostrar comandos de argumentos

1) establecer argumentos establecer parámetros de entrada del programa

inserte la descripción de la imagen aquí

2) mostrar argumentos ver parámetros de entrada del programa

inserte la descripción de la imagen aquí

7.17 vigilancia del reloj

El comando watch es un comando poderoso que se puede usar para monitorear una variable o una sección de la memoria.Cuando el valor de esta variable o la memoria cambia, GDB se descompondrá. Una variable o una dirección de memoria que se esté monitoreando generará un punto de vigilancia (punto de observación).

Uso: ver nombre de variable o dirección de memoria

1) Variable entera: int i; watch i


2) Tipo de puntero: char*p; watch p o watch *p
Nota: hay una diferencia entre watch p y watch *p, el primero es para ver *(&p), que es la propia variable p; el segundo es la contenido de la memoria apuntada por p . Necesitamos verificar la dirección, porque el propósito es ver cómo cambian los datos en una determinada dirección de memoria.


3) Una matriz o memoria: char buf[128], watch buf
aquí es para monitorear los datos de buf 128. En este momento, en lugar de usar puntos de interrupción de hardware, se realiza mediante interrupciones suaves. El uso de interrupciones suaves para verificar las variables de memoria consume más recursos de la CPU, y especificar la dirección con precisión es una interrupción de hardware.

Nota: Cuando el punto de observación establecido es una variable local, después de que la variable local deje de ser válida, el punto de observación también se invalidará.


7.18 Monitoreo de pantalla

Las variables o direcciones de memoria monitoreadas por el comando de visualización generarán automáticamente los valores de estas variables o memoria cada vez que se interrumpa el programa.

inserte la descripción de la imagen aquí



8. Consejos de depuración

8.1 Cómo mostrar el resultado de la impresión por completo

Cuando el comando de impresión imprime una cadena o matriz de caracteres, si la cadena es demasiado larga, el comando de impresión no la mostrará completamente de forma predeterminada; se
puede configurar con el comando set print element 0 para mostrar completamente todas las cadenas de la variable.


8.2 Deshabilitar el cambio de subprocesos en subprocesos múltiples

Múltiples subprocesos llaman a la misma función. Cuando ingresamos a la función y realizamos la depuración línea por línea, originalmente esperábamos ejecutar las siguientes 11 líneas después de ejecutar la línea 10. En este momento, el sistema puede cambiar a otro subproceso y saltar a Al código fuente de la línea 5 de la función, causando confusión.

Para evitar la interferencia de otros subprocesos, puede usar el comando set scheduler-locking on para bloquear el flujo de ejecución en el subproceso actual; también puede usar el comando set scheduler-locking off para desbloquearlo.


8.3 Puntos de corte condicionales

En la depuración real, generalmente usamos tres tipos de puntos de interrupción: puntos de interrupción ordinarios, puntos de interrupción condicionales y puntos de interrupción de hardware.

1) Los puntos de interrupción de hardware también se denominan puntos de interrupción de datos. Dichos puntos de interrupción son en realidad algunos puntos de interrupción agregados con el comando watch presentado en el curso anterior (algunos puntos de interrupción agregados por el reloj se realizan a través de interrupciones suaves, no puntos de interrupción de hardware). Se activa un punto de interrupción de hardware cuando cambia la dirección de memoria supervisada o el valor de la variable.

2) Los puntos de interrupción ordinarios son puntos de interrupción distintos de los puntos de interrupción condicionales y los puntos de interrupción de hardware.

3) Un punto de interrupción condicional es un punto de interrupción que se activa solo cuando se cumple una determinada condición
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí


8.4 Usar gdb para depurar programas multiproceso

Un programa multiproceso se refiere a un programa con una estructura similar a Nginx.El proceso principal genera procesos secundarios a través de la función fork().

1) Método 1: utilice gdb para depurar el proceso principal y, después de que aparezca el proceso secundario fork(), utilice gdb para adjuntarlo al proceso secundario. Al mismo tiempo, debe volver a abrir una ventana de sesión para la depuración.


2) Método 2: utilice el modo show follow-fork para ver el valor actual, o configure el modo follow-fork para establecer si GDB continuará depurando el proceso principal o el proceso secundario cuando un proceso bifurca un nuevo proceso secundario (el valor es hijo), el valor predeterminado es el proceso padre (el valor es padre).

Supongo que te gusta

Origin blog.csdn.net/locahuang/article/details/126834194
Recomendado
Clasificación