1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 // * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // Original author: Jim Blandy <[email protected]> <[email protected]>
30
31 // test_assembler.cc: Implementation of google_breakpad::TestAssembler.
32 // See test_assembler.h for details.
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h> // Must come first
36 #endif
37
38 #include "common/test_assembler.h"
39
40 #include <assert.h>
41 #include <stdio.h>
42
43 #include <iterator>
44
45 namespace google_breakpad {
46 namespace test_assembler {
47
48 using std::back_insert_iterator;
49
Label()50 Label::Label() : value_(new Binding()) { }
Label(uint64_t value)51 Label::Label(uint64_t value) : value_(new Binding(value)) { }
Label(const Label & label)52 Label::Label(const Label& label) {
53 value_ = label.value_;
54 value_->Acquire();
55 }
~Label()56 Label::~Label() {
57 if (value_->Release()) delete value_;
58 }
59
operator =(uint64_t value)60 Label& Label::operator=(uint64_t value) {
61 value_->Set(NULL, value);
62 return *this;
63 }
64
operator =(const Label & label)65 Label& Label::operator=(const Label& label) {
66 value_->Set(label.value_, 0);
67 return *this;
68 }
69
operator +(uint64_t addend) const70 Label Label::operator+(uint64_t addend) const {
71 Label l;
72 l.value_->Set(this->value_, addend);
73 return l;
74 }
75
operator -(uint64_t subtrahend) const76 Label Label::operator-(uint64_t subtrahend) const {
77 Label l;
78 l.value_->Set(this->value_, -subtrahend);
79 return l;
80 }
81
82 // When NDEBUG is #defined, assert doesn't evaluate its argument. This
83 // means you can't simply use assert to check the return value of a
84 // function with necessary side effects.
85 //
86 // ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
87 // NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
88 // that x is true.
89 #ifdef NDEBUG
90 #define ALWAYS_EVALUATE_AND_ASSERT(x) x
91 #else
92 #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
93 #endif
94
operator -(const Label & label) const95 uint64_t Label::operator-(const Label& label) const {
96 uint64_t offset;
97 ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
98 return offset;
99 }
100
Value() const101 uint64_t Label::Value() const {
102 uint64_t v = 0;
103 ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
104 return v;
105 };
106
IsKnownConstant(uint64_t * value_p) const107 bool Label::IsKnownConstant(uint64_t* value_p) const {
108 Binding* base;
109 uint64_t addend;
110 value_->Get(&base, &addend);
111 if (base != NULL) return false;
112 if (value_p) *value_p = addend;
113 return true;
114 }
115
IsKnownOffsetFrom(const Label & label,uint64_t * offset_p) const116 bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const
117 {
118 Binding* label_base, *this_base;
119 uint64_t label_addend, this_addend;
120 label.value_->Get(&label_base, &label_addend);
121 value_->Get(&this_base, &this_addend);
122 // If this and label are related, Get will find their final
123 // common ancestor, regardless of how indirect the relation is. This
124 // comparison also handles the constant vs. constant case.
125 if (this_base != label_base) return false;
126 if (offset_p) *offset_p = this_addend - label_addend;
127 return true;
128 }
129
Binding()130 Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { }
131
Binding(uint64_t addend)132 Label::Binding::Binding(uint64_t addend)
133 : base_(NULL), addend_(addend), reference_count_(1) { }
134
~Binding()135 Label::Binding::~Binding() {
136 assert(reference_count_ == 0);
137 if (base_ && base_ != this && base_->Release())
138 delete base_;
139 }
140
Set(Binding * binding,uint64_t addend)141 void Label::Binding::Set(Binding* binding, uint64_t addend) {
142 if (!base_ && !binding) {
143 // We're equating two constants. This could be okay.
144 assert(addend_ == addend);
145 } else if (!base_) {
146 // We are a known constant, but BINDING may not be, so turn the
147 // tables and try to set BINDING's value instead.
148 binding->Set(NULL, addend_ - addend);
149 } else {
150 if (binding) {
151 // Find binding's final value. Since the final value is always either
152 // completely unconstrained or a constant, never a reference to
153 // another variable (otherwise, it wouldn't be final), this
154 // guarantees we won't create cycles here, even for code like this:
155 // l = m, m = n, n = l;
156 uint64_t binding_addend;
157 binding->Get(&binding, &binding_addend);
158 addend += binding_addend;
159 }
160
161 // It seems likely that setting a binding to itself is a bug
162 // (although I can imagine this might turn out to be helpful to
163 // permit).
164 assert(binding != this);
165
166 if (base_ != this) {
167 // Set the other bindings on our chain as well. Note that this
168 // is sufficient even though binding relationships form trees:
169 // All binding operations traverse their chains to the end, and
170 // all bindings related to us share some tail of our chain, so
171 // they will see the changes we make here.
172 base_->Set(binding, addend - addend_);
173 // We're not going to use base_ any more.
174 if (base_->Release()) delete base_;
175 }
176
177 // Adopt BINDING as our base. Note that it should be correct to
178 // acquire here, after the release above, even though the usual
179 // reference-counting rules call for acquiring first, and then
180 // releasing: the self-reference assertion above should have
181 // complained if BINDING were 'this' or anywhere along our chain,
182 // so we didn't release BINDING.
183 if (binding) binding->Acquire();
184 base_ = binding;
185 addend_ = addend;
186 }
187 }
188
Get(Binding ** base,uint64_t * addend)189 void Label::Binding::Get(Binding** base, uint64_t* addend) {
190 if (base_ && base_ != this) {
191 // Recurse to find the end of our reference chain (the root of our
192 // tree), and then rewrite every binding along the chain to refer
193 // to it directly, adjusting addends appropriately. (This is why
194 // this member function isn't this-const.)
195 Binding* final_base;
196 uint64_t final_addend;
197 base_->Get(&final_base, &final_addend);
198 if (final_base) final_base->Acquire();
199 if (base_->Release()) delete base_;
200 base_ = final_base;
201 addend_ += final_addend;
202 }
203 *base = base_;
204 *addend = addend_;
205 }
206
207 template<typename Inserter>
InsertEndian(test_assembler::Endianness endianness,size_t size,uint64_t number,Inserter dest)208 static inline void InsertEndian(test_assembler::Endianness endianness,
209 size_t size, uint64_t number, Inserter dest) {
210 assert(size > 0);
211 if (endianness == kLittleEndian) {
212 for (size_t i = 0; i < size; i++) {
213 *dest++ = (char) (number & 0xff);
214 number >>= 8;
215 }
216 } else {
217 assert(endianness == kBigEndian);
218 // The loop condition is odd, but it's correct for size_t.
219 for (size_t i = size - 1; i < size; i--)
220 *dest++ = (char) ((number >> (i * 8)) & 0xff);
221 }
222 }
223
Append(Endianness endianness,size_t size,uint64_t number)224 Section& Section::Append(Endianness endianness, size_t size, uint64_t number) {
225 InsertEndian(endianness, size, number,
226 back_insert_iterator<string>(contents_));
227 return *this;
228 }
229
Append(Endianness endianness,size_t size,const Label & label)230 Section& Section::Append(Endianness endianness, size_t size,
231 const Label& label) {
232 // If this label's value is known, there's no reason to waste an
233 // entry in references_ on it.
234 uint64_t value;
235 if (label.IsKnownConstant(&value))
236 return Append(endianness, size, value);
237
238 // This will get caught when the references are resolved, but it's
239 // nicer to find out earlier.
240 assert(endianness != kUnsetEndian);
241
242 references_.push_back(Reference(contents_.size(), endianness, size, label));
243 contents_.append(size, 0);
244 return *this;
245 }
246
247 #define ENDIANNESS_L kLittleEndian
248 #define ENDIANNESS_B kBigEndian
249 #define ENDIANNESS(e) ENDIANNESS_ ## e
250
251 #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
252 Section& Section::e ## bits(uint ## bits ## _t v) { \
253 InsertEndian(ENDIANNESS(e), bits / 8, v, \
254 back_insert_iterator<string>(contents_)); \
255 return *this; \
256 }
257
258 #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
259 Section& Section::e ## bits(const Label& v) { \
260 return Append(ENDIANNESS(e), bits / 8, v); \
261 }
262
263 // Define L16, B32, and friends.
264 #define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
265 DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
266 DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
267
268 DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
269 DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
270 DEFINE_SHORT_APPEND_ENDIAN(L, 16);
271 DEFINE_SHORT_APPEND_ENDIAN(L, 32);
272 DEFINE_SHORT_APPEND_ENDIAN(L, 64);
273 DEFINE_SHORT_APPEND_ENDIAN(B, 16);
274 DEFINE_SHORT_APPEND_ENDIAN(B, 32);
275 DEFINE_SHORT_APPEND_ENDIAN(B, 64);
276
277 #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
278 Section& Section::D ## bits(uint ## bits ## _t v) { \
279 InsertEndian(endianness_, bits / 8, v, \
280 back_insert_iterator<string>(contents_)); \
281 return *this; \
282 }
283 #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
284 Section& Section::D ## bits(const Label& v) { \
285 return Append(endianness_, bits / 8, v); \
286 }
287 #define DEFINE_SHORT_APPEND_DEFAULT(bits) \
288 DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
289 DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
290
291 DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
292 DEFINE_SHORT_APPEND_DEFAULT(16);
293 DEFINE_SHORT_APPEND_DEFAULT(32);
294 DEFINE_SHORT_APPEND_DEFAULT(64);
295
Append(const Section & section)296 Section& Section::Append(const Section& section) {
297 size_t base = contents_.size();
298 contents_.append(section.contents_);
299 for (vector<Reference>::const_iterator it = section.references_.begin();
300 it != section.references_.end(); it++)
301 references_.push_back(Reference(base + it->offset, it->endianness,
302 it->size, it->label));
303 return *this;
304 }
305
LEB128(long long value)306 Section& Section::LEB128(long long value) {
307 while (value < -0x40 || 0x3f < value) {
308 contents_ += (value & 0x7f) | 0x80;
309 if (value < 0)
310 value = (value >> 7) | ~(((unsigned long long) -1) >> 7);
311 else
312 value = (value >> 7);
313 }
314 contents_ += value & 0x7f;
315 return *this;
316 }
317
ULEB128(uint64_t value)318 Section& Section::ULEB128(uint64_t value) {
319 while (value > 0x7f) {
320 contents_ += (value & 0x7f) | 0x80;
321 value = (value >> 7);
322 }
323 contents_ += value;
324 return *this;
325 }
326
Align(size_t alignment,uint8_t pad_byte)327 Section& Section::Align(size_t alignment, uint8_t pad_byte) {
328 // ALIGNMENT must be a power of two.
329 assert(((alignment - 1) & alignment) == 0);
330 size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
331 contents_.append(new_size - contents_.size(), pad_byte);
332 assert((contents_.size() & (alignment - 1)) == 0);
333 return *this;
334 }
335
Clear()336 void Section::Clear() {
337 contents_.clear();
338 references_.clear();
339 }
340
GetContents(string * contents)341 bool Section::GetContents(string* contents) {
342 // For each label reference, find the label's value, and patch it into
343 // the section's contents.
344 for (size_t i = 0; i < references_.size(); i++) {
345 Reference& r = references_[i];
346 uint64_t value;
347 if (!r.label.IsKnownConstant(&value)) {
348 fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
349 return false;
350 }
351 assert(r.offset < contents_.size());
352 assert(contents_.size() - r.offset >= r.size);
353 InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
354 }
355 contents->clear();
356 std::swap(contents_, *contents);
357 references_.clear();
358 return true;
359 }
360
361 } // namespace test_assembler
362 } // namespace google_breakpad
363