CODEGENOPT(ForceDwarfFrameSection , 1, 0) ///< Set when -fforce-dwarf-frame is
///< enabled.
+///< Set when -femit-dwarf-unwind is passed.
+ENUM_CODEGENOPT(EmitDwarfUnwind, llvm::EmitDwarfUnwindType, 2,
+ llvm::EmitDwarfUnwindType::Default)
+
///< Set when -fxray-always-emit-customevents is enabled.
CODEGENOPT(XRayAlwaysEmitCustomEvents , 1, 0)
defm force_dwarf_frame : BoolFOption<"force-dwarf-frame",
CodeGenOpts<"ForceDwarfFrameSection">, DefaultFalse,
PosFlag<SetTrue, [CC1Option], "Always emit a debug frame section">, NegFlag<SetFalse>>;
+def femit_dwarf_unwind_EQ : Joined<["-"], "femit-dwarf-unwind=">,
+ Group<f_Group>, Flags<[CC1Option, CC1AsOption]>,
+ HelpText<"When to emit DWARF unwind (EH frame) info">,
+ Values<"always,no-compact-unwind,default">,
+ NormalizedValues<["Always", "NoCompactUnwind", "Default"]>,
+ NormalizedValuesScope<"llvm::EmitDwarfUnwindType">,
+ MarshallingInfoEnum<CodeGenOpts<"EmitDwarfUnwind">, "Default">;
def g_Flag : Flag<["-"], "g">, Group<g_Group>,
HelpText<"Generate source-level debug information">;
def gline_tables_only : Flag<["-"], "gline-tables-only">, Group<gN_Group>,
}
Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile;
+ Options.MCOptions.EmitDwarfUnwind = CodeGenOpts.getEmitDwarfUnwind();
Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll;
Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels;
Options.MCOptions.MCUseDwarfDirectory =
DefaultIncrementalLinkerCompatible))
CmdArgs.push_back("-mincremental-linker-compatible");
+ Args.AddLastArg(CmdArgs, options::OPT_femit_dwarf_unwind_EQ);
+
// If you add more args here, also add them to the block below that
// starts with "// If CollectArgsForIntegratedAssembler() isn't called below".
}
Args.ClaimAllArgs(options::OPT_Wa_COMMA);
Args.ClaimAllArgs(options::OPT_Xassembler);
+ Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ);
}
if (isa<AnalyzeJobAction>(JA)) {
--- /dev/null
+// REQUIRES: x86-registered-target
+
+// RUN: rm -rf %t; mkdir %t
+// RUN: %clang -target x86_64-apple-macos11.0 -c %s -o %t/x86_64.o
+// RUN: %clang -target x86_64-apple-macos11.0 -femit-dwarf-unwind=no-compact-unwind -c %s -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix=WITH-FDE
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix=NO-FDE
+
+// WITH-FDE: FDE
+// NO-FDE-NOT: FDE
+
+int foo() {
+ return 1;
+}
--- /dev/null
+// REQUIRES: x86-registered-target
+
+// RUN: rm -rf %t; mkdir %t
+// RUN: %clang -target x86_64-apple-macos11.0 -c %s -o %t/x86_64.o
+// RUN: %clang -target x86_64-apple-macos11.0 -femit-dwarf-unwind=no-compact-unwind -c %s -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix=WITH-FDE
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix=NO-FDE
+
+// WITH-FDE: FDE
+// NO-FDE-NOT: FDE
+
+.text
+_foo:
+ .cfi_startproc
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
unsigned IncrementalLinkerCompatible : 1;
unsigned EmbedBitcode : 1;
+ /// Whether to emit DWARF unwind info.
+ EmitDwarfUnwindType EmitDwarfUnwind;
+
/// The name of the relocation model to use.
std::string RelocationModel;
.Default(0);
}
+ if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
+ Opts.EmitDwarfUnwind =
+ llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
+ .Case("always", EmitDwarfUnwindType::Always)
+ .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
+ .Case("default", EmitDwarfUnwindType::Default);
+ }
+
return Success;
}
assert(MRI && "Unable to create target register info!");
MCTargetOptions MCOptions;
+ MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
+
std::unique_ptr<MCAsmInfo> MAI(
TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
assert(MAI && "Unable to create target asm info!");
class SMDiagnostic;
class SMLoc;
class SourceMgr;
+enum class EmitDwarfUnwindType;
/// Context object for machine code objects. This class owns all of the
/// sections that it creates.
bool getGenDwarfForAssembly() { return GenDwarfForAssembly; }
void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; }
unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; }
+ EmitDwarfUnwindType emitDwarfUnwindInfo() const;
void setGenDwarfFileNumber(unsigned FileNumber) {
GenDwarfFileNumber = FileNumber;
Z, ///< zlib style complession
};
+enum class EmitDwarfUnwindType {
+ Always, // Always emit dwarf unwind
+ NoCompactUnwind, // Only emit if compact unwind isn't available
+ Default, // Default behavior is based on the target
+};
+
class StringRef;
class MCTargetOptions {
bool PreserveAsmComments : 1;
bool Dwarf64 : 1;
+
+ EmitDwarfUnwindType EmitDwarfUnwind;
+
int DwarfVersion = 0;
enum DwarfDirectory {
namespace llvm {
class MCTargetOptions;
+enum class EmitDwarfUnwindType;
namespace mc {
bool getDwarf64();
+EmitDwarfUnwindType getEmitDwarfUnwind();
+
bool getShowMCInst();
bool getFatalWarnings();
"Cannot emit MC with limited codegen pipeline");
Ctx = &MMIWP->getMMI().getContext();
+ // libunwind is unable to load compact unwind dynamically, so we must generate
+ // DWARF unwind info for the JIT.
+ Options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always;
if (Options.MCOptions.MCSaveTempLabels)
Ctx->setAllowTemporaryLabels(false);
: TM(std::move(MMI.TM)),
Context(MMI.TM.getTargetTriple(), MMI.TM.getMCAsmInfo(),
MMI.TM.getMCRegisterInfo(), MMI.TM.getMCSubtargetInfo(), nullptr,
- nullptr, false),
+ &MMI.TM.Options.MCOptions, false),
MachineFunctions(std::move(MMI.MachineFunctions)) {
Context.setObjectFileInfo(MMI.TM.getObjFileLowering());
ObjFileMMI = MMI.ObjFileMMI;
MachineModuleInfo::MachineModuleInfo(const LLVMTargetMachine *TM)
: TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
- nullptr, nullptr, false) {
+ nullptr, &TM->Options.MCOptions, false) {
Context.setObjectFileInfo(TM->getObjFileLowering());
initialize();
}
MCContext *ExtContext)
: TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
- nullptr, nullptr, false),
+ nullptr, &TM->Options.MCOptions, false),
ExternalContext(ExtContext) {
Context.setObjectFileInfo(TM->getObjFileLowering());
initialize();
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
// and projects/libunwind/src/UnwindLevel1-gcc-ext.c.
const char *P = (const char *)Addr;
const char *End = P + Size;
- do {
+ while (P != End)
P = processFDE(P, false);
- } while(P != End);
}
void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr,
size_t Size) {
const char *P = (const char *)Addr;
const char *End = P + Size;
- do {
+ while (P != End)
P = processFDE(P, true);
- } while(P != End);
}
#else
// Dwarf Management
//===----------------------------------------------------------------------===//
+EmitDwarfUnwindType MCContext::emitDwarfUnwindInfo() const {
+ if (!TargetOptions)
+ return EmitDwarfUnwindType::Default;
+ return TargetOptions->EmitDwarfUnwind;
+}
+
void MCContext::setGenDwarfRootFile(StringRef InputFileName, StringRef Buffer) {
// MCDwarf needs the root file as well as the compilation directory.
// If we find a '.file 0' directive that will supersede these values.
void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB,
bool IsEH) {
- Streamer.generateCompactUnwindEncodings(MAB);
-
MCContext &Context = Streamer.getContext();
const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
const MCAsmInfo *AsmInfo = Context.getAsmInfo();
// Emit the compact unwind info if available.
bool NeedsEHFrameSection = !MOFI->getSupportsCompactUnwindWithoutEHFrame();
if (IsEH && MOFI->getCompactUnwindSection()) {
+ Streamer.generateCompactUnwindEncodings(MAB);
bool SectionEmitted = false;
for (const MCDwarfFrameInfo &Frame : FrameArray) {
if (Frame.CompactUnwindEncoding == 0) continue;
(T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32))
SupportsCompactUnwindWithoutEHFrame = true;
- if (T.isWatchABI())
+ switch (Ctx->emitDwarfUnwindInfo()) {
+ case EmitDwarfUnwindType::Always:
+ OmitDwarfIfHaveCompactUnwind = false;
+ break;
+ case EmitDwarfUnwindType::NoCompactUnwind:
OmitDwarfIfHaveCompactUnwind = true;
+ break;
+ case EmitDwarfUnwindType::Default:
+ OmitDwarfIfHaveCompactUnwind =
+ T.isWatchABI() || SupportsCompactUnwindWithoutEHFrame;
+ break;
+ }
FDECFIEncoding = dwarf::DW_EH_PE_pcrel;
MCSaveTempLabels(false), MCIncrementalLinkerCompatible(false),
ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false),
PreserveAsmComments(true), Dwarf64(false),
+ EmitDwarfUnwind(EmitDwarfUnwindType::Default),
MCUseDwarfDirectory(DefaultDwarfDirectory) {}
StringRef MCTargetOptions::getABIName() const {
-//===-- MCTargetOptionsCommandFlags.cpp --------------------------*- C++
-//-*-===//
+//===-- MCTargetOptionsCommandFlags.cpp -----------------------*- C++ //-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
MCOPT(bool, IncrementalLinkerCompatible)
MCOPT(int, DwarfVersion)
MCOPT(bool, Dwarf64)
+MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind)
MCOPT(bool, ShowMCInst)
MCOPT(bool, FatalWarnings)
MCOPT(bool, NoWarn)
cl::desc("Generate debugging info in the 64-bit DWARF format"));
MCBINDOPT(Dwarf64);
+ static cl::opt<EmitDwarfUnwindType> EmitDwarfUnwind(
+ "emit-dwarf-unwind", cl::desc("Whether to emit DWARF EH frame entries."),
+ cl::init(EmitDwarfUnwindType::Default),
+ cl::values(clEnumValN(EmitDwarfUnwindType::Always, "always",
+ "Always emit EH frame entries"),
+ clEnumValN(EmitDwarfUnwindType::NoCompactUnwind,
+ "no-compact-unwind",
+ "Only emit EH frame entries when compact unwind is "
+ "not available"),
+ clEnumValN(EmitDwarfUnwindType::Default, "default",
+ "Use target platform default")));
+ MCBINDOPT(EmitDwarfUnwind);
+
static cl::opt<bool> ShowMCInst(
"asm-show-inst",
cl::desc("Emit internal instruction representation to assembly file"));
Options.MCNoWarn = getNoWarn();
Options.MCNoDeprecatedWarn = getNoDeprecatedWarn();
Options.MCNoTypeCheck = getNoTypeCheck();
+ Options.EmitDwarfUnwind = getEmitDwarfUnwind();
+
return Options;
}
default:
// Any other CFI directives indicate a frame that we aren't prepared
// to represent via compact unwind, so just bail out.
- return 0;
+ return CU::UNWIND_MODE_DWARF;
case MCCFIInstruction::OpDefCfaRegister: {
// Defines a frame pointer. E.g.
//
// generate a compact unwinding representation, so bail out.
if (*MRI.getLLVMRegNum(Inst.getRegister(), true) !=
(Is64Bit ? X86::RBP : X86::EBP))
- return 0;
+ return CU::UNWIND_MODE_DWARF;
// Reset the counts.
memset(SavedRegs, 0, sizeof(SavedRegs));
--- /dev/null
+// RUN: rm -rf %t; mkdir %t
+// RUN: llvm-mc -triple x86_64-apple-macos11.0 %s -filetype=obj -o %t/x86_64.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64.o | FileCheck %s --check-prefix TWO-FDES
+// RUN: llvm-mc -triple arm64-apple-macos11.0 %s -filetype=obj -o %t/arm64.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/arm64.o | FileCheck %s --check-prefix ONE-FDE
+// RUN: llvm-mc -triple x86_64-apple-macos11.0 %s -filetype=obj --emit-dwarf-unwind no-compact-unwind -o %t/x86_64-no-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/x86_64-no-dwarf.o | FileCheck %s --check-prefix ONE-FDE
+// RUN: llvm-mc -triple arm64-apple-macos11.0 %s -filetype=obj --emit-dwarf-unwind always -o %t/arm64-dwarf.o
+// RUN: llvm-objdump --macho --dwarf=frames %t/arm64-dwarf.o | FileCheck %s --check-prefix TWO-FDES
+
+// TWO-FDES: FDE
+// TWO-FDES: FDE
+
+// ONE-FDE-NOT: FDE
+// ONE-FDE: FDE
+// ONE-FDE-NOT: FDE
+
+_main:
+ .cfi_startproc
+ .cfi_def_cfa_offset 16
+ ret
+ .cfi_endproc
+
+_foo:
+ .cfi_startproc
+ .cfi_def_cfa_offset 16
+ /// This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+ /// unwind, so we must use DWARf unwind for this function.
+ .cfi_escape 0x2e, 0x10
+ ret
+ .cfi_endproc
+
+.subsections_via_symbols
--- /dev/null
+// RUN: llvm-mc -triple x86_64-apple-macos10.6 -filetype=obj %s -o %t.o
+// RUN: llvm-objdump --macho --unwind-info --dwarf=frames %t.o | FileCheck %s
+
+/// For functions whose unwind info cannot be encoded with compact unwind, make
+/// sure that we encode them using DWARF unwind, and make sure we emit a compact
+/// unwind entry that indicates that a DWARF encoding is being used.
+
+_f:
+ .cfi_startproc
+ ## This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+ ## unwind, so we must use DWARF unwind instead.
+ .cfi_escape 0x2e, 0x10
+ ret
+ .cfi_endproc
+
+_g:
+ .cfi_startproc
+ ## This encodes DW_CFA_GNU_args_size which cannot be expressed using compact
+ ## unwind, so we must use DWARF unwind instead.
+ .cfi_escape 0x2e, 0x10
+ ret
+ .cfi_endproc
+
+// CHECK: Contents of __compact_unwind section:
+// CHECK: Entry at offset 0x0:
+// CHECK: start: 0x[[#%x,F:]] _f
+// CHECK: length: 0x1
+// CHECK: compact encoding: 0x04000000
+// CHECK: Entry at offset 0x20:
+// CHECK: start: 0x[[#%x,G:]] _g
+// CHECK: length: 0x1
+// CHECK: compact encoding: 0x04000000
+
+// CHECK: .eh_frame contents:
+// CHECK: 00000000 00000014 00000000 CIE
+// CHECK: Format: DWARF32
+// CHECK: Version: 1
+// CHECK: Augmentation: "zR"
+// CHECK: Code alignment factor: 1
+// CHECK: Data alignment factor: -8
+// CHECK: Return address column: 16
+// CHECK: Augmentation data: 10
+
+// CHECK: FDE cie=00000000 pc=[[#%.8x,F]]...
+// CHECK: Format: DWARF32
+// CHECK: DW_CFA_GNU_args_size: +16
+
+// CHECK: FDE cie=00000000 pc=[[#%.8x,G]]...
+// CHECK: Format: DWARF32
+// CHECK: DW_CFA_GNU_args_size: +16