1*c34698a8SPavel 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"
57ebe9cc4SMed Ismail Bennani #include "lldb/Target/Process.h"
67ebe9cc4SMed Ismail Bennani #include "lldb/Target/StackFrameList.h"
77ebe9cc4SMed Ismail Bennani #include "lldb/Target/Target.h"
87ebe9cc4SMed Ismail Bennani #include "lldb/Target/Thread.h"
9*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
107ebe9cc4SMed Ismail Bennani 
117ebe9cc4SMed Ismail Bennani using namespace llvm;
127ebe9cc4SMed Ismail Bennani using namespace lldb;
137ebe9cc4SMed Ismail Bennani using namespace lldb_private;
147ebe9cc4SMed Ismail Bennani 
157ebe9cc4SMed Ismail Bennani namespace lldb_private {
166b2979c1SDavide Italiano 
17cb0c4ee3SMed Ismail Bennani /// Stores a function module spec, symbol name and possibly an alternate symbol
18cb0c4ee3SMed Ismail Bennani /// name.
19cb0c4ee3SMed Ismail Bennani struct SymbolLocation {
20cb0c4ee3SMed Ismail Bennani   FileSpec module_spec;
21db31e2e1SMed Ismail Bennani   std::vector<ConstString> symbols;
22e825c244SJan Kratochvil 
23e825c244SJan Kratochvil   // The symbols are regular expressions. In such case all symbols are matched
24e825c244SJan Kratochvil   // with their trailing @VER symbol version stripped.
25e825c244SJan Kratochvil   bool symbols_are_regex = false;
26cb0c4ee3SMed Ismail Bennani };
276b2979c1SDavide Italiano 
287ebe9cc4SMed Ismail Bennani /// Fetches the abort frame location depending on the current platform.
297ebe9cc4SMed Ismail Bennani ///
30cb0c4ee3SMed Ismail Bennani /// \param[in] os
31cb0c4ee3SMed Ismail Bennani ///    The target's os type.
32cb0c4ee3SMed Ismail Bennani /// \param[in,out] location
33cb0c4ee3SMed Ismail Bennani ///    The struct that will contain the abort module spec and symbol names.
347ebe9cc4SMed Ismail Bennani /// \return
35cb0c4ee3SMed Ismail Bennani ///    \b true, if the platform is supported
36cb0c4ee3SMed Ismail Bennani ///    \b false, otherwise.
GetAbortLocation(llvm::Triple::OSType os,SymbolLocation & location)37cb0c4ee3SMed Ismail Bennani bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) {
38cb0c4ee3SMed Ismail Bennani   switch (os) {
397ebe9cc4SMed Ismail Bennani   case llvm::Triple::Darwin:
407ebe9cc4SMed Ismail Bennani   case llvm::Triple::MacOSX:
41cb0c4ee3SMed Ismail Bennani     location.module_spec = FileSpec("libsystem_kernel.dylib");
42db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("__pthread_kill"));
437ebe9cc4SMed Ismail Bennani     break;
447ebe9cc4SMed Ismail Bennani   case llvm::Triple::Linux:
45cb0c4ee3SMed Ismail Bennani     location.module_spec = FileSpec("libc.so.6");
46db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("raise"));
47db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("__GI_raise"));
48db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("gsignal"));
49e825c244SJan Kratochvil     location.symbols.push_back(ConstString("pthread_kill"));
50e825c244SJan Kratochvil     location.symbols_are_regex = true;
517ebe9cc4SMed Ismail Bennani     break;
527ebe9cc4SMed Ismail Bennani   default:
53a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
547ebe9cc4SMed Ismail Bennani     LLDB_LOG(log, "AssertFrameRecognizer::GetAbortLocation Unsupported OS");
55cb0c4ee3SMed Ismail Bennani     return false;
567ebe9cc4SMed Ismail Bennani   }
577ebe9cc4SMed Ismail Bennani 
58cb0c4ee3SMed Ismail Bennani   return true;
597ebe9cc4SMed Ismail Bennani }
607ebe9cc4SMed Ismail Bennani 
617ebe9cc4SMed Ismail Bennani /// Fetches the assert frame location depending on the current platform.
627ebe9cc4SMed Ismail Bennani ///
63cb0c4ee3SMed Ismail Bennani /// \param[in] os
64cb0c4ee3SMed Ismail Bennani ///    The target's os type.
65cb0c4ee3SMed Ismail Bennani /// \param[in,out] location
66cb0c4ee3SMed Ismail Bennani ///    The struct that will contain the assert module spec and symbol names.
677ebe9cc4SMed Ismail Bennani /// \return
68cb0c4ee3SMed Ismail Bennani ///    \b true, if the platform is supported
69cb0c4ee3SMed Ismail Bennani ///    \b false, otherwise.
GetAssertLocation(llvm::Triple::OSType os,SymbolLocation & location)70cb0c4ee3SMed Ismail Bennani bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) {
71cb0c4ee3SMed Ismail Bennani   switch (os) {
727ebe9cc4SMed Ismail Bennani   case llvm::Triple::Darwin:
737ebe9cc4SMed Ismail Bennani   case llvm::Triple::MacOSX:
74cb0c4ee3SMed Ismail Bennani     location.module_spec = FileSpec("libsystem_c.dylib");
75db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("__assert_rtn"));
767ebe9cc4SMed Ismail Bennani     break;
777ebe9cc4SMed Ismail Bennani   case llvm::Triple::Linux:
78cb0c4ee3SMed Ismail Bennani     location.module_spec = FileSpec("libc.so.6");
79db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("__assert_fail"));
80db31e2e1SMed Ismail Bennani     location.symbols.push_back(ConstString("__GI___assert_fail"));
817ebe9cc4SMed Ismail Bennani     break;
827ebe9cc4SMed Ismail Bennani   default:
83a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Unwind);
847ebe9cc4SMed Ismail Bennani     LLDB_LOG(log, "AssertFrameRecognizer::GetAssertLocation Unsupported OS");
85cb0c4ee3SMed Ismail Bennani     return false;
867ebe9cc4SMed Ismail Bennani   }
877ebe9cc4SMed Ismail Bennani 
88cb0c4ee3SMed Ismail Bennani   return true;
897ebe9cc4SMed Ismail Bennani }
907ebe9cc4SMed Ismail Bennani 
RegisterAssertFrameRecognizer(Process * process)917ebe9cc4SMed Ismail Bennani void RegisterAssertFrameRecognizer(Process *process) {
92cb0c4ee3SMed Ismail Bennani   Target &target = process->GetTarget();
93cb0c4ee3SMed Ismail Bennani   llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
94cb0c4ee3SMed Ismail Bennani   SymbolLocation location;
957ebe9cc4SMed Ismail Bennani 
96cb0c4ee3SMed Ismail Bennani   if (!GetAbortLocation(os, location))
977ebe9cc4SMed Ismail Bennani     return;
987ebe9cc4SMed Ismail Bennani 
99e825c244SJan Kratochvil   if (!location.symbols_are_regex) {
1001b7c9eaeSRaphael Isemann     target.GetFrameRecognizerManager().AddRecognizer(
101e825c244SJan Kratochvil         std::make_shared<AssertFrameRecognizer>(),
102db31e2e1SMed Ismail Bennani         location.module_spec.GetFilename(), location.symbols,
103cb0c4ee3SMed Ismail Bennani         /*first_instruction_only*/ false);
104e825c244SJan Kratochvil     return;
105e825c244SJan Kratochvil   }
106e825c244SJan Kratochvil   std::string module_re = "^";
107e825c244SJan Kratochvil   for (char c : location.module_spec.GetFilename().GetStringRef()) {
108e825c244SJan Kratochvil     if (c == '.')
109e825c244SJan Kratochvil       module_re += '\\';
110e825c244SJan Kratochvil     module_re += c;
111e825c244SJan Kratochvil   }
112e825c244SJan Kratochvil   module_re += '$';
113e825c244SJan Kratochvil   std::string symbol_re = "^(";
114e825c244SJan Kratochvil   for (auto it = location.symbols.cbegin(); it != location.symbols.cend();
115e825c244SJan Kratochvil        ++it) {
116e825c244SJan Kratochvil     if (it != location.symbols.cbegin())
117e825c244SJan Kratochvil       symbol_re += '|';
118e825c244SJan Kratochvil     symbol_re += it->GetStringRef();
119e825c244SJan Kratochvil   }
120e825c244SJan Kratochvil   // Strip the trailing @VER symbol version.
121e825c244SJan Kratochvil   symbol_re += ")(@.*)?$";
122e825c244SJan Kratochvil   target.GetFrameRecognizerManager().AddRecognizer(
123e825c244SJan Kratochvil       std::make_shared<AssertFrameRecognizer>(),
124e825c244SJan Kratochvil       std::make_shared<RegularExpression>(std::move(module_re)),
125e825c244SJan Kratochvil       std::make_shared<RegularExpression>(std::move(symbol_re)),
126e825c244SJan Kratochvil       /*first_instruction_only*/ false);
1277ebe9cc4SMed Ismail Bennani }
1287ebe9cc4SMed Ismail Bennani 
1297ebe9cc4SMed Ismail Bennani } // namespace lldb_private
1307ebe9cc4SMed Ismail Bennani 
1317ebe9cc4SMed Ismail Bennani lldb::RecognizedStackFrameSP
RecognizeFrame(lldb::StackFrameSP frame_sp)1327ebe9cc4SMed Ismail Bennani AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) {
1337ebe9cc4SMed Ismail Bennani   ThreadSP thread_sp = frame_sp->GetThread();
1347ebe9cc4SMed Ismail Bennani   ProcessSP process_sp = thread_sp->GetProcess();
135cb0c4ee3SMed Ismail Bennani   Target &target = process_sp->GetTarget();
136cb0c4ee3SMed Ismail Bennani   llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS();
137cb0c4ee3SMed Ismail Bennani   SymbolLocation location;
1387ebe9cc4SMed Ismail Bennani 
139cb0c4ee3SMed Ismail Bennani   if (!GetAssertLocation(os, location))
1407ebe9cc4SMed Ismail Bennani     return RecognizedStackFrameSP();
1417ebe9cc4SMed Ismail Bennani 
142e825c244SJan Kratochvil   const uint32_t frames_to_fetch = 6;
1437ebe9cc4SMed Ismail Bennani   const uint32_t last_frame_index = frames_to_fetch - 1;
1447ebe9cc4SMed Ismail Bennani   StackFrameSP prev_frame_sp = nullptr;
1457ebe9cc4SMed Ismail Bennani 
1467ebe9cc4SMed Ismail Bennani   // Fetch most relevant frame
1477ebe9cc4SMed Ismail Bennani   for (uint32_t frame_index = 0; frame_index < frames_to_fetch; frame_index++) {
1487ebe9cc4SMed Ismail Bennani     prev_frame_sp = thread_sp->GetStackFrameAtIndex(frame_index);
1497ebe9cc4SMed Ismail Bennani 
1507ebe9cc4SMed Ismail Bennani     if (!prev_frame_sp) {
151a007a6d8SPavel Labath       Log *log = GetLog(LLDBLog::Unwind);
1527ebe9cc4SMed Ismail Bennani       LLDB_LOG(log, "Abort Recognizer: Hit unwinding bound ({1} frames)!",
1537ebe9cc4SMed Ismail Bennani                frames_to_fetch);
1547ebe9cc4SMed Ismail Bennani       break;
1557ebe9cc4SMed Ismail Bennani     }
1567ebe9cc4SMed Ismail Bennani 
1577ebe9cc4SMed Ismail Bennani     SymbolContext sym_ctx =
1587ebe9cc4SMed Ismail Bennani         prev_frame_sp->GetSymbolContext(eSymbolContextEverything);
1597ebe9cc4SMed Ismail Bennani 
1605a4b2e15SJim Ingham     if (!sym_ctx.module_sp ||
1615a4b2e15SJim Ingham         !sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec))
162cb0c4ee3SMed Ismail Bennani       continue;
163cb0c4ee3SMed Ismail Bennani 
164cb0c4ee3SMed Ismail Bennani     ConstString func_name = sym_ctx.GetFunctionName();
165cb0c4ee3SMed Ismail Bennani 
166db31e2e1SMed Ismail Bennani     if (llvm::is_contained(location.symbols, func_name)) {
1677ebe9cc4SMed Ismail Bennani       // We go a frame beyond the assert location because the most relevant
1687ebe9cc4SMed Ismail Bennani       // frame for the user is the one in which the assert function was called.
1697ebe9cc4SMed Ismail Bennani       // If the assert location is the last frame fetched, then it is set as
1707ebe9cc4SMed Ismail Bennani       // the most relevant frame.
1717ebe9cc4SMed Ismail Bennani 
1727ebe9cc4SMed Ismail Bennani       StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(
1737ebe9cc4SMed Ismail Bennani           std::min(frame_index + 1, last_frame_index));
1747ebe9cc4SMed Ismail Bennani 
1757ebe9cc4SMed Ismail Bennani       // Pass assert location to AbortRecognizedStackFrame to set as most
1767ebe9cc4SMed Ismail Bennani       // relevant frame.
1777ebe9cc4SMed Ismail Bennani       return lldb::RecognizedStackFrameSP(
1787ebe9cc4SMed Ismail Bennani           new AssertRecognizedStackFrame(most_relevant_frame_sp));
1797ebe9cc4SMed Ismail Bennani     }
1807ebe9cc4SMed Ismail Bennani   }
1817ebe9cc4SMed Ismail Bennani 
1827ebe9cc4SMed Ismail Bennani   return RecognizedStackFrameSP();
18317d0091dSMed Ismail Bennani }
1847ebe9cc4SMed Ismail Bennani 
AssertRecognizedStackFrame(StackFrameSP most_relevant_frame_sp)1857ebe9cc4SMed Ismail Bennani AssertRecognizedStackFrame::AssertRecognizedStackFrame(
1867ebe9cc4SMed Ismail Bennani     StackFrameSP most_relevant_frame_sp)
1877ebe9cc4SMed Ismail Bennani     : m_most_relevant_frame(most_relevant_frame_sp) {
1887ebe9cc4SMed Ismail Bennani   m_stop_desc = "hit program assert";
1897ebe9cc4SMed Ismail Bennani }
1907ebe9cc4SMed Ismail Bennani 
GetMostRelevantFrame()1917ebe9cc4SMed Ismail Bennani lldb::StackFrameSP AssertRecognizedStackFrame::GetMostRelevantFrame() {
1927ebe9cc4SMed Ismail Bennani   return m_most_relevant_frame;
1937ebe9cc4SMed Ismail Bennani }
194