summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Symbol/UnwindPlan.h60
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp143
-rw-r--r--lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h7
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp2
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp314
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h7
-rw-r--r--lldb/source/Symbol/UnwindPlan.cpp36
-rw-r--r--lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp65
8 files changed, 484 insertions, 150 deletions
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index a76ea23b46b..f5c32faca80 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -28,14 +28,22 @@ namespace lldb_private {
// 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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
} 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 @@ public:
uint16_t length;
} expr;
} m_value;
- }; // class CFAValue
+ }; // class FAValue
public:
Row();
@@ -302,7 +333,9 @@ public:
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 @@ public:
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
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
index e943c3dc1c9..3a1f2fb37b7 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -54,7 +54,8 @@ RegisterContextLLDB::RegisterContextLLDB(Thread &thread,
: 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 @@ void RegisterContextLLDB::InitializeZerothFrame() {
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 @@ void RegisterContextLLDB::InitializeZerothFrame() {
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,7 +382,7 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
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
{
@@ -388,6 +391,8 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
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 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
}
}
- 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 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
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 @@ void RegisterContextLLDB::InitializeNonZerothFrame() {
}
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 @@ RegisterContextLLDB::SavedLocationForRegister(
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 @@ RegisterContextLLDB::SavedLocationForRegister(
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 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() {
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 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() {
// 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 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() {
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 @@ bool RegisterContextLLDB::TryFallbackUnwindPlan() {
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 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
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,18 +1744,18 @@ bool RegisterContextLLDB::ForceSwitchToFallbackUnwindPlan() {
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));
@@ -1721,12 +1764,12 @@ bool RegisterContextLLDB::ReadCFAValueForRow(
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 @@ bool RegisterContextLLDB::ReadCFAValueForRow(
}
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 @@ bool RegisterContextLLDB::ReadCFAValueForRow(
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",
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
index 7e9e77dcf06..d436bc1890c 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -192,9 +192,9 @@ private:
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 @@ private:
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;
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index 327d0b0e4f7..9295a095353 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -92,7 +92,7 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite(
// 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 ||
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 10a56980594..eb1989895af 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -59,6 +59,7 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {
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 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {
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 @@ void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {
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 @@ void x86AssemblyInspectionEngine::Initialize(
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 @@ void x86AssemblyInspectionEngine::Initialize(
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 @@ void x86AssemblyInspectionEngine::Initialize(
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 @@ bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {
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 @@ bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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,12 +852,12 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
}
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
@@ -740,7 +866,10 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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;
@@ -748,7 +877,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
}
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) &&
@@ -756,29 +885,29 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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;
}
}
@@ -787,24 +916,38 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
// 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,12 +959,14 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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);
@@ -829,17 +974,17 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
}
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;
@@ -847,27 +992,48 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
// 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 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
// 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;
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
index cec9803c8a4..e02b510ba1f 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.h
@@ -98,10 +98,15 @@ private:
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 @@ private:
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;
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
index 23ca1324ab0..0f8d9bf7e5a 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source/Symbol/UnwindPlan.cpp
@@ -29,6 +29,8 @@ operator==(const UnwindPlan::Row::RegisterLocation &rhs) const {
case atCFAPlusOffset:
case isCFAPlusOffset:
+ case atAFAPlusOffset:
+ case isAFAPlusOffset:
return m_location.offset == rhs.m_location.offset;
case inOtherRegister:
@@ -95,6 +97,16 @@ void UnwindPlan::Row::RegisterLocation::Dump(Stream &s,
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 @@ static void DumpRegisterName(Stream &s, const UnwindPlan *unwind_plan,
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 @@ operator==(const UnwindPlan::Row::CFAValue &rhs) const {
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::CFAValue::Dump(Stream &s, const UnwindPlan *unwind_plan,
void UnwindPlan::Row::Clear() {
m_cfa_value.SetUnspecified();
+ m_afa_value.SetUnspecified();
m_offset = 0;
m_register_locations.clear();
}
@@ -183,6 +196,12 @@ void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
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 @@ void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan,
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::SetRegisterLocationToSame(uint32_t reg_num,
}
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 @@ bool UnwindPlan::PlanValidAtAddress(Address addr) {
// 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;
diff --git a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
index f0c9cefeb7b..735738aee0e 100644
--- a/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
+++ b/lldb/unittests/UnwindAssembly/x86/Testx86AssemblyInspectionEngine.cpp
@@ -133,7 +133,7 @@ std::unique_ptr<x86AssemblyInspectionEngine> Geti386Inspector() {
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 @@ TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign8BitDisp_i386) {
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 @@ TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
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 @@ TEST_F(Testx86AssemblyInspectionEngine, TestStackRealign32BitDisp_x86_64) {
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) {
OpenPOWER on IntegriCloud