Skip to content

Commit 4538ed3

Browse files
author
Aleksandr Urakov
committedOct 30, 2018
[x86] Fix issues with a realigned stack in MSVC compiled applications
Summary: This patch fixes issues with a stack realignment. MSVC maintains two frame pointers (`ebx` and `ebp`) for a realigned stack - one is used for access to function parameters, while another is used for access to locals. To support this the patch: - adds an alternative frame pointer (`ebx`); - considers stack realignment instructions (e.g. `and esp, -32`); - along with CFA (Canonical Frame Address) which point to the position next to the saved return address (or to the first parameter on the stack) introduces AFA (Aligned Frame Address) which points to the position of the stack pointer right after realignment. AFA is used for access to registers saved after the realignment (see the test); Here is an example of the code with the realignment: ``` struct __declspec(align(256)) OverAligned { char c; }; void foo(int foo_arg) { OverAligned oa_foo = { 1 }; auto aaa_foo = 1234; } void bar(int bar_arg) { OverAligned oa_bar = { 2 }; auto aaa_bar = 5678; foo(1111); } int main() { bar(2222); return 0; } ``` and here is the `bar` disassembly: ``` push ebx mov ebx, esp sub esp, 8 and esp, -100h add esp, 4 push ebp mov ebp, [ebx+4] mov [esp+4], ebp mov ebp, esp sub esp, 200h mov byte ptr [ebp-200h], 2 mov dword ptr [ebp-4], 5678 push 1111 ; foo_arg call j_?foo@@Yaxh@Z ; foo(int) add esp, 4 mov esp, ebp pop ebp mov esp, ebx pop ebx retn ``` Reviewers: labath, zturner, jasonmolenda, stella.stamenova Reviewed By: jasonmolenda Subscribers: abidh, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D53435 llvm-svn: 345577
1 parent d62afe0 commit 4538ed3

File tree

8 files changed

+484
-150
lines changed

8 files changed

+484
-150
lines changed
 

‎lldb/include/lldb/Symbol/UnwindPlan.h

