|
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 // test_assembler.cc: Implementation of google_breakpad::TestAssembler. |
|
33 // See test_assembler.h for details. |
|
34 |
|
35 #include "common/test_assembler.h" |
|
36 |
|
37 #include <assert.h> |
|
38 #include <stdio.h> |
|
39 |
|
40 #include <iterator> |
|
41 |
|
42 namespace google_breakpad { |
|
43 namespace test_assembler { |
|
44 |
|
45 using std::back_insert_iterator; |
|
46 |
|
47 Label::Label() : value_(new Binding()) { } |
|
48 Label::Label(uint64_t value) : value_(new Binding(value)) { } |
|
49 Label::Label(const Label &label) { |
|
50 value_ = label.value_; |
|
51 value_->Acquire(); |
|
52 } |
|
53 Label::~Label() { |
|
54 if (value_->Release()) delete value_; |
|
55 } |
|
56 |
|
57 Label &Label::operator=(uint64_t value) { |
|
58 value_->Set(NULL, value); |
|
59 return *this; |
|
60 } |
|
61 |
|
62 Label &Label::operator=(const Label &label) { |
|
63 value_->Set(label.value_, 0); |
|
64 return *this; |
|
65 } |
|
66 |
|
67 Label Label::operator+(uint64_t addend) const { |
|
68 Label l; |
|
69 l.value_->Set(this->value_, addend); |
|
70 return l; |
|
71 } |
|
72 |
|
73 Label Label::operator-(uint64_t subtrahend) const { |
|
74 Label l; |
|
75 l.value_->Set(this->value_, -subtrahend); |
|
76 return l; |
|
77 } |
|
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 #define ALWAYS_EVALUATE_AND_ASSERT(x) x |
|
88 #else |
|
89 #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) |
|
90 #endif |
|
91 |
|
92 uint64_t Label::operator-(const Label &label) const { |
|
93 uint64_t offset; |
|
94 ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); |
|
95 return offset; |
|
96 } |
|
97 |
|
98 uint64_t Label::Value() const { |
|
99 uint64_t v = 0; |
|
100 ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v)); |
|
101 return v; |
|
102 }; |
|
103 |
|
104 bool Label::IsKnownConstant(uint64_t *value_p) const { |
|
105 Binding *base; |
|
106 uint64_t addend; |
|
107 value_->Get(&base, &addend); |
|
108 if (base != NULL) return false; |
|
109 if (value_p) *value_p = addend; |
|
110 return true; |
|
111 } |
|
112 |
|
113 bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const |
|
114 { |
|
115 Binding *label_base, *this_base; |
|
116 uint64_t label_addend, this_addend; |
|
117 label.value_->Get(&label_base, &label_addend); |
|
118 value_->Get(&this_base, &this_addend); |
|
119 // If this and label are related, Get will find their final |
|
120 // common ancestor, regardless of how indirect the relation is. This |
|
121 // comparison also handles the constant vs. constant case. |
|
122 if (this_base != label_base) return false; |
|
123 if (offset_p) *offset_p = this_addend - label_addend; |
|
124 return true; |
|
125 } |
|
126 |
|
127 Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } |
|
128 |
|
129 Label::Binding::Binding(uint64_t addend) |
|
130 : base_(NULL), addend_(addend), reference_count_(1) { } |
|
131 |
|
132 Label::Binding::~Binding() { |
|
133 assert(reference_count_ == 0); |
|
134 if (base_ && base_ != this && base_->Release()) |
|
135 delete base_; |
|
136 } |
|
137 |
|
138 void Label::Binding::Set(Binding *binding, uint64_t addend) { |
|
139 if (!base_ && !binding) { |
|
140 // We're equating two constants. This could be okay. |
|
141 assert(addend_ == addend); |
|
142 } else if (!base_) { |
|
143 // We are a known constant, but BINDING may not be, so turn the |
|
144 // tables and try to set BINDING's value instead. |
|
145 binding->Set(NULL, addend_ - addend); |
|
146 } else { |
|
147 if (binding) { |
|
148 // Find binding's final value. Since the final value is always either |
|
149 // completely unconstrained or a constant, never a reference to |
|
150 // another variable (otherwise, it wouldn't be final), this |
|
151 // guarantees we won't create cycles here, even for code like this: |
|
152 // l = m, m = n, n = l; |
|
153 uint64_t binding_addend; |
|
154 binding->Get(&binding, &binding_addend); |
|
155 addend += binding_addend; |
|
156 } |
|
157 |
|
158 // It seems likely that setting a binding to itself is a bug |
|
159 // (although I can imagine this might turn out to be helpful to |
|
160 // permit). |
|
161 assert(binding != this); |
|
162 |
|
163 if (base_ != this) { |
|
164 // Set the other bindings on our chain as well. Note that this |
|
165 // is sufficient even though binding relationships form trees: |
|
166 // All binding operations traverse their chains to the end, and |
|
167 // all bindings related to us share some tail of our chain, so |
|
168 // they will see the changes we make here. |
|
169 base_->Set(binding, addend - addend_); |
|
170 // We're not going to use base_ any more. |
|
171 if (base_->Release()) delete base_; |
|
172 } |
|
173 |
|
174 // Adopt BINDING as our base. Note that it should be correct to |
|
175 // acquire here, after the release above, even though the usual |
|
176 // reference-counting rules call for acquiring first, and then |
|
177 // releasing: the self-reference assertion above should have |
|
178 // complained if BINDING were 'this' or anywhere along our chain, |
|
179 // so we didn't release BINDING. |
|
180 if (binding) binding->Acquire(); |
|
181 base_ = binding; |
|
182 addend_ = addend; |
|
183 } |
|
184 } |
|
185 |
|
186 void Label::Binding::Get(Binding **base, uint64_t *addend) { |
|
187 if (base_ && base_ != this) { |
|
188 // Recurse to find the end of our reference chain (the root of our |
|
189 // tree), and then rewrite every binding along the chain to refer |
|
190 // to it directly, adjusting addends appropriately. (This is why |
|
191 // this member function isn't this-const.) |
|
192 Binding *final_base; |
|
193 uint64_t final_addend; |
|
194 base_->Get(&final_base, &final_addend); |
|
195 if (final_base) final_base->Acquire(); |
|
196 if (base_->Release()) delete base_; |
|
197 base_ = final_base; |
|
198 addend_ += final_addend; |
|
199 } |
|
200 *base = base_; |
|
201 *addend = addend_; |
|
202 } |
|
203 |
|
204 template<typename Inserter> |
|
205 static inline void InsertEndian(test_assembler::Endianness endianness, |
|
206 size_t size, uint64_t number, Inserter dest) { |
|
207 assert(size > 0); |
|
208 if (endianness == kLittleEndian) { |
|
209 for (size_t i = 0; i < size; i++) { |
|
210 *dest++ = (char) (number & 0xff); |
|
211 number >>= 8; |
|
212 } |
|
213 } else { |
|
214 assert(endianness == kBigEndian); |
|
215 // The loop condition is odd, but it's correct for size_t. |
|
216 for (size_t i = size - 1; i < size; i--) |
|
217 *dest++ = (char) ((number >> (i * 8)) & 0xff); |
|
218 } |
|
219 } |
|
220 |
|
221 Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { |
|
222 InsertEndian(endianness, size, number, |
|
223 back_insert_iterator<string>(contents_)); |
|
224 return *this; |
|
225 } |
|
226 |
|
227 Section &Section::Append(Endianness endianness, size_t size, |
|
228 const Label &label) { |
|
229 // If this label's value is known, there's no reason to waste an |
|
230 // entry in references_ on it. |
|
231 uint64_t value; |
|
232 if (label.IsKnownConstant(&value)) |
|
233 return Append(endianness, size, value); |
|
234 |
|
235 // This will get caught when the references are resolved, but it's |
|
236 // nicer to find out earlier. |
|
237 assert(endianness != kUnsetEndian); |
|
238 |
|
239 references_.push_back(Reference(contents_.size(), endianness, size, label)); |
|
240 contents_.append(size, 0); |
|
241 return *this; |
|
242 } |
|
243 |
|
244 #define ENDIANNESS_L kLittleEndian |
|
245 #define ENDIANNESS_B kBigEndian |
|
246 #define ENDIANNESS(e) ENDIANNESS_ ## e |
|
247 |
|
248 #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ |
|
249 Section &Section::e ## bits(uint ## bits ## _t v) { \ |
|
250 InsertEndian(ENDIANNESS(e), bits / 8, v, \ |
|
251 back_insert_iterator<string>(contents_)); \ |
|
252 return *this; \ |
|
253 } |
|
254 |
|
255 #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ |
|
256 Section &Section::e ## bits(const Label &v) { \ |
|
257 return Append(ENDIANNESS(e), bits / 8, v); \ |
|
258 } |
|
259 |
|
260 // Define L16, B32, and friends. |
|
261 #define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ |
|
262 DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ |
|
263 DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) |
|
264 |
|
265 DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); |
|
266 DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); |
|
267 DEFINE_SHORT_APPEND_ENDIAN(L, 16); |
|
268 DEFINE_SHORT_APPEND_ENDIAN(L, 32); |
|
269 DEFINE_SHORT_APPEND_ENDIAN(L, 64); |
|
270 DEFINE_SHORT_APPEND_ENDIAN(B, 16); |
|
271 DEFINE_SHORT_APPEND_ENDIAN(B, 32); |
|
272 DEFINE_SHORT_APPEND_ENDIAN(B, 64); |
|
273 |
|
274 #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ |
|
275 Section &Section::D ## bits(uint ## bits ## _t v) { \ |
|
276 InsertEndian(endianness_, bits / 8, v, \ |
|
277 back_insert_iterator<string>(contents_)); \ |
|
278 return *this; \ |
|
279 } |
|
280 #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ |
|
281 Section &Section::D ## bits(const Label &v) { \ |
|
282 return Append(endianness_, bits / 8, v); \ |
|
283 } |
|
284 #define DEFINE_SHORT_APPEND_DEFAULT(bits) \ |
|
285 DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ |
|
286 DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) |
|
287 |
|
288 DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) |
|
289 DEFINE_SHORT_APPEND_DEFAULT(16); |
|
290 DEFINE_SHORT_APPEND_DEFAULT(32); |
|
291 DEFINE_SHORT_APPEND_DEFAULT(64); |
|
292 |
|
293 Section &Section::Append(const Section §ion) { |
|
294 size_t base = contents_.size(); |
|
295 contents_.append(section.contents_); |
|
296 for (vector<Reference>::const_iterator it = section.references_.begin(); |
|
297 it != section.references_.end(); it++) |
|
298 references_.push_back(Reference(base + it->offset, it->endianness, |
|
299 it->size, it->label)); |
|
300 return *this; |
|
301 } |
|
302 |
|
303 Section &Section::LEB128(long long value) { |
|
304 while (value < -0x40 || 0x3f < value) { |
|
305 contents_ += (value & 0x7f) | 0x80; |
|
306 if (value < 0) |
|
307 value = (value >> 7) | ~(((unsigned long long) -1) >> 7); |
|
308 else |
|
309 value = (value >> 7); |
|
310 } |
|
311 contents_ += value & 0x7f; |
|
312 return *this; |
|
313 } |
|
314 |
|
315 Section &Section::ULEB128(uint64_t value) { |
|
316 while (value > 0x7f) { |
|
317 contents_ += (value & 0x7f) | 0x80; |
|
318 value = (value >> 7); |
|
319 } |
|
320 contents_ += value; |
|
321 return *this; |
|
322 } |
|
323 |
|
324 Section &Section::Align(size_t alignment, uint8_t pad_byte) { |
|
325 // ALIGNMENT must be a power of two. |
|
326 assert(((alignment - 1) & alignment) == 0); |
|
327 size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); |
|
328 contents_.append(new_size - contents_.size(), pad_byte); |
|
329 assert((contents_.size() & (alignment - 1)) == 0); |
|
330 return *this; |
|
331 } |
|
332 |
|
333 void Section::Clear() { |
|
334 contents_.clear(); |
|
335 references_.clear(); |
|
336 } |
|
337 |
|
338 bool Section::GetContents(string *contents) { |
|
339 // For each label reference, find the label's value, and patch it into |
|
340 // the section's contents. |
|
341 for (size_t i = 0; i < references_.size(); i++) { |
|
342 Reference &r = references_[i]; |
|
343 uint64_t value; |
|
344 if (!r.label.IsKnownConstant(&value)) { |
|
345 fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); |
|
346 return false; |
|
347 } |
|
348 assert(r.offset < contents_.size()); |
|
349 assert(contents_.size() - r.offset >= r.size); |
|
350 InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); |
|
351 } |
|
352 contents->clear(); |
|
353 std::swap(contents_, *contents); |
|
354 references_.clear(); |
|
355 return true; |
|
356 } |
|
357 |
|
358 } // namespace test_assembler |
|
359 } // namespace google_breakpad |