El uso de gdb en un código ensamblador de un solo paso fuera del ejecutable especificado provoca el error "no se pueden encontrar los límites de la función actual"

86

Estoy fuera del ejecutable de destino de gdb y ni siquiera tengo una pila que corresponda a ese destino. De todos modos, quiero dar un solo paso, para poder verificar lo que está sucediendo en mi código de ensamblaje, porque no soy un experto en ensamblaje x86. Desafortunadamente, gdb se niega a realizar esta sencilla depuración a nivel de ensamblador. Me permite establecer y detenerme en el punto de interrupción apropiado, pero tan pronto como intento avanzar en un solo paso, gdb informa el error "No se pueden encontrar los límites de la función actual" y el EIP no cambia.

Detalles adicionales:

El código de la máquina fue generado por las declaraciones gcc asm y lo copié en la ubicación de la memoria del kernel donde se está ejecutando, desde la salida de objdump -d. No me importaría una forma sencilla de usar un cargador para cargar mi código objeto en una dirección reubicada, pero tenga en cuenta que la carga debe realizarse en un módulo del kernel.

Supongo que otra alternativa sería producir un módulo de kernel falso o un archivo de información de depuración para entregarlo a gdb, para que crea que esta área está dentro del código del programa. gdb funciona bien en el propio ejecutable del kernel.

(Para aquellos que realmente quieran saber, estoy insertando código en tiempo de ejecución en el espacio de datos del kernel de Linux dentro de una VM de VMware y depurándolo desde gdb depurando el kernel de forma remota a través del código auxiliar de gdb integrado de VMware Workstation. Tenga en cuenta que no estoy escribiendo kernel exploits; soy un estudiante de posgrado en seguridad que está escribiendo un prototipo).

(Puedo establecer un punto de interrupción en cada instrucción dentro de mi ensamblaje. Esto funciona pero se volvería bastante laborioso después de un tiempo, ya que el tamaño de las instrucciones de ensamblaje x86 varía y la ubicación del ensamblaje cambiará cada vez que reinicie).

Paul
fuente
La gente inteligente de ksplice.com inyecta datos y código en el kernel ensamblando módulos de kernel "falsos" y cargándolos. Y si ellos pueden hacerlo, ¿por qué tú no? ;-)
ephemient

Respuestas:

116

Puede utilizar stepio nexti(que se puede abreviar como sio ni) para recorrer el código de su máquina.

R Samuel Klatchko
fuente
1
Guau. En retrospectiva, no sé cómo me olvidé de Stepi. Supongo que asumí que debido a que gdb no tenía código fuente, ese paso volvería a las instrucciones de ensamblaje.
Paul
1
nota: a menudo no puede escribir "break main", "ejecutar" para los programas de ensamblaje. Escriba "layout asm", "start" en su lugar. Obtuve esto al leer el mensaje a continuación, pero es posible que alguien más que lea esta publicación no sea tan paciente.
Dmitry
1
@Dmitry startes equivalente a tbreak mainseguido de run(nota: en tbreaklugar de break)
Ruslan
151

En lugar de gdbcorrer gdbtui. O corre gdbcon el -tuiinterruptor. O presione C-x C-adespués de ingresar gdb. Ahora estás en el modo TUI de GDB .

Ingrese layout asmpara hacer el ensamblaje de la pantalla de la ventana superior; esto seguirá automáticamente su puntero de instrucciones, aunque también puede cambiar los marcos o desplazarse mientras depura. Presione C-x spara ingresar al modo SingleKey, donde run continue up down finishetc. se abrevian en una sola tecla, lo que le permite recorrer su programa muy rápidamente.

   + ------------------------------------------------- -------------------------- +
B +> | 0x402670 <main> push% r15 |
   | 0x402672 <principal + 2> mov% edi,% r15d |
   | 0x402675 <principal + 5> push% r14 |
   | 0x402677 <principal + 7> push% r13 |
   | 0x402679 <principal + 9> mov% rsi,% r13 |
   | 0x40267c <principal + 12> push% r12 |
   | 0x40267e <main + 14> push% rbp |
   | 0x40267f <principal + 15> push% rbx |
   | 0x402680 <principal + 16> sub $ 0x438,% rsp |
   | 0x402687 <main + 23> mov (% rsi),% rdi |
   | 0x40268a <principal + 26> movq $ 0x402a10,0x400 (% rsp) |
   | 0x402696 <principal + 38> movq $ 0x0,0x408 (% rsp) |
   | 0x4026a2 <principal + 50> movq $ 0x402510,0x410 (% rsp) |
   + ------------------------------------------------- -------------------------- +
proceso hijo 21518 En: Línea principal: ?? PC: 0x402670
(gdb) archivo / opt / j64-602 / bin / jconsole
Leyendo símbolos de /opt/j64-602/bin/jconsole...done.
(no se encontraron símbolos de depuración) ... hecho.
(gdb) conjunto de diseño
(gdb) inicio
(gdb)
efímero
fuente
26

Lo más útil que puede hacer aquí es display/i $pc, antes de usarlo stepicomo ya se sugirió en la respuesta de R Samuel Klatchko. Esto le dice a gdb que desensamble la instrucción actual justo antes de imprimir el indicador cada vez; entonces puedes seguir presionando Enter para repetir el stepicomando.

(Consulte mi respuesta a otra pregunta para obtener más detalles: el contexto de esa pregunta era diferente, pero el principio es el mismo).

Matthew Slattery
fuente