summaryrefslogtreecommitdiff
path: root/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp')
-rw-r--r--llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp683
1 files changed, 659 insertions, 24 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
index b74ecac681f3..92a461dbd941 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -24,8 +24,6 @@
#include <cassert>
#include <cinttypes>
#include <cstdint>
-#include <string>
-#include <vector>
using namespace llvm;
using namespace dwarf;
@@ -43,6 +41,211 @@ static void printRegister(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
OS << "reg" << RegNum;
}
+UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }
+
+UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
+
+UnwindLocation UnwindLocation::createSame() { return {Same}; }
+
+UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
+ return {Constant, InvalidRegisterNumber, Value, None, false};
+}
+
+UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, false};
+}
+
+UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, true};
+}
+
+UnwindLocation
+UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
+}
+
+UnwindLocation
+UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
+}
+
+UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
+ return {Expr, false};
+}
+
+UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {
+ return {Expr, true};
+}
+
+void UnwindLocation::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ if (Dereference)
+ OS << '[';
+ switch (Kind) {
+ case Unspecified:
+ OS << "unspecified";
+ break;
+ case Undefined:
+ OS << "undefined";
+ break;
+ case Same:
+ OS << "same";
+ break;
+ case CFAPlusOffset:
+ OS << "CFA";
+ if (Offset == 0)
+ break;
+ if (Offset > 0)
+ OS << "+";
+ OS << Offset;
+ break;
+ case RegPlusOffset:
+ printRegister(OS, MRI, IsEH, RegNum);
+ if (Offset == 0 && !AddrSpace)
+ break;
+ if (Offset >= 0)
+ OS << "+";
+ OS << Offset;
+ if (AddrSpace)
+ OS << " in addrspace" << *AddrSpace;
+ break;
+ case DWARFExpr:
+ Expr->print(OS, DIDumpOptions(), MRI, nullptr, IsEH);
+ break;
+ case Constant:
+ OS << Offset;
+ break;
+ }
+ if (Dereference)
+ OS << ']';
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const UnwindLocation &UL) {
+ UL.dump(OS, nullptr, false);
+ return OS;
+}
+
+bool UnwindLocation::operator==(const UnwindLocation &RHS) const {
+ if (Kind != RHS.Kind)
+ return false;
+ switch (Kind) {
+ case Unspecified:
+ case Undefined:
+ case Same:
+ return true;
+ case CFAPlusOffset:
+ return Offset == RHS.Offset && Dereference == RHS.Dereference;
+ case RegPlusOffset:
+ return RegNum == RHS.RegNum && Offset == RHS.Offset &&
+ Dereference == RHS.Dereference;
+ case DWARFExpr:
+ return *Expr == *RHS.Expr && Dereference == RHS.Dereference;
+ case Constant:
+ return Offset == RHS.Offset;
+ }
+ return false;
+}
+
+void RegisterLocations::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ bool First = true;
+ for (const auto &RegLocPair : Locations) {
+ if (First)
+ First = false;
+ else
+ OS << ", ";
+ printRegister(OS, MRI, IsEH, RegLocPair.first);
+ OS << '=';
+ RegLocPair.second.dump(OS, MRI, IsEH);
+ }
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const RegisterLocations &RL) {
+ RL.dump(OS, nullptr, false);
+ return OS;
+}
+
+void UnwindRow::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ OS.indent(2 * IndentLevel);
+ if (hasAddress())
+ OS << format("0x%" PRIx64 ": ", *Address);
+ OS << "CFA=";
+ CFAValue.dump(OS, MRI, IsEH);
+ if (RegLocs.hasLocations()) {
+ OS << ": ";
+ RegLocs.dump(OS, MRI, IsEH);
+ }
+ OS << "\n";
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
+ Row.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+void UnwindTable::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ for (const UnwindRow &Row : Rows)
+ Row.dump(OS, MRI, IsEH, IndentLevel);
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
+ Rows.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+Expected<UnwindTable> UnwindTable::create(const FDE *Fde) {
+ const CIE *Cie = Fde->getLinkedCIE();
+ if (Cie == nullptr)
+ return createStringError(errc::invalid_argument,
+ "unable to get CIE for FDE at offset 0x%" PRIx64,
+ Fde->getOffset());
+
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty() && Fde->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ Row.setAddress(Fde->getInitialLocation());
+ UT.EndAddress = Fde->getInitialLocation() + Fde->getAddressRange();
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // We need to save the initial locations of registers from the CIE parsing
+ // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
+ const RegisterLocations InitialLocs = Row.getRegisterLocations();
+ if (Error FdeError = UT.parseRows(Fde->cfis(), Row, &InitialLocs))
+ return std::move(FdeError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
+Expected<UnwindTable> UnwindTable::create(const CIE *Cie) {
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
// 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;
@@ -115,6 +318,16 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
// Operands: SLEB128
addInstruction(Opcode, Data.getSLEB128(C));
break;
+ case DW_CFA_LLVM_def_aspace_cfa:
+ case DW_CFA_LLVM_def_aspace_cfa_sf: {
+ auto RegNum = Data.getULEB128(C);
+ auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa
+ ? Data.getULEB128(C)
+ : Data.getSLEB128(C);
+ auto AddressSpace = Data.getULEB128(C);
+ addInstruction(Opcode, RegNum, CfaOffset, AddressSpace);
+ break;
+ }
case DW_CFA_offset_extended:
case DW_CFA_register:
case DW_CFA_def_cfa:
@@ -175,24 +388,424 @@ Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
return C.takeError();
}
-namespace {
+StringRef CFIProgram::callFrameString(unsigned Opcode) const {
+ return dwarf::CallFrameString(Opcode, Arch);
+}
+
+const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) {
+#define ENUM_TO_CSTR(e) \
+ case e: \
+ return #e;
+ switch (OT) {
+ ENUM_TO_CSTR(OT_Unset);
+ ENUM_TO_CSTR(OT_None);
+ ENUM_TO_CSTR(OT_Address);
+ ENUM_TO_CSTR(OT_Offset);
+ ENUM_TO_CSTR(OT_FactoredCodeOffset);
+ ENUM_TO_CSTR(OT_SignedFactDataOffset);
+ ENUM_TO_CSTR(OT_UnsignedFactDataOffset);
+ ENUM_TO_CSTR(OT_Register);
+ ENUM_TO_CSTR(OT_AddressSpace);
+ ENUM_TO_CSTR(OT_Expression);
+ }
+ return "<unknown CFIProgram::OperandType>";
+}
+
+llvm::Expected<uint64_t>
+CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ case OT_SignedFactDataOffset:
+ case OT_UnsignedFactDataOffset:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed "
+ "result, call getOperandAsSigned instead",
+ OperandIdx);
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return Operand;
+
+ case OT_FactoredCodeOffset: {
+ const uint64_t CodeAlignmentFactor = CFIP.codeAlign();
+ if (CodeAlignmentFactor == 0)
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment "
+ "is zero",
+ OperandIdx);
+ return Operand * CodeAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+llvm::Expected<int64_t>
+CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, "
+ "call getOperandAsUnsigned instead",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ return (int64_t)Operand;
+
+ case OT_FactoredCodeOffset:
+ case OT_SignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s but data "
+ "alignment is zero",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+ return int64_t(Operand) * DataAlignmentFactor;
+ }
+
+ case OT_UnsignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32
+ "] has type OT_UnsignedFactDataOffset but data "
+ "alignment is zero",
+ OperandIdx);
+ return Operand * DataAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
+ const RegisterLocations *InitialLocs) {
+ std::vector<RegisterLocations> RegisterStates;
+ for (const CFIProgram::Instruction &Inst : CFIP) {
+ switch (Inst.Opcode) {
+ case dwarf::DW_CFA_set_loc: {
+ // The DW_CFA_set_loc instruction takes a single operand that
+ // represents a target address. The required action is to create a new
+ // table row using the specified address as the location. All other
+ // values in the new row are initially identical to the current row.
+ // The new location value is always greater than the current one. If
+ // the segment_size field of this FDE's CIE is non- zero, the initial
+ // location is preceded by a segment selector of the given length
+ llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!NewAddress)
+ return NewAddress.takeError();
+ if (*NewAddress <= Row.getAddress())
+ return createStringError(
+ errc::invalid_argument,
+ "%s with adrress 0x%" PRIx64 " which must be greater than the "
+ "current row address 0x%" PRIx64,
+ CFIP.callFrameString(Inst.Opcode).str().c_str(), *NewAddress,
+ Row.getAddress());
+ Rows.push_back(Row);
+ Row.setAddress(*NewAddress);
+ break;
+ }
+
+ case dwarf::DW_CFA_advance_loc:
+ case dwarf::DW_CFA_advance_loc1:
+ case dwarf::DW_CFA_advance_loc2:
+ case dwarf::DW_CFA_advance_loc4: {
+ // The DW_CFA_advance instruction takes a single operand that
+ // represents a constant delta. The required action is to create a new
+ // table row with a location value that is computed by taking the
+ // current entry’s location value and adding the value of delta *
+ // code_alignment_factor. All other values in the new row are initially
+ // identical to the current row.
+ Rows.push_back(Row);
+ llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ Row.slideAddress(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_restore:
+ case dwarf::DW_CFA_restore_extended: {
+ // The DW_CFA_restore instruction takes a single operand (encoded with
+ // the opcode) that represents a register number. The required action
+ // is to change the rule for the indicated register to the rule
+ // assigned it by the initial_instructions in the CIE.
+ if (InitialLocs == nullptr)
+ return createStringError(
+ errc::invalid_argument, "%s encountered while parsing a CIE",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Optional<UnwindLocation> O =
+ InitialLocs->getRegisterLocation(*RegNum))
+ Row.getRegisterLocations().setRegisterLocation(*RegNum, *O);
+ else
+ Row.getRegisterLocations().removeRegisterLocation(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_offset:
+ case dwarf::DW_CFA_offset_extended:
+ case dwarf::DW_CFA_offset_extended_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_nop:
+ break;
+
+ case dwarf::DW_CFA_remember_state:
+ RegisterStates.push_back(Row.getRegisterLocations());
+ break;
+
+ case dwarf::DW_CFA_restore_state:
+ if (RegisterStates.empty())
+ return createStringError(errc::invalid_argument,
+ "DW_CFA_restore_state without a matching "
+ "previous DW_CFA_remember_state");
+ Row.getRegisterLocations() = RegisterStates.back();
+ RegisterStates.pop_back();
+ break;
+
+ case dwarf::DW_CFA_GNU_window_save:
+ switch (CFIP.triple()) {
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ case Triple::aarch64_32: {
+ // DW_CFA_GNU_window_save is used for different things on different
+ // architectures. For aarch64 it is known as
+ // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the
+ // value of the return address state between 1 and 0. If there is
+ // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it
+ // should be initially set to 1.
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 1);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(1));
+ }
+ break;
+ }
+
+ case Triple::sparc:
+ case Triple::sparcv9:
+ case Triple::sparcel:
+ for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {
+ Row.getRegisterLocations().setRegisterLocation(
+ RegNum, UnwindLocation::createAtCFAPlusOffset((RegNum - 16) * 8));
+ }
+ break;
+ default: {
+ return createStringError(
+ errc::not_supported,
+ "DW_CFA opcode %#x is not supported for architecture %s",
+ Inst.Opcode, Triple::getArchTypeName(CFIP.triple()).str().c_str());
-} // end anonymous namespace
+ break;
+ }
+ }
+ break;
-ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
- static OperandType OpTypes[DW_CFA_restore+1][2];
+ case dwarf::DW_CFA_undefined: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createUndefined());
+ break;
+ }
+
+ case dwarf::DW_CFA_same_value: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createSame());
+ break;
+ }
+
+ case dwarf::DW_CFA_GNU_args_size:
+ break;
+
+ case dwarf::DW_CFA_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, 1);
+ if (!NewRegNum)
+ return NewRegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsRegisterPlusOffset(*NewRegNum, 0));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_offset:
+ case dwarf::DW_CFA_val_offset_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, 0);
+ else
+ Row.getCFAValue().setRegister(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_offset:
+ case dwarf::DW_CFA_def_cfa_offset_sf: {
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {
+ return createStringError(
+ errc::invalid_argument,
+ "%s found when CFA rule was not RegPlusOffset",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ Row.getCFAValue().setOffset(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa:
+ case dwarf::DW_CFA_def_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, *Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa:
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ llvm::Expected<uint32_t> CFAAddrSpace =
+ Inst.getOperandAsUnsigned(CFIP, 2);
+ if (!CFAAddrSpace)
+ return CFAAddrSpace.takeError();
+ Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
+ *RegNum, *Offset, *CFAAddrSpace);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_expression:
+ Row.getCFAValue() =
+ UnwindLocation::createIsDWARFExpression(*Inst.Expression);
+ break;
+ }
+ }
+ return Error::success();
+}
+
+ArrayRef<CFIProgram::OperandType[CFIProgram::MaxOperands]>
+CFIProgram::getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
static bool Initialized = false;
if (Initialized) {
- return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
}
Initialized = true;
-#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
- do { \
- OpTypes[OP][0] = OPTYPE0; \
- OpTypes[OP][1] = OPTYPE1; \
+#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \
+ do { \
+ OpTypes[OP][0] = OPTYPE0; \
+ OpTypes[OP][1] = OPTYPE1; \
+ OpTypes[OP][2] = OPTYPE2; \
} while (false)
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
+ DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None)
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
@@ -205,6 +818,10 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset,
+ OT_AddressSpace);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register,
+ OT_SignedFactDataOffset, OT_AddressSpace);
DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
@@ -230,7 +847,7 @@ ArrayRef<CFIProgram::OperandType[2]> CFIProgram::getOperandTypes() {
#undef DECLARE_OP1
#undef DECLARE_OP2
- return ArrayRef<OperandType[2]>(&OpTypes[0], DW_CFA_restore+1);
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
}
/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
@@ -238,14 +855,14 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const MCRegisterInfo *MRI, bool IsEH,
const Instruction &Instr, unsigned OperandIdx,
uint64_t Operand) const {
- assert(OperandIdx < 2);
+ assert(OperandIdx < MaxOperands);
uint8_t Opcode = Instr.Opcode;
OperandType Type = getOperandTypes()[Opcode][OperandIdx];
switch (Type) {
case OT_Unset: {
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
- auto OpcodeName = CallFrameString(Opcode, Arch);
+ auto OpcodeName = callFrameString(Opcode);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
@@ -285,6 +902,9 @@ void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << ' ';
printRegister(OS, MRI, IsEH, Operand);
break;
+ case OT_AddressSpace:
+ OS << format(" in addrspace%" PRId64, Operand);
+ break;
case OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
@@ -298,10 +918,8 @@ void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned IndentLevel) const {
for (const auto &Instr : Instructions) {
uint8_t Opcode = Instr.Opcode;
- if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
- Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
OS.indent(2 * IndentLevel);
- OS << CallFrameString(Opcode, Arch) << ":";
+ OS << callFrameString(Opcode) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, DumpOpts, MRI, IsEH, Instr, i, Instr.Ops[i]);
OS << '\n';
@@ -333,8 +951,10 @@ void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
<< format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8,
getCIEId(IsDWARF64, IsEH))
<< " CIE\n"
- << " Format: " << FormatString(IsDWARF64) << "\n"
- << format(" Version: %d\n", Version)
+ << " Format: " << FormatString(IsDWARF64) << "\n";
+ if (IsEH && Version != 1)
+ OS << "WARNING: unsupported CIE version\n";
+ OS << format(" Version: %d\n", Version)
<< " Augmentation: \"" << Augmentation << "\"\n";
if (Version >= 4) {
OS << format(" Address size: %u\n", (uint32_t)AddressSize);
@@ -355,6 +975,16 @@ void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << "\n";
CFIs.dump(OS, DumpOpts, MRI, IsEH);
OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the CIE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
}
void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
@@ -374,6 +1004,16 @@ void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
CFIs.dump(OS, DumpOpts, MRI, IsEH);
OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the FDE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
}
DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
@@ -434,11 +1074,6 @@ Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
uint8_t Version = Data.getU8(&Offset);
const char *Augmentation = Data.getCStr(&Offset);
StringRef AugmentationString(Augmentation ? Augmentation : "");
- // TODO: we should provide a way to report a warning and continue dumping.
- if (IsEH && Version != 1)
- return createStringError(errc::not_supported,
- "unsupported CIE version: %" PRIu8, Version);
-
uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
Data.getU8(&Offset);
Data.setAddressSize(AddressSize);