Home | History | Annotate | Download | only in common
      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 (at) mozilla.com> <jimb (at) 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 &section) {
    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
    360