[dwarfdump] Make debug_frame dump actually useful.

This adds support for pretty-printing instruction operands. The new
output looks like:

00000000 00000010 ffffffff CIE
  Version:               1
  Augmentation:
  Code alignment factor: 1
  Data alignment factor: -4
  Return address column: 8

  DW_CFA_def_cfa:  reg4 +4
  DW_CFA_offset:  reg8 -4
  DW_CFA_nop:
  DW_CFA_nop:

00000014 00000010 00000000 FDE cie=00000000 pc=00000000...00000022
  DW_CFA_advance_loc:  3
  DW_CFA_def_cfa_offset:  +12
  DW_CFA_nop:

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230551 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Frederic Riss 2015-02-25 21:30:22 +00:00
parent 0a7d07b87b
commit e9e16aa4a5
2 changed files with 148 additions and 15 deletions

View File

@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
@ -267,16 +269,147 @@ private:
uint64_t AddressRange;
CIE *LinkedCIE;
};
/// \brief Types of operands to CF instructions.
enum OperandType {
OT_Unset,
OT_None,
OT_Address,
OT_Offset,
OT_FactoredCodeOffset,
OT_SignedFactDataOffset,
OT_UnsignedFactDataOffset,
OT_Register,
OT_Expression
};
} // end anonymous namespace
/// \brief Initialize the array describing the types of operands.
static ArrayRef<OperandType[2]> getOperandTypes() {
static OperandType OpTypes[DW_CFA_restore+1][2];
#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
do { \
OpTypes[OP][0] = OPTYPE0; \
OpTypes[OP][1] = OPTYPE1; \
} while (0)
#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
DECLARE_OP1(DW_CFA_set_loc, OT_Address);
DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
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_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);
DECLARE_OP1(DW_CFA_undefined, OT_Register);
DECLARE_OP1(DW_CFA_same_value, OT_Register);
DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
DECLARE_OP1(DW_CFA_restore, OT_Register);
DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
DECLARE_OP0(DW_CFA_remember_state);
DECLARE_OP0(DW_CFA_restore_state);
DECLARE_OP0(DW_CFA_GNU_window_save);
DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
DECLARE_OP0(DW_CFA_nop);
#undef DECLARE_OP0
#undef DECLARE_OP1
#undef DECLARE_OP2
return OpTypes;
}
static ArrayRef<OperandType[2]> OpTypes = getOperandTypes();
/// \brief Print \p Opcode's operand number \p OperandIdx which has
/// value \p Operand.
static void printOperand(raw_ostream &OS, uint8_t Opcode, unsigned OperandIdx,
uint64_t Operand, uint64_t CodeAlignmentFactor,
int64_t DataAlignmentFactor) {
assert(OperandIdx < 2);
OperandType Type = OpTypes[Opcode][OperandIdx];
switch (Type) {
case OT_Unset:
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
if (const char *OpcodeName = CallFrameString(Opcode))
OS << " " << OpcodeName;
else
OS << format(" Opcode %x", Opcode);
break;
case OT_None:
break;
case OT_Address:
OS << format(" %" PRIx64, Operand);
break;
case OT_Offset:
// The offsets are all encoded in a unsigned form, but in practice
// consumers use them signed. It's most certainly legacy due to
// the lack of signed variants in the first Dwarf standards.
OS << format(" %+" PRId64, int64_t(Operand));
break;
case OT_FactoredCodeOffset: // Always Unsigned
if (CodeAlignmentFactor)
OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
else
OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
break;
case OT_SignedFactDataOffset:
if (DataAlignmentFactor)
OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
break;
case OT_UnsignedFactDataOffset:
if (DataAlignmentFactor)
OS << format(" %" PRId64, Operand * DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
break;
case OT_Register:
OS << format(" reg%d", Operand);
break;
case OT_Expression:
OS << " expression";
break;
}
}
void FrameEntry::dumpInstructions(raw_ostream &OS) const {
// TODO: at the moment only instruction names are dumped. Expand this to
// dump operands as well.
uint64_t CodeAlignmentFactor = 0;
int64_t DataAlignmentFactor = 0;
const CIE *Cie = dyn_cast<CIE>(this);
if (!Cie)
Cie = cast<FDE>(this)->getLinkedCIE();
if (Cie) {
CodeAlignmentFactor = Cie->getCodeAlignmentFactor();
DataAlignmentFactor = Cie->getDataAlignmentFactor();
}
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";
OS << " " << CallFrameString(Opcode) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, Opcode, i, Instr.Ops[i], CodeAlignmentFactor,
DataAlignmentFactor);
OS << '\n';
}
}

View File

@ -6,22 +6,22 @@
; FRAMES: 00000000 00000010 ffffffff CIE
; FRAMES: Version: 1
; FRAMES: DW_CFA_def_cfa
; FRAMES-NEXT: DW_CFA_offset
; FRAMES-NEXT: DW_CFA_nop
; FRAMES-NEXT: DW_CFA_nop
; FRAMES: DW_CFA_def_cfa: reg4 +4
; FRAMES-NEXT: DW_CFA_offset: reg8 -4
; FRAMES-NEXT: DW_CFA_nop:
; FRAMES-NEXT: DW_CFA_nop:
; FRAMES: 00000014 00000010 00000000 FDE cie=00000000 pc=00000000...00000022
; FRAMES: DW_CFA_advance_loc
; FRAMES-NEXT: DW_CFA_def_cfa_offset
; FRAMES-NEXT: DW_CFA_nop
; FRAMES: DW_CFA_advance_loc: 3
; FRAMES-NEXT: DW_CFA_def_cfa_offset: +12
; FRAMES-NEXT: DW_CFA_nop:
; FRAMES: 00000028 00000014 00000000 FDE cie=00000000 pc=00000030...00000080
; FRAMES: DW_CFA_advance_loc
; FRAMES-NEXT: DW_CFA_def_cfa_offset
; FRAMES-NEXT: DW_CFA_offset
; FRAMES-NEXT: DW_CFA_advance_loc
; FRAMES-NEXT: DW_CFA_def_cfa_register
; FRAMES: DW_CFA_advance_loc: 1
; FRAMES-NEXT: DW_CFA_def_cfa_offset: +8
; FRAMES-NEXT: DW_CFA_offset: reg5 -8
; FRAMES-NEXT: DW_CFA_advance_loc: 2
; FRAMES-NEXT: DW_CFA_def_cfa_register: reg5
; FRAMES-NOT: CIE
; FRAMES-NOT: FDE