// 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>
// Derived from: // test_assembler.cc: Implementation of google_breakpad::TestAssembler. // See test_assembler.h for details.
// Derived from: // cfi_assembler.cc: Implementation of google_breakpad::CFISection class. // See cfi_assembler.h for details.
// 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
bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const {
Binding *label_base, *this_base;
uint64_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) returnfalse; if (offset_p) *offset_p = this_addend - label_addend; returntrue;
}
Label::Binding::~Binding() {
assert(reference_count_ == 0); if (base_ && base_ != this && base_->Release()) delete base_;
}
void Label::Binding::Set(Binding* binding, uint64_t addend) { if (!base_ && !binding) { // We're equating two constants. This could be okay.
assert(addend_ == addend);
} elseif (!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;
uint64_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, uint64_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;
uint64_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> staticinlinevoid InsertEndian(test_assembler::Endianness endianness,
size_t size, uint64_t number, Inserter dest) {
assert(size > 0); 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, const Label& label) { // If this label's value is known, there's no reason to waste an // entry in references_ on it.
uint64_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);
if (dwarf64) {
D32(0xffffffff);
D64(entry_length_->length);
entry_length_->start = Here(); if (eh_frame_)
D64(Here() - cie_pointer); else
D64(cie_pointer);
} else {
D32(entry_length_->length);
entry_length_->start = Here(); if (eh_frame_)
D32(Here() - cie_pointer); else
D32(cie_pointer);
}
EncodedPointer(initial_location); // The FDE length in an .eh_frame section uses the same encoding as the // initial location, but ignores the base address (selected by the upper // nybble of the encoding), as it's a length, not an address that can be // made relative.
EncodedPointer(address_range, DwarfPointerEncoding(pointer_encoding_ & 0x0f)); return *this;
}
CFISection& CFISection::EncodedPointer(uint64_t address,
DwarfPointerEncoding encoding, const EncodedPointerBases& bases) { // Omitted data is extremely easy to emit. if (encoding == lul::DW_EH_PE_omit) return *this;
// If (encoding & lul::DW_EH_PE_indirect) != 0, then we assume // that ADDRESS is the address at which the pointer is stored --- in // other words, that bit has no effect on how we write the pointer.
encoding = DwarfPointerEncoding(encoding & ~lul::DW_EH_PE_indirect);
// Find the base address to which this pointer is relative. The upper // nybble of the encoding specifies this.
uint64_t base; switch (encoding & 0xf0) { case lul::DW_EH_PE_absptr:
base = 0; break; case lul::DW_EH_PE_pcrel:
base = bases.cfi + Size(); break; case lul::DW_EH_PE_textrel:
base = bases.text; break; case lul::DW_EH_PE_datarel:
base = bases.data; break; case lul::DW_EH_PE_funcrel:
base = fde_start_address_; break; case lul::DW_EH_PE_aligned:
base = 0; break; default:
abort();
};
// Make ADDRESS relative. Yes, this is appropriate even for "absptr" // values; see gcc/unwind-pe.h.
address -= base;
// Align the pointer, if required. if ((encoding & 0xf0) == lul::DW_EH_PE_aligned) Align(AddressSize());
// Append ADDRESS to this section in the appropriate form. For the // fixed-width forms, we don't need to differentiate between signed and // unsigned encodings, because ADDRESS has already been extended to 64 // bits before it was passed to us. switch (encoding & 0x0f) { case lul::DW_EH_PE_absptr:
Address(address); break;
case lul::DW_EH_PE_uleb128:
ULEB128(address); break;
case lul::DW_EH_PE_sleb128:
LEB128(address); break;
case lul::DW_EH_PE_udata2: case lul::DW_EH_PE_sdata2:
D16(address); break;
case lul::DW_EH_PE_udata4: case lul::DW_EH_PE_sdata4:
D32(address); break;
case lul::DW_EH_PE_udata8: case lul::DW_EH_PE_sdata8:
D64(address); break;
default:
abort();
}
return *this;
};
} // namespace lul_test
Messung V0.5
¤ Dauer der Verarbeitung: 0.27 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.