This revision was automatically updated to reflect the committed changes.
Closed by commit rL345577: [x86] Fix issues with a realigned stack in MSVC 
compiled applications (authored by aleksandr.urakov, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D53435?vs=171650&id=171651#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D53435

Files:
  lldb/trunk/include/lldb/Symbol/UnwindPlan.h
  lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
  lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
  lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
  lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
  lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
  lldb/trunk/source/Symbol/UnwindPlan.cpp
  lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp

Index: lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
===================================================================
--- lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ lldb/trunk/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -133,7 +133,7 @@
 
 namespace lldb_private {
 static std::ostream &operator<<(std::ostream &OS,
-                                const UnwindPlan::Row::CFAValue &CFA) {
+                                const UnwindPlan::Row::FAValue &CFA) {
   StreamString S;
   CFA.Dump(S, nullptr, nullptr);
   return OS << S.GetData();
@@ -2368,7 +2368,7 @@
   ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
                                                            sample_range, plan));
 
-  UnwindPlan::Row::CFAValue esp_plus_4, esp_plus_8, ebp_plus_8;
+  UnwindPlan::Row::FAValue esp_plus_4, esp_plus_8, ebp_plus_8;
   esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
   esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
   ebp_plus_8.SetIsRegisterPlusOffset(k_ebp, 8);
@@ -2402,7 +2402,7 @@
   ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
                                                            sample_range, plan));
 
-  UnwindPlan::Row::CFAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
+  UnwindPlan::Row::FAValue rsp_plus_8, rsp_plus_16, rbp_plus_16;
   rsp_plus_8.SetIsRegisterPlusOffset(k_rsp, 8);
   rsp_plus_16.SetIsRegisterPlusOffset(k_rsp, 16);
   rbp_plus_16.SetIsRegisterPlusOffset(k_rbp, 16);
@@ -2416,6 +2416,65 @@
             plan.GetRowForFunctionOffset(sizeof(data) - 1)->GetCFAValue());
 }
 
+TEST_F(Testx86AssemblyInspectionEngine, TestStackRealignMSVC_i386) {
+  std::unique_ptr<x86AssemblyInspectionEngine> engine = Geti386Inspector();
+
+  uint8_t data[] = {
+      0x53,                               // offset 00 -- pushl %ebx
+      0x8b, 0xdc,                         // offset 01 -- movl %esp, %ebx
+      0x83, 0xec, 0x08,                   // offset 03 -- subl $8, %esp
+      0x81, 0xe4, 0x00, 0xff, 0xff, 0xff, // offset 06 -- andl $-256, %esp
+      0x83, 0xc4, 0x04,                   // offset 12 -- addl $4, %esp
+      0x55,                               // offset 15 -- pushl %ebp
+      0x8b, 0xec,                         // offset 16 -- movl %esp, %ebp
+      0x81, 0xec, 0x00, 0x02, 0x00, 0x00, // offset 18 -- subl $512, %esp
+      0x89, 0x7d, 0xfc,                   // offset 24 -- movl %edi, -4(%ebp)
+      0x8b, 0xe5,                         // offset 27 -- movl %ebp, %esp
+      0x5d,                               // offset 29 -- popl %ebp
+      0x8b, 0xe3,                         // offset 30 -- movl %ebx, %esp
+      0x5b,                               // offset 32 -- popl %ebx
+      0xc3                                // offset 33 -- retl
+  };
+
+  AddressRange sample_range(0x1000, sizeof(data));
+  UnwindPlan plan(eRegisterKindLLDB);
+  ASSERT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly(data, sizeof(data),
+                                                           sample_range, plan));
+
+  UnwindPlan::Row::FAValue esp_minus_4, esp_plus_0, esp_plus_4, esp_plus_8,
+      ebx_plus_8, ebp_plus_0;
+  esp_minus_4.SetIsRegisterPlusOffset(k_esp, -4);
+  esp_plus_0.SetIsRegisterPlusOffset(k_esp, 0);
+  esp_plus_4.SetIsRegisterPlusOffset(k_esp, 4);
+  esp_plus_8.SetIsRegisterPlusOffset(k_esp, 8);
+  ebx_plus_8.SetIsRegisterPlusOffset(k_ebx, 8);
+  ebp_plus_0.SetIsRegisterPlusOffset(k_ebp, 0);
+
+  // Test CFA
+  EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(0)->GetCFAValue());
+  EXPECT_EQ(esp_plus_8, plan.GetRowForFunctionOffset(1)->GetCFAValue());
+  for (size_t i = 3; i < 33; ++i)
+    EXPECT_EQ(ebx_plus_8, plan.GetRowForFunctionOffset(i)->GetCFAValue())
+        << "i: " << i;
+  EXPECT_EQ(esp_plus_4, plan.GetRowForFunctionOffset(33)->GetCFAValue());
+
+  // Test AFA
+  EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(12)->GetAFAValue());
+  EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(15)->GetAFAValue());
+  EXPECT_EQ(esp_plus_0, plan.GetRowForFunctionOffset(16)->GetAFAValue());
+  for (size_t i = 18; i < 30; ++i)
+    EXPECT_EQ(ebp_plus_0, plan.GetRowForFunctionOffset(i)->GetAFAValue())
+        << "i: " << i;
+  EXPECT_EQ(esp_minus_4, plan.GetRowForFunctionOffset(30)->GetAFAValue());
+
+  // Test saved register
+  UnwindPlan::Row::RegisterLocation reg_loc;
+  EXPECT_TRUE(
+      plan.GetRowForFunctionOffset(27)->GetRegisterInfo(k_edi, reg_loc));
+  EXPECT_TRUE(reg_loc.IsAtAFAPlusOffset());
+  EXPECT_EQ(-4, reg_loc.GetOffset());
+}
+
 // Give the disassembler random bytes to test that it doesn't exceed
 // the bounds of the array when run under clang's address sanitizer.
 TEST_F(Testx86AssemblyInspectionEngine, TestDisassemblyJunkBytes) {
Index: lldb/trunk/source/Symbol/UnwindPlan.cpp
===================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp
@@ -29,6 +29,8 @@
 
     case atCFAPlusOffset:
     case isCFAPlusOffset:
+    case atAFAPlusOffset:
+    case isAFAPlusOffset:
       return m_location.offset == rhs.m_location.offset;
 
     case inOtherRegister:
@@ -95,6 +97,16 @@
       s.PutChar(']');
   } break;
 
