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