|  | //===-- ExpressionSourceCode.cpp --------------------------------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "lldb/Expression/ExpressionSourceCode.h" | 
|  |  | 
|  | #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" | 
|  | #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" | 
|  | #include "lldb/Core/StreamString.h" | 
|  | #include "lldb/Symbol/Block.h" | 
|  | #include "lldb/Symbol/CompileUnit.h" | 
|  | #include "lldb/Symbol/DebugMacros.h" | 
|  | #include "lldb/Symbol/TypeSystem.h" | 
|  | #include "lldb/Symbol/VariableList.h" | 
|  | #include "lldb/Target/ExecutionContext.h" | 
|  | #include "lldb/Target/Language.h" | 
|  | #include "lldb/Target/Platform.h" | 
|  | #include "lldb/Target/StackFrame.h" | 
|  | #include "lldb/Target/Target.h" | 
|  |  | 
|  | using namespace lldb_private; | 
|  |  | 
|  | const char *ExpressionSourceCode::g_expression_prefix = R"( | 
|  | #ifndef NULL | 
|  | #define NULL (__null) | 
|  | #endif | 
|  | #ifndef Nil | 
|  | #define Nil (__null) | 
|  | #endif | 
|  | #ifndef nil | 
|  | #define nil (__null) | 
|  | #endif | 
|  | #ifndef YES | 
|  | #define YES ((BOOL)1) | 
|  | #endif | 
|  | #ifndef NO | 
|  | #define NO ((BOOL)0) | 
|  | #endif | 
|  | typedef __INT8_TYPE__ int8_t; | 
|  | typedef __UINT8_TYPE__ uint8_t; | 
|  | typedef __INT16_TYPE__ int16_t; | 
|  | typedef __UINT16_TYPE__ uint16_t; | 
|  | typedef __INT32_TYPE__ int32_t; | 
|  | typedef __UINT32_TYPE__ uint32_t; | 
|  | typedef __INT64_TYPE__ int64_t; | 
|  | typedef __UINT64_TYPE__ uint64_t; | 
|  | typedef __INTPTR_TYPE__ intptr_t; | 
|  | typedef __UINTPTR_TYPE__ uintptr_t; | 
|  | typedef __SIZE_TYPE__ size_t; | 
|  | typedef __PTRDIFF_TYPE__ ptrdiff_t; | 
|  | typedef unsigned short unichar; | 
|  | extern "C" | 
|  | { | 
|  | int printf(const char * __restrict, ...); | 
|  | } | 
|  | )"; | 
|  |  | 
|  | static const char *c_start_marker = "    /*LLDB_BODY_START*/\n    "; | 
|  | static const char *c_end_marker = ";\n    /*LLDB_BODY_END*/\n"; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class AddMacroState { | 
|  | enum State { | 
|  | CURRENT_FILE_NOT_YET_PUSHED, | 
|  | CURRENT_FILE_PUSHED, | 
|  | CURRENT_FILE_POPPED | 
|  | }; | 
|  |  | 
|  | public: | 
|  | AddMacroState(const FileSpec ¤t_file, const uint32_t current_file_line) | 
|  | : m_state(CURRENT_FILE_NOT_YET_PUSHED), m_current_file(current_file), | 
|  | m_current_file_line(current_file_line) {} | 
|  |  | 
|  | void StartFile(const FileSpec &file) { | 
|  | m_file_stack.push_back(file); | 
|  | if (file == m_current_file) | 
|  | m_state = CURRENT_FILE_PUSHED; | 
|  | } | 
|  |  | 
|  | void EndFile() { | 
|  | if (m_file_stack.size() == 0) | 
|  | return; | 
|  |  | 
|  | FileSpec old_top = m_file_stack.back(); | 
|  | m_file_stack.pop_back(); | 
|  | if (old_top == m_current_file) | 
|  | m_state = CURRENT_FILE_POPPED; | 
|  | } | 
|  |  | 
|  | // An entry is valid if it occurs before the current line in | 
|  | // the current file. | 
|  | bool IsValidEntry(uint32_t line) { | 
|  | switch (m_state) { | 
|  | case CURRENT_FILE_NOT_YET_PUSHED: | 
|  | return true; | 
|  | case CURRENT_FILE_PUSHED: | 
|  | // If we are in file included in the current file, | 
|  | // the entry should be added. | 
|  | if (m_file_stack.back() != m_current_file) | 
|  | return true; | 
|  |  | 
|  | if (line >= m_current_file_line) | 
|  | return false; | 
|  | else | 
|  | return true; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::vector<FileSpec> m_file_stack; | 
|  | State m_state; | 
|  | FileSpec m_current_file; | 
|  | uint32_t m_current_file_line; | 
|  | }; | 
|  |  | 
|  | } // anonymous namespace | 
|  |  | 
|  | static void AddMacros(const DebugMacros *dm, CompileUnit *comp_unit, | 
|  | AddMacroState &state, StreamString &stream) { | 
|  | if (dm == nullptr) | 
|  | return; | 
|  |  | 
|  | for (size_t i = 0; i < dm->GetNumMacroEntries(); i++) { | 
|  | const DebugMacroEntry &entry = dm->GetMacroEntryAtIndex(i); | 
|  | uint32_t line; | 
|  |  | 
|  | switch (entry.GetType()) { | 
|  | case DebugMacroEntry::DEFINE: | 
|  | if (state.IsValidEntry(entry.GetLineNumber())) | 
|  | stream.Printf("#define %s\n", entry.GetMacroString().AsCString()); | 
|  | else | 
|  | return; | 
|  | break; | 
|  | case DebugMacroEntry::UNDEF: | 
|  | if (state.IsValidEntry(entry.GetLineNumber())) | 
|  | stream.Printf("#undef %s\n", entry.GetMacroString().AsCString()); | 
|  | else | 
|  | return; | 
|  | break; | 
|  | case DebugMacroEntry::START_FILE: | 
|  | line = entry.GetLineNumber(); | 
|  | if (state.IsValidEntry(line)) | 
|  | state.StartFile(entry.GetFileSpec(comp_unit)); | 
|  | else | 
|  | return; | 
|  | break; | 
|  | case DebugMacroEntry::END_FILE: | 
|  | state.EndFile(); | 
|  | break; | 
|  | case DebugMacroEntry::INDIRECT: | 
|  | AddMacros(entry.GetIndirectDebugMacros(), comp_unit, state, stream); | 
|  | break; | 
|  | default: | 
|  | // This is an unknown/invalid entry. Ignore. | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp, | 
|  | StreamString &stream) { | 
|  | for (size_t i = 0; i < var_list_sp->GetSize(); i++) { | 
|  | lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i); | 
|  |  | 
|  | ConstString var_name = var_sp->GetName(); | 
|  | if (!var_name || var_name == ConstString("this") || | 
|  | var_name == ConstString(".block_descriptor")) | 
|  | continue; | 
|  |  | 
|  | stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString()); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ExpressionSourceCode::GetText(std::string &text, | 
|  | lldb::LanguageType wrapping_language, | 
|  | bool static_method, | 
|  | ExecutionContext &exe_ctx) const { | 
|  | const char *target_specific_defines = "typedef signed char BOOL;\n"; | 
|  | std::string module_macros; | 
|  |  | 
|  | Target *target = exe_ctx.GetTargetPtr(); | 
|  | if (target) { | 
|  | if (target->GetArchitecture().GetMachine() == llvm::Triple::aarch64) { | 
|  | target_specific_defines = "typedef bool BOOL;\n"; | 
|  | } | 
|  | if (target->GetArchitecture().GetMachine() == llvm::Triple::x86_64) { | 
|  | if (lldb::PlatformSP platform_sp = target->GetPlatform()) { | 
|  | static ConstString g_platform_ios_simulator("ios-simulator"); | 
|  | if (platform_sp->GetPluginName() == g_platform_ios_simulator) { | 
|  | target_specific_defines = "typedef bool BOOL;\n"; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ClangModulesDeclVendor *decl_vendor = | 
|  | target->GetClangModulesDeclVendor()) { | 
|  | ClangPersistentVariables *persistent_vars = | 
|  | llvm::cast<ClangPersistentVariables>( | 
|  | target->GetPersistentExpressionStateForLanguage( | 
|  | lldb::eLanguageTypeC)); | 
|  | const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = | 
|  | persistent_vars->GetHandLoadedClangModules(); | 
|  | ClangModulesDeclVendor::ModuleVector modules_for_macros; | 
|  |  | 
|  | for (ClangModulesDeclVendor::ModuleID module : hand_imported_modules) { | 
|  | modules_for_macros.push_back(module); | 
|  | } | 
|  |  | 
|  | if (target->GetEnableAutoImportClangModules()) { | 
|  | if (StackFrame *frame = exe_ctx.GetFramePtr()) { | 
|  | if (Block *block = frame->GetFrameBlock()) { | 
|  | SymbolContext sc; | 
|  |  | 
|  | block->CalculateSymbolContext(&sc); | 
|  |  | 
|  | if (sc.comp_unit) { | 
|  | StreamString error_stream; | 
|  |  | 
|  | decl_vendor->AddModulesForCompileUnit( | 
|  | *sc.comp_unit, modules_for_macros, error_stream); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | decl_vendor->ForEachMacro( | 
|  | modules_for_macros, | 
|  | [&module_macros](const std::string &expansion) -> bool { | 
|  | module_macros.append(expansion); | 
|  | module_macros.append("\n"); | 
|  | return false; | 
|  | }); | 
|  | } | 
|  | } | 
|  |  | 
|  | StreamString debug_macros_stream; | 
|  | StreamString lldb_local_var_decls; | 
|  | if (StackFrame *frame = exe_ctx.GetFramePtr()) { | 
|  | const SymbolContext &sc = frame->GetSymbolContext( | 
|  | lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry); | 
|  |  | 
|  | if (sc.comp_unit && sc.line_entry.IsValid()) { | 
|  | DebugMacros *dm = sc.comp_unit->GetDebugMacros(); | 
|  | if (dm) { | 
|  | AddMacroState state(sc.line_entry.file, sc.line_entry.line); | 
|  | AddMacros(dm, sc.comp_unit, state, debug_macros_stream); | 
|  | } | 
|  | } | 
|  |  | 
|  | ConstString object_name; | 
|  | if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) { | 
|  | if (target->GetInjectLocalVariables(&exe_ctx)) { | 
|  | lldb::VariableListSP var_list_sp = | 
|  | frame->GetInScopeVariableList(false, true); | 
|  | AddLocalVariableDecls(var_list_sp, lldb_local_var_decls); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (m_wrap) { | 
|  | switch (wrapping_language) { | 
|  | default: | 
|  | return false; | 
|  | case lldb::eLanguageTypeC: | 
|  | case lldb::eLanguageTypeC_plus_plus: | 
|  | case lldb::eLanguageTypeObjC: | 
|  | break; | 
|  | } | 
|  |  | 
|  | StreamString wrap_stream; | 
|  |  | 
|  | wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), | 
|  | debug_macros_stream.GetData(), g_expression_prefix, | 
|  | target_specific_defines, m_prefix.c_str()); | 
|  |  | 
|  | // First construct a tagged form of the user expression so we can find it | 
|  | // later: | 
|  | std::string tagged_body; | 
|  | switch (wrapping_language) { | 
|  | default: | 
|  | tagged_body = m_body; | 
|  | break; | 
|  | case lldb::eLanguageTypeC: | 
|  | case lldb::eLanguageTypeC_plus_plus: | 
|  | case lldb::eLanguageTypeObjC: | 
|  | tagged_body.append(c_start_marker); | 
|  | tagged_body.append(m_body); | 
|  | tagged_body.append(c_end_marker); | 
|  | break; | 
|  | } | 
|  | switch (wrapping_language) { | 
|  | default: | 
|  | break; | 
|  | case lldb::eLanguageTypeC: | 
|  | wrap_stream.Printf("void                           \n" | 
|  | "%s(void *$__lldb_arg)          \n" | 
|  | "{                              \n" | 
|  | "    %s;                        \n" | 
|  | "%s" | 
|  | "}                              \n", | 
|  | m_name.c_str(), lldb_local_var_decls.GetData(), | 
|  | tagged_body.c_str()); | 
|  | break; | 
|  | case lldb::eLanguageTypeC_plus_plus: | 
|  | wrap_stream.Printf("void                                   \n" | 
|  | "$__lldb_class::%s(void *$__lldb_arg)   \n" | 
|  | "{                                      \n" | 
|  | "    %s;                                \n" | 
|  | "%s" | 
|  | "}                                      \n", | 
|  | m_name.c_str(), lldb_local_var_decls.GetData(), | 
|  | tagged_body.c_str()); | 
|  | break; | 
|  | case lldb::eLanguageTypeObjC: | 
|  | if (static_method) { | 
|  | wrap_stream.Printf( | 
|  | "@interface $__lldb_objc_class ($__lldb_category)        \n" | 
|  | "+(void)%s:(void *)$__lldb_arg;                          \n" | 
|  | "@end                                                    \n" | 
|  | "@implementation $__lldb_objc_class ($__lldb_category)   \n" | 
|  | "+(void)%s:(void *)$__lldb_arg                           \n" | 
|  | "{                                                       \n" | 
|  | "%s" | 
|  | "}                                                       \n" | 
|  | "@end                                                    \n", | 
|  | m_name.c_str(), m_name.c_str(), tagged_body.c_str()); | 
|  | } else { | 
|  | wrap_stream.Printf( | 
|  | "@interface $__lldb_objc_class ($__lldb_category)       \n" | 
|  | "-(void)%s:(void *)$__lldb_arg;                         \n" | 
|  | "@end                                                   \n" | 
|  | "@implementation $__lldb_objc_class ($__lldb_category)  \n" | 
|  | "-(void)%s:(void *)$__lldb_arg                          \n" | 
|  | "{                                                      \n" | 
|  | "%s" | 
|  | "}                                                      \n" | 
|  | "@end                                                   \n", | 
|  | m_name.c_str(), m_name.c_str(), tagged_body.c_str()); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | text = wrap_stream.GetString(); | 
|  | } else { | 
|  | text.append(m_body); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool ExpressionSourceCode::GetOriginalBodyBounds( | 
|  | std::string transformed_text, lldb::LanguageType wrapping_language, | 
|  | size_t &start_loc, size_t &end_loc) { | 
|  | const char *start_marker; | 
|  | const char *end_marker; | 
|  |  | 
|  | switch (wrapping_language) { | 
|  | default: | 
|  | return false; | 
|  | case lldb::eLanguageTypeC: | 
|  | case lldb::eLanguageTypeC_plus_plus: | 
|  | case lldb::eLanguageTypeObjC: | 
|  | start_marker = c_start_marker; | 
|  | end_marker = c_end_marker; | 
|  | break; | 
|  | } | 
|  |  | 
|  | start_loc = transformed_text.find(start_marker); | 
|  | if (start_loc == std::string::npos) | 
|  | return false; | 
|  | start_loc += strlen(start_marker); | 
|  | end_loc = transformed_text.find(end_marker); | 
|  | if (end_loc == std::string::npos) | 
|  | return false; | 
|  | return true; | 
|  | } |