forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			424 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			424 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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 "lldb/Core/StreamString.h"
 | |
| #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
 | |
| #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
 | |
| #include "lldb/Symbol/CompileUnit.h"
 | |
| #include "lldb/Symbol/DebugMacros.h"
 | |
| #include "lldb/Symbol/Block.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;
 | |
|     
 | |
|     if (Target *target = exe_ctx.GetTargetPtr())
 | |
|     {
 | |
|         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()))
 | |
|         {
 | |
|             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;
 | |
| }
 | |
| 
 |