+  case atAFAPlusOffset:
+  case isAFAPlusOffset: {
+    s.PutChar('=');
+    if (m_type == atAFAPlusOffset)
+      s.PutChar('[');
+    s.Printf("AFA%+d", m_location.offset);
+    if (m_type == atAFAPlusOffset)
+      s.PutChar(']');
+  } break;
+
   case inOtherRegister: {
     const RegisterInfo *other_reg_info = nullptr;
     if (unwind_plan)
@@ -125,8 +137,8 @@
     s.Printf("reg(%u)", reg_num);
 }
 
-bool UnwindPlan::Row::CFAValue::
-operator==(const UnwindPlan::Row::CFAValue &rhs) const {
+bool UnwindPlan::Row::FAValue::
+operator==(const UnwindPlan::Row::FAValue &rhs) const {
   if (m_type == rhs.m_type) {
     switch (m_type) {
     case unspecified:
@@ -148,7 +160,7 @@
   return false;
 }
 
-void UnwindPlan::Row::CFAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
+void UnwindPlan::Row::FAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
                                      Thread *thread) const {
   switch (m_type) {
   case isRegisterPlusOffset:
@@ -171,6 +183,7 @@
 
 void UnwindPlan::Row::Clear() {
   m_cfa_value.SetUnspecified();
+  m_afa_value.SetUnspecified();
   m_offset = 0;
   m_register_locations.clear();
 }
@@ -183,6 +196,12 @@
     s.Printf("%4" PRId64 ": CFA=", GetOffset());
 
   m_cfa_value.Dump(s, unwind_plan, thread);
+
+  if (!m_afa_value.IsUnspecified()) {
+    s.Printf(" AFA=");
+    m_afa_value.Dump(s, unwind_plan, thread);
+  }
+
   s.Printf(" => ");
   for (collection::const_iterator idx = m_register_locations.begin();
        idx != m_register_locations.end(); ++idx) {
@@ -194,7 +213,8 @@
   s.EOL();
 }
 
-UnwindPlan::Row::Row() : m_offset(0), m_cfa_value(), m_register_locations() {}
+UnwindPlan::Row::Row()
+    : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations() {}
 
 bool UnwindPlan::Row::GetRegisterInfo(
     uint32_t reg_num,
@@ -296,8 +316,10 @@
 }
 
 bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const {
-  return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value &&
-         m_register_locations == rhs.m_register_locations;
+  return m_offset == rhs.m_offset &&
+      m_cfa_value == rhs.m_cfa_value &&
+      m_afa_value == rhs.m_afa_value &&
+      m_register_locations == rhs.m_register_locations;
 }
 
 void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) {
@@ -399,7 +421,7 @@
   // UnwindPlan.
   if (GetRowAtIndex(0).get() == nullptr ||
       GetRowAtIndex(0)->GetCFAValue().GetValueType() ==
-          Row::CFAValue::unspecified) {
+          Row::FAValue::unspecified) {
     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
     if (log) {
       StreamString s;
Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
===================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
@@ -98,10 +98,15 @@
   bool push_extended_pattern_p();
   bool push_misc_reg_p();
   bool mov_rsp_rbp_pattern_p();
+  bool mov_rsp_rbx_pattern_p();
+  bool mov_rbp_rsp_pattern_p();
+  bool mov_rbx_rsp_pattern_p();
   bool sub_rsp_pattern_p(int &amount);
   bool add_rsp_pattern_p(int &amount);
   bool lea_rsp_pattern_p(int &amount);
   bool lea_rbp_rsp_pattern_p(int &amount);
+  bool lea_rbx_rsp_pattern_p(int &amount);
+  bool and_rsp_pattern_p();
   bool push_reg_p(int &regno);
   bool pop_reg_p(int &regno);
   bool pop_rbp_pattern_p();
@@ -157,9 +162,11 @@
   uint32_t m_machine_ip_regnum;
   uint32_t m_machine_sp_regnum;
   uint32_t m_machine_fp_regnum;
+  uint32_t m_machine_alt_fp_regnum;
   uint32_t m_lldb_ip_regnum;
   uint32_t m_lldb_sp_regnum;
   uint32_t m_lldb_fp_regnum;
+  uint32_t m_lldb_alt_fp_regnum;
 
   typedef std::map<uint32_t, lldb_reg_info> MachineRegnumToNameAndLLDBRegnum;
 
Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
===================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -59,6 +59,7 @@
     m_machine_ip_regnum = k_machine_eip;
     m_machine_sp_regnum = k_machine_esp;
     m_machine_fp_regnum = k_machine_ebp;
+    m_machine_alt_fp_regnum = k_machine_ebx;
     m_wordsize = 4;
 
     struct lldb_reg_info reginfo;
@@ -84,6 +85,7 @@
     m_machine_ip_regnum = k_machine_rip;
     m_machine_sp_regnum = k_machine_rsp;
     m_machine_fp_regnum = k_machine_rbp;
+    m_machine_alt_fp_regnum = k_machine_rbx;
     m_wordsize = 8;
 
     struct lldb_reg_info reginfo;
@@ -135,6 +137,8 @@
     m_lldb_sp_regnum = lldb_regno;
   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
     m_lldb_fp_regnum = lldb_regno;
+  if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
+    m_lldb_alt_fp_regnum = lldb_regno;
   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
     m_lldb_ip_regnum = lldb_regno;
 
@@ -160,6 +164,7 @@
     m_machine_ip_regnum = k_machine_eip;
     m_machine_sp_regnum = k_machine_esp;
     m_machine_fp_regnum = k_machine_ebp;
+    m_machine_alt_fp_regnum = k_machine_ebx;
     m_wordsize = 4;
 
     struct lldb_reg_info reginfo;
@@ -185,6 +190,7 @@
     m_machine_ip_regnum = k_machine_rip;
     m_machine_sp_regnum = k_machine_rsp;
     m_machine_fp_regnum = k_machine_rbp;
+    m_machine_alt_fp_regnum = k_machine_rbx;
     m_wordsize = 8;
 
     struct lldb_reg_info reginfo;
@@ -239,6 +245,8 @@
     m_lldb_sp_regnum = lldb_regno;
   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
     m_lldb_fp_regnum = lldb_regno;
+  if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
+    m_lldb_alt_fp_regnum = lldb_regno;
   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
     m_lldb_ip_regnum = lldb_regno;
 
@@ -387,6 +395,45 @@
   return false;
 }
 
+// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3]
+// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3]
+bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+  if (*(p) == 0x8b && *(p + 1) == 0xdc)
+    return true;
+  if (*(p) == 0x89 && *(p + 1) == 0xe3)
+    return true;
+  return false;
+}
+
+// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec]
+// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec]
+bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+  if (*(p) == 0x8b && *(p + 1) == 0xe5)
+    return true;
+  if (*(p) == 0x89 && *(p + 1) == 0xec)
+    return true;
+  return false;
+}
+
+// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc]
+// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc]
+bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+  if (*(p) == 0x8b && *(p + 1) == 0xe3)
+    return true;
+  if (*(p) == 0x89 && *(p + 1) == 0xdc)
+    return true;
+  return false;
+}
+
 // subq $0x20, %rsp
 bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) {
   uint8_t *p = m_cur_insn;
@@ -476,6 +523,46 @@
   return false;
 }
 
+// lea -0x28(%ebx), %esp
+// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
+bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+
+  // Check opcode
+  if (*p != 0x8d)
+    return false;
+  ++p;
+
+  // 8 bit displacement
+  if (*p == 0x63) {
+    amount = (int8_t)p[1];
+    return true;
+  }
+
+  // 32 bit displacement
+  if (*p == 0xa3) {
+    amount = (int32_t)extract_4(p + 1);
+    return true;
+  }
+
+  return false;
+}
+
+// and -0xfffffff0, %esp
+// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
+bool x86AssemblyInspectionEngine::and_rsp_pattern_p() {
+  uint8_t *p = m_cur_insn;
+  if (m_wordsize == 8 && *p == 0x48)
+    p++;
+
+  if (*p != 0x81 && *p != 0x83)
+    return false;
+
+  return *++p == 0xe4;
+}
+
 // popq %rbx
 // popl %ebx
 bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
