(gdb) break *0x972

Debugging, GNU± Linux and WebHosting and ... and ...

LD_PRELOAD interpolation and variadic functions

As part of my work on OpenMP debugging, I had to implement interpolation functions to capture the beginning and end of some library functions. In general, that's easy:

// library function we want to intercept:
// int test(int a, int b);

int test(int a, int b) {
   static fct_t real_test = dlsym(RTLD_NEXT, "test");

   //before test
   real_test(a, b);
   //after test


I didn't test this code, but that should work. Now, what it the function you want to intercept looks like that:

void myprintf_real(const char *fmt, ...);

Portable Answer

you can't intercept it!

ASM Hardcore Answer

//tested and certainly only working on x86-64
void myprintf_asm_interpo(const char *fmt, ...) {
   //before myprintf

  // unroll the frame
  asm volatile("mov    -0xb8(%rbp),%rdi\n\t"
               "mov    -0xa8(%rbp),%rsi\n\t"
               "mov    -0xa0(%rbp),%rdx\n\t"
               "mov    -0x98(%rbp),%rcx\n\t"
               "mov    -0x90(%rbp),%r8\n\t"
               "mov    -0x88(%rbp),%r9\n\t"
               "add     $0xc0,%rsp\n\t");

  //jump to myprintf_real;

  volatile register void ** rsp asm ("rsp");

  //movq    $[addrs], -8(%%rsp) // I can't compile that ...

  *(rsp-1) = myprintf_real;

  asm volatile(
    "mov    %rbp,%rsp\n\t"
    "pop     %rbp\n\t"
    "mov     (%rax), %rax\n\t"
    "jmpq    *%rax");

I disassembled the function prolog with GDB, then reversed it and put it before jumping to myprintf_real. With that technique I can't insert code after the function execution (because it returns directly to the caller frame), but that was already a good start.

GCC-Specific Clean Answer

With __builtin_apply_args() and __builtin_apply()! Easy peasy! I prefer my code to be gcc-specific than architecture specific, especially with such a hardcoded blob of assembly!

int myprintf_gcc_interpo(char *fmt, ...) {
    // before 
    void *arg = __builtin_apply_args();
    void *ret = __builtin_apply((void*)printf, arg, 100);

From stackoverflow with love ;-) Test it with this file.