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