@@ -640,7 +727,8 @@
     return false;
 
   addr_t current_func_text_offset = 0;
-  int current_sp_bytes_offset_from_cfa = 0;
+  int current_sp_bytes_offset_from_fa = 0;
+  bool is_aligned = false;
   UnwindPlan::Row::RegisterLocation initial_regloc;
   UnwindPlan::RowSP row(new UnwindPlan::Row);
 
@@ -657,8 +745,8 @@
   row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc);
 
   // saved instruction pointer can be found at CFA - wordsize.
-  current_sp_bytes_offset_from_cfa = m_wordsize;
-  initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_cfa);
+  current_sp_bytes_offset_from_fa = m_wordsize;
+  initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
   row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc);
 
   unwind_plan.AppendRow(row);
@@ -682,6 +770,7 @@
   UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
   int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the
                                                    // epilogue started executed
+  bool prologue_completed_is_aligned;
   std::vector<bool> prologue_completed_saved_registers;
 
   while (current_func_text_offset < size) {
@@ -701,22 +790,59 @@
       break;
     }
 
-    if (push_rbp_pattern_p()) {
-      current_sp_bytes_offset_from_cfa += m_wordsize;
-      row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
-      UnwindPlan::Row::RegisterLocation regloc;
-      regloc.SetAtCFAPlusOffset(-row->GetCFAValue().GetOffset());
-      row->SetRegisterInfo(m_lldb_fp_regnum, regloc);
-      saved_registers[m_machine_fp_regnum] = true;
-      row_updated = true;
+    auto &cfa_value = row->GetCFAValue();
+    auto &afa_value = row->GetAFAValue();
+    auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value;
+
+    if (mov_rsp_rbp_pattern_p()) {
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_fp_regnum, fa_value_ptr->GetOffset());
+        row_updated = true;
+      }
     }
 
-    else if (mov_rsp_rbp_pattern_p()) {
-      row->GetCFAValue().SetIsRegisterPlusOffset(
-          m_lldb_fp_regnum, row->GetCFAValue().GetOffset());
+    else if (mov_rsp_rbx_pattern_p()) {
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset());
+        row_updated = true;
+      }
+    }
+
+    else if (and_rsp_pattern_p()) {
+      current_sp_bytes_offset_from_fa = 0;
+      afa_value.SetIsRegisterPlusOffset(
+          m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
+      fa_value_ptr = &afa_value;
+      is_aligned = true;
       row_updated = true;
     }
 
+    else if (mov_rbp_rsp_pattern_p()) {
+      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
+      {
+        is_aligned = false;
+        fa_value_ptr = &cfa_value;
+        afa_value.SetUnspecified();
+        row_updated = true;
+      }
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
+        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
+    }
+
+    else if (mov_rbx_rsp_pattern_p()) {
+      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum)
+      {
+        is_aligned = false;
+        fa_value_ptr = &cfa_value;
+        afa_value.SetUnspecified();
+        row_updated = true;
+      }
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum)
+        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
+    }
+
     // This is the start() function (or a pthread equivalent), it starts with a
     // pushl $0x0 which puts the saved pc value of 0 on the stack.  In this
     // case we want to pretend we didn't see a stack movement at all --
