/src/mozilla-central/tools/profiler/tests/gtest/LulTestInfrastructure.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2010, Google Inc. |
2 | | // All rights reserved. |
3 | | // |
4 | | // Redistribution and use in source and binary forms, with or without |
5 | | // modification, are permitted provided that the following conditions are |
6 | | // met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright |
9 | | // notice, this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above |
11 | | // copyright notice, this list of conditions and the following disclaimer |
12 | | // in the documentation and/or other materials provided with the |
13 | | // distribution. |
14 | | // * Neither the name of Google Inc. nor the names of its |
15 | | // contributors may be used to endorse or promote products derived from |
16 | | // this software without specific prior written permission. |
17 | | // |
18 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
19 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
20 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
21 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
22 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | | |
30 | | // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
31 | | |
32 | | // Derived from: |
33 | | // test_assembler.cc: Implementation of google_breakpad::TestAssembler. |
34 | | // See test_assembler.h for details. |
35 | | |
36 | | // Derived from: |
37 | | // cfi_assembler.cc: Implementation of google_breakpad::CFISection class. |
38 | | // See cfi_assembler.h for details. |
39 | | |
40 | | #include "LulTestInfrastructure.h" |
41 | | |
42 | | namespace lul_test { |
43 | | namespace test_assembler { |
44 | | |
45 | | using std::back_insert_iterator; |
46 | | |
47 | 0 | Label::Label() : value_(new Binding()) { } |
48 | 0 | Label::Label(uint64_t value) : value_(new Binding(value)) { } |
49 | 0 | Label::Label(const Label &label) { |
50 | 0 | value_ = label.value_; |
51 | 0 | value_->Acquire(); |
52 | 0 | } |
53 | 0 | Label::~Label() { |
54 | 0 | if (value_->Release()) delete value_; |
55 | 0 | } |
56 | | |
57 | 0 | Label &Label::operator=(uint64_t value) { |
58 | 0 | value_->Set(NULL, value); |
59 | 0 | return *this; |
60 | 0 | } |
61 | | |
62 | 0 | Label &Label::operator=(const Label &label) { |
63 | 0 | value_->Set(label.value_, 0); |
64 | 0 | return *this; |
65 | 0 | } |
66 | | |
67 | 0 | Label Label::operator+(uint64_t addend) const { |
68 | 0 | Label l; |
69 | 0 | l.value_->Set(this->value_, addend); |
70 | 0 | return l; |
71 | 0 | } |
72 | | |
73 | 0 | Label Label::operator-(uint64_t subtrahend) const { |
74 | 0 | Label l; |
75 | 0 | l.value_->Set(this->value_, -subtrahend); |
76 | 0 | return l; |
77 | 0 | } |
78 | | |
79 | | // When NDEBUG is #defined, assert doesn't evaluate its argument. This |
80 | | // means you can't simply use assert to check the return value of a |
81 | | // function with necessary side effects. |
82 | | // |
83 | | // ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether |
84 | | // NDEBUG is #defined; when NDEBUG is not #defined, it further asserts |
85 | | // that x is true. |
86 | | #ifdef NDEBUG |
87 | 0 | #define ALWAYS_EVALUATE_AND_ASSERT(x) x |
88 | | #else |
89 | | #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) |
90 | | #endif |
91 | | |
92 | 0 | uint64_t Label::operator-(const Label &label) const { |
93 | 0 | uint64_t offset; |
94 | 0 | ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); |
95 | 0 | return offset; |
96 | 0 | } |
97 | | |
98 | 0 | bool Label::IsKnownConstant(uint64_t *value_p) const { |
99 | 0 | Binding *base; |
100 | 0 | uint64_t addend; |
101 | 0 | value_->Get(&base, &addend); |
102 | 0 | if (base != NULL) return false; |
103 | 0 | if (value_p) *value_p = addend; |
104 | 0 | return true; |
105 | 0 | } |
106 | | |
107 | | bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const |
108 | 0 | { |
109 | 0 | Binding *label_base, *this_base; |
110 | 0 | uint64_t label_addend, this_addend; |
111 | 0 | label.value_->Get(&label_base, &label_addend); |
112 | 0 | value_->Get(&this_base, &this_addend); |
113 | 0 | // If this and label are related, Get will find their final |
114 | 0 | // common ancestor, regardless of how indirect the relation is. This |
115 | 0 | // comparison also handles the constant vs. constant case. |
116 | 0 | if (this_base != label_base) return false; |
117 | 0 | if (offset_p) *offset_p = this_addend - label_addend; |
118 | 0 | return true; |
119 | 0 | } |
120 | | |
121 | 0 | Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } |
122 | | |
123 | | Label::Binding::Binding(uint64_t addend) |
124 | 0 | : base_(NULL), addend_(addend), reference_count_(1) { } |
125 | | |
126 | 0 | Label::Binding::~Binding() { |
127 | 0 | assert(reference_count_ == 0); |
128 | 0 | if (base_ && base_ != this && base_->Release()) |
129 | 0 | delete base_; |
130 | 0 | } |
131 | | |
132 | 0 | void Label::Binding::Set(Binding *binding, uint64_t addend) { |
133 | 0 | if (!base_ && !binding) { |
134 | 0 | // We're equating two constants. This could be okay. |
135 | 0 | assert(addend_ == addend); |
136 | 0 | } else if (!base_) { |
137 | 0 | // We are a known constant, but BINDING may not be, so turn the |
138 | 0 | // tables and try to set BINDING's value instead. |
139 | 0 | binding->Set(NULL, addend_ - addend); |
140 | 0 | } else { |
141 | 0 | if (binding) { |
142 | 0 | // Find binding's final value. Since the final value is always either |
143 | 0 | // completely unconstrained or a constant, never a reference to |
144 | 0 | // another variable (otherwise, it wouldn't be final), this |
145 | 0 | // guarantees we won't create cycles here, even for code like this: |
146 | 0 | // l = m, m = n, n = l; |
147 | 0 | uint64_t binding_addend; |
148 | 0 | binding->Get(&binding, &binding_addend); |
149 | 0 | addend += binding_addend; |
150 | 0 | } |
151 | 0 |
|
152 | 0 | // It seems likely that setting a binding to itself is a bug |
153 | 0 | // (although I can imagine this might turn out to be helpful to |
154 | 0 | // permit). |
155 | 0 | assert(binding != this); |
156 | 0 |
|
157 | 0 | if (base_ != this) { |
158 | 0 | // Set the other bindings on our chain as well. Note that this |
159 | 0 | // is sufficient even though binding relationships form trees: |
160 | 0 | // All binding operations traverse their chains to the end, and |
161 | 0 | // all bindings related to us share some tail of our chain, so |
162 | 0 | // they will see the changes we make here. |
163 | 0 | base_->Set(binding, addend - addend_); |
164 | 0 | // We're not going to use base_ any more. |
165 | 0 | if (base_->Release()) delete base_; |
166 | 0 | } |
167 | 0 |
|
168 | 0 | // Adopt BINDING as our base. Note that it should be correct to |
169 | 0 | // acquire here, after the release above, even though the usual |
170 | 0 | // reference-counting rules call for acquiring first, and then |
171 | 0 | // releasing: the self-reference assertion above should have |
172 | 0 | // complained if BINDING were 'this' or anywhere along our chain, |
173 | 0 | // so we didn't release BINDING. |
174 | 0 | if (binding) binding->Acquire(); |
175 | 0 | base_ = binding; |
176 | 0 | addend_ = addend; |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 0 | void Label::Binding::Get(Binding **base, uint64_t *addend) { |
181 | 0 | if (base_ && base_ != this) { |
182 | 0 | // Recurse to find the end of our reference chain (the root of our |
183 | 0 | // tree), and then rewrite every binding along the chain to refer |
184 | 0 | // to it directly, adjusting addends appropriately. (This is why |
185 | 0 | // this member function isn't this-const.) |
186 | 0 | Binding *final_base; |
187 | 0 | uint64_t final_addend; |
188 | 0 | base_->Get(&final_base, &final_addend); |
189 | 0 | if (final_base) final_base->Acquire(); |
190 | 0 | if (base_->Release()) delete base_; |
191 | 0 | base_ = final_base; |
192 | 0 | addend_ += final_addend; |
193 | 0 | } |
194 | 0 | *base = base_; |
195 | 0 | *addend = addend_; |
196 | 0 | } |
197 | | |
198 | | template<typename Inserter> |
199 | | static inline void InsertEndian(test_assembler::Endianness endianness, |
200 | 0 | size_t size, uint64_t number, Inserter dest) { |
201 | 0 | assert(size > 0); |
202 | 0 | if (endianness == kLittleEndian) { |
203 | 0 | for (size_t i = 0; i < size; i++) { |
204 | 0 | *dest++ = (char) (number & 0xff); |
205 | 0 | number >>= 8; |
206 | 0 | } |
207 | 0 | } else { |
208 | 0 | assert(endianness == kBigEndian); |
209 | 0 | // The loop condition is odd, but it's correct for size_t. |
210 | 0 | for (size_t i = size - 1; i < size; i--) |
211 | 0 | *dest++ = (char) ((number >> (i * 8)) & 0xff); |
212 | 0 | } |
213 | 0 | } Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:void lul_test::test_assembler::InsertEndian<std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(lul_test::test_assembler::Endianness, unsigned long, unsigned long, std::__1::back_insert_iterator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >) Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:void lul_test::test_assembler::InsertEndian<std::__1::__wrap_iter<char*> >(lul_test::test_assembler::Endianness, unsigned long, unsigned long, std::__1::__wrap_iter<char*>) |
214 | | |
215 | 0 | Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { |
216 | 0 | InsertEndian(endianness, size, number, |
217 | 0 | back_insert_iterator<string>(contents_)); |
218 | 0 | return *this; |
219 | 0 | } |
220 | | |
221 | | Section &Section::Append(Endianness endianness, size_t size, |
222 | 0 | const Label &label) { |
223 | 0 | // If this label's value is known, there's no reason to waste an |
224 | 0 | // entry in references_ on it. |
225 | 0 | uint64_t value; |
226 | 0 | if (label.IsKnownConstant(&value)) |
227 | 0 | return Append(endianness, size, value); |
228 | 0 | |
229 | 0 | // This will get caught when the references are resolved, but it's |
230 | 0 | // nicer to find out earlier. |
231 | 0 | assert(endianness != kUnsetEndian); |
232 | 0 |
|
233 | 0 | references_.push_back(Reference(contents_.size(), endianness, size, label)); |
234 | 0 | contents_.append(size, 0); |
235 | 0 | return *this; |
236 | 0 | } |
237 | | |
238 | 0 | #define ENDIANNESS_L kLittleEndian |
239 | 0 | #define ENDIANNESS_B kBigEndian |
240 | 0 | #define ENDIANNESS(e) ENDIANNESS_ ## e |
241 | | |
242 | | #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ |
243 | 0 | Section &Section::e ## bits(uint ## bits ## _t v) { \ |
244 | 0 | InsertEndian(ENDIANNESS(e), bits / 8, v, \ |
245 | 0 | back_insert_iterator<string>(contents_)); \ |
246 | 0 | return *this; \ |
247 | 0 | } Unexecuted instantiation: lul_test::test_assembler::Section::L16(unsigned short) Unexecuted instantiation: lul_test::test_assembler::Section::L32(unsigned int) Unexecuted instantiation: lul_test::test_assembler::Section::L64(unsigned long) Unexecuted instantiation: lul_test::test_assembler::Section::B16(unsigned short) Unexecuted instantiation: lul_test::test_assembler::Section::B32(unsigned int) Unexecuted instantiation: lul_test::test_assembler::Section::B64(unsigned long) |
248 | | |
249 | | #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ |
250 | 0 | Section &Section::e ## bits(const Label &v) { \ |
251 | 0 | return Append(ENDIANNESS(e), bits / 8, v); \ |
252 | 0 | } Unexecuted instantiation: lul_test::test_assembler::Section::L8(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::B8(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::L16(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::L32(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::L64(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::B16(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::B32(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::B64(lul_test::test_assembler::Label const&) |
253 | | |
254 | | // Define L16, B32, and friends. |
255 | | #define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ |
256 | | DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ |
257 | | DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) |
258 | | |
259 | | DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); |
260 | | DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); |
261 | | DEFINE_SHORT_APPEND_ENDIAN(L, 16); |
262 | | DEFINE_SHORT_APPEND_ENDIAN(L, 32); |
263 | | DEFINE_SHORT_APPEND_ENDIAN(L, 64); |
264 | | DEFINE_SHORT_APPEND_ENDIAN(B, 16); |
265 | | DEFINE_SHORT_APPEND_ENDIAN(B, 32); |
266 | | DEFINE_SHORT_APPEND_ENDIAN(B, 64); |
267 | | |
268 | | #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ |
269 | 0 | Section &Section::D ## bits(uint ## bits ## _t v) { \ |
270 | 0 | InsertEndian(endianness_, bits / 8, v, \ |
271 | 0 | back_insert_iterator<string>(contents_)); \ |
272 | 0 | return *this; \ |
273 | 0 | } Unexecuted instantiation: lul_test::test_assembler::Section::D16(unsigned short) Unexecuted instantiation: lul_test::test_assembler::Section::D32(unsigned int) Unexecuted instantiation: lul_test::test_assembler::Section::D64(unsigned long) |
274 | | #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ |
275 | 0 | Section &Section::D ## bits(const Label &v) { \ |
276 | 0 | return Append(endianness_, bits / 8, v); \ |
277 | 0 | } Unexecuted instantiation: lul_test::test_assembler::Section::D8(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::D16(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::D32(lul_test::test_assembler::Label const&) Unexecuted instantiation: lul_test::test_assembler::Section::D64(lul_test::test_assembler::Label const&) |
278 | | #define DEFINE_SHORT_APPEND_DEFAULT(bits) \ |
279 | | DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ |
280 | | DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) |
281 | | |
282 | | DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) |
283 | | DEFINE_SHORT_APPEND_DEFAULT(16); |
284 | | DEFINE_SHORT_APPEND_DEFAULT(32); |
285 | | DEFINE_SHORT_APPEND_DEFAULT(64); |
286 | | |
287 | 0 | Section &Section::LEB128(long long value) { |
288 | 0 | while (value < -0x40 || 0x3f < value) { |
289 | 0 | contents_ += (value & 0x7f) | 0x80; |
290 | 0 | if (value < 0) |
291 | 0 | value = (value >> 7) | ~(((unsigned long long) -1) >> 7); |
292 | 0 | else |
293 | 0 | value = (value >> 7); |
294 | 0 | } |
295 | 0 | contents_ += value & 0x7f; |
296 | 0 | return *this; |
297 | 0 | } |
298 | | |
299 | 0 | Section &Section::ULEB128(uint64_t value) { |
300 | 0 | while (value > 0x7f) { |
301 | 0 | contents_ += (value & 0x7f) | 0x80; |
302 | 0 | value = (value >> 7); |
303 | 0 | } |
304 | 0 | contents_ += value; |
305 | 0 | return *this; |
306 | 0 | } |
307 | | |
308 | 0 | Section &Section::Align(size_t alignment, uint8_t pad_byte) { |
309 | 0 | // ALIGNMENT must be a power of two. |
310 | 0 | assert(((alignment - 1) & alignment) == 0); |
311 | 0 | size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); |
312 | 0 | contents_.append(new_size - contents_.size(), pad_byte); |
313 | 0 | assert((contents_.size() & (alignment - 1)) == 0); |
314 | 0 | return *this; |
315 | 0 | } |
316 | | |
317 | 0 | bool Section::GetContents(string *contents) { |
318 | 0 | // For each label reference, find the label's value, and patch it into |
319 | 0 | // the section's contents. |
320 | 0 | for (size_t i = 0; i < references_.size(); i++) { |
321 | 0 | Reference &r = references_[i]; |
322 | 0 | uint64_t value; |
323 | 0 | if (!r.label.IsKnownConstant(&value)) { |
324 | 0 | fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); |
325 | 0 | return false; |
326 | 0 | } |
327 | 0 | assert(r.offset < contents_.size()); |
328 | 0 | assert(contents_.size() - r.offset >= r.size); |
329 | 0 | InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); |
330 | 0 | } |
331 | 0 | contents->clear(); |
332 | 0 | std::swap(contents_, *contents); |
333 | 0 | references_.clear(); |
334 | 0 | return true; |
335 | 0 | } |
336 | | |
337 | | } // namespace test_assembler |
338 | | } // namespace lul_test |
339 | | |
340 | | |
341 | | namespace lul_test { |
342 | | |
343 | | CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, |
344 | | int data_alignment_factor, |
345 | | unsigned return_address_register, |
346 | | uint8_t version, |
347 | | const string &augmentation, |
348 | 0 | bool dwarf64) { |
349 | 0 | assert(!entry_length_); |
350 | 0 | entry_length_ = new PendingLength(); |
351 | 0 | in_fde_ = false; |
352 | 0 |
|
353 | 0 | if (dwarf64) { |
354 | 0 | D32(kDwarf64InitialLengthMarker); |
355 | 0 | D64(entry_length_->length); |
356 | 0 | entry_length_->start = Here(); |
357 | 0 | D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); |
358 | 0 | } else { |
359 | 0 | D32(entry_length_->length); |
360 | 0 | entry_length_->start = Here(); |
361 | 0 | D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); |
362 | 0 | } |
363 | 0 | D8(version); |
364 | 0 | AppendCString(augmentation); |
365 | 0 | ULEB128(code_alignment_factor); |
366 | 0 | LEB128(data_alignment_factor); |
367 | 0 | if (version == 1) |
368 | 0 | D8(return_address_register); |
369 | 0 | else |
370 | 0 | ULEB128(return_address_register); |
371 | 0 | return *this; |
372 | 0 | } |
373 | | |
374 | | CFISection &CFISection::FDEHeader(Label cie_pointer, |
375 | | uint64_t initial_location, |
376 | | uint64_t address_range, |
377 | 0 | bool dwarf64) { |
378 | 0 | assert(!entry_length_); |
379 | 0 | entry_length_ = new PendingLength(); |
380 | 0 | in_fde_ = true; |
381 | 0 | fde_start_address_ = initial_location; |
382 | 0 |
|
383 | 0 | if (dwarf64) { |
384 | 0 | D32(0xffffffff); |
385 | 0 | D64(entry_length_->length); |
386 | 0 | entry_length_->start = Here(); |
387 | 0 | if (eh_frame_) |
388 | 0 | D64(Here() - cie_pointer); |
389 | 0 | else |
390 | 0 | D64(cie_pointer); |
391 | 0 | } else { |
392 | 0 | D32(entry_length_->length); |
393 | 0 | entry_length_->start = Here(); |
394 | 0 | if (eh_frame_) |
395 | 0 | D32(Here() - cie_pointer); |
396 | 0 | else |
397 | 0 | D32(cie_pointer); |
398 | 0 | } |
399 | 0 | EncodedPointer(initial_location); |
400 | 0 | // The FDE length in an .eh_frame section uses the same encoding as the |
401 | 0 | // initial location, but ignores the base address (selected by the upper |
402 | 0 | // nybble of the encoding), as it's a length, not an address that can be |
403 | 0 | // made relative. |
404 | 0 | EncodedPointer(address_range, |
405 | 0 | DwarfPointerEncoding(pointer_encoding_ & 0x0f)); |
406 | 0 | return *this; |
407 | 0 | } |
408 | | |
409 | 0 | CFISection &CFISection::FinishEntry() { |
410 | 0 | assert(entry_length_); |
411 | 0 | Align(address_size_, lul::DW_CFA_nop); |
412 | 0 | entry_length_->length = Here() - entry_length_->start; |
413 | 0 | delete entry_length_; |
414 | 0 | entry_length_ = NULL; |
415 | 0 | in_fde_ = false; |
416 | 0 | return *this; |
417 | 0 | } |
418 | | |
419 | | CFISection &CFISection::EncodedPointer(uint64_t address, |
420 | | DwarfPointerEncoding encoding, |
421 | 0 | const EncodedPointerBases &bases) { |
422 | 0 | // Omitted data is extremely easy to emit. |
423 | 0 | if (encoding == lul::DW_EH_PE_omit) |
424 | 0 | return *this; |
425 | 0 | |
426 | 0 | // If (encoding & lul::DW_EH_PE_indirect) != 0, then we assume |
427 | 0 | // that ADDRESS is the address at which the pointer is stored --- in |
428 | 0 | // other words, that bit has no effect on how we write the pointer. |
429 | 0 | encoding = DwarfPointerEncoding(encoding & ~lul::DW_EH_PE_indirect); |
430 | 0 |
|
431 | 0 | // Find the base address to which this pointer is relative. The upper |
432 | 0 | // nybble of the encoding specifies this. |
433 | 0 | uint64_t base; |
434 | 0 | switch (encoding & 0xf0) { |
435 | 0 | case lul::DW_EH_PE_absptr: base = 0; break; |
436 | 0 | case lul::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; |
437 | 0 | case lul::DW_EH_PE_textrel: base = bases.text; break; |
438 | 0 | case lul::DW_EH_PE_datarel: base = bases.data; break; |
439 | 0 | case lul::DW_EH_PE_funcrel: base = fde_start_address_; break; |
440 | 0 | case lul::DW_EH_PE_aligned: base = 0; break; |
441 | 0 | default: abort(); |
442 | 0 | }; |
443 | 0 |
|
444 | 0 | // Make ADDRESS relative. Yes, this is appropriate even for "absptr" |
445 | 0 | // values; see gcc/unwind-pe.h. |
446 | 0 | address -= base; |
447 | 0 |
|
448 | 0 | // Align the pointer, if required. |
449 | 0 | if ((encoding & 0xf0) == lul::DW_EH_PE_aligned) |
450 | 0 | Align(AddressSize()); |
451 | 0 |
|
452 | 0 | // Append ADDRESS to this section in the appropriate form. For the |
453 | 0 | // fixed-width forms, we don't need to differentiate between signed and |
454 | 0 | // unsigned encodings, because ADDRESS has already been extended to 64 |
455 | 0 | // bits before it was passed to us. |
456 | 0 | switch (encoding & 0x0f) { |
457 | 0 | case lul::DW_EH_PE_absptr: |
458 | 0 | Address(address); |
459 | 0 | break; |
460 | 0 |
|
461 | 0 | case lul::DW_EH_PE_uleb128: |
462 | 0 | ULEB128(address); |
463 | 0 | break; |
464 | 0 |
|
465 | 0 | case lul::DW_EH_PE_sleb128: |
466 | 0 | LEB128(address); |
467 | 0 | break; |
468 | 0 |
|
469 | 0 | case lul::DW_EH_PE_udata2: |
470 | 0 | case lul::DW_EH_PE_sdata2: |
471 | 0 | D16(address); |
472 | 0 | break; |
473 | 0 |
|
474 | 0 | case lul::DW_EH_PE_udata4: |
475 | 0 | case lul::DW_EH_PE_sdata4: |
476 | 0 | D32(address); |
477 | 0 | break; |
478 | 0 |
|
479 | 0 | case lul::DW_EH_PE_udata8: |
480 | 0 | case lul::DW_EH_PE_sdata8: |
481 | 0 | D64(address); |
482 | 0 | break; |
483 | 0 |
|
484 | 0 | default: |
485 | 0 | abort(); |
486 | 0 | } |
487 | 0 | |
488 | 0 | return *this; |
489 | 0 | }; |
490 | | |
491 | | } // namespace lul_test |