Collect IRExecutionUnits as part of persistent expression state.
authorSean Callanan <scallanan@apple.com>
Mon, 21 Mar 2016 22:23:38 +0000 (22:23 +0000)
committerSean Callanan <scallanan@apple.com>
Mon, 21 Mar 2016 22:23:38 +0000 (22:23 +0000)
IRExecutionUnits contain code and data that persistent declarations can
depend on.  In order to keep them alive and provide for lookup of these
symbols, we now allow any PersistentExpressionState to keep a list of
execution units.  Then, when doing symbol lookup on behalf of an
expression, any IRExecutionUnit can consult the persistent expression
states on a particular Target to find the appropriate symbol.

<rdar://problem/22864976>

llvm-svn: 263995

lldb/include/lldb/Expression/ExpressionVariable.h
lldb/include/lldb/Expression/IRExecutionUnit.h
lldb/source/Expression/ExpressionVariable.cpp
lldb/source/Expression/IRExecutionUnit.cpp
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h

index d8030ba..451acb6 100644 (file)
@@ -16,6 +16,8 @@
 #include <vector>
 
 // Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
 // Project includes
 #include "lldb/lldb-public.h"
 #include "lldb/Core/ConstString.h"
@@ -309,10 +311,19 @@ public:
     RemovePersistentVariable (lldb::ExpressionVariableSP variable) = 0;
     
     virtual lldb::addr_t
-    LookupSymbol (const ConstString &name) = 0;
+    LookupSymbol (const ConstString &name);
+    
+    void
+    RegisterExecutionUnit (lldb::IRExecutionUnitSP &execution_unit_sp);
     
 private:
     LLVMCastKind m_kind;
+    
+    typedef std::set<lldb::IRExecutionUnitSP>               ExecutionUnitSet;
+    ExecutionUnitSet                                        m_execution_units;              ///< The execution units that contain valuable symbols.
+    
+    typedef llvm::DenseMap<const char *, lldb::addr_t>      SymbolMap;
+    SymbolMap                                               m_symbol_map;                   ///< The addresses of the symbols in m_execution_units.
 };
     
 } // namespace lldb_private
index 4411d0a..e59bb06 100644 (file)
@@ -79,7 +79,12 @@ public:
     /// Destructor
     //------------------------------------------------------------------
     ~IRExecutionUnit() override;
