libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] Request for help with libunwind-dynamic


From: Tim Holy
Subject: [Libunwind-devel] Request for help with libunwind-dynamic
Date: Fri, 12 Jul 2013 09:35:30 -0500
User-agent: KMail/4.8.5 (Linux/3.2.0-49-generic; KDE/4.8.5; x86_64; ; )

Hello,

I'm a user and contributor to a relatively new LLVM-based dynamic language, 
Julia. We use libunwind for our backtraces, and I've also used libunwind to 
develop a sampling profiler for Julia.

Occasionally I've seen "truncated" backtraces (more detail below), where 
unw_step returns 0 when it shouldn't. My impression (which could, of course, 
be entirely mistaken---I'm only recently self-educated on frames, registers, 
etc.) is that these truncated backtraces may occur because we are not 
providing sufficient unwind information, and I'm wondering whether we need to 
be 
explicitly using libunwind-dynamic. I am having a bit of trouble understanding 
just how much I have to do to use it. In particular, the examples I've seen 
almost all derive from Gtest-dyn1.c, in which "fake dynamic" code is generated 
by memcpying a function, and the various parameters for interacting with 
libunwind-dynamic are hard-coded. 

The documentation on "dynamic unwind directives" seems to suggest that any 
operation involving a register requires a directive? Wouldn't that mean I'd 
have to go through the LLVM-produced assembly instruction-by-instruction and 
check it? I've tried supplying just _U_dyn_op_stop or the alias/stop 
combination that one finds in Gtest-dyn1.c; with either one, the best I've been 
able to achieve is a segfault on program launch.

Here's my current best attempt, in case that's useful. The LLVM Function* is 
f, and the address (returned by getPointerToFunction()) is fptr.

      unw_dyn_region_info_t *region;
      unw_dyn_info_t di;
      region = (unw_dyn_region_info_t *) alloca(_U_dyn_region_info_size(2));
      region->op_count = 2;
      region->next = NULL;
      // Count the number of instructions
      int insn_count = 0;
      for (Function::iterator i = f->begin(); i != f->end(); i++)
        insn_count += i->size();
      region->insn_count = insn_count+4; // +4 for prologue/epilogue
      printf("%lx\n", fptr);
      printf("nisn = %d\n", insn_count);
  //     _U_dyn_op_alias(&region->op[0], 0, -1, fptr);
      _U_dyn_op_stop(&region->op[0]);
      memset(&di, 0, sizeof(di));
      di.start_ip = fptr;
      di.end_ip = di.start_ip+16*region->insn_count/3;
      di.format = UNW_INFO_FORMAT_DYNAMIC;
      di.u.pi.name_ptr = (unw_word_t) "A test";
      di.u.pi.regions = region;
      _U_dyn_register (&di);

The segfault can be avoided by commenting out the U_dyn_register step.

Not sure whether you can help, but in any event thanks for taking the time to 
read this.

Best,
--Tim


On the truncated backtraces: using a Julia function which is equivalent to the 
C function:
int64_t unsafe_iceil(double x) {
    ix = (int64_t) x;
    return ix + (x > ix);
}
and which generated the following assembly:
Filename: /tmp/unrooted.jl
Source line: 4
        push    RBP
        mov     RBP, RSP
Source line: 4
        cvttsd2si       RCX, XMM0
Source line: 5
        cvtsi2sd        XMM1, RCX
        ucomisd XMM0, XMM1
Source line: 6
        seta    AL
        movzx   EAX, AL
        add     RAX, RCX
        pop     RBP
        ret

When calling this from a higher-level function, I got 2 types of backtraces, 
ones of length 3 and 19. The length-3 backtraces are truncated (the first two 
steps are generated by the signal handler and OS). 

On one trial, the address of the function entry was 0x00007f3788531d90. For 
truncated backtraces, the third frame pointer was always one of the following:
 0x00007f3788531d99
 0x00007f3788531d9e
 0x00007f3788531da2
 0x00007f3788531da5
 0x00007f3788531da8
 0x00007f3788531dab

The length-19 backtraces were always one of the following (note that some of 
these may not have been inside unsafe_iceil):
 0x00007f3788531d90
 0x00007f3788531d91
 0x00007f3788531dac
 0x00007f378afc1bb0
 0x00007f378afc1bba

Note that these are intermingled---the length-19 backtraces start at function 
entry, and then there is a somewhat-curious gap of 9 bytes, followed by 
truncated backtraces.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]