diff --git a/lldb/docs/use/formatting.rst b/lldb/docs/use/formatting.rst index 939c4e18f74990..e2644d50217b31 100644 --- a/lldb/docs/use/formatting.rst +++ b/lldb/docs/use/formatting.rst @@ -134,7 +134,9 @@ A complete list of currently supported format string variables is listed below: +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``thread.queue`` | The queue name of the thread if the target OS supports dispatch queues | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``thread.stop-reason`` | A textual reason each thread stopped | +| ``thread.stop-reason`` | A textual reason why the thread stopped. If the thread have a recognized frame, this displays its recognized stop reason. Otherwise, gets the stop info description. | ++---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``thread.stop-reason-raw`` | A textual reason why the thread stopped. Always returns stop info description. | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``thread.return-value`` | The return value of the latest step operation (currently only for step-out.) | +---------------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h index 8ee320b0ebb1c5..106b0706ebf903 100644 --- a/lldb/include/lldb/Core/FormatEntity.h +++ b/lldb/include/lldb/Core/FormatEntity.h @@ -61,6 +61,7 @@ class FormatEntity { ThreadName, ThreadQueue, ThreadStopReason, + ThreadStopReasonRaw, ThreadReturnValue, ThreadCompletedExpression, ScriptThread, diff --git a/lldb/include/lldb/Target/AssertFrameRecognizer.h b/lldb/include/lldb/Target/AssertFrameRecognizer.h new file mode 100644 index 00000000000000..4acfefa9edfb0b --- /dev/null +++ b/lldb/include/lldb/Target/AssertFrameRecognizer.h @@ -0,0 +1,55 @@ +//===-- AssertFrameRecognizer.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. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AssertFrameRecognizer_h_ +#define liblldb_AssertFrameRecognizer_h_ + +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrameRecognizer.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" + +#include + +namespace lldb_private { + +/// Registers the assert stack frame recognizer. +/// +/// \param[in] process +/// The process that is currently asserting. This will give us information on +/// the target and the platform. +void RegisterAssertFrameRecognizer(Process *process); + +/// \class AssertRecognizedStackFrame +/// +/// Holds the stack frame where the assert is called from. +class AssertRecognizedStackFrame : public RecognizedStackFrame { +public: + AssertRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp); + lldb::StackFrameSP GetMostRelevantFrame() override; + llvm::StringRef GetStopDescription() override; + +private: + lldb::StackFrameSP m_most_relevant_frame; +}; + +/// \class AssertFrameRecognizer +/// +/// When a thread stops, it checks depending on the platform if the top frame is +/// an abort stack frame. If so, it looks for an assert stack frame in the upper +/// frames and set it as the most relavant frame when found. +class AssertFrameRecognizer : public StackFrameRecognizer { +public: + std::string GetName() override { return "Assert StackFrame Recognizer"; } + lldb::RecognizedStackFrameSP + RecognizeFrame(lldb::StackFrameSP frame_sp) override; +}; + +} // namespace lldb_private + +#endif // liblldb_AssertFrameRecognizer_h_ diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 2021ac5215f389..59febd5c1f4eca 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -12,6 +12,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Target/StopInfo.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" @@ -33,6 +34,8 @@ class RecognizedStackFrame virtual lldb::ValueObjectSP GetExceptionObject() { return lldb::ValueObjectSP(); } + virtual lldb::StackFrameSP GetMostRelevantFrame() { return nullptr; }; + virtual llvm::StringRef GetStopDescription() { return ""; } virtual ~RecognizedStackFrame(){}; protected: diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index cdc8d39251c6c5..1a24e2c2fc6c1a 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -216,6 +216,12 @@ class Thread : public std::enable_shared_from_this, virtual void RefreshStateAfterStop() = 0; + void SelectMostRelevantFrame(); + + llvm::StringRef GetStopDescription(); + + llvm::StringRef GetStopDescriptionRaw(); + void WillStop(); bool ShouldStop(Event *event_ptr); diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py b/lldb/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py index 36fdc862294801..ab81bde771d1ff 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/inferior-assert/TestInferiorAssert.py @@ -104,12 +104,13 @@ def set_breakpoint(self, line): def check_stop_reason(self): matched = lldbplatformutil.match_android_device( self.getArchitecture(), valid_api_levels=list(range(1, 16 + 1))) - if matched: - # On android until API-16 the abort() call ended in a sigsegv - # instead of in a sigabrt - stop_reason = 'stop reason = signal SIGSEGV' - else: - stop_reason = 'stop reason = signal SIGABRT' + + target = self.dbg.GetTargetAtIndex(0) + process = target.GetProcess() + + thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonSignal) + + stop_reason = 'stop reason = ' + thread.GetStopDescription(256) # The stop reason of the thread should be an abort signal or exception. self.expect("thread list", STOPPED_DUE_TO_ASSERT, @@ -173,6 +174,22 @@ def inferior_asserting_registers(self): self.runCmd("run", RUN_SUCCEEDED) self.check_stop_reason() + # change current frame to frame 0, since recognizer might have selected + # different frame. + target = self.dbg.GetTargetAtIndex(0) + self.assertTrue(target, VALID_TARGET) + + process = target.GetProcess() + self.assertTrue(process.IsValid(), "current process is valid") + + thread = process.GetSelectedThread() + self.assertTrue(thread.IsValid(), "current thread is valid") + + thread.SetSelectedFrame(0) + frame = thread.GetSelectedFrame() + + self.assertTrue(thread.GetFrameAtIndex(0) == frame, "Frame #0 selected") + # lldb should be able to read from registers from the inferior after # asserting. lldbplatformutil.check_first_register_readable(self) diff --git a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py index ce9ee8e027ffb6..f7d18e626e0147 100644 --- a/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py +++ b/lldb/packages/Python/lldbsuite/test/lang/objc/exceptions/TestObjCExceptions.py @@ -25,8 +25,8 @@ def test_objc_exceptions_at_throw(self): launch_info = lldb.SBLaunchInfo(["a.out", "0"]) lldbutil.run_to_name_breakpoint(self, "objc_exception_throw", launch_info=launch_info) - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', 'stop reason = breakpoint']) + self.expect("thread list", + substrs=['stopped', 'stop reason = hit Objective-C exception']) self.expect('thread exception', substrs=[ '(NSException *) exception = ', diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index f90e93130960a6..9516d72da04728 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -325,7 +325,8 @@ size_t SBThread::GetStopDescription(char *dst, size_t dst_len) { StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo(); if (stop_info_sp) { - const char *stop_desc = stop_info_sp->GetDescription(); + const char *stop_desc = + exe_ctx.GetThreadPtr()->GetStopDescription().data(); if (stop_desc) { if (dst) return ::snprintf(dst, dst_len, "%s", stop_desc); diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index 4d43df9c3a6396..e47f109eb41a20 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -166,6 +166,7 @@ static FormatEntity::Entry::Definition g_thread_child_entries[] = { ENTRY("queue", ThreadQueue), ENTRY("name", ThreadName), ENTRY("stop-reason", ThreadStopReason), + ENTRY("stop-reason-raw", ThreadStopReasonRaw), ENTRY("return-value", ThreadReturnValue), ENTRY("completed-expression", ThreadCompletedExpression), }; @@ -328,6 +329,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) { ENUM_TO_CSTR(ThreadName); ENUM_TO_CSTR(ThreadQueue); ENUM_TO_CSTR(ThreadStopReason); + ENUM_TO_CSTR(ThreadStopReasonRaw); ENUM_TO_CSTR(ThreadReturnValue); ENUM_TO_CSTR(ThreadCompletedExpression); ENUM_TO_CSTR(ScriptThread); @@ -1273,15 +1275,23 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, case Entry::Type::ThreadStopReason: if (exe_ctx) { - Thread *thread = exe_ctx->GetThreadPtr(); - if (thread) { - StopInfoSP stop_info_sp = thread->GetStopInfo(); - if (stop_info_sp && stop_info_sp->IsValid()) { - const char *cstr = stop_info_sp->GetDescription(); - if (cstr && cstr[0]) { - s.PutCString(cstr); - return true; - } + if (Thread *thread = exe_ctx->GetThreadPtr()) { + llvm::StringRef stop_description = thread->GetStopDescription(); + if (!stop_description.empty()) { + s.PutCString(stop_description); + return true; + } + } + } + return false; + + case Entry::Type::ThreadStopReasonRaw: + if (exe_ctx) { + if (Thread *thread = exe_ctx->GetThreadPtr()) { + llvm::StringRef stop_description = thread->GetStopDescriptionRaw(); + if (!stop_description.empty()) { + s.PutCString(stop_description); + return true; } } } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index e5c816d7eef523..beb5b13d4950ac 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -2673,6 +2673,10 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { ValueObjectSP exception; lldb::ValueObjectSP GetExceptionObject() override { return exception; } + + llvm::StringRef GetStopDescription() override { + return "hit Objective-C exception"; + } }; class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer { diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp new file mode 100644 index 00000000000000..489cba19ab1364 --- /dev/null +++ b/lldb/source/Target/AssertFrameRecognizer.cpp @@ -0,0 +1,173 @@ +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrameList.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" + +#include "lldb/Target/AssertFrameRecognizer.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +namespace lldb_private { +/// Fetches the abort frame location depending on the current platform. +/// +/// \param[in] process_sp +/// The process that is currently aborting. This will give us information on +/// the target and the platform. +/// \return +/// If the platform is supported, returns an optional tuple containing +/// the abort module as a \a FileSpec and the symbol name as a \a StringRef. +/// Otherwise, returns \a llvm::None. +llvm::Optional> +GetAbortLocation(Process *process) { + Target &target = process->GetTarget(); + + StringRef module_name; + StringRef symbol_name; + + switch (target.GetArchitecture().GetTriple().getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + module_name = "libsystem_kernel.dylib"; + symbol_name = "__pthread_kill"; + break; + case llvm::Triple::Linux: + module_name = "libc.so.6"; + symbol_name = "__GI_raise"; + break; + default: + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS"); + return llvm::None; + } + + return std::make_tuple(FileSpec(module_name), symbol_name); +} + +/// Fetches the assert frame location depending on the current platform. +/// +/// \param[in] process_sp +/// The process that is currently asserting. This will give us information on +/// the target and the platform. +/// \return +/// If the platform is supported, returns an optional tuple containing +/// the asserting frame module as a \a FileSpec and the symbol name as a \a +/// StringRef. +/// Otherwise, returns \a llvm::None. +llvm::Optional> +GetAssertLocation(Process *process) { + Target &target = process->GetTarget(); + + StringRef module_name; + StringRef symbol_name; + + switch (target.GetArchitecture().GetTriple().getOS()) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + module_name = "libsystem_c.dylib"; + symbol_name = "__assert_rtn"; + break; + case llvm::Triple::Linux: + module_name = "libc.so.6"; + symbol_name = "__GI___assert_fail"; + break; + default: + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS"); + return llvm::None; + } + + return std::make_tuple(FileSpec(module_name), symbol_name); +} + +void RegisterAssertFrameRecognizer(Process *process) { + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, [process]() { + auto abort_location = GetAbortLocation(process); + + if (!abort_location.hasValue()) + return; + + FileSpec module_spec; + StringRef function_name; + std::tie(module_spec, function_name) = *abort_location; + + StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP(new AssertFrameRecognizer()), + module_spec.GetFilename(), ConstString(function_name), false); + }); +} + +} // namespace lldb_private + +AssertRecognizedStackFrame::AssertRecognizedStackFrame( + StackFrameSP most_relevant_frame_sp) + : m_most_relevant_frame(most_relevant_frame_sp) {} + +lldb::RecognizedStackFrameSP +AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { + ThreadSP thread_sp = frame_sp->GetThread(); + ProcessSP process_sp = thread_sp->GetProcess(); + + auto assert_location = GetAssertLocation(process_sp.get()); + + if (!assert_location.hasValue()) + return RecognizedStackFrameSP(); + + FileSpec module_spec; + StringRef function_name; + std::tie(module_spec, function_name) = *assert_location; + + const uint32_t frames_to_fetch = 5; + const uint32_t last_frame_index = frames_to_fetch - 1; + StackFrameSP prev_frame_sp = nullptr; + + // Fetch most relevant frame + for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) { + prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index); + + if (!prev_frame_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); + LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!", + frames_to_fetch); + break; + } + + SymbolContext sym_ctx = + prev_frame_sp->GetSymbolContext(eSymbolContextEverything); + + if (sym_ctx.module_sp->GetFileSpec().FileEquals(module_spec) && + sym_ctx.GetFunctionName() == ConstString(function_name)) { + + // We go a frame beyond the assert location because the most relevant + // frame for the user is the one in which the assert function was called. + // If the assert location is the last frame fetched, then it is set as + // the most relevant frame. + + StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex( + std::min(frame_index + 1, last_frame_index)); + + // Pass assert location to AbortRecognizedStackFrame to set as most + // relevant frame. + return lldb::RecognizedStackFrameSP( + new AssertRecognizedStackFrame(most_relevant_frame_sp)); + } + } + + return RecognizedStackFrameSP(); +}; + +lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() { + return m_most_relevant_frame; +} + +llvm::StringRef AssertRecognizedStackFrame::GetStopDescription() { + return "hit program assert"; +} diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index 12ae2a9dd9da83..893065442e8064 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -8,6 +8,7 @@ lldb_tablegen(TargetPropertiesEnum.inc -gen-lldb-property-enum-defs add_lldb_library(lldbTarget ABI.cpp + AssertFrameRecognizer.cpp ExecutionContext.cpp InstrumentationRuntime.cpp InstrumentationRuntimeStopInfo.cpp diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index b2213d7fc962ad..9dd6af9143a0d7 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -38,6 +38,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/AssertFrameRecognizer.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/JITLoader.h" @@ -538,6 +539,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize(); if (!value_sp->OptionWasSet() && platform_cache_line_size != 0) value_sp->SetUInt64Value(platform_cache_line_size); + + RegisterAssertFrameRecognizer(this); } Process::~Process() { @@ -934,11 +937,17 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, Debugger &debugger = process_sp->GetTarget().GetDebugger(); if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget()) { + ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); + + if (!thread_sp || !thread_sp->IsValid()) + return false; + const bool only_threads_with_stop_reason = true; - const uint32_t start_frame = 0; + const uint32_t start_frame = thread_sp->GetSelectedFrameIndex(); const uint32_t num_frames = 1; const uint32_t num_frames_with_source = 1; const bool stop_format = true; + process_sp->GetStatus(*stream); process_sp->GetThreadStatus(*stream, only_threads_with_stop_reason, start_frame, num_frames, diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index fa71ef7362d973..296f2e4366f340 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -92,7 +92,7 @@ class StackFrameRecognizerManagerImpl { StackFrameRecognizerSP GetRecognizerForFrame(StackFrameSP frame) { const SymbolContext &symctx = - frame->GetSymbolContext(eSymbolContextModule | eSymbolContextFunction); + frame->GetSymbolContext(eSymbolContextEverything); ConstString function_name = symctx.GetFunctionName(); ModuleSP module_sp = symctx.module_sp; if (!module_sp) return StackFrameRecognizerSP(); diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 82930ded21a175..75df5310f48812 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -573,9 +573,64 @@ void Thread::SetState(StateType state) { m_state = state; } +llvm::StringRef Thread::GetStopDescription() { + StackFrameSP frame_sp = GetStackFrameAtIndex(0); + + if (!frame_sp) + return GetStopDescriptionRaw(); + + auto recognized_frame_sp = frame_sp->GetRecognizedFrame(); + + if (!recognized_frame_sp) + return GetStopDescriptionRaw(); + + llvm::StringRef recognized_stop_description = + recognized_frame_sp->GetStopDescription(); + + if (!recognized_stop_description.empty()) + return recognized_stop_description; + + return GetStopDescriptionRaw(); +} + +llvm::StringRef Thread::GetStopDescriptionRaw() { + StopInfoSP stop_info_sp = GetStopInfo(); + llvm::StringRef raw_stop_description; + if (stop_info_sp && stop_info_sp->IsValid()) + raw_stop_description = stop_info_sp->GetDescription(); + return raw_stop_description; +} + +void Thread::SelectMostRelevantFrame() { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD); + + auto frames_list_sp = GetStackFrameList(); + + // Only the top frame should be recognized. + auto frame_sp = frames_list_sp->GetFrameAtIndex(0); + + auto recognized_frame_sp = frame_sp->GetRecognizedFrame(); + + if (!recognized_frame_sp) { + LLDB_LOG(log, "Frame #0 not recognized"); + return; + } + + if (StackFrameSP most_relevant_frame_sp = + recognized_frame_sp->GetMostRelevantFrame()) { + LLDB_LOG(log, "Found most relevant frame at index {0}", + most_relevant_frame_sp->GetFrameIndex()); + SetSelectedFrame(most_relevant_frame_sp.get()); + } else { + LLDB_LOG(log, "No relevant frame!"); + } +} + void Thread::WillStop() { ThreadPlan *current_plan = GetCurrentPlan(); + SelectMostRelevantFrame(); + // FIXME: I may decide to disallow threads with no plans. In which // case this should go to an assert. diff --git a/lldb/test/Shell/Recognizer/Inputs/assert.c b/lldb/test/Shell/Recognizer/Inputs/assert.c new file mode 100644 index 00000000000000..61213350291521 --- /dev/null +++ b/lldb/test/Shell/Recognizer/Inputs/assert.c @@ -0,0 +1,9 @@ +#include + +int main() { + int a = 42; + assert(a == 42); + a--; + assert(a == 42); + return 0; +} diff --git a/lldb/test/Shell/Recognizer/assert.test b/lldb/test/Shell/Recognizer/assert.test new file mode 100644 index 00000000000000..9b4aa21611e0cd --- /dev/null +++ b/lldb/test/Shell/Recognizer/assert.test @@ -0,0 +1,13 @@ +# UNSUPPORTED: system-windows +# RUN: %clang_host -g -O0 %S/Inputs/assert.c -o %t.out +# RUN: %lldb -b -s %s %t.out | FileCheck %s +run +# CHECK: thread #{{.*}}stop reason = hit program assert +frame info +# CHECK: frame #{{.*}}`main at assert.c +frame recognizer info 0 +# CHECK: frame 0 is recognized by Assert StackFrame Recognizer +set set thread-format "{${thread.stop-reason-raw}}\n" +thread info +# CHECK: signal SIGABRT +q