-        
+    
+    ConstString GetFunctionName()
+    {
+        return m_name;
+    }
+    
     llvm::Module *
     GetModule()
     {
@@ -136,6 +141,79 @@ public:
         
     lldb::addr_t
     FindSymbol(const ConstString &name);
+    
+    void
+    GetStaticInitializers(std::vector <lldb::addr_t> &static_initializers);
+    
+    //----------------------------------------------------------------------
+    /// @class JittedFunction IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
+    /// @brief Encapsulates a single function that has been generated by the JIT.
+    ///
+    /// Functions that have been generated by the JIT are first resident in the
+    /// local process, and then placed in the target process.  JittedFunction
+    /// represents a function possibly resident in both.
+    //----------------------------------------------------------------------
+    struct JittedEntity {
+        ConstString m_name;             ///< The function's name
+        lldb::addr_t m_local_addr;      ///< The address of the function in LLDB's memory
+        lldb::addr_t m_remote_addr;     ///< The address of the function in the target's memory
+        
+        //------------------------------------------------------------------
+        /// Constructor
+        ///
+        /// Initializes class variabes.
+        ///
+        /// @param[in] name
+        ///     The name of the function.
+        ///
+        /// @param[in] local_addr
+        ///     The address of the function in LLDB, or LLDB_INVALID_ADDRESS if
+        ///     it is not present in LLDB's memory.
+        ///
+        /// @param[in] remote_addr
+        ///     The address of the function in the target, or LLDB_INVALID_ADDRESS
+        ///     if it is not present in the target's memory.
+        //------------------------------------------------------------------
+        JittedEntity (const char *name,
+                      lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
+                      lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
+        m_name (name),
+        m_local_addr (local_addr),
+        m_remote_addr (remote_addr)
+        {
+        }
+    };
+    
+    struct JittedFunction : JittedEntity
+    {
+        bool m_external;
+        JittedFunction (const char *name,
+                        bool external,
+                        lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
+                        lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
+        JittedEntity (name, local_addr, remote_addr),
+        m_external(external)
+        {}
+    };
+    
+    struct JittedGlobalVariable : JittedEntity
+    {
+        JittedGlobalVariable (const char *name,
+                              lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
+                              lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
+        JittedEntity (name, local_addr, remote_addr)
+        {}
+    };
+    
+    const std::vector<JittedFunction> &GetJittedFunctions()
+    {
+        return m_jitted_functions;
+    }
+    
+    const std::vector<JittedGlobalVariable> &GetJittedGlobalVariables()
+    {
+        return m_jitted_global_variables;
+    }
 
 private:
     //------------------------------------------------------------------
@@ -225,6 +303,10 @@ private:
     FindInRuntimes(const std::vector<SearchSpec> &specs,
                    const lldb_private::SymbolContext &sc);
     
+    lldb::addr_t
+    FindInUserDefinedSymbols(const std::vector<SearchSpec> &specs,
+                             const lldb_private::SymbolContext &sc);
+    
     void
     ReportSymbolLookupError(const ConstString &name);
 
@@ -309,45 +391,6 @@ private:
         IRExecutionUnit                    &m_parent;           ///< The execution unit this is a proxy for.
     };
     
-    //----------------------------------------------------------------------
-    /// @class JittedFunction IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
-    /// @brief Encapsulates a single function that has been generated by the JIT.
-    ///
-    /// Functions that have been generated by the JIT are first resident in the
-    /// local process, and then placed in the target process.  JittedFunction
-    /// represents a function possibly resident in both.
-    //----------------------------------------------------------------------
-    struct JittedFunction {
-        std::string m_name;             ///< The function's name
-        lldb::addr_t m_local_addr;      ///< The address of the function in LLDB's memory
-        lldb::addr_t m_remote_addr;     ///< The address of the function in the target's memory
-        
-        //------------------------------------------------------------------
-        /// Constructor
-        ///
-        /// Initializes class variables.
-        ///
-        /// @param[in] name
-        ///     The name of the function.
-        ///
-        /// @param[in] local_addr
-        ///     The address of the function in LLDB, or LLDB_INVALID_ADDRESS if
-        ///     it is not present in LLDB's memory.
-        ///
-        /// @param[in] remote_addr
-        ///     The address of the function in the target, or LLDB_INVALID_ADDRESS
-        ///     if it is not present in the target's memory.
-        //------------------------------------------------------------------
-        JittedFunction (const char *name,
-                        lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
-                        lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
-            m_name (name),
-            m_local_addr (local_addr),
-            m_remote_addr (remote_addr)
-        {
-        }
-    };
-    
     static const unsigned eSectionIDInvalid = (unsigned)-1;
     
     //----------------------------------------------------------------------
@@ -398,6 +441,9 @@ private:
         void dump (Log *log);
     };
     
+    bool
+    CommitOneAllocation (lldb::ProcessSP &process_sp, Error &error, AllocationRecord &record);
+    
     typedef std::vector<AllocationRecord>   RecordVector;
     RecordVector                            m_records;
 
@@ -406,7 +452,8 @@ private:
     std::unique_ptr<llvm::Module>            m_module_ap;            ///< Holder for the module until it's been handed off
     llvm::Module                           *m_module;               ///< Owned by the execution engine
     std::vector<std::string>                m_cpu_features;
-    llvm::SmallVector<JittedFunction, 1>    m_jitted_functions;     ///< A vector of all functions that have been JITted into machine code
+    std::vector<JittedFunction>             m_jitted_functions;     ///< A vector of all functions that have been JITted into machine code
+    std::vector<JittedGlobalVariable>       m_jitted_global_variables; ///< A vector of all functions that have been JITted into machine code
     const ConstString                       m_name;
     SymbolContext                           m_sym_ctx;              ///< Used for symbol lookups
     std::vector<ConstString>                m_failed_lookups;
@@ -417,6 +464,12 @@ private:
     lldb::addr_t                            m_function_end_load_addr;
     
     bool                                    m_strip_underscore;     ///< True for platforms where global symbols have a _ prefix
+    bool                                    m_reported_allocations; ///< True after allocations have been reported.  It is possible that
+                                                                    ///< sections will be allocated when this is true, in which case they weren't
+                                                                    ///< depended on by any function.  (Top-level code defining a variable, but
+                                                                    ///< defining no functions using that variable, would do this.)  If this
+                                                                    ///< is true, any allocations need to be committed immediately -- no
+                                                                    ///< opportunity for relocation.
 };
 
 } // namespace lldb_private
index 8bef60f..5567ee2 100644 (file)
@@ -7,7 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "lldb/Core/Log.h"
 #include "lldb/Expression/ExpressionVariable.h"
+#include "lldb/Expression/IRExecutionUnit.h"
 
 using namespace lldb_private;
 
@@ -34,3 +36,55 @@ ExpressionVariable::GetValueBytes()
 PersistentExpressionState::~PersistentExpressionState ()
 {
 }
+
+lldb::addr_t
+PersistentExpressionState::LookupSymbol (const ConstString &name)
+{
+    SymbolMap::iterator si = m_symbol_map.find(name.GetCString());
+    
+    if (si != m_symbol_map.end())
+        return si->second;
+    else
+        return LLDB_INVALID_ADDRESS;
+}
+
+
+void
+PersistentExpressionState::RegisterExecutionUnit (lldb::IRExecutionUnitSP &execution_unit_sp)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+    
+    m_execution_units.insert(execution_unit_sp);
+    
+    if (log)
+        log->Printf ("Registering JITted Functions:\n");
+    
+    for (const IRExecutionUnit::JittedFunction &jitted_function : execution_unit_sp->GetJittedFunctions())
+    {
+        if (jitted_function.m_external &&
+            jitted_function.m_name != execution_unit_sp->GetFunctionName() &&
+            jitted_function.m_remote_addr != LLDB_INVALID_ADDRESS)
+        {
+            m_symbol_map[jitted_function.m_name.GetCString()] = jitted_function.m_remote_addr;
+            if (log)
+                log->Printf ("  Function: %s at 0x%" PRIx64 ".", jitted_function.m_name.GetCString(), jitted_function.m_remote_addr);
+        }
+    }
+    
+    if (log)
+        log->Printf ("Registering JIIted Symbols:\n");
+    
+    for (const IRExecutionUnit::JittedGlobalVariable &global_var : execution_unit_sp->GetJittedGlobalVariables())
+    {
+        if (global_var.m_remote_addr != LLDB_INVALID_ADDRESS)
+        {
+            // Demangle the name before inserting it, so that lookups by the ConstStr of the demangled name
+            // will find the mangled one (needed for looking up metadata pointers.)
+            Mangled mangler(global_var.m_name);
+            mangler.GetDemangledName(lldb::eLanguageTypeUnknown);
+            m_symbol_map[global_var.m_name.GetCString()] = global_var.m_remote_addr;
+            if (log)
+                log->Printf ("  Symbol: %s at 0x%" PRIx64 ".", global_var.m_name.GetCString(), global_var.m_remote_addr);
+        }
+    }
+}
index 6b223fd..db6f19a 100644 (file)
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/SourceMgr.h"
@@ -28,6 +29,7 @@
 #include "lldb/Target/ExecutionContext.h"
 #include "lldb/Target/Target.h"
 #include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Utility/LLDBAssert.h"
 
 #include "lldb/../../source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
 