@@ -726,85 +852,102 @@
     }
 
     else if (push_reg_p(machine_regno)) {
-      current_sp_bytes_offset_from_cfa += m_wordsize;
-      // the PUSH instruction has moved the stack pointer - if the CFA is set
+      current_sp_bytes_offset_from_fa += m_wordsize;
+      // the PUSH instruction has moved the stack pointer - if the FA is set
       // in terms of the stack pointer, we need to add a new row of
       // instructions.
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
       // record where non-volatile (callee-saved, spilled) registers are saved
       // on the stack
       if (nonvolatile_reg_p(machine_regno) &&
           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
           saved_registers[machine_regno] == false) {
         UnwindPlan::Row::RegisterLocation regloc;
-        regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_cfa);
+        if (is_aligned)
+            regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa);
+        else
+            regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
         row->SetRegisterInfo(lldb_regno, regloc);
         saved_registers[machine_regno] = true;
         row_updated = true;
       }
     }
 
     else if (pop_reg_p(machine_regno)) {
-      current_sp_bytes_offset_from_cfa -= m_wordsize;
+      current_sp_bytes_offset_from_fa -= m_wordsize;
 
       if (nonvolatile_reg_p(machine_regno) &&
           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
           saved_registers[machine_regno] == true) {
         saved_registers[machine_regno] = false;
         row->RemoveRegisterInfo(lldb_regno);
 
-        if (machine_regno == (int)m_machine_fp_regnum) {
-          row->GetCFAValue().SetIsRegisterPlusOffset(
-              m_lldb_sp_regnum, row->GetCFAValue().GetOffset());
+        if (lldb_regno == fa_value_ptr->GetRegisterNumber()) {
+          fa_value_ptr->SetIsRegisterPlusOffset(
+              m_lldb_sp_regnum, fa_value_ptr->GetOffset());
         }
 
         in_epilogue = true;
         row_updated = true;
       }
 
-      // the POP instruction has moved the stack pointer - if the CFA is set in
+      // the POP instruction has moved the stack pointer - if the FA is set in
       // terms of the stack pointer, we need to add a new row of instructions.
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetIsRegisterPlusOffset(
-            m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa);
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
     }
 
     else if (pop_misc_reg_p()) {
-      current_sp_bytes_offset_from_cfa -= m_wordsize;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetIsRegisterPlusOffset(
-            m_lldb_sp_regnum, current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa -= m_wordsize;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
     }
 
     // The LEAVE instruction moves the value from rbp into rsp and pops a value
     // off the stack into rbp (restoring the caller's rbp value). It is the
     // opposite of ENTER, or 'push rbp, mov rsp rbp'.
     else if (leave_pattern_p()) {
-      // We're going to copy the value in rbp into rsp, so re-set the sp offset
-      // based on the CFAValue.  Also, adjust it to recognize that we're
-      // popping the saved rbp value off the stack.
-      current_sp_bytes_offset_from_cfa = row->GetCFAValue().GetOffset();
-      current_sp_bytes_offset_from_cfa -= m_wordsize;
-      row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
-
-      // rbp is restored to the caller's value
-      saved_registers[m_machine_fp_regnum] = false;
-      row->RemoveRegisterInfo(m_lldb_fp_regnum);
-
-      // cfa is now in terms of rsp again.
-      row->GetCFAValue().SetIsRegisterPlusOffset(
-          m_lldb_sp_regnum, row->GetCFAValue().GetOffset());
-      row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      if (saved_registers[m_machine_fp_regnum]) {
+        saved_registers[m_machine_fp_regnum] = false;
+        row->RemoveRegisterInfo(m_lldb_fp_regnum);
+
+        row_updated = true;
+      }
+
+      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
+      {
+        is_aligned = false;
+        fa_value_ptr = &cfa_value;
+        afa_value.SetUnspecified();
+        row_updated = true;
+      }
+
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
+      {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_sp_regnum, fa_value_ptr->GetOffset());
+
+        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
+      }
+
+      current_sp_bytes_offset_from_fa -= m_wordsize;
+
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetIsRegisterPlusOffset(
+            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
+        row_updated = true;
+      }
 
       in_epilogue = true;
-      row_updated = true;
     }
 
     else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) &&
@@ -816,58 +959,81 @@
       UnwindPlan::Row::RegisterLocation regloc;
 
       // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we
-      // want to express this as the offset from the CFA.  If the frame base is
-      // rbp (like the above instruction), the CFA offset for rbp is probably
-      // 16.  So we want to say that the value is stored at the CFA address -
+      // want to express this as the offset from the FA.  If the frame base is
+      // rbp (like the above instruction), the FA offset for rbp is probably
+      // 16.  So we want to say that the value is stored at the FA address -
       // 96.
