// Binary search table is not useful if the number of entries is small. // In particular, this avoids it for the in-memory JIT mini-debug-info. static constexpr size_t kMinDebugFrameHdrEntries = 100;
staticvoid WriteCIE(InstructionSet isa, /*inout*/ std::vector<uint8_t>* buffer) { using Reg = dwarf::Reg; // Scratch registers should be marked as undefined. This tells the // debugger that its value in the previous frame is not recoverable. bool is64bit = Is64BitInstructionSet(isa); switch (isa) { case InstructionSet::kArm: case InstructionSet::kThumb2: {
dwarf::DebugFrameOpCodeWriter<> opcodes;
opcodes.DefCFA(Reg::ArmCore(13), 0); // R13(SP). // core registers. for (int reg = 0; reg < 13; reg++) { if (reg < 4 || reg == 12) {
opcodes.Undefined(Reg::ArmCore(reg));
} else {
opcodes.SameValue(Reg::ArmCore(reg));
}
} // fp registers. for (int reg = 0; reg < 32; reg++) { if (reg < 16) {
opcodes.Undefined(Reg::ArmFp(reg));
} else {
opcodes.SameValue(Reg::ArmFp(reg));
}
} auto return_reg = Reg::ArmCore(14); // R14(LR).
WriteCIE(is64bit, return_reg, opcodes, buffer); return;
} case InstructionSet::kArm64: {
dwarf::DebugFrameOpCodeWriter<> opcodes;
opcodes.DefCFA(Reg::Arm64Core(31), 0); // R31(SP). // core registers. for (int reg = 0; reg < 30; reg++) { if (reg < 8 || reg == 16 || reg == 17) {
opcodes.Undefined(Reg::Arm64Core(reg));
} else {
opcodes.SameValue(Reg::Arm64Core(reg));
}
} // fp registers. for (int reg = 0; reg < 32; reg++) { if (reg < 8 || reg >= 16) {
opcodes.Undefined(Reg::Arm64Fp(reg));
} else {
opcodes.SameValue(Reg::Arm64Fp(reg));
}
} auto return_reg = Reg::Arm64Core(30); // R30(LR).
WriteCIE(is64bit, return_reg, opcodes, buffer); return;
} case InstructionSet::kRiscv64: {
dwarf::DebugFrameOpCodeWriter<> opcodes;
opcodes.DefCFA(Reg::Riscv64Core(2), 0); // X2(SP). // core registers. for (int reg = 3; reg < 32; reg++) { // Skip X0 (Zero), X1 (RA) and X2 (SP). if ((reg >= 5 && reg < 8) || (reg >= 10 && reg < 18) || reg >= 28) {
opcodes.Undefined(Reg::Riscv64Core(reg));
} else {
opcodes.SameValue(Reg::Riscv64Core(reg));
}
} // fp registers. for (int reg = 0; reg < 32; reg++) { if (reg < 8 || (reg >=10 && reg < 18) || reg >= 28) {
opcodes.Undefined(Reg::Riscv64Fp(reg));
} else {
opcodes.SameValue(Reg::Riscv64Fp(reg));
}
} auto return_reg = Reg::Riscv64Core(1); // X1(RA).
WriteCIE(is64bit, return_reg, opcodes, buffer); return;
} case InstructionSet::kX86: { // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
constexpr bool generate_opcodes_for_x86_fp = false;
dwarf::DebugFrameOpCodeWriter<> opcodes;
opcodes.DefCFA(Reg::X86Core(4), 4); // R4(ESP).
opcodes.Offset(Reg::X86Core(8), -4); // R8(EIP). // core registers. for (int reg = 0; reg < 8; reg++) { if (reg <= 3) {
opcodes.Undefined(Reg::X86Core(reg));
} elseif (reg == 4) { // Stack pointer.
} else {
opcodes.SameValue(Reg::X86Core(reg));
}
} // fp registers. if (generate_opcodes_for_x86_fp) { for (int reg = 0; reg < 8; reg++) {
opcodes.Undefined(Reg::X86Fp(reg));
}
} auto return_reg = Reg::X86Core(8); // R8(EIP).
WriteCIE(is64bit, return_reg, opcodes, buffer); return;
} case InstructionSet::kX86_64: {
dwarf::DebugFrameOpCodeWriter<> opcodes;
opcodes.DefCFA(Reg::X86_64Core(4), 8); // R4(RSP).
opcodes.Offset(Reg::X86_64Core(16), -8); // R16(RIP). // core registers. for (int reg = 0; reg < 16; reg++) { if (reg == 4) { // Stack pointer.
} elseif (reg < 12 && reg != 3 && reg != 5) { // except EBX and EBP.
opcodes.Undefined(Reg::X86_64Core(reg));
} else {
opcodes.SameValue(Reg::X86_64Core(reg));
}
} // fp registers. for (int reg = 0; reg < 16; reg++) { if (reg < 12) {
opcodes.Undefined(Reg::X86_64Fp(reg));
} else {
opcodes.SameValue(Reg::X86_64Fp(reg));
}
} auto return_reg = Reg::X86_64Core(16); // R16(RIP).
WriteCIE(is64bit, return_reg, opcodes, buffer); return;
} case InstructionSet::kNone: break;
}
LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
UNREACHABLE();
}
template<typename ElfTypes> void WriteCFISection(ElfBuilder<ElfTypes>* builder, const ArrayRef<const MethodDebugInfo>& method_infos) { // The methods can be written in any order. // Let's therefore sort them in the lexicographical order of the opcodes. // This has no effect on its own. However, if the final .debug_frame section is // compressed it reduces the size since similar opcodes sequences are grouped.
std::vector<const MethodDebugInfo*> sorted_method_infos;
sorted_method_infos.reserve(method_infos.size()); for (size_t i = 0; i < method_infos.size(); i++) { if (!method_infos[i].cfi.empty() && !method_infos[i].deduped) {
sorted_method_infos.push_back(&method_infos[i]);
}
} if (sorted_method_infos.empty()) { return;
}
std::stable_sort(
sorted_method_infos.begin(),
sorted_method_infos.end(),
[](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
ArrayRef<const uint8_t> l = lhs->cfi;
ArrayRef<const uint8_t> r = rhs->cfi; return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
});
if (binary_search_table_is_valid && method_infos.size() >= kMinDebugFrameHdrEntries) {
std::sort(binary_search_table.begin(), binary_search_table.end());
// Custom Android section. It is very similar to the official .eh_frame_hdr format.
std::vector<uint8_t> header_buffer;
dwarf::Writer<> header(&header_buffer);
header.PushUint8(1); // Version.
header.PushUint8(dwarf::DW_EH_PE_omit); // Encoding of .eh_frame pointer - none.
header.PushUint8(dwarf::DW_EH_PE_udata4); // Encoding of binary search table size.
header.PushUint8(dwarf::DW_EH_PE_udata4); // Encoding of binary search table data.
header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.