@@ -48,7 +50,8 @@ IRExecutionUnit::IRExecutionUnit (std::unique_ptr<llvm::LLVMContext> &context_ap
     m_sym_ctx(sym_ctx),
     m_did_jit(false),
     m_function_load_addr(LLDB_INVALID_ADDRESS),
-    m_function_end_load_addr(LLDB_INVALID_ADDRESS)
+    m_function_end_load_addr(LLDB_INVALID_ADDRESS),
+    m_reported_allocations(false)
 {
 }
 
@@ -122,7 +125,7 @@ IRExecutionUnit::DisassembleFunction (Stream &stream,
 
     for (JittedFunction &function : m_jitted_functions)
     {
-        if (strstr(function.m_name.c_str(), m_name.AsCString()))
+        if (function.m_name.AsCString() != m_name.AsCString())
         {
             func_local_addr = function.m_local_addr;
             func_remote_addr = function.m_remote_addr;
@@ -285,7 +288,6 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
     }
 
     llvm::Triple triple(m_module->getTargetTriple());
-    llvm::Function *function = m_module->getFunction (m_name.AsCString());
     llvm::Reloc::Model relocModel;
     llvm::CodeModel::Model codeModel;
 
@@ -340,34 +342,69 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
 
     m_execution_engine_ap->DisableLazyCompilation();
 
-    // We don't actually need the function pointer here, this just forces it to get resolved.
-
-    void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function);
-
-    if (!error.Success())
+    for (llvm::Function &function : *m_module)
     {
-        // We got an error through our callback!
-        return;
+        if (function.isDeclaration())
+            continue;
+        
+        const bool external = function.hasExternalLinkage() || function.hasLinkOnceODRLinkage();
+        
+        void *fun_ptr = m_execution_engine_ap->getPointerToFunction(&function);
+        
+        if (!error.Success())
+        {
+            // We got an error through our callback!
+            return;
+        }
+        
+        if (!fun_ptr)
+        {
+            error.SetErrorToGenericError();
+            error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", function.getName().str().c_str());
+            return;
+        }
+        m_jitted_functions.push_back (JittedFunction(function.getName().str().c_str(), external, (lldb::addr_t)fun_ptr));
     }
 
-    if (!function)
+    CommitAllocations(process_sp);
+    ReportAllocations(*m_execution_engine_ap);
+    
+    // We have to do this after calling ReportAllocations because for the MCJIT, getGlobalValueAddress
+    // will cause the JIT to perform all relocations.  That can only be done once, and has to happen
+    // after we do the remapping from local -> remote.
+    // That means we don't know the local address of the Variables, but we don't need that for anything,
+    // so that's okay.
+    
+    std::function<void (llvm::GlobalValue &)> RegisterOneValue = [this] (llvm::GlobalValue &val) {
+        if (val.hasExternalLinkage() && !val.isDeclaration())
+        {
+            uint64_t var_ptr_addr = m_execution_engine_ap->getGlobalValueAddress(val.getName().str());
+            
+            lldb::addr_t remote_addr = GetRemoteAddressForLocal(var_ptr_addr);
+            
+            // This is a really unfortunae API that sometimes returns local addresses and sometimes returns remote addresses, based on whether
+            // the variable was relocated during ReportAllocations or not.
+            
+            if (remote_addr == LLDB_INVALID_ADDRESS)
+            {
+                remote_addr = var_ptr_addr;
+            }
+                
+            if (var_ptr_addr != 0)
+                m_jitted_global_variables.push_back (JittedGlobalVariable (val.getName().str().c_str(), LLDB_INVALID_ADDRESS, remote_addr));
+        }
+    };
+    
+    for (llvm::GlobalVariable &global_var : m_module->getGlobalList())
     {
-        error.SetErrorToGenericError();
-        error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString());
-        return;
+        RegisterOneValue(global_var);
     }
-
-    if (!fun_ptr)
+    
+    for (llvm::GlobalAlias &global_alias : m_module->getAliasList())
     {
-        error.SetErrorToGenericError();
-        error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString());
-        return;
+        RegisterOneValue(global_alias);
     }
 
