13

With strace it is possible to see the ioctl call for the certain file descriptor and with certain command. The third argument is a structure, but strace shows it as a raw pointer to the memory. strace output example:

open("/dev/node", O_RDWR) = 3
ioctl(3, 0x108, 0x8f0eb18) = 0
close(3)  

Is there a way (strace options or other tools) to see what is the structure, or at least a value behind a raw pointer?

425nesp
  • 6,936
  • 9
  • 50
  • 61
Terry Greentail
  • 143
  • 1
  • 5
  • Does it give you the address of the instruction? If so it's really simple in GDB to add a break point and then look at the memory... How you'd determine the actual structure I'm not so sure. – Matt Jun 21 '12 at 09:56
  • I mean that if I would write it in my program, it would look like this: `ioctl( dev_node, IOCTL_CODE, &ioctl_struct )`, where third argument is a structure of type Ioctl_Buf_Struct. When strace is used for the binary program as we see in the example above, I would be curious to know what is behind 0x8f0eb18 address: what is the structure that is sent there, or at least what is it's value. Can gdb help here? – Terry Greentail Jun 21 '12 at 10:55
  • well... If you run the program, stop if just before that command, then you can find the values by dereferencing the pointer. Use strace to find all the malloc calls, until you find the one that returns that pointer. That will tell you the size of the struct. You can then look at the memory, with the known size, and so reproduce the struct in it's binary form. You may never know *what* the struct is, but you can find the value. – Matt Jun 21 '12 at 14:46

2 Answers2

2

In gdb, if you stop it right before the call to ioctl, you can then enter:

(gdb) p *(ioctl_struct *) 0x8f0eb18

That will show you how the contents of that memory location maps to the ioctl_struct.

koral
  • 5,410
  • 1
  • 13
  • 5
2

I've run into a similar problem: wanted to inspect a syscall to ioctl made by vde_switch (which creates a TUN/TAP virtual network interface), in order to know what I was doing wrong in my code (which had to do the same thing as vde_switch, but programmatically.)

By running:

sudo strace vde_switch -tap tap0

I was able to know, as Terry Greentail, that the syscall being made was ioctl(5, TUNSETIFF, 0x7fffa99404e0) and the pointer would be a reference to a structure of type struct ifreq. In my code I had something like ioctl(tapfd, TUNSETIFF, &ifr_dev).

Initially I tried to make gdb stop on a syscall, setting: catch syscall ioctl (I had run gdb as gdb --args vde_switch -tap tap0), but whenever the catch was hit, gdb showed no information about the parameters of ioctl. After struggling with this for a while, I decided to run strace inside gdb, as:

gdb --args strace vde_witch -tap -tap0

Although no breakpoint had worked in this way, the output showed which file descriptor was being used:

open("/dev/net/tun", O_RDWR)            = 9
ioctl(9, TUNSETIFF, 0x7fffffffe350)     = 0

So I tried another time with: gdb --args strace vde_witch -tap -tap0 and set a conditional breakpoint:

b ioctl if $rdi==9

The calling convention (I'm on an AMD64) uses RDI for the first parameter, RSI for the second and RDX for the third (see System V AMD64 ABI.) Finally, when the breakpoint was hit, I was able to inspect the ifreq structure:

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>}}
Tarc
  • 3,214
  • 3
  • 29
  • 41