Add support for some extended push instructions in i386/x86_64 like
'push 0x20(%esp)' which clang can generate when emitting
-fomit-frame-pointer code for 32-bit.

Add a unit test program which includes this instruction.

Also fix a bug in the refactoring/rewrite of the x86 assembly
instruction profiler where I'd hard coded it as a 64-bit disassembler
instead of using the ArchSpec to pick a 32-bit or 64-bit disassembler
from llvm.  When the disassembler would hit an instruction
that is invalid in 64-bit mode, it would stop disassembling the function.
This likely led to the TestSBData testsuite failure on linux with 32-bit
i386 and gcc-4.9; I'll test that in a bit.

The newly added unit test program is 32-bit i386 code and it includes
an instruction which is invalid in 64-bit mode so it will catch this.

<rdar://problem/28557876> 

llvm-svn: 282991
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 1384cf1..9131aca 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -29,10 +29,9 @@
 
       m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1),
       m_register_map_initialized(false), m_disasm_context() {
-  m_disasm_context = ::LLVMCreateDisasm("x86_64-apple-macosx", nullptr,
-                                        /*TagType=*/1, nullptr, nullptr);
-  //      ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,
-  //                         /*TagType=*/1, nullptr, nullptr);
+  m_disasm_context =
+      ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,
+                         /*TagType=*/1, nullptr, nullptr);
 }
 
 x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() {
@@ -320,6 +319,50 @@
   return false;
 }
 
+// pushl imm8(%esp)
+//
+// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)'
+// (same byte pattern for 'pushq 0x20(%rsp)' in an x86_64 program)
+//
+// 0xff (with opcode bits '6' in next byte, PUSH r/m32)
+// 0x74 (ModR/M byte with three bits used to specify the opcode)
+//      mod == b01, opcode == b110, R/M == b100
+//      "+disp8"
+// 0x24 (SIB byte - scaled index = 0, r32 == esp)
+// 0x20 imm8 value
+
+bool x86AssemblyInspectionEngine::push_extended_pattern_p() {
+  if (*m_cur_insn == 0xff) {
+    // Get the 3 opcode bits from the ModR/M byte
+    uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7;
+    if (opcode == 6) {
+      // I'm only looking for 0xff /6 here - I
+      // don't really care what value is being pushed,
+      // just that we're pushing a 32/64 bit value on
+      // to the stack is enough.
+      return true;
+    }
+  }
+  return false;
+}
+
+// pushq %rbx
+// pushl %ebx
+bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {
+  uint8_t *p = m_cur_insn;
+  int regno_prefix_bit = 0;
+  // If we have a rex prefix byte, check to see if a B bit is set
+  if (m_wordsize == 8 && *p == 0x41) {
+    regno_prefix_bit = 1 << 3;
+    p++;
+  }
+  if (*p >= 0x50 && *p <= 0x57) {
+    regno = (*p - 0x50) | regno_prefix_bit;
+    return true;
+  }
+  return false;
+}
+
 // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
 // movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
 bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {
@@ -395,23 +438,6 @@
   return false;
 }
 
-// pushq %rbx
-// pushl %ebx
-bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {
-  uint8_t *p = m_cur_insn;
-  int regno_prefix_bit = 0;
-  // If we have a rex prefix byte, check to see if a B bit is set
-  if (m_wordsize == 8 && *p == 0x41) {
-    regno_prefix_bit = 1 << 3;
-    p++;
-  }
-  if (*p >= 0x50 && *p <= 0x57) {
-    regno = (*p - 0x50) | regno_prefix_bit;
-    return true;
-  }
-  return false;
-}
-
 // popq %rbx
 // popl %ebx
 bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
@@ -762,6 +788,14 @@
       in_epilogue = true;
     }
 
+    else if (push_extended_pattern_p() || push_imm_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);
+        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) {
@@ -1002,6 +1036,16 @@
         continue;
       }
 
+      // push extended
+      if (push_extended_pattern_p()) {
+        row->SetOffset(offset);
+        row->GetCFAValue().IncOffset(m_wordsize);
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+        unwind_plan.InsertRow(new_row);
+        unwind_plan_updated = true;
+        continue;
+      }
+
       // add/sub %rsp/%esp
       int amount;
       if (add_rsp_pattern_p(amount)) {
@@ -1045,16 +1089,16 @@
       //     [0x5d] pop %rbp/%ebp
       //  => [0xc3] ret
       if (pop_rbp_pattern_p() || leave_pattern_p()) {
-          offset += 1;
-          row->SetOffset(offset);
-          row->GetCFAValue().SetIsRegisterPlusOffset(
-              first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
+        offset += 1;
+        row->SetOffset(offset);
+        row->GetCFAValue().SetIsRegisterPlusOffset(
+            first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
 
-          UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
-          unwind_plan.InsertRow(new_row);
-          unwind_plan_updated = true;
-          reinstate_unwind_state = true;
-          continue;
+        UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
+        unwind_plan.InsertRow(new_row);
+        unwind_plan_updated = true;
+        reinstate_unwind_state = true;
+        continue;
       }
     } else {
       // CFA register is not sp or fp.