Tracing msgrcv with ltrace
ltrace is a tool for tracing dynamic library calls. I use it from time to time and this time I needed to trace the msgrcv
system call. Usually, you would use strace to trace the system calls, but I need an output of both library calls and system calls. One interesting feature is that I don’t need to trace the actual system calls using the -S
flag and can trace the libc
system call wrappers instead:
msgrcv@libc.so.6(0x10002, 0x5634e4d2db08, 4712, 0xffffffffc0000000) = 708 <0.828835>
So far so good, but the output is not very useful as I don’t see the message received. ltrace
properly displays the most common library calls but for some reason not the msgrcv
and several others like semop
and shmat
. Luckily for me ltrace
can use function prototype descriptions from a custom ltrace.conf
file. msgrcv
is a tricky function to describe: just like read
and similar functions, it uses output parameter and the length of the data is returned by the function. In addition to that, the output parameter is a complex type. My first attempt at configuration got me pretty far:
long msgrcv(int, +struct(long, array(char, retval))*, ulong, long, hex(int));
An important detail is the +
sign before the output parameter. ltrace
will wait until the function returns and will display the rest of the parameters after that. The second important detail is specifying the length of the data as retval
(an alias for arg0
). It is the value function returned. I could have used the arg3
and show the full content of the second argument but using the function result allows to show only the portion of the array that is filled:
msgrcv@libc.so.6(65538, { 536870912, [ '{', '\0', '\0', '\0', '\002' ] }, 4712, -1073741824, 0) = 5 <19.964097>
I was very happy until the msgrcv
system call failed. The function returned a -1
which was interpreted as an unsigned integer and ltrace
printed a huge amount of junk until it hit the limit of array size to be printed. Turns out this issue is described in the “to do” list of the ltrace
for many years without any progress. But the same “to do” revealed that there is a workaround. I can wrap the retval
in zero()
and the result will be much better:
long msgrcv(int, +struct(long, array(char, zero(retval)))*, ulong, long, hex(int));
The only downside is that I get an error message for failing calls, but it is much easier to deal with than kilobytes of junk:
msgrcv@libc.so.6(3833859 <no return ...>
error: maximum array length seems negative
, { 0, [ '{' ] }, 4712, 0, 0x800) = -1 <0.000520>