Merge "ART: Do not recursively abort when visiting locks in a bad state"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index dd9f414..de0e3bd 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -117,7 +117,6 @@
runtime/monitor_pool_test.cc \
runtime/monitor_test.cc \
runtime/parsed_options_test.cc \
- runtime/proxy_test.cc \
runtime/reference_table_test.cc \
runtime/thread_pool_test.cc \
runtime/transaction_test.cc \
@@ -128,6 +127,7 @@
COMPILER_GTEST_COMMON_SRC_FILES := \
runtime/jni_internal_test.cc \
+ runtime/proxy_test.cc \
runtime/reflection_test.cc \
compiler/dex/global_value_numbering_test.cc \
compiler/dex/local_value_numbering_test.cc \
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f2a8d84..f9a78be 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -148,16 +148,18 @@
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask,
+ SrcMap* src_mapping_table,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
const std::vector<uint8_t>& native_gc_map,
const std::vector<uint8_t>* cfi_info)
: CompiledCode(driver, instruction_set, quick_code), frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
- mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
- vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
- gc_map_(driver->DeduplicateGCMap(native_gc_map)),
- cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) {
+ src_mapping_table_(driver->DeduplicateSrcMappingTable(src_mapping_table->Arrange())),
+ mapping_table_(driver->DeduplicateMappingTable(mapping_table)),
+ vmap_table_(driver->DeduplicateVMapTable(vmap_table)),
+ gc_map_(driver->DeduplicateGCMap(native_gc_map)),
+ cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) {
}
CompiledMethod::CompiledMethod(CompilerDriver* driver,
@@ -170,6 +172,7 @@
: CompiledCode(driver, instruction_set, code),
frame_size_in_bytes_(frame_size_in_bytes),
core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask),
+ src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())),
@@ -182,19 +185,22 @@
const std::string& symbol)
: CompiledCode(driver, instruction_set, code, symbol),
frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
- fp_spill_mask_(0), gc_map_(driver->DeduplicateGCMap(gc_map)) {
- mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>());
- vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>());
+ fp_spill_mask_(0),
+ src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
+ mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
+ vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
+ gc_map_(driver->DeduplicateGCMap(gc_map)) {
}
CompiledMethod::CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set,
const std::string& code, const std::string& symbol)
: CompiledCode(driver, instruction_set, code, symbol),
frame_size_in_bytes_(kStackAlignment), core_spill_mask_(0),
- fp_spill_mask_(0) {
- mapping_table_ = driver->DeduplicateMappingTable(std::vector<uint8_t>());
- vmap_table_ = driver->DeduplicateVMapTable(std::vector<uint8_t>());
- gc_map_ = driver->DeduplicateGCMap(std::vector<uint8_t>());
+ fp_spill_mask_(0),
+ src_mapping_table_(driver->DeduplicateSrcMappingTable(SrcMap())),
+ mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
+ vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
+ gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())) {
}
} // namespace art
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index c98d06a..d02cbff 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -100,7 +100,97 @@
std::vector<uint32_t> oatdata_offsets_to_compiled_code_offset_;
};
-class CompiledMethod : public CompiledCode {
+class SrcMapElem {
+ public:
+ uint32_t from_;
+ int32_t to_;
+
+ bool operator<(const SrcMapElem& sme) const {
+ uint64_t lhs = (static_cast<uint64_t>(from_) << 32) + to_;
+ uint64_t rhs = (static_cast<uint64_t>(sme.from_) << 32) + sme.to_;
+ return lhs < rhs;
+ }
+
+ operator uint8_t() const {
+ return static_cast<uint8_t>(from_ + to_);
+ }
+};
+
+class SrcMap FINAL : public std::vector<SrcMapElem> {
+ public:
+ struct CompareByTo {
+ bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+ return lhs.to_ < rhs.to_;
+ }
+ };
+
+ struct CompareByFrom {
+ bool operator()(const SrcMapElem& lhs, const SrcMapElem& rhs) {
+ return lhs.from_ < rhs.from_;
+ }
+ };
+
+ void SortByTo() {
+ std::sort(begin(), end(), CompareByTo());
+ }
+
+ void SortByFrom() {
+ std::sort(begin(), end(), CompareByFrom());
+ }
+
+ const_iterator FindByTo(int32_t to) const {
+ return std::lower_bound(begin(), end(), SrcMapElem({0, to}), CompareByTo());
+ }
+
+ SrcMap& Arrange() {
+ SortByTo();
+
+ // Remove duplicate pairs.
+ if (!empty()) {
+ SrcMap tmp;
+ tmp.swap(*this);
+ iterator it = tmp.begin();
+ iterator prev = it;
+ it++;
+ push_back(*prev);
+ for (; it != tmp.end(); it++) {
+ if (prev->from_ != it->from_ || prev->to_ != it->to_) {
+ push_back(*(prev = it));
+ }
+ }
+ }
+ return *this;
+ }
+
+ void DeltaFormat(const SrcMapElem& start, uint32_t highest_pc) {
+ // Convert from abs values to deltas.
+ if (!empty()) {
+ SortByFrom();
+
+ // TODO: one PC can be mapped to several Java src lines.
+ // do we want such a one-to-many correspondence?
+
+ // get rid of the highest values
+ size_t i = size() - 1;
+ for (; i > 0 ; i--) {
+ if ((*this)[i].from_ >= highest_pc) {
+ break;
+ }
+ }
+ this->resize(i + 1);
+
+ for (size_t i = size(); --i >= 1; ) {
+ (*this)[i].from_ -= (*this)[i-1].from_;
+ (*this)[i].to_ -= (*this)[i-1].to_;
+ }
+ DCHECK((*this)[0].from_ >= start.from_);
+ (*this)[0].from_ -= start.from_;
+ (*this)[0].to_ -= start.to_;
+ }
+ }
+};
+
+class CompiledMethod FINAL : public CompiledCode {
public:
// Constructs a CompiledMethod for the non-LLVM compilers.
CompiledMethod(CompilerDriver* driver,
@@ -109,6 +199,7 @@
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
const uint32_t fp_spill_mask,
+ SrcMap* src_mapping_table,
const std::vector<uint8_t>& mapping_table,
const std::vector<uint8_t>& vmap_table,
const std::vector<uint8_t>& native_gc_map,
@@ -145,6 +236,11 @@
return fp_spill_mask_;
}
+ const SrcMap& GetSrcMappingTable() const {
+ DCHECK(src_mapping_table_ != nullptr);
+ return *src_mapping_table_;
+ }
+
const std::vector<uint8_t>& GetMappingTable() const {
DCHECK(mapping_table_ != nullptr);
return *mapping_table_;
@@ -171,6 +267,8 @@
const uint32_t core_spill_mask_;
// For quick code, a bit mask describing spilled FPR callee-save registers.
const uint32_t fp_spill_mask_;
+ // For quick code, a set of pairs (PC, Line) mapping from native PC offset to Java line
+ SrcMap* src_mapping_table_;
// For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to
// native PC offset. Size prefixed.
std::vector<uint8_t>* mapping_table_;
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index be79b63..ebebe70 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -15,6 +15,7 @@
*/
#include "dex/compiler_internals.h"
+#include "driver/compiler_options.h"
#include "dex_file-inl.h"
#include "gc_map.h"
#include "gc_map_builder.h"
@@ -648,15 +649,19 @@
void Mir2Lir::CreateMappingTables() {
+ bool generate_src_map = cu_->compiler_driver->GetCompilerOptions().GetIncludeDebugSymbols();
+
uint32_t pc2dex_data_size = 0u;
uint32_t pc2dex_entries = 0u;
uint32_t pc2dex_offset = 0u;
uint32_t pc2dex_dalvik_offset = 0u;
+ uint32_t pc2dex_src_entries = 0u;
uint32_t dex2pc_data_size = 0u;
uint32_t dex2pc_entries = 0u;
uint32_t dex2pc_offset = 0u;
uint32_t dex2pc_dalvik_offset = 0u;
for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+ pc2dex_src_entries++;
if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
pc2dex_entries += 1;
DCHECK(pc2dex_offset <= tgt_lir->offset);
@@ -677,6 +682,10 @@
}
}
+ if (generate_src_map) {
+ src_mapping_table_.reserve(pc2dex_src_entries);
+ }
+
uint32_t total_entries = pc2dex_entries + dex2pc_entries;
uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
@@ -692,6 +701,10 @@
dex2pc_offset = 0u;
dex2pc_dalvik_offset = 0u;
for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+ if (generate_src_map && !tgt_lir->flags.is_nop) {
+ src_mapping_table_.push_back(SrcMapElem({tgt_lir->offset,
+ static_cast<int32_t>(tgt_lir->dalvik_offset)}));
+ }
if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
DCHECK(pc2dex_offset <= tgt_lir->offset);
write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset);
@@ -1088,7 +1101,7 @@
std::unique_ptr<std::vector<uint8_t>> cfi_info(ReturnFrameDescriptionEntry());
CompiledMethod* result =
new CompiledMethod(cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
- core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
+ core_spill_mask_, fp_spill_mask_, &src_mapping_table_, encoded_mapping_table_,
vmap_encoder.GetData(), native_gc_map_, cfi_info.get());
return result;
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 4b8f794..573bd91 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1715,6 +1715,8 @@
*/
int live_sreg_;
CodeBuffer code_buffer_;
+ // The source mapping table data (pc -> dex). More entries than in encoded_mapping_table_
+ SrcMap src_mapping_table_;
// The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
std::vector<uint8_t> encoded_mapping_table_;
ArenaVector<uint32_t> core_vmap_table_;
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 93b7999..6173163 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -263,8 +263,10 @@
{ kX86Cmc, kNullary, NO_OPERAND, { 0, 0, 0xF5, 0, 0, 0, 0, 0, false }, "Cmc", "" },
{ kX86Shld32RRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { 0, 0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld32RRI", "!0r,!1r,!2d" },
+ { kX86Shld32RRC, kShiftRegRegCl, IS_TERTIARY_OP | REG_DEF0_USE01 | REG_USEC | SETS_CCODES, { 0, 0, 0x0F, 0xA5, 0, 0, 0, 0, false }, "Shld32RRC", "!0r,!1r,cl" },
{ kX86Shld32MRI, kMemRegImm, IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { 0, 0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld32MRI", "[!0r+!1d],!2r,!3d" },
{ kX86Shrd32RRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { 0, 0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd32RRI", "!0r,!1r,!2d" },
+ { kX86Shrd32RRC, kShiftRegRegCl, IS_TERTIARY_OP | REG_DEF0_USE01 | REG_USEC | SETS_CCODES, { 0, 0, 0x0F, 0xAD, 0, 0, 0, 0, false }, "Shrd32RRC", "!0r,!1r,cl" },
{ kX86Shrd32MRI, kMemRegImm, IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { 0, 0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd32MRI", "[!0r+!1d],!2r,!3d" },
{ kX86Shld64RRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { REX_W, 0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld64RRI", "!0r,!1r,!2d" },
{ kX86Shld64MRI, kMemRegImm, IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { REX_W, 0, 0x0F, 0xA4, 0, 0, 0, 1, false }, "Shld64MRI", "[!0r+!1d],!2r,!3d" },
@@ -591,6 +593,7 @@
case kShiftRegCl: return true;
case kRegCond: return true;
case kRegRegCond: return true;
+ case kShiftRegRegCl: return true;
case kJmp:
switch (entry->opcode) {
case kX86JmpR: return true;
@@ -768,6 +771,9 @@
DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(lir->operands[4]));
return ComputeSize(entry, lir->operands[4], lir->operands[1], lir->operands[0],
lir->operands[3]);
+ case kShiftRegRegCl: // lir operands - 0: reg1, 1: reg2, 2: cl
+ DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(lir->operands[2]));
+ return ComputeSize(entry, lir->operands[0], NO_REG, lir->operands[1], 0);
case kRegCond: // lir operands - 0: reg, 1: cond
return ComputeSize(entry, NO_REG, NO_REG, lir->operands[0], 0);
case kMemCond: // lir operands - 0: base, 1: disp, 2: cond
@@ -1336,6 +1342,19 @@
DCHECK_EQ(0, entry->skeleton.immediate_bytes);
}
+void X86Mir2Lir::EmitShiftRegRegCl(const X86EncodingMap* entry, int32_t raw_reg1, int32_t raw_reg2, int32_t raw_cl) {
+ DCHECK_EQ(false, entry->skeleton.r8_form);
+ DCHECK_EQ(rs_rCX.GetRegNum(), RegStorage::RegNum(raw_cl));
+ EmitPrefixAndOpcode(entry, raw_reg1, NO_REG, raw_reg2);
+ uint8_t low_reg1 = LowRegisterBits(raw_reg1);
+ uint8_t low_reg2 = LowRegisterBits(raw_reg2);
+ uint8_t modrm = (3 << 6) | (low_reg1 << 3) | low_reg2;
+ code_buffer_.push_back(modrm);
+ DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+ DCHECK_EQ(0, entry->skeleton.ax_opcode);
+ DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
void X86Mir2Lir::EmitShiftMemImm(const X86EncodingMap* entry, int32_t raw_base, int32_t disp,
int32_t imm) {
DCHECK_EQ(false, entry->skeleton.r8_form);
@@ -1829,6 +1848,9 @@
case kShiftMemCl: // lir operands - 0: base, 1:displacement, 2: cl
EmitShiftMemCl(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
break;
+ case kShiftRegRegCl: // lir operands - 0: reg1, 1: reg2, 2: cl
+ EmitShiftRegRegCl(entry, lir->operands[1], lir->operands[0], lir->operands[2]);
+ break;
case kRegCond: // lir operands - 0: reg, 1: condition
EmitRegCond(entry, lir->operands[0], lir->operands[1]);
break;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 1f5b350..7d1e20e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -457,6 +457,8 @@
void EmitShiftRegImm(const X86EncodingMap* entry, int32_t raw_reg, int32_t imm);
void EmitShiftRegCl(const X86EncodingMap* entry, int32_t raw_reg, int32_t raw_cl);
void EmitShiftMemCl(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t raw_cl);
+ void EmitShiftRegRegCl(const X86EncodingMap* entry, int32_t raw_reg1, int32_t raw_reg2,
+ int32_t raw_cl);
void EmitShiftMemImm(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t imm);
void EmitRegCond(const X86EncodingMap* entry, int32_t raw_reg, int32_t cc);
void EmitMemCond(const X86EncodingMap* entry, int32_t raw_base, int32_t disp, int32_t cc);
@@ -478,8 +480,10 @@
void GenConstWide(RegLocation rl_dest, int64_t value);
void GenMultiplyVectorSignedByte(BasicBlock *bb, MIR *mir);
void GenShiftByteVector(BasicBlock *bb, MIR *mir);
- void AndMaskVectorRegister(RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3, uint32_t m4);
- void MaskVectorRegister(X86OpCode opcode, RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3, uint32_t m4);
+ void AndMaskVectorRegister(RegStorage rs_src1, uint32_t m1, uint32_t m2, uint32_t m3,
+ uint32_t m4);
+ void MaskVectorRegister(X86OpCode opcode, RegStorage rs_src1, uint32_t m1, uint32_t m2,
+ uint32_t m3, uint32_t m4);
void AppendOpcodeWithConst(X86OpCode opcode, int reg, MIR* mir);
static bool ProvidesFullMemoryBarrier(X86OpCode opcode);
@@ -551,7 +555,8 @@
void GenMoveVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed multiply of units in two vector registers: vB = vB .* @note vC using vA to know the type of the vector.
+ * @brief Packed multiply of units in two vector registers: vB = vB .* @note vC using vA to know
+ * the type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -561,7 +566,8 @@
void GenMultiplyVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the type of the vector.
+ * @brief Packed addition of units in two vector registers: vB = vB .+ vC using vA to know the
+ * type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -571,7 +577,8 @@
void GenAddVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the type of the vector.
+ * @brief Packed subtraction of units in two vector registers: vB = vB .- vC using vA to know the
+ * type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -581,7 +588,8 @@
void GenSubtractVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the type of the vector.
+ * @brief Packed shift left of units in two vector registers: vB = vB .<< vC using vA to know the
+ * type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -591,7 +599,8 @@
void GenShiftLeftVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to know the type of the vector.
+ * @brief Packed signed shift right of units in two vector registers: vB = vB .>> vC using vA to
+ * know the type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -601,7 +610,8 @@
void GenSignedShiftRightVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA to know the type of the vector.
+ * @brief Packed unsigned shift right of units in two vector registers: vB = vB .>>> vC using vA
+ * to know the type of the vector.
* @param bb The basic block in which the MIR is from..
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -611,7 +621,8 @@
void GenUnsignedShiftRightVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the type of the vector.
+ * @brief Packed bitwise and of units in two vector registers: vB = vB .& vC using vA to know the
+ * type of the vector.
* @note vA: TypeSize
* @note vB: destination and source
* @note vC: source
@@ -619,7 +630,8 @@
void GenAndVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the type of the vector.
+ * @brief Packed bitwise or of units in two vector registers: vB = vB .| vC using vA to know the
+ * type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
@@ -629,7 +641,8 @@
void GenOrVector(BasicBlock *bb, MIR *mir);
/*
- * @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the type of the vector.
+ * @brief Packed bitwise xor of units in two vector registers: vB = vB .^ vC using vA to know the
+ * type of the vector.
* @param bb The basic block in which the MIR is from.
* @param mir The MIR whose opcode is kMirConstVector.
* @note vA: TypeSize
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index afa2ae2..cc51538 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -793,8 +793,115 @@
bool X86Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) {
DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64);
- if (is_long && cu_->instruction_set == kX86) {
- return false;
+ if (is_long && !cu_->target64) {
+ /*
+ * We want to implement the following algorithm
+ * mov eax, low part of arg1
+ * mov edx, high part of arg1
+ * mov ebx, low part of arg2
+ * mov ecx, high part of arg2
+ * mov edi, eax
+ * sub edi, ebx
+ * mov edi, edx
+ * sbb edi, ecx
+ * is_min ? "cmovgel eax, ebx" : "cmovll eax, ebx"
+ * is_min ? "cmovgel edx, ecx" : "cmovll edx, ecx"
+ *
+ * The algorithm above needs 5 registers: a pair for the first operand
+ * (which later will be used as result), a pair for the second operand
+ * and a temp register (e.g. 'edi') for intermediate calculations.
+ * Ideally we have 6 GP caller-save registers in 32-bit mode. They are:
+ * 'eax', 'ebx', 'ecx', 'edx', 'esi' and 'edi'. So there should be
+ * always enough registers to operate on. Practically, there is a pair
+ * of registers 'edi' and 'esi' which holds promoted values and
+ * sometimes should be treated as 'callee save'. If one of the operands
+ * is in the promoted registers then we have enough register to
+ * operate on. Otherwise there is lack of resources and we have to
+ * save 'edi' before calculations and restore after.
+ */
+
+ RegLocation rl_src1 = info->args[0];
+ RegLocation rl_src2 = info->args[2];
+ RegLocation rl_dest = InlineTargetWide(info);
+ int res_vreg, src1_vreg, src2_vreg;
+
+ /*
+ * If the result register is the same as the second element, then we
+ * need to be careful. The reason is that the first copy will
+ * inadvertently clobber the second element with the first one thus
+ * yielding the wrong result. Thus we do a swap in that case.
+ */
+ res_vreg = mir_graph_->SRegToVReg(rl_dest.s_reg_low);
+ src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+ if (res_vreg == src2_vreg) {
+ std::swap(rl_src1, rl_src2);
+ }
+
+ rl_src1 = LoadValueWide(rl_src1, kCoreReg);
+ RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+
+ // Pick the first integer as min/max.
+ OpRegCopyWide(rl_result.reg, rl_src1.reg);
+
+ /*
+ * If the integers are both in the same register, then there is
+ * nothing else to do because they are equal and we have already
+ * moved one into the result.
+ */
+ src1_vreg = mir_graph_->SRegToVReg(rl_src1.s_reg_low);
+ src2_vreg = mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+ if (src1_vreg == src2_vreg) {
+ StoreValueWide(rl_dest, rl_result);
+ return true;
+ }
+
+ // Free registers to make some room for the second operand.
+ // But don't try to free ourselves or promoted registers.
+ if (res_vreg != src1_vreg &&
+ IsTemp(rl_src1.reg.GetLow()) && IsTemp(rl_src1.reg.GetHigh())) {
+ FreeTemp(rl_src1.reg);
+ }
+ rl_src2 = LoadValueWide(rl_src2, kCoreReg);
+
+ // Do we have a free register for intermediate calculations?
+ RegStorage tmp = AllocTemp(false);
+ if (tmp == RegStorage::InvalidReg()) {
+ /*
+ * No, will use 'edi'.
+ *
+ * As mentioned above we have 4 temporary and 2 promotable
+ * caller-save registers. Therefore, we assume that a free
+ * register can be allocated only if 'esi' and 'edi' are
+ * already used as operands. If number of promotable registers
+ * increases from 2 to 4 then our assumption fails and operand
+ * data is corrupted.
+ * Let's DCHECK it.
+ */
+ DCHECK(IsTemp(rl_src2.reg.GetLow()) &&
+ IsTemp(rl_src2.reg.GetHigh()) &&
+ IsTemp(rl_result.reg.GetLow()) &&
+ IsTemp(rl_result.reg.GetHigh()));
+ tmp = rs_rDI;
+ NewLIR1(kX86Push32R, tmp.GetReg());
+ }
+
+ // Now we are ready to do calculations.
+ OpRegReg(kOpMov, tmp, rl_result.reg.GetLow());
+ OpRegReg(kOpSub, tmp, rl_src2.reg.GetLow());
+ OpRegReg(kOpMov, tmp, rl_result.reg.GetHigh());
+ OpRegReg(kOpSbc, tmp, rl_src2.reg.GetHigh());
+
+ // Let's put pop 'edi' here to break a bit the dependency chain.
+ if (tmp == rs_rDI) {
+ NewLIR1(kX86Pop32R, tmp.GetReg());
+ }
+
+ // Conditionally move the other integer into the destination register.
+ ConditionCode cc = is_min ? kCondGe : kCondLt;
+ OpCondRegReg(kOpCmov, cc, rl_result.reg.GetLow(), rl_src2.reg.GetLow());
+ OpCondRegReg(kOpCmov, cc, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh());
+ StoreValueWide(rl_dest, rl_result);
+ return true;
}
// Get the two arguments to the invoke and place them in GP registers.
@@ -3033,7 +3140,53 @@
void X86Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest,
RegLocation rl_src1, RegLocation rl_shift) {
if (!cu_->target64) {
- Mir2Lir::GenShiftOpLong(opcode, rl_dest, rl_src1, rl_shift);
+ // Long shift operations in 32-bit. Use shld or shrd to create a 32-bit register filled from
+ // the other half, shift the other half, if the shift amount is less than 32 we're done,
+ // otherwise move one register to the other and place zero or sign bits in the other.
+ LIR* branch;
+ FlushAllRegs();
+ LockCallTemps();
+ LoadValueDirectFixed(rl_shift, rs_rCX);
+ RegStorage r_tmp = RegStorage::MakeRegPair(rs_rAX, rs_rDX);
+ LoadValueDirectWideFixed(rl_src1, r_tmp);
+ switch (opcode) {
+ case Instruction::SHL_LONG:
+ case Instruction::SHL_LONG_2ADDR:
+ NewLIR3(kX86Shld32RRC, r_tmp.GetHighReg(), r_tmp.GetLowReg(), rs_rCX.GetReg());
+ NewLIR2(kX86Sal32RC, r_tmp.GetLowReg(), rs_rCX.GetReg());
+ NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+ branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+ OpRegCopy(r_tmp.GetHigh(), r_tmp.GetLow());
+ LoadConstant(r_tmp.GetLow(), 0);
+ branch->target = NewLIR0(kPseudoTargetLabel);
+ break;
+ case Instruction::SHR_LONG:
+ case Instruction::SHR_LONG_2ADDR:
+ NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(), rs_rCX.GetReg());
+ NewLIR2(kX86Sar32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
+ NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+ branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+ OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
+ NewLIR2(kX86Sar32RI, r_tmp.GetHighReg(), 31);
+ branch->target = NewLIR0(kPseudoTargetLabel);
+ break;
+ case Instruction::USHR_LONG:
+ case Instruction::USHR_LONG_2ADDR:
+ NewLIR3(kX86Shrd32RRC, r_tmp.GetLowReg(), r_tmp.GetHighReg(),
+ rs_rCX.GetReg());
+ NewLIR2(kX86Shr32RC, r_tmp.GetHighReg(), rs_rCX.GetReg());
+ NewLIR2(kX86Test8RI, rs_rCX.GetReg(), 32);
+ branch = NewLIR2(kX86Jcc8, 0, kX86CondZ);
+ OpRegCopy(r_tmp.GetLow(), r_tmp.GetHigh());
+ LoadConstant(r_tmp.GetHigh(), 0);
+ branch->target = NewLIR0(kPseudoTargetLabel);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected case: " << opcode;
+ return;
+ }
+ RegLocation rl_result = LocCReturnWide();
+ StoreValueWide(rl_dest, rl_result);
return;
}
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 95941e0..f4bb40c 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -760,10 +760,7 @@
RegisterClass X86Mir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
// X86_64 can handle any size.
if (cu_->target64) {
- if (size == kReference) {
- return kRefReg;
- }
- return kCoreReg;
+ return RegClassBySize(size);
}
if (UNLIKELY(is_volatile)) {
@@ -1439,8 +1436,8 @@
// Generate the FDE for the method.
DCHECK_NE(data_offset_, 0U);
- WriteFDEHeader(cfi_info);
- WriteFDEAddressRange(cfi_info, data_offset_);
+ WriteFDEHeader(cfi_info, cu_->target64);
+ WriteFDEAddressRange(cfi_info, data_offset_, cu_->target64);
// The instructions in the FDE.
if (stack_decrement_ != nullptr) {
@@ -1500,7 +1497,7 @@
}
PadCFI(cfi_info);
- WriteCFILength(cfi_info);
+ WriteCFILength(cfi_info, cu_->target64);
return cfi_info;
}
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 500c6b8..9620cd1 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -484,8 +484,10 @@
#undef BinaryShiftOpcode
kX86Cmc,
kX86Shld32RRI,
+ kX86Shld32RRC,
kX86Shld32MRI,
kX86Shrd32RRI,
+ kX86Shrd32RRC,
kX86Shrd32MRI,
kX86Shld64RRI,
kX86Shld64MRI,
@@ -675,6 +677,7 @@
kMemRegImm, // MRI instruction kinds.
kShiftRegImm, kShiftMemImm, kShiftArrayImm, // Shift opcode with immediate.
kShiftRegCl, kShiftMemCl, kShiftArrayCl, // Shift opcode with register CL.
+ kShiftRegRegCl,
// kRegRegReg, kRegRegMem, kRegRegArray, // RRR, RRM, RRA instruction kinds.
kRegCond, kMemCond, kArrayCond, // R, M, A instruction kinds following by a condition.
kRegRegCond, // RR instruction kind followed by a condition.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 645fc1c..3915381 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -354,6 +354,7 @@
compiler_get_method_code_addr_(NULL),
support_boot_image_fixup_(instruction_set != kMips),
dedupe_code_("dedupe code"),
+ dedupe_src_mapping_table_("dedupe source mapping table"),
dedupe_mapping_table_("dedupe mapping table"),
dedupe_vmap_table_("dedupe vmap table"),
dedupe_gc_map_("dedupe gc map"),
@@ -390,6 +391,10 @@
return dedupe_code_.Add(Thread::Current(), code);
}
+SrcMap* CompilerDriver::DeduplicateSrcMappingTable(const SrcMap& src_map) {
+ return dedupe_src_mapping_table_.Add(Thread::Current(), src_map);
+}
+
std::vector<uint8_t>* CompilerDriver::DeduplicateMappingTable(const std::vector<uint8_t>& code) {
return dedupe_mapping_table_.Add(Thread::Current(), code);
}
@@ -1524,7 +1529,13 @@
return true;
}
- return SkipClassCheckClassPath(descriptor, dex_file, dex_files);
+ if (dex_files.size() > 1) {
+ // Multi-dex compilation, only take first class.
+ return SkipClassCheckClassPath(descriptor, dex_file, dex_files);
+ } else {
+ // Single dex, take everything.
+ return false;
+ }
}
// A fast version of SkipClass above if the class pointer is available
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 233c4f8..d8f318b 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -601,6 +601,7 @@
LOCKS_EXCLUDED(compiled_classes_lock_);
std::vector<uint8_t>* DeduplicateCode(const std::vector<uint8_t>& code);
+ SrcMap* DeduplicateSrcMappingTable(const SrcMap& src_map);
std::vector<uint8_t>* DeduplicateMappingTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateVMapTable(const std::vector<uint8_t>& code);
std::vector<uint8_t>* DeduplicateGCMap(const std::vector<uint8_t>& code);
@@ -770,14 +771,15 @@
bool support_boot_image_fixup_;
// DeDuplication data structures, these own the corresponding byte arrays.
+ template <typename ByteArray>
class DedupeHashFunc {
public:
- size_t operator()(const std::vector<uint8_t>& array) const {
+ size_t operator()(const ByteArray& array) const {
// For small arrays compute a hash using every byte.
static const size_t kSmallArrayThreshold = 16;
size_t hash = 0x811c9dc5;
if (array.size() <= kSmallArrayThreshold) {
- for (uint8_t b : array) {
+ for (auto b : array) {
hash = (hash * 16777619) ^ b;
}
} else {
@@ -803,11 +805,13 @@
return hash;
}
};
- DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_code_;
- DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_mapping_table_;
- DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_vmap_table_;
- DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_gc_map_;
- DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc, 4> dedupe_cfi_info_;
+
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_code_;
+ DedupeSet<SrcMap, size_t, DedupeHashFunc<SrcMap>, 4> dedupe_src_mapping_table_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_mapping_table_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_vmap_table_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_gc_map_;
+ DedupeSet<std::vector<uint8_t>, size_t, DedupeHashFunc<std::vector<uint8_t>>, 4> dedupe_cfi_info_;
DISALLOW_COPY_AND_ASSIGN(CompilerDriver);
};
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
index 60f76ef..bbfbc6e 100644
--- a/compiler/elf_fixup.cc
+++ b/compiler/elf_fixup.cc
@@ -38,28 +38,32 @@
Elf32_Off base_address = oat_data_begin - oatdata_address;
if (!FixupDynamic(*elf_file.get(), base_address)) {
- LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup .dynamic in " << file->GetPath();
+ return false;
}
if (!FixupSectionHeaders(*elf_file.get(), base_address)) {
- LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup section headers in " << file->GetPath();
+ return false;
}
if (!FixupProgramHeaders(*elf_file.get(), base_address)) {
- LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup program headers in " << file->GetPath();
+ return false;
}
if (!FixupSymbols(*elf_file.get(), base_address, true)) {
- LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup .dynsym in " << file->GetPath();
+ return false;
}
if (!FixupSymbols(*elf_file.get(), base_address, false)) {
- LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup .symtab in " << file->GetPath();
+ return false;
}
if (!FixupRelocations(*elf_file.get(), base_address)) {
- LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath();
- return false;
+ LOG(WARNING) << "Failed to fixup .rel.dyn in " << file->GetPath();
+ return false;
+ }
+ if (!elf_file->FixupDebugSections(base_address)) {
+ LOG(WARNING) << "Failed to fixup debug sections in " << file->GetPath();
+ return false;
}
return true;
}
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index bb5f7e0..e45eb61 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -16,11 +16,14 @@
#include "elf_writer_quick.h"
+#include <unordered_map>
+
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
#include "buffered_output_stream.h"
#include "driver/compiler_driver.h"
#include "dwarf.h"
+#include "elf_file.h"
#include "elf_utils.h"
#include "file_output_stream.h"
#include "globals.h"
@@ -39,6 +42,30 @@
return ((binding) << 4) + ((type) & 0xf);
}
+static void PushByte(std::vector<uint8_t>* buf, int data) {
+ buf->push_back(data & 0xff);
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const char* str, const char* def = nullptr) {
+ if (str == nullptr) {
+ str = def;
+ }
+
+ uint32_t offset = buf->size();
+ for (size_t i = 0; str[i] != '\0'; ++i) {
+ buf->push_back(str[i]);
+ }
+ buf->push_back('\0');
+ return offset;
+}
+
+static uint32_t PushStr(std::vector<uint8_t>* buf, const std::string &str) {
+ uint32_t offset = buf->size();
+ buf->insert(buf->end(), str.begin(), str.end());
+ buf->push_back('\0');
+ return offset;
+}
+
static void UpdateWord(std::vector<uint8_t>* buf, int offset, int data) {
(*buf)[offset+0] = data;
(*buf)[offset+1] = data >> 8;
@@ -51,7 +78,7 @@
buf->push_back((data >> 8) & 0xff);
}
-bool ElfWriterQuick::ElfBuilder::Write() {
+bool ElfWriterQuick::ElfBuilder::Init() {
// The basic layout of the elf file. Order may be different in final output.
// +-------------------------+
// | Elf32_Ehdr |
@@ -120,16 +147,19 @@
// | .debug_str\0 | (Optional)
// | .debug_info\0 | (Optional)
// | .eh_frame\0 | (Optional)
+ // | .debug_line\0 | (Optional)
// | .debug_abbrev\0 | (Optional)
// +-------------------------+ (Optional)
- // | .debug_str | (Optional)
- // +-------------------------+ (Optional)
// | .debug_info | (Optional)
// +-------------------------+ (Optional)
+ // | .debug_abbrev | (Optional)
+ // +-------------------------+ (Optional)
// | .eh_frame | (Optional)
// +-------------------------+ (Optional)
- // | .debug_abbrev | (Optional)
- // +-------------------------+
+ // | .debug_line | (Optional)
+ // +-------------------------+ (Optional)
+ // | .debug_str | (Optional)
+ // +-------------------------+ (Optional)
// | Elf32_Shdr NULL |
// | Elf32_Shdr .dynsym |
// | Elf32_Shdr .dynstr |
@@ -138,173 +168,117 @@
// | Elf32_Shdr .rodata |
// | Elf32_Shdr .dynamic |
// | Elf32_Shdr .shstrtab |
- // | Elf32_Shdr .debug_str | (Optional)
// | Elf32_Shdr .debug_info | (Optional)
- // | Elf32_Shdr .eh_frame | (Optional)
// | Elf32_Shdr .debug_abbrev| (Optional)
+ // | Elf32_Shdr .eh_frame | (Optional)
+ // | Elf32_Shdr .debug_line | (Optional)
+ // | Elf32_Shdr .debug_str | (Optional)
// +-------------------------+
-
if (fatal_error_) {
return false;
}
// Step 1. Figure out all the offsets.
- // What phdr is.
- uint32_t phdr_offset = sizeof(Elf32_Ehdr);
- const uint8_t PH_PHDR = 0;
- const uint8_t PH_LOAD_R__ = 1;
- const uint8_t PH_LOAD_R_X = 2;
- const uint8_t PH_LOAD_RW_ = 3;
- const uint8_t PH_DYNAMIC = 4;
- const uint8_t PH_NUM = 5;
- uint32_t phdr_size = sizeof(Elf32_Phdr) * PH_NUM;
if (debug_logging_) {
- LOG(INFO) << "phdr_offset=" << phdr_offset << std::hex << " " << phdr_offset;
- LOG(INFO) << "phdr_size=" << phdr_size << std::hex << " " << phdr_size;
+ LOG(INFO) << "phdr_offset=" << PHDR_OFFSET << std::hex << " " << PHDR_OFFSET;
+ LOG(INFO) << "phdr_size=" << PHDR_SIZE << std::hex << " " << PHDR_SIZE;
}
- Elf32_Phdr program_headers[PH_NUM];
- memset(&program_headers, 0, sizeof(program_headers));
- program_headers[PH_PHDR].p_type = PT_PHDR;
- program_headers[PH_PHDR].p_offset = phdr_offset;
- program_headers[PH_PHDR].p_vaddr = phdr_offset;
- program_headers[PH_PHDR].p_paddr = phdr_offset;
- program_headers[PH_PHDR].p_filesz = sizeof(program_headers);
- program_headers[PH_PHDR].p_memsz = sizeof(program_headers);
- program_headers[PH_PHDR].p_flags = PF_R;
- program_headers[PH_PHDR].p_align = sizeof(Elf32_Word);
- program_headers[PH_LOAD_R__].p_type = PT_LOAD;
- program_headers[PH_LOAD_R__].p_offset = 0;
- program_headers[PH_LOAD_R__].p_vaddr = 0;
- program_headers[PH_LOAD_R__].p_paddr = 0;
- program_headers[PH_LOAD_R__].p_flags = PF_R;
+ memset(&program_headers_, 0, sizeof(program_headers_));
+ program_headers_[PH_PHDR].p_type = PT_PHDR;
+ program_headers_[PH_PHDR].p_offset = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_vaddr = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_paddr = PHDR_OFFSET;
+ program_headers_[PH_PHDR].p_filesz = sizeof(program_headers_);
+ program_headers_[PH_PHDR].p_memsz = sizeof(program_headers_);
+ program_headers_[PH_PHDR].p_flags = PF_R;
+ program_headers_[PH_PHDR].p_align = sizeof(Elf32_Word);
- program_headers[PH_LOAD_R_X].p_type = PT_LOAD;
- program_headers[PH_LOAD_R_X].p_flags = PF_R | PF_X;
+ program_headers_[PH_LOAD_R__].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_R__].p_offset = 0;
+ program_headers_[PH_LOAD_R__].p_vaddr = 0;
+ program_headers_[PH_LOAD_R__].p_paddr = 0;
+ program_headers_[PH_LOAD_R__].p_flags = PF_R;
- program_headers[PH_LOAD_RW_].p_type = PT_LOAD;
- program_headers[PH_LOAD_RW_].p_flags = PF_R | PF_W;
+ program_headers_[PH_LOAD_R_X].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_R_X].p_flags = PF_R | PF_X;
- program_headers[PH_DYNAMIC].p_type = PT_DYNAMIC;
- program_headers[PH_DYNAMIC].p_flags = PF_R | PF_W;
+ program_headers_[PH_LOAD_RW_].p_type = PT_LOAD;
+ program_headers_[PH_LOAD_RW_].p_flags = PF_R | PF_W;
+
+ program_headers_[PH_DYNAMIC].p_type = PT_DYNAMIC;
+ program_headers_[PH_DYNAMIC].p_flags = PF_R | PF_W;
// Get the dynstr string.
- std::string dynstr(dynsym_builder_.GenerateStrtab());
+ dynstr_ = dynsym_builder_.GenerateStrtab();
// Add the SONAME to the dynstr.
- uint32_t dynstr_soname_offset = dynstr.size();
+ dynstr_soname_offset_ = dynstr_.size();
std::string file_name(elf_file_->GetPath());
size_t directory_separator_pos = file_name.rfind('/');
if (directory_separator_pos != std::string::npos) {
file_name = file_name.substr(directory_separator_pos + 1);
}
- dynstr += file_name;
- dynstr += '\0';
+ dynstr_ += file_name;
+ dynstr_ += '\0';
if (debug_logging_) {
- LOG(INFO) << "dynstr size (bytes) =" << dynstr.size()
- << std::hex << " " << dynstr.size();
+ LOG(INFO) << "dynstr size (bytes) =" << dynstr_.size()
+ << std::hex << " " << dynstr_.size();
LOG(INFO) << "dynsym size (elements)=" << dynsym_builder_.GetSize()
<< std::hex << " " << dynsym_builder_.GetSize();
}
- // get the strtab
- std::string strtab;
- if (IncludingDebugSymbols()) {
- strtab = symtab_builder_.GenerateStrtab();
- if (debug_logging_) {
- LOG(INFO) << "strtab size (bytes) =" << strtab.size()
- << std::hex << " " << strtab.size();
- LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
- << std::hex << " " << symtab_builder_.GetSize();
- }
- }
-
// Get the section header string table.
- std::vector<Elf32_Shdr*> section_ptrs;
- std::string shstrtab;
- shstrtab += '\0';
+ shstrtab_ += '\0';
// Setup sym_undef
- Elf32_Shdr null_hdr;
- memset(&null_hdr, 0, sizeof(null_hdr));
- null_hdr.sh_type = SHT_NULL;
- null_hdr.sh_link = SHN_UNDEF;
- section_ptrs.push_back(&null_hdr);
+ memset(&null_hdr_, 0, sizeof(null_hdr_));
+ null_hdr_.sh_type = SHT_NULL;
+ null_hdr_.sh_link = SHN_UNDEF;
+ section_ptrs_.push_back(&null_hdr_);
- uint32_t section_index = 1;
+ section_index_ = 1;
// setup .dynsym
- section_ptrs.push_back(&dynsym_builder_.section_);
- AssignSectionStr(&dynsym_builder_, &shstrtab);
- dynsym_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&dynsym_builder_.section_);
+ AssignSectionStr(&dynsym_builder_, &shstrtab_);
+ dynsym_builder_.section_index_ = section_index_++;
// Setup .dynstr
- section_ptrs.push_back(&dynsym_builder_.strtab_.section_);
- AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab);
- dynsym_builder_.strtab_.section_index_ = section_index++;
+ section_ptrs_.push_back(&dynsym_builder_.strtab_.section_);
+ AssignSectionStr(&dynsym_builder_.strtab_, &shstrtab_);
+ dynsym_builder_.strtab_.section_index_ = section_index_++;
// Setup .hash
- section_ptrs.push_back(&hash_builder_.section_);
- AssignSectionStr(&hash_builder_, &shstrtab);
- hash_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&hash_builder_.section_);
+ AssignSectionStr(&hash_builder_, &shstrtab_);
+ hash_builder_.section_index_ = section_index_++;
// Setup .rodata
- section_ptrs.push_back(&rodata_builder_.section_);
- AssignSectionStr(&rodata_builder_, &shstrtab);
- rodata_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&rodata_builder_.section_);
+ AssignSectionStr(&rodata_builder_, &shstrtab_);
+ rodata_builder_.section_index_ = section_index_++;
// Setup .text
- section_ptrs.push_back(&text_builder_.section_);
- AssignSectionStr(&text_builder_, &shstrtab);
- text_builder_.section_index_ = section_index++;
+ section_ptrs_.push_back(&text_builder_.section_);
+ AssignSectionStr(&text_builder_, &shstrtab_);
+ text_builder_.section_index_ = section_index_++;
// Setup .dynamic
- section_ptrs.push_back(&dynamic_builder_.section_);
- AssignSectionStr(&dynamic_builder_, &shstrtab);
- dynamic_builder_.section_index_ = section_index++;
-
- if (IncludingDebugSymbols()) {
- // Setup .symtab
- section_ptrs.push_back(&symtab_builder_.section_);
- AssignSectionStr(&symtab_builder_, &shstrtab);
- symtab_builder_.section_index_ = section_index++;
-
- // Setup .strtab
- section_ptrs.push_back(&symtab_builder_.strtab_.section_);
- AssignSectionStr(&symtab_builder_.strtab_, &shstrtab);
- symtab_builder_.strtab_.section_index_ = section_index++;
- }
- ElfRawSectionBuilder* it = other_builders_.data();
- for (uint32_t cnt = 0; cnt < other_builders_.size(); ++it, ++cnt) {
- // Setup all the other sections.
- section_ptrs.push_back(&it->section_);
- AssignSectionStr(it, &shstrtab);
- it->section_index_ = section_index++;
- }
-
- // Setup shstrtab
- section_ptrs.push_back(&shstrtab_builder_.section_);
- AssignSectionStr(&shstrtab_builder_, &shstrtab);
- shstrtab_builder_.section_index_ = section_index++;
-
- if (debug_logging_) {
- LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab.size()
- << std::hex << " " << shstrtab.size();
- LOG(INFO) << "section list size (elements)=" << section_ptrs.size()
- << std::hex << " " << section_ptrs.size();
- }
+ section_ptrs_.push_back(&dynamic_builder_.section_);
+ AssignSectionStr(&dynamic_builder_, &shstrtab_);
+ dynamic_builder_.section_index_ = section_index_++;
// Fill in the hash section.
- std::vector<Elf32_Word> hash = dynsym_builder_.GenerateHashContents();
+ hash_ = dynsym_builder_.GenerateHashContents();
if (debug_logging_) {
- LOG(INFO) << ".hash size (bytes)=" << hash.size() * sizeof(Elf32_Word)
- << std::hex << " " << hash.size() * sizeof(Elf32_Word);
+ LOG(INFO) << ".hash size (bytes)=" << hash_.size() * sizeof(Elf32_Word)
+ << std::hex << " " << hash_.size() * sizeof(Elf32_Word);
}
- Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers);
- std::vector<ElfFilePiece> pieces;
+ Elf32_Word base_offset = sizeof(Elf32_Ehdr) + sizeof(program_headers_);
// Get the layout in the sections.
//
@@ -318,14 +292,14 @@
dynsym_builder_.strtab_.section_.sh_offset = NextOffset(dynsym_builder_.strtab_.section_,
dynsym_builder_.section_);
dynsym_builder_.strtab_.section_.sh_addr = dynsym_builder_.strtab_.section_.sh_offset;
- dynsym_builder_.strtab_.section_.sh_size = dynstr.size();
+ dynsym_builder_.strtab_.section_.sh_size = dynstr_.size();
dynsym_builder_.strtab_.section_.sh_link = dynsym_builder_.strtab_.GetLink();
// Get the layout of the hash section
hash_builder_.section_.sh_offset = NextOffset(hash_builder_.section_,
dynsym_builder_.strtab_.section_);
hash_builder_.section_.sh_addr = hash_builder_.section_.sh_offset;
- hash_builder_.section_.sh_size = hash.size() * sizeof(Elf32_Word);
+ hash_builder_.section_.sh_size = hash_.size() * sizeof(Elf32_Word);
hash_builder_.section_.sh_link = hash_builder_.GetLink();
// Get the layout of the rodata section.
@@ -349,7 +323,70 @@
dynamic_builder_.section_.sh_size = dynamic_builder_.GetSize() * sizeof(Elf32_Dyn);
dynamic_builder_.section_.sh_link = dynamic_builder_.GetLink();
+ if (debug_logging_) {
+ LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
+ << " dynsym size=" << dynsym_builder_.section_.sh_size;
+ LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
+ << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
+ LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
+ << " hash size=" << hash_builder_.section_.sh_size;
+ LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
+ << " rodata size=" << rodata_builder_.section_.sh_size;
+ LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
+ << " text size=" << text_builder_.section_.sh_size;
+ LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
+ << " dynamic size=" << dynamic_builder_.section_.sh_size;
+ }
+
+ return true;
+}
+
+bool ElfWriterQuick::ElfBuilder::Write() {
+ std::vector<ElfFilePiece> pieces;
Elf32_Shdr prev = dynamic_builder_.section_;
+ std::string strtab;
+
+ if (IncludingDebugSymbols()) {
+ // Setup .symtab
+ section_ptrs_.push_back(&symtab_builder_.section_);
+ AssignSectionStr(&symtab_builder_, &shstrtab_);
+ symtab_builder_.section_index_ = section_index_++;
+
+ // Setup .strtab
+ section_ptrs_.push_back(&symtab_builder_.strtab_.section_);
+ AssignSectionStr(&symtab_builder_.strtab_, &shstrtab_);
+ symtab_builder_.strtab_.section_index_ = section_index_++;
+
+ strtab = symtab_builder_.GenerateStrtab();
+ if (debug_logging_) {
+ LOG(INFO) << "strtab size (bytes) =" << strtab.size()
+ << std::hex << " " << strtab.size();
+ LOG(INFO) << "symtab size (elements) =" << symtab_builder_.GetSize()
+ << std::hex << " " << symtab_builder_.GetSize();
+ }
+ }
+
+ // Setup all the other sections.
+ for (ElfRawSectionBuilder *builder = other_builders_.data(),
+ *end = builder + other_builders_.size();
+ builder != end; ++builder) {
+ section_ptrs_.push_back(&builder->section_);
+ AssignSectionStr(builder, &shstrtab_);
+ builder->section_index_ = section_index_++;
+ }
+
+ // Setup shstrtab
+ section_ptrs_.push_back(&shstrtab_builder_.section_);
+ AssignSectionStr(&shstrtab_builder_, &shstrtab_);
+ shstrtab_builder_.section_index_ = section_index_++;
+
+ if (debug_logging_) {
+ LOG(INFO) << ".shstrtab size (bytes) =" << shstrtab_.size()
+ << std::hex << " " << shstrtab_.size();
+ LOG(INFO) << "section list size (elements)=" << section_ptrs_.size()
+ << std::hex << " " << section_ptrs_.size();
+ }
+
if (IncludingDebugSymbols()) {
// Get the layout of the symtab section.
symtab_builder_.section_.sh_offset = NextOffset(symtab_builder_.section_,
@@ -367,27 +404,14 @@
symtab_builder_.strtab_.section_.sh_link = symtab_builder_.strtab_.GetLink();
prev = symtab_builder_.strtab_.section_;
- }
- if (debug_logging_) {
- LOG(INFO) << "dynsym off=" << dynsym_builder_.section_.sh_offset
- << " dynsym size=" << dynsym_builder_.section_.sh_size;
- LOG(INFO) << "dynstr off=" << dynsym_builder_.strtab_.section_.sh_offset
- << " dynstr size=" << dynsym_builder_.strtab_.section_.sh_size;
- LOG(INFO) << "hash off=" << hash_builder_.section_.sh_offset
- << " hash size=" << hash_builder_.section_.sh_size;
- LOG(INFO) << "rodata off=" << rodata_builder_.section_.sh_offset
- << " rodata size=" << rodata_builder_.section_.sh_size;
- LOG(INFO) << "text off=" << text_builder_.section_.sh_offset
- << " text size=" << text_builder_.section_.sh_size;
- LOG(INFO) << "dynamic off=" << dynamic_builder_.section_.sh_offset
- << " dynamic size=" << dynamic_builder_.section_.sh_size;
- if (IncludingDebugSymbols()) {
+ if (debug_logging_) {
LOG(INFO) << "symtab off=" << symtab_builder_.section_.sh_offset
<< " symtab size=" << symtab_builder_.section_.sh_size;
LOG(INFO) << "strtab off=" << symtab_builder_.strtab_.section_.sh_offset
<< " strtab size=" << symtab_builder_.strtab_.section_.sh_size;
}
}
+
// Get the layout of the extra sections. (This will deal with the debug
// sections if they are there)
for (auto it = other_builders_.begin(); it != other_builders_.end(); ++it) {
@@ -403,10 +427,11 @@
<< " " << it->name_ << " size=" << it->section_.sh_size;
}
}
+
// Get the layout of the shstrtab section
shstrtab_builder_.section_.sh_offset = NextOffset(shstrtab_builder_.section_, prev);
shstrtab_builder_.section_.sh_addr = 0;
- shstrtab_builder_.section_.sh_size = shstrtab.size();
+ shstrtab_builder_.section_.sh_size = shstrtab_.size();
shstrtab_builder_.section_.sh_link = shstrtab_builder_.GetLink();
if (debug_logging_) {
LOG(INFO) << "shstrtab off=" << shstrtab_builder_.section_.sh_offset
@@ -430,58 +455,58 @@
// Setup the dynamic section.
// This will add the 2 values we cannot know until now time, namely the size
// and the soname_offset.
- std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr.size(),
- dynstr_soname_offset);
+ std::vector<Elf32_Dyn> dynamic = dynamic_builder_.GetDynamics(dynstr_.size(),
+ dynstr_soname_offset_);
CHECK_EQ(dynamic.size() * sizeof(Elf32_Dyn), dynamic_builder_.section_.sh_size);
// Finish setup of the program headers now that we know the layout of the
// whole file.
Elf32_Word load_r_size = rodata_builder_.section_.sh_offset + rodata_builder_.section_.sh_size;
- program_headers[PH_LOAD_R__].p_filesz = load_r_size;
- program_headers[PH_LOAD_R__].p_memsz = load_r_size;
- program_headers[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign;
+ program_headers_[PH_LOAD_R__].p_filesz = load_r_size;
+ program_headers_[PH_LOAD_R__].p_memsz = load_r_size;
+ program_headers_[PH_LOAD_R__].p_align = rodata_builder_.section_.sh_addralign;
Elf32_Word load_rx_size = text_builder_.section_.sh_size;
- program_headers[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset;
- program_headers[PH_LOAD_R_X].p_filesz = load_rx_size;
- program_headers[PH_LOAD_R_X].p_memsz = load_rx_size;
- program_headers[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign;
+ program_headers_[PH_LOAD_R_X].p_offset = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_vaddr = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_paddr = text_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_R_X].p_filesz = load_rx_size;
+ program_headers_[PH_LOAD_R_X].p_memsz = load_rx_size;
+ program_headers_[PH_LOAD_R_X].p_align = text_builder_.section_.sh_addralign;
- program_headers[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
- program_headers[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size;
- program_headers[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign;
+ program_headers_[PH_LOAD_RW_].p_offset = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_vaddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_paddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_LOAD_RW_].p_filesz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_LOAD_RW_].p_memsz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_LOAD_RW_].p_align = dynamic_builder_.section_.sh_addralign;
- program_headers[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset;
- program_headers[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
- program_headers[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size;
- program_headers[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign;
+ program_headers_[PH_DYNAMIC].p_offset = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_vaddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_paddr = dynamic_builder_.section_.sh_offset;
+ program_headers_[PH_DYNAMIC].p_filesz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_DYNAMIC].p_memsz = dynamic_builder_.section_.sh_size;
+ program_headers_[PH_DYNAMIC].p_align = dynamic_builder_.section_.sh_addralign;
// Finish setup of the Ehdr values.
- elf_header_.e_phoff = phdr_offset;
+ elf_header_.e_phoff = PHDR_OFFSET;
elf_header_.e_shoff = sections_offset;
elf_header_.e_phnum = PH_NUM;
- elf_header_.e_shnum = section_ptrs.size();
+ elf_header_.e_shnum = section_ptrs_.size();
elf_header_.e_shstrndx = shstrtab_builder_.section_index_;
// Add the rest of the pieces to the list.
pieces.push_back(ElfFilePiece("Elf Header", 0, &elf_header_, sizeof(elf_header_)));
- pieces.push_back(ElfFilePiece("Program headers", phdr_offset,
- &program_headers, sizeof(program_headers)));
+ pieces.push_back(ElfFilePiece("Program headers", PHDR_OFFSET,
+ &program_headers_, sizeof(program_headers_)));
pieces.push_back(ElfFilePiece(".dynamic", dynamic_builder_.section_.sh_offset,
dynamic.data(), dynamic_builder_.section_.sh_size));
pieces.push_back(ElfFilePiece(".dynsym", dynsym_builder_.section_.sh_offset,
dynsym.data(), dynsym.size() * sizeof(Elf32_Sym)));
pieces.push_back(ElfFilePiece(".dynstr", dynsym_builder_.strtab_.section_.sh_offset,
- dynstr.c_str(), dynstr.size()));
+ dynstr_.c_str(), dynstr_.size()));
pieces.push_back(ElfFilePiece(".hash", hash_builder_.section_.sh_offset,
- hash.data(), hash.size() * sizeof(Elf32_Word)));
+ hash_.data(), hash_.size() * sizeof(Elf32_Word)));
pieces.push_back(ElfFilePiece(".rodata", rodata_builder_.section_.sh_offset,
nullptr, rodata_builder_.section_.sh_size));
pieces.push_back(ElfFilePiece(".text", text_builder_.section_.sh_offset,
@@ -493,13 +518,13 @@
strtab.c_str(), strtab.size()));
}
pieces.push_back(ElfFilePiece(".shstrtab", shstrtab_builder_.section_.sh_offset,
- &shstrtab[0], shstrtab.size()));
- for (uint32_t i = 0; i < section_ptrs.size(); ++i) {
+ &shstrtab_[0], shstrtab_.size()));
+ for (uint32_t i = 0; i < section_ptrs_.size(); ++i) {
// Just add all the sections in induvidually since they are all over the
// place on the heap/stack.
Elf32_Word cur_off = sections_offset + i * sizeof(Elf32_Shdr);
pieces.push_back(ElfFilePiece("section table piece", cur_off,
- section_ptrs[i], sizeof(Elf32_Shdr)));
+ section_ptrs_[i], sizeof(Elf32_Shdr)));
}
if (!WriteOutFile(pieces)) {
@@ -664,7 +689,7 @@
// Lets say the state is something like this.
// +--------+ +--------+ +-----------+
// | symtab | | bucket | | chain |
- // | nullptr | | 1 | | STN_UNDEF |
+ // | null | | 1 | | STN_UNDEF |
// | <sym1> | | 4 | | 2 |
// | <sym2> | | | | 5 |
// | <sym3> | | | | STN_UNDEF |
@@ -836,13 +861,24 @@
}
std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
- std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+ std::vector<uint8_t>* cfi_info = new std::vector<uint8_t>;
// Length (will be filled in later in this routine).
- PushWord(cfi_info, 0);
+ if (is_x86_64) {
+ PushWord(cfi_info, 0xffffffff); // Indicates 64bit
+ PushWord(cfi_info, 0);
+ PushWord(cfi_info, 0);
+ } else {
+ PushWord(cfi_info, 0);
+ }
// CIE id: always 0.
- PushWord(cfi_info, 0);
+ if (is_x86_64) {
+ PushWord(cfi_info, 0);
+ PushWord(cfi_info, 0);
+ } else {
+ PushWord(cfi_info, 0);
+ }
// Version: always 1.
cfi_info->push_back(0x01);
@@ -874,8 +910,14 @@
// Augmentation length: 1.
cfi_info->push_back(1);
- // Augmentation data: 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
- cfi_info->push_back(0x03);
+ // Augmentation data.
+ if (is_x86_64) {
+ // 0x04 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata8).
+ cfi_info->push_back(0x04);
+ } else {
+ // 0x03 ((DW_EH_PE_absptr << 4) | DW_EH_PE_udata4).
+ cfi_info->push_back(0x03);
+ }
// Initial instructions.
if (is_x86_64) {
@@ -905,11 +947,13 @@
}
// Set the length of the CIE inside the generated bytes.
- uint32_t length = cfi_info->size() - 4;
- (*cfi_info)[0] = length;
- (*cfi_info)[1] = length >> 8;
- (*cfi_info)[2] = length >> 16;
- (*cfi_info)[3] = length >> 24;
+ if (is_x86_64) {
+ uint32_t length = cfi_info->size() - 12;
+ UpdateWord(cfi_info, 4, length);
+ } else {
+ uint32_t length = cfi_info->size() - 4;
+ UpdateWord(cfi_info, 0, length);
+ }
return cfi_info;
}
@@ -940,8 +984,12 @@
compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols(),
debug);
+ if (!builder.Init()) {
+ return false;
+ }
+
if (compiler_driver_->GetCompilerOptions().GetIncludeDebugSymbols()) {
- WriteDebugSymbols(builder, oat_writer);
+ WriteDebugSymbols(&builder, oat_writer);
}
if (compiler_driver_->GetCompilerOptions().GetIncludePatchInformation()) {
@@ -954,15 +1002,17 @@
return builder.Write();
}
-void ElfWriterQuick::WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer) {
+void ElfWriterQuick::WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer) {
std::unique_ptr<std::vector<uint8_t>> cfi_info(
ConstructCIEFrame(compiler_driver_->GetInstructionSet()));
+ Elf32_Addr text_section_address = builder->text_builder_.section_.sh_addr;
+
// Iterate over the compiled methods.
const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
- ElfSymtabBuilder* symtab = &builder.symtab_builder_;
+ ElfSymtabBuilder* symtab = &builder->symtab_builder_;
for (auto it = method_info.begin(); it != method_info.end(); ++it) {
- symtab->AddSymbol(it->method_name_, &builder.text_builder_, it->low_pc_, true,
+ symtab->AddSymbol(it->method_name_, &builder->text_builder_, it->low_pc_, true,
it->high_pc_ - it->low_pc_, STB_GLOBAL, STT_FUNC);
// Include CFI for compiled method, if possible.
@@ -976,96 +1026,314 @@
int cur_offset = cfi_info->size();
cfi_info->insert(cfi_info->end(), fde->begin(), fde->end());
- // Set the 'CIE_pointer' field to cur_offset+4.
- uint32_t CIE_pointer = cur_offset + 4;
- uint32_t offset_to_update = cur_offset + sizeof(uint32_t);
- (*cfi_info)[offset_to_update+0] = CIE_pointer;
- (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
- (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
- (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+ bool is_64bit = *(reinterpret_cast<const uint32_t*>(fde->data())) == 0xffffffff;
- // Set the 'initial_location' field to address the start of the method.
- offset_to_update = cur_offset + 2*sizeof(uint32_t);
- const uint32_t quick_code_start = it->low_pc_;
- (*cfi_info)[offset_to_update+0] = quick_code_start;
- (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
- (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
- (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ // Set the 'CIE_pointer' field.
+ uint64_t CIE_pointer = cur_offset + (is_64bit ? 12 : 4);
+ uint64_t offset_to_update = CIE_pointer;
+ if (is_64bit) {
+ (*cfi_info)[offset_to_update+0] = CIE_pointer;
+ (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+ (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+ (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+ (*cfi_info)[offset_to_update+4] = CIE_pointer >> 32;
+ (*cfi_info)[offset_to_update+5] = CIE_pointer >> 40;
+ (*cfi_info)[offset_to_update+6] = CIE_pointer >> 48;
+ (*cfi_info)[offset_to_update+7] = CIE_pointer >> 56;
+ } else {
+ (*cfi_info)[offset_to_update+0] = CIE_pointer;
+ (*cfi_info)[offset_to_update+1] = CIE_pointer >> 8;
+ (*cfi_info)[offset_to_update+2] = CIE_pointer >> 16;
+ (*cfi_info)[offset_to_update+3] = CIE_pointer >> 24;
+ }
+
+ // Set the 'initial_location' field.
+ offset_to_update += is_64bit ? 8 : 4;
+ if (is_64bit) {
+ const uint64_t quick_code_start = it->low_pc_ + text_section_address;
+ (*cfi_info)[offset_to_update+0] = quick_code_start;
+ (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+ (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+ (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ (*cfi_info)[offset_to_update+4] = quick_code_start >> 32;
+ (*cfi_info)[offset_to_update+5] = quick_code_start >> 40;
+ (*cfi_info)[offset_to_update+6] = quick_code_start >> 48;
+ (*cfi_info)[offset_to_update+7] = quick_code_start >> 56;
+ } else {
+ const uint32_t quick_code_start = it->low_pc_ + text_section_address;
+ (*cfi_info)[offset_to_update+0] = quick_code_start;
+ (*cfi_info)[offset_to_update+1] = quick_code_start >> 8;
+ (*cfi_info)[offset_to_update+2] = quick_code_start >> 16;
+ (*cfi_info)[offset_to_update+3] = quick_code_start >> 24;
+ }
}
}
}
- if (cfi_info.get() != nullptr) {
- // Now lay down the Elf sections.
- ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
- ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
- eh_frame.SetBuffer(std::move(*cfi_info.get()));
+ bool hasCFI = (cfi_info.get() != nullptr);
+ bool hasLineInfo = false;
+ for (auto& dbg_info : oat_writer->GetCFIMethodInfo()) {
+ if (dbg_info.dbgstream_ != nullptr &&
+ !dbg_info.compiled_method_->GetSrcMappingTable().empty()) {
+ hasLineInfo = true;
+ break;
+ }
+ }
- FillInCFIInformation(oat_writer, debug_info.GetBuffer(), debug_abbrev.GetBuffer(),
- debug_str.GetBuffer());
- builder.RegisterRawSection(debug_info);
- builder.RegisterRawSection(debug_abbrev);
- builder.RegisterRawSection(eh_frame);
- builder.RegisterRawSection(debug_str);
+ if (hasLineInfo || hasCFI) {
+ ElfRawSectionBuilder debug_info(".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ ElfRawSectionBuilder debug_abbrev(".debug_abbrev", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ ElfRawSectionBuilder debug_str(".debug_str", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+ ElfRawSectionBuilder debug_line(".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0);
+
+ FillInCFIInformation(oat_writer, debug_info.GetBuffer(),
+ debug_abbrev.GetBuffer(), debug_str.GetBuffer(),
+ hasLineInfo ? debug_line.GetBuffer() : nullptr,
+ text_section_address);
+
+ builder->RegisterRawSection(debug_info);
+ builder->RegisterRawSection(debug_abbrev);
+
+ if (hasCFI) {
+ ElfRawSectionBuilder eh_frame(".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0);
+ eh_frame.SetBuffer(std::move(*cfi_info.get()));
+ builder->RegisterRawSection(eh_frame);
+ }
+
+ if (hasLineInfo) {
+ builder->RegisterRawSection(debug_line);
+ }
+
+ builder->RegisterRawSection(debug_str);
+ }
+}
+
+class LineTableGenerator FINAL : public Leb128Encoder {
+ public:
+ LineTableGenerator(int line_base, int line_range, int opcode_base,
+ std::vector<uint8_t>* data, uintptr_t current_address,
+ size_t current_line)
+ : Leb128Encoder(data), line_base_(line_base), line_range_(line_range),
+ opcode_base_(opcode_base), current_address_(current_address),
+ current_line_(current_line) {}
+
+ void PutDelta(unsigned delta_addr, int delta_line) {
+ current_line_ += delta_line;
+ current_address_ += delta_addr;
+
+ if (delta_line >= line_base_ && delta_line < line_base_ + line_range_) {
+ unsigned special_opcode = (delta_line - line_base_) +
+ (line_range_ * delta_addr) + opcode_base_;
+ if (special_opcode <= 255) {
+ PushByte(data_, special_opcode);
+ return;
+ }
+ }
+
+ // generate standart opcode for address advance
+ if (delta_addr != 0) {
+ PushByte(data_, DW_LNS_advance_pc);
+ PushBackUnsigned(delta_addr);
+ }
+
+ // generate standart opcode for line delta
+ if (delta_line != 0) {
+ PushByte(data_, DW_LNS_advance_line);
+ PushBackSigned(delta_line);
+ }
+
+ // generate standart opcode for new LTN entry
+ PushByte(data_, DW_LNS_copy);
+ }
+
+ void SetAddr(uintptr_t addr) {
+ if (current_address_ == addr) {
+ return;
+ }
+
+ current_address_ = addr;
+
+ PushByte(data_, 0); // extended opcode:
+ PushByte(data_, 1 + 4); // length: opcode_size + address_size
+ PushByte(data_, DW_LNE_set_address);
+ PushWord(data_, addr);
+ }
+
+ void SetLine(unsigned line) {
+ int delta_line = line - current_line_;
+ if (delta_line) {
+ current_line_ = line;
+ PushByte(data_, DW_LNS_advance_line);
+ PushBackSigned(delta_line);
+ }
+ }
+
+ void SetFile(unsigned file_index) {
+ PushByte(data_, DW_LNS_set_file);
+ PushBackUnsigned(file_index);
+ }
+
+ void EndSequence() {
+ // End of Line Table Program
+ // 0(=ext), 1(len), DW_LNE_end_sequence
+ PushByte(data_, 0);
+ PushByte(data_, 1);
+ PushByte(data_, DW_LNE_end_sequence);
+ }
+
+ private:
+ const int line_base_;
+ const int line_range_;
+ const int opcode_base_;
+ uintptr_t current_address_;
+ size_t current_line_;
+
+ DISALLOW_COPY_AND_ASSIGN(LineTableGenerator);
+};
+
+// TODO: rewriting it using DexFile::DecodeDebugInfo needs unneeded stuff.
+static void GetLineInfoForJava(const uint8_t* dbgstream, const SrcMap& pc2dex,
+ SrcMap* result, uint32_t start_pc = 0) {
+ if (dbgstream == nullptr) {
+ return;
+ }
+
+ int adjopcode;
+ uint32_t dex_offset = 0;
+ uint32_t java_line = DecodeUnsignedLeb128(&dbgstream);
+
+ // skip parameters
+ for (uint32_t param_count = DecodeUnsignedLeb128(&dbgstream); param_count != 0; --param_count) {
+ DecodeUnsignedLeb128(&dbgstream);
+ }
+
+ for (bool is_end = false; is_end == false; ) {
+ uint8_t opcode = *dbgstream;
+ dbgstream++;
+ switch (opcode) {
+ case DexFile::DBG_END_SEQUENCE:
+ is_end = true;
+ break;
+
+ case DexFile::DBG_ADVANCE_PC:
+ dex_offset += DecodeUnsignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_ADVANCE_LINE:
+ java_line += DecodeSignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_START_LOCAL:
+ case DexFile::DBG_START_LOCAL_EXTENDED:
+ DecodeUnsignedLeb128(&dbgstream);
+ DecodeUnsignedLeb128(&dbgstream);
+ DecodeUnsignedLeb128(&dbgstream);
+
+ if (opcode == DexFile::DBG_START_LOCAL_EXTENDED) {
+ DecodeUnsignedLeb128(&dbgstream);
+ }
+ break;
+
+ case DexFile::DBG_END_LOCAL:
+ case DexFile::DBG_RESTART_LOCAL:
+ DecodeUnsignedLeb128(&dbgstream);
+ break;
+
+ case DexFile::DBG_SET_PROLOGUE_END:
+ case DexFile::DBG_SET_EPILOGUE_BEGIN:
+ case DexFile::DBG_SET_FILE:
+ break;
+
+ default:
+ adjopcode = opcode - DexFile::DBG_FIRST_SPECIAL;
+ dex_offset += adjopcode / DexFile::DBG_LINE_RANGE;
+ java_line += DexFile::DBG_LINE_BASE + (adjopcode % DexFile::DBG_LINE_RANGE);
+
+ for (SrcMap::const_iterator found = pc2dex.FindByTo(dex_offset);
+ found != pc2dex.end() && found->to_ == static_cast<int32_t>(dex_offset);
+ found++) {
+ result->push_back({found->from_ + start_pc, static_cast<int32_t>(java_line)});
+ }
+ break;
+ }
}
}
void ElfWriterQuick::FillInCFIInformation(OatWriter* oat_writer,
std::vector<uint8_t>* dbg_info,
std::vector<uint8_t>* dbg_abbrev,
- std::vector<uint8_t>* dbg_str) {
+ std::vector<uint8_t>* dbg_str,
+ std::vector<uint8_t>* dbg_line,
+ uint32_t text_section_offset) {
+ const std::vector<OatWriter::DebugInfo>& method_info = oat_writer->GetCFIMethodInfo();
+
+ uint32_t producer_str_offset = PushStr(dbg_str, "Android dex2oat");
+
// Create the debug_abbrev section with boilerplate information.
// We only care about low_pc and high_pc right now for the compilation
// unit and methods.
// Tag 1: Compilation unit: DW_TAG_compile_unit.
- dbg_abbrev->push_back(1);
- dbg_abbrev->push_back(DW_TAG_compile_unit);
+ PushByte(dbg_abbrev, 1);
+ PushByte(dbg_abbrev, DW_TAG_compile_unit);
// There are children (the methods).
- dbg_abbrev->push_back(DW_CHILDREN_yes);
+ PushByte(dbg_abbrev, DW_CHILDREN_yes);
+
+ // DW_AT_producer DW_FORM_data1.
+ // REVIEW: we can get rid of dbg_str section if
+ // DW_FORM_string (immediate string) was used everywhere instead of
+ // DW_FORM_strp (ref to string from .debug_str section).
+ // DW_FORM_strp makes sense only if we reuse the strings.
+ PushByte(dbg_abbrev, DW_AT_producer);
+ PushByte(dbg_abbrev, DW_FORM_strp);
// DW_LANG_Java DW_FORM_data1.
- dbg_abbrev->push_back(DW_AT_language);
- dbg_abbrev->push_back(DW_FORM_data1);
+ PushByte(dbg_abbrev, DW_AT_language);
+ PushByte(dbg_abbrev, DW_FORM_data1);
// DW_AT_low_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_low_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_low_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// DW_AT_high_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_high_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_high_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
+
+ if (dbg_line != nullptr) {
+ // DW_AT_stmt_list DW_FORM_sec_offset.
+ PushByte(dbg_abbrev, DW_AT_stmt_list);
+ PushByte(dbg_abbrev, DW_FORM_sec_offset);
+ }
// End of DW_TAG_compile_unit.
PushHalf(dbg_abbrev, 0);
// Tag 2: Compilation unit: DW_TAG_subprogram.
- dbg_abbrev->push_back(2);
- dbg_abbrev->push_back(DW_TAG_subprogram);
+ PushByte(dbg_abbrev, 2);
+ PushByte(dbg_abbrev, DW_TAG_subprogram);
// There are no children.
- dbg_abbrev->push_back(DW_CHILDREN_no);
+ PushByte(dbg_abbrev, DW_CHILDREN_no);
// Name of the method.
- dbg_abbrev->push_back(DW_AT_name);
- dbg_abbrev->push_back(DW_FORM_strp);
+ PushByte(dbg_abbrev, DW_AT_name);
+ PushByte(dbg_abbrev, DW_FORM_strp);
// DW_AT_low_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_low_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_low_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// DW_AT_high_pc DW_FORM_addr.
- dbg_abbrev->push_back(DW_AT_high_pc);
- dbg_abbrev->push_back(DW_FORM_addr);
+ PushByte(dbg_abbrev, DW_AT_high_pc);
+ PushByte(dbg_abbrev, DW_FORM_addr);
// End of DW_TAG_subprogram.
PushHalf(dbg_abbrev, 0);
// Start the debug_info section with the header information
// 'unit_length' will be filled in later.
+ int cunit_length = dbg_info->size();
PushWord(dbg_info, 0);
// 'version' - 3.
@@ -1075,55 +1343,153 @@
PushWord(dbg_info, 0);
// Address size: 4.
- dbg_info->push_back(4);
+ PushByte(dbg_info, 4);
// Start the description for the compilation unit.
// This uses tag 1.
- dbg_info->push_back(1);
+ PushByte(dbg_info, 1);
+
+ // The producer is Android dex2oat.
+ PushWord(dbg_info, producer_str_offset);
// The language is Java.
- dbg_info->push_back(DW_LANG_Java);
+ PushByte(dbg_info, DW_LANG_Java);
- // Leave space for low_pc and high_pc.
- int low_pc_offset = dbg_info->size();
+ // low_pc and high_pc.
+ uint32_t cunit_low_pc = 0 - 1;
+ uint32_t cunit_high_pc = 0;
+ int cunit_low_pc_pos = dbg_info->size();
PushWord(dbg_info, 0);
PushWord(dbg_info, 0);
- // Walk through the information in the method table, and enter into dbg_info.
- const std::vector<OatWriter::DebugInfo>& dbg = oat_writer->GetCFIMethodInfo();
- uint32_t low_pc = 0xFFFFFFFFU;
- uint32_t high_pc = 0;
+ if (dbg_line == nullptr) {
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
- for (uint32_t i = 0; i < dbg.size(); i++) {
- const OatWriter::DebugInfo& info = dbg[i];
- if (info.low_pc_ < low_pc) {
- low_pc = info.low_pc_;
+ cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_);
+ cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_);
+
+ // Start a new TAG: subroutine (2).
+ PushByte(dbg_info, 2);
+
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+ PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+ PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
}
- if (info.high_pc_ > high_pc) {
- high_pc = info.high_pc_;
+ } else {
+ // TODO: in gdb info functions <regexp> - reports Java functions, but
+ // source file is <unknown> because .debug_line is formed as one
+ // compilation unit. To fix this it is possible to generate
+ // a separate compilation unit for every distinct Java source.
+ // Each of the these compilation units can have several non-adjacent
+ // method ranges.
+
+ // Line number table offset
+ PushWord(dbg_info, dbg_line->size());
+
+ size_t lnt_length = dbg_line->size();
+ PushWord(dbg_line, 0);
+
+ PushHalf(dbg_line, 4); // LNT Version DWARF v4 => 4
+
+ size_t lnt_hdr_length = dbg_line->size();
+ PushWord(dbg_line, 0); // TODO: 64-bit uses 8-byte here
+
+ PushByte(dbg_line, 1); // minimum_instruction_length (ubyte)
+ PushByte(dbg_line, 1); // maximum_operations_per_instruction (ubyte) = always 1
+ PushByte(dbg_line, 1); // default_is_stmt (ubyte)
+
+ const int8_t LINE_BASE = -5;
+ PushByte(dbg_line, LINE_BASE); // line_base (sbyte)
+
+ const uint8_t LINE_RANGE = 14;
+ PushByte(dbg_line, LINE_RANGE); // line_range (ubyte)
+
+ const uint8_t OPCODE_BASE = 13;
+ PushByte(dbg_line, OPCODE_BASE); // opcode_base (ubyte)
+
+ // Standard_opcode_lengths (array of ubyte).
+ PushByte(dbg_line, 0); PushByte(dbg_line, 1); PushByte(dbg_line, 1);
+ PushByte(dbg_line, 1); PushByte(dbg_line, 1); PushByte(dbg_line, 0);
+ PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1);
+ PushByte(dbg_line, 0); PushByte(dbg_line, 0); PushByte(dbg_line, 1);
+
+ PushByte(dbg_line, 0); // include_directories (sequence of path names) = EMPTY
+
+ // File_names (sequence of file entries).
+ std::unordered_map<const char*, size_t> files;
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
+ // TODO: add package directory to the file name
+ const char* file_name = dbg.src_file_name_ == nullptr ? "null" : dbg.src_file_name_;
+ auto found = files.find(file_name);
+ if (found == files.end()) {
+ size_t file_index = 1 + files.size();
+ files[file_name] = file_index;
+ PushStr(dbg_line, file_name);
+ PushByte(dbg_line, 0); // include directory index = LEB128(0) - no directory
+ PushByte(dbg_line, 0); // modification time = LEB128(0) - NA
+ PushByte(dbg_line, 0); // file length = LEB128(0) - NA
+ }
+ }
+ PushByte(dbg_line, 0); // End of file_names.
+
+ // Set lnt header length.
+ UpdateWord(dbg_line, lnt_hdr_length, dbg_line->size() - lnt_hdr_length - 4);
+
+ // Generate Line Number Program code, one long program for all methods.
+ LineTableGenerator line_table_generator(LINE_BASE, LINE_RANGE, OPCODE_BASE,
+ dbg_line, 0, 1);
+
+ SrcMap pc2java_map;
+ for (size_t i = 0; i < method_info.size(); ++i) {
+ const OatWriter::DebugInfo &dbg = method_info[i];
+ const char* file_name = (dbg.src_file_name_ == nullptr) ? "null" : dbg.src_file_name_;
+ size_t file_index = files[file_name];
+ DCHECK_NE(file_index, 0U) << file_name;
+
+ cunit_low_pc = std::min(cunit_low_pc, dbg.low_pc_);
+ cunit_high_pc = std::max(cunit_high_pc, dbg.high_pc_);
+
+ // Start a new TAG: subroutine (2).
+ PushByte(dbg_info, 2);
+
+ // Enter name, low_pc, high_pc.
+ PushWord(dbg_info, PushStr(dbg_str, dbg.method_name_));
+ PushWord(dbg_info, dbg.low_pc_ + text_section_offset);
+ PushWord(dbg_info, dbg.high_pc_ + text_section_offset);
+
+ pc2java_map.clear();
+ GetLineInfoForJava(dbg.dbgstream_, dbg.compiled_method_->GetSrcMappingTable(),
+ &pc2java_map, dbg.low_pc_);
+ pc2java_map.DeltaFormat({dbg.low_pc_, 1}, dbg.high_pc_);
+
+ line_table_generator.SetFile(file_index);
+ line_table_generator.SetAddr(dbg.low_pc_ + text_section_offset);
+ line_table_generator.SetLine(1);
+ for (auto& src_map_elem : pc2java_map) {
+ line_table_generator.PutDelta(src_map_elem.from_, src_map_elem.to_);
+ }
}
- // Start a new TAG: subroutine (2).
- dbg_info->push_back(2);
+ // End Sequence should have the highest address set.
+ line_table_generator.SetAddr(cunit_high_pc + text_section_offset);
+ line_table_generator.EndSequence();
- // Enter the name into the string table (and NUL terminate).
- uint32_t str_offset = dbg_str->size();
- dbg_str->insert(dbg_str->end(), info.method_name_.begin(), info.method_name_.end());
- dbg_str->push_back('\0');
-
- // Enter name, low_pc, high_pc.
- PushWord(dbg_info, str_offset);
- PushWord(dbg_info, info.low_pc_);
- PushWord(dbg_info, info.high_pc_);
+ // set lnt length
+ UpdateWord(dbg_line, lnt_length, dbg_line->size() - lnt_length - 4);
}
// One byte terminator
- dbg_info->push_back(0);
+ PushByte(dbg_info, 0);
- // We have now walked all the methods. Fill in lengths and low/high PCs.
- UpdateWord(dbg_info, 0, dbg_info->size() - 4);
- UpdateWord(dbg_info, low_pc_offset, low_pc);
- UpdateWord(dbg_info, low_pc_offset + 4, high_pc);
+ // Fill in cunit's low_pc and high_pc.
+ UpdateWord(dbg_info, cunit_low_pc_pos, cunit_low_pc + text_section_offset);
+ UpdateWord(dbg_info, cunit_low_pc_pos + 4, cunit_high_pc + text_section_offset);
+
+ // We have now walked all the methods. Fill in lengths.
+ UpdateWord(dbg_info, cunit_length, dbg_info->size() - cunit_length - 4);
}
} // namespace art
diff --git a/compiler/elf_writer_quick.h b/compiler/elf_writer_quick.h
index 8cfe550..c7ef872 100644
--- a/compiler/elf_writer_quick.h
+++ b/compiler/elf_writer_quick.h
@@ -48,7 +48,7 @@
~ElfWriterQuick() {}
class ElfBuilder;
- void WriteDebugSymbols(ElfBuilder& builder, OatWriter* oat_writer);
+ void WriteDebugSymbols(ElfBuilder* builder, OatWriter* oat_writer);
void ReservePatchSpace(std::vector<uint8_t>* buffer, bool debug);
class ElfSectionBuilder {
@@ -237,6 +237,7 @@
}
~ElfBuilder() {}
+ bool Init();
bool Write();
// Adds the given raw section to the builder. This will copy it. The caller
@@ -253,8 +254,29 @@
bool fatal_error_ = false;
+ // What phdr is.
+ static const uint32_t PHDR_OFFSET = sizeof(Elf32_Ehdr);
+ enum : uint8_t {
+ PH_PHDR = 0,
+ PH_LOAD_R__ = 1,
+ PH_LOAD_R_X = 2,
+ PH_LOAD_RW_ = 3,
+ PH_DYNAMIC = 4,
+ PH_NUM = 5,
+ };
+ static const uint32_t PHDR_SIZE = sizeof(Elf32_Phdr) * PH_NUM;
+ Elf32_Phdr program_headers_[PH_NUM];
+
Elf32_Ehdr elf_header_;
+ Elf32_Shdr null_hdr_;
+ std::string shstrtab_;
+ uint32_t section_index_;
+ std::string dynstr_;
+ uint32_t dynstr_soname_offset_;
+ std::vector<Elf32_Shdr*> section_ptrs_;
+ std::vector<Elf32_Word> hash_;
+
public:
ElfOatSectionBuilder text_builder_;
ElfOatSectionBuilder rodata_builder_;
@@ -316,7 +338,8 @@
* @param dbg_str Debug strings.
*/
void FillInCFIInformation(OatWriter* oat_writer, std::vector<uint8_t>* dbg_info,
- std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str);
+ std::vector<uint8_t>* dbg_abbrev, std::vector<uint8_t>* dbg_str,
+ std::vector<uint8_t>* dbg_line, uint32_t text_section_offset);
DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
};
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 1ba5d32..0fb1575 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -411,10 +411,12 @@
const uint32_t quick_code_start = quick_code_offset -
writer_->oat_header_->GetExecutableOffset();
+ const DexFile::CodeItem *code_item = it.GetMethodCodeItem();
writer_->method_info_.push_back(DebugInfo(name,
- quick_code_start,
- quick_code_start + code_size,
- compiled_method));
+ dex_file_->GetSourceFile(dex_file_->GetClassDef(class_def_index_)),
+ quick_code_start, quick_code_start + code_size,
+ code_item == nullptr ? nullptr : dex_file_->GetDebugInfoStream(code_item),
+ compiled_method));
}
}
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index ef5fd6b..11f8bff 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -98,14 +98,18 @@
~OatWriter();
struct DebugInfo {
- DebugInfo(const std::string& method_name, uint32_t low_pc, uint32_t high_pc,
+ DebugInfo(const std::string& method_name, const char* src_file_name,
+ uint32_t low_pc, uint32_t high_pc, const uint8_t* dbgstream,
CompiledMethod* compiled_method)
- : method_name_(method_name), low_pc_(low_pc), high_pc_(high_pc),
+ : method_name_(method_name), src_file_name_(src_file_name),
+ low_pc_(low_pc), high_pc_(high_pc), dbgstream_(dbgstream),
compiled_method_(compiled_method) {
}
std::string method_name_; // Note: this name is a pretty-printed name.
+ const char* src_file_name_;
uint32_t low_pc_;
uint32_t high_pc_;
+ const uint8_t* dbgstream_;
CompiledMethod* compiled_method_;
};
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index bd8c27e..7269fff 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -19,6 +19,7 @@
#include "code_generator_arm.h"
#include "code_generator_x86.h"
#include "code_generator_x86_64.h"
+#include "compiled_method.h"
#include "dex/verified_method.h"
#include "driver/dex_compilation_unit.h"
#include "gc_map_builder.h"
@@ -297,7 +298,7 @@
}
}
-void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data) const {
+void CodeGenerator::BuildMappingTable(std::vector<uint8_t>* data, SrcMap* src_map) const {
uint32_t pc2dex_data_size = 0u;
uint32_t pc2dex_entries = pc_infos_.Size();
uint32_t pc2dex_offset = 0u;
@@ -305,6 +306,10 @@
uint32_t dex2pc_data_size = 0u;
uint32_t dex2pc_entries = 0u;
+ if (src_map != nullptr) {
+ src_map->reserve(pc2dex_entries);
+ }
+
// We currently only have pc2dex entries.
for (size_t i = 0; i < pc2dex_entries; i++) {
struct PcInfo pc_info = pc_infos_.Get(i);
@@ -312,6 +317,9 @@
pc2dex_data_size += SignedLeb128Size(pc_info.dex_pc - pc2dex_dalvik_offset);
pc2dex_offset = pc_info.native_pc;
pc2dex_dalvik_offset = pc_info.dex_pc;
+ if (src_map != nullptr) {
+ src_map->push_back(SrcMapElem({pc2dex_offset, pc2dex_dalvik_offset}));
+ }
}
uint32_t total_entries = pc2dex_entries + dex2pc_entries;
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index b31c3a3..24e0277 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -32,6 +32,7 @@
class CodeGenerator;
class DexCompilationUnit;
+class SrcMap;
class CodeAllocator {
public:
@@ -126,7 +127,7 @@
void GenerateSlowPaths();
- void BuildMappingTable(std::vector<uint8_t>* vector) const;
+ void BuildMappingTable(std::vector<uint8_t>* vector, SrcMap* src_map) const;
void BuildVMapTable(std::vector<uint8_t>* vector) const;
void BuildNativeGCMap(
std::vector<uint8_t>* vector, const DexCompilationUnit& dex_compilation_unit) const;
@@ -142,6 +143,7 @@
protected:
CodeGenerator(HGraph* graph, size_t number_of_registers)
: frame_size_(kUninitializedFrameSize),
+ core_spill_mask_(-1),
graph_(graph),
block_labels_(graph->GetArena(), 0),
pc_infos_(graph->GetArena(), 32),
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8a5077b..fce6ab0 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -161,7 +161,10 @@
}
std::vector<uint8_t> mapping_table;
- codegen->BuildMappingTable(&mapping_table);
+ SrcMap src_mapping_table;
+ codegen->BuildMappingTable(&mapping_table,
+ GetCompilerDriver()->GetCompilerOptions().GetIncludeDebugSymbols() ?
+ &src_mapping_table : nullptr);
std::vector<uint8_t> vmap_table;
codegen->BuildVMapTable(&vmap_table);
std::vector<uint8_t> gc_map;
@@ -173,6 +176,7 @@
codegen->GetFrameSize(),
codegen->GetCoreSpillMask(),
0, /* FPR spill mask, unused */
+ &src_mapping_table,
mapping_table,
vmap_table,
gc_map,
diff --git a/compiler/utils/dwarf_cfi.cc b/compiler/utils/dwarf_cfi.cc
index b3d1a47..83e5f5a 100644
--- a/compiler/utils/dwarf_cfi.cc
+++ b/compiler/utils/dwarf_cfi.cc
@@ -65,44 +65,86 @@
buf->push_back(0x0b);
}
-void WriteFDEHeader(std::vector<uint8_t>* buf) {
+void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit) {
// 'length' (filled in by other functions).
- PushWord(buf, 0);
+ if (is_64bit) {
+ PushWord(buf, 0xffffffff); // Indicates 64bit
+ PushWord(buf, 0);
+ PushWord(buf, 0);
+ } else {
+ PushWord(buf, 0);
+ }
// 'CIE_pointer' (filled in by linker).
- PushWord(buf, 0);
+ if (is_64bit) {
+ PushWord(buf, 0);
+ PushWord(buf, 0);
+ } else {
+ PushWord(buf, 0);
+ }
// 'initial_location' (filled in by linker).
- PushWord(buf, 0);
+ if (is_64bit) {
+ PushWord(buf, 0);
+ PushWord(buf, 0);
+ } else {
+ PushWord(buf, 0);
+ }
// 'address_range' (filled in by other functions).
- PushWord(buf, 0);
+ if (is_64bit) {
+ PushWord(buf, 0);
+ PushWord(buf, 0);
+ } else {
+ PushWord(buf, 0);
+ }
// Augmentation length: 0
buf->push_back(0);
}
-void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data) {
- const int kOffsetOfAddressRange = 12;
- CHECK(buf->size() >= kOffsetOfAddressRange + sizeof(uint32_t));
+void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit) {
+ const size_t kOffsetOfAddressRange = is_64bit? 28 : 12;
+ CHECK(buf->size() >= kOffsetOfAddressRange + (is_64bit? 8 : 4));
uint8_t *p = buf->data() + kOffsetOfAddressRange;
- p[0] = data;
- p[1] = data >> 8;
- p[2] = data >> 16;
- p[3] = data >> 24;
+ if (is_64bit) {
+ p[0] = data;
+ p[1] = data >> 8;
+ p[2] = data >> 16;
+ p[3] = data >> 24;
+ p[4] = data >> 32;
+ p[5] = data >> 40;
+ p[6] = data >> 48;
+ p[7] = data >> 56;
+ } else {
+ p[0] = data;
+ p[1] = data >> 8;
+ p[2] = data >> 16;
+ p[3] = data >> 24;
+ }
}
-void WriteCFILength(std::vector<uint8_t>* buf) {
- uint32_t length = buf->size() - 4;
+void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit) {
+ uint64_t length = is_64bit ? buf->size() - 12 : buf->size() - 4;
DCHECK_EQ((length & 0x3), 0U);
- DCHECK_GT(length, 4U);
- uint8_t *p = buf->data();
- p[0] = length;
- p[1] = length >> 8;
- p[2] = length >> 16;
- p[3] = length >> 24;
+ uint8_t *p = is_64bit? buf->data() + 4 : buf->data();
+ if (is_64bit) {
+ p[0] = length;
+ p[1] = length >> 8;
+ p[2] = length >> 16;
+ p[3] = length >> 24;
+ p[4] = length >> 32;
+ p[5] = length >> 40;
+ p[6] = length >> 48;
+ p[7] = length >> 56;
+ } else {
+ p[0] = length;
+ p[1] = length >> 8;
+ p[2] = length >> 16;
+ p[3] = length >> 24;
+ }
}
void PadCFI(std::vector<uint8_t>* buf) {
diff --git a/compiler/utils/dwarf_cfi.h b/compiler/utils/dwarf_cfi.h
index e5acc0e..0c8b151 100644
--- a/compiler/utils/dwarf_cfi.h
+++ b/compiler/utils/dwarf_cfi.h
@@ -66,20 +66,24 @@
/**
* @brief Write FDE header into an FDE buffer
* @param buf FDE buffer.
+ * @param is_64bit If FDE is for 64bit application.
*/
-void WriteFDEHeader(std::vector<uint8_t>* buf);
+void WriteFDEHeader(std::vector<uint8_t>* buf, bool is_64bit);
/**
* @brief Set 'address_range' field of an FDE buffer
* @param buf FDE buffer.
+ * @param data Data value.
+ * @param is_64bit If FDE is for 64bit application.
*/
-void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data);
+void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint64_t data, bool is_64bit);
/**
* @brief Set 'length' field of an FDE buffer
* @param buf FDE buffer.
+ * @param is_64bit If FDE is for 64bit application.
*/
-void WriteCFILength(std::vector<uint8_t>* buf);
+void WriteCFILength(std::vector<uint8_t>* buf, bool is_64bit);
/**
* @brief Pad an FDE buffer with 0 until its size is a multiple of 4
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 48edb15..2c9bc28 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1409,13 +1409,13 @@
}
void X86Assembler::InitializeFrameDescriptionEntry() {
- WriteFDEHeader(&cfi_info_);
+ WriteFDEHeader(&cfi_info_, false /* is_64bit */);
}
void X86Assembler::FinalizeFrameDescriptionEntry() {
- WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+ WriteFDEAddressRange(&cfi_info_, buffer_.Size(), false /* is_64bit */);
PadCFI(&cfi_info_);
- WriteCFILength(&cfi_info_);
+ WriteCFILength(&cfi_info_, false /* is_64bit */);
}
constexpr size_t kFramePointerSize = 4;
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 62b72c2..1e2884a 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1716,13 +1716,13 @@
}
void X86_64Assembler::InitializeFrameDescriptionEntry() {
- WriteFDEHeader(&cfi_info_);
+ WriteFDEHeader(&cfi_info_, true /* is_64bit */);
}
void X86_64Assembler::FinalizeFrameDescriptionEntry() {
- WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+ WriteFDEAddressRange(&cfi_info_, buffer_.Size(), true /* is_64bit */);
PadCFI(&cfi_info_);
- WriteCFILength(&cfi_info_);
+ WriteCFILength(&cfi_info_, true /* is_64bit */);
}
constexpr size_t kFramePointerSize = 8;
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 0ca8962..0bf758e 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -702,12 +702,24 @@
load = true;
immediate_bytes = 1;
break;
+ case 0xA5:
+ opcode << "shld";
+ has_modrm = true;
+ load = true;
+ cx = true;
+ break;
case 0xAC:
opcode << "shrd";
has_modrm = true;
load = true;
immediate_bytes = 1;
break;
+ case 0xAD:
+ opcode << "shrd";
+ has_modrm = true;
+ load = true;
+ cx = true;
+ break;
case 0xAE:
if (prefix[0] == 0xF3) {
prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index eed20da..72ad9a5 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -569,6 +569,11 @@
}
}
+ t.NewTiming("Fixup Debug Sections");
+ if (!oat_file_->FixupDebugSections(delta_)) {
+ return false;
+ }
+
return true;
}
diff --git a/runtime/Android.mk b/runtime/Android.mk
index f55d3fb..1f2f86e 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -106,7 +106,7 @@
mirror/string.cc \
mirror/throwable.cc \
monitor.cc \
- native_bridge.cc \
+ native_bridge_art_interface.cc \
native/dalvik_system_DexFile.cc \
native/dalvik_system_VMDebug.cc \
native/dalvik_system_VMRuntime.cc \
@@ -417,7 +417,7 @@
LOCAL_C_INCLUDES += $$(ART_C_INCLUDES)
LOCAL_C_INCLUDES += art/sigchainlib
- LOCAL_SHARED_LIBRARIES += liblog libnativehelper
+ LOCAL_SHARED_LIBRARIES += liblog libnativehelper libnativebridge
include external/libcxx/libcxx.mk
LOCAL_SHARED_LIBRARIES += libbacktrace_libc++
ifeq ($$(art_target_or_host),target)
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 4db5ea6..6add93b 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -22,9 +22,9 @@
// Offset of field Thread::tls32_.state_and_flags verified in InitCpu
#define THREAD_FLAGS_OFFSET 0
// Offset of field Thread::tlsPtr_.card_table verified in InitCpu
-#define THREAD_CARD_TABLE_OFFSET 112
+#define THREAD_CARD_TABLE_OFFSET 120
// Offset of field Thread::tlsPtr_.exception verified in InitCpu
-#define THREAD_EXCEPTION_OFFSET 116
+#define THREAD_EXCEPTION_OFFSET 124
#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64
#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index c143c5d..65a48f6 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -66,7 +66,7 @@
#if defined(__APPLE__) && defined(__x86_64__)
// mac symbols have a prefix of _ on x86_64
extern "C" void _art_quick_throw_null_pointer_exception();
-extern "C" void _art_quick_throw_stack_overflow_from_signal();
+extern "C" void _art_quick_throw_stack_overflow();
extern "C" void _art_quick_test_suspend();
#define EXT_SYM(sym) _ ## sym
#else
@@ -395,7 +395,7 @@
// the previous frame.
// Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
- uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
+ uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_stack_overflow));
return true;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 91cd11b..3ab4ef8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2022,21 +2022,20 @@
return mirror::Class::ComputeClassSize(false, 0, num_32, num_64, num_ref);
}
-bool ClassLinker::FindOatClass(const DexFile& dex_file,
- uint16_t class_def_idx,
- OatFile::OatClass* oat_class) {
- DCHECK(oat_class != nullptr);
+OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx,
+ bool* found) {
DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
if (oat_file == nullptr) {
- return false;
+ *found = false;
+ return OatFile::OatClass::Invalid();
}
uint dex_location_checksum = dex_file.GetLocationChecksum();
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
&dex_location_checksum);
CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
- *oat_class = oat_dex_file->GetOatClass(class_def_idx);
- return true;
+ *found = true;
+ return oat_dex_file->GetOatClass(class_def_idx);
}
static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx,
@@ -2073,8 +2072,7 @@
return 0;
}
-bool ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method) {
- DCHECK(oat_method != nullptr);
+const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) {
// Although we overwrite the trampoline of non-static methods, we may get here via the resolution
// method for direct methods (or virtual methods made direct).
mirror::Class* declaring_class = method->GetDeclaringClass();
@@ -2101,15 +2099,14 @@
GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(),
method->GetDeclaringClass()->GetDexClassDefIndex(),
method->GetDexMethodIndex()));
- OatFile::OatClass oat_class;
- if (!FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
- declaring_class->GetDexClassDefIndex(),
- &oat_class)) {
- return false;
+ OatFile::OatClass oat_class = FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
+ declaring_class->GetDexClassDefIndex(),
+ found);
+ if (!found) {
+ return OatFile::OatMethod::Invalid();
}
-
- *oat_method = oat_class.GetOatMethod(oat_method_index);
- return true;
+ *found = true;
+ return oat_class.GetOatMethod(oat_method_index);
}
// Special case to get oat code without overwriting a trampoline.
@@ -2118,9 +2115,10 @@
if (method->IsProxyMethod()) {
return GetQuickProxyInvokeHandler();
}
- OatFile::OatMethod oat_method;
+ bool found;
+ OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
const void* result = nullptr;
- if (FindOatMethodFor(method, &oat_method)) {
+ if (found) {
result = oat_method.GetQuickCode();
}
@@ -2146,10 +2144,11 @@
if (method->IsProxyMethod()) {
return GetPortableProxyInvokeHandler();
}
- OatFile::OatMethod oat_method;
+ bool found;
+ OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
const void* result = nullptr;
const void* quick_code = nullptr;
- if (FindOatMethodFor(method, &oat_method)) {
+ if (found) {
result = oat_method.GetPortableCode();
quick_code = oat_method.GetQuickCode();
}
@@ -2170,8 +2169,9 @@
const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
uint32_t method_idx) {
- OatFile::OatClass oat_class;
- if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+ bool found;
+ OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
+ if (!found) {
return nullptr;
}
uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
@@ -2180,8 +2180,9 @@
const void* ClassLinker::GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
uint32_t method_idx) {
- OatFile::OatClass oat_class;
- if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+ bool found;
+ OatFile::OatClass oat_class = FindOatClass(dex_file, class_def_idx, &found);
+ if (!found) {
return nullptr;
}
uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
@@ -2234,8 +2235,9 @@
while (it.HasNextInstanceField()) {
it.Next();
}
- OatFile::OatClass oat_class;
- bool has_oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class);
+ bool has_oat_class;
+ OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
+ &has_oat_class);
// Link the code of methods skipped by LinkCode.
for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) {
mirror::ArtMethod* method = klass->GetDirectMethod(method_index);
@@ -2386,12 +2388,16 @@
return; // no fields or methods - for example a marker interface
}
- OatFile::OatClass oat_class;
- if (Runtime::Current()->IsStarted()
- && !Runtime::Current()->UseCompileTimeClassPath()
- && FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class)) {
- LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
- } else {
+
+ bool has_oat_class = false;
+ if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+ OatFile::OatClass oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(),
+ &has_oat_class);
+ if (has_oat_class) {
+ LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
+ }
+ }
+ if (!has_oat_class) {
LoadClassMembers(dex_file, class_data, klass, class_loader, nullptr);
}
}
@@ -3561,19 +3567,13 @@
proxy_class->GetDirectMethods();
CHECK_EQ(proxy_direct_methods->GetLength(), 16);
mirror::ArtMethod* proxy_constructor = proxy_direct_methods->Get(2);
+ // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its
+ // code_ too)
mirror::ArtMethod* constructor = down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self));
if (constructor == nullptr) {
CHECK(self->IsExceptionPending()); // OOME.
return nullptr;
}
- // Make the proxy constructor's code always point to the uninstrumented code. This avoids
- // getting a method enter event for the proxy constructor as the proxy constructor doesn't
- // have an activation.
- bool have_portable_code;
- constructor->SetEntryPointFromQuickCompiledCode(GetQuickOatCodeFor(proxy_constructor));
- constructor->SetEntryPointFromPortableCompiledCode(GetPortableOatCodeFor(proxy_constructor,
- &have_portable_code));
-
// Make this constructor public and fix the class to be our Proxy version
constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
constructor->SetDeclaringClass(klass.Get());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 6fc0f0e..d2c9b40 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -392,7 +392,7 @@
}
private:
- bool FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method)
+ const OatFile::OatMethod FindOatMethodFor(mirror::ArtMethod* method, bool* found)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
OatFile& GetImageOatFile(gc::space::ImageSpace* space)
@@ -461,9 +461,9 @@
void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Finds the associated oat class for a dex_file and descriptor. Returns whether the class
- // was found, and sets the data in oat_class.
- bool FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, OatFile::OatClass* oat_class)
+ // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
+ // error and sets found to false.
+ OatFile::OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index ab4a2bb..eed6f71 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -285,19 +285,6 @@
return StringPrintf("%s/framework/%s.jar", GetAndroidRoot(), jar_prefix.c_str());
}
-std::string CommonRuntimeTest::GetLibCoreOatFileName() {
- return GetOatFileName("core");
-}
-
-std::string CommonRuntimeTest::GetOatFileName(const std::string& oat_prefix) {
- if (IsHost()) {
- const char* host_dir = getenv("ANDROID_HOST_OUT");
- CHECK(host_dir != nullptr);
- return StringPrintf("%s/framework/%s.art", host_dir, oat_prefix.c_str());
- }
- return StringPrintf("%s/framework/%s.art", GetAndroidRoot(), oat_prefix.c_str());
-}
-
std::string CommonRuntimeTest::GetTestAndroidRoot() {
if (IsHost()) {
const char* host_dir = getenv("ANDROID_HOST_OUT");
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index ddb6c81..1ca6eb3 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -97,12 +97,6 @@
// Gets the path of the specified dex file for host or target.
std::string GetDexFileName(const std::string& jar_prefix);
- // Gets the path of the libcore oat file.
- std::string GetLibCoreOatFileName();
-
- // Gets the path of the specified oat file for host or target.
- std::string GetOatFileName(const std::string& oat_prefix);
-
std::string GetTestAndroidRoot();
std::vector<const DexFile*> OpenTestDexFiles(const char* name)
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 6179b5e..566ce03 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1020,7 +1020,7 @@
return nullptr;
}
-struct PACKED(1) FDE {
+struct PACKED(1) FDE32 {
uint32_t raw_length_;
uint32_t GetLength() {
return raw_length_ + sizeof(raw_length_);
@@ -1031,25 +1031,186 @@
uint8_t instructions[0];
};
-static FDE* NextFDE(FDE* frame) {
+static FDE32* NextFDE(FDE32* frame) {
byte* fde_bytes = reinterpret_cast<byte*>(frame);
fde_bytes += frame->GetLength();
- return reinterpret_cast<FDE*>(fde_bytes);
+ return reinterpret_cast<FDE32*>(fde_bytes);
}
-static bool IsFDE(FDE* frame) {
+static bool IsFDE(FDE32* frame) {
return frame->CIE_pointer != 0;
}
-// TODO This only works for 32-bit Elf Files.
-static bool FixupEHFrame(uintptr_t text_start, byte* eh_frame, size_t eh_frame_size) {
- FDE* last_frame = reinterpret_cast<FDE*>(eh_frame + eh_frame_size);
- FDE* frame = NextFDE(reinterpret_cast<FDE*>(eh_frame));
- for (; frame < last_frame; frame = NextFDE(frame)) {
- if (!IsFDE(frame)) {
+struct PACKED(1) FDE64 {
+ uint32_t raw_length_;
+ uint64_t extended_length_;
+ uint64_t GetLength() {
+ return extended_length_ + sizeof(raw_length_) + sizeof(extended_length_);
+ }
+ uint64_t CIE_pointer;
+ uint64_t initial_location;
+ uint64_t address_range;
+ uint8_t instructions[0];
+};
+
+static FDE64* NextFDE(FDE64* frame) {
+ byte* fde_bytes = reinterpret_cast<byte*>(frame);
+ fde_bytes += frame->GetLength();
+ return reinterpret_cast<FDE64*>(fde_bytes);
+}
+
+static bool IsFDE(FDE64* frame) {
+ return frame->CIE_pointer != 0;
+}
+
+static bool FixupEHFrame(off_t base_address_delta,
+ byte* eh_frame, size_t eh_frame_size) {
+ if (*(reinterpret_cast<uint32_t*>(eh_frame)) == 0xffffffff) {
+ FDE64* last_frame = reinterpret_cast<FDE64*>(eh_frame + eh_frame_size);
+ FDE64* frame = NextFDE(reinterpret_cast<FDE64*>(eh_frame));
+ for (; frame < last_frame; frame = NextFDE(frame)) {
+ if (!IsFDE(frame)) {
+ return false;
+ }
+ frame->initial_location += base_address_delta;
+ }
+ return true;
+ } else {
+ FDE32* last_frame = reinterpret_cast<FDE32*>(eh_frame + eh_frame_size);
+ FDE32* frame = NextFDE(reinterpret_cast<FDE32*>(eh_frame));
+ for (; frame < last_frame; frame = NextFDE(frame)) {
+ if (!IsFDE(frame)) {
+ return false;
+ }
+ frame->initial_location += base_address_delta;
+ }
+ return true;
+ }
+}
+
+static uint8_t* NextLeb128(uint8_t* current) {
+ DecodeUnsignedLeb128(const_cast<const uint8_t**>(¤t));
+ return current;
+}
+
+struct PACKED(1) DebugLineHeader {
+ uint32_t unit_length_; // TODO 32-bit specific size
+ uint16_t version_;
+ uint32_t header_length_; // TODO 32-bit specific size
+ uint8_t minimum_instruction_lenght_;
+ uint8_t maximum_operations_per_instruction_;
+ uint8_t default_is_stmt_;
+ int8_t line_base_;
+ uint8_t line_range_;
+ uint8_t opcode_base_;
+ uint8_t remaining_[0];
+
+ bool IsStandardOpcode(const uint8_t* op) const {
+ return *op != 0 && *op < opcode_base_;
+ }
+
+ bool IsExtendedOpcode(const uint8_t* op) const {
+ return *op == 0;
+ }
+
+ const uint8_t* GetStandardOpcodeLengths() const {
+ return remaining_;
+ }
+
+ uint8_t* GetNextOpcode(uint8_t* op) const {
+ if (IsExtendedOpcode(op)) {
+ uint8_t* length_field = op + 1;
+ uint32_t length = DecodeUnsignedLeb128(const_cast<const uint8_t**>(&length_field));
+ return length_field + length;
+ } else if (!IsStandardOpcode(op)) {
+ return op + 1;
+ } else if (*op == DW_LNS_fixed_advance_pc) {
+ return op + 1 + sizeof(uint16_t);
+ } else {
+ uint8_t num_args = GetStandardOpcodeLengths()[*op - 1];
+ op += 1;
+ for (int i = 0; i < num_args; i++) {
+ op = NextLeb128(op);
+ }
+ return op;
+ }
+ }
+
+ uint8_t* GetDebugLineData() const {
+ const uint8_t* hdr_start =
+ reinterpret_cast<const uint8_t*>(&header_length_) + sizeof(header_length_);
+ return const_cast<uint8_t*>(hdr_start + header_length_);
+ }
+};
+
+class DebugLineInstructionIterator {
+ public:
+ static DebugLineInstructionIterator* Create(DebugLineHeader* header, size_t section_size) {
+ std::unique_ptr<DebugLineInstructionIterator> line_iter(
+ new DebugLineInstructionIterator(header, section_size));
+ if (line_iter.get() == nullptr) {
+ return nullptr;
+ } else {
+ return line_iter.release();
+ }
+ }
+
+ ~DebugLineInstructionIterator() {}
+
+ bool Next() {
+ if (current_instruction_ == nullptr) {
return false;
}
- frame->initial_location += text_start;
+ current_instruction_ = header_->GetNextOpcode(current_instruction_);
+ if (current_instruction_ >= last_instruction_) {
+ current_instruction_ = nullptr;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ uint8_t* GetInstruction() {
+ return current_instruction_;
+ }
+
+ bool IsExtendedOpcode() {
+ return header_->IsExtendedOpcode(current_instruction_);
+ }
+
+ uint8_t GetOpcode() {
+ if (!IsExtendedOpcode()) {
+ return *current_instruction_;
+ } else {
+ uint8_t* len_ptr = current_instruction_ + 1;
+ return *NextLeb128(len_ptr);
+ }
+ }
+
+ uint8_t* GetArguments() {
+ if (!IsExtendedOpcode()) {
+ return current_instruction_ + 1;
+ } else {
+ uint8_t* len_ptr = current_instruction_ + 1;
+ return NextLeb128(len_ptr) + 1;
+ }
+ }
+
+ private:
+ DebugLineInstructionIterator(DebugLineHeader* header, size_t size)
+ : header_(header), last_instruction_(reinterpret_cast<uint8_t*>(header) + size),
+ current_instruction_(header->GetDebugLineData()) {}
+
+ DebugLineHeader* header_;
+ uint8_t* last_instruction_;
+ uint8_t* current_instruction_;
+};
+
+static bool FixupDebugLine(off_t base_offset_delta, DebugLineInstructionIterator* iter) {
+ while (iter->Next()) {
+ if (iter->IsExtendedOpcode() && iter->GetOpcode() == DW_LNE_set_address) {
+ *reinterpret_cast<uint32_t*>(iter->GetArguments()) += base_offset_delta;
+ }
}
return true;
}
@@ -1189,20 +1350,29 @@
public:
~DebugAbbrev() {}
static DebugAbbrev* Create(const byte* dbg_abbrev, size_t dbg_abbrev_size) {
- std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev);
- const byte* last = dbg_abbrev + dbg_abbrev_size;
- while (dbg_abbrev < last) {
- std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
- if (tag.get() == nullptr) {
- return nullptr;
- } else {
- abbrev->tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, abbrev->tag_list_.size()));
- abbrev->tag_list_.push_back(std::move(tag));
- }
+ std::unique_ptr<DebugAbbrev> abbrev(new DebugAbbrev(dbg_abbrev, dbg_abbrev + dbg_abbrev_size));
+ if (!abbrev->ReadAtOffset(0)) {
+ return nullptr;
}
return abbrev.release();
}
+ bool ReadAtOffset(uint32_t abbrev_offset) {
+ tags_.clear();
+ tag_list_.clear();
+ const byte* dbg_abbrev = begin_ + abbrev_offset;
+ while (dbg_abbrev < end_ && *dbg_abbrev != 0) {
+ std::unique_ptr<DebugTag> tag(DebugTag::Create(&dbg_abbrev));
+ if (tag.get() == nullptr) {
+ return false;
+ } else {
+ tags_.insert(std::pair<uint32_t, uint32_t>(tag->index_, tag_list_.size()));
+ tag_list_.push_back(std::move(tag));
+ }
+ }
+ return true;
+ }
+
DebugTag* ReadTag(const byte* entry) {
uint32_t tag_num = DecodeUnsignedLeb128(&entry);
auto it = tags_.find(tag_num);
@@ -1215,7 +1385,9 @@
}
private:
- DebugAbbrev() {}
+ DebugAbbrev(const byte* begin, const byte* end) : begin_(begin), end_(end) {}
+ const byte* begin_;
+ const byte* end_;
std::map<uint32_t, uint32_t> tags_;
std::vector<std::unique_ptr<DebugTag>> tag_list_;
};
@@ -1239,11 +1411,21 @@
if (current_entry_ == nullptr || current_tag_ == nullptr) {
return false;
}
+ bool reread_abbrev = false;
current_entry_ += current_tag_->GetSize();
+ if (reinterpret_cast<DebugInfoHeader*>(current_entry_) >= next_cu_) {
+ current_cu_ = next_cu_;
+ next_cu_ = GetNextCu(current_cu_);
+ current_entry_ = reinterpret_cast<byte*>(current_cu_) + sizeof(DebugInfoHeader);
+ reread_abbrev = true;
+ }
if (current_entry_ >= last_entry_) {
current_entry_ = nullptr;
return false;
}
+ if (reread_abbrev) {
+ abbrev_->ReadAtOffset(current_cu_->debug_abbrev_offset);
+ }
current_tag_ = abbrev_->ReadTag(current_entry_);
if (current_tag_ == nullptr) {
current_entry_ = nullptr;
@@ -1271,49 +1453,91 @@
}
private:
+ static DebugInfoHeader* GetNextCu(DebugInfoHeader* hdr) {
+ byte* hdr_byte = reinterpret_cast<byte*>(hdr);
+ return reinterpret_cast<DebugInfoHeader*>(hdr_byte + sizeof(uint32_t) + hdr->unit_length);
+ }
+
DebugInfoIterator(DebugInfoHeader* header, size_t frame_size, DebugAbbrev* abbrev)
: abbrev_(abbrev),
+ current_cu_(header),
+ next_cu_(GetNextCu(header)),
last_entry_(reinterpret_cast<byte*>(header) + frame_size),
current_entry_(reinterpret_cast<byte*>(header) + sizeof(DebugInfoHeader)),
current_tag_(abbrev_->ReadTag(current_entry_)) {}
DebugAbbrev* abbrev_;
+ DebugInfoHeader* current_cu_;
+ DebugInfoHeader* next_cu_;
byte* last_entry_;
byte* current_entry_;
DebugTag* current_tag_;
};
-static bool FixupDebugInfo(uint32_t text_start, DebugInfoIterator* iter) {
+static bool FixupDebugInfo(off_t base_address_delta, DebugInfoIterator* iter) {
do {
if (iter->GetCurrentTag()->GetAttrSize(DW_AT_low_pc) != sizeof(int32_t) ||
iter->GetCurrentTag()->GetAttrSize(DW_AT_high_pc) != sizeof(int32_t)) {
+ LOG(ERROR) << "DWARF information with 64 bit pointers is not supported yet.";
return false;
}
uint32_t* PC_low = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_low_pc));
uint32_t* PC_high = reinterpret_cast<uint32_t*>(iter->GetPointerToField(DW_AT_high_pc));
if (PC_low != nullptr && PC_high != nullptr) {
- *PC_low += text_start;
- *PC_high += text_start;
+ *PC_low += base_address_delta;
+ *PC_high += base_address_delta;
}
} while (iter->next());
return true;
}
-static bool FixupDebugSections(const byte* dbg_abbrev, size_t dbg_abbrev_size,
- uintptr_t text_start,
- byte* dbg_info, size_t dbg_info_size,
- byte* eh_frame, size_t eh_frame_size) {
- std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(dbg_abbrev, dbg_abbrev_size));
+bool ElfFile::FixupDebugSections(off_t base_address_delta) {
+ const Elf32_Shdr* debug_info = FindSectionByName(".debug_info");
+ const Elf32_Shdr* debug_abbrev = FindSectionByName(".debug_abbrev");
+ const Elf32_Shdr* eh_frame = FindSectionByName(".eh_frame");
+ const Elf32_Shdr* debug_str = FindSectionByName(".debug_str");
+ const Elf32_Shdr* debug_line = FindSectionByName(".debug_line");
+ const Elf32_Shdr* strtab_sec = FindSectionByName(".strtab");
+ const Elf32_Shdr* symtab_sec = FindSectionByName(".symtab");
+
+ if (debug_info == nullptr || debug_abbrev == nullptr ||
+ debug_str == nullptr || strtab_sec == nullptr || symtab_sec == nullptr) {
+ // Release version of ART does not generate debug info.
+ return true;
+ }
+ if (base_address_delta == 0) {
+ return true;
+ }
+ if (eh_frame != nullptr &&
+ !FixupEHFrame(base_address_delta, Begin() + eh_frame->sh_offset, eh_frame->sh_size)) {
+ return false;
+ }
+
+ std::unique_ptr<DebugAbbrev> abbrev(DebugAbbrev::Create(Begin() + debug_abbrev->sh_offset,
+ debug_abbrev->sh_size));
if (abbrev.get() == nullptr) {
return false;
}
- std::unique_ptr<DebugInfoIterator> iter(
- DebugInfoIterator::Create(reinterpret_cast<DebugInfoHeader*>(dbg_info),
- dbg_info_size, abbrev.get()));
- if (iter.get() == nullptr) {
+ DebugInfoHeader* info_header =
+ reinterpret_cast<DebugInfoHeader*>(Begin() + debug_info->sh_offset);
+ std::unique_ptr<DebugInfoIterator> info_iter(DebugInfoIterator::Create(info_header,
+ debug_info->sh_size,
+ abbrev.get()));
+ if (info_iter.get() == nullptr) {
return false;
}
- return FixupDebugInfo(text_start, iter.get())
- && FixupEHFrame(text_start, eh_frame, eh_frame_size);
+ if (debug_line != nullptr) {
+ DebugLineHeader* line_header =
+ reinterpret_cast<DebugLineHeader*>(Begin() + debug_line->sh_offset);
+ std::unique_ptr<DebugLineInstructionIterator> line_iter(
+ DebugLineInstructionIterator::Create(line_header, debug_line->sh_size));
+ if (line_iter.get() == nullptr) {
+ return false;
+ }
+ if (!FixupDebugLine(base_address_delta, line_iter.get())) {
+ return false;
+ }
+ }
+ return FixupDebugInfo(base_address_delta, info_iter.get());
}
void ElfFile::GdbJITSupport() {
@@ -1331,19 +1555,13 @@
}
ElfFile& all = *all_ptr;
- // Do we have interesting sections?
- const Elf32_Shdr* debug_info = all.FindSectionByName(".debug_info");
- const Elf32_Shdr* debug_abbrev = all.FindSectionByName(".debug_abbrev");
+ // We need the eh_frame for gdb but debug info might be present without it.
const Elf32_Shdr* eh_frame = all.FindSectionByName(".eh_frame");
- const Elf32_Shdr* debug_str = all.FindSectionByName(".debug_str");
- const Elf32_Shdr* strtab_sec = all.FindSectionByName(".strtab");
- const Elf32_Shdr* symtab_sec = all.FindSectionByName(".symtab");
- Elf32_Shdr* text_sec = all.FindSectionByName(".text");
- if (debug_info == nullptr || debug_abbrev == nullptr || eh_frame == nullptr ||
- debug_str == nullptr || text_sec == nullptr || strtab_sec == nullptr ||
- symtab_sec == nullptr) {
+ if (eh_frame == nullptr) {
return;
}
+
+ // Do we have interesting sections?
// We need to add in a strtab and symtab to the image.
// all is MAP_PRIVATE so it can be written to freely.
// We also already have strtab and symtab so we are fine there.
@@ -1354,13 +1572,9 @@
elf_hdr.e_phentsize = 0;
elf_hdr.e_type = ET_EXEC;
- text_sec->sh_type = SHT_NOBITS;
- text_sec->sh_offset = 0;
-
- if (!FixupDebugSections(
- all.Begin() + debug_abbrev->sh_offset, debug_abbrev->sh_size, text_sec->sh_addr,
- all.Begin() + debug_info->sh_offset, debug_info->sh_size,
- all.Begin() + eh_frame->sh_offset, eh_frame->sh_size)) {
+ // Since base_address_ is 0 if we are actually loaded at a known address (i.e. this is boot.oat)
+ // and the actual address stuff starts at in regular files this is good.
+ if (!all.FixupDebugSections(reinterpret_cast<intptr_t>(base_address_))) {
LOG(ERROR) << "Failed to load GDB data";
return;
}
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index a966bd9..1922911 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -128,6 +128,8 @@
// executable is true at run time, false at compile time.
bool Load(bool executable, std::string* error_msg);
+ bool FixupDebugSections(off_t base_address_delta);
+
private:
ElfFile(File* file, bool writable, bool program_header_only);
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index ae42284..9c6f8c4 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -121,6 +121,13 @@
// Do not change stubs for these methods.
return;
}
+ std::string temp;
+ // Note that the Proxy class itself is not a proxy class.
+ if (strcmp(method->GetDeclaringClass()->GetDescriptor(&temp), "Ljava/lang/reflect/Proxy;") == 0 &&
+ method->IsConstructor()) {
+ // Do not stub Proxy.<init>.
+ return;
+ }
const void* new_portable_code;
const void* new_quick_code;
bool uninstall = !entry_exit_stubs_installed_ && !interpreter_stubs_installed_;
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 9eab3fd..e085ac2 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -25,7 +25,7 @@
#include "mirror/art_method.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
-#include "native_bridge.h"
+#include "nativebridge/native_bridge.h"
#include "java_vm_ext.h"
#include "parsed_options.h"
#include "ScopedLocalRef.h"
@@ -135,7 +135,7 @@
CHECK(NeedsNativeBridge());
uint32_t len = 0;
- return NativeBridgeGetTrampoline(handle_, symbol_name.c_str(), shorty, len);
+ return android::NativeBridgeGetTrampoline(handle_, symbol_name.c_str(), shorty, len);
}
private:
@@ -645,8 +645,8 @@
void* handle = dlopen(path_str, RTLD_LAZY);
bool needs_native_bridge = false;
if (handle == nullptr) {
- if (NativeBridgeIsSupported(path_str)) {
- handle = NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
+ if (android::NativeBridgeIsSupported(path_str)) {
+ handle = android::NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
needs_native_bridge = true;
}
}
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index b7d485e..1c870cd 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -43,7 +43,6 @@
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
#include "mirror/throwable.h"
-#include "native_bridge.h"
#include "parsed_options.h"
#include "reflection.h"
#include "runtime.h"
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 89de16e..dfb42b8 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -137,25 +137,26 @@
return dest;
}
-// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
-class Leb128EncodingVector {
+// An encoder that pushed uint32_t data onto the given std::vector.
+class Leb128Encoder {
public:
- Leb128EncodingVector() {
+ explicit Leb128Encoder(std::vector<uint8_t>* data) : data_(data) {
+ DCHECK(data != nullptr);
}
void Reserve(uint32_t size) {
- data_.reserve(size);
+ data_->reserve(size);
}
void PushBackUnsigned(uint32_t value) {
uint8_t out = value & 0x7f;
value >>= 7;
while (value != 0) {
- data_.push_back(out | 0x80);
+ data_->push_back(out | 0x80);
out = value & 0x7f;
value >>= 7;
}
- data_.push_back(out);
+ data_->push_back(out);
}
template<typename It>
@@ -169,12 +170,12 @@
uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
uint8_t out = value & 0x7f;
while (extra_bits != 0u) {
- data_.push_back(out | 0x80);
+ data_->push_back(out | 0x80);
value >>= 7;
out = value & 0x7f;
extra_bits >>= 7;
}
- data_.push_back(out);
+ data_->push_back(out);
}
template<typename It>
@@ -185,12 +186,23 @@
}
const std::vector<uint8_t>& GetData() const {
- return data_;
+ return *data_;
+ }
+
+ protected:
+ std::vector<uint8_t>* const data_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Leb128Encoder);
+};
+
+// An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
+class Leb128EncodingVector FINAL : private std::vector<uint8_t>, public Leb128Encoder {
+ public:
+ Leb128EncodingVector() : Leb128Encoder(this) {
}
private:
- std::vector<uint8_t> data_;
-
DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
};
diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc
index 3543654..a1177d6 100644
--- a/runtime/mirror/object.cc
+++ b/runtime/mirror/object.cc
@@ -162,7 +162,8 @@
break;
}
case LockWord::kThinLocked: {
- // Inflate the thin lock to a monitor and stick the hash code inside of the monitor.
+ // Inflate the thin lock to a monitor and stick the hash code inside of the monitor. May
+ // fail spuriously.
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
Handle<mirror::Object> h_this(hs.NewHandle(current_this));
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 7118af1..5dd16ef 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -176,10 +176,6 @@
// Deflated monitors have a null object.
}
-/*
- * Links a thread into a monitor's wait set. The monitor lock must be
- * held by the caller of this routine.
- */
void Monitor::AppendToWaitSet(Thread* thread) {
DCHECK(owner_ == Thread::Current());
DCHECK(thread != NULL);
@@ -197,10 +193,6 @@
t->SetWaitNext(thread);
}
-/*
- * Unlinks a thread from a monitor's wait set. The monitor lock must
- * be held by the caller of this routine.
- */
void Monitor::RemoveFromWaitSet(Thread *thread) {
DCHECK(owner_ == Thread::Current());
DCHECK(thread != NULL);
@@ -395,29 +387,6 @@
return true;
}
-/*
- * Wait on a monitor until timeout, interrupt, or notification. Used for
- * Object.wait() and (somewhat indirectly) Thread.sleep() and Thread.join().
- *
- * If another thread calls Thread.interrupt(), we throw InterruptedException
- * and return immediately if one of the following are true:
- * - blocked in wait(), wait(long), or wait(long, int) methods of Object
- * - blocked in join(), join(long), or join(long, int) methods of Thread
- * - blocked in sleep(long), or sleep(long, int) methods of Thread
- * Otherwise, we set the "interrupted" flag.
- *
- * Checks to make sure that "ns" is in the range 0-999999
- * (i.e. fractions of a millisecond) and throws the appropriate
- * exception if it isn't.
- *
- * The spec allows "spurious wakeups", and recommends that all code using
- * Object.wait() do so in a loop. This appears to derive from concerns
- * about pthread_cond_wait() on multiprocessor systems. Some commentary
- * on the web casts doubt on whether these can/should occur.
- *
- * Since we're allowed to wake up "early", we clamp extremely long durations
- * to return at the end of the 32-bit time epoch.
- */
void Monitor::Wait(Thread* self, int64_t ms, int32_t ns,
bool interruptShouldThrow, ThreadState why) {
DCHECK(self != NULL);
@@ -641,11 +610,6 @@
return true;
}
-/*
- * Changes the shape of a monitor from thin to fat, preserving the internal lock state. The calling
- * thread must own the lock or the owner must be suspended. There's a race with other threads
- * inflating the lock and so the caller should read the monitor following the call.
- */
void Monitor::Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code) {
DCHECK(self != nullptr);
DCHECK(obj != nullptr);
@@ -823,38 +787,37 @@
}
}
-/*
- * Object.wait(). Also called for class init.
- */
void Monitor::Wait(Thread* self, mirror::Object *obj, int64_t ms, int32_t ns,
bool interruptShouldThrow, ThreadState why) {
DCHECK(self != nullptr);
DCHECK(obj != nullptr);
LockWord lock_word = obj->GetLockWord(true);
- switch (lock_word.GetState()) {
- case LockWord::kHashCode:
- // Fall-through.
- case LockWord::kUnlocked:
- ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
- return; // Failure.
- case LockWord::kThinLocked: {
- uint32_t thread_id = self->GetThreadId();
- uint32_t owner_thread_id = lock_word.ThinLockOwner();
- if (owner_thread_id != thread_id) {
+ while (lock_word.GetState() != LockWord::kFatLocked) {
+ switch (lock_word.GetState()) {
+ case LockWord::kHashCode:
+ // Fall-through.
+ case LockWord::kUnlocked:
ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
return; // Failure.
- } else {
- // We own the lock, inflate to enqueue ourself on the Monitor.
- Inflate(self, self, obj, 0);
- lock_word = obj->GetLockWord(true);
+ case LockWord::kThinLocked: {
+ uint32_t thread_id = self->GetThreadId();
+ uint32_t owner_thread_id = lock_word.ThinLockOwner();
+ if (owner_thread_id != thread_id) {
+ ThrowIllegalMonitorStateExceptionF("object not locked by thread before wait()");
+ return; // Failure.
+ } else {
+ // We own the lock, inflate to enqueue ourself on the Monitor. May fail spuriously so
+ // re-load.
+ Inflate(self, self, obj, 0);
+ lock_word = obj->GetLockWord(true);
+ }
+ break;
}
- break;
- }
- case LockWord::kFatLocked:
- break; // Already set for a wait.
- default: {
- LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
- return;
+ case LockWord::kFatLocked: // Unreachable given the loop condition above. Fall-through.
+ default: {
+ LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
+ return;
+ }
}
}
Monitor* mon = lock_word.FatLockMonitor();
diff --git a/runtime/monitor.h b/runtime/monitor.h
index e8321eb..efa83c7 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -74,6 +74,8 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DoNotify(self, obj, true);
}
+
+ // Object.wait(). Also called for class init.
static void Wait(Thread* self, mirror::Object* obj, int64_t ms, int32_t ns,
bool interruptShouldThrow, ThreadState why)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -119,6 +121,7 @@
return monitor_id_;
}
+ // Inflate the lock on obj. May fail to inflate for spurious reasons, always re-check.
static void InflateThinLocked(Thread* self, Handle<mirror::Object> obj, LockWord lock_word,
uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS;
@@ -137,9 +140,18 @@
LOCKS_EXCLUDED(monitor_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Links a thread into a monitor's wait set. The monitor lock must be held by the caller of this
+ // routine.
void AppendToWaitSet(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(monitor_lock_);
+
+ // Unlinks a thread from a monitor's wait set. The monitor lock must be held by the caller of
+ // this routine.
void RemoveFromWaitSet(Thread* thread) EXCLUSIVE_LOCKS_REQUIRED(monitor_lock_);
+ // Changes the shape of a monitor from thin to fat, preserving the internal lock state. The
+ // calling thread must own the lock or the owner must be suspended. There's a race with other
+ // threads inflating the lock, installing hash codes and spurious failures. The caller should
+ // re-read the lock word following the call.
static void Inflate(Thread* self, Thread* owner, mirror::Object* obj, int32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -170,6 +182,25 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Wait on a monitor until timeout, interrupt, or notification. Used for Object.wait() and
+ // (somewhat indirectly) Thread.sleep() and Thread.join().
+ //
+ // If another thread calls Thread.interrupt(), we throw InterruptedException and return
+ // immediately if one of the following are true:
+ // - blocked in wait(), wait(long), or wait(long, int) methods of Object
+ // - blocked in join(), join(long), or join(long, int) methods of Thread
+ // - blocked in sleep(long), or sleep(long, int) methods of Thread
+ // Otherwise, we set the "interrupted" flag.
+ //
+ // Checks to make sure that "ns" is in the range 0-999999 (i.e. fractions of a millisecond) and
+ // throws the appropriate exception if it isn't.
+ //
+ // The spec allows "spurious wakeups", and recommends that all code using Object.wait() do so in
+ // a loop. This appears to derive from concerns about pthread_cond_wait() on multiprocessor
+ // systems. Some commentary on the web casts doubt on whether these can/should occur.
+ //
+ // Since we're allowed to wake up "early", we clamp extremely long durations to return at the end
+ // of the 32-bit time epoch.
void Wait(Thread* self, int64_t msec, int32_t nsec, bool interruptShouldThrow, ThreadState why)
LOCKS_EXCLUDED(monitor_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/native_bridge.cc b/runtime/native_bridge.cc
deleted file mode 100644
index d0b516b..0000000
--- a/runtime/native_bridge.cc
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "native_bridge.h"
-
-#include <dlfcn.h>
-#include <stdio.h>
-#include "jni.h"
-
-#include "base/mutex.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
-#include "ScopedLocalRef.h"
-#include "thread.h"
-
-#ifdef HAVE_ANDROID_OS
-#include "cutils/properties.h"
-#endif
-
-
-namespace art {
-
-// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
-static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
-
-// The library name we are supposed to load.
-static std::string native_bridge_library_string = "";
-
-// Whether a native bridge is available (loaded and ready).
-static bool available = false;
-// Whether we have already initialized (or tried to).
-static bool initialized = false;
-
-struct NativeBridgeCallbacks;
-static NativeBridgeCallbacks* callbacks = nullptr;
-
-// ART interfaces to native-bridge.
-struct NativeBridgeArtCallbacks {
- // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
- //
- // Parameters:
- // env [IN] pointer to JNIenv.
- // mid [IN] Java methodID.
- // Returns:
- // short descriptor for method.
- const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
-
- // Get number of native methods for specified class.
- //
- // Parameters:
- // env [IN] pointer to JNIenv.
- // clazz [IN] Java class object.
- // Returns:
- // number of native methods.
- uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
-
- // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
- // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
- //
- // Parameters:
- // env [IN] pointer to JNIenv.
- // clazz [IN] Java class object.
- // methods [OUT] array of method with the name, shorty, and fnPtr.
- // method_count [IN] max number of elements in methods.
- // Returns:
- // number of method it actually wrote to methods.
- uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
- uint32_t method_count);
-};
-
-// Native-bridge interfaces to ART
-struct NativeBridgeCallbacks {
- // Initialize native-bridge. Native-bridge's internal implementation must ensure MT safety and
- // that the native-bridge is initialized only once. Thus it is OK to call this interface for an
- // already initialized native-bridge.
- //
- // Parameters:
- // art_cbs [IN] the pointer to NativeBridgeArtCallbacks.
- // Returns:
- // true iff initialization was successful.
- bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
-
- // Load a shared library that is supported by the native-bridge.
- //
- // Parameters:
- // libpath [IN] path to the shared library
- // flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
- // Returns:
- // The opaque handle of the shared library if sucessful, otherwise NULL
- void* (*loadLibrary)(const char* libpath, int flag);
-
- // Get a native-bridge trampoline for specified native method. The trampoline has same
- // sigature as the native method.
- //
- // Parameters:
- // handle [IN] the handle returned from loadLibrary
- // shorty [IN] short descriptor of native method
- // len [IN] length of shorty
- // Returns:
- // address of trampoline if successful, otherwise NULL
- void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
-
- // Check whether native library is valid and is for an ABI that is supported by native-bridge.
- //
- // Parameters:
- // libpath [IN] path to the shared library
- // Returns:
- // TRUE if library is supported by native-bridge, FALSE otherwise
- bool (*isSupported)(const char* libpath);
-};
-
-static const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
- ScopedObjectAccess soa(env);
- StackHandleScope<1> scope(soa.Self());
- mirror::ArtMethod* m = soa.DecodeMethod(mid);
- MethodHelper mh(scope.NewHandle(m));
- return mh.GetShorty();
-}
-
-static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
- if (clazz == nullptr)
- return 0;
-
- ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
-
- uint32_t native_method_count = 0;
- for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
- mirror::ArtMethod* m = c->GetDirectMethod(i);
- if (m->IsNative()) {
- native_method_count++;
- }
- }
- for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
- mirror::ArtMethod* m = c->GetVirtualMethod(i);
- if (m->IsNative()) {
- native_method_count++;
- }
- }
- return native_method_count;
-}
-
-static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
- uint32_t method_count) {
- if ((clazz == nullptr) || (methods == nullptr)) {
- return 0;
- }
- ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
-
- uint32_t count = 0;
- for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
- mirror::ArtMethod* m = c->GetDirectMethod(i);
- if (m->IsNative()) {
- if (count < method_count) {
- methods[count].name = m->GetName();
- methods[count].signature = m->GetShorty();
- methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
- count++;
- } else {
- LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
- }
- }
- }
- for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
- mirror::ArtMethod* m = c->GetVirtualMethod(i);
- if (m->IsNative()) {
- if (count < method_count) {
- methods[count].name = m->GetName();
- methods[count].signature = m->GetShorty();
- methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
- count++;
- } else {
- LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
- }
- }
- }
- return count;
-}
-
-static NativeBridgeArtCallbacks NativeBridgeArtItf = {
- GetMethodShorty,
- GetNativeMethodCount,
- GetNativeMethods
-};
-
-void SetNativeBridgeLibraryString(const std::string& nb_library_string) {
- // This is called when the runtime starts and nothing is working concurrently
- // so we don't need a lock here.
-
- native_bridge_library_string = nb_library_string;
-
- if (native_bridge_library_string.empty()) {
- initialized = true;
- available = false;
- }
-}
-
-static bool NativeBridgeInitialize() {
- // TODO: Missing annotalysis static lock ordering of DEFAULT_MUTEX_ACQUIRED, place lock into
- // global order or remove.
- static Mutex lock("native bridge lock");
- MutexLock mu(Thread::Current(), lock);
-
- if (initialized) {
- // Somebody did it before.
- return available;
- }
-
- available = false;
-
- void* handle = dlopen(native_bridge_library_string.c_str(), RTLD_LAZY);
- if (handle != nullptr) {
- callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
- kNativeBridgeInterfaceSymbol));
-
- if (callbacks != nullptr) {
- available = callbacks->initialize(&NativeBridgeArtItf);
- }
-
- if (!available) {
- dlclose(handle);
- }
- }
-
- initialized = true;
-
- return available;
-}
-
-void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
- if (NativeBridgeInitialize()) {
- return callbacks->loadLibrary(libpath, flag);
- }
- return nullptr;
-}
-
-void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
- uint32_t len) {
- if (NativeBridgeInitialize()) {
- return callbacks->getTrampoline(handle, name, shorty, len);
- }
- return nullptr;
-}
-
-bool NativeBridgeIsSupported(const char* libpath) {
- if (NativeBridgeInitialize()) {
- return callbacks->isSupported(libpath);
- }
- return false;
-}
-
-}; // namespace art
diff --git a/runtime/native_bridge.h b/runtime/native_bridge.h
deleted file mode 100644
index be647fc..0000000
--- a/runtime/native_bridge.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_NATIVE_BRIDGE_H_
-#define ART_RUNTIME_NATIVE_BRIDGE_H_
-
-#include <string>
-
-namespace art {
-
-// Initialize the native bridge, if any. Should be called by Runtime::Init(). An empty string
-// signals that we do not want to load a native bridge.
-void SetNativeBridgeLibraryString(const std::string& native_bridge_library_string);
-
-// Load a shared library that is supported by the native-bridge.
-void* NativeBridgeLoadLibrary(const char* libpath, int flag);
-
-// Get a native-bridge trampoline for specified native method.
-void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
-
-// True if native library is valid and is for an ABI that is supported by native-bridge.
-bool NativeBridgeIsSupported(const char* libpath);
-
-}; // namespace art
-
-#endif // ART_RUNTIME_NATIVE_BRIDGE_H_
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
new file mode 100644
index 0000000..453c92f
--- /dev/null
+++ b/runtime/native_bridge_art_interface.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "native_bridge_art_interface.h"
+
+#include "mirror/art_method-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+
+const char* GetMethodShorty(JNIEnv* env, jmethodID mid) {
+ ScopedObjectAccess soa(env);
+ StackHandleScope<1> scope(soa.Self());
+ mirror::ArtMethod* m = soa.DecodeMethod(mid);
+ MethodHelper mh(scope.NewHandle(m));
+ return mh.GetShorty();
+}
+
+uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) {
+ if (clazz == nullptr)
+ return 0;
+
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+
+ uint32_t native_method_count = 0;
+ for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+ mirror::ArtMethod* m = c->GetDirectMethod(i);
+ if (m->IsNative()) {
+ native_method_count++;
+ }
+ }
+ for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+ mirror::ArtMethod* m = c->GetVirtualMethod(i);
+ if (m->IsNative()) {
+ native_method_count++;
+ }
+ }
+ return native_method_count;
+}
+
+uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+ uint32_t method_count) {
+ if ((clazz == nullptr) || (methods == nullptr)) {
+ return 0;
+ }
+ ScopedObjectAccess soa(env);
+ mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+ mirror::ArtMethod* m = c->GetDirectMethod(i);
+ if (m->IsNative()) {
+ if (count < method_count) {
+ methods[count].name = m->GetName();
+ methods[count].signature = m->GetShorty();
+ methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+ count++;
+ } else {
+ LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
+ }
+ }
+ }
+ for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+ mirror::ArtMethod* m = c->GetVirtualMethod(i);
+ if (m->IsNative()) {
+ if (count < method_count) {
+ methods[count].name = m->GetName();
+ methods[count].signature = m->GetShorty();
+ methods[count].fnPtr = const_cast<void*>(m->GetNativeMethod());
+ count++;
+ } else {
+ LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(m);
+ }
+ }
+ }
+ return count;
+}
+
+}; // namespace art
diff --git a/runtime/native_bridge_art_interface.h b/runtime/native_bridge_art_interface.h
new file mode 100644
index 0000000..08735c8
--- /dev/null
+++ b/runtime/native_bridge_art_interface.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
+#define ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
+
+#include <jni.h>
+#include <stdint.h>
+
+namespace art {
+
+const char* GetMethodShorty(JNIEnv* env, jmethodID mid);
+
+uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz);
+
+uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+ uint32_t method_count);
+
+}; // namespace art
+
+#endif // ART_RUNTIME_NATIVE_BRIDGE_ART_INTERFACE_H_
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 971daf8..b74b10f 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -460,15 +460,17 @@
uint32_t bitmap_size = 0;
const byte* bitmap_pointer = nullptr;
const byte* methods_pointer = nullptr;
- if (type == kOatClassSomeCompiled) {
- bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
- bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
- CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
- methods_pointer = bitmap_pointer + bitmap_size;
- } else {
- methods_pointer = after_type_pointer;
+ if (type != kOatClassNoneCompiled) {
+ if (type == kOatClassSomeCompiled) {
+ bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(after_type_pointer));
+ bitmap_pointer = after_type_pointer + sizeof(bitmap_size);
+ CHECK_LE(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation();
+ methods_pointer = bitmap_pointer + bitmap_size;
+ } else {
+ methods_pointer = after_type_pointer;
+ }
+ CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
}
- CHECK_LE(methods_pointer, oat_file_->End()) << oat_file_->GetLocation();
return OatClass(oat_file_,
status,
@@ -486,22 +488,23 @@
const OatMethodOffsets* methods_pointer)
: oat_file_(oat_file), status_(status), type_(type),
bitmap_(bitmap_pointer), methods_pointer_(methods_pointer) {
- CHECK(methods_pointer != nullptr);
switch (type_) {
case kOatClassAllCompiled: {
CHECK_EQ(0U, bitmap_size);
CHECK(bitmap_pointer == nullptr);
+ CHECK(methods_pointer != nullptr);
break;
}
case kOatClassSomeCompiled: {
CHECK_NE(0U, bitmap_size);
CHECK(bitmap_pointer != nullptr);
+ CHECK(methods_pointer != nullptr);
break;
}
case kOatClassNoneCompiled: {
CHECK_EQ(0U, bitmap_size);
CHECK(bitmap_pointer == nullptr);
- methods_pointer_ = nullptr;
+ CHECK(methods_pointer_ == nullptr);
break;
}
case kOatClassMax: {
@@ -536,16 +539,6 @@
oat_method_offsets.gc_map_offset_);
}
-OatFile::OatMethod::OatMethod(const byte* base,
- const uint32_t code_offset,
- const uint32_t gc_map_offset)
- : begin_(base),
- code_offset_(code_offset),
- native_gc_map_offset_(gc_map_offset) {
-}
-
-OatFile::OatMethod::~OatMethod() {}
-
uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
uintptr_t code = reinterpret_cast<uintptr_t>(GetQuickCode());
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 810eccb..508bfc2 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -126,14 +126,19 @@
const uint8_t* GetMappingTable() const;
const uint8_t* GetVmapTable() const;
- ~OatMethod();
-
// Create an OatMethod with offsets relative to the given base address
- OatMethod(const byte* base,
- const uint32_t code_offset,
- const uint32_t gc_map_offset);
+ OatMethod(const byte* base, const uint32_t code_offset, const uint32_t gc_map_offset)
+ : begin_(base),
+ code_offset_(code_offset),
+ native_gc_map_offset_(gc_map_offset) {
+ }
+ ~OatMethod() {}
- OatMethod() {}
+ // A representation of an invalid OatMethod, used when an OatMethod or OatClass can't be found.
+ // See ClassLinker::FindOatMethodFor.
+ static const OatMethod Invalid() {
+ return OatMethod(nullptr, -1, -1);
+ }
private:
template<class T>
@@ -144,10 +149,10 @@
return reinterpret_cast<T>(begin_ + offset);
}
- const byte* begin_;
+ const byte* const begin_;
- uint32_t code_offset_;
- uint32_t native_gc_map_offset_;
+ const uint32_t code_offset_;
+ const uint32_t native_gc_map_offset_;
friend class OatClass;
};
@@ -168,7 +173,12 @@
// methods are not included.
const OatMethod GetOatMethod(uint32_t method_index) const;
- OatClass() {}
+ // A representation of an invalid OatClass, used when an OatClass can't be found.
+ // See ClassLinker::FindOatClass.
+ static OatClass Invalid() {
+ return OatClass(nullptr, mirror::Class::kStatusError, kOatClassNoneCompiled, 0, nullptr,
+ nullptr);
+ }
private:
OatClass(const OatFile* oat_file,
@@ -178,15 +188,15 @@
const uint32_t* bitmap_pointer,
const OatMethodOffsets* methods_pointer);
- const OatFile* oat_file_;
+ const OatFile* const oat_file_;
- mirror::Class::Status status_;
+ const mirror::Class::Status status_;
- OatClassType type_;
+ const OatClassType type_;
- const uint32_t* bitmap_;
+ const uint32_t* const bitmap_;
- const OatMethodOffsets* methods_pointer_;
+ const OatMethodOffsets* const methods_pointer_;
friend class OatDexFile;
};
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 27f7765..a023ff1 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -609,7 +609,7 @@
return false;
}
} else if (StartsWith(option, "-XX:NativeBridge=")) {
- if (!ParseStringAfterChar(option, '=', &native_bridge_library_string_)) {
+ if (!ParseStringAfterChar(option, '=', &native_bridge_library_path_)) {
return false;
}
} else if (StartsWith(option, "-ea") ||
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index aa2c557..1afd610 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -46,7 +46,7 @@
bool check_jni_;
bool force_copy_;
std::string jni_trace_;
- std::string native_bridge_library_string_;
+ std::string native_bridge_library_path_;
CompilerCallbacks* compiler_callbacks_;
bool is_zygote_;
bool must_relocate_;
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 5af26b0..d977ce9 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -17,14 +17,14 @@
#include <jni.h>
#include <vector>
-#include "common_runtime_test.h"
+#include "common_compiler_test.h"
#include "field_helper.h"
#include "mirror/art_field-inl.h"
#include "scoped_thread_state_change.h"
namespace art {
-class ProxyTest : public CommonRuntimeTest {
+class ProxyTest : public CommonCompilerTest {
public:
// Generate a proxy class with the given name and interfaces. This is a simplification from what
// libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
@@ -103,12 +103,6 @@
soa.Self()->AssertNoPendingException();
return proxyClass;
}
-
- protected:
- void SetUpRuntimeOptions(RuntimeOptions *options) OVERRIDE {
- options->push_back(std::make_pair(StringPrintf("-Ximage:%s", GetLibCoreOatFileName().c_str()),
- nullptr));
- }
};
// Creates a proxy class and check ClassHelper works correctly.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d3957c1..05003cb 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -63,7 +63,7 @@
#include "mirror/stack_trace_element.h"
#include "mirror/throwable.h"
#include "monitor.h"
-#include "native_bridge.h"
+#include "native_bridge_art_interface.h"
#include "parsed_options.h"
#include "oat_file.h"
#include "quick/quick_method_frame_info.h"
@@ -143,7 +143,8 @@
target_sdk_version_(0),
implicit_null_checks_(false),
implicit_so_checks_(false),
- implicit_suspend_checks_(false) {
+ implicit_suspend_checks_(false),
+ native_bridge_art_callbacks_({GetMethodShorty, GetNativeMethodCount, GetNativeMethods}) {
}
Runtime::~Runtime() {
@@ -708,8 +709,11 @@
self->ClearException();
// Look for a native bridge.
- SetNativeBridgeLibraryString(options->native_bridge_library_string_);
-
+ native_bridge_library_path_ = options->native_bridge_library_path_;
+ if (!native_bridge_library_path_.empty()) {
+ android::SetupNativeBridge(native_bridge_library_path_.c_str(), &native_bridge_art_callbacks_);
+ VLOG(startup) << "Runtime::Setup native bridge library: " << native_bridge_library_path_;
+ }
VLOG(startup) << "Runtime::Init exiting";
return true;
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e76280a..34ccdcb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -31,6 +31,7 @@
#include "instrumentation.h"
#include "instruction_set.h"
#include "jobject_comparator.h"
+#include "nativebridge/native_bridge.h"
#include "object_callbacks.h"
#include "offsets.h"
#include "profiler_options.h"
@@ -616,6 +617,25 @@
bool implicit_so_checks_; // StackOverflow checks are implicit.
bool implicit_suspend_checks_; // Thread suspension checks are implicit.
+ // The path to the native bridge library. If this is not empty the native bridge will be
+ // initialized and loaded from the pointed path.
+ //
+ // The native bridge allows running native code compiled for a foreign ISA. The way it works is,
+ // if standard dlopen fails to load native library associated with native activity, it calls to
+ // the native bridge to load it and then gets the trampoline for the entry to native activity.
+ std::string native_bridge_library_path_;
+
+ // Native bridge library runtime callbacks. They represent the runtime interface to native bridge.
+ //
+ // The interface is expected to expose the following methods:
+ // getMethodShorty(): in the case of native method calling JNI native function CallXXXXMethodY(),
+ // native bridge calls back to VM for the shorty of the method so that it can prepare based on
+ // host calling convention.
+ // getNativeMethodCount() and getNativeMethods(): in case of JNI function UnregisterNatives(),
+ // native bridge can call back to get all native methods of specified class so that all
+ // corresponding trampolines can be destroyed.
+ android::NativeBridgeRuntimeCallbacks native_bridge_art_callbacks_;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b845f50..b55977b 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1372,21 +1372,11 @@
}
void EncodeUnsignedLeb128(uint32_t data, std::vector<uint8_t>* dst) {
- size_t encoded_size = UnsignedLeb128Size(data);
- size_t cur_index = dst->size();
- dst->resize(dst->size() + encoded_size);
- uint8_t* write_pos = &((*dst)[cur_index]);
- uint8_t* write_pos_after = EncodeUnsignedLeb128(write_pos, data);
- DCHECK_EQ(static_cast<size_t>(write_pos_after - write_pos), encoded_size);
+ Leb128Encoder(dst).PushBackUnsigned(data);
}
void EncodeSignedLeb128(int32_t data, std::vector<uint8_t>* dst) {
- size_t encoded_size = SignedLeb128Size(data);
- size_t cur_index = dst->size();
- dst->resize(dst->size() + encoded_size);
- uint8_t* write_pos = &((*dst)[cur_index]);
- uint8_t* write_pos_after = EncodeSignedLeb128(write_pos, data);
- DCHECK_EQ(static_cast<size_t>(write_pos_after - write_pos), encoded_size);
+ Leb128Encoder(dst).PushBackSigned(data);
}
void PushWord(std::vector<uint8_t>* buf, int data) {
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index c02f310..63bfc44 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -123,7 +123,7 @@
// Resist the urge to delete the space. <: is a bigraph sequence.
std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
- const int32_t error = FindEntry(handle_, name, zip_entry.get());
+ const int32_t error = FindEntry(handle_, ZipEntryName(name), zip_entry.get());
if (error) {
*error_msg = std::string(ErrorCodeString(error));
return nullptr;
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 268f0be..3acc643 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -22,27 +22,9 @@
#include "jni.h"
#include "stdio.h"
-#include "string.h"
#include "unistd.h"
-#include "native_bridge.h"
-
-
-// Native bridge interfaces...
-
-struct NativeBridgeArtCallbacks {
- const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
- uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
- uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
- uint32_t method_count);
-};
-
-struct NativeBridgeCallbacks {
- bool (*initialize)(NativeBridgeArtCallbacks* art_cbs);
- void* (*loadLibrary)(const char* libpath, int flag);
- void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
- bool (*isSupported)(const char* libpath);
-};
+#include "nativebridge/native_bridge.h"
struct NativeBridgeMethod {
const char* name;
@@ -53,7 +35,7 @@
};
static NativeBridgeMethod* find_native_bridge_method(const char *name);
-static NativeBridgeArtCallbacks* gNativeBridgeArtCallbacks;
+static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks;
static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = nullptr;
@@ -225,7 +207,7 @@
}
// NativeBridgeCallbacks implementations
-extern "C" bool native_bridge_initialize(NativeBridgeArtCallbacks* art_cbs) {
+extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* art_cbs) {
if (art_cbs != nullptr) {
gNativeBridgeArtCallbacks = art_cbs;
printf("Native bridge initialized.\n");
@@ -281,7 +263,9 @@
return strcmp(libpath, "libjavacore.so") != 0;
}
-NativeBridgeCallbacks NativeBridgeItf {
+// "NativeBridgeItf" is effectively an API (it is the name of the symbol that will be loaded
+// by the native bridge library).
+android::NativeBridgeCallbacks NativeBridgeItf {
.initialize = &native_bridge_initialize,
.loadLibrary = &native_bridge_loadLibrary,
.getTrampoline = &native_bridge_getTrampoline,
diff --git a/test/run-test b/test/run-test
index 496f7d1..b8e40d9 100755
--- a/test/run-test
+++ b/test/run-test
@@ -206,6 +206,14 @@
break
fi
done
+
+# tmp_dir may be relative, resolve.
+#
+# Cannot use realpath, as it does not exist on Mac.
+# Cannot us a simple "cd", as the path might not be created yet.
+# Use -m option of readlink: canonicalizes, but allows non-existing components.
+tmp_dir="`cd $oldwd ; readlink -m $tmp_dir`"
+
mkdir -p $tmp_dir
if [ "$basic_verify" = "true" ]; then