xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ClangExpressionSourceCode.cpp -------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "ClangExpressionSourceCode.h"
10061da546Spatrick 
11*f6aab3d8Srobert #include "ClangExpressionUtil.h"
12*f6aab3d8Srobert 
13061da546Spatrick #include "clang/Basic/CharInfo.h"
14dda28197Spatrick #include "clang/Basic/FileManager.h"
15061da546Spatrick #include "clang/Basic/SourceManager.h"
16061da546Spatrick #include "clang/Lex/Lexer.h"
17061da546Spatrick #include "llvm/ADT/StringRef.h"
18061da546Spatrick 
19061da546Spatrick #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
20061da546Spatrick #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
21061da546Spatrick #include "lldb/Symbol/Block.h"
22061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
23061da546Spatrick #include "lldb/Symbol/DebugMacros.h"
24061da546Spatrick #include "lldb/Symbol/TypeSystem.h"
25061da546Spatrick #include "lldb/Symbol/VariableList.h"
26061da546Spatrick #include "lldb/Target/ExecutionContext.h"
27061da546Spatrick #include "lldb/Target/Language.h"
28061da546Spatrick #include "lldb/Target/Platform.h"
29061da546Spatrick #include "lldb/Target/StackFrame.h"
30061da546Spatrick #include "lldb/Target/Target.h"
31061da546Spatrick #include "lldb/Utility/StreamString.h"
32*f6aab3d8Srobert #include "lldb/lldb-forward.h"
33061da546Spatrick 
34061da546Spatrick using namespace lldb_private;
35061da546Spatrick 
36061da546Spatrick #define PREFIX_NAME "<lldb wrapper prefix>"
37be691f3bSpatrick #define SUFFIX_NAME "<lldb wrapper suffix>"
38061da546Spatrick 
39061da546Spatrick const llvm::StringRef ClangExpressionSourceCode::g_prefix_file_name = PREFIX_NAME;
40061da546Spatrick 
41061da546Spatrick const char *ClangExpressionSourceCode::g_expression_prefix =
42061da546Spatrick "#line 1 \"" PREFIX_NAME R"("
43061da546Spatrick #ifndef offsetof
44061da546Spatrick #define offsetof(t, d) __builtin_offsetof(t, d)
45061da546Spatrick #endif
46061da546Spatrick #ifndef NULL
47061da546Spatrick #define NULL (__null)
48061da546Spatrick #endif
49061da546Spatrick #ifndef Nil
50061da546Spatrick #define Nil (__null)
51061da546Spatrick #endif
52061da546Spatrick #ifndef nil
53061da546Spatrick #define nil (__null)
54061da546Spatrick #endif
55061da546Spatrick #ifndef YES
56061da546Spatrick #define YES ((BOOL)1)
57061da546Spatrick #endif
58061da546Spatrick #ifndef NO
59061da546Spatrick #define NO ((BOOL)0)
60061da546Spatrick #endif
61061da546Spatrick typedef __INT8_TYPE__ int8_t;
62061da546Spatrick typedef __UINT8_TYPE__ uint8_t;
63061da546Spatrick typedef __INT16_TYPE__ int16_t;
64061da546Spatrick typedef __UINT16_TYPE__ uint16_t;
65061da546Spatrick typedef __INT32_TYPE__ int32_t;
66061da546Spatrick typedef __UINT32_TYPE__ uint32_t;
67061da546Spatrick typedef __INT64_TYPE__ int64_t;
68061da546Spatrick typedef __UINT64_TYPE__ uint64_t;
69061da546Spatrick typedef __INTPTR_TYPE__ intptr_t;
70061da546Spatrick typedef __UINTPTR_TYPE__ uintptr_t;
71061da546Spatrick typedef __SIZE_TYPE__ size_t;
72061da546Spatrick typedef __PTRDIFF_TYPE__ ptrdiff_t;
73061da546Spatrick typedef unsigned short unichar;
74061da546Spatrick extern "C"
75061da546Spatrick {
76061da546Spatrick     int printf(const char * __restrict, ...);
77061da546Spatrick }
78061da546Spatrick )";
79061da546Spatrick 
80be691f3bSpatrick const char *ClangExpressionSourceCode::g_expression_suffix =
81be691f3bSpatrick     "\n;\n#line 1 \"" SUFFIX_NAME "\"\n";
82be691f3bSpatrick 
83061da546Spatrick namespace {
84061da546Spatrick 
85061da546Spatrick class AddMacroState {
86061da546Spatrick   enum State {
87061da546Spatrick     CURRENT_FILE_NOT_YET_PUSHED,
88061da546Spatrick     CURRENT_FILE_PUSHED,
89061da546Spatrick     CURRENT_FILE_POPPED
90061da546Spatrick   };
91061da546Spatrick 
92061da546Spatrick public:
AddMacroState(const FileSpec & current_file,const uint32_t current_file_line)93061da546Spatrick   AddMacroState(const FileSpec &current_file, const uint32_t current_file_line)
94*f6aab3d8Srobert       : m_current_file(current_file), m_current_file_line(current_file_line) {}
95061da546Spatrick 
StartFile(const FileSpec & file)96061da546Spatrick   void StartFile(const FileSpec &file) {
97061da546Spatrick     m_file_stack.push_back(file);
98061da546Spatrick     if (file == m_current_file)
99061da546Spatrick       m_state = CURRENT_FILE_PUSHED;
100061da546Spatrick   }
101061da546Spatrick 
EndFile()102061da546Spatrick   void EndFile() {
103061da546Spatrick     if (m_file_stack.size() == 0)
104061da546Spatrick       return;
105061da546Spatrick 
106061da546Spatrick     FileSpec old_top = m_file_stack.back();
107061da546Spatrick     m_file_stack.pop_back();
108061da546Spatrick     if (old_top == m_current_file)
109061da546Spatrick       m_state = CURRENT_FILE_POPPED;
110061da546Spatrick   }
111061da546Spatrick 
112061da546Spatrick   // An entry is valid if it occurs before the current line in the current
113061da546Spatrick   // file.
IsValidEntry(uint32_t line)114061da546Spatrick   bool IsValidEntry(uint32_t line) {
115061da546Spatrick     switch (m_state) {
116061da546Spatrick     case CURRENT_FILE_NOT_YET_PUSHED:
117061da546Spatrick       return true;
118061da546Spatrick     case CURRENT_FILE_PUSHED:
119061da546Spatrick       // If we are in file included in the current file, the entry should be
120061da546Spatrick       // added.
121061da546Spatrick       if (m_file_stack.back() != m_current_file)
122061da546Spatrick         return true;
123061da546Spatrick 
124061da546Spatrick       return line < m_current_file_line;
125061da546Spatrick     default:
126061da546Spatrick       return false;
127061da546Spatrick     }
128061da546Spatrick   }
129061da546Spatrick 
130061da546Spatrick private:
131061da546Spatrick   std::vector<FileSpec> m_file_stack;
132*f6aab3d8Srobert   State m_state = CURRENT_FILE_NOT_YET_PUSHED;
133061da546Spatrick   FileSpec m_current_file;
134061da546Spatrick   uint32_t m_current_file_line;
135061da546Spatrick };
136061da546Spatrick 
137061da546Spatrick } // anonymous namespace
138061da546Spatrick 
AddMacros(const DebugMacros * dm,CompileUnit * comp_unit,AddMacroState & state,StreamString & stream)139061da546Spatrick static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit,
140061da546Spatrick                       AddMacroState &state, StreamString &stream) {
141061da546Spatrick   if (dm == nullptr)
142061da546Spatrick     return;
143061da546Spatrick 
144061da546Spatrick   for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) {
145061da546Spatrick     const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i);
146061da546Spatrick     uint32_t line;
147061da546Spatrick 
148061da546Spatrick     switch (entry.GetType()) {
149061da546Spatrick     case DebugMacroEntry::DEFINE:
150061da546Spatrick       if (state.IsValidEntry(entry.GetLineNumber()))
151061da546Spatrick         stream.Printf("#define %s\n", entry.GetMacroString().AsCString());
152061da546Spatrick       else
153061da546Spatrick         return;
154061da546Spatrick       break;
155061da546Spatrick     case DebugMacroEntry::UNDEF:
156061da546Spatrick       if (state.IsValidEntry(entry.GetLineNumber()))
157061da546Spatrick         stream.Printf("#undef %s\n", entry.GetMacroString().AsCString());
158061da546Spatrick       else
159061da546Spatrick         return;
160061da546Spatrick       break;
161061da546Spatrick     case DebugMacroEntry::START_FILE:
162061da546Spatrick       line = entry.GetLineNumber();
163061da546Spatrick       if (state.IsValidEntry(line))
164061da546Spatrick         state.StartFile(entry.GetFileSpec(comp_unit));
165061da546Spatrick       else
166061da546Spatrick         return;
167061da546Spatrick       break;
168061da546Spatrick     case DebugMacroEntry::END_FILE:
169061da546Spatrick       state.EndFile();
170061da546Spatrick       break;
171061da546Spatrick     case DebugMacroEntry::INDIRECT:
172061da546Spatrick       AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream);
173061da546Spatrick       break;
174061da546Spatrick     default:
175061da546Spatrick       // This is an unknown/invalid entry. Ignore.
176061da546Spatrick       break;
177061da546Spatrick     }
178061da546Spatrick   }
179061da546Spatrick }
180061da546Spatrick 
ClangExpressionSourceCode(llvm::StringRef filename,llvm::StringRef name,llvm::StringRef prefix,llvm::StringRef body,Wrapping wrap,WrapKind wrap_kind)181061da546Spatrick lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode(
182061da546Spatrick     llvm::StringRef filename, llvm::StringRef name, llvm::StringRef prefix,
183dda28197Spatrick     llvm::StringRef body, Wrapping wrap, WrapKind wrap_kind)
184dda28197Spatrick     : ExpressionSourceCode(name, prefix, body, wrap), m_wrap_kind(wrap_kind) {
185061da546Spatrick   // Use #line markers to pretend that we have a single-line source file
186061da546Spatrick   // containing only the user expression. This will hide our wrapper code
187061da546Spatrick   // from the user when we render diagnostics with Clang.
188061da546Spatrick   m_start_marker = "#line 1 \"" + filename.str() + "\"\n";
189be691f3bSpatrick   m_end_marker = g_expression_suffix;
190061da546Spatrick }
191061da546Spatrick 
192061da546Spatrick namespace {
193061da546Spatrick /// Allows checking if a token is contained in a given expression.
194061da546Spatrick class TokenVerifier {
195061da546Spatrick   /// The tokens we found in the expression.
196061da546Spatrick   llvm::StringSet<> m_tokens;
197061da546Spatrick 
198061da546Spatrick public:
199061da546Spatrick   TokenVerifier(std::string body);
200061da546Spatrick   /// Returns true iff the given expression body contained a token with the
201061da546Spatrick   /// given content.
hasToken(llvm::StringRef token) const202061da546Spatrick   bool hasToken(llvm::StringRef token) const {
203061da546Spatrick     return m_tokens.find(token) != m_tokens.end();
204061da546Spatrick   }
205061da546Spatrick };
206*f6aab3d8Srobert 
207*f6aab3d8Srobert // If we're evaluating from inside a lambda that captures a 'this' pointer,
208*f6aab3d8Srobert // add a "using" declaration to 'stream' for each capture used in the
209*f6aab3d8Srobert // expression (tokenized by 'verifier').
210*f6aab3d8Srobert //
211*f6aab3d8Srobert // If no 'this' capture exists, generate no using declarations. Instead
212*f6aab3d8Srobert // capture lookups will get resolved by the same mechanism as class member
213*f6aab3d8Srobert // variable lookup. That's because Clang generates an unnamed structure
214*f6aab3d8Srobert // representing the lambda closure whose members are the captured variables.
AddLambdaCaptureDecls(StreamString & stream,StackFrame * frame,TokenVerifier const & verifier)215*f6aab3d8Srobert void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame,
216*f6aab3d8Srobert                            TokenVerifier const &verifier) {
217*f6aab3d8Srobert   assert(frame);
218*f6aab3d8Srobert 
219*f6aab3d8Srobert   if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) {
220*f6aab3d8Srobert     uint32_t numChildren = thisValSP->GetNumChildren();
221*f6aab3d8Srobert     for (uint32_t i = 0; i < numChildren; ++i) {
222*f6aab3d8Srobert       auto childVal = thisValSP->GetChildAtIndex(i, true);
223*f6aab3d8Srobert       ConstString childName(childVal ? childVal->GetName() : ConstString(""));
224*f6aab3d8Srobert 
225*f6aab3d8Srobert       if (!childName.IsEmpty() && verifier.hasToken(childName.GetStringRef()) &&
226*f6aab3d8Srobert           childName != "this") {
227*f6aab3d8Srobert         stream.Printf("using $__lldb_local_vars::%s;\n",
228*f6aab3d8Srobert                       childName.GetCString());
229*f6aab3d8Srobert       }
230*f6aab3d8Srobert     }
231*f6aab3d8Srobert   }
232*f6aab3d8Srobert }
233*f6aab3d8Srobert 
234061da546Spatrick } // namespace
235061da546Spatrick 
TokenVerifier(std::string body)236061da546Spatrick TokenVerifier::TokenVerifier(std::string body) {
237061da546Spatrick   using namespace clang;
238061da546Spatrick 
239061da546Spatrick   // We only care about tokens and not their original source locations. If we
240061da546Spatrick   // move the whole expression to only be in one line we can simplify the
241061da546Spatrick   // following code that extracts the token contents.
242061da546Spatrick   std::replace(body.begin(), body.end(), '\n', ' ');
243061da546Spatrick   std::replace(body.begin(), body.end(), '\r', ' ');
244061da546Spatrick 
245061da546Spatrick   FileSystemOptions file_opts;
246061da546Spatrick   FileManager file_mgr(file_opts,
247061da546Spatrick                        FileSystem::Instance().GetVirtualFileSystem());
248061da546Spatrick 
249061da546Spatrick   // Let's build the actual source code Clang needs and setup some utility
250061da546Spatrick   // objects.
251061da546Spatrick   llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
252061da546Spatrick   llvm::IntrusiveRefCntPtr<DiagnosticOptions> diags_opts(
253061da546Spatrick       new DiagnosticOptions());
254061da546Spatrick   DiagnosticsEngine diags(diag_ids, diags_opts);
255061da546Spatrick   clang::SourceManager SM(diags, file_mgr);
256061da546Spatrick   auto buf = llvm::MemoryBuffer::getMemBuffer(body);
257061da546Spatrick 
258be691f3bSpatrick   FileID FID = SM.createFileID(buf->getMemBufferRef());
259061da546Spatrick 
260061da546Spatrick   // Let's just enable the latest ObjC and C++ which should get most tokens
261061da546Spatrick   // right.
262061da546Spatrick   LangOptions Opts;
263061da546Spatrick   Opts.ObjC = true;
264061da546Spatrick   Opts.DollarIdents = true;
265061da546Spatrick   Opts.CPlusPlus17 = true;
266061da546Spatrick   Opts.LineComment = true;
267061da546Spatrick 
268be691f3bSpatrick   Lexer lex(FID, buf->getMemBufferRef(), SM, Opts);
269061da546Spatrick 
270061da546Spatrick   Token token;
271061da546Spatrick   bool exit = false;
272061da546Spatrick   while (!exit) {
273061da546Spatrick     // Returns true if this is the last token we get from the lexer.
274061da546Spatrick     exit = lex.LexFromRawLexer(token);
275061da546Spatrick 
276061da546Spatrick     // Extract the column number which we need to extract the token content.
277061da546Spatrick     // Our expression is just one line, so we don't need to handle any line
278061da546Spatrick     // numbers here.
279061da546Spatrick     bool invalid = false;
280061da546Spatrick     unsigned start = SM.getSpellingColumnNumber(token.getLocation(), &invalid);
281061da546Spatrick     if (invalid)
282061da546Spatrick       continue;
283061da546Spatrick     // Column numbers start at 1, but indexes in our string start at 0.
284061da546Spatrick     --start;
285061da546Spatrick 
286061da546Spatrick     // Annotations don't have a length, so let's skip them.
287061da546Spatrick     if (token.isAnnotation())
288061da546Spatrick       continue;
289061da546Spatrick 
290061da546Spatrick     // Extract the token string from our source code and store it.
291061da546Spatrick     std::string token_str = body.substr(start, token.getLength());
292061da546Spatrick     if (token_str.empty())
293061da546Spatrick       continue;
294061da546Spatrick     m_tokens.insert(token_str);
295061da546Spatrick   }
296061da546Spatrick }
297061da546Spatrick 
AddLocalVariableDecls(StreamString & stream,const std::string & expr,StackFrame * frame) const298*f6aab3d8Srobert void ClangExpressionSourceCode::AddLocalVariableDecls(StreamString &stream,
299*f6aab3d8Srobert                                                       const std::string &expr,
300*f6aab3d8Srobert                                                       StackFrame *frame) const {
301*f6aab3d8Srobert   assert(frame);
302061da546Spatrick   TokenVerifier tokens(expr);
303061da546Spatrick 
304*f6aab3d8Srobert   lldb::VariableListSP var_list_sp = frame->GetInScopeVariableList(false, true);
305*f6aab3d8Srobert 
306061da546Spatrick   for (size_t i = 0; i < var_list_sp->GetSize(); i++) {
307061da546Spatrick     lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
308061da546Spatrick 
309061da546Spatrick     ConstString var_name = var_sp->GetName();
310061da546Spatrick 
311*f6aab3d8Srobert     if (var_name == "this" && m_wrap_kind == WrapKind::CppMemberFunction) {
312*f6aab3d8Srobert       AddLambdaCaptureDecls(stream, frame, tokens);
313*f6aab3d8Srobert 
314*f6aab3d8Srobert       continue;
315*f6aab3d8Srobert     }
316061da546Spatrick 
317061da546Spatrick     // We can check for .block_descriptor w/o checking for langauge since this
318061da546Spatrick     // is not a valid identifier in either C or C++.
319061da546Spatrick     if (!var_name || var_name == ".block_descriptor")
320061da546Spatrick       continue;
321061da546Spatrick 
322061da546Spatrick     if (!expr.empty() && !tokens.hasToken(var_name.GetStringRef()))
323061da546Spatrick       continue;
324061da546Spatrick 
325dda28197Spatrick     const bool is_objc = m_wrap_kind == WrapKind::ObjCInstanceMethod ||
326dda28197Spatrick                          m_wrap_kind == WrapKind::ObjCStaticMethod;
327dda28197Spatrick     if ((var_name == "self" || var_name == "_cmd") && is_objc)
328061da546Spatrick       continue;
329061da546Spatrick 
330061da546Spatrick     stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
331061da546Spatrick   }
332061da546Spatrick }
333061da546Spatrick 
GetText(std::string & text,ExecutionContext & exe_ctx,bool add_locals,bool force_add_all_locals,llvm::ArrayRef<std::string> modules) const334061da546Spatrick bool ClangExpressionSourceCode::GetText(
335dda28197Spatrick     std::string &text, ExecutionContext &exe_ctx, bool add_locals,
336dda28197Spatrick     bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const {
337061da546Spatrick   const char *target_specific_defines = "typedef signed char BOOL;\n";
338061da546Spatrick   std::string module_macros;
339be691f3bSpatrick   llvm::raw_string_ostream module_macros_stream(module_macros);
340061da546Spatrick 
341061da546Spatrick   Target *target = exe_ctx.GetTargetPtr();
342061da546Spatrick   if (target) {
343061da546Spatrick     if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64 ||
344061da546Spatrick         target->GetArchitecture().GetMachine() == llvm::Triple::aarch64_32) {
345061da546Spatrick       target_specific_defines = "typedef bool BOOL;\n";
346061da546Spatrick     }
347061da546Spatrick     if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) {
348061da546Spatrick       if (lldb::PlatformSP platform_sp = target->GetPlatform()) {
349*f6aab3d8Srobert         if (platform_sp->GetPluginName() == "ios-simulator") {
350061da546Spatrick           target_specific_defines = "typedef bool BOOL;\n";
351061da546Spatrick         }
352061da546Spatrick       }
353061da546Spatrick     }
354061da546Spatrick 
355061da546Spatrick     auto *persistent_vars = llvm::cast<ClangPersistentVariables>(
356061da546Spatrick         target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
357be691f3bSpatrick     std::shared_ptr<ClangModulesDeclVendor> decl_vendor =
358be691f3bSpatrick         persistent_vars->GetClangModulesDeclVendor();
359be691f3bSpatrick     if (decl_vendor) {
360061da546Spatrick       const ClangModulesDeclVendor::ModuleVector &hand_imported_modules =
361061da546Spatrick           persistent_vars->GetHandLoadedClangModules();
362061da546Spatrick       ClangModulesDeclVendor::ModuleVector modules_for_macros;
363061da546Spatrick 
364061da546Spatrick       for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) {
365061da546Spatrick         modules_for_macros.push_back(module);
366061da546Spatrick       }
367061da546Spatrick 
368061da546Spatrick       if (target->GetEnableAutoImportClangModules()) {
369061da546Spatrick         if (StackFrame *frame = exe_ctx.GetFramePtr()) {
370061da546Spatrick           if (Block *block = frame->GetFrameBlock()) {
371061da546Spatrick             SymbolContext sc;
372061da546Spatrick 
373061da546Spatrick             block->CalculateSymbolContext(&sc);
374061da546Spatrick 
375061da546Spatrick             if (sc.comp_unit) {
376061da546Spatrick               StreamString error_stream;
377061da546Spatrick 
378061da546Spatrick               decl_vendor->AddModulesForCompileUnit(
379061da546Spatrick                   *sc.comp_unit, modules_for_macros, error_stream);
380061da546Spatrick             }
381061da546Spatrick           }
382061da546Spatrick         }
383061da546Spatrick       }
384061da546Spatrick 
385061da546Spatrick       decl_vendor->ForEachMacro(
386061da546Spatrick           modules_for_macros,
387be691f3bSpatrick           [&module_macros_stream](llvm::StringRef token,
388be691f3bSpatrick                                   llvm::StringRef expansion) -> bool {
389be691f3bSpatrick             // Check if the macro hasn't already been defined in the
390be691f3bSpatrick             // g_expression_prefix (which defines a few builtin macros).
391be691f3bSpatrick             module_macros_stream << "#ifndef " << token << "\n";
392be691f3bSpatrick             module_macros_stream << expansion << "\n";
393be691f3bSpatrick             module_macros_stream << "#endif\n";
394061da546Spatrick             return false;
395061da546Spatrick           });
396061da546Spatrick     }
397061da546Spatrick   }
398061da546Spatrick 
399061da546Spatrick   StreamString debug_macros_stream;
400061da546Spatrick   StreamString lldb_local_var_decls;
401061da546Spatrick   if (StackFrame *frame = exe_ctx.GetFramePtr()) {
402061da546Spatrick     const SymbolContext &sc = frame->GetSymbolContext(
403061da546Spatrick         lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry);
404061da546Spatrick 
405061da546Spatrick     if (sc.comp_unit && sc.line_entry.IsValid()) {
406061da546Spatrick       DebugMacros *dm = sc.comp_unit->GetDebugMacros();
407061da546Spatrick       if (dm) {
408061da546Spatrick         AddMacroState state(sc.line_entry.file, sc.line_entry.line);
409061da546Spatrick         AddMacros(dm, sc.comp_unit, state, debug_macros_stream);
410061da546Spatrick       }
411061da546Spatrick     }
412061da546Spatrick 
413061da546Spatrick     if (add_locals)
414061da546Spatrick       if (target->GetInjectLocalVariables(&exe_ctx)) {
415*f6aab3d8Srobert         AddLocalVariableDecls(lldb_local_var_decls,
416*f6aab3d8Srobert                               force_add_all_locals ? "" : m_body, frame);
417061da546Spatrick       }
418061da546Spatrick   }
419061da546Spatrick 
420061da546Spatrick   if (m_wrap) {
421061da546Spatrick     // Generate a list of @import statements that will import the specified
422061da546Spatrick     // module into our expression.
423061da546Spatrick     std::string module_imports;
424061da546Spatrick     for (const std::string &module : modules) {
425061da546Spatrick       module_imports.append("@import ");
426061da546Spatrick       module_imports.append(module);
427061da546Spatrick       module_imports.append(";\n");
428061da546Spatrick     }
429061da546Spatrick 
430061da546Spatrick     StreamString wrap_stream;
431061da546Spatrick 
432be691f3bSpatrick     wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix,
433be691f3bSpatrick                        module_macros.c_str(), debug_macros_stream.GetData(),
434061da546Spatrick                        target_specific_defines, m_prefix.c_str());
435061da546Spatrick 
436061da546Spatrick     // First construct a tagged form of the user expression so we can find it
437061da546Spatrick     // later:
438061da546Spatrick     std::string tagged_body;
439061da546Spatrick     tagged_body.append(m_start_marker);
440061da546Spatrick     tagged_body.append(m_body);
441061da546Spatrick     tagged_body.append(m_end_marker);
442dda28197Spatrick 
443dda28197Spatrick     switch (m_wrap_kind) {
444dda28197Spatrick     case WrapKind::Function:
445061da546Spatrick       wrap_stream.Printf("%s"
446061da546Spatrick                          "void                           \n"
447061da546Spatrick                          "%s(void *$__lldb_arg)          \n"
448061da546Spatrick                          "{                              \n"
449061da546Spatrick                          "    %s;                        \n"
450061da546Spatrick                          "%s"
451061da546Spatrick                          "}                              \n",
452061da546Spatrick                          module_imports.c_str(), m_name.c_str(),
453061da546Spatrick                          lldb_local_var_decls.GetData(), tagged_body.c_str());
454061da546Spatrick       break;
455dda28197Spatrick     case WrapKind::CppMemberFunction:
456061da546Spatrick       wrap_stream.Printf("%s"
457061da546Spatrick                          "void                                   \n"
458061da546Spatrick                          "$__lldb_class::%s(void *$__lldb_arg)   \n"
459061da546Spatrick                          "{                                      \n"
460061da546Spatrick                          "    %s;                                \n"
461061da546Spatrick                          "%s"
462061da546Spatrick                          "}                                      \n",
463061da546Spatrick                          module_imports.c_str(), m_name.c_str(),
464061da546Spatrick                          lldb_local_var_decls.GetData(), tagged_body.c_str());
465061da546Spatrick       break;
466dda28197Spatrick     case WrapKind::ObjCInstanceMethod:
467061da546Spatrick       wrap_stream.Printf(
468061da546Spatrick           "%s"
469061da546Spatrick           "@interface $__lldb_objc_class ($__lldb_category)       \n"
470061da546Spatrick           "-(void)%s:(void *)$__lldb_arg;                         \n"
471061da546Spatrick           "@end                                                   \n"
472061da546Spatrick           "@implementation $__lldb_objc_class ($__lldb_category)  \n"
473061da546Spatrick           "-(void)%s:(void *)$__lldb_arg                          \n"
474061da546Spatrick           "{                                                      \n"
475061da546Spatrick           "    %s;                                                \n"
476061da546Spatrick           "%s"
477061da546Spatrick           "}                                                      \n"
478061da546Spatrick           "@end                                                   \n",
479061da546Spatrick           module_imports.c_str(), m_name.c_str(), m_name.c_str(),
480061da546Spatrick           lldb_local_var_decls.GetData(), tagged_body.c_str());
481dda28197Spatrick       break;
482dda28197Spatrick 
483dda28197Spatrick     case WrapKind::ObjCStaticMethod:
484dda28197Spatrick       wrap_stream.Printf(
485dda28197Spatrick           "%s"
486dda28197Spatrick           "@interface $__lldb_objc_class ($__lldb_category)        \n"
487dda28197Spatrick           "+(void)%s:(void *)$__lldb_arg;                          \n"
488dda28197Spatrick           "@end                                                    \n"
489dda28197Spatrick           "@implementation $__lldb_objc_class ($__lldb_category)   \n"
490dda28197Spatrick           "+(void)%s:(void *)$__lldb_arg                           \n"
491dda28197Spatrick           "{                                                       \n"
492dda28197Spatrick           "    %s;                                                 \n"
493dda28197Spatrick           "%s"
494dda28197Spatrick           "}                                                       \n"
495dda28197Spatrick           "@end                                                    \n",
496dda28197Spatrick           module_imports.c_str(), m_name.c_str(), m_name.c_str(),
497dda28197Spatrick           lldb_local_var_decls.GetData(), tagged_body.c_str());
498061da546Spatrick       break;
499061da546Spatrick     }
500061da546Spatrick 
501dda28197Spatrick     text = std::string(wrap_stream.GetString());
502061da546Spatrick   } else {
503061da546Spatrick     text.append(m_body);
504061da546Spatrick   }
505061da546Spatrick 
506061da546Spatrick   return true;
507061da546Spatrick }
508061da546Spatrick 
GetOriginalBodyBounds(std::string transformed_text,size_t & start_loc,size_t & end_loc)509061da546Spatrick bool ClangExpressionSourceCode::GetOriginalBodyBounds(
510dda28197Spatrick     std::string transformed_text, size_t &start_loc, size_t &end_loc) {
511061da546Spatrick   start_loc = transformed_text.find(m_start_marker);
512061da546Spatrick   if (start_loc == std::string::npos)
513061da546Spatrick     return false;
514061da546Spatrick   start_loc += m_start_marker.size();
515061da546Spatrick   end_loc = transformed_text.find(m_end_marker);
516061da546Spatrick   return end_loc != std::string::npos;
517061da546Spatrick }
518