-      regloc.SetAtCFAPlusOffset(
-          -(stack_offset + row->GetCFAValue().GetOffset()));
+      if (is_aligned)
+          regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
+      else
+          regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
 
       row->SetRegisterInfo(lldb_regno, regloc);
 
       row_updated = true;
     }
 
     else if (sub_rsp_pattern_p(stack_offset)) {
-      current_sp_bytes_offset_from_cfa += stack_offset;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa += stack_offset;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
     }
 
     else if (add_rsp_pattern_p(stack_offset)) {
-      current_sp_bytes_offset_from_cfa -= stack_offset;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa -= stack_offset;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
       in_epilogue = true;
     }
 
     else if (push_extended_pattern_p() || push_imm_pattern_p() ||
              push_misc_reg_p()) {
-      current_sp_bytes_offset_from_cfa += m_wordsize;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa += m_wordsize;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
     }
 
     else if (lea_rsp_pattern_p(stack_offset)) {
-      current_sp_bytes_offset_from_cfa -= stack_offset;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa -= stack_offset;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
       if (stack_offset > 0)
         in_epilogue = true;
     }
 
-    else if (lea_rbp_rsp_pattern_p(stack_offset) &&
-             row->GetCFAValue().GetRegisterNumber() == m_lldb_fp_regnum) {
-      current_sp_bytes_offset_from_cfa =
-          row->GetCFAValue().GetOffset() - stack_offset;
+    else if (lea_rbp_rsp_pattern_p(stack_offset)) {
+      if (is_aligned &&
+          cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) {
+        is_aligned = false;
+        fa_value_ptr = &cfa_value;
+        afa_value.SetUnspecified();
+        row_updated = true;
+      }
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {
+        current_sp_bytes_offset_from_fa =
+          fa_value_ptr->GetOffset() - stack_offset;
+      }
+    }
+
+    else if (lea_rbx_rsp_pattern_p(stack_offset)) {
+      if (is_aligned &&
+          cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) {
+        is_aligned = false;
+        fa_value_ptr = &cfa_value;
+        afa_value.SetUnspecified();
+        row_updated = true;
+      }
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {
+        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;
+      }
     }
 
     else if (ret_pattern_p() && prologue_completed_row.get()) {
@@ -877,8 +1043,9 @@
       UnwindPlan::Row *newrow = new UnwindPlan::Row;
       *newrow = *prologue_completed_row.get();
       row.reset(newrow);
-      current_sp_bytes_offset_from_cfa =
+      current_sp_bytes_offset_from_fa =
           prologue_completed_sp_bytes_offset_from_cfa;
+      is_aligned = prologue_completed_is_aligned;
 
       saved_registers.clear();
       saved_registers.resize(prologue_completed_saved_registers.size(), false);
@@ -896,9 +1063,9 @@
     // This is used in i386 programs to get the PIC base address for finding
     // global data
     else if (call_next_insn_pattern_p()) {
-      current_sp_bytes_offset_from_cfa += m_wordsize;
-      if (row->GetCFAValue().GetRegisterNumber() == m_lldb_sp_regnum) {
-        row->GetCFAValue().SetOffset(current_sp_bytes_offset_from_cfa);
+      current_sp_bytes_offset_from_fa += m_wordsize;
+      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
+        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
         row_updated = true;
       }
     }
@@ -931,7 +1098,8 @@
     // track of it either way.
     if (in_epilogue == false) {
       prologue_completed_sp_bytes_offset_from_cfa =
-          current_sp_bytes_offset_from_cfa;
+          current_sp_bytes_offset_from_fa;
+      prologue_completed_is_aligned = is_aligned;
     }
 
     m_cur_insn = m_cur_insn + insn_len;
Index: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
===================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -92,7 +92,7 @@
   // assembly parsing instead.
 
   if (first_row->GetCFAValue().GetValueType() !=
-          UnwindPlan::Row::CFAValue::isRegisterPlusOffset ||
+          UnwindPlan::Row::FAValue::isRegisterPlusOffset ||
       RegisterNumber(thread, unwind_plan.GetRegisterKind(),
                      first_row->GetCFAValue().GetRegisterNumber()) !=
           sp_regnum ||
Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -54,7 +54,8 @@
     : RegisterContext(thread, frame_number), m_thread(thread),
       m_fast_unwind_plan_sp(), m_full_unwind_plan_sp(),
       m_fallback_unwind_plan_sp(), m_all_registers_available(false),
-      m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS), m_start_pc(),
+      m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS),
+      m_afa(LLDB_INVALID_ADDRESS), m_start_pc(),
       m_current_pc(), m_current_offset(0), m_current_offset_backed_up_one(0),
       m_sym_ctx(sym_ctx), m_sym_ctx_valid(false), m_frame_number(frame_number),
       m_registers(), m_parent_unwind(unwind_lldb) {
@@ -228,7 +229,7 @@
     return;
   }
 
-  if (!ReadCFAValueForRow(row_register_kind, active_row, m_cfa)) {
+  if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
     // Try the fall back unwind plan since the
     // full unwind plan failed.
     FuncUnwindersSP func_unwinders_sp;
@@ -256,12 +257,14 @@
       m_frame_type = eNotAValidFrame;
       return;
     }
-  }
+  } else
+    ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
 
   UnwindLogMsg("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64
-               " using %s UnwindPlan",
+               " afa is 0x%" PRIx64 " using %s UnwindPlan",
                (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
                (uint64_t)m_cfa,
+               (uint64_t)m_afa,
                m_full_unwind_plan_sp->GetSourceName().GetCString());
 }
 
@@ -379,15 +382,17 @@
       RegisterKind row_register_kind = m_full_unwind_plan_sp->GetRegisterKind();
       UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
       if (row.get()) {
-        if (!ReadCFAValueForRow(row_register_kind, row, m_cfa)) {
+        if (!ReadFrameAddress(row_register_kind, row->GetCFAValue(), m_cfa)) {
           UnwindLogMsg("failed to get cfa value");
           if (m_frame_type != eSkipFrame) // don't override eSkipFrame
           {
             m_frame_type = eNotAValidFrame;
           }
           return;
         }
 
+        ReadFrameAddress(row_register_kind, row->GetAFAValue(), m_afa);
+
         // A couple of sanity checks..
         if (m_cfa == LLDB_INVALID_ADDRESS || m_cfa == 0 || m_cfa == 1) {
           UnwindLogMsg("could not find a valid cfa address");
@@ -420,7 +425,8 @@
         }
       }
 
-      UnwindLogMsg("initialized frame cfa is 0x%" PRIx64, (uint64_t)m_cfa);
+      UnwindLogMsg("initialized frame cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
+                   (uint64_t)m_cfa, (uint64_t)m_afa);
       return;
     }
     m_frame_type = eNotAValidFrame;
