xref: /aosp_15_r20/external/google-breakpad/src/common/test_assembler.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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