Skip to content

[lldb/Plugins] Add Swift Runtime Failure Recognizer #773

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
SWIFT_SOURCES := RuntimeFailure.swift
SWIFTFLAGS_EXTRAS += -Xllvm -enable-trap-debug-info

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// RuntimeFailure.swift
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
// -----------------------------------------------------------------------------
@inline(never)
func testit(_ a: Int8) -> Int8 {
return a + 1
}

print(testit(127))
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# TestSwiftRuntimeFailureRecognizer.py
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# ------------------------------------------------------------------------------
"""
Test Swift Runtime Failure Recognizer
"""
import lldb
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbtest as lldbtest
import lldbsuite.test.lldbutil as lldbutil
import unittest2


class TestSwiftRuntimeRecognizer(lldbtest.TestBase):

mydir = lldbtest.TestBase.compute_mydir(__file__)

@swiftTest
def test_swift_runtime_recognizer(self):
"""Test Swift Runtime Failure Recognizer"""
self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"))

self.expect("frame recognizer list",
substrs=['Swift Runtime Failure StackFrame Recognizer, function Swift runtime failure (regexp)'])

self.runCmd("process launch")

self.expect("frame recognizer info 0",
substrs=['frame 0 is recognized by Swift Runtime Failure StackFrame Recognizer'])

self.expect("thread info",
substrs=['stop reason = Swift runtime failure: arithmetic overflow'])

self.expect("frame info",
patterns=['frame #1(.*)`testit(.*)at RuntimeFailure\.swift'])
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/Swift/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_lldb_library(lldbPluginSwiftLanguage PLUGIN
SwiftMetatype.cpp
SwiftOptionSet.cpp
SwiftOptional.cpp
SwiftRuntimeFailureRecognizer.cpp
SwiftSet.cpp

LINK_LIBS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "SwiftRuntimeFailureRecognizer.h"

#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"

#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h"

using namespace llvm;
using namespace lldb;
using namespace lldb_private;

SwiftRuntimeFailureRecognizedStackFrame::
SwiftRuntimeFailureRecognizedStackFrame(StackFrameSP most_relevant_frame_sp,
StringRef stop_desc)
: m_most_relevant_frame(most_relevant_frame_sp) {
m_stop_desc = stop_desc;
}

lldb::RecognizedStackFrameSP SwiftRuntimeFailureFrameRecognizer::RecognizeFrame(
lldb::StackFrameSP frame_sp) {
if (frame_sp->GetFrameIndex())
return {};

ThreadSP thread_sp = frame_sp->GetThread();
ProcessSP process_sp = thread_sp->GetProcess();

StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1);

if (!most_relevant_frame_sp) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
LLDB_LOG(
log,
"Swift Runtime Failure Recognizer: Hit unwinding bound (1 frame)!");
return {};
}

SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything);

if (!sc.block)
return {};

// The runtime error is set as the function name in the inlined function info
// of frame #0 by the compiler (https://github.com/apple/swift/pull/29506)
const InlineFunctionInfo *inline_info = nullptr;
Block *inline_block = sc.block->GetContainingInlinedBlock();

if (!inline_block)
return {};

inline_info = sc.block->GetInlinedFunctionInfo();

if (!inline_info)
return {};

StringRef runtime_error =
inline_info->GetName(sc.function->GetLanguage()).AsCString();

if (runtime_error.empty())
return {};

return lldb::RecognizedStackFrameSP(
new SwiftRuntimeFailureRecognizedStackFrame(most_relevant_frame_sp,
runtime_error));
}

lldb::StackFrameSP
SwiftRuntimeFailureRecognizedStackFrame::GetMostRelevantFrame() {
return m_most_relevant_frame;
}

namespace lldb_private {

void RegisterSwiftRuntimeFailureRecognizer() {
static llvm::once_flag g_once_flag;

llvm::call_once(g_once_flag, []() {
RegularExpressionSP module_regex_sp = nullptr;
RegularExpressionSP symbol_regex_sp(
new RegularExpression("Swift runtime failure"));

StackFrameRecognizerSP srf_recognizer_sp =
std::make_shared<SwiftRuntimeFailureFrameRecognizer>();

StackFrameRecognizerManager::AddRecognizer(
srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
});
}

} // namespace lldb_private
45 changes: 45 additions & 0 deletions lldb/source/Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===-- SwiftRuntimeFailureRecognizer.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 liblldb_SwiftRuntimeFailureRegognizer_h_
#define liblldb_SwiftRuntimeFailureRegognizer_h_

#include "lldb/Target/StackFrameRecognizer.h"

namespace lldb_private {

void RegisterSwiftRuntimeFailureRecognizer();

/// Holds the stack frame that caused the runtime failure and the inlined stop
/// reason message.
class SwiftRuntimeFailureRecognizedStackFrame : public RecognizedStackFrame {
public:
SwiftRuntimeFailureRecognizedStackFrame(
lldb::StackFrameSP most_relevant_frame_sp, llvm::StringRef stop_desc);
lldb::StackFrameSP GetMostRelevantFrame() override;

private:
lldb::StackFrameSP m_most_relevant_frame;
};

/// When a thread stops, it checks the current frame contains a swift runtime
/// failure diagnostic. If so, it returns a \a
/// SwiftRuntimeFailureRecognizedStackFrame holding the diagnostic a stop reason
/// description with and the parent frame as the most relavant frame.
class SwiftRuntimeFailureFrameRecognizer : public StackFrameRecognizer {
public:
std::string GetName() override {
return "Swift Runtime Failure StackFrame Recognizer";
}
lldb::RecognizedStackFrameSP
RecognizeFrame(lldb::StackFrameSP frame) override;
};

} // namespace lldb_private

#endif // liblldb_SwiftRuntimeFailureRegognizer_h_
2 changes: 2 additions & 0 deletions lldb/source/Target/SwiftLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@

// FIXME: we should not need this
#include "Plugins/Language/Swift/SwiftFormatters.h"
#include "Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.h"

using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -1989,6 +1990,7 @@ void SwiftLanguageRuntime::Initialize() {
return CommandObjectSP(new CommandObjectMultiwordSwift(interpreter));
},
SwiftLanguageRuntimeImpl::GetBreakpointExceptionPrecondition);
RegisterSwiftRuntimeFailureRecognizer();
}

void SwiftLanguageRuntime::Terminate() {
Expand Down