-    m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr));
-
-    CommitAllocations(process_sp);
-    ReportAllocations(*m_execution_engine_ap);
     WriteData(process_sp);
 
     if (m_failed_lookups.size())
@@ -401,7 +438,7 @@ IRExecutionUnit::GetRunnableInfo(Error &error,
     {
         jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr);
 
-        if (!jitted_function.m_name.compare(m_name.AsCString()))
+        if (!m_name.IsEmpty() && jitted_function.m_name == m_name)
         {
             AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr);
             m_function_end_load_addr = func_range.first + func_range.second;
@@ -612,6 +649,14 @@ IRExecutionUnit::MemoryManager::allocateCodeSection(uintptr_t Size,
         log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
                     (uint64_t)Size, Alignment, SectionID, (void *)return_value);
     }
+    
+    if (m_parent.m_reported_allocations)
+    {
+        Error err;
+        lldb::ProcessSP process_sp = m_parent.GetBestExecutionContextScope()->CalculateProcess();
+        
+        m_parent.CommitOneAllocation(process_sp, err, m_parent.m_records.back());
+    }
 
     return return_value;
 }
@@ -642,6 +687,14 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
         log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
                     (uint64_t)Size, Alignment, SectionID, (void *)return_value);
     }
+    
+    if (m_parent.m_reported_allocations)
+    {
+        Error err;
+        lldb::ProcessSP process_sp = m_parent.GetBestExecutionContextScope()->CalculateProcess();
+        
+        m_parent.CommitOneAllocation(process_sp, err, m_parent.m_records.back());
+    }
 
     return return_value;
 }
@@ -931,6 +984,22 @@ IRExecutionUnit::FindInRuntimes(const std::vector<SearchSpec> &specs, const lldb
 }
 
 lldb::addr_t
