Files
archived-llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
Adrian Prantl 460dd60c1a [DIExpression] Introduce a dedicated DW_OP_LLVM_fragment operation
so we can stop using DW_OP_bit_piece with the wrong semantics.

The entire back story can be found here:
http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20161114/405934.html

The gist is that in LLVM we've been misinterpreting DW_OP_bit_piece's
offset field to mean the offset into the source variable rather than
the offset into the location at the top the DWARF expression stack. In
order to be able to fix this in a subsequent patch, this patch
introduces a dedicated DW_OP_LLVM_fragment operation with the
semantics that we used to apply to DW_OP_bit_piece, which is what we
actually need while inside of LLVM. This patch is complete with a
bitcode upgrade for expressions using the old format. It does not yet
fix the DWARF backend to use DW_OP_bit_piece correctly.

Implementation note: We discussed several options for implementing
this, including reserving a dedicated field in DIExpression for the
fragment size and offset, but using an custom operator at the end of
the expression works just fine and is more efficient because we then
only pay for it when we need it.

Differential Revision: https://reviews.llvm.org/D27361
rdar://problem/29335809

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@288683 91177308-0d34-0410-b5e6-96231b3b80d8
2016-12-05 18:04:47 +00:00

290 lines
9.7 KiB
C++

//===-- AsmPrinterDwarf.cpp - AsmPrinter Dwarf Support --------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Dwarf emissions parts of AsmPrinter.
//
//===----------------------------------------------------------------------===//
#include "ByteStreamer.h"
#include "DwarfDebug.h"
#include "DwarfExpression.h"
#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
//===----------------------------------------------------------------------===//
// Dwarf Emission Helper Routines
//===----------------------------------------------------------------------===//
/// EmitSLEB128 - emit the specified signed leb128 value.
void AsmPrinter::EmitSLEB128(int64_t Value, const char *Desc) const {
if (isVerbose() && Desc)
OutStreamer->AddComment(Desc);
OutStreamer->EmitSLEB128IntValue(Value);
}
/// EmitULEB128 - emit the specified unsigned leb128 value.
void AsmPrinter::EmitULEB128(uint64_t Value, const char *Desc,
unsigned PadTo) const {
if (isVerbose() && Desc)
OutStreamer->AddComment(Desc);
OutStreamer->EmitULEB128IntValue(Value, PadTo);
}
static const char *DecodeDWARFEncoding(unsigned Encoding) {
switch (Encoding) {
case dwarf::DW_EH_PE_absptr:
return "absptr";
case dwarf::DW_EH_PE_omit:
return "omit";
case dwarf::DW_EH_PE_pcrel:
return "pcrel";
case dwarf::DW_EH_PE_udata4:
return "udata4";
case dwarf::DW_EH_PE_udata8:
return "udata8";
case dwarf::DW_EH_PE_sdata4:
return "sdata4";
case dwarf::DW_EH_PE_sdata8:
return "sdata8";
case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4:
return "pcrel udata4";
case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4:
return "pcrel sdata4";
case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8:
return "pcrel udata8";
case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8:
return "pcrel sdata8";
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4
:
return "indirect pcrel udata4";
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4
:
return "indirect pcrel sdata4";
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8
:
return "indirect pcrel udata8";
case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8
:
return "indirect pcrel sdata8";
}
return "<unknown encoding>";
}
/// EmitEncodingByte - Emit a .byte 42 directive that corresponds to an
/// encoding. If verbose assembly output is enabled, we output comments
/// describing the encoding. Desc is an optional string saying what the
/// encoding is specifying (e.g. "LSDA").
void AsmPrinter::EmitEncodingByte(unsigned Val, const char *Desc) const {
if (isVerbose()) {
if (Desc)
OutStreamer->AddComment(Twine(Desc) + " Encoding = " +
Twine(DecodeDWARFEncoding(Val)));
else
OutStreamer->AddComment(Twine("Encoding = ") + DecodeDWARFEncoding(Val));
}
OutStreamer->EmitIntValue(Val, 1);
}
/// GetSizeOfEncodedValue - Return the size of the encoding in bytes.
unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const {
if (Encoding == dwarf::DW_EH_PE_omit)
return 0;
switch (Encoding & 0x07) {
default:
llvm_unreachable("Invalid encoded value.");
case dwarf::DW_EH_PE_absptr:
return MF->getDataLayout().getPointerSize();
case dwarf::DW_EH_PE_udata2:
return 2;
case dwarf::DW_EH_PE_udata4:
return 4;
case dwarf::DW_EH_PE_udata8:
return 8;
}
}
void AsmPrinter::EmitTTypeReference(const GlobalValue *GV,
unsigned Encoding) const {
if (GV) {
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
const MCExpr *Exp =
TLOF.getTTypeGlobalReference(GV, Encoding, TM, MMI, *OutStreamer);
OutStreamer->EmitValue(Exp, GetSizeOfEncodedValue(Encoding));
} else
OutStreamer->EmitIntValue(0, GetSizeOfEncodedValue(Encoding));
}
void AsmPrinter::emitDwarfSymbolReference(const MCSymbol *Label,
bool ForceOffset) const {
if (!ForceOffset) {
// On COFF targets, we have to emit the special .secrel32 directive.
if (MAI->needsDwarfSectionOffsetDirective()) {
OutStreamer->EmitCOFFSecRel32(Label);
return;
}
// If the format uses relocations with dwarf, refer to the symbol directly.
if (MAI->doesDwarfUseRelocationsAcrossSections()) {
OutStreamer->EmitSymbolValue(Label, 4);
return;
}
}
// Otherwise, emit it as a label difference from the start of the section.
EmitLabelDifference(Label, Label->getSection().getBeginSymbol(), 4);
}
void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntryRef S) const {
if (MAI->doesDwarfUseRelocationsAcrossSections()) {
emitDwarfSymbolReference(S.getSymbol());
return;
}
// Just emit the offset directly; no need for symbol math.
EmitInt32(S.getOffset());
}
/// EmitDwarfRegOp - Emit dwarf register operation.
void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer,
const MachineLocation &MLoc) const {
DebugLocDwarfExpression Expr(getDwarfVersion(), Streamer);
const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo();
int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false);
if (Reg < 0) {
// We assume that pointers are always in an addressable register.
if (MLoc.isIndirect())
// FIXME: We have no reasonable way of handling errors in here. The
// caller might be in the middle of a dwarf expression. We should
// probably assert that Reg >= 0 once debug info generation is more
// mature.
return Expr.EmitOp(dwarf::DW_OP_nop,
"nop (could not find a dwarf register number)");
// Attempt to find a valid super- or sub-register.
if (!Expr.AddMachineRegFragment(*MF->getSubtarget().getRegisterInfo(),
MLoc.getReg()))
Expr.EmitOp(dwarf::DW_OP_nop,
"nop (could not find a dwarf register number)");
return;
}
if (MLoc.isIndirect())
Expr.AddRegIndirect(Reg, MLoc.getOffset());
else
Expr.AddReg(Reg);
}
//===----------------------------------------------------------------------===//
// Dwarf Lowering Routines
//===----------------------------------------------------------------------===//
void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
switch (Inst.getOperation()) {
default:
llvm_unreachable("Unexpected instruction");
case MCCFIInstruction::OpDefCfaOffset:
OutStreamer->EmitCFIDefCfaOffset(Inst.getOffset());
break;
case MCCFIInstruction::OpAdjustCfaOffset:
OutStreamer->EmitCFIAdjustCfaOffset(Inst.getOffset());
break;
case MCCFIInstruction::OpDefCfa:
OutStreamer->EmitCFIDefCfa(Inst.getRegister(), Inst.getOffset());
break;
case MCCFIInstruction::OpDefCfaRegister:
OutStreamer->EmitCFIDefCfaRegister(Inst.getRegister());
break;
case MCCFIInstruction::OpOffset:
OutStreamer->EmitCFIOffset(Inst.getRegister(), Inst.getOffset());
break;
case MCCFIInstruction::OpRegister:
OutStreamer->EmitCFIRegister(Inst.getRegister(), Inst.getRegister2());
break;
case MCCFIInstruction::OpWindowSave:
OutStreamer->EmitCFIWindowSave();
break;
case MCCFIInstruction::OpSameValue:
OutStreamer->EmitCFISameValue(Inst.getRegister());
break;
case MCCFIInstruction::OpGnuArgsSize:
OutStreamer->EmitCFIGnuArgsSize(Inst.getOffset());
break;
case MCCFIInstruction::OpEscape:
OutStreamer->EmitCFIEscape(Inst.getValues());
break;
}
}
void AsmPrinter::emitDwarfDIE(const DIE &Die) const {
// Emit the code (index) for the abbreviation.
if (isVerbose())
OutStreamer->AddComment("Abbrev [" + Twine(Die.getAbbrevNumber()) + "] 0x" +
Twine::utohexstr(Die.getOffset()) + ":0x" +
Twine::utohexstr(Die.getSize()) + " " +
dwarf::TagString(Die.getTag()));
EmitULEB128(Die.getAbbrevNumber());
// Emit the DIE attribute values.
for (const auto &V : Die.values()) {
dwarf::Attribute Attr = V.getAttribute();
assert(V.getForm() && "Too many attributes for DIE (check abbreviation)");
if (isVerbose()) {
OutStreamer->AddComment(dwarf::AttributeString(Attr));
if (Attr == dwarf::DW_AT_accessibility)
OutStreamer->AddComment(
dwarf::AccessibilityString(V.getDIEInteger().getValue()));
}
// Emit an attribute using the defined form.
V.EmitValue(this);
}
// Emit the DIE children if any.
if (Die.hasChildren()) {
for (auto &Child : Die.children())
emitDwarfDIE(Child);
OutStreamer->AddComment("End Of Children Mark");
EmitInt8(0);
}
}
void AsmPrinter::emitDwarfAbbrev(const DIEAbbrev &Abbrev) const {
// Emit the abbreviations code (base 1 index.)
EmitULEB128(Abbrev.getNumber(), "Abbreviation Code");
// Emit the abbreviations data.
Abbrev.Emit(this);
}