~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to thirdparty/breakpad/common/test_assembler.cc

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2010, Google Inc.
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are
 
6
// met:
 
7
//
 
8
//     * Redistributions of source code must retain the above copyright
 
9
// notice, this list of conditions and the following disclaimer.
 
10
//     * Redistributions in binary form must reproduce the above
 
11
// copyright notice, this list of conditions and the following disclaimer
 
12
// in the documentation and/or other materials provided with the
 
13
// distribution.
 
14
//     * Neither the name of Google Inc. nor the names of its
 
15
// contributors may be used to endorse or promote products derived from
 
16
// this software without specific prior written permission.
 
17
//
 
18
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
19
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
20
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
21
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
22
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
24
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 
 
30
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
 
31
 
 
32
// test_assembler.cc: Implementation of google_breakpad::TestAssembler.
 
33
// See test_assembler.h for details.
 
34
 
 
35
#include "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(u_int64_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=(u_int64_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+(u_int64_t addend) const {
 
68
  Label l;
 
69
  l.value_->Set(this->value_, addend);
 
70
  return l;
 
71
}
 
72
 
 
73
Label Label::operator-(u_int64_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
u_int64_t Label::operator-(const Label &label) const {
 
93
  u_int64_t offset;
 
94
  ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
 
95
  return offset;
 
96
}
 
97
 
 
98
u_int64_t Label::Value() const {
 
99
  u_int64_t v = 0;
 
100
  ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
 
101
  return v;
 
102
};
 
103
 
 
104
bool Label::IsKnownConstant(u_int64_t *value_p) const {
 
105
  Binding *base;
 
106
  u_int64_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, u_int64_t *offset_p) const
 
114
{
 
115
  Binding *label_base, *this_base;
 
116
  u_int64_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(u_int64_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, u_int64_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
      u_int64_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, u_int64_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
    u_int64_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, u_int64_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, u_int64_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
  u_int64_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(u_int ## 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(u_int ## 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(u_int64_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, u_int8_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
    u_int64_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