Skip to content

Commit 4ffcb26

Browse files
committed
[lldb] Add frame recognizer for __builtin_verbose_trap
This patch adds a frame recognizer for Clang's `__builtin_verbose_trap`, which behaves like a `__builtin_trap`, but emits a failure-reason string into debug-info in order for debuggers to display it to a user. The frame recognizer triggers when we encounter a frame with a function name that begins with `__llvm_verbose_trap`, which is the magic prefix Clang emits into debug-info for verbose traps. Once such frame is encountered we display the frame function name as the `Stop Reason` and display that frame to the user. Example output: ``` (lldb) run warning: a.out was compiled with optimization - stepping may behave oddly; variables may not be available. Process 35942 launched: 'a.out' (arm64) Process 35942 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = __llvm_verbose_trap: Function is not implemented frame #1: 0x0000000100003fa4 a.out`main [inlined] Dummy::func(this=<unavailable>) at verbose_trap.cpp:3:5 [opt] 1 struct Dummy { 2 void func() { -> 3 __builtin_verbose_trap("Function is not implemented"); 4 } 5 }; 6 7 int main() { (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = __llvm_verbose_trap: Function is not implemented frame #0: 0x0000000100003fa4 a.out`main [inlined] __llvm_verbose_trap: Function is not implemented at verbose_trap.cpp:0 [opt] * frame #1: 0x0000000100003fa4 a.out`main [inlined] Dummy::func(this=<unavailable>) at verbose_trap.cpp:3:5 [opt] frame #2: 0x0000000100003fa4 a.out`main at verbose_trap.cpp:8:13 [opt] frame #3: 0x0000000189d518b4 dyld`start + 1988 ```
1 parent 3358838 commit 4ffcb26

File tree

6 files changed

+144
-0
lines changed

6 files changed

+144
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#ifndef LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H
2+
#define LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H
3+
4+
#include "lldb/Target/StackFrameRecognizer.h"
5+
6+
namespace lldb_private {
7+
8+
void RegisterVerboseTrapFrameRecognizer(Process &process);
9+
10+
/// Holds the stack frame that caused the Verbose trap and the inlined stop
11+
/// reason message.
12+
class VerboseTrapRecognizedStackFrame : public RecognizedStackFrame {
13+
public:
14+
VerboseTrapRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp,
15+
std::string stop_desc);
16+
17+
lldb::StackFrameSP GetMostRelevantFrame() override;
18+
19+
private:
20+
lldb::StackFrameSP m_most_relevant_frame;
21+
};
22+
23+
/// When a thread stops, it checks the current frame contains a
24+
/// Verbose Trap diagnostic. If so, it returns a \a
25+
/// VerboseTrapRecognizedStackFrame holding the diagnostic a stop reason
26+
/// description with and the parent frame as the most relavant frame.
27+
class VerboseTrapFrameRecognizer : public StackFrameRecognizer {
28+
public:
29+
std::string GetName() override {
30+
return "Verbose Trap StackFrame Recognizer";
31+
}
32+
33+
lldb::RecognizedStackFrameSP
34+
RecognizeFrame(lldb::StackFrameSP frame) override;
35+
};
36+
37+
} // namespace lldb_private
38+
39+
#endif // LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H

lldb/source/Target/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ add_lldb_library(lldbTarget
7878
UnixSignals.cpp
7979
UnwindAssembly.cpp
8080
UnwindLLDB.cpp
81+
VerboseTrapFrameRecognizer.cpp
8182

8283
LINK_LIBS
8384
lldbBreakpoint

lldb/source/Target/Process.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "lldb/Target/ThreadPlanCallFunction.h"
6464
#include "lldb/Target/ThreadPlanStack.h"
6565
#include "lldb/Target/UnixSignals.h"
66+
#include "lldb/Target/VerboseTrapFrameRecognizer.h"
6667
#include "lldb/Utility/Event.h"
6768
#include "lldb/Utility/LLDBLog.h"
6869
#include "lldb/Utility/Log.h"
@@ -497,6 +498,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
497498
value_sp->SetValueAs(platform_cache_line_size);
498499

499500
RegisterAssertFrameRecognizer(this);
501+
RegisterVerboseTrapFrameRecognizer(*this);
500502
}
501503

502504
Process::~Process() {
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "lldb/Target/VerboseTrapFrameRecognizer.h"
2+
3+
#include "lldb/Core/Module.h"
4+
#include "lldb/Symbol/Function.h"
5+
#include "lldb/Symbol/SymbolContext.h"
6+
#include "lldb/Target/Process.h"
7+
#include "lldb/Target/Target.h"
8+
9+
#include "lldb/Utility/LLDBLog.h"
10+
#include "lldb/Utility/Log.h"
11+
12+
using namespace llvm;
13+
using namespace lldb;
14+
using namespace lldb_private;
15+
16+
VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame(
17+
StackFrameSP most_relevant_frame_sp, std::string stop_desc)
18+
: m_most_relevant_frame(most_relevant_frame_sp) {
19+
m_stop_desc = std::move(stop_desc);
20+
}
21+
22+
lldb::RecognizedStackFrameSP
23+
VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
24+
if (frame_sp->GetFrameIndex())
25+
return {};
26+
27+
ThreadSP thread_sp = frame_sp->GetThread();
28+
ProcessSP process_sp = thread_sp->GetProcess();
29+
30+
StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1);
31+
32+
if (!most_relevant_frame_sp) {
33+
Log *log = GetLog(LLDBLog::Unwind);
34+
LLDB_LOG(
35+
log,
36+
"Failed to find most relevant frame: Hit unwinding bound (1 frame)!");
37+
return {};
38+
}
39+
40+
SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
41+
42+
if (!sc.block)
43+
return {};
44+
45+
// The runtime error is set as the function name in the inlined function info
46+
// of frame #0 by the compiler
47+
const InlineFunctionInfo *inline_info = nullptr;
48+
Block *inline_block = sc.block->GetContainingInlinedBlock();
49+
50+
if (!inline_block)
51+
return {};
52+
53+
inline_info = sc.block->GetInlinedFunctionInfo();
54+
55+
if (!inline_info)
56+
return {};
57+
58+
auto runtime_error = inline_info->GetName().GetString();
59+
60+
if (runtime_error.empty())
61+
return {};
62+
63+
return lldb::RecognizedStackFrameSP(new VerboseTrapRecognizedStackFrame(
64+
most_relevant_frame_sp, std::move(runtime_error)));
65+
}
66+
67+
lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() {
68+
return m_most_relevant_frame;
69+
}
70+
71+
namespace lldb_private {
72+
73+
void RegisterVerboseTrapFrameRecognizer(Process &process) {
74+
RegularExpressionSP module_regex_sp = nullptr;
75+
RegularExpressionSP symbol_regex_sp(
76+
new RegularExpression("(__llvm_verbose_trap)"));
77+
78+
StackFrameRecognizerSP srf_recognizer_sp =
79+
std::make_shared<VerboseTrapFrameRecognizer>();
80+
81+
process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
82+
srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
83+
}
84+
85+
} // namespace lldb_private
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
struct Dummy {
2+
void func() { __builtin_verbose_trap("Function is not implemented"); }
3+
};
4+
5+
int main() {
6+
Dummy{}.func();
7+
return 0;
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RUN: %clang_host -g -O0 %S/Inputs/verbose_trap.cpp -o %t.out
2+
# RUN: %lldb -b -s %s %t.out | FileCheck %s
3+
run
4+
# CHECK: thread #{{.*}}stop reason = __llvm_verbose_trap: Function is not implemented
5+
frame info
6+
# CHECK: frame #{{.*}}`Dummy::func(this={{.*}}) at verbose_trap.cpp
7+
frame recognizer info 0
8+
# CHECK: frame 0 is recognized by Verbose Trap StackFrame Recognizer
9+
q

0 commit comments

Comments
 (0)