[Lldb-commits] [lldb] r217116 - ASan malloc/free history threads

Kuba Brecka kuba.brecka at gmail.com
Wed Sep 3 18:03:19 PDT 2014


Author: kuba.brecka
Date: Wed Sep  3 20:03:18 2014
New Revision: 217116

URL: http://llvm.org/viewvc/llvm-project?rev=217116&view=rev
Log:
ASan malloc/free history threads

Reviewed at http://reviews.llvm.org/D4596


Added:
    lldb/trunk/include/lldb/Target/MemoryHistory.h
    lldb/trunk/source/Plugins/MemoryHistory/
    lldb/trunk/source/Plugins/MemoryHistory/CMakeLists.txt
    lldb/trunk/source/Plugins/MemoryHistory/asan/
    lldb/trunk/source/Plugins/MemoryHistory/asan/CMakeLists.txt
    lldb/trunk/source/Plugins/MemoryHistory/asan/Makefile
    lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
    lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h
    lldb/trunk/source/Target/MemoryHistory.cpp
    lldb/trunk/test/functionalities/asan/
    lldb/trunk/test/functionalities/asan/Makefile
    lldb/trunk/test/functionalities/asan/TestAsan.py
    lldb/trunk/test/functionalities/asan/main.c
Modified:
    lldb/trunk/include/lldb/Core/PluginManager.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/include/lldb/lldb-private-interfaces.h
    lldb/trunk/lldb.xcodeproj/project.pbxproj
    lldb/trunk/source/CMakeLists.txt
    lldb/trunk/source/Commands/CommandObjectMemory.cpp
    lldb/trunk/source/Core/PluginManager.cpp
    lldb/trunk/source/Plugins/CMakeLists.txt
    lldb/trunk/source/Plugins/Makefile
    lldb/trunk/source/Plugins/Process/Utility/HistoryThread.h
    lldb/trunk/source/Target/CMakeLists.txt
    lldb/trunk/source/lldb.cpp
    lldb/trunk/test/lldbtest.py

Modified: lldb/trunk/include/lldb/Core/PluginManager.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/PluginManager.h?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/PluginManager.h (original)
+++ lldb/trunk/include/lldb/Core/PluginManager.h Wed Sep  3 20:03:18 2014
@@ -342,6 +342,23 @@ public:
 
     static UnwindAssemblyCreateInstance
     GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &name);
+    
+    //------------------------------------------------------------------
+    // MemoryHistory
+    //------------------------------------------------------------------
+    static bool
+    RegisterPlugin (const ConstString &name,
+                    const char *description,
+                    MemoryHistoryCreateInstance create_callback);
+    
+    static bool
+    UnregisterPlugin (MemoryHistoryCreateInstance create_callback);
+    
+    static MemoryHistoryCreateInstance
+    GetMemoryHistoryCreateCallbackAtIndex (uint32_t idx);
+    
+    static MemoryHistoryCreateInstance
+    GetMemoryHistoryCreateCallbackForPluginName (const ConstString &name);
 
     //------------------------------------------------------------------
     // Some plug-ins might register a DebuggerInitializeCallback

Added: lldb/trunk/include/lldb/Target/MemoryHistory.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/MemoryHistory.h?rev=217116&view=auto
==============================================================================
--- lldb/trunk/include/lldb/Target/MemoryHistory.h (added)
+++ lldb/trunk/include/lldb/Target/MemoryHistory.h Wed Sep  3 20:03:18 2014
@@ -0,0 +1,42 @@
+//===-- MemoryHistory.h ---------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MemoryHistory_h_
+#define liblldb_MemoryHistory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/PluginInterface.h"
+
+namespace lldb_private {
+    
+typedef std::vector<lldb::ThreadSP> HistoryThreads;
+    
+class MemoryHistory :
+    public std::enable_shared_from_this<MemoryHistory>,
+    public PluginInterface
+{
+public:
+
+    static lldb::MemoryHistorySP
+    FindPlugin (const lldb::ProcessSP process);
+
+    virtual HistoryThreads
+    GetHistoryThreads(lldb::addr_t address) = 0;
+};
+    
+} // namespace lldb_private
+
+#endif  // liblldb_MemoryHistory_h_

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Wed Sep  3 20:03:18 2014
@@ -116,6 +116,7 @@ class   Log;
 class   LogChannel;
 class   Mangled;
 class   Materializer;
