xref: /llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp (revision dd060bdede8edec18ad5ca122e15cc24a821e3fe)
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