138 lines · cpp
1#include "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 15using namespace llvm;16using namespace lldb;17using namespace lldb_private;18 19/// The 0th frame is the artificial inline frame generated to store20/// the verbose_trap message. So, starting with the current parent frame,21/// find the first frame that's not inside of the STL.22static StackFrameSP FindMostRelevantFrame(Thread &selected_thread) {23 // Defensive upper-bound of when we stop walking up the frames in24 // case we somehow ended up looking at an infinite recursion.25 const size_t max_stack_depth = 128;26 27 // Start at parent frame.28 size_t stack_idx = 1;29 StackFrameSP most_relevant_frame_sp =30 selected_thread.GetStackFrameAtIndex(stack_idx);31 32 while (most_relevant_frame_sp && stack_idx <= max_stack_depth) {33 auto const &sc =34 most_relevant_frame_sp->GetSymbolContext(eSymbolContextEverything);35 ConstString frame_name = sc.GetFunctionName();36 if (!frame_name)37 return nullptr;38 39 // Found a frame outside of the `std` namespace. That's the40 // first frame in user-code that ended up triggering the41 // 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;44 45 ++stack_idx;46 most_relevant_frame_sp = selected_thread.GetStackFrameAtIndex(stack_idx);47 }48 49 return nullptr;50}51 52VerboseTrapRecognizedStackFrame::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);56}57 58lldb::RecognizedStackFrameSP59VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {60 if (frame_sp->GetFrameIndex())61 return {};62 63 ThreadSP thread_sp = frame_sp->GetThread();64 ProcessSP process_sp = thread_sp->GetProcess();65 66 StackFrameSP most_relevant_frame_sp = FindMostRelevantFrame(*thread_sp);67 68 if (!most_relevant_frame_sp) {69 Log *log = GetLog(LLDBLog::Unwind);70 LLDB_LOG(71 log,72 "Failed to find most relevant frame: Hit unwinding bound (1 frame)!");73 return {};74 }75 76 SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything);77 78 if (!sc.block)79 return {};80 81 // The runtime error is set as the function name in the inlined function info82 // of frame #0 by the compiler83 const InlineFunctionInfo *inline_info = nullptr;84 Block *inline_block = sc.block->GetContainingInlinedBlock();85 86 if (!inline_block)87 return {};88 89 inline_info = sc.block->GetInlinedFunctionInfo();90 91 if (!inline_info)92 return {};93 94 auto func_name = inline_info->GetName().GetStringRef();95 if (func_name.empty())96 return {};97 98 auto maybe_trap_reason =99 clang::CodeGen::DemangleTrapReasonInDebugInfo(func_name);100 if (!maybe_trap_reason.has_value()) {101 LLDB_LOGF(GetLog(LLDBLog::Unwind), "Failed to demangle '%s' as trap reason",102 func_name.str().c_str());103 return {};104 }105 auto [category, message] = maybe_trap_reason.value();106 107 std::string stop_reason =108 category.empty() ? "<empty category>" : category.str();109 if (!message.empty()) {110 stop_reason += ": ";111 stop_reason += message.str();112 }113 114 return std::make_shared<VerboseTrapRecognizedStackFrame>(115 most_relevant_frame_sp, std::move(stop_reason));116}117 118lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() {119 return m_most_relevant_frame;120}121 122namespace lldb_private {123 124void RegisterVerboseTrapFrameRecognizer(Process &process) {125 RegularExpressionSP module_regex_sp = nullptr;126 auto symbol_regex_sp = std::make_shared<RegularExpression>(127 llvm::formatv("^{0}", ClangTrapPrefix).str());128 129 StackFrameRecognizerSP srf_recognizer_sp =130 std::make_shared<VerboseTrapFrameRecognizer>();131 132 process.GetTarget().GetFrameRecognizerManager().AddRecognizer(133 srf_recognizer_sp, module_regex_sp, symbol_regex_sp,134 Mangled::ePreferDemangled, false);135}136 137} // namespace lldb_private138