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 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>
35 #include "hphp/util/eh-frame-msvc.h"
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.
53 EHFrameDesc(EHFrameDesc
&&) = default;
56 * Shared component (the "header") of CIEs and FDEs.
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
)
67 const std::vector
<uint8_t>& m_vec
;
72 * Helper structs for reading CIE and FDE data.
75 private: using Entry::Entry
;
78 CodeAddress
start() const;
81 private: using Entry::Entry
;
87 void for_each_fde(F f
) const;
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
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
{
111 * Either allocate a fresh buffer, or take exclusive ownership of the
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
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:
138 * augment str: personality ? "zPR" : "zR"
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);
154 * Write an FDE with the following fields:
157 * CIE pointer: offset of `&m_buf[m_cie.idx]'
158 * initial PC: `start'
159 * address range: `size'
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.
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
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
227 void begin_expression(uint8_t reg
);
228 void begin_val_expression(uint8_t reg
);
229 void end_expression();
232 * Padding instruction.
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
248 void op_consts(int64_t cns
);
251 * Register based addressing.
253 void op_breg(uint8_t reg
, int64_t off
);
264 * Arithmetic and logical operations.
278 /////////////////////////////////////////////////////////////////////////////
282 void write(// Prevent template argument deduction:
283 typename
boost::mpl::identity
<T
>::type t
) {
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);
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 /////////////////////////////////////////////////////////////////////////////
303 // The managed buffer.
304 std::unique_ptr
<std::vector
<uint8_t>> m_buf
{nullptr};
306 // Metadata for the emitted CIE.
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.
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.
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"