[Ltrace-devel] Tracing of IRELATIVE PLT entries and IFUNC symbols

Petr Machata pmachata at redhat.com
Fri Oct 18 13:02:04 UTC 2013


Hi there,

I have a bunch of patches to implement tracing of IRELATIVE PLT slots
and STT_GNU_IFUNC symbols.  It all sits on pmachata/ifunc.

IFUNC symbols are used for embedding code snippets that decide what
actual symbol should a call resolve to.  If a PLT slot resolves to an
IFUNC symbol, instead of taking this as the final address, the dynamic
linker calls it, and its return value is what the PLT entry is actually
resolved to.

When a user requests tracing of an IFUNC symbol via -x (i.e. tracing of
entry points), presumably what he wants to trace is the actual symbol
that this resolves to as well.  So when a call to an IFUNC returns,
ltrace reads the return value and puts breakpoint there as well.  This
is how it looks in practice:

$ ./ltrace -L -x xyz ~/tmp/if
xyz.IFUNC()                                      = 0x400644
xyz(1, 0x7fff3d421348, 0x7fff3d421358, 0x4006a0) = 2
xyz(2, 0x7fff3d421348, 0x7fff3d421358, 0x4006a0) = 3

ltrace in RHEL 5 and 6 supports this by way of a kludge that I'm not
particularly proud of.  Now I rewrote it properly.

The actual function that xyz resolves to is called xyz_1, but that is
not reflected above.  ltrace has no idea what 0x400644 is, and so when
it puts a breakpoint there, it names it after the IFUNC itself.  If
tracing of the actual function is requested explicitly, ltrace notices
that it already has a breakpoint, and just uses that:

$ ./ltrace -L -x xyz\* ~/tmp/if
xyz.IFUNC()                                        = 0x400644
xyz_1(1, 0x7fff30674228, 0x7fff30674238, 0x4006a0) = 2
xyz_1(2, 0x7fff30674228, 0x7fff30674238, 0x4006a0) = 3

IRELATIVE PLT slots come up when an IFUNC function is called from the
binary itself.  Because the logic for resolving IFUNC's is inside the
dynamic linker, the toolchain sets up a dedicated PLT entry through
which the calls are made.  Current master treats them thus:

$ ltrace ~/tmp/if
__libc_start_main([ "/home/petr/tmp/if" ] <unfinished ...>
(1, 0x7fff372a0488, 0x7fff372a0498, 0x4006a0) = 2
(2, 0x7fff372a0488, 0x7fff372a0498, 0x4006a0) = 3

This is how it looks after fixing:
$ ./ltrace ~/tmp/if
__libc_start_main([ "/home/petr/tmp/if" ] <unfinished ...>
xyz(1, 0x7fffb1d69588, 0x7fffb1d69598, 0x4006a0) = 2
xyz(2, 0x7fffb1d69588, 0x7fffb1d69598, 0x4006a0) = 3

However, if the binary is stripped, the symbol associated with the
IRELATIVE PLT entry may not be present anymore (though they might if
they end up in .dynsym).  Then this is how it looks:

$ ./ltrace ~/tmp/a.out
__libc_start_main([ "/home/petr/tmp/a.out" ] <unfinished ...>
IREL.0x4004e3(1, 0x7fff2daf5748, 0x7fff2daf5758, 0x400510) = 2
IREL.0x4004e3(2, 0x7fff2daf5748, 0x7fff2daf5758, 0x400510) = 3

OK.  To get to the point described above, a fair amount of
infrastructure needed to be written.

- A per-OS portions was introduced to structs breakpoint, library and
  library_symbol.  Previously only struct process had one.  This is
  necessary because the existence of IFUNC symbols is OS-dependent.

- A new breakpoint callback was introduced: breakpoint_get_return_bp.
  The intention is that a breakpoint itself can best determine where the
  corresponding return breakpoint should be placed, and how it should
  look like.  Besides using this to implement IFUNC return hook, I hope
  to be able to exploit this on ARM, where we now mangle breakpoint
  address to smuggle a hidden argument to breakpoint constructor.

- A new backend hook, os_elf_add_func_entry, was introduced.  That's
  modeled after arch_elf_add_plt_entry and serves similar purpose,
  except for tracing static symbols.

- Individual symbols can now hard-code their prototype, instead of going
  through prototype lookup in their corresponding prototype library.
  This is used for fixing prototype of IFUNC symbols.

The actual implementation of IFUNC on Linux and of IRELATIVE on
x86{,_64} is a matter of fairly straightforward hooking into the above.
I intend to enable IRELATIVE on PPC's, ARM and s390 as well, but didn't
get to that as of yet.  ia64 doesn't have IRELATIVE support as far as I
know.

Thanks,
PM



More information about the Ltrace-devel mailing list