Me encontré con un problema similar: quería inspeccionar un syscall a ioctl
hecho por vde_switch
(que crea una interfaz de red virtual TUN/TAP), para saber qué estaba haciendo mal en mi código (que tenía hacer lo mismo que vde_switch
, pero mediante programación)
ejecutando:.
sudo strace vde_switch -tap tap0
pude conocer, como Terry Greentail, que la llamada al sistema que se hizo fue ioctl(5, TUNSETIFF, 0x7fffa99404e0)
y el puntero sería una referencia a una estructura de tipo struct ifreq
. En mi código tenía algo así como ioctl(tapfd, TUNSETIFF, &ifr_dev)
.
Inicialmente traté de hacer parada GDB en una llamada al sistema, estableciendo: catch syscall ioctl
(me había acabado BGF como gdb --args vde_switch -tap tap0
), pero cada vez que se vio afectada la captura, el BGF no mostraron ninguna información acerca de los parámetros de ioctl
. Después de luchar con esto durante un tiempo, decidí correr strace dentro de gdb, como:
gdb --args strace vde_witch -tap -tap0
Aunque ningún punto de interrupción había trabajado de esta manera, la salida mostraron lo que se estaba utilizando el descriptor de archivo:
open("/dev/net/tun", O_RDWR) = 9
ioctl(9, TUNSETIFF, 0x7fffffffe350) = 0
así que he intentado otra vez con: gdb --args strace vde_witch -tap -tap0
y establecer un punto de interrupción condicional:
b ioctl if $rdi==9
La convención de llamada (estoy en un AMD64) utiliza RDI
f o el primer parámetro, RSI
para el segundo y RDX
para el tercer (ver System V AMD64 ABI.) Por último, cuando fue alcanzado el punto de interrupción, yo era capaz de inspeccionar la estructura ifreq
:
Breakpoint 6, ioctl() at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: File or directory not found.
(gdb) p (struct ifreq) *$rdx
$5 = {ifr_ifrn = {ifrn_name = "tap0", '\000' <repete 11 vezes>}, ifr_ifru = {ifru_addr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_dstaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_broadaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_netmask = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_hwaddr = {sa_family = 4098, sa_data = '\000' <repete 13 vezes>}, ifru_flags = 4098, ifru_ivalue = 4098, ifru_mtu = 4098, ifru_map = {mem_start = 4098, mem_end = 0, base_addr = 0, irq = 0 '\000', dma = 0 '\000', port = 0 '\000'}, ifru_slave = "\002\020", '\000' <repete 13 vezes>, ifru_newname = "\002\020", '\000' <repete 13 vezes>, ifru_data = 0x1002 <Address 0x1002 out of bounds>}}
¿Te da la dirección de la ¿instrucción? Si es así, es realmente simple en GDB agregar un punto de quiebre y luego mirar la memoria ... Cómo no se puede determinar la estructura real. – Matt
Quiero decir que si lo escribiera en mi programa, se vería así: 'ioctl (dev_node, IOCTL_CODE, & ioctl_struct)', donde el tercer argumento es una estructura de tipo Ioctl_Buf_Struct. Cuando strace se utiliza para el programa binario como vemos en el ejemplo anterior, me gustaría saber qué hay detrás de la dirección 0x8f0eb18: cuál es la estructura que se envía allí, o al menos cuál es su valor. ¿Puede gdb ayudar aquí? –
bien ... Si ejecuta el programa, deténgalo si está justo antes de ese comando, luego puede encontrar los valores desreferenciando el puntero. Use strace para encontrar todas las llamadas malloc, hasta que encuentre la que devuelve ese puntero. Eso te dirá el tamaño de la estructura.Luego puede mirar la memoria, con el tamaño conocido, y así reproducir la estructura en su forma binaria. Puede que nunca sepas * qué * es la estructura, pero puedes encontrar el valor. – Matt