aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/dwarf/cfi_assembler.h2
-rw-r--r--src/common/test_assembler.cc357
-rw-r--r--src/common/test_assembler.h472
-rw-r--r--src/common/test_assembler_unittest.cc1644
4 files changed, 2474 insertions, 1 deletions
diff --git a/src/common/dwarf/cfi_assembler.h b/src/common/dwarf/cfi_assembler.h
index f5bf9710..7ec1a109 100644
--- a/src/common/dwarf/cfi_assembler.h
+++ b/src/common/dwarf/cfi_assembler.h
@@ -40,8 +40,8 @@
#include <string>
#include "common/dwarf/dwarf2enums.h"
+#include "common/test_assembler.h"
#include "google_breakpad/common/breakpad_types.h"
-#include "processor/test_assembler.h"
namespace google_breakpad {
diff --git a/src/common/test_assembler.cc b/src/common/test_assembler.cc
new file mode 100644
index 00000000..3fd7cad0
--- /dev/null
+++ b/src/common/test_assembler.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test_assembler.cc: Implementation of google_breakpad::TestAssembler.
+// See test_assembler.h for details.
+
+#include <cassert>
+#include <cstdio>
+#include <iterator>
+
+#include "common/test_assembler.h"
+
+namespace google_breakpad {
+namespace TestAssembler {
+
+using std::back_insert_iterator;
+
+Label::Label() : value_(new Binding()) { }
+Label::Label(u_int64_t value) : value_(new Binding(value)) { }
+Label::Label(const Label &label) {
+ value_ = label.value_;
+ value_->Acquire();
+}
+Label::~Label() {
+ if (value_->Release()) delete value_;
+}
+
+Label &Label::operator=(u_int64_t value) {
+ value_->Set(NULL, value);
+ return *this;
+}
+
+Label &Label::operator=(const Label &label) {
+ value_->Set(label.value_, 0);
+ return *this;
+}
+
+Label Label::operator+(u_int64_t addend) const {
+ Label l;
+ l.value_->Set(this->value_, addend);
+ return l;
+}
+
+Label Label::operator-(u_int64_t subtrahend) const {
+ Label l;
+ l.value_->Set(this->value_, -subtrahend);
+ return l;
+}
+
+// When NDEBUG is #defined, assert doesn't evaluate its argument. This
+// means you can't simply use assert to check the return value of a
+// function with necessary side effects.
+//
+// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
+// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
+// that x is true.
+#ifdef NDEBUG
+#define ALWAYS_EVALUATE_AND_ASSERT(x) x
+#else
+#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
+#endif
+
+u_int64_t Label::operator-(const Label &label) const {
+ u_int64_t offset;
+ ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
+ return offset;
+}
+
+u_int64_t Label::Value() const {
+ u_int64_t v;
+ ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
+ return v;
+};
+
+bool Label::IsKnownConstant(u_int64_t *value_p) const {
+ Binding *base;
+ u_int64_t addend;
+ value_->Get(&base, &addend);
+ if (base != NULL) return false;
+ if (value_p) *value_p = addend;
+ return true;
+}
+
+bool Label::IsKnownOffsetFrom(const Label &label, u_int64_t *offset_p) const
+{
+ Binding *label_base, *this_base;
+ u_int64_t label_addend, this_addend;
+ label.value_->Get(&label_base, &label_addend);
+ value_->Get(&this_base, &this_addend);
+ // If this and label are related, Get will find their final
+ // common ancestor, regardless of how indirect the relation is. This
+ // comparison also handles the constant vs. constant case.
+ if (this_base != label_base) return false;
+ if (offset_p) *offset_p = this_addend - label_addend;
+ return true;
+}
+
+Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { }
+
+Label::Binding::Binding(u_int64_t addend)
+ : base_(NULL), addend_(addend), reference_count_(1) { }
+
+Label::Binding::~Binding() {
+ assert(reference_count_ == 0);
+ if (base_ && base_ != this && base_->Release())
+ delete base_;
+}
+
+void Label::Binding::Set(Binding *binding, u_int64_t addend) {
+ if (!base_ && !binding) {
+ // We're equating two constants. This could be okay.
+ assert(addend_ == addend);
+ } else if (!base_) {
+ // We are a known constant, but BINDING may not be, so turn the
+ // tables and try to set BINDING's value instead.
+ binding->Set(NULL, addend_ - addend);
+ } else {
+ if (binding) {
+ // Find binding's final value. Since the final value is always either
+ // completely unconstrained or a constant, never a reference to
+ // another variable (otherwise, it wouldn't be final), this
+ // guarantees we won't create cycles here, even for code like this:
+ // l = m, m = n, n = l;
+ u_int64_t binding_addend;
+ binding->Get(&binding, &binding_addend);
+ addend += binding_addend;
+ }
+
+ // It seems likely that setting a binding to itself is a bug
+ // (although I can imagine this might turn out to be helpful to
+ // permit).
+ assert(binding != this);
+
+ if (base_ != this) {
+ // Set the other bindings on our chain as well. Note that this
+ // is sufficient even though binding relationships form trees:
+ // All binding operations traverse their chains to the end, and
+ // all bindings related to us share some tail of our chain, so
+ // they will see the changes we make here.
+ base_->Set(binding, addend - addend_);
+ // We're not going to use base_ any more.
+ if (base_->Release()) delete base_;
+ }
+
+ // Adopt BINDING as our base. Note that it should be correct to
+ // acquire here, after the release above, even though the usual
+ // reference-counting rules call for acquiring first, and then
+ // releasing: the self-reference assertion above should have
+ // complained if BINDING were 'this' or anywhere along our chain,
+ // so we didn't release BINDING.
+ if (binding) binding->Acquire();
+ base_ = binding;
+ addend_ = addend;
+ }
+}
+
+void Label::Binding::Get(Binding **base, u_int64_t *addend) {
+ if (base_ && base_ != this) {
+ // Recurse to find the end of our reference chain (the root of our
+ // tree), and then rewrite every binding along the chain to refer
+ // to it directly, adjusting addends appropriately. (This is why
+ // this member function isn't this-const.)
+ Binding *final_base;
+ u_int64_t final_addend;
+ base_->Get(&final_base, &final_addend);
+ if (final_base) final_base->Acquire();
+ if (base_->Release()) delete base_;
+ base_ = final_base;
+ addend_ += final_addend;
+ }
+ *base = base_;
+ *addend = addend_;
+}
+
+template<typename Inserter>
+static inline void InsertEndian(TestAssembler::Endianness endianness,
+ size_t size, u_int64_t number, Inserter dest) {
+ if (endianness == kLittleEndian) {
+ for (size_t i = 0; i < size; i++) {
+ *dest++ = (char) (number & 0xff);
+ number >>= 8;
+ }
+ } else {
+ assert(endianness == kBigEndian);
+ // The loop condition is odd, but it's correct for size_t.
+ for (size_t i = size - 1; i < size; i--)
+ *dest++ = (char) ((number >> (i * 8)) & 0xff);
+ }
+}
+
+Section &Section::Append(Endianness endianness, size_t size, u_int64_t number) {
+ InsertEndian(endianness, size, number,
+ back_insert_iterator<string>(contents_));
+ return *this;
+}
+
+Section &Section::Append(Endianness endianness, size_t size,
+ const Label &label) {
+ // If this label's value is known, there's no reason to waste an
+ // entry in references_ on it.
+ u_int64_t value;
+ if (label.IsKnownConstant(&value))
+ return Append(endianness, size, value);
+
+ // This will get caught when the references are resolved, but it's
+ // nicer to find out earlier.
+ assert(endianness != kUnsetEndian);
+
+ references_.push_back(Reference(contents_.size(), endianness, size, label));
+ contents_.append(size, 0);
+ return *this;
+}
+
+#define ENDIANNESS_L kLittleEndian
+#define ENDIANNESS_B kBigEndian
+#define ENDIANNESS(e) ENDIANNESS_ ## e
+
+#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
+ Section &Section::e ## bits(u_int ## bits ## _t v) { \
+ InsertEndian(ENDIANNESS(e), bits / 8, v, \
+ back_insert_iterator<string>(contents_)); \
+ return *this; \
+ }
+
+#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
+ Section &Section::e ## bits(const Label &v) { \
+ return Append(ENDIANNESS(e), bits / 8, v); \
+ }
+
+// Define L16, B32, and friends.
+#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
+ DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
+ DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
+
+DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
+DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
+DEFINE_SHORT_APPEND_ENDIAN(L, 16);
+DEFINE_SHORT_APPEND_ENDIAN(L, 32);
+DEFINE_SHORT_APPEND_ENDIAN(L, 64);
+DEFINE_SHORT_APPEND_ENDIAN(B, 16);
+DEFINE_SHORT_APPEND_ENDIAN(B, 32);
+DEFINE_SHORT_APPEND_ENDIAN(B, 64);
+
+#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
+ Section &Section::D ## bits(u_int ## bits ## _t v) { \
+ InsertEndian(endianness_, bits / 8, v, \
+ back_insert_iterator<string>(contents_)); \
+ return *this; \
+ }
+#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
+ Section &Section::D ## bits(const Label &v) { \
+ return Append(endianness_, bits / 8, v); \
+ }
+#define DEFINE_SHORT_APPEND_DEFAULT(bits) \
+ DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
+ DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
+
+DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
+DEFINE_SHORT_APPEND_DEFAULT(16);
+DEFINE_SHORT_APPEND_DEFAULT(32);
+DEFINE_SHORT_APPEND_DEFAULT(64);
+
+Section &Section::Append(const Section &section) {
+ size_t base = contents_.size();
+ contents_.append(section.contents_);
+ for (vector<Reference>::const_iterator it = section.references_.begin();
+ it != section.references_.end(); it++)
+ references_.push_back(Reference(base + it->offset, it->endianness,
+ it->size, it->label));
+ return *this;
+}
+
+Section &Section::LEB128(long long value) {
+ while (value < -0x40 || 0x3f < value) {
+ contents_ += (value & 0x7f) | 0x80;
+ if (value < 0)
+ value = (value >> 7) | ~(((unsigned long long) -1) >> 7);
+ else
+ value = (value >> 7);
+ }
+ contents_ += value & 0x7f;
+ return *this;
+}
+
+Section &Section::ULEB128(u_int64_t value) {
+ while (value > 0x7f) {
+ contents_ += (value & 0x7f) | 0x80;
+ value = (value >> 7);
+ }
+ contents_ += value;
+ return *this;
+}
+
+Section &Section::Align(size_t alignment, u_int8_t pad_byte) {
+ // ALIGNMENT must be a power of two.
+ assert(((alignment - 1) & alignment) == 0);
+ size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
+ contents_.append(new_size - contents_.size(), pad_byte);
+ assert((contents_.size() & (alignment - 1)) == 0);
+ return *this;
+}
+
+void Section::Clear() {
+ contents_.clear();
+ references_.clear();
+}
+
+bool Section::GetContents(string *contents) {
+ // For each label reference, find the label's value, and patch it into
+ // the section's contents.
+ for (size_t i = 0; i < references_.size(); i++) {
+ Reference &r = references_[i];
+ u_int64_t value;
+ if (!r.label.IsKnownConstant(&value)) {
+ fprintf(stderr, "Undefined label #%d at offset 0x%x\n", i, r.offset);
+ return false;
+ }
+ assert(r.offset < contents_.size());
+ assert(contents_.size() - r.offset >= r.size);
+ InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
+ }
+ contents->clear();
+ std::swap(contents_, *contents);
+ references_.clear();
+ return true;
+}
+
+} // namespace TestAssembler
+} // namespace google_breakpad
diff --git a/src/common/test_assembler.h b/src/common/test_assembler.h
new file mode 100644
index 00000000..560f7aef
--- /dev/null
+++ b/src/common/test_assembler.h
@@ -0,0 +1,472 @@
+// -*- mode: C++ -*-
+
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test-assembler.h: interface to class for building complex binary streams.
+
+// To test the Breakpad symbol dumper and processor thoroughly, for
+// all combinations of host system and minidump processor
+// architecture, we need to be able to easily generate complex test
+// data like debugging information and minidump files.
+//
+// For example, if we want our unit tests to provide full code
+// coverage for stack walking, it may be difficult to persuade the
+// compiler to generate every possible sort of stack walking
+// information that we want to support; there are probably DWARF CFI
+// opcodes that GCC never emits. Similarly, if we want to test our
+// error handling, we will need to generate damaged minidumps or
+// debugging information that (we hope) the client or compiler will
+// never produce on its own.
+//
+// google_breakpad::TestAssembler provides a predictable and
+// (relatively) simple way to generate complex formatted data streams
+// like minidumps and CFI. Furthermore, because TestAssembler is
+// portable, developers without access to (say) Visual Studio or a
+// SPARC assembler can still work on test data for those targets.
+
+#ifndef PROCESSOR_TEST_ASSEMBLER_H_
+#define PROCESSOR_TEST_ASSEMBLER_H_
+
+#include <list>
+#include <vector>
+#include <string>
+
+#include "google_breakpad/common/breakpad_types.h"
+
+namespace google_breakpad {
+
+using std::list;
+using std::string;
+using std::vector;
+
+namespace TestAssembler {
+
+// A Label represents a value not yet known that we need to store in a
+// section. As long as all the labels a section refers to are defined
+// by the time we retrieve its contents as bytes, we can use undefined
+// labels freely in that section's construction.
+//
+// A label can be in one of three states:
+// - undefined,
+// - defined as the sum of some other label and a constant, or
+// - a constant.
+//
+// A label's value never changes, but it can accumulate constraints.
+// Adding labels and integers is permitted, and yields a label.
+// Subtracting a constant from a label is permitted, and also yields a
+// label. Subtracting two labels that have some relationship to each
+// other is permitted, and yields a constant.
+//
+// For example:
+//
+// Label a; // a's value is undefined
+// Label b; // b's value is undefined
+// {
+// Label c = a + 4; // okay, even though a's value is unknown
+// b = c + 4; // also okay; b is now a+8
+// }
+// Label d = b - 2; // okay; d == a+6, even though c is gone
+// d.Value(); // error: d's value is not yet known
+// d - a; // is 6, even though their values are not known
+// a = 12; // now b == 20, and d == 18
+// d.Value(); // 18: no longer an error
+// b.Value(); // 20
+// d = 10; // error: d is already defined.
+//
+// Label objects' lifetimes are unconstrained: notice that, in the
+// above example, even though a and b are only related through c, and
+// c goes out of scope, the assignment to a sets b's value as well. In
+// particular, it's not necessary to ensure that a Label lives beyond
+// Sections that refer to it.
+class Label {
+ public:
+ Label(); // An undefined label.
+ Label(u_int64_t value); // A label with a fixed value
+ Label(const Label &value); // A label equal to another.
+ ~Label();
+
+ // Return this label's value; it must be known.
+ //
+ // Providing this as a cast operator is nifty, but the conversions
+ // happen in unexpected places. In particular, ISO C++ says that
+ // Label + size_t becomes ambigious, because it can't decide whether
+ // to convert the Label to a u_int64_t and then to a size_t, or use
+ // the overloaded operator that returns a new label, even though the
+ // former could fail if the label is not yet defined and the latter won't.
+ u_int64_t Value() const;
+
+ Label &operator=(u_int64_t value);
+ Label &operator=(const Label &value);
+ Label operator+(u_int64_t addend) const;
+ Label operator-(u_int64_t subtrahend) const;
+ u_int64_t operator-(const Label &subtrahend) const;
+
+ // We could also provide == and != that work on undefined, but
+ // related, labels.
+
+ // Return true if this label's value is known. If VALUE_P is given,
+ // set *VALUE_P to the known value if returning true.
+ bool IsKnownConstant(u_int64_t *value_p = NULL) const;
+
+ // Return true if the offset from LABEL to this label is known. If
+ // OFFSET_P is given, set *OFFSET_P to the offset when returning true.
+ //
+ // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m',
+ // except that it also returns a value indicating whether the
+ // subtraction is possible given what we currently know of l and m.
+ // It can be possible even if we don't know l and m's values. For
+ // example:
+ //
+ // Label l, m;
+ // m = l + 10;
+ // l.IsKnownConstant(); // false
+ // m.IsKnownConstant(); // false
+ // u_int64_t d;
+ // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10.
+ // l-m // -10
+ // m-l // 10
+ // m.Value() // error: m's value is not known
+ bool IsKnownOffsetFrom(const Label &label, u_int64_t *offset_p = NULL) const;
+
+ private:
+ // A label's value, or if that is not yet known, how the value is
+ // related to other labels' values. A binding may be:
+ // - a known constant,
+ // - constrained to be equal to some other binding plus a constant, or
+ // - unconstrained, and free to take on any value.
+ //
+ // Many labels may point to a single binding, and each binding may
+ // refer to another, so bindings and labels form trees whose leaves
+ // are labels, whose interior nodes (and roots) are bindings, and
+ // where links point from children to parents. Bindings are
+ // reference counted, allowing labels to be lightweight, copyable,
+ // assignable, placed in containers, and so on.
+ class Binding {
+ public:
+ Binding();
+ Binding(u_int64_t addend);
+ ~Binding();
+
+ // Increment our reference count.
+ void Acquire() { reference_count_++; };
+ // Decrement our reference count, and return true if it is zero.
+ bool Release() { return --reference_count_ == 0; }
+
+ // Set this binding to be equal to BINDING + ADDEND. If BINDING is
+ // NULL, then set this binding to the known constant ADDEND.
+ // Update every binding on this binding's chain to point directly
+ // to BINDING, or to be a constant, with addends adjusted
+ // appropriately.
+ void Set(Binding *binding, u_int64_t value);
+
+ // Return what we know about the value of this binding.
+ // - If this binding's value is a known constant, set BASE to
+ // NULL, and set ADDEND to its value.
+ // - If this binding is not a known constant but related to other
+ // bindings, set BASE to the binding at the end of the relation
+ // chain (which will always be unconstrained), and set ADDEND to the
+ // value to add to that binding's value to get this binding's
+ // value.
+ // - If this binding is unconstrained, set BASE to this, and leave
+ // ADDEND unchanged.
+ void Get(Binding **base, u_int64_t *addend);
+
+ private:
+ // There are three cases:
+ //
+ // - A binding representing a known constant value has base_ NULL,
+ // and addend_ equal to the value.
+ //
+ // - A binding representing a completely unconstrained value has
+ // base_ pointing to this; addend_ is unused.
+ //
+ // - A binding whose value is related to some other binding's
+ // value has base_ pointing to that other binding, and addend_
+ // set to the amount to add to that binding's value to get this
+ // binding's value. We only represent relationships of the form
+ // x = y+c.
+ //
+ // Thus, the bind_ links form a chain terminating in either a
+ // known constant value or a completely unconstrained value. Most
+ // operations on bindings do path compression: they change every
+ // binding on the chain to point directly to the final value,
+ // adjusting addends as appropriate.
+ Binding *base_;
+ u_int64_t addend_;
+
+ // The number of Labels and Bindings pointing to this binding.
+ // (When a binding points to itself, indicating a completely
+ // unconstrained binding, that doesn't count as a reference.)
+ int reference_count_;
+ };
+
+ // This label's value.
+ Binding *value_;
+};
+
+inline Label operator+(u_int64_t a, const Label &l) { return l + a; }
+// Note that int-Label isn't defined, as negating a Label is not an
+// operation we support.
+
+// Conventions for representing larger numbers as sequences of bytes.
+enum Endianness {
+ kBigEndian, // Big-endian: the most significant byte comes first.
+ kLittleEndian, // Little-endian: the least significant byte comes first.
+ kUnsetEndian, // used internally
+};
+
+// A section is a sequence of bytes, constructed by appending bytes
+// to the end. Sections have a convenient and flexible set of member
+// functions for appending data in various formats: big-endian and
+// little-endian signed and unsigned values of different sizes;
+// LEB128 and ULEB128 values (see below), and raw blocks of bytes.
+//
+// If you need to append a value to a section that is not convenient
+// to compute immediately, you can create a label, append the
+// label's value to the section, and then set the label's value
+// later, when it's convenient to do so. Once a label's value is
+// known, the section class takes care of updating all previously
+// appended references to it.
+//
+// Once all the labels to which a section refers have had their
+// values determined, you can get a copy of the section's contents
+// as a string.
+//
+// Note that there is no specified "start of section" label. This is
+// because there are typically several different meanings for "the
+// start of a section": the offset of the section within an object
+// file, the address in memory at which the section's content appear,
+// and so on. It's up to the code that uses the Section class to
+// keep track of these explicitly, as they depend on the application.
+class Section {
+ public:
+ Section(Endianness endianness = kUnsetEndian)
+ : endianness_(endianness) { };
+ ~Section() { };
+
+ // Set the default endianness of this section to ENDIANNESS. This
+ // sets the behavior of the D<N> appending functions. If the
+ // assembler's default endianness was set, this is the
+ void set_endianness(Endianness endianness) {
+ endianness_ = endianness;
+ }
+
+ // Return the default endianness of this section.
+ Endianness endianness() const { return endianness_; }
+
+ // Append the SIZE bytes at DATA or the contents of STRING to the
+ // end of this section. Return a reference to this section.
+ Section &Append(const u_int8_t *data, size_t size) {
+ contents_.append(reinterpret_cast<const char *>(data), size);
+ return *this;
+ };
+ Section &Append(const string &data) {
+ contents_.append(data);
+ return *this;
+ };
+
+ // Append SIZE copies of BYTE to the end of this section. Return a
+ // reference to this section.
+ Section &Append(size_t size, u_int8_t byte) {
+ contents_.append(size, (char) byte);
+ return *this;
+ }
+
+ // Append NUMBER to this section. ENDIANNESS is the endianness to
+ // use to write the number. SIZE is the length of the number in
+ // bytes. Return a reference to this section.
+ Section &Append(Endianness endianness, size_t size, u_int64_t number);
+ Section &Append(Endianness endianness, size_t size, const Label &label);
+
+ // Append SECTION to the end of this section. The labels SECTION
+ // refers to need not be defined yet.
+ //
+ // Note that this has no effect on any Labels' values, or on
+ // SECTION. If placing SECTION within 'this' provides new
+ // constraints on existing labels' values, then it's up to the
+ // caller to fiddle with those labels as needed.
+ Section &Append(const Section &section);
+
+ // Append the contents of DATA as a series of bytes terminated by
+ // a NULL character.
+ Section &AppendCString(const string &data) {
+ Append(data);
+ contents_ += '\0';
+ return *this;
+ }
+
+ // Append VALUE or LABEL to this section, with the given bit width and
+ // endianness. Return a reference to this section.
+ //
+ // The names of these functions have the form <ENDIANNESS><BITWIDTH>:
+ // <ENDIANNESS> is either 'L' (little-endian, least significant byte first),
+ // 'B' (big-endian, most significant byte first), or
+ // 'D' (default, the section's default endianness)
+ // <BITWIDTH> is 8, 16, 32, or 64.
+ //
+ // Since endianness doesn't matter for a single byte, all the
+ // <BITWIDTH>=8 functions are equivalent.
+ //
+ // These can be used to write both signed and unsigned values, as
+ // the compiler will properly sign-extend a signed value before
+ // passing it to the function, at which point the function's
+ // behavior is the same either way.
+ Section &L8(u_int8_t value) { contents_ += value; return *this; }
+ Section &B8(u_int8_t value) { contents_ += value; return *this; }
+ Section &D8(u_int8_t value) { contents_ += value; return *this; }
+ Section &L16(u_int16_t), &L32(u_int32_t), &L64(u_int64_t),
+ &B16(u_int16_t), &B32(u_int32_t), &B64(u_int64_t),
+ &D16(u_int16_t), &D32(u_int32_t), &D64(u_int64_t);
+ Section &L8(const Label &label), &L16(const Label &label),
+ &L32(const Label &label), &L64(const Label &label),
+ &B8(const Label &label), &B16(const Label &label),
+ &B32(const Label &label), &B64(const Label &label),
+ &D8(const Label &label), &D16(const Label &label),
+ &D32(const Label &label), &D64(const Label &label);
+
+ // Append VALUE in a signed LEB128 (Little-Endian Base 128) form.
+ //
+ // The signed LEB128 representation of an integer N is a variable
+ // number of bytes:
+ //
+ // - If N is between -0x40 and 0x3f, then its signed LEB128
+ // representation is a single byte whose value is N.
+ //
+ // - Otherwise, its signed LEB128 representation is (N & 0x7f) |
+ // 0x80, followed by the signed LEB128 representation of N / 128,
+ // rounded towards negative infinity.
+ //
+ // In other words, we break VALUE into groups of seven bits, put
+ // them in little-endian order, and then write them as eight-bit
+ // bytes with the high bit on all but the last.
+ //
+ // Note that VALUE cannot be a Label (we would have to implement
+ // relaxation).
+ Section &LEB128(long long value);
+
+ // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form.
+ //
+ // The unsigned LEB128 representation of an integer N is a variable
+ // number of bytes:
+ //
+ // - If N is between 0 and 0x7f, then its unsigned LEB128
+ // representation is a single byte whose value is N.
+ //
+ // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) |
+ // 0x80, followed by the unsigned LEB128 representation of N /
+ // 128, rounded towards negative infinity.
+ //
+ // Note that VALUE cannot be a Label (we would have to implement
+ // relaxation).
+ Section &ULEB128(u_int64_t value);
+
+ // Jump to the next location aligned on an ALIGNMENT-byte boundary,
+ // relative to the start of the section. Fill the gap with PAD_BYTE.
+ // ALIGNMENT must be a power of two. Return a reference to this
+ // section.
+ Section &Align(size_t alignment, u_int8_t pad_byte = 0);
+
+ // Clear the contents of this section.
+ void Clear();
+
+ // Return the current size of the section.
+ size_t Size() const { return contents_.size(); }
+
+ // Return a label representing the start of the section.
+ //
+ // It is up to the user whether this label represents the section's
+ // position in an object file, the section's address in memory, or
+ // what have you; some applications may need both, in which case
+ // this simple-minded interface won't be enough. This class only
+ // provides a single start label, for use with the Here and Mark
+ // member functions.
+ //
+ // Ideally, we'd provide this in a subclass that actually knows more
+ // about the application at hand and can provide an appropriate
+ // collection of start labels. But then the appending member
+ // functions like Append and D32 would return a reference to the
+ // base class, not the derived class, and the chaining won't work.
+ // Since the only value here is in pretty notation, that's a fatal
+ // flaw.
+ Label start() const { return start_; }
+
+ // Return a label representing the point at which the next Appended
+ // item will appear in the section, relative to start().
+ Label Here() const { return start_ + Size(); }
+
+ // Set *LABEL to Here, and return a reference to this section.
+ Section &Mark(Label *label) { *label = Here(); return *this; }
+
+ // If there are no undefined label references left in this
+ // section, set CONTENTS to the contents of this section, as a
+ // string, and clear this section. Return true on success, or false
+ // if there were still undefined labels.
+ bool GetContents(string *contents);
+
+ private:
+ // Used internally. A reference to a label's value.
+ struct Reference {
+ Reference(size_t set_offset, Endianness set_endianness, size_t set_size,
+ const Label &set_label)
+ : offset(set_offset), endianness(set_endianness), size(set_size),
+ label(set_label) { }
+
+ // The offset of the reference within the section.
+ size_t offset;
+
+ // The endianness of the reference.
+ Endianness endianness;
+
+ // The size of the reference.
+ size_t size;
+
+ // The label to which this is a reference.
+ Label label;
+ };
+
+ // The default endianness of this section.
+ Endianness endianness_;
+
+ // The contents of the section.
+ string contents_;
+
+ // References to labels within those contents.
+ vector<Reference> references_;
+
+ // A label referring to the beginning of the section.
+ Label start_;
+};
+
+} // namespace TestAssembler
+} // namespace google_breakpad
+
+#endif // PROCESSOR_TEST_ASSEMBLER_H_
diff --git a/src/common/test_assembler_unittest.cc b/src/common/test_assembler_unittest.cc
new file mode 100644
index 00000000..9b6990ce
--- /dev/null
+++ b/src/common/test_assembler_unittest.cc
@@ -0,0 +1,1644 @@
+// Copyright (c) 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
+
+// test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler.
+
+#include <string>
+#include <string.h>
+
+#include "breakpad_googletest_includes.h"
+#include "common/test_assembler.h"
+
+using google_breakpad::TestAssembler::Label;
+using google_breakpad::TestAssembler::Section;
+using google_breakpad::TestAssembler::kBigEndian;
+using google_breakpad::TestAssembler::kLittleEndian;
+using std::string;
+using testing::Test;
+
+TEST(ConstructLabel, Simple) {
+ Label l;
+}
+
+TEST(ConstructLabel, Undefined) {
+ Label l;
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(ConstructLabelDeathTest, Undefined) {
+ Label l;
+ ASSERT_DEATH(l.Value(), "IsKnownConstant\\(&v\\)");
+}
+
+TEST(ConstructLabel, Constant) {
+ Label l(0x060b9f974eaf301eULL);
+ u_int64_t v;
+ EXPECT_TRUE(l.IsKnownConstant(&v));
+ EXPECT_EQ(v, 0x060b9f974eaf301eULL);
+ EXPECT_EQ(l.Value(), 0x060b9f974eaf301eULL);
+}
+
+TEST(ConstructLabel, Copy) {
+ Label l;
+ Label m(l);
+ u_int64_t v;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &v));
+ EXPECT_EQ(0U, v);
+}
+
+// The left-hand-side of a label assignment can be either
+// unconstrained, related, or known. The right-hand-side can be any of
+// those, or an integer.
+TEST(Assignment, UnconstrainedToUnconstrained) {
+ Label l, m;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ u_int64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, UnconstrainedToRelated) {
+ Label l, m, n;
+ l = n;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ u_int64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, UnconstrainedToKnown) {
+ Label l, m;
+ l = 0x8fd16e55b20a39c1ULL;
+ l = m;
+ EXPECT_EQ(0U, l-m);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+ u_int64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x8fd16e55b20a39c1ULL, m.Value());
+}
+
+TEST(Assignment, RelatedToUnconstrained) {
+ Label l, m, n;
+ m = n;
+ l = m;
+ EXPECT_EQ(0U, l-n);
+ EXPECT_TRUE(l.IsKnownOffsetFrom(n));
+ u_int64_t d;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(n, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, RelatedToRelated) {
+ Label l, m, n, o;
+ l = n;
+ m = o;
+ l = m;
+ EXPECT_EQ(0U, n-o);
+ EXPECT_TRUE(n.IsKnownOffsetFrom(o));
+ u_int64_t d;
+ EXPECT_TRUE(n.IsKnownOffsetFrom(o, &d));
+ EXPECT_EQ(0U, d);
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(Assignment, RelatedToKnown) {
+ Label l, m, n;
+ m = n;
+ l = 0xd2011f8c82ad56f2ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, m.Value());
+ EXPECT_TRUE(n.IsKnownConstant());
+ EXPECT_EQ(0xd2011f8c82ad56f2ULL, n.Value());
+}
+
+TEST(Assignment, KnownToUnconstrained) {
+ Label l, m;
+ m = 0x50b024c0d6073887ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x50b024c0d6073887ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x50b024c0d6073887ULL, m.Value());
+}
+
+TEST(Assignment, KnownToRelated) {
+ Label l, m, n;
+ l = n;
+ m = 0x5348883655c727e5ULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, m.Value());
+ EXPECT_TRUE(n.IsKnownConstant());
+ EXPECT_EQ(0x5348883655c727e5ULL, n.Value());
+}
+
+TEST(Assignment, KnownToKnown) {
+ Label l, m;
+ l = 0x36c209c20987564eULL;
+ m = 0x36c209c20987564eULL;
+ l = m;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x36c209c20987564eULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x36c209c20987564eULL, m.Value());
+}
+
+TEST(Assignment, ConstantToUnconstrained) {
+ Label l;
+ l = 0xc02495f4d7f5a957ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xc02495f4d7f5a957ULL, l.Value());
+}
+
+TEST(Assignment, ConstantToRelated) {
+ Label l, m;
+ l = m;
+ l = 0x4577901cf275488dULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0x4577901cf275488dULL, l.Value());
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x4577901cf275488dULL, m.Value());
+}
+
+TEST(Assignment, ConstantToKnown) {
+ Label l;
+ l = 0xec0b9c369b7e8ea7ULL;
+ l = 0xec0b9c369b7e8ea7ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+ EXPECT_EQ(0xec0b9c369b7e8ea7ULL, l.Value());
+}
+
+TEST(AssignmentDeathTest, Self) {
+ Label l;
+ ASSERT_DEATH(l = l, "binding != this");
+}
+
+TEST(AssignmentDeathTest, IndirectCycle) {
+ Label l, m, n;
+ l = m;
+ m = n;
+ ASSERT_DEATH(n = l, "binding != this");
+}
+
+TEST(AssignmentDeathTest, Cycle) {
+ Label l, m, n, o;
+ l = m;
+ m = n;
+ o = n;
+ ASSERT_DEATH(o = l, "binding != this");
+}
+
+TEST(Addition, LabelConstant) {
+ Label l, m;
+ m = l + 0x5248d93e8bbe9497ULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x5248d93e8bbe9497ULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Addition, ConstantLabel) {
+ Label l, m;
+ m = 0xf51e94e00d6e3c84ULL + l;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0xf51e94e00d6e3c84ULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Addition, KnownLabelConstant) {
+ Label l, m;
+ l = 0x16286307042ce0d8ULL;
+ m = l + 0x3fdddd91306719d7ULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x3fdddd91306719d7ULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x16286307042ce0d8ULL + 0x3fdddd91306719d7ULL, m.Value());
+}
+
+TEST(Addition, ConstantKnownLabel) {
+ Label l, m;
+ l = 0x50f62d0cdd1031deULL;
+ m = 0x1b13462d8577c538ULL + l;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(0x1b13462d8577c538ULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x50f62d0cdd1031deULL + 0x1b13462d8577c538ULL, m.Value());
+}
+
+TEST(Subtraction, LabelConstant) {
+ Label l, m;
+ m = l - 0x0620884d21d3138eULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(-0x0620884d21d3138eULL, d);
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(Subtraction, KnownLabelConstant) {
+ Label l, m;
+ l = 0x6237fbaf9ef7929eULL;
+ m = l - 0x317730995d2ab6eeULL;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l));
+ u_int64_t d;
+ EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d));
+ EXPECT_EQ(-0x317730995d2ab6eeULL, d);
+ EXPECT_TRUE(m.IsKnownConstant());
+ EXPECT_EQ(0x6237fbaf9ef7929eULL - 0x317730995d2ab6eeULL, m.Value());
+}
+
+TEST(SubtractionDeathTest, LabelLabel) {
+ Label l, m;
+ ASSERT_DEATH(l - m, "IsKnownOffsetFrom\\(label, &offset\\)");
+}
+
+TEST(Subtraction, LabelLabel) {
+ Label l, m;
+ l = m + 0x7fa77ec63e28a17aULL;
+ EXPECT_EQ(0x7fa77ec63e28a17aULL, l - m);
+ EXPECT_EQ(-0x7fa77ec63e28a17aULL, m - l);
+}
+
+TEST(IsKnownConstant, Undefined) {
+ Label l;
+ EXPECT_FALSE(l.IsKnownConstant());
+}
+
+TEST(IsKnownConstant, RelatedLabel) {
+ Label l, m;
+ l = m;
+ EXPECT_FALSE(l.IsKnownConstant());
+ EXPECT_FALSE(m.IsKnownConstant());
+}
+
+TEST(IsKnownConstant, Constant) {
+ Label l;
+ l = 0xf374b1bdd6a22576ULL;
+ EXPECT_TRUE(l.IsKnownConstant());
+}
+
+TEST(IsKnownOffsetFrom, Unrelated) {
+ Label l, m;
+ EXPECT_FALSE(l.IsKnownOffsetFrom(m));
+}
+
+TEST(IsKnownOffsetFrom, Related) {
+ Label l, m;
+ l = m;
+ EXPECT_TRUE(l.IsKnownOffsetFrom(m));
+}
+
+// Test the construction of chains of related labels, and the
+// propagation of values through them.
+//
+// Although the relations between labels are supposed to behave
+// symmetrically --- that is, 'a = b' should put a and b in
+// indistinguishable states --- there's a distinction made internally
+// between the target (a) and the source (b).
+//
+// So there are five test axes to cover:
+//
+// - Do we construct the chain with assignment ("Assign") or with constructors
+// ("Construct")?
+//
+// - Do we set the value of the label at the start of the chain
+// ("Start") or the label at the end ("End")?
+//
+// - Are we testing the propagation of a relationship between variable
+// values ("Relation"), or the propagation of a known constant value
+// ("Value")?
+//
+// - Do we set the value before building the chain ("Before") or after
+// the chain has been built ("After")?
+//
+// - Do we add new relationships to the end of the existing chain
+// ("Forward") or to the beginning ("Backward")?
+//
+// Of course, "Construct" and "Backward" can't be combined, which
+// eliminates eight combinations, and "Construct", "End", and "Before"
+// can't be combined, which eliminates two more, so there are are 22
+// combinations, not 32.
+
+TEST(LabelChain, AssignStartRelationBeforeForward) {
+ Label a, b, c, d;
+ Label x;
+ a = x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationBeforeBackward) {
+ Label a, b, c, d;
+ Label x;
+ a = x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationAfterForward) {
+ Label a, b, c, d;
+ Label x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartRelationAfterBackward) {
+ Label a, b, c, d;
+ Label x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, AssignStartValueBeforeForward) {
+ Label a, b, c, d;
+ a = 0xa131200190546ac2ULL;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x111U, d.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x11U, c.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0x1U, b.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueBeforeBackward) {
+ Label a, b, c, d;
+ a = 0x8da17e1670ad4fa2ULL;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x111U, d.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x11U, c.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x1U, b.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueAfterForward) {
+ Label a, b, c, d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ a = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x111U, d.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x11U, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0x1U, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignStartValueAfterBackward) {
+ Label a, b, c, d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ a = 0xc86ca1d97ab5df6eULL;
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x111U, d.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x11U, c.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x1U, b.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0U, a.Value());
+}
+
+TEST(LabelChain, AssignEndRelationBeforeForward) {
+ Label a, b, c, d;
+ Label x;
+ x = d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(-(u_int64_t)0x111U, a-x);
+ EXPECT_EQ(-(u_int64_t)0x110U, b-x);
+ EXPECT_EQ(-(u_int64_t)0x100U, c-x);
+ EXPECT_EQ(-(u_int64_t)0U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationBeforeBackward) {
+ Label a, b, c, d;
+ Label x;
+ x = d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(-(u_int64_t)0x111U, a-x);
+ EXPECT_EQ(-(u_int64_t)0x110U, b-x);
+ EXPECT_EQ(-(u_int64_t)0x100U, c-x);
+ EXPECT_EQ(-(u_int64_t)0U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationAfterForward) {
+ Label a, b, c, d;
+ Label x;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ x = d;
+ EXPECT_EQ(-(u_int64_t)0x111U, a-x);
+ EXPECT_EQ(-(u_int64_t)0x110U, b-x);
+ EXPECT_EQ(-(u_int64_t)0x100U, c-x);
+ EXPECT_EQ(-(u_int64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, AssignEndRelationAfterBackward) {
+ Label a, b, c, d;
+ Label x;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ x = d;
+ EXPECT_EQ(-(u_int64_t)0x111U, a-x);
+ EXPECT_EQ(-(u_int64_t)0x110U, b-x);
+ EXPECT_EQ(-(u_int64_t)0x100U, c-x);
+ EXPECT_EQ(-(u_int64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, AssignEndValueBeforeForward) {
+ Label a, b, c, d;
+ d = 0xa131200190546ac2ULL;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x111, a.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x110, b.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x100, c.Value());
+ EXPECT_EQ(0xa131200190546ac2ULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueBeforeBackward) {
+ Label a, b, c, d;
+ d = 0x8da17e1670ad4fa2ULL;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x111, a.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x110, b.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x100, c.Value());
+ EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueAfterForward) {
+ Label a, b, c, d;
+ b = a + 0x1;
+ c = b + 0x10;
+ d = c + 0x100;
+ d = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, AssignEndValueAfterBackward) {
+ Label a, b, c, d;
+ d = c + 0x100;
+ c = b + 0x10;
+ b = a + 0x1;
+ d = 0xc86ca1d97ab5df6eULL;
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x111, a.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x110, b.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x100, c.Value());
+ EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x000, d.Value());
+}
+
+TEST(LabelChain, ConstructStartRelationBeforeForward) {
+ Label x;
+ Label a(x);
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, ConstructStartRelationAfterForward) {
+ Label x;
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ a = x;
+ EXPECT_EQ(0x111U, d-x);
+ EXPECT_EQ(0x11U, c-x);
+ EXPECT_EQ(0x1U, b-x);
+ EXPECT_EQ(0U, a-x);
+}
+
+TEST(LabelChain, ConstructStartValueBeforeForward) {
+ Label a(0x5d234d177d01ccc8ULL);
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x111U, d.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x011U, c.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x001U, b.Value());
+ EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x000U, a.Value());
+}
+
+TEST(LabelChain, ConstructStartValueAfterForward) {
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ a = 0xded85d54586e84fcULL;
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x111U, d.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x011U, c.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x001U, b.Value());
+ EXPECT_EQ(0xded85d54586e84fcULL + 0x000U, a.Value());
+}
+
+TEST(LabelChain, ConstructEndRelationAfterForward) {
+ Label x;
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ x = d;
+ EXPECT_EQ(-(u_int64_t)0x111U, a-x);
+ EXPECT_EQ(-(u_int64_t)0x110U, b-x);
+ EXPECT_EQ(-(u_int64_t)0x100U, c-x);
+ EXPECT_EQ(-(u_int64_t)0x000U, d-x);
+}
+
+TEST(LabelChain, ConstructEndValueAfterForward) {
+ Label a;
+ Label b(a + 0x1);
+ Label c(b + 0x10);
+ Label d(c + 0x100);
+ d = 0x99b8f51bafd41adaULL;
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value());
+ EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value());
+}
+
+TEST(LabelTree, KnownValue) {
+ Label l, m, n, o, p;
+ l = m;
+ m = n;
+ o = p;
+ p = n;
+ l = 0x536b5de3d468a1b5ULL;
+ EXPECT_EQ(0x536b5de3d468a1b5ULL, o.Value());
+}
+
+TEST(LabelTree, Related) {
+ Label l, m, n, o, p;
+ l = m - 1;
+ m = n - 10;
+ o = p + 100;
+ p = n + 1000;
+ EXPECT_EQ(1111U, o - l);
+}
+
+TEST(EquationDeathTest, EqualConstants) {
+ Label m = 0x0d3962f280f07d24ULL;
+ Label n = 0x0d3962f280f07d24ULL;
+ m = n; // no death expected
+}
+
+TEST(EquationDeathTest, EqualIndirectConstants) {
+ Label m = 0xa347f1e5238fe6a1ULL;
+ Label n;
+ Label o = n;
+ n = 0xa347f1e5238fe6a1ULL;
+ n = m; // no death expected
+}
+
+TEST(EquationDeathTest, ConstantClash) {
+ Label m = 0xd4cc0f4f630ec741ULL;
+ Label n = 0x934cd2d8254fc3eaULL;
+ ASSERT_DEATH(m = n, "addend_ == addend");
+}
+
+TEST(EquationDeathTest, IndirectConstantClash) {
+ Label m = 0xd4cc0f4f630ec741ULL;
+ Label n, o;
+ n = o;
+ o = 0xcfbe3b83ac49ce86ULL;
+ ASSERT_DEATH(m = n, "addend_ == addend");
+}
+
+// Assigning to a related label may free the next Binding on its
+// chain. This test always passes; it is interesting to memory
+// checkers and coverage analysis.
+TEST(LabelReferenceCount, AssignmentFree) {
+ Label l;
+ {
+ Label m;
+ l = m;
+ }
+ // This should free m's Binding.
+ l = 0xca8bae92f0376d4fULL;
+ ASSERT_EQ(0xca8bae92f0376d4fULL, l.Value());
+}
+
+// Finding the value of a label may free the Binding it refers to. This test
+// always passes; it is interesting to memory checkers and coverage analysis.
+TEST(LabelReferenceCount, FindValueFree) {
+ Label l;
+ {
+ Label m, n;
+ l = m;
+ m = n;
+ n = 0x7a0b0c576672daafULL;
+ // At this point, l's Binding refers to m's Binding, which refers
+ // to n's binding.
+ }
+ // Now, l is the only reference keeping the three Bindings alive.
+ // Resolving its value should free l's and m's original bindings.
+ ASSERT_EQ(0x7a0b0c576672daafULL, l.Value());
+}
+
+TEST(ConstructSection, Simple) {
+ Section s;
+}
+
+TEST(ConstructSection, WithEndian) {
+ Section s(kBigEndian);
+}
+
+// A fixture class for TestAssembler::Section tests.
+class SectionFixture {
+ public:
+ Section section;
+ string contents;
+ static const u_int8_t data[];
+ static const size_t data_size;
+};
+
+const u_int8_t SectionFixture::data[] = {
+ 0x87, 0x4f, 0x43, 0x67, 0x30, 0xd0, 0xd4, 0x0e
+};
+
+#define I0()
+#define I1(a) { a }
+#define I2(a,b) { a,b }
+#define I3(a,b,c) { a,b,c }
+#define I4(a,b,c,d) { a,b,c,d }
+#define I5(a,b,c,d,e) { a,b,c,d,e }
+#define I6(a,b,c,d,e,f) { a,b,c,d,e,f }
+#define I7(a,b,c,d,e,f,g) { a,b,c,d,e,f,g }
+#define I8(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h }
+#define I9(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i }
+#define ASSERT_BYTES(s, b) \
+ do \
+ { \
+ static const u_int8_t expected_bytes[] = b; \
+ ASSERT_EQ(sizeof(expected_bytes), s.size()); \
+ ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \
+ sizeof(expected_bytes)) == 0); \
+ } \
+ while(0)
+
+class Append: public SectionFixture, public Test { };
+
+TEST_F(Append, Bytes) {
+ section.Append(data, sizeof(data));
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(sizeof(data), contents.size());
+ EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+}
+
+TEST_F(Append, BytesTwice) {
+ section.Append(data, sizeof(data));
+ section.Append(data, sizeof(data));
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(2 * sizeof(data), contents.size());
+ ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data)));
+ ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data),
+ (const char *) data, sizeof(data)));
+}
+
+TEST_F(Append, String) {
+ string s1 = "howdy ";
+ string s2 = "there";
+ section.Append(s1);
+ section.Append(s2);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_STREQ(contents.c_str(), "howdy there");
+}
+
+TEST_F(Append, RepeatedBytes) {
+ section.Append((size_t) 10, '*');
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_STREQ(contents.c_str(), "**********");
+}
+
+TEST_F(Append, GeneralLE1) {
+ section.Append(kLittleEndian, 1, 42);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+}
+
+TEST_F(Append, GeneralLE2) {
+ section.Append(kLittleEndian, 2, 0x15a1);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0xa1, 0x15));
+}
+
+TEST_F(Append, GeneralLE3) {
+ section.Append(kLittleEndian, 3, 0x59ae8d);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59));
+}
+
+TEST_F(Append, GeneralLE4) {
+ section.Append(kLittleEndian, 4, 0x51603c56);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51));
+}
+
+TEST_F(Append, GeneralLE5) {
+ section.Append(kLittleEndian, 5, 0x385e2803b4ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38));
+}
+
+TEST_F(Append, GeneralLE6) {
+ section.Append(kLittleEndian, 6, 0xc7db9534dd1fULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7));
+}
+
+TEST_F(Append, GeneralLE7) {
+ section.Append(kLittleEndian, 7, 0x1445c9f1b843e6ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14));
+}
+
+TEST_F(Append, GeneralLE8) {
+ section.Append(kLittleEndian, 8, 0xaf48019dfe5c01e5ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf));
+}
+
+TEST_F(Append, GeneralBE1) {
+ section.Append(kBigEndian, 1, 0xd0ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(0xd0));
+}
+
+TEST_F(Append, GeneralBE2) {
+ section.Append(kBigEndian, 2, 0x2e7eULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2e, 0x7e));
+}
+
+TEST_F(Append, GeneralBE3) {
+ section.Append(kBigEndian, 3, 0x37dad6ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6));
+}
+
+TEST_F(Append, GeneralBE4) {
+ section.Append(kBigEndian, 4, 0x715935c7ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7));
+}
+
+TEST_F(Append, GeneralBE5) {
+ section.Append(kBigEndian, 5, 0x42baeb02b7ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7));
+}
+
+TEST_F(Append, GeneralBE6) {
+ section.Append(kBigEndian, 6, 0xf1cdf10e7b18ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18));
+}
+
+TEST_F(Append, GeneralBE7) {
+ section.Append(kBigEndian, 7, 0xf50a724f0b0d20ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20));
+}
+
+TEST_F(Append, GeneralBE8) {
+ section.Append(kBigEndian, 8, 0xa6b2cb5e98dc9c16ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16));
+}
+
+TEST_F(Append, GeneralLE1Label) {
+ Label l;
+ section.Append(kLittleEndian, 1, l);
+ l = 42;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+}
+
+TEST_F(Append, GeneralLE2Label) {
+ Label l;
+ section.Append(kLittleEndian, 2, l);
+ l = 0x15a1;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0xa1, 0x15));
+}
+
+TEST_F(Append, GeneralLE3Label) {
+ Label l;
+ section.Append(kLittleEndian, 3, l);
+ l = 0x59ae8d;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59));
+}
+
+TEST_F(Append, GeneralLE4Label) {
+ Label l;
+ section.Append(kLittleEndian, 4, l);
+ l = 0x51603c56;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51));
+}
+
+TEST_F(Append, GeneralLE5Label) {
+ Label l;
+ section.Append(kLittleEndian, 5, l);
+ l = 0x385e2803b4ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38));
+}
+
+TEST_F(Append, GeneralLE6Label) {
+ Label l;
+ section.Append(kLittleEndian, 6, l);
+ l = 0xc7db9534dd1fULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7));
+}
+
+TEST_F(Append, GeneralLE7Label) {
+ Label l;
+ section.Append(kLittleEndian, 7, l);
+ l = 0x1445c9f1b843e6ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14));
+}
+
+TEST_F(Append, GeneralLE8Label) {
+ Label l;
+ section.Append(kLittleEndian, 8, l);
+ l = 0xaf48019dfe5c01e5ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf));
+}
+
+TEST_F(Append, GeneralBE1Label) {
+ Label l;
+ section.Append(kBigEndian, 1, l);
+ l = 0xd0ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(0xd0));
+}
+
+TEST_F(Append, GeneralBE2Label) {
+ Label l;
+ section.Append(kBigEndian, 2, l);
+ l = 0x2e7eULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2e, 0x7e));
+}
+
+TEST_F(Append, GeneralBE3Label) {
+ Label l;
+ section.Append(kBigEndian, 3, l);
+ l = 0x37dad6ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6));
+}
+
+TEST_F(Append, GeneralBE4Label) {
+ Label l;
+ section.Append(kBigEndian, 4, l);
+ l = 0x715935c7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7));
+}
+
+TEST_F(Append, GeneralBE5Label) {
+ Label l;
+ section.Append(kBigEndian, 5, l);
+ l = 0x42baeb02b7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7));
+}
+
+TEST_F(Append, GeneralBE6Label) {
+ Label l;
+ section.Append(kBigEndian, 6, l);
+ l = 0xf1cdf10e7b18ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18));
+}
+
+TEST_F(Append, GeneralBE7Label) {
+ Label l;
+ section.Append(kBigEndian, 7, l);
+ l = 0xf50a724f0b0d20ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20));
+}
+
+TEST_F(Append, GeneralBE8Label) {
+ Label l;
+ section.Append(kBigEndian, 8, l);
+ l = 0xa6b2cb5e98dc9c16ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16));
+}
+
+TEST_F(Append, B8) {
+ section.Append(1, 0x2a);
+ section.B8(0xd3U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xd3));
+}
+
+TEST_F(Append, B8Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B8(l);
+ l = 0x4bU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x4b));
+}
+
+TEST_F(Append, B16) {
+ section.Append(1, 0x2a);
+ section.B16(0x472aU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x47, 0x2a));
+}
+
+TEST_F(Append, B16Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B16(l);
+ l = 0x55e8U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x55, 0xe8));
+}
+
+TEST_F(Append, B32) {
+ section.Append(1, 0x2a);
+ section.B32(0xbd412cbcU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xbd, 0x41, 0x2c, 0xbc));
+}
+
+TEST_F(Append, B32Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B32(l);
+ l = 0x208e37d5U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x20, 0x8e, 0x37, 0xd5));
+}
+
+TEST_F(Append, B64) {
+ section.Append(1, 0x2a);
+ section.B64(0x3402a013111e68adULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x34, 0x02, 0xa0, 0x13, 0x11, 0x1e, 0x68, 0xad));
+}
+
+TEST_F(Append, B64Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.B64(l);
+ l = 0x355dbfbb4ac6d57fULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x35, 0x5d, 0xbf, 0xbb, 0x4a, 0xc6, 0xd5, 0x7f));
+}
+
+TEST_F(Append, L8) {
+ section.Append(1, 0x2a);
+ section.L8(0x26U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x26));
+}
+
+TEST_F(Append, L8Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L8(l);
+ l = 0xa8U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xa8));
+}
+
+TEST_F(Append, L16) {
+ section.Append(1, 0x2a);
+ section.L16(0xca6dU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x6d, 0xca));
+}
+
+TEST_F(Append, L16Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L16(l);
+ l = 0xd21fU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x1f, 0xd2));
+}
+
+TEST_F(Append, L32) {
+ section.Append(1, 0x2a);
+ section.L32(0x558f6181U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x81, 0x61, 0x8f, 0x55));
+}
+
+TEST_F(Append, L32Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L32(l);
+ l = 0x4b810f82U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x82, 0x0f, 0x81, 0x4b));
+}
+
+TEST_F(Append, L64) {
+ section.Append(1, 0x2a);
+ section.L64(0x564384f7579515bfULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xbf, 0x15, 0x95, 0x57, 0xf7, 0x84, 0x43, 0x56));
+}
+
+TEST_F(Append, L64Label) {
+ Label l;
+ section.Append(1, 0x2a);
+ section.L64(l);
+ l = 0x424b1d020667c8dbULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xdb, 0xc8, 0x67, 0x06, 0x02, 0x1d, 0x4b, 0x42));
+}
+
+TEST_F(Append, D8Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D8(0xe6U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xe6));
+}
+
+TEST_F(Append, D8BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D8(l);
+ l = 0xeeU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0xee));
+}
+
+TEST_F(Append, D16Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D16(0x83b1U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x83, 0xb1));
+}
+
+TEST_F(Append, D16BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D16(l);
+ l = 0x5b55U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x5b, 0x55));
+}
+
+TEST_F(Append, D32Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D32(0xd0b0e431U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xd0, 0xb0, 0xe4, 0x31));
+}
+
+TEST_F(Append, D32BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D32(l);
+ l = 0x312fb340U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x31, 0x2f, 0xb3, 0x40));
+}
+
+TEST_F(Append, D64Big) {
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D64(0xb109843500dbcb16ULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xb1, 0x09, 0x84, 0x35, 0x00, 0xdb, 0xcb, 0x16));
+}
+
+TEST_F(Append, D64BigLabel) {
+ Label l;
+ section.set_endianness(kBigEndian);
+ section.Append(1, 0x2a);
+ section.D64(l);
+ l = 0x9a0d61b70f671fd7ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x9a, 0x0d, 0x61, 0xb7, 0x0f, 0x67, 0x1f, 0xd7));
+}
+
+TEST_F(Append, D8Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D8(0x42U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x42));
+}
+
+TEST_F(Append, D8LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D8(l);
+ l = 0x05U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I2(0x2a, 0x05));
+}
+
+TEST_F(Append, D16Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D16(0xc5c5U);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0xc5, 0xc5));
+}
+
+TEST_F(Append, D16LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D16(l);
+ l = 0xb620U;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I3(0x2a, 0x20, 0xb6));
+}
+
+TEST_F(Append, D32Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D32(0x1a87d0feU);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0xfe, 0xd0, 0x87, 0x1a));
+}
+
+TEST_F(Append, D32LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D32(l);
+ l = 0xb8012d6bU;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I5(0x2a, 0x6b, 0x2d, 0x01, 0xb8));
+}
+
+TEST_F(Append, D64Little) {
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D64(0x42de75c61375a1deULL);
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0xde, 0xa1, 0x75, 0x13, 0xc6, 0x75, 0xde, 0x42));
+}
+
+TEST_F(Append, D64LittleLabel) {
+ Label l;
+ section.set_endianness(kLittleEndian);
+ section.Append(1, 0x2a);
+ section.D64(l);
+ l = 0x8b3bececf3fb5312ULL;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents,
+ I9(0x2a, 0x12, 0x53, 0xfb, 0xf3, 0xec, 0xec, 0x3b, 0x8b));
+}
+
+TEST_F(Append, Variety) {
+ Label a, b, c, d, e, f, g, h;
+ section.Append(kBigEndian, 1, a)
+ .Append(kLittleEndian, 8, h)
+ .Append(kBigEndian, 1, 0x8bULL)
+ .Append(kLittleEndian, 8, 0x0ea56540448f4439ULL)
+ .Append(kBigEndian, 2, b)
+ .Append(kLittleEndian, 7, g)
+ .Append(kBigEndian, 2, 0xcf15ULL)
+ .Append(kLittleEndian, 7, 0x29694f04c5724aULL)
+ .Append(kBigEndian, 3, c)
+ .Append(kLittleEndian, 6, f)
+ .Append(kBigEndian, 3, 0x8c3ffdULL)
+ .Append(kLittleEndian, 6, 0x6f11ba80187aULL)
+ .Append(kBigEndian, 4, d)
+ .Append(kLittleEndian, 5, e)
+ .Append(kBigEndian, 4, 0x2fda2472ULL)
+ .Append(kLittleEndian, 5, 0x0aa02d423fULL)
+ .Append(kBigEndian, 5, e)
+ .Append(kLittleEndian, 4, d)
+ .Append(kBigEndian, 5, 0x53ba432138ULL)
+ .Append(kLittleEndian, 4, 0xf139ae60ULL)
+ .Append(kBigEndian, 6, f)
+ .Append(kLittleEndian, 3, c)
+ .Append(kBigEndian, 6, 0x168e436af716ULL)
+ .Append(kLittleEndian, 3, 0x3ef189ULL)
+ .Append(kBigEndian, 7, g)
+ .Append(kLittleEndian, 2, b)
+ .Append(kBigEndian, 7, 0xacd4ef233e47d9ULL)
+ .Append(kLittleEndian, 2, 0x5311ULL)
+ .Append(kBigEndian, 8, h)
+ .Append(kLittleEndian, 1, a)
+ .Append(kBigEndian, 8, 0x4668d5f1c93637a1ULL)
+ .Append(kLittleEndian, 1, 0x65ULL);
+ a = 0x79ac9bd8aa256b35ULL;
+ b = 0x22d13097ef86c91cULL;
+ c = 0xf204968b0a05862fULL;
+ d = 0x163177f15a0eb4ecULL;
+ e = 0xbd1b0f1d977f2246ULL;
+ f = 0x2b0842eee83c6461ULL;
+ g = 0x92f4b928a4bf875eULL;
+ h = 0x61a199a8f7286ba6ULL;
+ ASSERT_EQ(8 * 18U, section.Size());
+ ASSERT_TRUE(section.GetContents(&contents));
+
+ static const u_int8_t expected[] = {
+ 0x35, 0xa6, 0x6b, 0x28, 0xf7, 0xa8, 0x99, 0xa1, 0x61,
+ 0x8b, 0x39, 0x44, 0x8f, 0x44, 0x40, 0x65, 0xa5, 0x0e,
+ 0xc9, 0x1c, 0x5e, 0x87, 0xbf, 0xa4, 0x28, 0xb9, 0xf4,
+ 0xcf, 0x15, 0x4a, 0x72, 0xc5, 0x04, 0x4f, 0x69, 0x29,
+ 0x05, 0x86, 0x2f, 0x61, 0x64, 0x3c, 0xe8, 0xee, 0x42,
+ 0x8c, 0x3f, 0xfd, 0x7a, 0x18, 0x80, 0xba, 0x11, 0x6f,
+ 0x5a, 0x0e, 0xb4, 0xec, 0x46, 0x22, 0x7f, 0x97, 0x1d,
+ 0x2f, 0xda, 0x24, 0x72, 0x3f, 0x42, 0x2d, 0xa0, 0x0a,
+ 0x1d, 0x97, 0x7f, 0x22, 0x46, 0xec, 0xb4, 0x0e, 0x5a,
+ 0x53, 0xba, 0x43, 0x21, 0x38, 0x60, 0xae, 0x39, 0xf1,
+ 0x42, 0xee, 0xe8, 0x3c, 0x64, 0x61, 0x2f, 0x86, 0x05,
+ 0x16, 0x8e, 0x43, 0x6a, 0xf7, 0x16, 0x89, 0xf1, 0x3e,
+ 0xf4, 0xb9, 0x28, 0xa4, 0xbf, 0x87, 0x5e, 0x1c, 0xc9,
+ 0xac, 0xd4, 0xef, 0x23, 0x3e, 0x47, 0xd9, 0x11, 0x53,
+ 0x61, 0xa1, 0x99, 0xa8, 0xf7, 0x28, 0x6b, 0xa6, 0x35,
+ 0x46, 0x68, 0xd5, 0xf1, 0xc9, 0x36, 0x37, 0xa1, 0x65,
+ };
+
+ ASSERT_TRUE(0 == memcmp(contents.data(), expected, sizeof(expected)));
+}
+
+TEST_F(Append, Section) {
+ section.Append("murder");
+ {
+ Section middle;
+ middle.Append(" she");
+ section.Append(middle);
+ }
+ section.Append(" wrote");
+ EXPECT_EQ(16U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_STREQ(contents.c_str(), "murder she wrote");
+}
+
+TEST_F(Append, SectionRefs) {
+ section.Append("sugar ");
+ Label l;
+ {
+ Section middle;
+ Label m;
+ middle.B32(m);
+ section.Append(middle);
+ m = 0x66726565;
+ }
+ section.Append(" jazz");
+ EXPECT_EQ(15U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_STREQ(contents.c_str(), "sugar free jazz");
+}
+
+TEST_F(Append, LEB128_0) {
+ section.LEB128(0);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\0", 1), contents);
+}
+
+TEST_F(Append, LEB128_0x3f) {
+ section.LEB128(0x3f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x3f", 1), contents);
+}
+
+TEST_F(Append, LEB128_0x40) {
+ section.LEB128(0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xc0\x00", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x7f) {
+ section.LEB128(0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x00", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x80) {
+ section.LEB128(0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x01", 2), contents);
+}
+
+TEST_F(Append, LEB128_0xff) {
+ section.LEB128(0xff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x01", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x1fff) {
+ section.LEB128(0x1fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x3f", 2), contents);
+}
+
+TEST_F(Append, LEB128_0x2000) {
+ section.LEB128(0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\xc0\x00", 3), contents);
+}
+
+TEST_F(Append, LEB128_n1) {
+ section.LEB128(-1);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x7f", 1), contents);
+}
+
+TEST_F(Append, LEB128_n0x40) {
+ section.LEB128(-0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x40", 1), contents);
+}
+
+TEST_F(Append, LEB128_n0x41) {
+ section.LEB128(-0x41);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xbf\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x7f) {
+ section.LEB128(-0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x81\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x80) {
+ section.LEB128(-0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x7f", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x2000) {
+ section.LEB128(-0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x40", 2), contents);
+}
+
+TEST_F(Append, LEB128_n0x2001) {
+ section.LEB128(-0x2001);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\xbf\x7f", 3), contents);
+}
+
+TEST_F(Append,ULEB128_0) {
+ section.ULEB128(0);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\0", 1), contents);
+}
+
+TEST_F(Append,ULEB128_1) {
+ section.ULEB128(1);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x01", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x3f) {
+ section.ULEB128(0x3f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x3f", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x40) {
+ section.ULEB128(0x40);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x40", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x7f) {
+ section.ULEB128(0x7f);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x7f", 1), contents);
+}
+
+TEST_F(Append,ULEB128_0x80) {
+ section.ULEB128(0x80);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x01", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0xff) {
+ section.ULEB128(0xff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x01", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x100) {
+ section.ULEB128(0x100);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x02", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x1fff) {
+ section.ULEB128(0x1fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x3f", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x2000) {
+ section.ULEB128(0x2000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x40", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x3fff) {
+ section.ULEB128(0x3fff);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xff\x7f", 2), contents);
+}
+
+TEST_F(Append,ULEB128_0x4000) {
+ section.ULEB128(0x4000);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x80\x01", 3), contents);
+}
+
+TEST_F(Append,ULEB128_12857) {
+ section.ULEB128(12857);
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\xb9\x64", 2), contents);
+}
+
+TEST_F(Append, LEBChain) {
+ section.LEB128(-0x80).ULEB128(12857).Append("*");
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(string("\x80\x7f\xb9\x64*", 5), contents);
+}
+
+
+class GetContents: public SectionFixture, public Test { };
+
+TEST_F(GetContents, Undefined) {
+ Label l;
+ section.Append(kLittleEndian, 8, l);
+ ASSERT_FALSE(section.GetContents(&contents));
+}
+
+TEST_F(GetContents, ClearsContents) {
+ section.Append((size_t) 10, '*');
+ EXPECT_EQ(10U, section.Size());
+ EXPECT_TRUE(section.GetContents(&contents));
+ EXPECT_EQ(0U, section.Size());
+}
+
+TEST_F(GetContents, ClearsReferences) {
+ Label l;
+ section.Append(kBigEndian, 1, l);
+ l = 42;
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_BYTES(contents, I1(42));
+ ASSERT_TRUE(section.GetContents(&contents)); // should not die
+}
+
+class Miscellanea: public SectionFixture, public Test { };
+
+TEST_F(Miscellanea, Clear) {
+ section.Append("howdy");
+ Label l;
+ section.L32(l);
+ EXPECT_EQ(9U, section.Size());
+ section.Clear();
+ EXPECT_EQ(0U, section.Size());
+ l = 0x8d231bf0U;
+ ASSERT_TRUE(section.GetContents(&contents)); // should not die
+}
+
+TEST_F(Miscellanea, Align) {
+ section.Append("*");
+ EXPECT_EQ(1U, section.Size());
+ section.Align(4).Append("*");
+ EXPECT_EQ(5U, section.Size());
+ section.Append("*").Align(2);
+ EXPECT_EQ(6U, section.Size());
+}
+
+TEST_F(Miscellanea, AlignPad) {
+ section.Append("*");
+ EXPECT_EQ(1U, section.Size());
+ section.Align(4, ' ').Append("*");
+ EXPECT_EQ(5U, section.Size());
+ section.Append("*").Align(2, ' ');
+ EXPECT_EQ(6U, section.Size());
+ ASSERT_TRUE(section.GetContents(&contents));
+ ASSERT_EQ(string("* **"), contents);
+}
+
+TEST_F(Miscellanea, StartHereMark) {
+ Label m;
+ section.Append(42, ' ').Mark(&m).Append(13, '+');
+ EXPECT_EQ(42U, m - section.start());
+ EXPECT_EQ(42U + 13U, section.Here() - section.start());
+ EXPECT_FALSE(section.start().IsKnownConstant());
+ EXPECT_FALSE(m.IsKnownConstant());
+ EXPECT_FALSE(section.Here().IsKnownConstant());
+}
+
+TEST_F(Miscellanea, Endianness) {
+ section.set_endianness(kBigEndian);
+ EXPECT_EQ(kBigEndian, section.endianness());
+ section.set_endianness(kLittleEndian);
+ EXPECT_EQ(kLittleEndian, section.endianness());
+}