Path: blob/main/contrib/llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp
39587 views
#include "lldb/Target/AssertFrameRecognizer.h"1#include "lldb/Core/Module.h"2#include "lldb/Symbol/Function.h"3#include "lldb/Symbol/SymbolContext.h"4#include "lldb/Symbol/SymbolLocation.h"5#include "lldb/Target/Process.h"6#include "lldb/Target/StackFrameList.h"7#include "lldb/Target/Target.h"8#include "lldb/Target/Thread.h"9#include "lldb/Utility/LLDBLog.h"1011using namespace llvm;12using namespace lldb;13using namespace lldb_private;1415namespace lldb_private {16/// Fetches the abort frame location depending on the current platform.17///18/// \param[in] os19/// The target's os type.20/// \param[in,out] location21/// The struct that will contain the abort module spec and symbol names.22/// \return23/// \b true, if the platform is supported24/// \b false, otherwise.25bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {26switch (os) {27case llvm::Triple::Darwin:28case llvm::Triple::MacOSX:29location.module_spec = FileSpec("libsystem_kernel.dylib");30location.symbols.push_back(ConstString("__pthread_kill"));31break;32case llvm::Triple::Linux:33location.module_spec = FileSpec("libc.so.6");34location.symbols.push_back(ConstString("raise"));35location.symbols.push_back(ConstString("__GI_raise"));36location.symbols.push_back(ConstString("gsignal"));37location.symbols.push_back(ConstString("pthread_kill"));38location.symbols_are_regex = true;39break;40default:41Log *log = GetLog(LLDBLog::Unwind);42LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS");43return false;44}4546return true;47}4849/// Fetches the assert frame location depending on the current platform.50///51/// \param[in] os52/// The target's os type.53/// \param[in,out] location54/// The struct that will contain the assert module spec and symbol names.55/// \return56/// \b true, if the platform is supported57/// \b false, otherwise.58bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {59switch (os) {60case llvm::Triple::Darwin:61case llvm::Triple::MacOSX:62location.module_spec = FileSpec("libsystem_c.dylib");63location.symbols.push_back(ConstString("__assert_rtn"));64break;65case llvm::Triple::Linux:66location.module_spec = FileSpec("libc.so.6");67location.symbols.push_back(ConstString("__assert_fail"));68location.symbols.push_back(ConstString("__GI___assert_fail"));69break;70default:71Log *log = GetLog(LLDBLog::Unwind);72LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS");73return false;74}7576return true;77}7879void RegisterAssertFrameRecognizer(Process *process) {80Target &target = process->GetTarget();81llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();82SymbolLocation location;8384if (!GetAbortLocation(os, location))85return;8687if (!location.symbols_are_regex) {88target.GetFrameRecognizerManager().AddRecognizer(89std::make_shared<AssertFrameRecognizer>(),90location.module_spec.GetFilename(), location.symbols,91/*first_instruction_only*/ false);92return;93}94std::string module_re = "^";95for (char c : location.module_spec.GetFilename().GetStringRef()) {96if (c == '.')97module_re += '\\';98module_re += c;99}100module_re += '$';101std::string symbol_re = "^(";102for (auto it = location.symbols.cbegin(); it != location.symbols.cend();103++it) {104if (it != location.symbols.cbegin())105symbol_re += '|';106symbol_re += it->GetStringRef();107}108// Strip the trailing @VER symbol version.109symbol_re += ")(@.*)?$";110target.GetFrameRecognizerManager().AddRecognizer(111std::make_shared<AssertFrameRecognizer>(),112std::make_shared<RegularExpression>(std::move(module_re)),113std::make_shared<RegularExpression>(std::move(symbol_re)),114/*first_instruction_only*/ false);115}116117} // namespace lldb_private118119lldb::RecognizedStackFrameSP120AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {121ThreadSP thread_sp = frame_sp->GetThread();122ProcessSP process_sp = thread_sp->GetProcess();123Target &target = process_sp->GetTarget();124llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();125SymbolLocation location;126127if (!GetAssertLocation(os, location))128return RecognizedStackFrameSP();129130const uint32_t frames_to_fetch = 6;131const uint32_t last_frame_index = frames_to_fetch - 1;132StackFrameSP prev_frame_sp = nullptr;133134// Fetch most relevant frame135for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) {136prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index);137138if (!prev_frame_sp) {139Log *log = GetLog(LLDBLog::Unwind);140LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!",141frames_to_fetch);142break;143}144145SymbolContext sym_ctx =146prev_frame_sp->GetSymbolContext(eSymbolContextEverything);147148if (!sym_ctx.module_sp ||149!sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec))150continue;151152ConstString func_name = sym_ctx.GetFunctionName();153154if (llvm::is_contained(location.symbols, func_name)) {155// We go a frame beyond the assert location because the most relevant156// frame for the user is the one in which the assert function was called.157// If the assert location is the last frame fetched, then it is set as158// the most relevant frame.159160StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(161std::min(frame_index + 1, last_frame_index));162163// Pass assert location to AbortRecognizedStackFrame to set as most164// relevant frame.165return lldb::RecognizedStackFrameSP(166new AssertRecognizedStackFrame(most_relevant_frame_sp));167}168}169170return RecognizedStackFrameSP();171}172173AssertRecognizedStackFrame::AssertRecognizedStackFrame(174StackFrameSP most_relevant_frame_sp)175: m_most_relevant_frame(most_relevant_frame_sp) {176m_stop_desc = "hit program assert";177}178179lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() {180return m_most_relevant_frame;181}182183184