Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFCFIPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===- DWARFCFIPrinter.h ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_DEBUGINFO_DWARF_DWARFCFIPRINTER_H
#define LLVM_DEBUGINFO_DWARF_DWARFCFIPRINTER_H

#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h"

namespace llvm {

struct DIDumpOptions;

namespace dwarf {

// This class is separate from CFIProgram to decouple CFIPrograms from the
// enclosing DWARF dies and type units, which allows using them in lower-level
// places without build dependencies.

class CFIPrinter {
public:
static void print(const CFIProgram &P, raw_ostream &OS,
DIDumpOptions DumpOpts, unsigned IndentLevel,
std::optional<uint64_t> Address);

static void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const CFIProgram &P,
const CFIProgram::Instruction &Instr,
unsigned OperandIdx, uint64_t Operand,
std::optional<uint64_t> &Address);
};

} // end namespace dwarf

} // end namespace llvm

#endif // LLVM_DEBUGINFO_DWARF_DWARFCFIPRINTER_H
13 changes: 4 additions & 9 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFCFIProgram.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
namespace llvm {

namespace dwarf {

class CFIPrinter;

/// Represent a sequence of Call Frame Information instructions that, when read
/// in order, construct a table mapping PC to frame state. This can also be
/// referred to as "CFI rules" in DWARF literature to avoid confusion with
Expand All @@ -34,6 +37,7 @@ class CFIProgram {
public:
static constexpr size_t MaxOperands = 3;
typedef SmallVector<uint64_t, MaxOperands> Operands;
friend CFIPrinter;

/// An instruction consists of a DWARF CFI opcode and an optional sequence of
/// operands. If it refers to an expression, then this expression has its own
Expand Down Expand Up @@ -80,10 +84,6 @@ class CFIProgram {
LLVM_ABI Error parse(DWARFDataExtractor Data, uint64_t *Offset,
uint64_t EndOffset);

LLVM_ABI void dump(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned IndentLevel,
std::optional<uint64_t> InitialLocation) const;

void addInstruction(const Instruction &I) { Instructions.push_back(I); }

/// Get a DWARF CFI call frame string for the given DW_CFA opcode.
Expand Down Expand Up @@ -147,11 +147,6 @@ class CFIProgram {
/// Retrieve the array describing the types of operands according to the enum
/// above. This is indexed by opcode.
static ArrayRef<OperandType[MaxOperands]> getOperandTypes();

/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
void printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const Instruction &Instr, unsigned OperandIdx,
uint64_t Operand, std::optional<uint64_t> &Address) const;
};

} // end namespace dwarf
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/DebugInfo/DWARF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF
DWARFAbbreviationDeclaration.cpp
DWARFAddressRange.cpp
DWARFAcceleratorTable.cpp
DWARFCFIPrinter.cpp
DWARFCFIProgram.cpp
DWARFCompileUnit.cpp
DWARFContext.cpp
Expand Down
120 changes: 120 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFCFIPrinter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//===- DWARFCFIPrinter.cpp - Print the cfi-portions of .debug_frame -------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cinttypes>
#include <cstdint>
#include <optional>

using namespace llvm;
using namespace dwarf;

void CFIPrinter::print(const CFIProgram &P, raw_ostream &OS,
DIDumpOptions DumpOpts, unsigned IndentLevel,
std::optional<uint64_t> Address) {
for (const auto &Instr : P) {
uint8_t Opcode = Instr.Opcode;
OS.indent(2 * IndentLevel);
OS << P.callFrameString(Opcode) << ":";
for (size_t i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, DumpOpts, P, Instr, i, Instr.Ops[i], Address);
OS << '\n';
}
}

static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned RegNum) {
if (DumpOpts.GetNameForDWARFReg) {
auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);
if (!RegName.empty()) {
OS << RegName;
return;
}
}
OS << "reg" << RegNum;
}