+class   MemoryHistory;
 class   Module;
 class   ModuleList;
 class   ModuleSpec;
@@ -316,6 +317,7 @@ namespace lldb {
     typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
     typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
     typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
+    typedef std::shared_ptr<lldb_private::MemoryHistory> MemoryHistorySP;
     typedef std::shared_ptr<lldb_private::Module> ModuleSP;
     typedef std::weak_ptr<lldb_private::Module> ModuleWP;
     typedef std::shared_ptr<lldb_private::ObjectFile> ObjectFileSP;

Modified: lldb/trunk/include/lldb/lldb-private-interfaces.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-interfaces.h?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-interfaces.h (original)
+++ lldb/trunk/include/lldb/lldb-private-interfaces.h Wed Sep  3 20:03:18 2014
@@ -39,6 +39,7 @@ namespace lldb_private
     typedef bool (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
     typedef lldb::ThreadPlanSP (*ThreadPlanStepFromHereCallback) (ThreadPlan *current_plan, Flags &flags, lldb::FrameComparison operation, void *baton);
     typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
+    typedef lldb::MemoryHistorySP (*MemoryHistoryCreateInstance) (const lldb::ProcessSP &process_sp);
     typedef int (*ComparisonFunction)(const void *, const void *);
     typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
 

Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/lldb.xcodeproj/project.pbxproj (original)
+++ lldb/trunk/lldb.xcodeproj/project.pbxproj Wed Sep  3 20:03:18 2014
@@ -618,6 +618,8 @@
 		4CF3D80C15AF4DC800845BF3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
 		4CF52AF51428291E0051E832 /* SBFileSpecList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF52AF41428291E0051E832 /* SBFileSpecList.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; };
+		8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; };
+		8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; };
 		94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94094C69163B6CD90083A547 /* ValueObjectCast.cpp */; };
 		94145431175E63B500284436 /* lldb-versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 94145430175D7FDE00284436 /* lldb-versioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		941BCC7F14E48C4000BB969C /* SBTypeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9461568614E355F2003A195C /* SBTypeFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1894,6 +1896,10 @@
 		69A01E1E1236C5D400C660B5 /* Mutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mutex.cpp; sourceTree = "<group>"; };
 		69A01E1F1236C5D400C660B5 /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbols.cpp; sourceTree = "<group>"; };
 		69A01E201236C5D400C660B5 /* TimeValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeValue.cpp; sourceTree = "<group>"; };
+		8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MemoryHistory.cpp; path = source/Target/MemoryHistory.cpp; sourceTree = "<group>"; };
+		8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = "<group>"; };
+		8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = "<group>"; };
+		8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryHistoryASan.h; sourceTree = "<group>"; };
 		94005E0313F438DF001EF42D /* python-wrapper.swig */ = {isa = PBXFileReference; lastKnownFileType = text; path = "python-wrapper.swig"; sourceTree = "<group>"; };
 		94005E0513F45A1B001EF42D /* embedded_interpreter.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = embedded_interpreter.py; path = source/Interpreter/embedded_interpreter.py; sourceTree = "<group>"; };
 		94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PriorityPointerPair.h; path = include/lldb/Utility/PriorityPointerPair.h; sourceTree = "<group>"; };
@@ -2338,6 +2344,7 @@
 		260C897110F57C5600BB2B04 /* Plugins */ = {
 			isa = PBXGroup;
 			children = (
+				8C2D6A58197A1FB9006989C9 /* MemoryHistory */,
 				26DB3E051379E7AD0080DC73 /* ABI */,
 				260C897210F57C5600BB2B04 /* Disassembler */,
 				260C897810F57C5600BB2B04 /* DynamicLoader */,
@@ -3661,6 +3668,8 @@
 				4CB4430A12491DDA00C13DC2 /* LanguageRuntime.cpp */,
 				2690B36F1381D5B600ECFBAE /* Memory.h */,
 				2690B3701381D5C300ECFBAE /* Memory.cpp */,
+				8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */,
+				8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */,
 				2360092C193FB21500189DB1 /* MemoryRegionInfo.h */,
 				4CB443F612499B6E00C13DC2 /* ObjCLanguageRuntime.h */,
 				4CB443F212499B5000C13DC2 /* ObjCLanguageRuntime.cpp */,
@@ -4114,6 +4123,23 @@
 			path = source/Host/common;
 			sourceTree = "<group>";
 		};
+		8C2D6A58197A1FB9006989C9 /* MemoryHistory */ = {
+			isa = PBXGroup;
+			children = (
+				8C2D6A59197A1FCD006989C9 /* asan */,
+			);
+			path = MemoryHistory;
+			sourceTree = "<group>";
+		};
+		8C2D6A59197A1FCD006989C9 /* asan */ = {
+			isa = PBXGroup;
+			children = (
+				8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */,
+				8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */,
+			);
+			path = asan;
+			sourceTree = "<group>";
+		};
 		9457596415349416005A9070 /* POSIX */ = {
 			isa = PBXGroup;
 			children = (
@@ -4903,6 +4929,7 @@
 				2689005A13353E0400698AC0 /* ValueObjectList.cpp in Sources */,
 				2689005B13353E0400698AC0 /* ValueObjectRegister.cpp in Sources */,
 				2689005C13353E0400698AC0 /* ValueObjectVariable.cpp in Sources */,
+				8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */,
 				2689005D13353E0400698AC0 /* VMRange.cpp in Sources */,
 				2689005E13353E0E00698AC0 /* ClangASTSource.cpp in Sources */,
 				2689005F13353E0E00698AC0 /* ClangFunction.cpp in Sources */,
@@ -5126,6 +5153,7 @@
 				264A1300137252C700875C42 /* ARM64_DWARF_Registers.cpp in Sources */,
 				26DB3E161379E7AD0080DC73 /* ABIMacOSX_arm.cpp in Sources */,
 				26DB3E191379E7AD0080DC73 /* ABIMacOSX_arm64.cpp in Sources */,
+				8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */,
 				26DB3E1C1379E7AD0080DC73 /* ABIMacOSX_i386.cpp in Sources */,
 				26DB3E1F1379E7AD0080DC73 /* ABISysV_x86_64.cpp in Sources */,
 				232CB61D191E00CD00EF39FC /* SoftwareBreakpoint.cpp in Sources */,

Modified: lldb/trunk/source/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/CMakeLists.txt?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/CMakeLists.txt (original)
+++ lldb/trunk/source/CMakeLists.txt Wed Sep  3 20:03:18 2014
@@ -84,6 +84,7 @@ set( LLDB_USED_LIBS
   lldbPluginInstructionARM64
   lldbPluginObjectFilePECOFF
   lldbPluginOSPython
+  lldbPluginMemoryHistoryASan
   )
 
 # Need to export the API in the liblldb.dll for Windows

Modified: lldb/trunk/source/Commands/CommandObjectMemory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectMemory.cpp?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectMemory.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectMemory.cpp Wed Sep  3 20:03:18 2014
@@ -33,8 +33,10 @@
 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
 #include "lldb/Interpreter/OptionValueString.h"
 #include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/MemoryHistory.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -1667,6 +1669,96 @@ protected:
     OptionGroupWriteMemory m_memory_options;
 };
 
+//----------------------------------------------------------------------
+// Get malloc/free history of a memory address.
+//----------------------------------------------------------------------
+class CommandObjectMemoryHistory : public CommandObjectParsed
+{
+public:
+    
+    CommandObjectMemoryHistory (CommandInterpreter &interpreter) :
+    CommandObjectParsed (interpreter,
+                         "memory history",
+                         "Prints out the recorded stack traces for allocation/deallocation of a memory address.",
+                         NULL,
+                         eFlagRequiresTarget | eFlagRequiresProcess | eFlagProcessMustBePaused | eFlagProcessMustBeLaunched)
+    {
+        CommandArgumentEntry arg1;
+        CommandArgumentData addr_arg;
+        
+        // Define the first (and only) variant of this arg.
+        addr_arg.arg_type = eArgTypeAddress;
+        addr_arg.arg_repetition = eArgRepeatPlain;
+        
+        // There is only one variant this argument could be; put it into the argument entry.
+        arg1.push_back (addr_arg);
+        
+        // Push the data for the first argument into the m_arguments vector.
+        m_arguments.push_back (arg1);
+    }
+    
+    virtual
+    ~CommandObjectMemoryHistory ()
+    {
+    }
+    
+    virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+    {
+        return m_cmd_name.c_str();
+    }
+    
+protected:
+    virtual bool
+    DoExecute (Args& command, CommandReturnObject &result)
+    {
+        const size_t argc = command.GetArgumentCount();
+        
+        if (argc == 0 || argc > 1)
+        {
+            result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        
+        Error error;
+        lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
+                                                   command.GetArgumentAtIndex(0),
+                                                   LLDB_INVALID_ADDRESS,
+                                                   &error);
+        
+        if (addr == LLDB_INVALID_ADDRESS)
+        {
+            result.AppendError("invalid address expression");
+            result.AppendError(error.AsCString());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        
+        Stream *output_stream = &result.GetOutputStream();
+        
+        const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
+        const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp);
+        
+        if (! memory_history.get())
+        {
+            result.AppendError("no available memory history provider");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        
+        HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
+        
+        for (auto thread : thread_list) {
+            thread->GetStatus(*output_stream, 0, UINT32_MAX, 0);
+        }
+        
+        result.SetStatus(eReturnStatusSuccessFinishResult);
+        
+        return true;
+    }
+    
+};
+
 
 //-------------------------------------------------------------------------
 // CommandObjectMemory
@@ -1681,6 +1773,7 @@ CommandObjectMemory::CommandObjectMemory
     LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
+    LoadSubCommand ("history", CommandObjectSP (new CommandObjectMemoryHistory (interpreter)));
 }
 
 CommandObjectMemory::~CommandObjectMemory ()

Modified: lldb/trunk/source/Core/PluginManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/PluginManager.cpp?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Core/PluginManager.cpp (original)
+++ lldb/trunk/source/Core/PluginManager.cpp Wed Sep  3 20:03:18 2014
@@ -2068,6 +2068,110 @@ PluginManager::GetUnwindAssemblyCreateCa
     return NULL;
 }
 
+#pragma mark MemoryHistory
+
+struct MemoryHistoryInstance
+{
+    MemoryHistoryInstance() :
+    name(),
+    description(),
+    create_callback(NULL)
+    {
+    }
+    
+    ConstString name;
+    std::string description;
+    MemoryHistoryCreateInstance create_callback;
+};
+
+typedef std::vector<MemoryHistoryInstance> MemoryHistoryInstances;
+
+static Mutex &
+GetMemoryHistoryMutex ()
+{
+    static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+    return g_instances_mutex;
+}
+
+static MemoryHistoryInstances &
+GetMemoryHistoryInstances ()
+{
+    static MemoryHistoryInstances g_instances;
+    return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ MemoryHistoryCreateInstance create_callback
+ )
+{
+    if (create_callback)
+    {
+        MemoryHistoryInstance instance;
+        assert ((bool)name);
+        instance.name = name;
+        if (description && description[0])
+            instance.description = description;
+        instance.create_callback = create_callback;
+        Mutex::Locker locker (GetMemoryHistoryMutex ());
+        GetMemoryHistoryInstances ().push_back (instance);
+    }
+    return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (MemoryHistoryCreateInstance create_callback)
+{
+    if (create_callback)
+    {
+        Mutex::Locker locker (GetMemoryHistoryMutex ());
+        MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+        
+        MemoryHistoryInstances::iterator pos, end = instances.end();
+        for (pos = instances.begin(); pos != end; ++ pos)
+        {
+            if (pos->create_callback == create_callback)
+            {
+                instances.erase(pos);
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackAtIndex (uint32_t idx)
+{
+    Mutex::Locker locker (GetMemoryHistoryMutex ());
+    MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+    if (idx < instances.size())
+        return instances[idx].create_callback;
+    return NULL;
+}
+
+
+MemoryHistoryCreateInstance
+PluginManager::GetMemoryHistoryCreateCallbackForPluginName (const ConstString &name)
+{
+    if (name)
+    {
+        Mutex::Locker locker (GetMemoryHistoryMutex ());
+        MemoryHistoryInstances &instances = GetMemoryHistoryInstances ();
+        
+        MemoryHistoryInstances::iterator pos, end = instances.end();
+        for (pos = instances.begin(); pos != end; ++ pos)
+        {
+            if (name == pos->name)
+                return pos->create_callback;
+        }
+    }
+    return NULL;
+}
+
 void
 PluginManager::DebuggerInitialize (Debugger &debugger)
 {

Modified: lldb/trunk/source/Plugins/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/CMakeLists.txt?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/CMakeLists.txt Wed Sep  3 20:03:18 2014
@@ -4,6 +4,7 @@ add_subdirectory(DynamicLoader)
 add_subdirectory(Instruction)
 add_subdirectory(JITLoader)
 add_subdirectory(LanguageRuntime)
+add_subdirectory(MemoryHistory)
 add_subdirectory(ObjectContainer)
 add_subdirectory(ObjectFile)
 add_subdirectory(OperatingSystem)

Modified: lldb/trunk/source/Plugins/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Makefile?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Makefile (original)
+++ lldb/trunk/source/Plugins/Makefile Wed Sep  3 20:03:18 2014
@@ -24,7 +24,8 @@ DIRS := ABI/MacOSX-arm ABI/MacOSX-arm64
 	DynamicLoader/POSIX-DYLD \
 	DynamicLoader/Hexagon-DYLD \
 	OperatingSystem/Python \
-	SymbolVendor/ELF
+	SymbolVendor/ELF \
+	MemoryHistory/asan
 
 ifeq ($(HOST_OS),Darwin)
 DIRS += Process/MacOSX-Kernel

Added: lldb/trunk/source/Plugins/MemoryHistory/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/MemoryHistory/CMakeLists.txt?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/MemoryHistory/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/MemoryHistory/CMakeLists.txt Wed Sep  3 20:03:18 2014
@@ -0,0 +1 @@
+add_subdirectory(asan)

Added: lldb/trunk/source/Plugins/MemoryHistory/asan/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/MemoryHistory/asan/CMakeLists.txt?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/MemoryHistory/asan/CMakeLists.txt (added)
+++ lldb/trunk/source/Plugins/MemoryHistory/asan/CMakeLists.txt Wed Sep  3 20:03:18 2014
@@ -0,0 +1,5 @@
+set(LLVM_NO_RTTI 1)
+
+add_lldb_library(lldbPluginMemoryHistoryASan
+  MemoryHistoryASan.cpp
+  )

Added: lldb/trunk/source/Plugins/MemoryHistory/asan/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/MemoryHistory/asan/Makefile?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/MemoryHistory/asan/Makefile (added)
+++ lldb/trunk/source/Plugins/MemoryHistory/asan/Makefile Wed Sep  3 20:03:18 2014
@@ -0,0 +1,14 @@
+##===- source/Plugins/MemoryHistory/asan/Makefile -------------*- Makefile -*-===##
+# 
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+# 
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginMemoryHistoryASan
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile

Added: lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp (added)
+++ lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp Wed Sep  3 20:03:18 2014
@@ -0,0 +1,185 @@
+//===-- MemoryHistoryASan.cpp -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MemoryHistoryASan.h"
+
+#include "lldb/Target/MemoryHistory.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/Module.h"
+#include "Plugins/Process/Utility/HistoryThread.h"
+#include "lldb/Core/ValueObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+MemoryHistorySP
+MemoryHistoryASan::CreateInstance (const ProcessSP &process_sp)
+{
+    if (!process_sp.get())
+        return NULL;
+    
+    Target & target = process_sp->GetTarget();
+    
+    bool found_asan_runtime = false;
+    
+    const ModuleList &target_modules = target.GetImages();
+    Mutex::Locker modules_locker(target_modules.GetMutex());
+    const size_t num_modules = target_modules.GetSize();
+    for (size_t i = 0; i < num_modules; ++i)
+    {
+        Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
+        
+        SymbolContextList sc_list;
+        const bool include_symbols = true;
+        const bool append = true;
+        const bool include_inlines = true;
+
+        size_t num_matches = module_pointer->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+        
+        if (num_matches)
+        {
+            found_asan_runtime = true;
+            break;
+        }
+    }
+    
+    if (! found_asan_runtime)
+        return MemoryHistorySP();
+
+    return MemoryHistorySP(new MemoryHistoryASan(process_sp));
+}
+
+void
+MemoryHistoryASan::Initialize()
+{
+    PluginManager::RegisterPlugin (GetPluginNameStatic(),
+                                   "ASan memory history provider.",
+                                   CreateInstance);
+}
+
+void
+MemoryHistoryASan::Terminate()
+{
+    PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+MemoryHistoryASan::GetPluginNameStatic()
+{
+    static ConstString g_name("asan");
+    return g_name;
+}
+
+MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp)
+{
+    this->m_process_sp = process_sp;
+}
+
+const char *
+memory_history_asan_command_format = R"(
+    struct t {
+        void *alloc_trace[256];
+        size_t alloc_count;
+        int alloc_tid;
+        
+        void *free_trace[256];
+        size_t free_count;
+        int free_tid;
+    } t;
+
+    t.alloc_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_alloc_stack)((void *)0x%)" PRIx64 R"(, t.alloc_trace, 256, &t.alloc_tid);
+    t.free_count = ((size_t (*) (void *, void **, size_t, int *))__asan_get_free_stack)((void *)0x%)" PRIx64 R"(, t.free_trace, 256, &t.free_tid);
+
+    t;
+)";
+
+#define GET_STACK_FUNCTION_TIMEOUT_USEC 2*1000*1000
+
+HistoryThreads
+MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address)
+{
+    ProcessSP process_sp = m_process_sp;
+    ThreadSP thread_sp = m_process_sp->GetThreadList().GetSelectedThread();
+    StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+
+    if (!frame_sp)
+    {
+        return HistoryThreads();
+    }
+
+    ExecutionContext exe_ctx (frame_sp);
+    ValueObjectSP return_value_sp;
+    StreamString expr;
+    expr.Printf(memory_history_asan_command_format, address, address);
+    
+    EvaluateExpressionOptions options;
+    options.SetUnwindOnError(true);
+    options.SetTryAllThreads(true);
+    options.SetStopOthers(true);
+    options.SetIgnoreBreakpoints(true);
+    options.SetTimeoutUsec(GET_STACK_FUNCTION_TIMEOUT_USEC);
+
+    if (m_process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), return_value_sp, options) != eExpressionCompleted)
+    {
+        return HistoryThreads();
+    }
+    if (!return_value_sp)
+    {
+        return HistoryThreads();
+    }
+    
+    HistoryThreads result;
+    
+    int alloc_count = return_value_sp->GetValueForExpressionPath(".alloc_count")->GetValueAsUnsigned(0);
+    int free_count = return_value_sp->GetValueForExpressionPath(".free_count")->GetValueAsUnsigned(0);
+    tid_t alloc_tid = return_value_sp->GetValueForExpressionPath(".alloc_tid")->GetValueAsUnsigned(0);
+    tid_t free_tid = return_value_sp->GetValueForExpressionPath(".free_tid")->GetValueAsUnsigned(0);
+    
+    if (alloc_count > 0)
+    {
+        std::vector<lldb::addr_t> pcs;
+        ValueObjectSP trace_sp = return_value_sp->GetValueForExpressionPath(".alloc_trace");
+        for (int i = 0; i < alloc_count; i++) {
+            addr_t pc = trace_sp->GetChildAtIndex(i, true)->GetValueAsUnsigned(0);
+            pcs.push_back(pc);
+        }
+        
+        HistoryThread *history_thread = new HistoryThread(*process_sp, alloc_tid, pcs, 0, false);
+        ThreadSP new_thread_sp(history_thread);
+        // let's use thread name for the type of history thread, since history threads don't have names anyway
+        history_thread->SetThreadName("Memory allocated at");
+        result.push_back(new_thread_sp);
+    }
+    
+    if (free_count > 0)
+    {
+        std::vector<lldb::addr_t> pcs;
+        ValueObjectSP trace_sp = return_value_sp->GetValueForExpressionPath(".free_trace");
+        for (int i = 0; i < free_count; i++) {
+            addr_t pc = trace_sp->GetChildAtIndex(i, true)->GetValueAsUnsigned(0);
+            pcs.push_back(pc);
+        }
+        
+        HistoryThread *history_thread = new HistoryThread(*process_sp, free_tid, pcs, 0, false);
+        ThreadSP new_thread_sp(history_thread);
+        // let's use thread name for the type of history thread, since history threads don't have names anyway
+        history_thread->SetThreadName("Memory deallocated at");
+        result.push_back(new_thread_sp);
+    }
+    
+    return result;
+}

Added: lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h (added)
+++ lldb/trunk/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.h Wed Sep  3 20:03:18 2014
@@ -0,0 +1,62 @@
+//===-- MemoryHistoryASan.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_MemoryHistoryASan_h_
+#define liblldb_MemoryHistoryASan_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/MemoryHistory.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+class MemoryHistoryASan : public lldb_private::MemoryHistory
+{
+public:
+    
+    static lldb::MemoryHistorySP
+    CreateInstance (const lldb::ProcessSP &process_sp);
+    
+    static void
+    Initialize();
+    
+    static void
+    Terminate();
+    
+    static lldb_private::ConstString
+    GetPluginNameStatic();
+    
+    virtual
+    ~MemoryHistoryASan () {}
+    
+    virtual lldb_private::ConstString
+    GetPluginName() { return GetPluginNameStatic(); }
+    
+    virtual uint32_t
+    GetPluginVersion() { return 1; }
+    
+    virtual lldb_private::HistoryThreads
+    GetHistoryThreads(lldb::addr_t address);
+    
+private:
+    
+    MemoryHistoryASan(const lldb::ProcessSP &process_sp);
+    
+    lldb::ProcessSP m_process_sp;
+    
+};
+
+} // namespace lldb_private
+    
+#endif  // liblldb_MemoryHistoryASan_h_

Modified: lldb/trunk/source/Plugins/Process/Utility/HistoryThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/HistoryThread.h?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/HistoryThread.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/HistoryThread.h Wed Sep  3 20:03:18 2014
@@ -101,6 +101,18 @@ public:
     {
         m_thread_name = name;
     }
+    
+    virtual const char *
+    GetName ()
+    {
+        return m_thread_name.c_str();
+    }
+    
+    virtual void
+    SetName(const char *name)
+    {
+        m_thread_name = name;
+    }
 
 protected:
     virtual lldb::StackFrameListSP

Modified: lldb/trunk/source/Target/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/CMakeLists.txt?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/Target/CMakeLists.txt (original)
+++ lldb/trunk/source/Target/CMakeLists.txt Wed Sep  3 20:03:18 2014
@@ -11,6 +11,7 @@ add_lldb_library(lldbTarget
   JITLoaderList.cpp
   LanguageRuntime.cpp
   Memory.cpp
+  MemoryHistory.cpp
   NativeRegisterContext.cpp
   NativeRegisterContextRegisterInfo.cpp
   ObjCLanguageRuntime.cpp

Added: lldb/trunk/source/Target/MemoryHistory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/MemoryHistory.cpp?rev=217116&view=auto
==============================================================================
--- lldb/trunk/source/Target/MemoryHistory.cpp (added)
+++ lldb/trunk/source/Target/MemoryHistory.cpp Wed Sep  3 20:03:18 2014
@@ -0,0 +1,28 @@
+//===-- MemoryHistory.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/Target/MemoryHistory.h"
+
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::MemoryHistorySP
+MemoryHistory::FindPlugin (const ProcessSP process)
+{
+    MemoryHistoryCreateInstance create_callback = NULL;
+    
+    for (uint32_t idx = 0; (create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex(idx)) != NULL; ++idx)
+    {
+        return create_callback(process);
+    }
+    
+    return MemoryHistorySP();
+}

Modified: lldb/trunk/source/lldb.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/source/lldb.cpp (original)
+++ lldb/trunk/source/lldb.cpp Wed Sep  3 20:03:18 2014
@@ -92,6 +92,7 @@
 #include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
 #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
 #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+#include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -154,6 +155,7 @@ lldb_private::Initialize ()
 #endif
         JITLoaderGDB::Initialize();
         ProcessElfCore::Initialize();
+        MemoryHistoryASan::Initialize();
         
 #if defined (__APPLE__)
         //----------------------------------------------------------------------
@@ -244,6 +246,7 @@ lldb_private::Terminate ()
 #endif
     JITLoaderGDB::Terminate();
     ProcessElfCore::Terminate();
+    MemoryHistoryASan::Terminate();
     
 #if defined (__APPLE__)
     DynamicLoaderMacOSXDYLD::Terminate();

Added: lldb/trunk/test/functionalities/asan/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/asan/Makefile?rev=217116&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/asan/Makefile (added)
+++ lldb/trunk/test/functionalities/asan/Makefile Wed Sep  3 20:03:18 2014
@@ -0,0 +1,6 @@
+LEVEL = ../../make
+
+C_SOURCES := main.c
+CFLAGS := $(CFLAGS) -fsanitize=address -g
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/asan/TestAsan.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/asan/TestAsan.py?rev=217116&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/asan/TestAsan.py (added)
+++ lldb/trunk/test/functionalities/asan/TestAsan.py Wed Sep  3 20:03:18 2014
@@ -0,0 +1,90 @@
+"""
+Test that ASan memory history provider returns correct stack traces
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class AsanTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    # The default compiler ("clang") may not support Address Sanitizer or it
+    # may not have the debugging API which was recently added, so we're calling
+    # self.useBuiltClang() to use clang from the llvm-build directory instead
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym (self):
+        compiler = self.findBuiltClang ()
+        self.buildDsym (None, compiler)
+        self.asan_tests ()
+
+    @dwarf_test
+    def test_with_dwarf (self):
+        compiler = self.findBuiltClang ()
+        self.buildDwarf (None, compiler)
+        self.asan_tests ()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        self.line_malloc = line_number('main.c', '// malloc line')
+        self.line_malloc2 = line_number('main.c', '// malloc2 line')
+        self.line_free = line_number('main.c', '// free line')
+        self.line_breakpoint = line_number('main.c', '// break line')
+
+    def asan_tests (self):
+        exe = os.path.join (os.getcwd(), "a.out")
+        self.expect("file " + exe, patterns = [ "Current executable set to .*a.out" ])
+
+        self.runCmd("breakpoint set -f main.c -l %d" % self.line_breakpoint)
+
+        # "memory history" command should not work without a process
+        self.expect("memory history 0",
+            error = True,
+            substrs = ["invalid process"])
+
+        self.runCmd("run")
+
+        # ASan will relaunch the process to insert its library.
+        self.expect("thread list", "Process should be stopped due to exec.",
+            substrs = ['stopped', 'stop reason = exec'])
+
+        self.runCmd("continue")
+
+        # the stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped', 'stop reason = breakpoint'])
+
+        # test that the ASan dylib is present
+        self.expect("image lookup -n __asan_describe_address", "__asan_describe_address should be present",
+            substrs = ['1 match found'])
+
+        # test the 'memory history' command
+        self.expect("memory history 'pointer'",
+            substrs = [
+                'Memory allocated at', 'a.out`f1', 'main.c:%d' % self.line_malloc,
+                'Memory deallocated at', 'a.out`f2', 'main.c:%d' % self.line_free])
+
+        self.runCmd("breakpoint set -n __asan_report_error")
+
+        self.runCmd("continue")
+
+        # the stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped', 'stop reason = breakpoint'])
+
+        # make sure the 'memory history' command still works even when we're generating a report now
+        self.expect("memory history 'another_pointer'",
+            substrs = [
+                'Memory allocated at', 'a.out`f1', 'main.c:%d' % self.line_malloc2])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/asan/main.c
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/asan/main.c?rev=217116&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/asan/main.c (added)
+++ lldb/trunk/test/functionalities/asan/main.c Wed Sep  3 20:03:18 2014
@@ -0,0 +1,34 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+#include <stdlib.h>
+
+char *pointer;
+char *another_pointer;
+
+void f1() {
+    pointer = malloc(10); // malloc line
+    another_pointer = malloc(20); // malloc2 line
+}
+
+void f2() {
+    free(pointer); // free line
+}
+
+int main (int argc, char const *argv[])
+{
+    f1();
+    f2();
+
+    printf("Hello world!\n"); // break line
+
+    pointer[0] = 'A'; // BOOM
+
+    return 0;
+}

Modified: lldb/trunk/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lldbtest.py?rev=217116&r1=217115&r2=217116&view=diff
==============================================================================
--- lldb/trunk/test/lldbtest.py (original)
+++ lldb/trunk/test/lldbtest.py Wed Sep  3 20:03:18 2014
@@ -1325,6 +1325,22 @@ class Base(unittest2.TestCase):
         if not module.buildDwarf(self, architecture, compiler, dictionary, clean):
             raise Exception("Don't know how to build binary with dwarf")
 
+    def findBuiltClang(self):
+        """Tries to find and use Clang from the build directory as the compiler (instead of the system compiler)."""
+        paths_to_try = [
+          "llvm-build/Release+Asserts/x86_64/Release+Asserts/bin/clang",
+          "llvm-build/Debug+Asserts/x86_64/Debug+Asserts/bin/clang",
+          "llvm-build/Release/x86_64/Release/bin/clang",
+          "llvm-build/Debug/x86_64/Debug/bin/clang",
+        ]
+        lldb_root_path = os.path.join(os.path.dirname(__file__), "..")
+        for p in paths_to_try:
+            path = os.path.join(lldb_root_path, p)
+            if os.path.exists(path):
+                return path
+        
+        return os.environ["CC"]
+
     def getBuildFlags(self, use_cpp11=True, use_libcxx=False, use_libstdcxx=False, use_pthreads=True):
         """ Returns a dictionary (which can be provided to build* functions above) which
             contains OS-specific build flags.





More information about the lldb-commits mailing list