1*0b57cec5SDimitry Andric //===-- StackFrameRecognizer.cpp ------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "lldb/Target/StackFrameRecognizer.h"
10*0b57cec5SDimitry Andric #include "lldb/Core/Module.h"
11*0b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h"
12*0b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
13*0b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
14*0b57cec5SDimitry Andric #include "lldb/Utility/RegularExpression.h"
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric using namespace lldb;
17*0b57cec5SDimitry Andric using namespace lldb_private;
18*0b57cec5SDimitry Andric 
19*0b57cec5SDimitry Andric class ScriptedRecognizedStackFrame : public RecognizedStackFrame {
20*0b57cec5SDimitry Andric public:
ScriptedRecognizedStackFrame(ValueObjectListSP args)21*0b57cec5SDimitry Andric   ScriptedRecognizedStackFrame(ValueObjectListSP args) {
22*0b57cec5SDimitry Andric     m_arguments = args;
23*0b57cec5SDimitry Andric   }
24*0b57cec5SDimitry Andric };
25*0b57cec5SDimitry Andric 
ScriptedStackFrameRecognizer(ScriptInterpreter * interpreter,const char * pclass)26*0b57cec5SDimitry Andric ScriptedStackFrameRecognizer::ScriptedStackFrameRecognizer(
27*0b57cec5SDimitry Andric     ScriptInterpreter *interpreter, const char *pclass)
28*0b57cec5SDimitry Andric     : m_interpreter(interpreter), m_python_class(pclass) {
29*0b57cec5SDimitry Andric   m_python_object_sp =
30*0b57cec5SDimitry Andric       m_interpreter->CreateFrameRecognizer(m_python_class.c_str());
31*0b57cec5SDimitry Andric }
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric RecognizedStackFrameSP
RecognizeFrame(lldb::StackFrameSP frame)34*0b57cec5SDimitry Andric ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) {
35*0b57cec5SDimitry Andric   if (!m_python_object_sp || !m_interpreter)
36*0b57cec5SDimitry Andric     return RecognizedStackFrameSP();
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric   ValueObjectListSP args =
39*0b57cec5SDimitry Andric       m_interpreter->GetRecognizedArguments(m_python_object_sp, frame);
40*0b57cec5SDimitry Andric   auto args_synthesized = ValueObjectListSP(new ValueObjectList());
41*0b57cec5SDimitry Andric   for (const auto &o : args->GetObjects()) {
42*0b57cec5SDimitry Andric     args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create(
43*0b57cec5SDimitry Andric         *o, eValueTypeVariableArgument));
44*0b57cec5SDimitry Andric   }
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric   return RecognizedStackFrameSP(
47*0b57cec5SDimitry Andric       new ScriptedRecognizedStackFrame(args_synthesized));
48*0b57cec5SDimitry Andric }
49*0b57cec5SDimitry Andric 
AddRecognizer(StackFrameRecognizerSP recognizer,ConstString module,llvm::ArrayRef<ConstString> symbols,bool first_instruction_only)50*0b57cec5SDimitry Andric void StackFrameRecognizerManager::AddRecognizer(
51*0b57cec5SDimitry Andric     StackFrameRecognizerSP recognizer, ConstString module,
52*0b57cec5SDimitry Andric     llvm::ArrayRef<ConstString> symbols, bool first_instruction_only) {
53*0b57cec5SDimitry Andric   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false,
54*0b57cec5SDimitry Andric                             module, RegularExpressionSP(), symbols,
55*0b57cec5SDimitry Andric                             RegularExpressionSP(), first_instruction_only});
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
AddRecognizer(StackFrameRecognizerSP recognizer,RegularExpressionSP module,RegularExpressionSP symbol,bool first_instruction_only)58*0b57cec5SDimitry Andric void StackFrameRecognizerManager::AddRecognizer(
59*0b57cec5SDimitry Andric     StackFrameRecognizerSP recognizer, RegularExpressionSP module,
60*0b57cec5SDimitry Andric     RegularExpressionSP symbol, bool first_instruction_only) {
61*0b57cec5SDimitry Andric   m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true,
62*0b57cec5SDimitry Andric                             ConstString(), module, std::vector<ConstString>(),
63*0b57cec5SDimitry Andric                             symbol, first_instruction_only});
64*0b57cec5SDimitry Andric }
65*0b57cec5SDimitry Andric 
ForEach(const std::function<void (uint32_t,std::string,std::string,llvm::ArrayRef<ConstString>,bool)> & callback)66*0b57cec5SDimitry Andric void StackFrameRecognizerManager::ForEach(
67*0b57cec5SDimitry Andric     const std::function<void(uint32_t, std::string, std::string,
68*0b57cec5SDimitry Andric                              llvm::ArrayRef<ConstString>, bool)> &callback) {
69*0b57cec5SDimitry Andric   for (auto entry : m_recognizers) {
70*0b57cec5SDimitry Andric     if (entry.is_regexp) {
71*0b57cec5SDimitry Andric       std::string module_name;
72*0b57cec5SDimitry Andric       std::string symbol_name;
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric       if (entry.module_regexp)
75*0b57cec5SDimitry Andric         module_name = entry.module_regexp->GetText().str();
76*0b57cec5SDimitry Andric       if (entry.symbol_regexp)
77*0b57cec5SDimitry Andric         symbol_name = entry.symbol_regexp->GetText().str();
78*0b57cec5SDimitry Andric 
79*0b57cec5SDimitry Andric       callback(entry.recognizer_id, entry.recognizer->GetName(), module_name,
80*0b57cec5SDimitry Andric                llvm::ArrayRef(ConstString(symbol_name)), true);
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric     } else {
83*0b57cec5SDimitry Andric       callback(entry.recognizer_id, entry.recognizer->GetName(),
84*0b57cec5SDimitry Andric                entry.module.GetCString(), entry.symbols, false);
85*0b57cec5SDimitry Andric     }
86*0b57cec5SDimitry Andric   }
87*0b57cec5SDimitry Andric }
88*0b57cec5SDimitry Andric 
RemoveRecognizerWithID(uint32_t recognizer_id)89*0b57cec5SDimitry Andric bool StackFrameRecognizerManager::RemoveRecognizerWithID(
90*0b57cec5SDimitry Andric     uint32_t recognizer_id) {
91*0b57cec5SDimitry Andric   if (recognizer_id >= m_recognizers.size())
92*0b57cec5SDimitry Andric     return false;
93*0b57cec5SDimitry Andric   auto found =
94*0b57cec5SDimitry Andric       llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) {
95*0b57cec5SDimitry Andric         return e.recognizer_id == recognizer_id;
96*0b57cec5SDimitry Andric       });
97*0b57cec5SDimitry Andric   if (found == m_recognizers.end())
98*0b57cec5SDimitry Andric     return false;
99*0b57cec5SDimitry Andric   m_recognizers.erase(found);
100*0b57cec5SDimitry Andric   return true;
101*0b57cec5SDimitry Andric }
102*0b57cec5SDimitry Andric 
RemoveAllRecognizers()103*0b57cec5SDimitry Andric void StackFrameRecognizerManager::RemoveAllRecognizers() {
104*0b57cec5SDimitry Andric   m_recognizers.clear();
105*0b57cec5SDimitry Andric }
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric StackFrameRecognizerSP
GetRecognizerForFrame(StackFrameSP frame)108*0b57cec5SDimitry Andric StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) {
109*0b57cec5SDimitry Andric   const SymbolContext &symctx = frame->GetSymbolContext(
110*0b57cec5SDimitry Andric       eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol);
111*0b57cec5SDimitry Andric   ConstString function_name = symctx.GetFunctionName();
112*0b57cec5SDimitry Andric   ModuleSP module_sp = symctx.module_sp;
113*0b57cec5SDimitry Andric   if (!module_sp)
114*0b57cec5SDimitry Andric     return StackFrameRecognizerSP();
115*0b57cec5SDimitry Andric   ConstString module_name = module_sp->GetFileSpec().GetFilename();
116*0b57cec5SDimitry Andric   Symbol *symbol = symctx.symbol;
117*0b57cec5SDimitry Andric   if (!symbol)
118*0b57cec5SDimitry Andric     return StackFrameRecognizerSP();
119*0b57cec5SDimitry Andric   Address start_addr = symbol->GetAddress();
120*0b57cec5SDimitry Andric   Address current_addr = frame->GetFrameCodeAddress();
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   for (auto entry : m_recognizers) {
123*0b57cec5SDimitry Andric     if (entry.module)
124*0b57cec5SDimitry Andric       if (entry.module != module_name)
125*0b57cec5SDimitry Andric         continue;
126*0b57cec5SDimitry Andric 
127*0b57cec5SDimitry Andric     if (entry.module_regexp)
128*0b57cec5SDimitry Andric       if (!entry.module_regexp->Execute(module_name.GetStringRef()))
129*0b57cec5SDimitry Andric         continue;
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric     if (!entry.symbols.empty())
132*0b57cec5SDimitry Andric       if (!llvm::is_contained(entry.symbols, function_name))
133*0b57cec5SDimitry Andric         continue;
134*0b57cec5SDimitry Andric 
135*0b57cec5SDimitry Andric     if (entry.symbol_regexp)
136*0b57cec5SDimitry Andric       if (!entry.symbol_regexp->Execute(function_name.GetStringRef()))
137*0b57cec5SDimitry Andric         continue;
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric     if (entry.first_instruction_only)
140*0b57cec5SDimitry Andric       if (start_addr != current_addr)
141*0b57cec5SDimitry Andric         continue;
142*0b57cec5SDimitry Andric 
143*0b57cec5SDimitry Andric     return entry.recognizer;
144*0b57cec5SDimitry Andric   }
145*0b57cec5SDimitry Andric   return StackFrameRecognizerSP();
146*0b57cec5SDimitry Andric }
147*0b57cec5SDimitry Andric 
148*0b57cec5SDimitry Andric RecognizedStackFrameSP
RecognizeFrame(StackFrameSP frame)149*0b57cec5SDimitry Andric StackFrameRecognizerManager::RecognizeFrame(StackFrameSP frame) {
150*0b57cec5SDimitry Andric   auto recognizer = GetRecognizerForFrame(frame);
151*0b57cec5SDimitry Andric   if (!recognizer)
152*0b57cec5SDimitry Andric     return RecognizedStackFrameSP();
153*0b57cec5SDimitry Andric   return recognizer->RecognizeFrame(frame);
154*0b57cec5SDimitry Andric }
155*0b57cec5SDimitry Andric