+IRExecutionUnit::FindInUserDefinedSymbols(const std::vector<SearchSpec> &specs, const lldb_private::SymbolContext &sc)
+{
+    lldb::TargetSP target_sp = sc.target_sp;
+    
+    for (const SearchSpec &spec : specs)
+    {
+        lldb::addr_t symbol_load_addr = target_sp->GetPersistentSymbol(spec.name);
+        
+        if (symbol_load_addr != LLDB_INVALID_ADDRESS)
+            return symbol_load_addr;
+    }
+    
+    return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
 IRExecutionUnit::FindSymbol(const lldb_private::ConstString &name)
 {
     std::vector<SearchSpec> candidate_C_names;
@@ -943,6 +1012,9 @@ IRExecutionUnit::FindSymbol(const lldb_private::ConstString &name)
         ret = FindInRuntimes(candidate_C_names, m_sym_ctx);
 
     if (ret == LLDB_INVALID_ADDRESS)
+        ret = FindInUserDefinedSymbols(candidate_C_names, m_sym_ctx);
+
+    if (ret == LLDB_INVALID_ADDRESS)
     {
         CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names, m_sym_ctx);
         ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx);
@@ -951,6 +1023,42 @@ IRExecutionUnit::FindSymbol(const lldb_private::ConstString &name)
     return ret;
 }
 
