Optional Two-phase heap tracing
[hiphop-php.git] / hphp / util / eh-frame.h
blob7bfab527644148579be002470d1f57fe8464f8f9
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 HPHP_UTIL_EH_FRAME_H_
18 #define HPHP_UTIL_EH_FRAME_H_
20 #include "hphp/util/data-block.h"
21 #include "hphp/util/dwarf-reg.h"
23 #include <boost/mpl/identity.hpp>
24 #include <folly/Memory.h>
26 #include <cstring>
27 #include <memory>
28 #include <utility>
29 #include <vector>
31 #ifndef _MSC_VER
32 #include <dwarf.h>
33 #include <libdwarf.h>
34 #else
35 #include "hphp/util/eh-frame-msvc.h"
36 #endif
38 namespace HPHP {
40 ///////////////////////////////////////////////////////////////////////////////
43 * A handle to a dynamically-generated .eh_frame section.
45 * Contains an exclusive pointer to a buffer, as well as routines for
46 * inspecting its contents. When destructed, it deregisters the .eh_frame
47 * sections and frees the buffer.
49 struct EHFrameDesc {
50 ~EHFrameDesc();
52 EHFrameDesc() {}
53 EHFrameDesc(EHFrameDesc&&) = default;
56 * Shared component (the "header") of CIEs and FDEs.
58 struct Entry {
59 const uint8_t* get() const;
60 uint32_t length() const;
61 uint32_t cie_off() const;
63 Entry(const std::vector<uint8_t>& vec, size_t idx)
64 : m_vec(vec)
65 , m_idx(idx)
67 const std::vector<uint8_t>& m_vec;
68 size_t m_idx;
72 * Helper structs for reading CIE and FDE data.
74 struct CIE : Entry {
75 private: using Entry::Entry;
77 struct FDE : Entry {
78 CodeAddress start() const;
79 size_t range() const;
81 private: using Entry::Entry;
84 CIE cie() const;
86 template<class F>
87 void for_each_fde(F f) const;
89 private:
90 friend struct EHFrameWriter;
91 std::unique_ptr<std::vector<uint8_t>> m_buf;
95 * API for dynamically creating and registering new .eh_frame sections.
97 * An EHFrameWriter instance can be given (or asked to create) an exclusive
98 * pointer to a buffer. It permits writing exactly one CIE, contiguously
99 * followed by any number of FDES, before registering any FDEs written and
100 * returning an EHFrameDesc---which, when destructed, deregisters and frees its
101 * contents.
103 * In a pinch, EHFrameWriter could also just be used to write DWARF call frame
104 * instructions to a buffer, without the .eh_frame specifics, though there are
105 * currently assertions preventing that.
107 struct EHFrameWriter {
109 * Constructors.
111 * Either allocate a fresh buffer, or take exclusive ownership of the
112 * provided `buf'.
114 EHFrameWriter()
115 : m_buf(std::make_unique<std::vector<uint8_t>>())
117 explicit EHFrameWriter(std::unique_ptr<std::vector<uint8_t>>&& buf)
118 : m_buf(std::move(buf))
122 * Register the FDE written to the buffer (if one was written), then release
123 * the buffer.
125 * When all references to the returned value are lost, the buffer will delete
126 * itself and deregister its FDE (if it exists).
128 EHFrameDesc register_and_release();
130 /////////////////////////////////////////////////////////////////////////////
133 * Write a CIE with the following fields:
135 * length: automatic
136 * CIE id: 0
137 * version: 1
138 * augment str: personality ? "zPR" : "zR"
139 * code align: 1
140 * data align: -8
141 * return reg: rip
142 * augmentation: all pointer encodings DW_EH_PE_absptr
144 * Any initial call frame instructions should be written between the calls to
145 * begin_cie() and end_cie().
147 * @see: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
148 * https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/dwarfext.html
150 void begin_cie(uint8_t rip, const void* personality = nullptr);
151 void end_cie();
154 * Write an FDE with the following fields:
156 * length: automatic
157 * CIE pointer: offset of `&m_buf[m_cie.idx]'
158 * initial PC: `start'
159 * address range: `size'
160 * augmentation: 0
162 * Any call frame instructions should be written between the calls to
163 * begin_fde() and end_fde().
165 void begin_fde(CodeAddress start);
166 void end_fde(size_t size);
169 * Write an FDE with zero length.
171 * This is required at the end of an .eh_frame section, to indicate that
172 * there are no more FDEs sharing their CIE. (This requirement does not
173 * appear to be documented, but failing to zero-terminate causes a segfault
174 * in classify_object_over_fdes() in unwind-dw2-fde.c.
176 void null_fde();
178 /////////////////////////////////////////////////////////////////////////////
180 * Write a DWARF call frame instruction to the buffer.
182 * These all emit DW_CFA opcodes with the appropriate arguments. For
183 * documentation, see Chapter 6.4.2: Call Frame Instructions in
184 * http://dwarfstd.org/doc/DWARF4.pdf
188 * Row creation instruction.
190 * Emit the appropriate advance_loc* instruction, or set_loc if we are
191 * advancing more than 2^32 bytes.
193 void advance_loc_to(CodeAddress addr);
196 * CFA definition instructions.
198 void def_cfa(uint8_t reg, uint64_t off);
199 void def_cfa_register(uint8_t reg);
200 void def_cfa_offset(uint64_t off);
202 * Adjust the tracked CFA offset, and emit a def_cfa_offset for the new one.
204 void advance_cfa_offset(int64_t off);
207 * Register rule instructions.
209 void same_value(uint8_t reg);
210 void offset(uint8_t reg, uint64_t off);
211 void offset_extended_sf(uint8_t reg, int64_t off);
212 void restore(uint8_t reg);
214 * Begin a DWARF expression which either:
215 * - expression(): computes the memory location which contains the value
216 * of `reg'; or
217 * - val_expression(): computes the value of `reg'.
219 * The operations comprising the expression should be written between the
220 * calls to begin_{,val_}expression() and end_expression() (which ends either
221 * kind of expression).
223 * At present, we always use DW_FORM_block1, and attempting to write an
224 * expression whose operations contain more than (2^8 - 1) bytes will fail an
225 * assertion.
227 void begin_expression(uint8_t reg);
228 void begin_val_expression(uint8_t reg);
229 void end_expression();
232 * Padding instruction.
234 void nop();
236 /////////////////////////////////////////////////////////////////////////////
238 * Write a DWARF operation to the buffer.
240 * These all emit DW_OP opcodes with the appropriate arguments. For
241 * documentation, see Chapter 2.5: DWARF Expressions
242 * http://dwarfstd.org/doc/DWARF4.pdf
246 * Literal encodings.
248 void op_consts(int64_t cns);
251 * Register based addressing.
253 void op_breg(uint8_t reg, int64_t off);
256 * Stack operations.
258 void op_dup();
259 void op_drop();
260 void op_swap();
261 void op_deref();
264 * Arithmetic and logical operations.
266 void op_abs();
267 void op_and();
268 void op_div();
269 void op_minus();
270 void op_mod();
271 void op_mul();
272 void op_neg();
273 void op_not();
274 void op_or();
275 void op_plus();
278 /////////////////////////////////////////////////////////////////////////////
280 private:
281 template<class T>
282 void write(// Prevent template argument deduction:
283 typename boost::mpl::identity<T>::type t) {
284 auto& v = *m_buf;
285 auto const idx = v.size();
286 v.resize(idx + sizeof(T));
287 auto caddr = &v[idx];
288 std::memcpy(caddr, &t, sizeof t);
291 void dw_cfa(uint8_t);
292 void dw_op(uint8_t);
293 void write_uleb(uint64_t);
294 void write_sleb(int64_t);
296 void begin_expr_impl(uint8_t op, uint8_t reg);
298 static constexpr size_t kInvalidIdx = -1ull;
300 /////////////////////////////////////////////////////////////////////////////
302 private:
303 // The managed buffer.
304 std::unique_ptr<std::vector<uint8_t>> m_buf{nullptr};
306 // Metadata for the emitted CIE.
307 struct {
308 // Index of the CIE in m_buf.
309 size_t idx{kInvalidIdx};
310 // The CIE's data_alignment_factor.
311 int64_t data_align{-8};
312 // CFA offset at the end of the CIE's call frame instructions.
313 uint64_t offset{0};
314 } m_cie;
316 // Index in m_buf of the FDE currently being written.
317 size_t m_fde{kInvalidIdx};
318 // Current CFI table row address.
319 CodeAddress m_loc{nullptr};
320 // Current CFA offset.
321 uint64_t m_off{0};
323 // Index in m_buf of the expression currently being written.
324 size_t m_expr{kInvalidIdx};
327 ///////////////////////////////////////////////////////////////////////////////
331 #include "hphp/util/eh-frame-inl.h"
333 #endif