Skip to content

Commit e81f80e

Browse files
committed
Fix stack walking in fixupWork() for aarch64
1 parent ec9b964 commit e81f80e

2 files changed

Lines changed: 54 additions & 27 deletions

File tree

hphp/runtime/vm/jit/fixup.cpp

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
+----------------------------------------------------------------------+
1515
*/
1616

17+
#define UNW_LOCAL_ONLY
18+
#include <libunwind.h>
19+
1720
#include "hphp/runtime/vm/jit/fixup.h"
1821

1922
#include "hphp/runtime/base/stats.h"
@@ -181,47 +184,78 @@ bool processFixupForVMFrame(VMFrame frame) {
181184
return true;
182185
}
183186

184-
bool fixupWork(ActRec* nextRbp, bool soft) {
187+
/*
188+
* Perform a fixup of the VM registers for the current stack.
189+
*
190+
* Returns whether we successfully performed the fixup. (We assert on failure
191+
* if `soft` is not set).
192+
*/
193+
bool fixupWork(bool soft) {
185194
assertx(Cfg::Jit::Enabled);
186195

187196
TRACE(1, "fixup(begin):\n");
188197

198+
// Start looking for fixup entries at the current (C++) frame. This
199+
// will walk the frames upward until we find a TC frame.
200+
// Historically this walked the chain of frame pointers directly
201+
// and extrapolated the CFA for VM frames using a constant frame size,
202+
// but this was incorrect for C++ routines with padding after their CFA.
203+
ActRec* curFrame;
204+
205+
unw_cursor_t cursor;
206+
unw_context_t uc;
207+
int err;
208+
209+
err = unw_getcontext(&uc);
210+
assertx(err == 0);
211+
err = unw_init_local(&cursor, &uc);
212+
assertx(err == 0);
213+
214+
unw_word_t fp, ip, cfa;
215+
189216
while (true) {
190-
auto const rbp = nextRbp;
191-
nextRbp = rbp->m_sfp;
217+
err = unw_step(&cursor);
218+
if (err <= 0) {
219+
assertx(err == 0);
220+
break;
221+
}
222+
223+
#ifdef __aarch64__
224+
// On aarch64, the FP is stored in x29
225+
// and the CFA is the value of SP (x31) at the previous frame.
226+
unw_get_reg(&cursor, UNW_AARCH64_X29, &fp);
227+
unw_get_reg(&cursor, UNW_AARCH64_SP, &cfa);
228+
#else
229+
#endif
192230

193-
if (UNLIKELY(soft) && (!nextRbp || nextRbp == rbp)) return false;
194-
assertx(nextRbp && nextRbp != rbp && "Missing fixup for native call");
231+
auto const prevFrame = curFrame;
232+
curFrame = (ActRec*)fp;
195233

196-
TRACE(2, "considering frame %p, %p\n", rbp, (void*)rbp->m_savedRip);
234+
TRACE(2, "considering frame %p, %p\n", curFrame, (void*)prevFrame->m_savedRip);
197235

198-
if (isVMFrame(nextRbp, soft)) {
236+
if (prevFrame != nullptr && isVMFrame(curFrame, soft)) {
199237
TRACE(2, "fixup checking vm frame %s\n",
200-
nextRbp->func()->name()->data());
201-
auto const cfa = uintptr_t(rbp) + kNativeFrameSize;
202-
auto const frame = VMFrame{nextRbp, TCA(rbp->m_savedRip), cfa};
238+
curFrame->func()->name()->data());
239+
auto const frame = VMFrame{curFrame, TCA(prevFrame->m_savedRip), cfa};
203240
auto const res = processFixupForVMFrame(frame);
204241
if (res || LIKELY(soft)) return res;
205242
always_assert(false && "Fixup expected for leafmost VM frame");
206243
}
207244
}
208-
return false;
245+
246+
if (UNLIKELY(soft)) {
247+
return false;
248+
}
249+
250+
always_assert(false && "Missing fixup for native call");
209251
}
210252

211253
////////////////////////////////////////////////////////////////////////////////
212254
}
213255

214256
namespace detail {
215257
void syncVMRegsWork(bool soft) {
216-
// Start looking for fixup entries at the current (C++) frame. This
217-
// will walk the frames upward until we find a TC frame.
218-
DECLARE_FRAME_POINTER(framePtr);
219-
auto fp = regState() >= VMRegState::GUARDED_THRESHOLD ?
220-
(ActRec*)regState() : framePtr;
221-
222-
// TODO(mcolavita): This is incorrect for C++ routines with padding after
223-
// their CFA.
224-
auto const synced = FixupMap::fixupWork(fp, soft);
258+
auto const synced = FixupMap::fixupWork(soft);
225259

226260
if (synced) regState() = VMRegState::CLEAN;
227261
Stats::inc(Stats::TC_Sync);

hphp/runtime/vm/jit/fixup.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,6 @@ size_t size();
219219
*/
220220
bool processFixupForVMFrame(VMFrame frame);
221221

222-
/*
223-
* Perform a fixup of the VM registers for a stack whose first frame is `rbp`.
224-
*
225-
* Returns whether we successfully performed the fixup. (We assert on failure
226-
* if `soft` is not set).
227-
*/
228-
bool fixupWork(ActRec* rbp, bool soft = false);
229222
}
230223

231224
namespace detail {

0 commit comments

Comments
 (0)