xref: /freebsd-src/contrib/llvm-project/lldb/source/Target/VerboseTrapFrameRecognizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric #include "lldb/Target/VerboseTrapFrameRecognizer.h"
2*0fca6ea1SDimitry Andric 
3*0fca6ea1SDimitry Andric #include "lldb/Core/Module.h"
4*0fca6ea1SDimitry Andric #include "lldb/Symbol/Function.h"
5*0fca6ea1SDimitry Andric #include "lldb/Symbol/SymbolContext.h"
6*0fca6ea1SDimitry Andric #include "lldb/Target/Process.h"
7*0fca6ea1SDimitry Andric #include "lldb/Target/StackFrameRecognizer.h"
8*0fca6ea1SDimitry Andric #include "lldb/Target/Target.h"
9*0fca6ea1SDimitry Andric 
10*0fca6ea1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
11*0fca6ea1SDimitry Andric #include "lldb/Utility/Log.h"
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "clang/CodeGen/ModuleBuilder.h"
14*0fca6ea1SDimitry Andric 
15*0fca6ea1SDimitry Andric using namespace llvm;
16*0fca6ea1SDimitry Andric using namespace lldb;
17*0fca6ea1SDimitry Andric using namespace lldb_private;
18*0fca6ea1SDimitry Andric 
19*0fca6ea1SDimitry Andric VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame(
20*0fca6ea1SDimitry Andric     StackFrameSP most_relevant_frame_sp, std::string stop_desc)
21*0fca6ea1SDimitry Andric     : m_most_relevant_frame(most_relevant_frame_sp) {
22*0fca6ea1SDimitry Andric   m_stop_desc = std::move(stop_desc);
23*0fca6ea1SDimitry Andric }
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric lldb::RecognizedStackFrameSP
26*0fca6ea1SDimitry Andric VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
27*0fca6ea1SDimitry Andric   if (frame_sp->GetFrameIndex())
28*0fca6ea1SDimitry Andric     return {};
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric   ThreadSP thread_sp = frame_sp->GetThread();
31*0fca6ea1SDimitry Andric   ProcessSP process_sp = thread_sp->GetProcess();
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric   StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1);
34*0fca6ea1SDimitry Andric 
35*0fca6ea1SDimitry Andric   if (!most_relevant_frame_sp) {
36*0fca6ea1SDimitry Andric     Log *log = GetLog(LLDBLog::Unwind);
37*0fca6ea1SDimitry Andric     LLDB_LOG(
38*0fca6ea1SDimitry Andric         log,
39*0fca6ea1SDimitry Andric         "Failed to find most relevant frame: Hit unwinding bound (1 frame)!");
40*0fca6ea1SDimitry Andric     return {};
41*0fca6ea1SDimitry Andric   }
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric   SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric   if (!sc.block)
46*0fca6ea1SDimitry Andric     return {};
47*0fca6ea1SDimitry Andric 
48*0fca6ea1SDimitry Andric   // The runtime error is set as the function name in the inlined function info
49*0fca6ea1SDimitry Andric   // of frame #0 by the compiler
50*0fca6ea1SDimitry Andric   const InlineFunctionInfo *inline_info = nullptr;
51*0fca6ea1SDimitry Andric   Block *inline_block = sc.block->GetContainingInlinedBlock();
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric   if (!inline_block)
54*0fca6ea1SDimitry Andric     return {};
55*0fca6ea1SDimitry Andric 
56*0fca6ea1SDimitry Andric   inline_info = sc.block->GetInlinedFunctionInfo();
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric   if (!inline_info)
59*0fca6ea1SDimitry Andric     return {};
60*0fca6ea1SDimitry Andric 
61*0fca6ea1SDimitry Andric   auto func_name = inline_info->GetName().GetStringRef();
62*0fca6ea1SDimitry Andric   if (func_name.empty())
63*0fca6ea1SDimitry Andric     return {};
64*0fca6ea1SDimitry Andric 
65*0fca6ea1SDimitry Andric   static auto trap_regex =
66*0fca6ea1SDimitry Andric       llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str());
67*0fca6ea1SDimitry Andric   SmallVector<llvm::StringRef, 3> matches;
68*0fca6ea1SDimitry Andric   std::string regex_err_msg;
69*0fca6ea1SDimitry Andric   if (!trap_regex.match(func_name, &matches, &regex_err_msg)) {
70*0fca6ea1SDimitry Andric     LLDB_LOGF(GetLog(LLDBLog::Unwind),
71*0fca6ea1SDimitry Andric               "Failed to parse match trap regex for '%s': %s", func_name.data(),
72*0fca6ea1SDimitry Andric               regex_err_msg.c_str());
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric     return {};
75*0fca6ea1SDimitry Andric   }
76*0fca6ea1SDimitry Andric 
77*0fca6ea1SDimitry Andric   // For `__clang_trap_msg$category$message$` we expect 3 matches:
78*0fca6ea1SDimitry Andric   // 1. entire string
79*0fca6ea1SDimitry Andric   // 2. category
80*0fca6ea1SDimitry Andric   // 3. message
81*0fca6ea1SDimitry Andric   if (matches.size() != 3) {
82*0fca6ea1SDimitry Andric     LLDB_LOGF(GetLog(LLDBLog::Unwind),
83*0fca6ea1SDimitry Andric               "Unexpected function name format. Expected '<trap prefix>$<trap "
84*0fca6ea1SDimitry Andric               "category>$<trap message>'$ but got: '%s'.",
85*0fca6ea1SDimitry Andric               func_name.data());
86*0fca6ea1SDimitry Andric 
87*0fca6ea1SDimitry Andric     return {};
88*0fca6ea1SDimitry Andric   }
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric   auto category = matches[1];
91*0fca6ea1SDimitry Andric   auto message = matches[2];
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric   std::string stop_reason =
94*0fca6ea1SDimitry Andric       category.empty() ? "<empty category>" : category.str();
95*0fca6ea1SDimitry Andric   if (!message.empty()) {
96*0fca6ea1SDimitry Andric     stop_reason += ": ";
97*0fca6ea1SDimitry Andric     stop_reason += message.str();
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   return std::make_shared<VerboseTrapRecognizedStackFrame>(
101*0fca6ea1SDimitry Andric       most_relevant_frame_sp, std::move(stop_reason));
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric 
104*0fca6ea1SDimitry Andric lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() {
105*0fca6ea1SDimitry Andric   return m_most_relevant_frame;
106*0fca6ea1SDimitry Andric }
107*0fca6ea1SDimitry Andric 
108*0fca6ea1SDimitry Andric namespace lldb_private {
109*0fca6ea1SDimitry Andric 
110*0fca6ea1SDimitry Andric void RegisterVerboseTrapFrameRecognizer(Process &process) {
111*0fca6ea1SDimitry Andric   RegularExpressionSP module_regex_sp = nullptr;
112*0fca6ea1SDimitry Andric   auto symbol_regex_sp = std::make_shared<RegularExpression>(
113*0fca6ea1SDimitry Andric       llvm::formatv("^{0}", ClangTrapPrefix).str());
114*0fca6ea1SDimitry Andric 
115*0fca6ea1SDimitry Andric   StackFrameRecognizerSP srf_recognizer_sp =
116*0fca6ea1SDimitry Andric       std::make_shared<VerboseTrapFrameRecognizer>();
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric   process.GetTarget().GetFrameRecognizerManager().AddRecognizer(
119*0fca6ea1SDimitry Andric       srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false);
120*0fca6ea1SDimitry Andric }
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric } // namespace lldb_private
123