diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -352,6 +352,11 @@ /// false. bool SupportsDebugInformation = false; + /// True if target supports emitting .debug_frame unwind information when + /// ExceptionsType = ExceptionHandling::None and debug info is requested. + /// Defaults to false. + bool SupportsDebugUnwindInformation = false; + /// Exception handling format for the target. Defaults to None. ExceptionHandling ExceptionsType = ExceptionHandling::None; @@ -608,6 +613,10 @@ bool doesSupportDebugInformation() const { return SupportsDebugInformation; } + bool doesSupportDebugUnwindInformation() const { + return SupportsDebugUnwindInformation; + } + bool doesSupportExceptionHandling() const { return ExceptionsType != ExceptionHandling::None; } diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -14,6 +14,7 @@ #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" +#include "UnwindStreamer.h" #include "WasmException.h" #include "WinCFGuard.h" #include "WinException.h" @@ -135,6 +136,8 @@ static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "emit"; static const char *const DbgTimerDescription = "Debug Info Emission"; +static const char *const UnwindTimerName = "write_unwind"; +static const char *const UnwindTimerDescription = "DWARF Unwind Writer"; static const char *const EHTimerName = "write_exception"; static const char *const EHTimerDescription = "DWARF Exception Writer"; static const char *const CFGuardName = "Control Flow Guard"; @@ -321,6 +324,16 @@ } } + if (MAI->getExceptionHandlingType() == ExceptionHandling::None && + (TM.Options.ForceDwarfFrameSection || + (MMI->hasDebugInfo() && MAI->doesSupportDebugUnwindInformation()))) { + isCFIMoveForDebugging = true; + Handlers.emplace_back(std::make_unique(this), + UnwindTimerName, UnwindTimerDescription, + DWARFGroupName, DWARFGroupDescription); + return false; + } + switch (MAI->getExceptionHandlingType()) { case ExceptionHandling::SjLj: case ExceptionHandling::DwarfCFI: @@ -990,7 +1003,8 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); - if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && + if (!MAI->doesSupportDebugUnwindInformation() && + ExceptionHandlingType != ExceptionHandling::DwarfCFI && ExceptionHandlingType != ExceptionHandling::ARM) return; diff --git a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt --- a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -24,6 +24,7 @@ WinException.cpp CodeViewDebug.cpp WasmException.cpp + UnwindStreamer.cpp DEPENDS intrinsics_gen diff --git a/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h @@ -0,0 +1,50 @@ +//===- UnwindStreamer.h - Unwind Directive Streamer -------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing unwind info into assembly files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H + +#include "llvm/CodeGen/AsmPrinterHandler.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class AsmPrinter; +class MachineInstr; +class MCSymbol; + +/// Emits unwind info directives. +class LLVM_LIBRARY_VISIBILITY UnwindStreamer : public AsmPrinterHandler { +protected: + /// Target of directive emission. + AsmPrinter *Asm; + + /// Per-module flag to indicate if .debug_frame has been emitted yet. + bool HasEmittedDebugFrame = false; + +public: + UnwindStreamer(AsmPrinter *A); + ~UnwindStreamer() override; + + // Unused. + void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + void endModule() override {} + void beginInstruction(const MachineInstr *MI) override {} + void endInstruction() override {} + + void beginFunction(const MachineFunction *MF) override; + void endFunction(const MachineFunction *MF) override; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H diff --git a/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp @@ -0,0 +1,38 @@ +//===- CodeGen/AsmPrinter/UnwindStreamer.cpp - Unwind Directive Streamer --===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing unwind info into assembly files. +// +//===----------------------------------------------------------------------===// + +#include "UnwindStreamer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +namespace llvm { +class MachineFunction; +} // end namespace llvm + +UnwindStreamer::UnwindStreamer(AsmPrinter *A) : Asm(A) {} + +UnwindStreamer::~UnwindStreamer() = default; + +void UnwindStreamer::beginFunction(const MachineFunction *MF) { + assert(Asm->needsCFIMoves() == AsmPrinter::CFI_M_Debug); + if (!HasEmittedDebugFrame) { + Asm->OutStreamer->emitCFISections(false, true); + HasEmittedDebugFrame = true; + } + Asm->OutStreamer->emitCFIStartProc(/*IsSimple=*/false); +} + +void UnwindStreamer::endFunction(const MachineFunction *MF) { + Asm->OutStreamer->emitCFIEndProc(); +}