/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
void CFIPrinter::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const CFIProgram &P,
const CFIProgram::Instruction &Instr,
unsigned OperandIdx, uint64_t Operand,
std::optional<uint64_t> &Address) {
assert(OperandIdx < CFIProgram::MaxOperands);
uint8_t Opcode = Instr.Opcode;
CFIProgram::OperandType Type = P.getOperandTypes()[Opcode][OperandIdx];

switch (Type) {
case CFIProgram::OT_Unset: {
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
auto OpcodeName = P.callFrameString(Opcode);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
OS << format(" Opcode %x", Opcode);
break;
}
case CFIProgram::OT_None:
break;
case CFIProgram::OT_Address:
OS << format(" %" PRIx64, Operand);
Address = Operand;
break;
case CFIProgram::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 CFIProgram::OT_FactoredCodeOffset: // Always Unsigned
if (P.CodeAlignmentFactor)
OS << format(" %" PRId64, Operand * P.CodeAlignmentFactor);
else
OS << format(" %" PRId64 "*code_alignment_factor", Operand);
if (Address && P.CodeAlignmentFactor) {
*Address += Operand * P.CodeAlignmentFactor;
OS << format(" to 0x%" PRIx64, *Address);
}
break;
case CFIProgram::OT_SignedFactDataOffset:
if (P.DataAlignmentFactor)
OS << format(" %" PRId64, int64_t(Operand) * P.DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor", int64_t(Operand));
break;
case CFIProgram::OT_UnsignedFactDataOffset:
if (P.DataAlignmentFactor)
OS << format(" %" PRId64, Operand * P.DataAlignmentFactor);
else
OS << format(" %" PRId64 "*data_alignment_factor", Operand);
break;
case CFIProgram::OT_Register:
OS << ' ';
printRegister(OS, DumpOpts, Operand);
break;
case CFIProgram::OT_AddressSpace:
OS << format(" in addrspace%" PRId64, Operand);
break;
case CFIProgram::OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
DWARFExpressionPrinter::print(&Instr.Expression.value(), OS, DumpOpts,
nullptr);
break;
}
}
94 changes: 0 additions & 94 deletions llvm/lib/DebugInfo/DWARF/DWARFCFIProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,6 @@
using namespace llvm;
using namespace dwarf;

static void printRegister(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned RegNum) {
if (DumpOpts.GetNameForDWARFReg) {
auto RegName = DumpOpts.GetNameForDWARFReg(RegNum, DumpOpts.IsEH);
if (!RegName.empty()) {
OS << RegName;
return;
}
}
OS << "reg" << RegNum;
}

// 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;
Expand Down Expand Up @@ -361,85 +349,3 @@ CFIProgram::getOperandTypes() {

return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
}

/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
const Instruction &Instr, unsigned OperandIdx,
uint64_t Operand,
std::optional<uint64_t> &Address) const {
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);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
OS << format(" Opcode %x", Opcode);
break;
}
case OT_None:
break;
case OT_Address:
OS << format(" %" PRIx64, Operand);
Address = 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);
if (Address && CodeAlignmentFactor) {
*Address += Operand * CodeAlignmentFactor;
OS << format(" to 0x%" PRIx64, *Address);
}
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 << ' ';
printRegister(OS, DumpOpts, Operand);
break;
case OT_AddressSpace:
OS << format(" in addrspace%" PRId64, Operand);
break;
case OT_Expression:
assert(Instr.Expression && "missing DWARFExpression object");
OS << " ";
DWARFExpressionPrinter::print(&Instr.Expression.value(), OS, DumpOpts,
nullptr);
break;
}
}

void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
unsigned IndentLevel,
std::optional<uint64_t> Address) const {
for (const auto &Instr : Instructions) {
uint8_t Opcode = Instr.Opcode;
OS.indent(2 * IndentLevel);
OS << callFrameString(Opcode) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, DumpOpts, Instr, i, Instr.Ops[i], Address);
OS << '\n';
}
}
6 changes: 4 additions & 2 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"
#include "llvm/DebugInfo/DWARF/DWARFCFIProgram.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
Expand Down Expand Up @@ -602,7 +603,8 @@ void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
OS << "\n";
}
OS << "\n";
CFIs.dump(OS, DumpOpts, /*IndentLevel=*/1, /*InitialLocation=*/{});
CFIPrinter::print(CFIs, OS, DumpOpts, /*IndentLevel=*/1,
/*InitialLocation=*/{});
OS << "\n";

if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
Expand Down Expand Up @@ -630,7 +632,7 @@ void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
OS << " Format: " << FormatString(IsDWARF64) << "\n";
if (LSDAAddress)
OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
CFIs.dump(OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);
CFIPrinter::print(CFIs, OS, DumpOpts, /*IndentLevel=*/1, InitialLocation);
OS << "\n";

if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
Expand Down
5 changes: 3 additions & 2 deletions llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "llvm-readobj.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFCFIPrinter.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
Expand Down Expand Up @@ -228,8 +229,8 @@ void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
W.indent();
auto DumpOpts = DIDumpOptions();
DumpOpts.IsEH = true;
Entry.cfis().dump(W.getOStream(), DumpOpts, W.getIndentLevel(),
InitialLocation);
dwarf::CFIPrinter::print(Entry.cfis(), W.getOStream(), DumpOpts,
W.getIndentLevel(), InitialLocation);
W.unindent();
W.unindent();
W.getOStream() << "\n";
Expand Down
Loading