2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_BACKTRACE_INL_H_
18 #error "backtrace-inl.h should only be included by backtrace.h"
21 #include "hphp/runtime/base/array-data.h"
22 #include "hphp/runtime/base/rds-header.h"
23 #include "hphp/runtime/base/types.h"
24 #include "hphp/runtime/vm/act-rec.h"
25 #include "hphp/runtime/vm/vm-regs.h"
27 #include "hphp/runtime/vm/jit/types.h"
29 #include <folly/small_vector.h>
33 ///////////////////////////////////////////////////////////////////////////////
35 struct c_WaitableWaitHandle
;
37 ///////////////////////////////////////////////////////////////////////////////
39 namespace backtrace_detail
{
44 BTContext(const BTContext
&) = delete;
45 BTContext(BTContext
&&) = delete;
46 BTContext
& operator=(const BTContext
&) = delete;
47 BTContext
& operator=(BTContext
&&) = delete;
49 const ActRec
* clone(const BTContext
& src
, const ActRec
* fp
);
51 bool hasInlFrames
{false};
53 // To handle awaits in tail-position, we can reuse AsyncFunctionWaitHandle
54 // and stuff just enough tail-frame info into them to support backtracing.
55 // This field is set when iterating over these tail frames.
56 uint8_t afwhTailFrameIndex
{0};
58 // fakeAR is used to generate pseudo-frames representing inlined functions
59 // whose frames have been elided. The array operates like a ring buffer as
60 // createBacktrace needs to inspect the current and previous frame pointer,
61 // thus we introduce an m_sfp cycle between these frames.
64 IFrameID prevIFID
{kInvalidIFrameID
};
66 // The frame we should resume at after unwinding the inlined stack.
70 BTFrame
getPrevActRec(
71 BTContext
& ctx
, BTFrame frm
,
72 folly::small_vector
<c_WaitableWaitHandle
*, 64>& visitedWHs
76 * Take a `frm` cursor and perform miscellaneous preprocessing on it.
78 * Preprocessing includes:
79 * - Setting up virtual inline stack frames.
80 * - Setting up virtual FCallBuiltin inline frames.
81 * - Coalescing kInvalidOffset `pc` values to `pcOff()`.
83 BTFrame
initBTContextAt(BTContext
& ctx
, jit::CTCA ip
, BTFrame frm
);
88 void walkStack(L func
, c_WaitableWaitHandle
* wh
, bool skipTop
) {
89 using namespace backtrace_detail
;
93 folly::small_vector
<c_WaitableWaitHandle
*, 64> visitedWHs
;
95 auto frm
= wh
!= nullptr
96 ? getARFromWH(wh
, visitedWHs
)
99 // If there are no VM frames, we're done.
100 if (!frm
|| !rds::header()) return;
104 frm
= initBTContextAt(ctx
, vmJitReturnAddr(), frm
);
106 if (skipTop
) frm
= getPrevActRec(ctx
, frm
, visitedWHs
);
108 for (; frm
; frm
= getPrevActRec(ctx
, frm
, visitedWHs
)) {
109 if (ArrayData::call_helper(func
, frm
.fp
, frm
.pc
)) return;
114 void walkStack(L func
, bool skipTop
) {
115 walkStack(func
, nullptr, skipTop
);
118 namespace backtrace_detail
{
120 template<typename F
, typename Pred
>
121 from_ret_t
<F
> fromLeafImpl(F f
, Pred pred
,
123 c_WaitableWaitHandle
* wh
,
126 walkStack([&] (const ActRec
* fp
, Offset off
) {
127 if (!pred(fp
)) return false;
134 inline bool true_pred(const ActRec
* fp
) { return true; }
139 backtrace_detail::from_ret_t
<F
> fromLeaf(
140 F f
, backtrace_detail::from_ret_t
<F
> def
142 return backtrace_detail::fromLeafImpl(
143 f
, backtrace_detail::true_pred
, def
, nullptr, false
148 backtrace_detail::from_ret_t
<F
> fromCaller(
149 F f
, backtrace_detail::from_ret_t
<F
> def
151 return backtrace_detail::fromLeafImpl(
152 f
, backtrace_detail::true_pred
, def
, nullptr, true
157 backtrace_detail::from_ret_t
<F
> fromLeafWH(
158 c_WaitableWaitHandle
* wh
, F f
,
159 backtrace_detail::from_ret_t
<F
> def
161 return backtrace_detail::fromLeafImpl(
162 f
, backtrace_detail::true_pred
, def
, wh
, false
166 template<typename F
, typename Pred
>
167 backtrace_detail::from_ret_t
<F
> fromLeaf(
168 F f
, Pred pred
, backtrace_detail::from_ret_t
<F
> def
170 return backtrace_detail::fromLeafImpl(f
, pred
, def
, nullptr, false);
173 template<typename F
, typename Pred
>
174 backtrace_detail::from_ret_t
<F
> fromCaller(
175 F f
, Pred pred
, backtrace_detail::from_ret_t
<F
> def
177 return backtrace_detail::fromLeafImpl(f
, pred
, def
, nullptr, true);
180 template<typename F
, typename Pred
>
181 backtrace_detail::from_ret_t
<F
> fromLeafWH(
182 c_WaitableWaitHandle
* wh
, F f
, Pred pred
,
183 backtrace_detail::from_ret_t
<F
> def
185 return backtrace_detail::fromLeafImpl(f
, pred
, def
, wh
, false);
188 ///////////////////////////////////////////////////////////////////////////////