+// See DWARF standard v3, section 7.23
+const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
+const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
+
+void FrameEntry::parseInstructions(DataExtractor Data, uint32_t *Offset,
+ uint32_t EndOffset) {
+ while (*Offset < EndOffset) {
+ uint8_t Opcode = Data.getU8(Offset);
+ // Some instructions have a primary opcode encoded in the top bits.
+ uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK;
+
+ if (Primary) {
+ // If it's a primary opcode, the first operand is encoded in the bottom
+ // bits of the opcode itself.
+ uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
+ switch (Primary) {
+ default: llvm_unreachable("Impossible primary CFI opcode");
+ case DW_CFA_advance_loc:
+ case DW_CFA_restore:
+ addInstruction(Primary, Op1);
+ break;
+ case DW_CFA_offset:
+ addInstruction(Primary, Op1, Data.getULEB128(Offset));
+ break;
+ }
+ } else {
+ // Extended opcode - its value is Opcode itself.
+ switch (Opcode) {
+ default: llvm_unreachable("Invalid extended CFI opcode");
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ // No operands
+ addInstruction(Opcode);
+ break;
+ case DW_CFA_set_loc:
+ // Operands: Address
+ addInstruction(Opcode, Data.getAddress(Offset));
+ break;
+ case DW_CFA_advance_loc1:
+ // Operands: 1-byte delta
+ addInstruction(Opcode, Data.getU8(Offset));
+ break;
+ case DW_CFA_advance_loc2:
+ // Operands: 2-byte delta
+ addInstruction(Opcode, Data.getU16(Offset));
+ break;
+ case DW_CFA_advance_loc4:
+ // Operands: 4-byte delta
+ addInstruction(Opcode, Data.getU32(Offset));
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ // Operands: ULEB128
+ addInstruction(Opcode, Data.getULEB128(Offset));
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ // Operands: SLEB128
+ addInstruction(Opcode, Data.getSLEB128(Offset));
+ break;
+ case DW_CFA_offset_extended:
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ case DW_CFA_val_offset:
+ // Operands: ULEB128, ULEB128
+ addInstruction(Opcode, Data.getULEB128(Offset),
+ Data.getULEB128(Offset));
+ break;
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_val_offset_sf:
+ // Operands: ULEB128, SLEB128
+ addInstruction(Opcode, Data.getULEB128(Offset),
+ Data.getSLEB128(Offset));
+ break;
+ case DW_CFA_def_cfa_expression:
+ case DW_CFA_expression:
+ case DW_CFA_val_expression:
+ // TODO: implement this
+ report_fatal_error("Values with expressions not implemented yet!");
+ }
+ }
+ }
+}
+
+
+void FrameEntry::dumpInstructions(raw_ostream &OS) const {
+ // TODO: at the moment only instruction names are dumped. Expand this to
+ // dump operands as well.
+ for (const auto &Instr : Instructions) {
+ uint8_t Opcode = Instr.Opcode;
+ if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
+ Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
+ OS << " " << CallFrameString(Opcode) << ":\n";
+ }
+}
+
+
+namespace {
+/// \brief DWARF Common Information Entry (CIE)