Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(455)

Side by Side Diff: src/processor/test_assembler.cc

Issue 53001: Breakpad Processor: Add new unit tests for google_breakpad::Minidump (Closed)
Patch Set: Breakpad Processor: Add new unit tests for google_breakpad::Minidump Created 15 years, 3 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <cassert>
36 #include <cstdio>
37 #include <iterator>
38
39 #include "processor/test_assembler.h"
40
41 namespace google_breakpad {
42 namespace TestAssembler {
43
44 using std::back_insert_iterator;
45
46 Label::Label() : value_(new Binding()) { }
47 Label::Label(u_int64_t value) : value_(new Binding(value)) { }
48 Label::Label(const Label &label) {
49 value_ = label.value_;
50 value_->Acquire();
51 }
52 Label::~Label() {
53 if (value_->Release()) delete value_;
54 }
55
56 Label &Label::operator=(u_int64_t value) {
57 value_->Set(NULL, value);
58 return *this;
59 }
60
61 Label &Label::operator=(const Label &label) {
62 value_->Set(label.value_, 0);
63 return *this;
64 }
65
66 Label Label::operator+(u_int64_t addend) const {
67 Label l;
68 l.value_->Set(this->value_, addend);
69 return l;
70 }
71
72 Label Label::operator-(u_int64_t subtrahend) const {
73 Label l;
74 l.value_->Set(this->value_, -subtrahend);
75 return l;
76 }
77
78 // When NDEBUG is #defined, assert doesn't evaluate its argument. This
79 // means you can't simply use assert to check the return value of a
80 // function with necessary side effects.
81 //
82 // ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
83 // NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
84 // that x is true.
85 #ifdef NDEBUG
86 #define ALWAYS_EVALUATE_AND_ASSERT(x) x
87 #else
88 #define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
89 #endif
90
91 u_int64_t Label::operator-(const Label &label) const {
92 u_int64_t offset;
93 ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
94 return offset;
95 }
96
97 u_int64_t Label::Value() const {
98 u_int64_t v;
99 ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v));
100 return v;
101 };
102
103 bool Label::IsKnownConstant(u_int64_t *value_p) const {
104 Binding *base;
105 u_int64_t addend;
106 value_->Get(&base, &addend);
107 if (base != NULL) return false;
108 if (value_p) *value_p = addend;
109 return true;
110 }
111
112 bool Label::IsKnownOffsetFrom(const Label &label, u_int64_t *offset_p) const
113 {
114 Binding *label_base, *this_base;
115 u_int64_t label_addend, this_addend;
116 label.value_->Get(&label_base, &label_addend);
117 value_->Get(&this_base, &this_addend);
118 // If this and label are related, Get will find their final
119 // common ancestor, regardless of how indirect the relation is. This
120 // comparison also handles the constant vs. constant case.
121 if (this_base != label_base) return false;
122 if (offset_p) *offset_p = this_addend - label_addend;
123 return true;
124 }
125
126 Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { }
127
128 Label::Binding::Binding(u_int64_t addend)
129 : base_(NULL), addend_(addend), reference_count_(1) { }
130
131 Label::Binding::~Binding() {
132 assert(reference_count_ == 0);
133 if (base_ && base_ != this && base_->Release())
134 delete base_;
135 }
136
137 void Label::Binding::Set(Binding *binding, u_int64_t addend) {
138 if (!base_ && !binding) {
139 // We're equating two constants. This could be okay.
140 assert(addend_ == addend);
141 } else if (!base_) {
142 // We are a known constant, but BINDING may not be, so turn the
143 // tables and try to set BINDING's value instead.
144 binding->Set(NULL, addend_ - addend);
145 } else {
146 if (binding) {
147 // Find binding's final value. This avoids creating cycles for:
148 // l = m, m = n, n = l;
mochalatte 2010/03/03 22:26:09 from the test coverage, i assume this generalizes
jimb 2010/03/16 16:14:50 I've expanded the comment.
149 u_int64_t binding_addend;
150 binding->Get(&binding, &binding_addend);
151 addend += binding_addend;
152 }
153
154 // It seems likely that setting a binding to itself is a bug
155 // (although I can imagine this might turn out to be helpful to
156 // permit).
157 assert(binding != this);
158
159 if (base_ != this) {
160 // Set the other bindings on our chain as well. Note that this
161 // is sufficient even though binding relationships form trees:
162 // All binding operations traverse their chains to the end, and
163 // all bindings related to us share some tail of our chain, so
164 // they will see the changes we make here.
165 base_->Set(binding, addend - addend_);
166 // We're not going to use base_ any more.
167 if (base_->Release()) delete base_;
168 }
169
170 // Adopt BINDING as our base. Note that it should be correct to
171 // acquire here, after the release above, even though the usual
172 // reference-counting rules call for acquiring first, and then
173 // releasing: the self-reference assertion above should have
174 // complained if BINDING were 'this' or anywhere along our chain,
175 // so we didn't release BINDING.
176 if (binding) binding->Acquire();
177 base_ = binding;
178 addend_ = addend;
179 }
180 }
181
182 void Label::Binding::Get(Binding **base, u_int64_t *addend) {
183 if (base_ && base_ != this) {
184 // Recurse to find the end of our reference chain (the root of our
185 // tree), and then rewrite every binding along the chain to refer
186 // to it directly, adjusting addends appropriately. (This is why
187 // this member function isn't this-const.)
188 Binding *final_base;
189 u_int64_t final_addend;
190 base_->Get(&final_base, &final_addend);
191 if (final_base) final_base->Acquire();
192 if (base_->Release()) delete base_;
193 base_ = final_base;
194 addend_ += final_addend;
195 }
196 *base = base_;
197 *addend = addend_;
198 }
199
200 template<typename Inserter>
201 static inline void InsertEndian(TestAssembler::Endianness endianness,
202 size_t size, u_int64_t number, Inserter dest) {
203 if (endianness == kLittleEndian) {
204 for (size_t i = 0; i < size; i++) {
205 *dest++ = (char) (number & 0xff);
206 number >>= 8;
207 }
208 } else {
209 assert(endianness == kBigEndian);
210 // The loop condition is odd, but it's correct for size_t.
211 for (size_t i = size - 1; i < size; i--)
212 *dest++ = (char) ((number >> (i * 8)) & 0xff);
213 }
214 }
215
216 Section &Section::Append(Endianness endianness, size_t size, u_int64_t number) {
217 InsertEndian(endianness, size, number,
218 back_insert_iterator<string>(contents_));
219 return *this;
220 }
221
222 Section &Section::Append(Endianness endianness, size_t size,
223 const Label &label) {
224 // If this label's value is known, there's no reason to waste an
225 // entry in references_ on it.
226 u_int64_t value;
227 if (label.IsKnownConstant(&value))
228 return Append(endianness, size, value);
229
230 // This will get caught when the references are resolved, but it's
231 // nicer to find out earlier.
232 assert(endianness != kUnsetEndian);
233
234 references_.push_back(Reference(contents_.size(), endianness, size, label));
235 contents_.append(size, 0);
236 return *this;
237 }
238
239 #define ENDIANNESS_L kLittleEndian
240 #define ENDIANNESS_B kBigEndian
241 #define ENDIANNESS(e) ENDIANNESS_ ## e
242
243 #define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
244 Section &Section::e ## bits(u_int ## bits ## _t v) { \
245 InsertEndian(ENDIANNESS(e), bits / 8, v, \
246 back_insert_iterator<string>(contents_)); \
247 return *this; \
248 }
249
250 #define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
251 Section &Section::e ## bits(const Label &v) { \
252 return Append(ENDIANNESS(e), bits / 8, v); \
253 }
254
255 // Define L16, B32, and friends.
256 #define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
257 DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
258 DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
259
260 DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
261 DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
262 DEFINE_SHORT_APPEND_ENDIAN(L, 16);
263 DEFINE_SHORT_APPEND_ENDIAN(L, 32);
264 DEFINE_SHORT_APPEND_ENDIAN(L, 64);
265 DEFINE_SHORT_APPEND_ENDIAN(B, 16);
266 DEFINE_SHORT_APPEND_ENDIAN(B, 32);
267 DEFINE_SHORT_APPEND_ENDIAN(B, 64);
268
269 #define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
270 Section &Section::D ## bits(u_int ## bits ## _t v) { \
271 InsertEndian(default_endianness_, bits / 8, v, \
272 back_insert_iterator<string>(contents_)); \
273 return *this; \
274 }
275 #define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
276 Section &Section::D ## bits(const Label &v) { \
277 return Append(default_endianness_, bits / 8, v); \
278 }
279 #define DEFINE_SHORT_APPEND_DEFAULT(bits) \
280 DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
281 DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
282
283 DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
284 DEFINE_SHORT_APPEND_DEFAULT(16);
285 DEFINE_SHORT_APPEND_DEFAULT(32);
286 DEFINE_SHORT_APPEND_DEFAULT(64);
287
288 Section &Section::Append(const Section &section) {
289 size_t base = contents_.size();
290 contents_.append(section.contents_);
291 for (vector<Reference>::const_iterator it = section.references_.begin();
292 it != section.references_.end(); it++)
293 references_.push_back(Reference(base + it->offset, it->endianness,
294 it->size, it->label));
295 return *this;
296 }
297
298 Section &Section::LEB128(long long value) {
299 while (value < -0x40 || 0x3f < value) {
300 contents_ += (value & 0x7f) | 0x80;
301 if (value < 0)
302 value = (value >> 7) | ~(((unsigned long long) -1) >> 7);
303 else
304 value = (value >> 7);
305 }
306 contents_ += value & 0x7f;
307 return *this;
308 }
309
310 Section &Section::ULEB128(u_int64_t value) {
311 while (value > 0x7f) {
312 contents_ += (value & 0x7f) | 0x80;
313 value = (value >> 7);
314 }
315 contents_ += value;
316 return *this;
317 }
318
319 Section &Section::Align(size_t alignment, u_int8_t pad_byte) {
320 // ALIGNMENT must be a power of two.
321 assert(((alignment - 1) & alignment) == 0);
322 size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
323 contents_.append(new_size - contents_.size(), pad_byte);
324 assert((contents_.size() & (alignment - 1)) == 0);
325 return *this;
326 }
327
328 void Section::Clear() {
329 contents_.clear();
330 references_.clear();
331 }
332
333 bool Section::GetContents(string *contents) {
334 // For each label reference, find the label's value, and patch it into
335 // the section's contents.
336 for (size_t i = 0; i < references_.size(); i++) {
337 Reference &r = references_[i];
338 u_int64_t value;
339 if (!r.label.IsKnownConstant(&value)) {
340 fprintf(stderr, "Undefined label #%d at offset 0x%x\n", i, r.offset);
341 return false;
342 }
343 assert(r.offset < contents_.size());
344 assert(contents_.size() - r.offset >= r.size);
345 InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
346 }
347 contents->clear();
348 std::swap(contents_, *contents);
349 references_.clear();
350 return true;
351 }
352
353 } // namespace TestAssembler
354 } // namespace google_breakpad
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1004:630ec63f810e-tainted