1 //===-- ExpressionSourceCode.cpp --------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Expression/ExpressionSourceCode.h"
11 
12 #include "lldb/Core/StreamString.h"
13 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
14 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
15 #include "lldb/Symbol/CompileUnit.h"
16 #include "lldb/Symbol/DebugMacros.h"
17 #include "lldb/Symbol/Block.h"
18 #include "lldb/Symbol/TypeSystem.h"
19 #include "lldb/Symbol/VariableList.h"
20 #include "lldb/Target/ExecutionContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/Platform.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb_private;
27 
28 const char *
29 ExpressionSourceCode::g_expression_prefix = R"(
30 #ifndef NULL
31 #define NULL (__null)
32 #endif
33 #ifndef Nil
34 #define Nil (__null)
35 #endif
36 #ifndef nil
37 #define nil (__null)
38 #endif
39 #ifndef YES
40 #define YES ((BOOL)1)
41 #endif
42 #ifndef NO
43 #define NO ((BOOL)0)
44 #endif
45 typedef __INT8_TYPE__ int8_t;
46 typedef __UINT8_TYPE__ uint8_t;
47 typedef __INT16_TYPE__ int16_t;
48 typedef __UINT16_TYPE__ uint16_t;
49 typedef __INT32_TYPE__ int32_t;
50 typedef __UINT32_TYPE__ uint32_t;
51 typedef __INT64_TYPE__ int64_t;
52 typedef __UINT64_TYPE__ uint64_t;
53 typedef __INTPTR_TYPE__ intptr_t;
54 typedef __UINTPTR_TYPE__ uintptr_t;
55 typedef __SIZE_TYPE__ size_t;
56 typedef __PTRDIFF_TYPE__ ptrdiff_t;
57 typedef unsigned short unichar;
58 extern "C"
59 {
60     int printf(const char * __restrict, ...);
61 }
62 )";
63 
64 static const char *c_start_marker = "    /*LLDB_BODY_START*/\n    ";
65 static const char *c_end_marker   = ";\n    /*LLDB_BODY_END*/\n";
66 
67 namespace {
68 
69 class AddMacroState
70 {
71     enum State
72     {
73         CURRENT_FILE_NOT_YET_PUSHED,
74         CURRENT_FILE_PUSHED,
75         CURRENT_FILE_POPPED
76     };
77 
78 public:
79     AddMacroState(const FileSpec &current_file, const uint32_t current_file_line)
80         : m_state(CURRENT_FILE_NOT_YET_PUSHED),
81           m_current_file(current_file),
82           m_current_file_line(current_file_line)
83     { }
84 
85     void
86     StartFile(const FileSpec &file)
87     {
88         m_file_stack.push_back(file);
89         if (file == m_current_file)
90             m_state = CURRENT_FILE_PUSHED;
91     }
92 
93     void
94     EndFile()
95     {
96         if (m_file_stack.size() == 0)
97             return;
98 
99         FileSpec old_top = m_file_stack.back();
100         m_file_stack.pop_back();
101         if (old_top == m_current_file)
102             m_state = CURRENT_FILE_POPPED;
103     }
104 
105     // An entry is valid if it occurs before the current line in
106     // the current file.
107     bool
108     IsValidEntry(uint32_t line)
109     {
110         switch (m_state)
111         {
112             case CURRENT_FILE_NOT_YET_PUSHED:
113                 return true;
114             case CURRENT_FILE_PUSHED:
115                 // If we are in file included in the current file,
116                 // the entry should be added.
117                 if (m_file_stack.back() != m_current_file)
118                     return true;
119 
120                 if (line >= m_current_file_line)
121                     return false;
122                 else
123                     return true;
124             default:
125                 return false;
126         }
127     }
128 
129 private:
130     std::vector<FileSpec> m_file_stack;
131     State m_state;
132     FileSpec m_current_file;
133     uint32_t m_current_file_line;
134 };
135 
136 } // anonymous namespace
137 
138 static void
139 AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, AddMacroState &state, StreamString &stream)
140 {
141     if (dm == nullptr)
142         return;
143 
144     for (size_t i = 0; i < dm->GetNumMacroEntries(); i++)
145     {
146         const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i);
147         uint32_t line;
148 
149         switch (entry.GetType())
150         {
151             case DebugMacroEntry::DEFINE:
152                 if (state.IsValidEntry(entry.GetLineNumber()))
153                     stream.Printf("#define %s\n", entry.GetMacroString().AsCString());
154                 else
155                     return;
156                 break;
157             case DebugMacroEntry::UNDEF:
158                 if (state.IsValidEntry(entry.GetLineNumber()))
159                     stream.Printf("#undef %s\n", entry.GetMacroString().AsCString());
160                 else
161                     return;
162                 break;
163             case DebugMacroEntry::START_FILE:
164                 line = entry.GetLineNumber();
165                 if (state.IsValidEntry(line))
166                     state.StartFile(entry.GetFileSpec(comp_unit));
167                 else
168                     return;
169                 break;
170             case DebugMacroEntry::END_FILE:
171                 state.EndFile();
172                 break;
173             case DebugMacroEntry::INDIRECT:
174                 AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream);
175                 break;
176             default:
177                 // This is an unknown/invalid entry. Ignore.
178                 break;
179         }
180     }
181 }
182 
183 static void
184 AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, StreamString &stream)
185 {
186     for (size_t i = 0; i < var_list_sp->GetSize(); i++)
187     {
188         lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
189 
190         ConstString var_name = var_sp->GetName();
191         if (!var_name || var_name == ConstString("this") || var_name == ConstString(".block_descriptor"))
192             continue;
193 
194         stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
195     }
196 }
197 
198 bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool static_method, ExecutionContext &exe_ctx) const
199 {
200     const char *target_specific_defines = "typedef signed char BOOL;\n";
201     std::string module_macros;
202 
203     Target *target = exe_ctx.GetTargetPtr();
204     if (target)
205     {
206         if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64)
207         {
208             target_specific_defines = "typedef bool BOOL;\n";
209         }
210         if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
211         {
212             if (lldb::PlatformSP platform_sp = target->GetPlatform())
213             {
214                 static ConstString g_platform_ios_simulator ("ios-simulator");
215                 if (platform_sp->GetPluginName() == g_platform_ios_simulator)
216                 {
217                     target_specific_defines = "typedef bool BOOL;\n";
218                 }
219             }
220         }
221 
222         if (ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor())
223         {
224             ClangPersistentVariables *persistent_vars = llvm::cast<ClangPersistentVariables>(target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
225             const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = persistent_vars->GetHandLoadedClangModules();
226             ClangModulesDeclVendor::ModuleVector modules_for_macros;
227 
228             for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules)
229             {
230                 modules_for_macros.push_back(module);
231             }
232 
233             if (target->GetEnableAutoImportClangModules())
234             {
235                 if (StackFrame *frame = exe_ctx.GetFramePtr())
236                 {
237                     if (Block *block = frame->GetFrameBlock())
238                     {
239                         SymbolContext sc;
240 
241                         block->CalculateSymbolContext(&sc);
242 
243                         if (sc.comp_unit)
244                         {
245                             StreamString error_stream;
246 
247                             decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros, error_stream);
248                         }
249                     }
250                 }
251             }
252 
253             decl_vendor->ForEachMacro(modules_for_macros, [&module_macros] (const std::string &expansion) -> bool {
254                 module_macros.append(expansion);
255                 module_macros.append("\n");
256                 return false;
257             });
258         }
259 
260     }
261 
262     StreamString debug_macros_stream;
263     StreamString lldb_local_var_decls;
264     if (StackFrame *frame = exe_ctx.GetFramePtr())
265     {
266         const SymbolContext &sc = frame->GetSymbolContext(
267            lldb:: eSymbolContextCompUnit | lldb::eSymbolContextLineEntry);
268 
269         if (sc.comp_unit && sc.line_entry.IsValid())
270         {
271             DebugMacros *dm = sc.comp_unit->GetDebugMacros();
272             if (dm)
273             {
274                 AddMacroState state(sc.line_entry.file, sc.line_entry.line);
275                 AddMacros(dm, sc.comp_unit, state, debug_macros_stream);
276             }
277         }
278 
279         ConstString object_name;
280         if (Language::LanguageIsCPlusPlus(frame->GetLanguage()))
281         {
282             if (target->GetInjectLocalVariables(&exe_ctx))
283             {
284                 lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true);
285                 AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
286             }
287         }
288     }
289 
290     if (m_wrap)
291     {
292         switch (wrapping_language)
293         {
294         default:
295             return false;
296         case lldb::eLanguageTypeC:
297         case lldb::eLanguageTypeC_plus_plus:
298         case lldb::eLanguageTypeObjC:
299             break;
300         }
301 
302         StreamString wrap_stream;
303 
304         wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n",
305                            module_macros.c_str(),
306                            debug_macros_stream.GetData(),
307                            g_expression_prefix,
308                            target_specific_defines,
309                            m_prefix.c_str());
310 
311         // First construct a tagged form of the user expression so we can find it later:
312         std::string tagged_body;
313         switch (wrapping_language)
314         {
315             default:
316                 tagged_body = m_body;
317                 break;
318             case lldb::eLanguageTypeC:
319             case lldb::eLanguageTypeC_plus_plus:
320             case lldb::eLanguageTypeObjC:
321                 tagged_body.append(c_start_marker);
322                 tagged_body.append(m_body);
323                 tagged_body.append(c_end_marker);
324                 break;
325 
326         }
327         switch (wrapping_language)
328         {
329         default:
330             break;
331         case lldb::eLanguageTypeC:
332             wrap_stream.Printf("void                           \n"
333                                "%s(void *$__lldb_arg)          \n"
334                                "{                              \n"
335                                "    %s;                        \n"
336                                "%s"
337                                "}                              \n",
338                                m_name.c_str(),
339                                lldb_local_var_decls.GetData(),
340                                tagged_body.c_str());
341             break;
342         case lldb::eLanguageTypeC_plus_plus:
343             wrap_stream.Printf("void                                   \n"
344                                "$__lldb_class::%s(void *$__lldb_arg)   \n"
345                                "{                                      \n"
346                                "    %s;                                \n"
347                                "%s"
348                                "}                                      \n",
349                                m_name.c_str(),
350                                lldb_local_var_decls.GetData(),
351                                tagged_body.c_str());
352             break;
353         case lldb::eLanguageTypeObjC:
354             if (static_method)
355             {
356                 wrap_stream.Printf("@interface $__lldb_objc_class ($__lldb_category)        \n"
357                                    "+(void)%s:(void *)$__lldb_arg;                          \n"
358                                    "@end                                                    \n"
359                                    "@implementation $__lldb_objc_class ($__lldb_category)   \n"
360                                    "+(void)%s:(void *)$__lldb_arg                           \n"
361                                    "{                                                       \n"
362                                    "%s"
363                                    "}                                                       \n"
364                                    "@end                                                    \n",
365                                    m_name.c_str(),
366                                    m_name.c_str(),
367                                    tagged_body.c_str());
368             }
369             else
370             {
371                 wrap_stream.Printf("@interface $__lldb_objc_class ($__lldb_category)       \n"
372                                    "-(void)%s:(void *)$__lldb_arg;                         \n"
373                                    "@end                                                   \n"
374                                    "@implementation $__lldb_objc_class ($__lldb_category)  \n"
375                                    "-(void)%s:(void *)$__lldb_arg                          \n"
376                                    "{                                                      \n"
377                                    "%s"
378                                    "}                                                      \n"
379                                    "@end                                                   \n",
380                                    m_name.c_str(),
381                                    m_name.c_str(),
382                                    tagged_body.c_str());
383             }
384             break;
385         }
386 
387         text = wrap_stream.GetString();
388     }
389     else
390     {
391         text.append(m_body);
392     }
393 
394     return true;
395 }
396 
397 bool
398 ExpressionSourceCode::GetOriginalBodyBounds(std::string transformed_text,
399                                             lldb::LanguageType wrapping_language,
400                                             size_t &start_loc,
401                                             size_t &end_loc)
402 {
403     const char *start_marker;
404     const char *end_marker;
405 
406     switch (wrapping_language)
407     {
408     default:
409         return false;
410     case lldb::eLanguageTypeC:
411     case lldb::eLanguageTypeC_plus_plus:
412     case lldb::eLanguageTypeObjC:
413         start_marker = c_start_marker;
414         end_marker = c_end_marker;
415         break;
416     }
417 
418     start_loc = transformed_text.find(start_marker);
419     if (start_loc == std::string::npos)
420         return false;
421     start_loc += strlen(start_marker);
422     end_loc  = transformed_text.find(end_marker);
423     if (end_loc == std::string::npos)
424         return false;
425     return true;
426 }
427 
428