[lldb-dev] Problem unwinding from inside of a CRT function

Jason Molenda jmolenda at apple.com
Thu Jan 15 16:06:21 PST 2015

lldb is stopped on the first instruction of a function (at address 0x12350a1).  But there's no symbol for this function -- lldb doesn't KNOW it's at the first instruction of a function.  It can't profile the assembly instructions of the function to figure out how the unwind instructions should work.  So lldb falls back to the "architecture default unwind plan", e.g. ABISysV_x86_64::CreateDefaultUnwindPlan(), which assumes that the way to find the caller's eip address is to dereference ebp.

Basically, you need some source of unwind info for functions.  On Linux systems, this would be eh_frame instructions.  On Mac OS X, there's "compact unwind" info that does the same thing.  I'm sure Windows has something -- it's needed to do exception handling. 

If you don't have any source of unwind information, you need to have accurate function start addresses so lldb can look at the instruction stream and make up an unwind plan from those (v. UnwindAssembly-x86.cpp).  But this means you need to know the start address of all functions in the file.  On Mac OS X we have a special little section (LC_FUNCTION_STARTS) that encodes the length of each function in the file--so even if the function names are stripped before shipping, we can find the start address of each function easily.  lldb adds these to the symbol table and makes up function names for them.

If you have no compiler-generated unwind information (that lldb can parse) and you don't have start addresses for all functions in the file, things are going to work poorly.

For what it's worth, when looking at unwind issues it's usually easiest to turn on the unwind logging.  "log enable lldb unwind".  That'll show what lldb was up to.

Also, another ABI method is useful - see ABISysV_x86_64::CreateFunctionEntryUnwindPlan().  This is the UnwindPlan that lldb will use when it knows it is at the start of a function before any instructions have been executed.


> On Jan 15, 2015, at 3:56 PM, Zachary Turner <zturner at google.com> wrote:
> Having some trouble unwinding when I'm broken inside of a CRT function.  Another caveat is that I don't have symbols for this CRT function.  So the problem could be anything from something I've done wrong on my side, to an issue when symbols aren't present, to something else.  Here is the source code of this program:
> #include <stdio.h>
> int main (void)
> {
>   printf("This is line 1\n");
>   printf("This is line 2\n");
>   printf("This is line 3\n");
>   return 1;
> }
> Here is the disassembly of main:
> (lldb) disassemble -n main -F intel
>    0x1235040 <main>: push   ebp
>    0x1235041 <main+1>: mov    ebp, esp
>    0x1235043 <main+3>: sub    esp, 0x14
>    0x1235046 <main+6>: lea    eax, [0x1230040]
>    0x123504c <main+12>: mov    dword ptr [ebp - 0x4], 0x0
>    0x1235053 <main+19>: mov    dword ptr [esp], eax
>    0x1235056 <main+22>: call   0x12350a1
>    0x123505b <main+27>: lea    ecx, [0x1230050]
>    (snipped for brevity)
> (Using the argument to "call" as the breakpoint address)
> (lldb) break set -a 0x12350a1
> Breakpoint 3: address = 0x012350a1
> (lldb) run
> Process 17044 launching
> (lldb) Process 17044 launched: 'd:\testexe\expr_test.exe' (i386)
> (lldb) Process 17044 stopped
> * thread #1: tid = 0x40ec, 0x012350a1 expr_test.exe, stop reason = breakpoint 3.1
>     frame #0: 0x012350a1 expr_test.exe
> -> 0x12350a1: pushl  $0xc
>    0x12350a3: pushl  $0x1241000
>    0x12350a8: calll  0x1235be0
>    0x12350ad: xorl   %edi, %edi
> (lldb) disassemble -b -F intel
> -> 0x12350a1: 6a 0c           push   0xc
>    0x12350a3: 68 00 10 24 01  push   0x1241000
>    0x12350a8: e8 33 0b 00 00  call   0x1235be0
>    0x12350ad: 33 ff           xor    edi, edi
>    0x12350af: 89 7d e4        mov    dword ptr [ebp - 0x1c], edi
>    0x12350b2: 33 c0           xor    eax, eax
>    0x12350b4: 39 45 08        cmp    dword ptr [ebp + 0x8], eax
>    0x12350b7: 0f 95 c0        setne  al
>    0x12350ba: 85 c0           test   eax, eax
>    0x12350bc: 75 15           jne    0x12350d3
> Here's my register values:
> (lldb) register read
> General Purpose Registers:
>        eax = 0x01230040
>        ebx = 0x00000000
>        ecx = 0x00000001
>        edx = 0x00000000
>        edi = 0x00000000
>        esi = 0x00000000
>        ebp = 0x00EAF920
>        esp = 0x00EAF908
>        eip = 0x012350A1
>     eflags = 0b00000000000000000000001000010110
> And using the value of esp to dump the stack (sorry, I don't know how to use the -f argument to format this more nicely), 
> (lldb) memory read 0x00EAF908
> 0x00eaf908: 5b 50 23 01 40 00 23 01 00 00 00 00 00 00 00 00  [P#. at .#.........
> 0x00eaf918: 28 f9 ea 00 00 00 00 00 68 f9 ea 00 4e 52 23 01  (.......h...NR#.
> So the return address is 0x0123505b.  Cross-referencing this with the original disassembly of main(), it looks like this is the correct value.
> So it seems like the Unwinder has all the information it needs, but yet I'm still only getting 1 frame.  Any suggestions how to dig into this?

More information about the lldb-dev mailing list