gdb: tengo un volcado de núcleo de un ejecutable que NO fue creado con símbolos de depuración. ¿Puedo recuperar contenidos argv?

Tengo un volcado de núcleo de un ejecutable que NO fue construido con símbolos de depuración.

¿Puedo recuperar contenidos argv para ver cuál fue la línea de comando?

Si ejecuto gdb, puedo ver un retroceso y puedo navegar al marco principal (). Una vez allí, ¿hay una manera de recuperar argv, sin saber su dirección exacta?

Estoy en x86_x64 (CPU Intel Xeon) ejecutando una distribución / kernel de Linux de CEntOS,

Una razón por la que tengo esperanzas es que el volcado central parece mostrar un argumento parcial.

(El programa es postgres, y cuando cargo el archivo central, gdb imprime un mensaje que incluye el nombre de usuario db de postgres, la dirección OP del cliente y los primeros 10 caracteres de la consulta))

Mejor respuesta
En x86_64, los argumentos se pasan en los registros% rdi,% rsi, etc. (calling convention).

Por lo tanto, cuando entras en el marco principal, debes poder:

(gdb) p $rdi           # == argc
(gdb) p (char**) $rsi  # == argv

(gdb) set $argv = (char**)$rsi
(gdb) set $i = 0
(gdb) while $argv[$i]
> print $argv[$i++]
> end

Desafortunadamente, GDB normalmente no restaurará $ rdi y $ rsi al cambiar los marcos. Así que este ejemplo no funciona:

cat t.c

#include <stdlib.h>

int bar() { abort(); }
int foo() { return bar(); }
int main()
{
  foo();
  return 0;
}

gcc t.c && ./a.out
Aborted (core dumped)

gdb -q ./a.out core
Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
#0  0x00007fdc8284aa75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64  ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
    in ../nptl/sysdeps/unix/sysv/linux/raise.c
(gdb) bt
#0  0x00007fdc8284aa75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007fdc8284e5c0 in *__GI_abort () at abort.c:92
#2  0x000000000040052d in bar ()
#3  0x000000000040053b in foo ()
#4  0x000000000040054b in main ()
(gdb) fr 4
#4  0x000000000040054b in main ()
(gdb) p $rdi
$1 = 5524    ### clearly not the right value

Así que tendrás que trabajar un poco más …

Lo que puede hacer es utilizar el conocimiento de cómo se configura la pila de Linux en process startup, combinado con el hecho de que GDB restaurará el puntero de la pila:

(gdb) set backtrace past-main
(gdb) bt
#0  0x00007ffff7a8da75 in *__GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007ffff7a915c0 in *__GI_abort () at abort.c:92
#2  0x000000000040052d in bar ()
#3  0x000000000040053b in foo ()
#4  0x0000000000400556 in main ()
#5  0x00007ffff7a78c4d in __libc_start_main (main=<optimized out>, argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdad8) at libc-start.c:226
#6  0x0000000000400469 in _start ()

(gdb) frame 6
(gdb) disas
Dump of assembler code for function _start:
   0x0000000000400440 <+0>: xor    %ebp,%ebp
   0x0000000000400442 <+2>: mov    %rdx,%r9
   0x0000000000400445 <+5>: pop    %rsi
   0x0000000000400446 <+6>: mov    %rsp,%rdx
   0x0000000000400449 <+9>: and    $0xfffffffffffffff0,%rsp
   0x000000000040044d <+13>:    push   %rax
   0x000000000040044e <+14>:    push   %rsp
   0x000000000040044f <+15>:    mov    $0x400560,%r8
   0x0000000000400456 <+22>:    mov    $0x400570,%rcx
   0x000000000040045d <+29>:    mov    $0x40053d,%rdi
   0x0000000000400464 <+36>:    callq  0x400428 <__libc_start_main@plt>
=> 0x0000000000400469 <+41>:    hlt    
   0x000000000040046a <+42>:    nop
   0x000000000040046b <+43>:    nop
End of assembler dump.

Así que ahora esperamos que el% rsp original sea $ rsp 8 (un POP, dos PUSHes), pero podría estar en $ rsp 16 debido a la alineación que se realizó en la instrucción 0x0000000000400449

Veamos que hay ahí …

(gdb) x/8gx $rsp+8
0x7fffbe5d5e98: 0x000000000000001c  0x0000000000000004
0x7fffbe5d5ea8: 0x00007fffbe5d6eb8  0x00007fffbe5d6ec0
0x7fffbe5d5eb8: 0x00007fffbe5d6ec4  0x00007fffbe5d6ec8
0x7fffbe5d5ec8: 0x0000000000000000  0x00007fffbe5d6ecf

Parece prometedor: 4 (sospecha argc), seguido de 4 punteros que no son NULL, seguido de NULL.

Vamos a ver si eso se resuelve:

(gdb) x/s 0x00007fffbe5d6eb8
0x7fffbe5d6eb8:  "./a.out"
(gdb) x/s 0x00007fffbe5d6ec0
0x7fffbe5d6ec0:  "foo"
(gdb) x/s 0x00007fffbe5d6ec4
0x7fffbe5d6ec4:  "bar"
(gdb) x/s 0x00007fffbe5d6ec8
0x7fffbe5d6ec8:  "bazzzz"

De hecho, así es como invoco el binario. Como una comprobación de estado final, ¿se ve 0x00007fffbe5d6ecf como parte del entorno?

(gdb) x/s 0x00007fffbe5d6f3f
0x7fffbe5d6f3f:  "SSH_AGENT_PID=2874"

Sí, ese es el principio (o el final) del entorno.

Así que ahí lo tienen.

Notas finales: si GDB no imprimió < optimizado hacia fuera > tanto, podríamos haber recuperado argc y argv desde el fotograma # 5. Hay trabajo en ambos lados, GDB y GCC, para hacer que la impresión GDB sea mucho menos “optimizada” …

Además, al cargar el núcleo, mi GDB imprime:

Core was generated by `./a.out foo bar bazzzz'.

negando la necesidad de todo este ejercicio. Sin embargo, eso solo funciona para líneas de comando cortas, mientras que la solución anterior funcionará para cualquier línea de comando.

Por favor indique la dirección original:gdb: tengo un volcado de núcleo de un ejecutable que NO fue creado con símbolos de depuración. ¿Puedo recuperar contenidos argv? - Código de registro