1c34698a8SPavel Labath #include "lldb/Target/AssertFrameRecognizer.h" 27ebe9cc4SMed Ismail Bennani #include "lldb/Core/Module.h" 37ebe9cc4SMed Ismail Bennani #include "lldb/Symbol/Function.h" 47ebe9cc4SMed Ismail Bennani #include "lldb/Symbol/SymbolContext.h" 51c854965SMed Ismail Bennani #include "lldb/Symbol/SymbolLocation.h" 67ebe9cc4SMed Ismail Bennani #include "lldb/Target/Process.h" 77ebe9cc4SMed Ismail Bennani #include "lldb/Target/StackFrameList.h" 87ebe9cc4SMed Ismail Bennani #include "lldb/Target/Target.h" 97ebe9cc4SMed Ismail Bennani #include "lldb/Target/Thread.h" 10c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h" 117ebe9cc4SMed Ismail Bennani 127ebe9cc4SMed Ismail Bennani using namespace llvm; 137ebe9cc4SMed Ismail Bennani using namespace lldb; 147ebe9cc4SMed Ismail Bennani using namespace lldb_private; 157ebe9cc4SMed Ismail Bennani 167ebe9cc4SMed Ismail Bennani namespace lldb_private { 177ebe9cc4SMed Ismail Bennani /// Fetches the abort frame location depending on the current platform. 187ebe9cc4SMed Ismail Bennani /// 19cb0c4ee3SMed Ismail Bennani /// \param[in] os 20cb0c4ee3SMed Ismail Bennani /// The target's os type. 21cb0c4ee3SMed Ismail Bennani /// \param[in,out] location 22cb0c4ee3SMed Ismail Bennani /// The struct that will contain the abort module spec and symbol names. 237ebe9cc4SMed Ismail Bennani /// \return 24cb0c4ee3SMed Ismail Bennani /// \b true, if the platform is supported 25cb0c4ee3SMed Ismail Bennani /// \b false, otherwise. 26cb0c4ee3SMed Ismail Bennani bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { 27cb0c4ee3SMed Ismail Bennani switch (os) { 287ebe9cc4SMed Ismail Bennani case llvm::Triple::Darwin: 297ebe9cc4SMed Ismail Bennani case llvm::Triple::MacOSX: 30cb0c4ee3SMed Ismail Bennani location.module_spec = FileSpec("libsystem_kernel.dylib"); 31db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("__pthread_kill")); 327ebe9cc4SMed Ismail Bennani break; 337ebe9cc4SMed Ismail Bennani case llvm::Triple::Linux: 34cb0c4ee3SMed Ismail Bennani location.module_spec = FileSpec("libc.so.6"); 35db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("raise")); 36db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("__GI_raise")); 37db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("gsignal")); 38e825c244SJan Kratochvil location.symbols.push_back(ConstString("pthread_kill")); 39e825c244SJan Kratochvil location.symbols_are_regex = true; 407ebe9cc4SMed Ismail Bennani break; 417ebe9cc4SMed Ismail Bennani default: 42a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Unwind); 437ebe9cc4SMed Ismail Bennani LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS"); 44cb0c4ee3SMed Ismail Bennani return false; 457ebe9cc4SMed Ismail Bennani } 467ebe9cc4SMed Ismail Bennani 47cb0c4ee3SMed Ismail Bennani return true; 487ebe9cc4SMed Ismail Bennani } 497ebe9cc4SMed Ismail Bennani 507ebe9cc4SMed Ismail Bennani /// Fetches the assert frame location depending on the current platform. 517ebe9cc4SMed Ismail Bennani /// 52cb0c4ee3SMed Ismail Bennani /// \param[in] os 53cb0c4ee3SMed Ismail Bennani /// The target's os type. 54cb0c4ee3SMed Ismail Bennani /// \param[in,out] location 55cb0c4ee3SMed Ismail Bennani /// The struct that will contain the assert module spec and symbol names. 567ebe9cc4SMed Ismail Bennani /// \return 57cb0c4ee3SMed Ismail Bennani /// \b true, if the platform is supported 58cb0c4ee3SMed Ismail Bennani /// \b false, otherwise. 59cb0c4ee3SMed Ismail Bennani bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { 60cb0c4ee3SMed Ismail Bennani switch (os) { 617ebe9cc4SMed Ismail Bennani case llvm::Triple::Darwin: 627ebe9cc4SMed Ismail Bennani case llvm::Triple::MacOSX: 63cb0c4ee3SMed Ismail Bennani location.module_spec = FileSpec("libsystem_c.dylib"); 64db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("__assert_rtn")); 657ebe9cc4SMed Ismail Bennani break; 667ebe9cc4SMed Ismail Bennani case llvm::Triple::Linux: 67cb0c4ee3SMed Ismail Bennani location.module_spec = FileSpec("libc.so.6"); 68db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("__assert_fail")); 69db31e2e1SMed Ismail Bennani location.symbols.push_back(ConstString("__GI___assert_fail")); 707ebe9cc4SMed Ismail Bennani break; 717ebe9cc4SMed Ismail Bennani default: 72a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Unwind); 737ebe9cc4SMed Ismail Bennani LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS"); 74cb0c4ee3SMed Ismail Bennani return false; 757ebe9cc4SMed Ismail Bennani } 767ebe9cc4SMed Ismail Bennani 77cb0c4ee3SMed Ismail Bennani return true; 787ebe9cc4SMed Ismail Bennani } 797ebe9cc4SMed Ismail Bennani 807ebe9cc4SMed Ismail Bennani void RegisterAssertFrameRecognizer(Process *process) { 81cb0c4ee3SMed Ismail Bennani Target &target = process->GetTarget(); 82cb0c4ee3SMed Ismail Bennani llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); 83cb0c4ee3SMed Ismail Bennani SymbolLocation location; 847ebe9cc4SMed Ismail Bennani 85cb0c4ee3SMed Ismail Bennani if (!GetAbortLocation(os, location)) 867ebe9cc4SMed Ismail Bennani return; 877ebe9cc4SMed Ismail Bennani 88e825c244SJan Kratochvil if (!location.symbols_are_regex) { 891b7c9eaeSRaphael Isemann target.GetFrameRecognizerManager().AddRecognizer( 90e825c244SJan Kratochvil std::make_shared<AssertFrameRecognizer>(), 91db31e2e1SMed Ismail Bennani location.module_spec.GetFilename(), location.symbols, 92*dd060bdeSAdrian Vogelsgesang Mangled::ePreferDemangled, 93cb0c4ee3SMed Ismail Bennani /*first_instruction_only*/ false); 94e825c244SJan Kratochvil return; 95e825c244SJan Kratochvil } 96e825c244SJan Kratochvil std::string module_re = "^"; 97e825c244SJan Kratochvil for (char c : location.module_spec.GetFilename().GetStringRef()) { 98e825c244SJan Kratochvil if (c == '.') 99e825c244SJan Kratochvil module_re += '\\'; 100e825c244SJan Kratochvil module_re += c; 101e825c244SJan Kratochvil } 102e825c244SJan Kratochvil module_re += '$'; 103e825c244SJan Kratochvil std::string symbol_re = "^("; 104e825c244SJan Kratochvil for (auto it = location.symbols.cbegin(); it != location.symbols.cend(); 105e825c244SJan Kratochvil ++it) { 106e825c244SJan Kratochvil if (it != location.symbols.cbegin()) 107e825c244SJan Kratochvil symbol_re += '|'; 108e825c244SJan Kratochvil symbol_re += it->GetStringRef(); 109e825c244SJan Kratochvil } 110e825c244SJan Kratochvil // Strip the trailing @VER symbol version. 111e825c244SJan Kratochvil symbol_re += ")(@.*)?$"; 112e825c244SJan Kratochvil target.GetFrameRecognizerManager().AddRecognizer( 113e825c244SJan Kratochvil std::make_shared<AssertFrameRecognizer>(), 114e825c244SJan Kratochvil std::make_shared<RegularExpression>(std::move(module_re)), 115e825c244SJan Kratochvil std::make_shared<RegularExpression>(std::move(symbol_re)), 116*dd060bdeSAdrian Vogelsgesang Mangled::ePreferDemangled, 117e825c244SJan Kratochvil /*first_instruction_only*/ false); 1187ebe9cc4SMed Ismail Bennani } 1197ebe9cc4SMed Ismail Bennani 1207ebe9cc4SMed Ismail Bennani } // namespace lldb_private 1217ebe9cc4SMed Ismail Bennani 1227ebe9cc4SMed Ismail Bennani lldb::RecognizedStackFrameSP 1237ebe9cc4SMed Ismail Bennani AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { 1247ebe9cc4SMed Ismail Bennani ThreadSP thread_sp = frame_sp->GetThread(); 1257ebe9cc4SMed Ismail Bennani ProcessSP process_sp = thread_sp->GetProcess(); 126cb0c4ee3SMed Ismail Bennani Target &target = process_sp->GetTarget(); 127cb0c4ee3SMed Ismail Bennani llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); 128cb0c4ee3SMed Ismail Bennani SymbolLocation location; 1297ebe9cc4SMed Ismail Bennani 130cb0c4ee3SMed Ismail Bennani if (!GetAssertLocation(os, location)) 1317ebe9cc4SMed Ismail Bennani return RecognizedStackFrameSP(); 1327ebe9cc4SMed Ismail Bennani 133e825c244SJan Kratochvil const uint32_t frames_to_fetch = 6; 1347ebe9cc4SMed Ismail Bennani const uint32_t last_frame_index = frames_to_fetch - 1; 1357ebe9cc4SMed Ismail Bennani StackFrameSP prev_frame_sp = nullptr; 1367ebe9cc4SMed Ismail Bennani 1377ebe9cc4SMed Ismail Bennani // Fetch most relevant frame 1387ebe9cc4SMed Ismail Bennani for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) { 1397ebe9cc4SMed Ismail Bennani prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index); 1407ebe9cc4SMed Ismail Bennani 1417ebe9cc4SMed Ismail Bennani if (!prev_frame_sp) { 142a007a6d8SPavel Labath Log *log = GetLog(LLDBLog::Unwind); 1437ebe9cc4SMed Ismail Bennani LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!", 1447ebe9cc4SMed Ismail Bennani frames_to_fetch); 1457ebe9cc4SMed Ismail Bennani break; 1467ebe9cc4SMed Ismail Bennani } 1477ebe9cc4SMed Ismail Bennani 1487ebe9cc4SMed Ismail Bennani SymbolContext sym_ctx = 1497ebe9cc4SMed Ismail Bennani prev_frame_sp->GetSymbolContext(eSymbolContextEverything); 1507ebe9cc4SMed Ismail Bennani 1515a4b2e15SJim Ingham if (!sym_ctx.module_sp || 1525a4b2e15SJim Ingham !sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec)) 153cb0c4ee3SMed Ismail Bennani continue; 154cb0c4ee3SMed Ismail Bennani 155cb0c4ee3SMed Ismail Bennani ConstString func_name = sym_ctx.GetFunctionName(); 156cb0c4ee3SMed Ismail Bennani 157db31e2e1SMed Ismail Bennani if (llvm::is_contained(location.symbols, func_name)) { 1587ebe9cc4SMed Ismail Bennani // We go a frame beyond the assert location because the most relevant 1597ebe9cc4SMed Ismail Bennani // frame for the user is the one in which the assert function was called. 1607ebe9cc4SMed Ismail Bennani // If the assert location is the last frame fetched, then it is set as 1617ebe9cc4SMed Ismail Bennani // the most relevant frame. 1627ebe9cc4SMed Ismail Bennani 1637ebe9cc4SMed Ismail Bennani StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex( 1647ebe9cc4SMed Ismail Bennani std::min(frame_index + 1, last_frame_index)); 1657ebe9cc4SMed Ismail Bennani 1667ebe9cc4SMed Ismail Bennani // Pass assert location to AbortRecognizedStackFrame to set as most 1677ebe9cc4SMed Ismail Bennani // relevant frame. 1687ebe9cc4SMed Ismail Bennani return lldb::RecognizedStackFrameSP( 1697ebe9cc4SMed Ismail Bennani new AssertRecognizedStackFrame(most_relevant_frame_sp)); 1707ebe9cc4SMed Ismail Bennani } 1717ebe9cc4SMed Ismail Bennani } 1727ebe9cc4SMed Ismail Bennani 1737ebe9cc4SMed Ismail Bennani return RecognizedStackFrameSP(); 17417d0091dSMed Ismail Bennani } 1757ebe9cc4SMed Ismail Bennani 1767ebe9cc4SMed Ismail Bennani AssertRecognizedStackFrame::AssertRecognizedStackFrame( 1777ebe9cc4SMed Ismail Bennani StackFrameSP most_relevant_frame_sp) 1787ebe9cc4SMed Ismail Bennani : m_most_relevant_frame(most_relevant_frame_sp) { 1797ebe9cc4SMed Ismail Bennani m_stop_desc = "hit program assert"; 1807ebe9cc4SMed Ismail Bennani } 1817ebe9cc4SMed Ismail Bennani 1827ebe9cc4SMed Ismail Bennani lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() { 1837ebe9cc4SMed Ismail Bennani return m_most_relevant_frame; 1847ebe9cc4SMed Ismail Bennani } 185