+void
+IRExecutionUnit::GetStaticInitializers(std::vector <lldb::addr_t> &static_initializers)
+{
+    if (llvm::GlobalVariable *global_ctors = m_module->getNamedGlobal("llvm.global_ctors"))
+    {
+        if (llvm::ConstantArray *ctor_array = llvm::dyn_cast<llvm::ConstantArray>(global_ctors->getInitializer()))
+        {
+            for (llvm::Use &ctor_use : ctor_array->operands())
+            {
+                if (llvm::ConstantStruct *ctor_struct = llvm::dyn_cast<llvm::ConstantStruct>(ctor_use))
+                {
+                    lldbassert(ctor_struct->getNumOperands() == 3); // this is standardized
+                    if (llvm::Function *ctor_function = llvm::dyn_cast<llvm::Function>(ctor_struct->getOperand(1)))
+                    {
+                        ctor_function->dump();
+
+                        ConstString ctor_function_name_cs(ctor_function->getName().str());
+                        
+                        for (JittedFunction &jitted_function : m_jitted_functions)
+                        {
+                            if (ctor_function_name_cs == jitted_function.m_name)
+                            {
+                                if (jitted_function.m_remote_addr != LLDB_INVALID_ADDRESS)
+                                {
+                                    static_initializers.push_back(jitted_function.m_remote_addr);
+                                }
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
 uint64_t
 IRExecutionUnit::MemoryManager::getSymbolAddress(const std::string &Name)
 {
@@ -1039,19 +1147,17 @@ IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address)
 }
 
 bool
-IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
+IRExecutionUnit::CommitOneAllocation (lldb::ProcessSP &process_sp,
+                                      Error &error,
+                                      AllocationRecord &record)
 {
-    bool ret = true;
-
-    lldb_private::Error err;
-
-    for (AllocationRecord &record : m_records)
+    if (record.m_process_address != LLDB_INVALID_ADDRESS)
+    {
+        return true;
+    }
+    
+    switch (record.m_sect_type)
     {
-        if (record.m_process_address != LLDB_INVALID_ADDRESS)
-            continue;
-
-        switch (record.m_sect_type)
-        {
         case lldb::eSectionTypeInvalid:
         case lldb::eSectionTypeDWARFDebugAbbrev:
         case lldb::eSectionTypeDWARFDebugAddr:
@@ -1070,7 +1176,7 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
         case lldb::eSectionTypeDWARFAppleTypes:
         case lldb::eSectionTypeDWARFAppleNamespaces:
         case lldb::eSectionTypeDWARFAppleObjC:
-            err.Clear();
+            error.Clear();
             break;
         default:
             const bool zero_memory = false;
@@ -1079,13 +1185,26 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
                                                record.m_permissions,
                                                eAllocationPolicyProcessOnly,
                                                zero_memory,
-                                               err);
+                                               error);
             break;
-        }
+    }
+    
+    return error.Success();
+}
 
-        if (!err.Success())
+bool
+IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
+{
+    bool ret = true;
+
+    lldb_private::Error err;
+
+    for (AllocationRecord &record : m_records)
+    {
+        ret = CommitOneAllocation(process_sp, err, record);
+        
+        if (!ret)
         {
-            ret = false;
             break;
         }
     }
@@ -1108,6 +1227,8 @@ IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
 void
 IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
 {
+    m_reported_allocations = true;
+    
     for (AllocationRecord &record : m_records)
     {
         if (record.m_process_address == LLDB_INVALID_ADDRESS)
index 0952fec..e915965 100644 (file)
@@ -80,6 +80,7 @@
 #include "lldb/Target/ObjCLanguageRuntime.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
 #include "lldb/Utility/LLDBAssert.h"
 
 using namespace clang;
@@ -214,6 +215,56 @@ private:
     std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
 };
 
+class LoggingDiagnosticConsumer : public clang::DiagnosticConsumer
+{
+public:
+    LoggingDiagnosticConsumer ()
+    {
+        m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+        m_passthrough.reset(new clang::TextDiagnosticBuffer);
+    }
+    
+    LoggingDiagnosticConsumer (const std::shared_ptr<clang::TextDiagnosticBuffer> &passthrough)
+    {
+        m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+        m_passthrough = passthrough;
+    }
+    
+    void HandleDiagnostic (DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info)
+    {
+        if (m_log)
+        {
+            llvm::SmallVector<char, 32> diag_str;
+            Info.FormatDiagnostic(diag_str);
+            diag_str.push_back('\0');
+            const char *data = diag_str.data();
+            m_log->Printf("[clang] COMPILER DIAGNOSTIC: %s", data);
+
+            lldbassert(Info.getID() != clang::diag::err_unsupported_ast_node && "'log enable lldb expr' to investigate.");
+        }
+        
+        m_passthrough->HandleDiagnostic(DiagLevel, Info);
+    }
+    
+    void FlushDiagnostics (DiagnosticsEngine &Diags)
+    {
+        m_passthrough->FlushDiagnostics(Diags);
+    }
+    
+    DiagnosticConsumer *clone (DiagnosticsEngine &Diags) const
+    {
+        return new LoggingDiagnosticConsumer (m_passthrough);
+    }
+    
+    clang::TextDiagnosticBuffer *GetPassthrough()
+    {
+        return m_passthrough.get();
+    }
+private:
+    Log * m_log;
+    std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
+};
+
 //===----------------------------------------------------------------------===//
 // Implementation of ClangExpressionParser
 //===----------------------------------------------------------------------===//
@@ -769,3 +820,51 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
 
     return err;
 }
+
+Error
+ClangExpressionParser::RunStaticInitializers (lldb::IRExecutionUnitSP &execution_unit_sp,
+                                              ExecutionContext &exe_ctx)
+{
+    Error err;
+    
+    lldbassert(execution_unit_sp.get());
+    lldbassert(exe_ctx.HasThreadScope());
+    
+    if (!execution_unit_sp.get())
+    {
+        err.SetErrorString ("can't run static initializers for a NULL execution unit");
+        return err;
+    }
+    
+    if (!exe_ctx.HasThreadScope())
+    {
+        err.SetErrorString ("can't run static initializers without a thread");
+        return err;
+    }
+    
+    std::vector<lldb::addr_t> static_initializers;
+    
+    execution_unit_sp->GetStaticInitializers(static_initializers);
+    
+    for (lldb::addr_t static_initializer : static_initializers)
+    {
+        EvaluateExpressionOptions options;
+                
+        lldb::ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction(exe_ctx.GetThreadRef(),
+                                                                              Address(static_initializer),
+                                                                              CompilerType(),
+                                                                              llvm::ArrayRef<lldb::addr_t>(),
+                                                                              options));
+        
+        DiagnosticManager execution_errors;
+        lldb::ExpressionResults results = exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan(exe_ctx, call_static_initializer, options, execution_errors);
+        
+        if (results != lldb::eExpressionCompleted)
+        {
+            err.SetErrorStringWithFormat ("couldn't run static initializer: %s", execution_errors.GetString().c_str());
+            return err;
+        }
+    }
+    
+    return err;
+}
index 832dce7..cb72daa 100644 (file)
@@ -118,6 +118,22 @@ public:
                          ExecutionContext &exe_ctx,
                          bool &can_interpret,
                          lldb_private::ExecutionPolicy execution_policy) override;
+    
+    //------------------------------------------------------------------
+    /// Run all static initializers for an execution unit.
+    ///
+    /// @param[in] execution_unit_sp
+    ///     The execution unit.
+    ///
+    /// @param[in] exe_ctx
+    ///     The execution context to use when running them.  Thread can't be null.
+    ///
+    /// @return
+    ///     The error code indicating the 
+    //------------------------------------------------------------------
+    Error
+    RunStaticInitializers (lldb::IRExecutionUnitSP &execution_unit_sp,
+                           ExecutionContext &exe_ctx);
         
 private:
     std::unique_ptr<llvm::LLVMContext>       m_llvm_context;         ///< The LLVM context to generate IR into