@@ -584,13 +590,15 @@
     return;
   }
 
-  if (!ReadCFAValueForRow(row_register_kind, active_row, m_cfa)) {
+  if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), m_cfa)) {
     UnwindLogMsg("failed to get cfa");
     m_frame_type = eNotAValidFrame;
     return;
   }
 
-  UnwindLogMsg("m_cfa = 0x%" PRIx64, m_cfa);
+  ReadFrameAddress(row_register_kind, active_row->GetAFAValue(), m_afa);
+
+  UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa);
 
   if (CheckIfLoopingStack()) {
     TryFallbackUnwindPlan();
@@ -603,9 +611,10 @@
   }
 
   UnwindLogMsg("initialized frame current pc is 0x%" PRIx64
-               " cfa is 0x%" PRIx64,
+               " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64,
                (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()),
-               (uint64_t)m_cfa);
+               (uint64_t)m_cfa,
+               (uint64_t)m_afa);
 }
 
 bool RegisterContextLLDB::CheckIfLoopingStack() {
@@ -1314,8 +1323,8 @@
                     unwindplan_regloc)) {
               can_fetch_pc_value = true;
             }
-            if (ReadCFAValueForRow(unwindplan_registerkind, active_row,
-                                   cfa_value)) {
+            if (ReadFrameAddress(unwindplan_registerkind,
+                                 active_row->GetCFAValue(), cfa_value)) {
               can_fetch_cfa = true;
             }
           }
@@ -1444,6 +1453,36 @@
     return UnwindLLDB::RegisterSearchResult::eRegisterFound;
   }
 
+  if (unwindplan_regloc.IsAFAPlusOffset()) {
+    if (m_afa == LLDB_INVALID_ADDRESS)
+        return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+    int offset = unwindplan_regloc.GetOffset();
+    regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+    regloc.location.inferred_value = m_afa + offset;
+    m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+    UnwindLogMsg("supplying caller's register %s (%d), value is AFA plus "
+                 "offset %d [value is 0x%" PRIx64 "]",
+                 regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+                 regloc.location.inferred_value);
+    return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+  }
+
+  if (unwindplan_regloc.IsAtAFAPlusOffset()) {
+    if (m_afa == LLDB_INVALID_ADDRESS)
+        return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+
+    int offset = unwindplan_regloc.GetOffset();
+    regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+    regloc.location.target_memory_location = m_afa + offset;
+    m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = regloc;
+    UnwindLogMsg("supplying caller's register %s (%d) from the stack, saved at "
+                 "AFA plus offset %d [saved at 0x%" PRIx64 "]",
+                 regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB), offset,
+                 regloc.location.target_memory_location);
+    return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+  }
+
   if (unwindplan_regloc.IsInOtherRegister()) {
     uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
     RegisterNumber row_regnum(m_thread, unwindplan_registerkind,
@@ -1558,7 +1597,6 @@
 
   addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS;
   addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS;
-  addr_t old_this_frame_cfa_value = m_cfa;
   UnwindLLDB::RegisterLocation regloc;
   if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
                                regloc) ==
@@ -1588,6 +1626,7 @@
   // the value of the m_cfa ivar.  Save is down below a bit in 'old_cfa'.
   UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
   addr_t old_cfa = m_cfa;
+  addr_t old_afa = m_afa;
 
   m_registers.clear();
 
@@ -1598,19 +1637,21 @@
 
   if (active_row &&
       active_row->GetCFAValue().GetValueType() !=
-          UnwindPlan::Row::CFAValue::unspecified) {
+          UnwindPlan::Row::FAValue::unspecified) {
     addr_t new_cfa;
-    if (!ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(),
-                            active_row, new_cfa) ||
+    if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+                            active_row->GetCFAValue(), new_cfa) ||
         new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
       UnwindLogMsg("failed to get cfa with fallback unwindplan");
       m_fallback_unwind_plan_sp.reset();
       m_full_unwind_plan_sp = original_full_unwind_plan_sp;
-      m_cfa = old_cfa;
       return false;
     }
     m_cfa = new_cfa;
 
+    ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+                     active_row->GetAFAValue(), m_afa);
+
     if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB),
                                  regloc) ==
         UnwindLLDB::RegisterSearchResult::eRegisterFound) {
@@ -1631,19 +1672,18 @@
       m_fallback_unwind_plan_sp.reset();
       m_full_unwind_plan_sp = original_full_unwind_plan_sp;
       m_cfa = old_cfa;
+      m_afa = old_afa;
       return false;
     }
 
