Nice addition, Kuba! I look forward to working with that :-)
On Wed, Sep 3, 2014 at 6:03 PM, Kuba Brecka <[email protected]> wrote: > 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 ¤t_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. > > > _______________________________________________ > lldb-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits > -- Todd Fiala | Software Engineer | [email protected] | 650-943-3180
_______________________________________________ lldb-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits
