1 #include "lldb/Target/VerboseTrapFrameRecognizer.h"
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/StackFrameRecognizer.h"
8 #include "lldb/Target/Target.h"
10 #include "lldb/Utility/LLDBLog.h"
11 #include "lldb/Utility/Log.h"
13 #include "clang/CodeGen/ModuleBuilder.h"
17 using namespace lldb_private
;
19 /// The 0th frame is the artificial inline frame generated to store
20 /// the verbose_trap message. So, starting with the current parent frame,
21 /// find the first frame that's not inside of the STL.
22 static StackFrameSP
FindMostRelevantFrame(Thread
&selected_thread
) {
23 // Defensive upper-bound of when we stop walking up the frames in
24 // case we somehow ended up looking at an infinite recursion.
25 const size_t max_stack_depth
= 128;
27 // Start at parent frame.
29 StackFrameSP most_relevant_frame_sp
=
30 selected_thread
.GetStackFrameAtIndex(stack_idx
);
32 while (most_relevant_frame_sp
&& stack_idx
<= max_stack_depth
) {
34 most_relevant_frame_sp
->GetSymbolContext(eSymbolContextEverything
);
35 ConstString frame_name
= sc
.GetFunctionName();
39 // Found a frame outside of the `std` namespace. That's the
40 // first frame in user-code that ended up triggering the
41 // verbose_trap. Hence that's the one we want to display.
42 if (!frame_name
.GetStringRef().starts_with("std::"))
43 return most_relevant_frame_sp
;
46 most_relevant_frame_sp
= selected_thread
.GetStackFrameAtIndex(stack_idx
);
52 VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame(
53 StackFrameSP most_relevant_frame_sp
, std::string stop_desc
)
54 : m_most_relevant_frame(most_relevant_frame_sp
) {
55 m_stop_desc
= std::move(stop_desc
);
58 lldb::RecognizedStackFrameSP
59 VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp
) {
60 if (frame_sp
->GetFrameIndex())
63 ThreadSP thread_sp
= frame_sp
->GetThread();
64 ProcessSP process_sp
= thread_sp
->GetProcess();
66 StackFrameSP most_relevant_frame_sp
= FindMostRelevantFrame(*thread_sp
);
68 if (!most_relevant_frame_sp
) {
69 Log
*log
= GetLog(LLDBLog::Unwind
);
72 "Failed to find most relevant frame: Hit unwinding bound (1 frame)!");
76 SymbolContext sc
= frame_sp
->GetSymbolContext(eSymbolContextEverything
);
81 // The runtime error is set as the function name in the inlined function info
82 // of frame #0 by the compiler
83 const InlineFunctionInfo
*inline_info
= nullptr;
84 Block
*inline_block
= sc
.block
->GetContainingInlinedBlock();
89 inline_info
= sc
.block
->GetInlinedFunctionInfo();
94 auto func_name
= inline_info
->GetName().GetStringRef();
95 if (func_name
.empty())
98 static auto trap_regex
=
99 llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix
).str());
100 SmallVector
<llvm::StringRef
, 3> matches
;
101 std::string regex_err_msg
;
102 if (!trap_regex
.match(func_name
, &matches
, ®ex_err_msg
)) {
103 LLDB_LOGF(GetLog(LLDBLog::Unwind
),
104 "Failed to parse match trap regex for '%s': %s", func_name
.data(),
105 regex_err_msg
.c_str());
110 // For `__clang_trap_msg$category$message$` we expect 3 matches:
114 if (matches
.size() != 3) {
115 LLDB_LOGF(GetLog(LLDBLog::Unwind
),
116 "Unexpected function name format. Expected '<trap prefix>$<trap "
117 "category>$<trap message>'$ but got: '%s'.",
123 auto category
= matches
[1];
124 auto message
= matches
[2];
126 std::string stop_reason
=
127 category
.empty() ? "<empty category>" : category
.str();
128 if (!message
.empty()) {
130 stop_reason
+= message
.str();
133 return std::make_shared
<VerboseTrapRecognizedStackFrame
>(
134 most_relevant_frame_sp
, std::move(stop_reason
));
137 lldb::StackFrameSP
VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() {
138 return m_most_relevant_frame
;
141 namespace lldb_private
{
143 void RegisterVerboseTrapFrameRecognizer(Process
&process
) {
144 RegularExpressionSP module_regex_sp
= nullptr;
145 auto symbol_regex_sp
= std::make_shared
<RegularExpression
>(
146 llvm::formatv("^{0}", ClangTrapPrefix
).str());
148 StackFrameRecognizerSP srf_recognizer_sp
=
149 std::make_shared
<VerboseTrapFrameRecognizer
>();
151 process
.GetTarget().GetFrameRecognizerManager().AddRecognizer(
152 srf_recognizer_sp
, module_regex_sp
, symbol_regex_sp
,
153 Mangled::ePreferDemangled
, false);
156 } // namespace lldb_private