+47-13
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,22 @@ namespace lldb_private {
2828
// The UnwindPlan object specifies how to unwind out of a function - where this
2929
// function saves the caller's register values before modifying them (for non-
3030
// volatile aka saved registers) and how to find this frame's Canonical Frame
31-
// Address (CFA).
31+
// Address (CFA) or Aligned Frame Address (AFA).
3232

33+
// CFA is a DWARF's Canonical Frame Address.
3334
// Most commonly, registers are saved on the stack, offset some bytes from the
3435
// Canonical Frame Address, or CFA, which is the starting address of this
3536
// function's stack frame (the CFA is same as the eh_frame's CFA, whatever that
3637
// may be on a given architecture). The CFA address for the stack frame does
3738
// not change during the lifetime of the function.
3839

40+
// AFA is an artificially introduced Aligned Frame Address.
41+
// It is used only for stack frames with realignment (e.g. when some of the
42+
// locals has an alignment requirement higher than the stack alignment right
43+
// after the function call). It is used to access register values saved on the
44+
// stack after the realignment (and so they are inaccessible through the CFA).
45+
// AFA usually equals the stack pointer value right after the realignment.
46+
3947
// Internally, the UnwindPlan is structured as a vector of register locations
4048
// organized by code address in the function, showing which registers have been
4149
// saved at that point and where they are saved. It can be thought of as the
@@ -61,6 +69,8 @@ class UnwindPlan {
6169
same, // reg is unchanged
6270
atCFAPlusOffset, // reg = deref(CFA + offset)
6371
isCFAPlusOffset, // reg = CFA + offset
72+
atAFAPlusOffset, // reg = deref(AFA + offset)
73+
isAFAPlusOffset, // reg = AFA + offset
6474
inOtherRegister, // reg = other reg
6575
atDWARFExpression, // reg = deref(eval(dwarf_expr))
6676
isDWARFExpression // reg = eval(dwarf_expr)
@@ -90,6 +100,10 @@ class UnwindPlan {
90100

91101
bool IsAtCFAPlusOffset() const { return m_type == atCFAPlusOffset; }
92102

103+
bool IsAFAPlusOffset() const { return m_type == isAFAPlusOffset; }
104+
105+
bool IsAtAFAPlusOffset() const { return m_type == atAFAPlusOffset; }
106+
93107
bool IsInOtherRegister() const { return m_type == inOtherRegister; }
94108

95109
bool IsAtDWARFExpression() const { return m_type == atDWARFExpression; }
@@ -106,6 +120,16 @@ class UnwindPlan {
106120
m_location.offset = offset;
107121
}
108122

123+
void SetAtAFAPlusOffset(int32_t offset) {
124+
m_type = atAFAPlusOffset;
125+
m_location.offset = offset;
126+
}
127+
128+
void SetIsAFAPlusOffset(int32_t offset) {
129+
m_type = isAFAPlusOffset;
130+
m_location.offset = offset;
131+
}
132+
109133
void SetInRegister(uint32_t reg_num) {
110134
m_type = inOtherRegister;
111135
m_location.reg_num = reg_num;
@@ -120,9 +144,16 @@ class UnwindPlan {
120144
RestoreType GetLocationType() const { return m_type; }
121145

122146
int32_t GetOffset() const {
123-
if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
147+
switch(m_type)
148+
{
149+
case atCFAPlusOffset:
150+
case isCFAPlusOffset:
151+
case atAFAPlusOffset:
152+
case isAFAPlusOffset:
124153
return m_location.offset;
125-
return 0;
154+
default:
155+
return 0;
156+
}
126157
}
127158

128159
void GetDWARFExpr(const uint8_t **opcodes, uint16_t &len) const {
@@ -169,20 +200,20 @@ class UnwindPlan {
169200
} m_location;
170201
};
171202

172-
class CFAValue {
203+
class FAValue {
173204
public:
174205
enum ValueType {
175206
unspecified, // not specified
176-
isRegisterPlusOffset, // CFA = register + offset
177-
isRegisterDereferenced, // CFA = [reg]
178-
isDWARFExpression // CFA = eval(dwarf_expr)
207+
isRegisterPlusOffset, // FA = register + offset
208+
isRegisterDereferenced, // FA = [reg]
209+
isDWARFExpression // FA = eval(dwarf_expr)
179210
};
180211

181-
CFAValue() : m_type(unspecified), m_value() {}
212+
FAValue() : m_type(unspecified), m_value() {}
182213

183-
bool operator==(const CFAValue &rhs) const;
214+
bool operator==(const FAValue &rhs) const;
184215

185-
bool operator!=(const CFAValue &rhs) const { return !(*this == rhs); }
216+
bool operator!=(const FAValue &rhs) const { return !(*this == rhs); }
186217

187218
void SetUnspecified() { m_type = unspecified; }
188219

@@ -279,7 +310,7 @@ class UnwindPlan {
279310
uint16_t length;
280311
} expr;
281312
} m_value;
282-
}; // class CFAValue
313+
}; // class FAValue
283314

284315
public:
285316
Row();
@@ -302,7 +333,9 @@ class UnwindPlan {
302333

303334
void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
304335

305-
CFAValue &GetCFAValue() { return m_cfa_value; }
336+
FAValue &GetCFAValue() { return m_cfa_value; }
337+
338+
FAValue &GetAFAValue() { return m_afa_value; }
306339

307340
bool SetRegisterLocationToAtCFAPlusOffset(uint32_t reg_num, int32_t offset,
308341
bool can_replace);
@@ -329,7 +362,8 @@ class UnwindPlan {
329362
typedef std::map<uint32_t, RegisterLocation> collection;
330363
lldb::addr_t m_offset; // Offset into the function for this row
331364

332-
CFAValue m_cfa_value;
365+
FAValue m_cfa_value;
366+
FAValue m_afa_value;
333367
collection m_register_locations;
334368
}; // class Row
335369

0 commit comments

Comments
 (0)
Please sign in to comment.