[Lldb-commits] [PATCH] D18975: Fix unwind failures when PC points beyond the end of a function

Ulrich Weigand via lldb-commits lldb-commits at lists.llvm.org
Mon Apr 11 11:25:26 PDT 2016


uweigand created this revision.
uweigand added a reviewer: jasonmolenda.
uweigand added a subscriber: lldb-commits.

RegisterContextLLDB::InitializeNonZerothFrame already has code to attempt
to detect and handle the case where the PC points beyond the end of a
function, but there are certain cases where this doesn't work correctly.

In fact, there are *two* different places where this detection is attempted,
and the failure is in fact a result of an unfortunate interaction between
those two separate attempts.

First, the ResolveSymbolContextForAddress routine is called with the
resolve_tail_call_address flag set to true.  This causes the routine
to internally accept a PC pointing beyond the end of a function, and
still resolving the PC to that function symbol.

Second, the InitializeNonZerothFrame routine itself maintains a
"decr_pc_and_recompute_addr_range" flag and, if that turns out to
be true, itself decrements the PC by one and searches again for
a symbol at that new PC value.

Both approaches correctly identify the symbol associated with the PC.
However, the problem is now that later on, we also need to find the
DWARF CFI record associated with the PC.  This is done in the
RegisterContextLLDB::GetFullUnwindPlanForFrame routine, and uses
the "m_current_offset_backed_up_one" member variable.

However, that variable only actually contains the PC "backed up by
one" if the *second* approach above was taken.  If the function was
already identified via the first approach above, that member variable
is *not* backed up by one but simply points to the original PC.
This in turn causes GetEHFrameUnwindPlan to not correctly identify
the DWARF CFI record associated with the PC.

Now, in many cases, if the first method had to back up the PC by one,
we *still* use the second method too, because of this piece of code:

    // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
    // and our "current" pc is the start of a function...
    if (m_sym_ctx_valid
        && GetNextFrame()->m_frame_type != eTrapHandlerFrame
        && GetNextFrame()->m_frame_type != eDebuggerFrame
        && addr_range.GetBaseAddress().IsValid()
        && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
        && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
    {
        decr_pc_and_recompute_addr_range = true;
    }

In many cases, when the PC is one beyond the end of the current function,
it will indeed then be exactly at the start of the next function.  But this
is not always the case, e.g. if there happens to be alignment padding
between the end of one function and the start of the next.

In those cases, we may sucessfully look up the function symbol via
ResolveSymbolContextForAddress, but *not* set decr_pc_and_recompute_addr_range,
and therefore fail to find the correct DWARF CFI record.

A very simple fix for this problem is to just never use the first method.
Call ResolveSymbolContextForAddress with resolve_tail_call_address set
to false, which will cause it to fail if the PC is beyond the end of
the current function; or else, identify the next function if the PC
is also at the start of the next function.  In either case, we will
then set the decr_pc_and_recompute_addr_range variable and back up the
PC anyway, but this time also find the correct DWARF CFI.


http://reviews.llvm.org/D18975

Files:
  source/Plugins/Process/Utility/RegisterContextLLDB.cpp

Index: source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -470,11 +470,13 @@
         return;
     }
 
-    bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function...
-                                           // This will handle the case where the saved pc does not point to 
-                                           // a function/symbol because it is beyond the bounds of the correct
-                                           // function and there's no symbol there.  ResolveSymbolContextForAddress
-                                           // will fail to find a symbol, back up the pc by 1 and re-search.
+    bool resolve_tail_call_address = false; // m_current_pc can be one past the address range of the function...
+                                            // If the saved pc does not point to a function/symbol because it is
+                                            // beyond the bounds of the correct function and there's no symbol there,
+                                            // we do *not* want ResolveSymbolContextForAddress to back up the pc by 1,
+                                            // because then we might not find the correct unwind information later.
+                                            // Instead, let ResolveSymbolContextForAddress fail, and handle the case
+                                            // via decr_pc_and_recompute_addr_range below.
     const uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
     uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc,
                                                                             resolve_scope,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D18975.53290.patch
Type: text/x-patch
Size: 1919 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20160411/13bc290b/attachment-0001.bin>


More information about the lldb-commits mailing list