-    if (old_caller_pc_value != LLDB_INVALID_ADDRESS) {
-      if (old_caller_pc_value == new_caller_pc_value &&
-          new_cfa == old_this_frame_cfa_value) {
-        UnwindLogMsg("fallback unwind plan got the same values for this frame "
-                     "CFA and caller frame pc, not using");
-        m_fallback_unwind_plan_sp.reset();
-        m_full_unwind_plan_sp = original_full_unwind_plan_sp;
-        m_cfa = old_cfa;
-        return false;
-      }
+    if (old_caller_pc_value == new_caller_pc_value &&
+        m_cfa == old_cfa &&
+        m_afa == old_afa) {
+      UnwindLogMsg("fallback unwind plan got the same values for this frame "
+                   "CFA and caller frame pc, not using");
+      m_fallback_unwind_plan_sp.reset();
+      m_full_unwind_plan_sp = original_full_unwind_plan_sp;
+      return false;
     }
 
     UnwindLogMsg("trying to unwind from this function with the UnwindPlan '%s' "
@@ -1677,16 +1717,19 @@
 
   if (active_row &&
       active_row->GetCFAValue().GetValueType() !=
-          UnwindPlan::Row::CFAValue::unspecified) {
+          UnwindPlan::Row::FAValue::unspecified) {
     addr_t new_cfa;
-    if (!ReadCFAValueForRow(m_fallback_unwind_plan_sp->GetRegisterKind(),
-                            active_row, new_cfa) ||
+    if (!ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+                            active_row->GetCFAValue(), new_cfa) ||
         new_cfa == 0 || new_cfa == 1 || new_cfa == LLDB_INVALID_ADDRESS) {
       UnwindLogMsg("failed to get cfa with fallback unwindplan");
       m_fallback_unwind_plan_sp.reset();
       return false;
     }
 
+    ReadFrameAddress(m_fallback_unwind_plan_sp->GetRegisterKind(),
+                     active_row->GetAFAValue(), m_afa);
+
     m_full_unwind_plan_sp = m_fallback_unwind_plan_sp;
     m_fallback_unwind_plan_sp.reset();
 
@@ -1701,32 +1744,32 @@
   return false;
 }
 
-bool RegisterContextLLDB::ReadCFAValueForRow(
-    lldb::RegisterKind row_register_kind, const UnwindPlan::RowSP &row,
-    addr_t &cfa_value) {
+bool RegisterContextLLDB::ReadFrameAddress(
+    lldb::RegisterKind row_register_kind, UnwindPlan::Row::FAValue &fa,
+    addr_t &address) {
   RegisterValue reg_value;
 
-  cfa_value = LLDB_INVALID_ADDRESS;
+  address = LLDB_INVALID_ADDRESS;
   addr_t cfa_reg_contents;
 
-  switch (row->GetCFAValue().GetValueType()) {
-  case UnwindPlan::Row::CFAValue::isRegisterDereferenced: {
+  switch (fa.GetValueType()) {
+  case UnwindPlan::Row::FAValue::isRegisterDereferenced: {
     RegisterNumber cfa_reg(m_thread, row_register_kind,
-                           row->GetCFAValue().GetRegisterNumber());
+                           fa.GetRegisterNumber());
     if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
       const RegisterInfo *reg_info =
           GetRegisterInfoAtIndex(cfa_reg.GetAsKind(eRegisterKindLLDB));
       RegisterValue reg_value;
       if (reg_info) {
         Status error = ReadRegisterValueFromMemory(
             reg_info, cfa_reg_contents, reg_info->byte_size, reg_value);
         if (error.Success()) {
-          cfa_value = reg_value.GetAsUInt64();
+          address = reg_value.GetAsUInt64();
           UnwindLogMsg(
               "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64
               ", CFA value is 0x%" PRIx64,
               cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
-              cfa_reg_contents, cfa_value);
+              cfa_reg_contents, address);
           return true;
         } else {
           UnwindLogMsg("Tried to deref reg %s (%d) [0x%" PRIx64
@@ -1738,9 +1781,9 @@
     }
     break;
   }
-  case UnwindPlan::Row::CFAValue::isRegisterPlusOffset: {
+  case UnwindPlan::Row::FAValue::isRegisterPlusOffset: {
     RegisterNumber cfa_reg(m_thread, row_register_kind,
-                           row->GetCFAValue().GetRegisterNumber());
+                           fa.GetRegisterNumber());
     if (ReadGPRValue(cfa_reg, cfa_reg_contents)) {
       if (cfa_reg_contents == LLDB_INVALID_ADDRESS || cfa_reg_contents == 0 ||
           cfa_reg_contents == 1) {
@@ -1751,35 +1794,35 @@
         cfa_reg_contents = LLDB_INVALID_ADDRESS;
         return false;
       }
-      cfa_value = cfa_reg_contents + row->GetCFAValue().GetOffset();
+      address = cfa_reg_contents + fa.GetOffset();
       UnwindLogMsg(
           "CFA is 0x%" PRIx64 ": Register %s (%d) contents are 0x%" PRIx64
           ", offset is %d",
-          cfa_value, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
-          cfa_reg_contents, row->GetCFAValue().GetOffset());
+          address, cfa_reg.GetName(), cfa_reg.GetAsKind(eRegisterKindLLDB),
+          cfa_reg_contents, fa.GetOffset());
       return true;
     }
     break;
   }
-  case UnwindPlan::Row::CFAValue::isDWARFExpression: {
+  case UnwindPlan::Row::FAValue::isDWARFExpression: {
     ExecutionContext exe_ctx(m_thread.shared_from_this());
     Process *process = exe_ctx.GetProcessPtr();
-    DataExtractor dwarfdata(row->GetCFAValue().GetDWARFExpressionBytes(),
-                            row->GetCFAValue().GetDWARFExpressionLength(),
+    DataExtractor dwarfdata(fa.GetDWARFExpressionBytes(),
+                            fa.GetDWARFExpressionLength(),
                             process->GetByteOrder(),
                             process->GetAddressByteSize());
     ModuleSP opcode_ctx;
     DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr, 0,
-                              row->GetCFAValue().GetDWARFExpressionLength());
+                              fa.GetDWARFExpressionLength());
     dwarfexpr.SetRegisterKind(row_register_kind);
     Value result;
     Status error;
     if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result,
                            &error)) {
-      cfa_value = result.GetScalar().ULongLong();
+      address = result.GetScalar().ULongLong();
 
       UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64,
-                   cfa_value);
+                   address);
       return true;
     }
     UnwindLogMsg("Failed to set CFA value via DWARF expression: %s",
Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
===================================================================
--- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -192,9 +192,9 @@
 
   bool ReadGPRValue(const RegisterNumber &reg_num, lldb::addr_t &value);
 
-  // Get the CFA register for a given frame.
-  bool ReadCFAValueForRow(lldb::RegisterKind register_kind,
-                          const UnwindPlan::RowSP &row, lldb::addr_t &value);
+  // Get the Frame Address register for a given frame.
+  bool ReadFrameAddress(lldb::RegisterKind register_kind,
+                          UnwindPlan::Row::FAValue &fa, lldb::addr_t &address);
 
   lldb::UnwindPlanSP GetFastUnwindPlanForFrame();
 
@@ -225,6 +225,7 @@
   int m_frame_type;               // enum FrameType
 
   lldb::addr_t m_cfa;
+  lldb::addr_t m_afa;
   lldb_private::Address m_start_pc;
   lldb_private::Address m_current_pc;
 
Index: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
===================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h
@@ -28,14 +28,22 @@
 // The UnwindPlan object specifies how to unwind out of a function - where this
 // function saves the caller's register values before modifying them (for non-
 // volatile aka saved registers) and how to find this frame's Canonical Frame
-// Address (CFA).
+// Address (CFA) or Aligned Frame Address (AFA).
 
+// CFA is a DWARF's Canonical Frame Address.
 // Most commonly, registers are saved on the stack, offset some bytes from the
 // Canonical Frame Address, or CFA, which is the starting address of this
 // function's stack frame (the CFA is same as the eh_frame's CFA, whatever that
 // may be on a given architecture). The CFA address for the stack frame does
 // not change during the lifetime of the function.
 
+// AFA is an artificially introduced Aligned Frame Address.
+// It is used only for stack frames with realignment (e.g. when some of the
+// locals has an alignment requirement higher than the stack alignment right
+// after the function call). It is used to access register values saved on the
+// stack after the realignment (and so they are inaccessible through the CFA).
+// AFA usually equals the stack pointer value right after the realignment.
+
 // Internally, the UnwindPlan is structured as a vector of register locations
 // organized by code address in the function, showing which registers have been
 // saved at that point and where they are saved. It can be thought of as the
@@ -61,6 +69,8 @@
         same,              // reg is unchanged
         atCFAPlusOffset,   // reg = deref(CFA + offset)
         isCFAPlusOffset,   // reg = CFA + offset
+        atAFAPlusOffset,   // reg = deref(AFA + offset)
+        isAFAPlusOffset,   // reg = AFA + offset
         inOtherRegister,   // reg = other reg
         atDWARFExpression, // reg = deref(eval(dwarf_expr))
         isDWARFExpression  // reg = eval(dwarf_expr)
@@ -90,6 +100,10 @@
 
       bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
 
+      bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
+
+      bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
+
       bool IsInOtherRegister() const { return m_type == inOtherRegister; }
 
       bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
@@ -106,6 +120,16 @@
         m_location.offset = offset;
       }
 
+      void SetAtAFAPlusOffset(int32_t offset) {
+        m_type = atAFAPlusOffset;
+        m_location.offset = offset;
+      }
+
+      void SetIsAFAPlusOffset(int32_t offset) {
+        m_type = isAFAPlusOffset;
+        m_location.offset = offset;
+      }
+
       void SetInRegister(uint32_t reg_num) {
         m_type = inOtherRegister;
         m_location.reg_num = reg_num;
@@ -120,9 +144,16 @@
       RestoreType GetLocationType() const { return m_type; }
 
       int32_t GetOffset() const {
-        if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
+        switch(m_type)
+        {
+        case atCFAPlusOffset:
+        case isCFAPlusOffset:
+        case atAFAPlusOffset:
+        case isAFAPlusOffset:
           return m_location.offset;
-        return 0;
+        default:
+          return 0;
+        }
       }
 
       void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
@@ -169,20 +200,20 @@
       } m_location;
     };
 
-    class CFAValue {
+    class FAValue {
     public:
       enum ValueType {
         unspecified,            // not specified
-        isRegisterPlusOffset,   // CFA = register + offset
-        isRegisterDereferenced, // CFA = [reg]
-        isDWARFExpression       // CFA = eval(dwarf_expr)
+        isRegisterPlusOffset,   // FA = register + offset
+        isRegisterDereferenced, // FA = [reg]
+        isDWARFExpression       // FA = eval(dwarf_expr)
       };
 
-      CFAValue() : m_type(unspecified), m_value() {}
+      FAValue() : m_type(unspecified), m_value() {}
 
-      bool operator==(const CFAValue &rhs) const;
+      bool operator==(const FAValue &rhs) const;
 
-      bool operator!=(const CFAValue &rhs) const { return !(*this == rhs); }
+      bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
 
       void SetUnspecified() { m_type = unspecified; }
 
@@ -279,7 +310,7 @@
           uint16_t length;
         } expr;
       } m_value;
-    }; // class CFAValue
+    }; // class FAValue
 
   public:
     Row();
@@ -302,7 +333,9 @@
 
     void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
 
-    CFAValue &GetCFAValue() { return m_cfa_value; }
+    FAValue &GetCFAValue() { return m_cfa_value; }
+
+    FAValue &GetAFAValue() { return m_afa_value; }
 
     bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
                                               bool can_replace);
@@ -329,7 +362,8 @@
     typedef std::map<uint32_t, RegisterLocation> collection;
     lldb::addr_t m_offset; // Offset into the function for this row
 
-    CFAValue m_cfa_value;
+    FAValue m_cfa_value;
+    FAValue m_afa_value;
     collection m_register_locations;
   }; // class Row
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to