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