1 #include "lldb/Target/AssertFrameRecognizer.h" 2 #include "lldb/Core/Module.h" 3 #include "lldb/Symbol/Function.h" 4 #include "lldb/Symbol/SymbolContext.h" 5 #include "lldb/Symbol/SymbolLocation.h" 6 #include "lldb/Target/Process.h" 7 #include "lldb/Target/StackFrameList.h" 8 #include "lldb/Target/Target.h" 9 #include "lldb/Target/Thread.h" 10 #include "lldb/Utility/LLDBLog.h" 11 12 using namespace llvm; 13 using namespace lldb; 14 using namespace lldb_private; 15 16 namespace lldb_private { 17 /// Fetches the abort frame location depending on the current platform. 18 /// 19 /// \param[in] os 20 /// The target's os type. 21 /// \param[in,out] location 22 /// The struct that will contain the abort module spec and symbol names. 23 /// \return 24 /// \b true, if the platform is supported 25 /// \b false, otherwise. 26 bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { 27 switch (os) { 28 case llvm::Triple::Darwin: 29 case llvm::Triple::MacOSX: 30 location.module_spec = FileSpec("libsystem_kernel.dylib"); 31 location.symbols.push_back(ConstString("__pthread_kill")); 32 break; 33 case llvm::Triple::Linux: 34 location.module_spec = FileSpec("libc.so.6"); 35 location.symbols.push_back(ConstString("raise")); 36 location.symbols.push_back(ConstString("__GI_raise")); 37 location.symbols.push_back(ConstString("gsignal")); 38 location.symbols.push_back(ConstString("pthread_kill")); 39 location.symbols_are_regex = true; 40 break; 41 default: 42 Log *log = GetLog(LLDBLog::Unwind); 43 LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS"); 44 return false; 45 } 46 47 return true; 48 } 49 50 /// Fetches the assert frame location depending on the current platform. 51 /// 52 /// \param[in] os 53 /// The target's os type. 54 /// \param[in,out] location 55 /// The struct that will contain the assert module spec and symbol names. 56 /// \return 57 /// \b true, if the platform is supported 58 /// \b false, otherwise. 59 bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { 60 switch (os) { 61 case llvm::Triple::Darwin: 62 case llvm::Triple::MacOSX: 63 location.module_spec = FileSpec("libsystem_c.dylib"); 64 location.symbols.push_back(ConstString("__assert_rtn")); 65 break; 66 case llvm::Triple::Linux: 67 location.module_spec = FileSpec("libc.so.6"); 68 location.symbols.push_back(ConstString("__assert_fail")); 69 location.symbols.push_back(ConstString("__GI___assert_fail")); 70 break; 71 default: 72 Log *log = GetLog(LLDBLog::Unwind); 73 LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS"); 74 return false; 75 } 76 77 return true; 78 } 79 80 void RegisterAssertFrameRecognizer(Process *process) { 81 Target &target = process->GetTarget(); 82 llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); 83 SymbolLocation location; 84 85 if (!GetAbortLocation(os, location)) 86 return; 87 88 if (!location.symbols_are_regex) { 89 target.GetFrameRecognizerManager().AddRecognizer( 90 std::make_shared<AssertFrameRecognizer>(), 91 location.module_spec.GetFilename(), location.symbols, 92 /*first_instruction_only*/ false); 93 return; 94 } 95 std::string module_re = "^"; 96 for (char c : location.module_spec.GetFilename().GetStringRef()) { 97 if (c == '.') 98 module_re += '\\'; 99 module_re += c; 100 } 101 module_re += '$'; 102 std::string symbol_re = "^("; 103 for (auto it = location.symbols.cbegin(); it != location.symbols.cend(); 104 ++it) { 105 if (it != location.symbols.cbegin()) 106 symbol_re += '|'; 107 symbol_re += it->GetStringRef(); 108 } 109 // Strip the trailing @VER symbol version. 110 symbol_re += ")(@.*)?$"; 111 target.GetFrameRecognizerManager().AddRecognizer( 112 std::make_shared<AssertFrameRecognizer>(), 113 std::make_shared<RegularExpression>(std::move(module_re)), 114 std::make_shared<RegularExpression>(std::move(symbol_re)), 115 /*first_instruction_only*/ false); 116 } 117 118 } // namespace lldb_private 119 120 lldb::RecognizedStackFrameSP 121 AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 122 ThreadSP thread_sp = frame_sp->GetThread(); 123 ProcessSP process_sp = thread_sp->GetProcess(); 124 Target &target = process_sp->GetTarget(); 125 llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); 126 SymbolLocation location; 127 128 if (!GetAssertLocation(os, location)) 129 return RecognizedStackFrameSP(); 130 131 const uint32_t frames_to_fetch = 6; 132 const uint32_t last_frame_index = frames_to_fetch - 1; 133 StackFrameSP prev_frame_sp = nullptr; 134 135 // Fetch most relevant frame 136 for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) { 137 prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index); 138 139 if (!prev_frame_sp) { 140 Log *log = GetLog(LLDBLog::Unwind); 141 LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!", 142 frames_to_fetch); 143 break; 144 } 145 146 SymbolContext sym_ctx = 147 prev_frame_sp->GetSymbolContext(eSymbolContextEverything); 148 149 if (!sym_ctx.module_sp || 150 !sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec)) 151 continue; 152 153 ConstString func_name = sym_ctx.GetFunctionName(); 154 155 if (llvm::is_contained(location.symbols, func_name)) { 156 // We go a frame beyond the assert location because the most relevant 157 // frame for the user is the one in which the assert function was called. 158 // If the assert location is the last frame fetched, then it is set as 159 // the most relevant frame. 160 161 StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex( 162 std::min(frame_index + 1, last_frame_index)); 163 164 // Pass assert location to AbortRecognizedStackFrame to set as most 165 // relevant frame. 166 return lldb::RecognizedStackFrameSP( 167 new AssertRecognizedStackFrame(most_relevant_frame_sp)); 168 } 169 } 170 171 return RecognizedStackFrameSP(); 172 } 173 174 AssertRecognizedStackFrame::AssertRecognizedStackFrame( 175 StackFrameSP most_relevant_frame_sp) 176 : m_most_relevant_frame(most_relevant_frame_sp) { 177 m_stop_desc = "hit program assert"; 178 } 179 180 lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() { 181 return m_most_relevant_frame; 182 } 183