// Writer for .debug_frame opcodes (DWARF-3). // See the DWARF specification for the precise meaning of the opcodes. // The writer is very light-weight, however it will do the following for you: // * Choose the most compact encoding of a given opcode. // * Keep track of current state and convert absolute values to deltas. // * Divide by header-defined factors as appropriate. template<typename Vector = std::vector<uint8_t> > class DebugFrameOpCodeWriter : private Writer<Vector> {
static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type");
public: // To save space, DWARF divides most offsets by header-defined factors. // They are used in integer divisions, so we make them constants. // We usually subtract from stack base pointer, so making the factor // negative makes the encoded values positive and thus easier to encode. static constexpr int kDataAlignmentFactor = -4; static constexpr int kCodeAlignmentFactor = 1;
// Explicitely advance the program counter to given location. void ALWAYS_INLINE AdvancePC(int absolute_pc) {
DCHECK_GE(absolute_pc, current_pc_); if (UNLIKELY(enabled_)) { int delta = FactorCodeOffset(absolute_pc - current_pc_); if (delta != 0) { if (delta <= 0x3F) { this->PushUint8(DW_CFA_advance_loc | delta);
} elseif (delta <= UINT8_MAX) { this->PushUint8(DW_CFA_advance_loc1); this->PushUint8(delta);
} elseif (delta <= UINT16_MAX) { this->PushUint8(DW_CFA_advance_loc2); this->PushUint16(delta);
} else { this->PushUint8(DW_CFA_advance_loc4); this->PushUint32(delta);
}
}
current_pc_ = absolute_pc;
}
}
// Override this method to automatically advance the PC before each opcode. virtualvoid ImplicitlyAdvancePC() { }
// Common alias in assemblers - spill relative to current stack pointer. void ALWAYS_INLINE RelOffset(Reg reg, int offset) {
Offset(reg, offset - current_cfa_offset_);
}
// Common alias in assemblers - increase stack frame size. void ALWAYS_INLINE AdjustCFAOffset(int delta) {
DefCFAOffset(current_cfa_offset_ + delta);
}
// Custom alias - spill many registers based on bitmask. void ALWAYS_INLINE RelOffsetForMany(Reg reg_base,
int32_t offset,
uint32_t reg_mask,
int32_t reg_size) {
DCHECK(reg_size == 4 || reg_size == 8); if (UNLIKELY(enabled_)) { for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) { // Skip zero bits and go to the set bit. int num_zeros = CTZ(reg_mask);
i += num_zeros;
reg_mask >>= num_zeros;
RelOffset(Reg(reg_base.num() + i), offset);
offset += reg_size;
}
}
}
// Custom alias - unspill many registers based on bitmask. void ALWAYS_INLINE RestoreMany(Reg reg_base, uint32_t reg_mask) { if (UNLIKELY(enabled_)) { for (int i = 0; reg_mask != 0u; reg_mask >>= 1, i++) { // Skip zero bits and go to the set bit. int num_zeros = CTZ(reg_mask);
i += num_zeros;
reg_mask >>= num_zeros;
Restore(Reg(reg_base.num() + i));
}
}
}
void ALWAYS_INLINE Nop() { if (UNLIKELY(enabled_)) { this->PushUint8(DW_CFA_nop);
}
}
void ALWAYS_INLINE Offset(Reg reg, int offset) { if (UNLIKELY(enabled_)) {
ImplicitlyAdvancePC(); int factored_offset = FactorDataOffset(offset); // May change sign. if (factored_offset >= 0) { if (0 <= reg.num() && reg.num() <= 0x3F) { this->PushUint8(DW_CFA_offset | reg.num()); this->PushUleb128(factored_offset);
} else { this->PushUint8(DW_CFA_offset_extended); this->PushUleb128(reg.num()); this->PushUleb128(factored_offset);
}
} else {
uses_dwarf3_features_ = true; this->PushUint8(DW_CFA_offset_extended_sf); this->PushUleb128(reg.num()); this->PushSleb128(factored_offset);
}
}
}
// The previous value of "reg" is stored in register "new_reg". void ALWAYS_INLINE Register(Reg reg, Reg new_reg) { if (UNLIKELY(enabled_)) {
ImplicitlyAdvancePC(); this->PushUint8(DW_CFA_register); this->PushUleb128(reg.num()); this->PushUleb128(new_reg.num());
}
}
void ALWAYS_INLINE DefCFAOffset(int offset) { if (UNLIKELY(enabled_)) { if (current_cfa_offset_ != offset) {
ImplicitlyAdvancePC(); if (offset >= 0) { this->PushUint8(DW_CFA_def_cfa_offset); this->PushUleb128(offset); // Non-factored.
} else {
uses_dwarf3_features_ = true; this->PushUint8(DW_CFA_def_cfa_offset_sf); this->PushSleb128(FactorDataOffset(offset));
}
}
} // Uncoditional so that the user can still get and check the value.
current_cfa_offset_ = offset;
}
void ALWAYS_INLINE ValOffset(Reg reg, int offset) { if (UNLIKELY(enabled_)) {
ImplicitlyAdvancePC();
uses_dwarf3_features_ = true; int factored_offset = FactorDataOffset(offset); // May change sign. if (factored_offset >= 0) { this->PushUint8(DW_CFA_val_offset); this->PushUleb128(reg.num()); this->PushUleb128(factored_offset);
} else { this->PushUint8(DW_CFA_val_offset_sf); this->PushUleb128(reg.num()); this->PushSleb128(factored_offset);
}
}
}
void ALWAYS_INLINE DefCFAExpression(uint8_t* expr, int expr_size) { if (UNLIKELY(enabled_)) {
ImplicitlyAdvancePC();
uses_dwarf3_features_ = true; this->PushUint8(DW_CFA_def_cfa_expression); this->PushUleb128(expr_size); this->PushData(expr, expr_size);
}
}
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.