¿Por qué GDB necesita tanto el ejecutable como el volcado del núcleo?

11

Estoy depurando utilizando volcados de núcleo, y tenga en cuenta que gdb necesita que suministre tanto el ejecutable como el volcado de núcleo. ¿Por qué es esto? Si el volcado del núcleo contiene toda la memoria que utiliza el proceso, ¿no está el ejecutable contenido en el volcado del núcleo? ¿Quizás no hay garantía de que todo el exe se cargue en la memoria (aunque los ejecutables individuales no suelen ser tan grandes) o tal vez el volcado del núcleo no contiene toda la memoria relevante después de todo? ¿Es por los símbolos (tal vez no están cargados en la memoria normalmente)?


fuente
1
El ejecutable contiene la información del símbolo, como se indica en la documentación de gdb ...
Thomas Dickey
1
Sorprendentemente, ninguna respuesta (excepto la que acabo de agregar) menciona el formato DWARF
Basile Starynkevitch

Respuestas:

15

El volcado del núcleo es solo el volcado de la huella de memoria de sus programas, si sabe dónde estaba todo, podría usarlo.

Utiliza el ejecutable porque explica dónde (en términos de direcciones lógicas) se encuentran las cosas en la memoria, es decir, el archivo central.

Si usa un comando objdump, volcará los metadatos sobre el objeto ejecutable que está investigando. Usando un objeto ejecutable llamado a.out como ejemplo.

objdump -h a.outvoltea solo la información del encabezado, verá secciones llamadas eg. .data o .bss o .text (hay muchos más). Estos informan al cargador del núcleo dónde se pueden encontrar varias secciones en el objeto y en qué parte del espacio de direcciones del proceso se debe cargar la sección, y para algunas secciones (por ejemplo, .data .text), qué se debe cargar. (La sección .bss no contiene ningún dato en el archivo, pero se refiere a la cantidad de memoria que se debe reservar en el proceso para datos no inicializados, se llena con ceros).

El diseño del archivo de objeto ejecutable se ajusta a un estándar, ELF.

objdump -x a.out - tira todo

Si el objeto ejecutable todavía contiene sus tablas de símbolos (no se ha eliminado, man stripy solía -ggenerar una generación de depuración para gcc asumir la compilación de la fuente de CA), puede examinar el contenido principal por nombres de símbolos, por ejemplo, si tenía una variable / buffer llamado inputLine en su código fuente, puede usar ese nombre gdbpara ver su contenido. es decir gdb, conocería el desplazamiento desde el inicio del segmento de datos inicializado de sus programas donde comienza inputLine y la longitud de esa variable.

Lecturas adicionales Artículo 1 , Artículo 2 y para la especificación del formato ejecutable y de enlace (ELF) .


Actualización después del comentario de @mirabilos a continuación.

Pero si usa la tabla de símbolos como en

$ gdb --batch -s a.out -c core -q -ex "x buf1"

Produce

 0x601060 <buf1>:    0x72617453

y luego no usar la tabla de símbolos y examinar la dirección directamente en,

$ gdb --batch -c core -q -ex "x 0x601060"

Produce

0x601060:   0x72617453

He examinado la memoria directamente sin usar la tabla de símbolos en el segundo comando.


También veo que la respuesta de @ user580082 agrega más explicaciones y votará positivamente.

X Tian
fuente
66
Nunca he oído hablar de la "sección de pila básica". .bss es (históricamente) "bloque iniciado por símbolo" y prácticamente, "datos unitarios", mientras que .data es "datos inicializados" y el texto (no .code) se usa para almacenar el código de máquina. No hay una sección de pila en un binario, ya que las pilas se crean en tiempo de ejecución.
jlliagre
"Si sabes dónde estaba todo, entonces podrías usar eso" tampoco es verdad porque no todo en el programa está necesariamente incluido en la huella.
mirabilos
1
@jlliagre tienes razón, llamé por error .text .code (porque estaba pensando en una explicación mientras redactaba la respuesta) - actualizado. He pensado erróneamente en bss incorrectamente por nombre, y he actualizado mi respuesta, pero evité * Bloque iniciado por símbolo, ya que no creo que realmente se agregue a la ecuación, y he explicado que se utiliza como datos no inicializados, que fue nuestro entendimiento común. Gracias, agradezco su comentario para corregir esta publicación.
X Tian
4

El archivo central es una instantánea de la imagen de la pila, las asignaciones de memoria y los registros en el momento de la finalización del proceso. Los contenidos de los cuales se pueden manipular como se indica en la página principal del manual . Por defecto, las asignaciones privadas, las asignaciones compartidas y la información del encabezado ELF se vuelcan en el archivo principal.

Volviendo a su pregunta , la razón por la que gdb requiere un ejecutable es porque no simula la ejecución, al leer e interpretar las instrucciones binarias como lo hace valgrind, se convierte en el padre del proceso para controlar el comportamiento del proceso durante la ejecución hora. Utiliza el archivo central para determinar las asignaciones de memoria y el estado del proceso del procesador durante el bloqueo.

En Linux, los procesos principales pueden obtener información adicional sobre sus hijos, en particular la capacidad de localizarlos, lo que permite al depurador acceder a la información de bajo nivel del proceso, como leer / escribir su memoria, registros, cambiar asignaciones de señales, detener su ejecución, etc.

Comprenderá el requisito del ejecutable a pesar de tener un archivo core más una vez que lea cómo funciona cualquier depurador.

enzima
fuente
1

(además de otras buenas respuestas)

En los sistemas Linux modernos (y muchos de tipo Unix), la información de depuración (incluidos los metadatos sobre los tipos de símbolos, la ubicación del código fuente, el tipo de variables, etc., etc.) está en formato DWARF y se encuentra dentro del ejecutable ELF ( o bibliotecas compartidas ELF) cuando se compila con alguna -gopción. Recomiendo compilar programas para depurar -g3 -O0y quizás -fno-inlinesi se usa un GCC reciente ; sin embargo, con GCC puede incluso compilar con información de optimización y depuración, por ejemplo, con -O2 -g1, aunque la información de depuración en ese caso puede ser un poco "confusa" (esto podría ayudar un poco a atrapar algunos errores de Heisenbugs ).

Es bastante razonable evitar poner esa información en los archivos principales , ya que es posible que tenga muchos archivos principales diferentes (imagine un software ampliamente utilizado con muchos usuarios haciendo informes de errores, la mayoría de ellos con un corevolcado) para el mismo ejecutable. También los archivos core (5) son volcados por el kernel, lo que no debería importarle la existencia de secciones DWARF en ejecutables elf (5) (porque estas secciones no están mapeadas en el espacio de direcciones virtuales del proceso de falla que volcó el núcleo en alguna señal ( 7) ). Incluso existe la posibilidad de que la información de depuración se coloque en archivos separados (fuera del ejecutable).

Por cierto, GDB puede usarse dolorosamente para depurar volcados de núcleo para ejecutables sin ninguna información de depuración. Pero luego prácticamente depura en el nivel de código de máquina (no en el nivel simbólico proporcionado por los lenguajes de programación y sus compiladores).

Basile Starynkevitch
fuente