Emit CFI for x86 & x86_64 JNI compiler.
Now for host-side x86 & x86_64 ART, we are able to get complete stacktrace with even mixed C/C++ & Java stack frames.
Testing:
1. art/test/run-test --host --gdb [--64] --no-relocate 005
2. In gdb, run 'b art::Class_classForName' which is implementation of a Java native method, then 'r'
3. In gdb, run 'bt'. You should see stack frames down to main()
Change-Id: I2d17e9aa0f6d42d374b5362a15ea35a2fce96302
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 7983040..5c5163d 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -107,6 +107,7 @@
utils/arm64/assembler_arm64.cc \
utils/arm64/managed_register_arm64.cc \
utils/assembler.cc \
+ utils/dwarf_cfi.cc \
utils/mips/assembler_mips.cc \
utils/mips/managed_register_mips.cc \
utils/x86/assembler_x86.cc \
diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc
index f098a34..f2a8d84 100644
--- a/compiler/compiled_method.cc
+++ b/compiler/compiled_method.cc
@@ -165,14 +165,15 @@
const std::vector<uint8_t>& code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
- const uint32_t fp_spill_mask)
+ const uint32_t fp_spill_mask,
+ const std::vector<uint8_t>* cfi_info)
: 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),
mapping_table_(driver->DeduplicateMappingTable(std::vector<uint8_t>())),
vmap_table_(driver->DeduplicateVMapTable(std::vector<uint8_t>())),
gc_map_(driver->DeduplicateGCMap(std::vector<uint8_t>())),
- cfi_info_(nullptr) {
+ cfi_info_(driver->DeduplicateCFIInfo(cfi_info)) {
}
// Constructs a CompiledMethod for the Portable compiler.
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index b8cd851..c98d06a 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -120,7 +120,8 @@
const std::vector<uint8_t>& quick_code,
const size_t frame_size_in_bytes,
const uint32_t core_spill_mask,
- const uint32_t fp_spill_mask);
+ const uint32_t fp_spill_mask,
+ const std::vector<uint8_t>* cfi_info);
// Constructs a CompiledMethod for the Portable compiler.
CompiledMethod(CompilerDriver* driver, InstructionSet instruction_set, const std::string& code,
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 511297c..be79b63 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1085,7 +1085,7 @@
vmap_encoder.PushBackUnsigned(0u); // Size is 0.
}
- std::unique_ptr<std::vector<uint8_t>> cfi_info(ReturnCallFrameInformation());
+ 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_,
@@ -1250,7 +1250,7 @@
AppendLIR(load_pc_rel);
}
-std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() {
+std::vector<uint8_t>* Mir2Lir::ReturnFrameDescriptionEntry() {
// Default case is to do nothing.
return nullptr;
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 2221bb5..4b8f794 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -1528,10 +1528,10 @@
uint32_t type_idx, RegLocation rl_dest,
RegLocation rl_src);
/*
- * @brief Generate the debug_frame FDE information if possible.
- * @returns pointer to vector containg CFE information, or NULL.
+ * @brief Generate the eh_frame FDE information if possible.
+ * @returns pointer to vector containg FDE information, or NULL.
*/
- virtual std::vector<uint8_t>* ReturnCallFrameInformation();
+ virtual std::vector<uint8_t>* ReturnFrameDescriptionEntry();
/**
* @brief Used to insert marker that can be used to associate MIR with LIR.
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index d3ed48d..24a3fe3 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -360,7 +360,7 @@
* @brief Generate the debug_frame FDE information.
* @returns pointer to vector containing CFE information
*/
- std::vector<uint8_t>* ReturnCallFrameInformation() OVERRIDE;
+ std::vector<uint8_t>* ReturnFrameDescriptionEntry() OVERRIDE;
LIR* InvokeTrampoline(OpKind op, RegStorage r_tgt, QuickEntrypointEnum trampoline) OVERRIDE;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 69f3e67..f0fd4e0 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -24,6 +24,7 @@
#include "mirror/array.h"
#include "mirror/string.h"
#include "x86_lir.h"
+#include "utils/dwarf_cfi.h"
namespace art {
@@ -1009,19 +1010,6 @@
return call;
}
-/*
- * @brief Enter a 32 bit quantity into a buffer
- * @param buf buffer.
- * @param data Data value.
- */
-
-static void PushWord(std::vector<uint8_t>&buf, int32_t data) {
- buf.push_back(data & 0xff);
- buf.push_back((data >> 8) & 0xff);
- buf.push_back((data >> 16) & 0xff);
- buf.push_back((data >> 24) & 0xff);
-}
-
void X86Mir2Lir::InstallLiteralPools() {
// These are handled differently for x86.
DCHECK(code_literal_list_ == nullptr);
@@ -1042,10 +1030,10 @@
align_size--;
}
for (LIR *p = const_vectors_; p != nullptr; p = p->next) {
- PushWord(code_buffer_, p->operands[0]);
- PushWord(code_buffer_, p->operands[1]);
- PushWord(code_buffer_, p->operands[2]);
- PushWord(code_buffer_, p->operands[3]);
+ PushWord(&code_buffer_, p->operands[0]);
+ PushWord(&code_buffer_, p->operands[1]);
+ PushWord(&code_buffer_, p->operands[2]);
+ PushWord(&code_buffer_, p->operands[3]);
}
}
@@ -1418,47 +1406,6 @@
return true;
}
-/*
- * @brief Enter an 'advance LOC' into the FDE buffer
- * @param buf FDE buffer.
- * @param increment Amount by which to increase the current location.
- */
-static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
- if (increment < 64) {
- // Encoding in opcode.
- buf.push_back(0x1 << 6 | increment);
- } else if (increment < 256) {
- // Single byte delta.
- buf.push_back(0x02);
- buf.push_back(increment);
- } else if (increment < 256 * 256) {
- // Two byte delta.
- buf.push_back(0x03);
- buf.push_back(increment & 0xff);
- buf.push_back((increment >> 8) & 0xff);
- } else {
- // Four byte delta.
- buf.push_back(0x04);
- PushWord(buf, increment);
- }
-}
-
-static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
- uint8_t buffer[12];
- uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
- for (uint8_t *p = buffer; p < ptr; p++) {
- buf.push_back(*p);
- }
-}
-
-static void EncodeSignedLeb128(std::vector<uint8_t>& buf, int32_t value) {
- uint8_t buffer[12];
- uint8_t *ptr = EncodeSignedLeb128(buffer, value);
- for (uint8_t *p = buffer; p < ptr; p++) {
- buf.push_back(*p);
- }
-}
-
static bool ARTRegIDToDWARFRegID(bool is_x86_64, int art_reg_id, int* dwarf_reg_id) {
if (is_x86_64) {
switch (art_reg_id) {
@@ -1481,36 +1428,23 @@
}
}
-std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
- std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+std::vector<uint8_t>* X86Mir2Lir::ReturnFrameDescriptionEntry() {
+ std::vector<uint8_t>* cfi_info = new std::vector<uint8_t>;
// Generate the FDE for the method.
DCHECK_NE(data_offset_, 0U);
- // Length (will be filled in later in this routine).
- PushWord(*cfi_info, 0);
-
- // 'CIE_pointer' (filled in by linker).
- PushWord(*cfi_info, 0);
-
- // 'initial_location' (filled in by linker).
- PushWord(*cfi_info, 0);
-
- // 'address_range' (number of bytes in the method).
- PushWord(*cfi_info, data_offset_);
-
- // Augmentation length: 0
- cfi_info->push_back(0);
+ WriteFDEHeader(cfi_info);
+ WriteFDEAddressRange(cfi_info, data_offset_);
// The instructions in the FDE.
if (stack_decrement_ != nullptr) {
// Advance LOC to just past the stack decrement.
uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
- AdvanceLoc(*cfi_info, pc);
+ DW_CFA_advance_loc(cfi_info, pc);
// Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
- cfi_info->push_back(0x0e);
- EncodeUnsignedLeb128(*cfi_info, frame_size_);
+ DW_CFA_def_cfa_offset(cfi_info, frame_size_);
// Handle register spills
const uint32_t kSpillInstLen = (cu_->target64) ? 5 : 4;
@@ -1522,14 +1456,12 @@
pc += kSpillInstLen;
// Advance LOC to pass this instruction
- AdvanceLoc(*cfi_info, kSpillInstLen);
+ DW_CFA_advance_loc(cfi_info, kSpillInstLen);
int dwarf_reg_id;
if (ARTRegIDToDWARFRegID(cu_->target64, reg, &dwarf_reg_id)) {
- // DW_CFA_offset_extended_sf reg_no offset
- cfi_info->push_back(0x11);
- EncodeUnsignedLeb128(*cfi_info, dwarf_reg_id);
- EncodeSignedLeb128(*cfi_info, offset / kDataAlignmentFactor);
+ // DW_CFA_offset_extended_sf reg offset
+ DW_CFA_offset_extended_sf(cfi_info, dwarf_reg_id, offset / kDataAlignmentFactor);
}
offset += GetInstructionSetPointerSize(cu_->instruction_set);
@@ -1539,16 +1471,15 @@
// We continue with that stack until the epilogue.
if (stack_increment_ != nullptr) {
uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
- AdvanceLoc(*cfi_info, new_pc - pc);
+ DW_CFA_advance_loc(cfi_info, new_pc - pc);
// We probably have code snippets after the epilogue, so save the
// current state: DW_CFA_remember_state.
- cfi_info->push_back(0x0a);
+ DW_CFA_remember_state(cfi_info);
// We have now popped the stack: DW_CFA_def_cfa_offset 4/8.
// There is only the return PC on the stack now.
- cfi_info->push_back(0x0e);
- EncodeUnsignedLeb128(*cfi_info, GetInstructionSetPointerSize(cu_->instruction_set));
+ DW_CFA_def_cfa_offset(cfi_info, GetInstructionSetPointerSize(cu_->instruction_set));
// Everything after that is the same as before the epilogue.
// Stack bump was followed by RET instruction.
@@ -1556,25 +1487,16 @@
if (post_ret_insn != nullptr) {
pc = new_pc;
new_pc = post_ret_insn->offset;
- AdvanceLoc(*cfi_info, new_pc - pc);
+ DW_CFA_advance_loc(cfi_info, new_pc - pc);
// Restore the state: DW_CFA_restore_state.
- cfi_info->push_back(0x0b);
+ DW_CFA_restore_state(cfi_info);
}
}
}
- // Padding to a multiple of 4
- while ((cfi_info->size() & 3) != 0) {
- // DW_CFA_nop is encoded as 0.
- cfi_info->push_back(0);
- }
+ PadCFI(cfi_info);
+ WriteCFILength(cfi_info);
- // Set the length of the FDE 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;
return cfi_info;
}
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 12e9401..bb5f7e0 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -46,13 +46,6 @@
(*buf)[offset+3] = data >> 24;
}
-static void PushWord(std::vector<uint8_t>* buf, int data) {
- buf->push_back(data & 0xff);
- buf->push_back((data >> 8) & 0xff);
- buf->push_back((data >> 16) & 0xff);
- buf->push_back((data >> 24) & 0xff);
-}
-
static void PushHalf(std::vector<uint8_t>* buf, int data) {
buf->push_back(data & 0xff);
buf->push_back((data >> 8) & 0xff);
@@ -842,24 +835,6 @@
}
}
-static 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);
-}
-
-static 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);
-}
-
std::vector<uint8_t>* ConstructCIEFrameX86(bool is_x86_64) {
std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index c38cfaf..1a35da0 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -90,6 +90,7 @@
// Assembler that holds generated instructions
std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set));
+ jni_asm->InitializeFrameDescriptionEntry();
// Offsets into data structures
// TODO: if cross compiling these offsets are for the host not the target
@@ -432,12 +433,14 @@
std::vector<uint8_t> managed_code(cs);
MemoryRegion code(&managed_code[0], managed_code.size());
__ FinalizeInstructions(code);
+ jni_asm->FinalizeFrameDescriptionEntry();
return new CompiledMethod(driver,
instruction_set,
managed_code,
frame_size,
main_jni_conv->CoreSpillMask(),
- main_jni_conv->FpSpillMask());
+ main_jni_conv->FpSpillMask(),
+ jni_asm->GetFrameDescriptionEntry());
}
// Copy a single parameter from the managed to the JNI calling convention
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index f72f5e5..4addfa0 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -499,6 +499,10 @@
// and branch to a ExceptionSlowPath if it is.
virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
+ virtual void InitializeFrameDescriptionEntry() {}
+ virtual void FinalizeFrameDescriptionEntry() {}
+ virtual std::vector<uint8_t>* GetFrameDescriptionEntry() { return nullptr; }
+
virtual ~Assembler() {}
protected:
diff --git a/compiler/utils/dwarf_cfi.cc b/compiler/utils/dwarf_cfi.cc
new file mode 100644
index 0000000..b3d1a47
--- /dev/null
+++ b/compiler/utils/dwarf_cfi.cc
@@ -0,0 +1,114 @@
+/*
+ * 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 "leb128.h"
+#include "utils.h"
+
+#include "dwarf_cfi.h"
+
+namespace art {
+
+void DW_CFA_advance_loc(std::vector<uint8_t>* buf, uint32_t increment) {
+ if (increment < 64) {
+ // Encoding in opcode.
+ buf->push_back(0x1 << 6 | increment);
+ } else if (increment < 256) {
+ // Single byte delta.
+ buf->push_back(0x02);
+ buf->push_back(increment);
+ } else if (increment < 256 * 256) {
+ // Two byte delta.
+ buf->push_back(0x03);
+ buf->push_back(increment & 0xff);
+ buf->push_back((increment >> 8) & 0xff);
+ } else {
+ // Four byte delta.
+ buf->push_back(0x04);
+ PushWord(buf, increment);
+ }
+}
+
+void DW_CFA_offset_extended_sf(std::vector<uint8_t>* buf, int reg, int32_t offset) {
+ buf->push_back(0x11);
+ EncodeUnsignedLeb128(reg, buf);
+ EncodeSignedLeb128(offset, buf);
+}
+
+void DW_CFA_offset(std::vector<uint8_t>* buf, int reg, uint32_t offset) {
+ buf->push_back((0x2 << 6) | reg);
+ EncodeUnsignedLeb128(offset, buf);
+}
+
+void DW_CFA_def_cfa_offset(std::vector<uint8_t>* buf, int32_t offset) {
+ buf->push_back(0x0e);
+ EncodeUnsignedLeb128(offset, buf);
+}
+
+void DW_CFA_remember_state(std::vector<uint8_t>* buf) {
+ buf->push_back(0x0a);
+}
+
+void DW_CFA_restore_state(std::vector<uint8_t>* buf) {
+ buf->push_back(0x0b);
+}
+
+void WriteFDEHeader(std::vector<uint8_t>* buf) {
+ // 'length' (filled in by other functions).
+ PushWord(buf, 0);
+
+ // 'CIE_pointer' (filled in by linker).
+ PushWord(buf, 0);
+
+ // 'initial_location' (filled in by linker).
+ PushWord(buf, 0);
+
+ // 'address_range' (filled in by other functions).
+ 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));
+
+ uint8_t *p = buf->data() + kOffsetOfAddressRange;
+ 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;
+ 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;
+}
+
+void PadCFI(std::vector<uint8_t>* buf) {
+ while (buf->size() & 0x3) {
+ buf->push_back(0);
+ }
+}
+
+} // namespace art
diff --git a/compiler/utils/dwarf_cfi.h b/compiler/utils/dwarf_cfi.h
new file mode 100644
index 0000000..e5acc0e
--- /dev/null
+++ b/compiler/utils/dwarf_cfi.h
@@ -0,0 +1,91 @@
+/*
+ * 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_COMPILER_UTILS_DWARF_CFI_H_
+#define ART_COMPILER_UTILS_DWARF_CFI_H_
+
+#include <vector>
+
+namespace art {
+
+/**
+ * @brief Enter a 'DW_CFA_advance_loc' into an FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+void DW_CFA_advance_loc(std::vector<uint8_t>* buf, uint32_t increment);
+
+/**
+ * @brief Enter a 'DW_CFA_offset_extended_sf' into an FDE buffer
+ * @param buf FDE buffer.
+ * @param reg Register number.
+ * @param offset Offset of register address from CFA.
+ */
+void DW_CFA_offset_extended_sf(std::vector<uint8_t>* buf, int reg, int32_t offset);
+
+/**
+ * @brief Enter a 'DW_CFA_offset' into an FDE buffer
+ * @param buf FDE buffer.
+ * @param reg Register number.
+ * @param offset Offset of register address from CFA.
+ */
+void DW_CFA_offset(std::vector<uint8_t>* buf, int reg, uint32_t offset);
+
+/**
+ * @brief Enter a 'DW_CFA_def_cfa_offset' into an FDE buffer
+ * @param buf FDE buffer.
+ * @param offset New offset of CFA.
+ */
+void DW_CFA_def_cfa_offset(std::vector<uint8_t>* buf, int32_t offset);
+
+/**
+ * @brief Enter a 'DW_CFA_remember_state' into an FDE buffer
+ * @param buf FDE buffer.
+ */
+void DW_CFA_remember_state(std::vector<uint8_t>* buf);
+
+/**
+ * @brief Enter a 'DW_CFA_restore_state' into an FDE buffer
+ * @param buf FDE buffer.
+ */
+void DW_CFA_restore_state(std::vector<uint8_t>* buf);
+
+/**
+ * @brief Write FDE header into an FDE buffer
+ * @param buf FDE buffer.
+ */
+void WriteFDEHeader(std::vector<uint8_t>* buf);
+
+/**
+ * @brief Set 'address_range' field of an FDE buffer
+ * @param buf FDE buffer.
+ */
+void WriteFDEAddressRange(std::vector<uint8_t>* buf, uint32_t data);
+
+/**
+ * @brief Set 'length' field of an FDE buffer
+ * @param buf FDE buffer.
+ */
+void WriteCFILength(std::vector<uint8_t>* buf);
+
+/**
+ * @brief Pad an FDE buffer with 0 until its size is a multiple of 4
+ * @param buf FDE buffer.
+ */
+void PadCFI(std::vector<uint8_t>* buf);
+} // namespace art
+
+#endif // ART_COMPILER_UTILS_DWARF_CFI_H_
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index b6a5c20..48edb15 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -20,6 +20,7 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "memory_region.h"
#include "thread.h"
+#include "utils/dwarf_cfi.h"
namespace art {
namespace x86 {
@@ -1407,20 +1408,61 @@
EmitOperand(reg_or_opcode, Operand(operand));
}
+void X86Assembler::InitializeFrameDescriptionEntry() {
+ WriteFDEHeader(&cfi_info_);
+}
+
+void X86Assembler::FinalizeFrameDescriptionEntry() {
+ WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+ PadCFI(&cfi_info_);
+ WriteCFILength(&cfi_info_);
+}
+
constexpr size_t kFramePointerSize = 4;
void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
const std::vector<ManagedRegister>& spill_regs,
const ManagedRegisterEntrySpills& entry_spills) {
+ cfi_cfa_offset_ = kFramePointerSize; // Only return address on stack
+ cfi_pc_ = buffer_.Size(); // Nothing emitted yet
+ DCHECK_EQ(cfi_pc_, 0U);
+
+ uint32_t reg_offset = 1;
CHECK_ALIGNED(frame_size, kStackAlignment);
for (int i = spill_regs.size() - 1; i >= 0; --i) {
pushl(spill_regs.at(i).AsX86().AsCpuRegister());
+
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += kFramePointerSize;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
+ // DW_CFA_offset reg offset
+ reg_offset++;
+ DW_CFA_offset(&cfi_info_, spill_regs.at(i).AsX86().DWARFRegId(), reg_offset);
}
+
// return address then method on stack
- addl(ESP, Immediate(-frame_size + (spill_regs.size() * kFramePointerSize) +
- sizeof(StackReference<mirror::ArtMethod>) /*method*/ +
- kFramePointerSize /*return address*/));
+ int32_t adjust = frame_size - (spill_regs.size() * kFramePointerSize) -
+ sizeof(StackReference<mirror::ArtMethod>) /*method*/ -
+ kFramePointerSize /*return address*/;
+ addl(ESP, Immediate(-adjust));
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += adjust;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
+
pushl(method_reg.AsX86().AsCpuRegister());
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += kFramePointerSize;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
+
for (size_t i = 0; i < entry_spills.size(); ++i) {
movl(Address(ESP, frame_size + sizeof(StackReference<mirror::ArtMethod>) +
(i * kFramePointerSize)),
@@ -1442,6 +1484,12 @@
void X86Assembler::IncreaseFrameSize(size_t adjust) {
CHECK_ALIGNED(adjust, kStackAlignment);
addl(ESP, Immediate(-adjust));
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += adjust;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
}
void X86Assembler::DecreaseFrameSize(size_t adjust) {
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index ce20768..5c4e34f 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -571,6 +571,12 @@
// and branch to a ExceptionSlowPath if it is.
void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
+ void InitializeFrameDescriptionEntry() OVERRIDE;
+ void FinalizeFrameDescriptionEntry() OVERRIDE;
+ std::vector<uint8_t>* GetFrameDescriptionEntry() OVERRIDE {
+ return &cfi_info_;
+ }
+
private:
inline void EmitUint8(uint8_t value);
inline void EmitInt32(int32_t value);
@@ -589,6 +595,9 @@
void EmitGenericShift(int rm, Register reg, const Immediate& imm);
void EmitGenericShift(int rm, Register operand, Register shifter);
+ std::vector<uint8_t> cfi_info_;
+ uint32_t cfi_cfa_offset_, cfi_pc_;
+
DISALLOW_COPY_AND_ASSIGN(X86Assembler);
};
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index 09d2b49..5d46ee2 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -88,6 +88,14 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class X86ManagedRegister : public ManagedRegister {
public:
+ int DWARFRegId() const {
+ CHECK(IsCpuRegister());
+ // For all the X86 registers we care about:
+ // EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
+ // DWARF register id is the same as id_.
+ return static_cast<int>(id_);
+ }
+
ByteRegister AsByteRegister() const {
CHECK(IsCpuRegister());
CHECK_LT(AsCpuRegister(), ESP); // ESP, EBP, ESI and EDI cannot be encoded as byte registers.
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 7684271..62b72c2 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -20,6 +20,7 @@
#include "entrypoints/quick/quick_entrypoints.h"
#include "memory_region.h"
#include "thread.h"
+#include "utils/dwarf_cfi.h"
namespace art {
namespace x86_64 {
@@ -1714,11 +1715,26 @@
}
}
+void X86_64Assembler::InitializeFrameDescriptionEntry() {
+ WriteFDEHeader(&cfi_info_);
+}
+
+void X86_64Assembler::FinalizeFrameDescriptionEntry() {
+ WriteFDEAddressRange(&cfi_info_, buffer_.Size());
+ PadCFI(&cfi_info_);
+ WriteCFILength(&cfi_info_);
+}
+
constexpr size_t kFramePointerSize = 8;
void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg,
const std::vector<ManagedRegister>& spill_regs,
const ManagedRegisterEntrySpills& entry_spills) {
+ cfi_cfa_offset_ = kFramePointerSize; // Only return address on stack
+ cfi_pc_ = buffer_.Size(); // Nothing emitted yet
+ DCHECK_EQ(cfi_pc_, 0U);
+
+ uint32_t reg_offset = 1;
CHECK_ALIGNED(frame_size, kStackAlignment);
int gpr_count = 0;
for (int i = spill_regs.size() - 1; i >= 0; --i) {
@@ -1726,6 +1742,16 @@
if (spill.IsCpuRegister()) {
pushq(spill.AsCpuRegister());
gpr_count++;
+
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += kFramePointerSize;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
+ // DW_CFA_offset reg offset
+ reg_offset++;
+ DW_CFA_offset(&cfi_info_, spill.DWARFRegId(), reg_offset);
}
}
// return address then method on stack
@@ -1733,6 +1759,13 @@
- (gpr_count * kFramePointerSize)
- kFramePointerSize /*return address*/;
subq(CpuRegister(RSP), Immediate(rest_of_frame));
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += rest_of_frame;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
+
// spill xmms
int64_t offset = rest_of_frame;
for (int i = spill_regs.size() - 1; i >= 0; --i) {
@@ -1796,6 +1829,12 @@
void X86_64Assembler::IncreaseFrameSize(size_t adjust) {
CHECK_ALIGNED(adjust, kStackAlignment);
addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust)));
+ // DW_CFA_advance_loc
+ DW_CFA_advance_loc(&cfi_info_, buffer_.Size() - cfi_pc_);
+ cfi_pc_ = buffer_.Size();
+ // DW_CFA_def_cfa_offset
+ cfi_cfa_offset_ += adjust;
+ DW_CFA_def_cfa_offset(&cfi_info_, cfi_cfa_offset_);
}
void X86_64Assembler::DecreaseFrameSize(size_t adjust) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 2f814df..ee11575 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -614,6 +614,12 @@
// and branch to a ExceptionSlowPath if it is.
void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE;
+ void InitializeFrameDescriptionEntry() OVERRIDE;
+ void FinalizeFrameDescriptionEntry() OVERRIDE;
+ std::vector<uint8_t>* GetFrameDescriptionEntry() OVERRIDE {
+ return &cfi_info_;
+ }
+
private:
void EmitUint8(uint8_t value);
void EmitInt32(int32_t value);
@@ -655,6 +661,9 @@
void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, CpuRegister src);
void EmitOptionalByteRegNormalizingRex32(CpuRegister dst, const Operand& operand);
+ std::vector<uint8_t> cfi_info_;
+ uint32_t cfi_cfa_offset_, cfi_pc_;
+
DISALLOW_COPY_AND_ASSIGN(X86_64Assembler);
};
diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h
index 822659f..3a96ad0 100644
--- a/compiler/utils/x86_64/managed_register_x86_64.h
+++ b/compiler/utils/x86_64/managed_register_x86_64.h
@@ -87,6 +87,21 @@
// There is a one-to-one mapping between ManagedRegister and register id.
class X86_64ManagedRegister : public ManagedRegister {
public:
+ int DWARFRegId() const {
+ CHECK(IsCpuRegister());
+ switch (id_) {
+ case RAX: return 0;
+ case RDX: return 1;
+ case RCX: return 2;
+ case RBX: return 3;
+ case RSI: return 4;
+ case RDI: return 5;
+ case RBP: return 6;
+ case RSP: return 7;
+ default: return static_cast<int>(id_); // R8 ~ R15
+ }
+ }
+
CpuRegister AsCpuRegister() const {
CHECK(IsCpuRegister());
return CpuRegister(static_cast<Register>(id_));
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 4d49809..f966fbd 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1354,4 +1354,29 @@
return true;
}
+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);
+}
+
+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);
+}
+
+void PushWord(std::vector<uint8_t>* buf, int data) {
+ buf->push_back(data & 0xff);
+ buf->push_back((data >> 8) & 0xff);
+ buf->push_back((data >> 16) & 0xff);
+ buf->push_back((data >> 24) & 0xff);
+}
+
} // namespace art
diff --git a/runtime/utils.h b/runtime/utils.h
index 73872d3..49bcbf9 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -497,6 +497,11 @@
}
};
+void PushWord(std::vector<uint8_t>* buf, int32_t data);
+
+void EncodeUnsignedLeb128(uint32_t data, std::vector<uint8_t>* buf);
+void EncodeSignedLeb128(int32_t data, std::vector<uint8_t>* buf);
+
} // namespace art
#endif // ART_RUNTIME_UTILS_H_