diff options
31 files changed, 971 insertions, 21 deletions
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h index 8d2b104ffb6..db15f651f2d 100644 --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -78,7 +78,10 @@ public: //-------------------------------------------------------------------------- uint64_t GetStopReasonDataAtIndex(uint32_t idx); - + + bool + GetStopReasonExtendedInfoAsJSON (lldb::SBStream &stream); + size_t GetStopDescription (char *dst, size_t dst_len); diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index f313e788641..55e6df06d84 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -361,6 +361,28 @@ public: GetMemoryHistoryCreateCallbackForPluginName (const ConstString &name); //------------------------------------------------------------------ + // InstrumentationRuntime + //------------------------------------------------------------------ + static bool + RegisterPlugin (const ConstString &name, + const char *description, + InstrumentationRuntimeCreateInstance create_callback, + InstrumentationRuntimeGetType get_type_callback); + + static bool + UnregisterPlugin (InstrumentationRuntimeCreateInstance create_callback); + + static InstrumentationRuntimeGetType + GetInstrumentationRuntimeGetTypeCallbackAtIndex (uint32_t idx); + + static InstrumentationRuntimeCreateInstance + GetInstrumentationRuntimeCreateCallbackAtIndex (uint32_t idx); + + static InstrumentationRuntimeCreateInstance + GetInstrumentationRuntimeCreateCallbackForPluginName (const ConstString &name); + + + //------------------------------------------------------------------ // Some plug-ins might register a DebuggerInitializeCallback // callback when registering the plug-in. After a new Debugger // instance is created, this DebuggerInitialize function will get diff --git a/lldb/include/lldb/Target/InstrumentationRuntime.h b/lldb/include/lldb/Target/InstrumentationRuntime.h new file mode 100644 index 00000000000..70aa6290840 --- /dev/null +++ b/lldb/include/lldb/Target/InstrumentationRuntime.h @@ -0,0 +1,47 @@ +//===-- InstrumentationRuntime.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_InstrumentationRuntime_h_ +#define liblldb_InstrumentationRuntime_h_ + +// C Includes +// C++ Includes +#include <vector> +#include <map> + +// 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::map<lldb::InstrumentationRuntimeType, lldb::InstrumentationRuntimeSP> InstrumentationRuntimeCollection; + +class InstrumentationRuntime : + public std::enable_shared_from_this<InstrumentationRuntime>, + public PluginInterface +{ +public: + + static void + ModulesDidLoad(lldb_private::ModuleList &module_list, Process *process, InstrumentationRuntimeCollection &runtimes); + + virtual void + ModulesDidLoad(lldb_private::ModuleList &module_list); + + virtual bool + IsActive(); + +}; + +} // namespace lldb_private + +#endif // liblldb_InstrumentationRuntime_h_ diff --git a/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h b/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h new file mode 100644 index 00000000000..624267ce822 --- /dev/null +++ b/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h @@ -0,0 +1,52 @@ +//===-- InstrumentationRuntimeStopInfo.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_InstrumentationRuntimeStopInfo_h_ +#define liblldb_InstrumentationRuntimeStopInfo_h_ + +// C Includes +// C++ Includes +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/Target/StopInfo.h" +#include "lldb/Core/StructuredData.h" + +namespace lldb_private { + +class InstrumentationRuntimeStopInfo : public StopInfo +{ +public: + + virtual ~InstrumentationRuntimeStopInfo() + { + } + + virtual lldb::StopReason + GetStopReason () const + { + return lldb::eStopReasonInstrumentation; + } + + virtual const char * + GetDescription (); + + static lldb::StopInfoSP + CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additional_data); + +private: + + InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data); + +}; + +} // namespace lldb_private + +#endif // liblldb_InstrumentationRuntimeStopInfo_h_ diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 7a9185b3122..ee71f875036 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -52,6 +52,7 @@ #include "lldb/Target/ThreadList.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/PseudoTerminal.h" +#include "lldb/Target/InstrumentationRuntime.h" namespace lldb_private { @@ -3082,6 +3083,7 @@ protected: AllocatedMemoryCache m_allocated_memory_cache; bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach? LanguageRuntimeCollection m_language_runtimes; + InstrumentationRuntimeCollection m_instrumentation_runtimes; std::unique_ptr<NextEventAction> m_next_event_action_ap; std::vector<PreResumeCallbackAndBaton> m_pre_resume_actions; ProcessRunLock m_public_run_lock; diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h index 8de40e852f4..e0d029bcc95 100644 --- a/lldb/include/lldb/Target/StopInfo.h +++ b/lldb/include/lldb/Target/StopInfo.h @@ -18,6 +18,7 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Target/Process.h" +#include "lldb/Core/StructuredData.h" namespace lldb_private { @@ -140,6 +141,12 @@ public: return m_override_should_stop == eLazyBoolYes; } + StructuredData::ObjectSP + GetExtendedInfo () + { + return m_extended_info; + } + static lldb::StopInfoSP CreateStopReasonWithBreakpointSiteID (Thread &thread, lldb::break_id_t break_id); @@ -211,6 +218,8 @@ protected: LazyBool m_override_should_notify; LazyBool m_override_should_stop; + StructuredData::ObjectSP m_extended_info; // The extended info for this stop info + // This determines whether the target has run since this stop info. // N.B. running to evaluate a user expression does not count. bool HasTargetRunSinceMe (); diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 87373fb8f19..64b610eaa55 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -535,7 +535,7 @@ public: DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx); bool - GetDescription (Stream &s, lldb::DescriptionLevel level, bool json_output); + GetDescription (Stream &s, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo); //------------------------------------------------------------------ /// Default implementation for stepping into. diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 5164326c895..b49e29cded0 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -185,7 +185,8 @@ namespace lldb { eStopReasonException, eStopReasonExec, // Program was re-exec'ed eStopReasonPlanComplete, - eStopReasonThreadExiting + eStopReasonThreadExiting, + eStopReasonInstrumentation } StopReason; //---------------------------------------------------------------------- @@ -387,6 +388,11 @@ namespace lldb { eLanguageTypeDylan = 0x0020, ///< Dylan. eNumLanguageTypes } LanguageType; + + typedef enum InstrumentationRuntimeType { + eInstrumentationRuntimeTypeAddressSanitizer = 0x0000, + eNumInstrumentationRuntimeTypes + } InstrumentationRuntimeType; typedef enum DynamicValueType { diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 97660aaad30..0f95fc9f383 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -104,6 +104,7 @@ class FunctionInfo; class InlineFunctionInfo; class Instruction; class InstructionList; +class InstrumentationRuntime; class IOHandler; class IOObject; class IRExecutionUnit; @@ -312,6 +313,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP; typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP; typedef std::shared_ptr<lldb_private::Instruction> InstructionSP; + typedef std::shared_ptr<lldb_private::InstrumentationRuntime> InstrumentationRuntimeSP; typedef std::shared_ptr<lldb_private::IOHandler> IOHandlerSP; typedef std::shared_ptr<lldb_private::IOObject> IOObjectSP; typedef std::shared_ptr<lldb_private::JITLoader> JITLoaderSP; diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index db0c84ec9e4..4d608fe10cc 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -40,6 +40,8 @@ namespace lldb_private 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 lldb::InstrumentationRuntimeType (*InstrumentationRuntimeGetType) (); + typedef lldb::InstrumentationRuntimeSP (*InstrumentationRuntimeCreateInstance) (const lldb::ProcessSP &process_sp); typedef int (*ComparisonFunction)(const void *, const void *); typedef void (*DebuggerInitializeCallback)(Debugger &debugger); diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 3454c9f56cb..b4d59d73824 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -637,6 +637,9 @@ 8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; }; 8CCB018219BA4E270009FD44 /* SBThreadCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8CCB018319BA51BF0009FD44 /* SBThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */; }; + 8CF02AE919DCC01900B14BE0 /* InstrumentationRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */; }; + 8CF02AEA19DCC02100B14BE0 /* AddressSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02AE519DCBF8400B14BE0 /* AddressSanitizerRuntime.cpp */; }; + 8CF02AEF19DD16B100B14BE0 /* InstrumentationRuntimeStopInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CF02AED19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.cpp */; }; 94094C6B163B6F840083A547 /* ValueObjectCast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94094C69163B6CD90083A547 /* ValueObjectCast.cpp */; }; 940B02F619DC96E700AD0F52 /* SBExecutionContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 940B02F519DC96E700AD0F52 /* SBExecutionContext.cpp */; }; 94145431175E63B500284436 /* lldb-versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 94145430175D7FDE00284436 /* lldb-versioning.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1965,6 +1968,12 @@ 8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SBThreadCollection.cpp; path = source/API/SBThreadCollection.cpp; sourceTree = "<group>"; }; 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBThreadCollection.h; path = include/lldb/API/SBThreadCollection.h; sourceTree = "<group>"; }; 8CCB018419BA54930009FD44 /* SBThreadCollection.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBThreadCollection.i; sourceTree = "<group>"; }; + 8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentationRuntime.cpp; path = source/Target/InstrumentationRuntime.cpp; sourceTree = "<group>"; }; + 8CF02AE019DCBF3B00B14BE0 /* InstrumentationRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InstrumentationRuntime.h; path = include/lldb/Target/InstrumentationRuntime.h; sourceTree = "<group>"; }; + 8CF02AE519DCBF8400B14BE0 /* AddressSanitizerRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AddressSanitizerRuntime.cpp; sourceTree = "<group>"; }; + 8CF02AE619DCBF8400B14BE0 /* AddressSanitizerRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddressSanitizerRuntime.h; sourceTree = "<group>"; }; + 8CF02AED19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = InstrumentationRuntimeStopInfo.cpp; path = source/Target/InstrumentationRuntimeStopInfo.cpp; sourceTree = "<group>"; }; + 8CF02AEE19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = InstrumentationRuntimeStopInfo.h; path = include/lldb/Target/InstrumentationRuntimeStopInfo.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>"; }; @@ -2423,6 +2432,7 @@ 260C897110F57C5600BB2B04 /* Plugins */ = { isa = PBXGroup; children = ( + 8CF02ADD19DCBEC200B14BE0 /* InstrumentationRuntime */, 8C2D6A58197A1FB9006989C9 /* MemoryHistory */, 26DB3E051379E7AD0080DC73 /* ABI */, 260C897210F57C5600BB2B04 /* Disassembler */, @@ -3746,6 +3756,10 @@ 26BC7DEF10F1B80200F91463 /* Target */ = { isa = PBXGroup; children = ( + 8CF02AE019DCBF3B00B14BE0 /* InstrumentationRuntime.h */, + 8CF02ADF19DCBF3B00B14BE0 /* InstrumentationRuntime.cpp */, + 8CF02AEE19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.h */, + 8CF02AED19DD15CF00B14BE0 /* InstrumentationRuntimeStopInfo.cpp */, 3FDFD6C3199C396E009756A7 /* FileAction.h */, 3FDFDDBC199C3A06009756A7 /* FileAction.cpp */, 23EDE3311926843600F6A132 /* NativeRegisterContext.h */, @@ -4264,6 +4278,23 @@ path = asan; sourceTree = "<group>"; }; + 8CF02ADD19DCBEC200B14BE0 /* InstrumentationRuntime */ = { + isa = PBXGroup; + children = ( + 8CF02ADE19DCBEE600B14BE0 /* AddressSanitizer */, + ); + path = InstrumentationRuntime; + sourceTree = "<group>"; + }; + 8CF02ADE19DCBEE600B14BE0 /* AddressSanitizer */ = { + isa = PBXGroup; + children = ( + 8CF02AE519DCBF8400B14BE0 /* AddressSanitizerRuntime.cpp */, + 8CF02AE619DCBF8400B14BE0 /* AddressSanitizerRuntime.h */, + ); + path = AddressSanitizer; + sourceTree = "<group>"; + }; 9457596415349416005A9070 /* POSIX */ = { isa = PBXGroup; children = ( @@ -4965,6 +4996,7 @@ 2689000713353DB600698AC0 /* BreakpointSite.cpp in Sources */, 2689000913353DB600698AC0 /* BreakpointSiteList.cpp in Sources */, 26474CC918D0CB5B0073DEBA /* RegisterContextMemory.cpp in Sources */, + 8CF02AEA19DCC02100B14BE0 /* AddressSanitizerRuntime.cpp in Sources */, 26474CB218D0CB180073DEBA /* RegisterContextLinux_i386.cpp in Sources */, 26474CCB18D0CB5B0073DEBA /* RegisterContextPOSIX_mips64.cpp in Sources */, 2689000B13353DB600698AC0 /* Stoppoint.cpp in Sources */, @@ -5002,6 +5034,7 @@ 2689002813353DDE00698AC0 /* CommandObjectThread.cpp in Sources */, 2689002913353DDE00698AC0 /* CommandObjectVersion.cpp in Sources */, 2689002A13353E0400698AC0 /* Address.cpp in Sources */, + 8CF02AE919DCC01900B14BE0 /* InstrumentationRuntime.cpp in Sources */, 2689002B13353E0400698AC0 /* AddressRange.cpp in Sources */, 236124A41986B4E2004EFC37 /* IOObject.cpp in Sources */, 2689002C13353E0400698AC0 /* AddressResolver.cpp in Sources */, @@ -5223,6 +5256,7 @@ 268900FA13353E6F00698AC0 /* ThreadList.cpp in Sources */, 268900FB13353E6F00698AC0 /* ThreadPlan.cpp in Sources */, 232CB619191E00CD00EF39FC /* NativeProcessProtocol.cpp in Sources */, + 8CF02AEF19DD16B100B14BE0 /* InstrumentationRuntimeStopInfo.cpp in Sources */, 268900FC13353E6F00698AC0 /* ThreadPlanBase.cpp in Sources */, 268900FD13353E6F00698AC0 /* ThreadPlanCallFunction.cpp in Sources */, 268900FE13353E6F00698AC0 /* ThreadPlanCallUserExpression.cpp in Sources */, diff --git a/lldb/scripts/Python/interface/SBThread.i b/lldb/scripts/Python/interface/SBThread.i index dac0f9bc4a7..53848214352 100644 --- a/lldb/scripts/Python/interface/SBThread.i +++ b/lldb/scripts/Python/interface/SBThread.i @@ -110,6 +110,14 @@ public: ") GetStopReasonDataAtIndex; uint64_t GetStopReasonDataAtIndex(uint32_t idx); + + %feature("autodoc", " + Collects a thread's stop reason extended information dictionary and prints it + into the SBStream in a JSON format. The format of this JSON dictionary depends + on the stop reason and is currently used only for instrumentation plugins. + ") GetStopReasonExtendedInfoAsJSON; + bool + GetStopReasonExtendedInfoAsJSON (lldb::SBStream &stream); %feature("autodoc", " Pass only an (int)length and expect to get a Python string describing the diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp index 390fa0d4b6e..036ce10fcde 100644 --- a/lldb/source/API/SBThread.cpp +++ b/lldb/source/API/SBThread.cpp @@ -195,6 +195,7 @@ SBThread::GetStopReasonDataCount () case eStopReasonExec: case eStopReasonPlanComplete: case eStopReasonThreadExiting: + case eStopReasonInstrumentation: // There is no data for these stop reasons. return 0; @@ -255,6 +256,7 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx) case eStopReasonExec: case eStopReasonPlanComplete: case eStopReasonThreadExiting: + case eStopReasonInstrumentation: // There is no data for these stop reasons. return 0; @@ -306,6 +308,26 @@ SBThread::GetStopReasonDataAtIndex (uint32_t idx) return 0; } +bool +SBThread::GetStopReasonExtendedInfoAsJSON (lldb::SBStream &stream) +{ + Stream &strm = stream.ref(); + + ExecutionContext exe_ctx (m_opaque_sp.get()); + if (! exe_ctx.HasThreadScope()) + return false; + + + StopInfoSP stop_info = exe_ctx.GetThreadPtr()->GetStopInfo(); + StructuredData::ObjectSP info = stop_info->GetExtendedInfo(); + if (! info) + return false; + + info->Dump(strm); + + return true; +} + size_t SBThread::GetStopDescription (char *dst, size_t dst_len) { diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 785e8f078ee..fbb233ab1db 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1431,7 +1431,8 @@ public: void OptionParsingStarting () { - m_json = false; + m_json_thread = false; + m_json_stopinfo = false; } virtual @@ -1448,10 +1449,14 @@ public: switch (short_option) { case 'j': - m_json = true; + m_json_thread = true; + break; + + case 's': + m_json_stopinfo = true; break; - default: + default: return Error("invalid short option character '%c'", short_option); } @@ -1464,7 +1469,8 @@ public: return g_option_table; } - bool m_json; + bool m_json_thread; + bool m_json_stopinfo; static OptionDefinition g_option_table[]; }; @@ -1486,7 +1492,7 @@ public: HandleOneThread (Thread &thread, CommandReturnObject &result) { Stream &strm = result.GetOutputStream(); - if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) + if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json_thread, m_options.m_json_stopinfo)) { result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID()); result.SetStatus (eReturnStatusFailed); @@ -1503,6 +1509,7 @@ OptionDefinition CommandObjectThreadInfo::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."}, + { LLDB_OPT_SET_ALL, false, "stop-info",'s', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the extended stop info in JSON format."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 5a910a9040a..2dc9b0367cf 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -3234,6 +3234,7 @@ Debugger::HandleProcessEvent (const EventSP &event_sp) case eStopReasonException: case eStopReasonExec: case eStopReasonThreadExiting: + case eStopReasonInstrumentation: if (!other_thread) other_thread = thread; break; diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index 0cca76ee95e..95574cb2dea 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -2172,6 +2172,125 @@ PluginManager::GetMemoryHistoryCreateCallbackForPluginName (const ConstString &n return NULL; } +#pragma mark InstrumentationRuntime + +struct InstrumentationRuntimeInstance +{ + InstrumentationRuntimeInstance() : + name(), + description(), + create_callback(NULL) + { + } + + ConstString name; + std::string description; + InstrumentationRuntimeCreateInstance create_callback; + InstrumentationRuntimeGetType get_type_callback; +}; + +typedef std::vector<InstrumentationRuntimeInstance> InstrumentationRuntimeInstances; + +static Mutex & +GetInstrumentationRuntimeMutex () +{ + static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive); + return g_instances_mutex; +} + +static InstrumentationRuntimeInstances & +GetInstrumentationRuntimeInstances () +{ + static InstrumentationRuntimeInstances g_instances; + return g_instances; +} + +bool +PluginManager::RegisterPlugin +( + const ConstString &name, + const char *description, + InstrumentationRuntimeCreateInstance create_callback, + InstrumentationRuntimeGetType get_type_callback + ) +{ + if (create_callback) + { + InstrumentationRuntimeInstance instance; + assert ((bool)name); + instance.name = name; + if (description && description[0]) + instance.description = description; + instance.create_callback = create_callback; + instance.get_type_callback = get_type_callback; + Mutex::Locker locker (GetInstrumentationRuntimeMutex ()); + GetInstrumentationRuntimeInstances ().push_back (instance); + } + return false; +} + +bool +PluginManager::UnregisterPlugin (InstrumentationRuntimeCreateInstance create_callback) +{ + if (create_callback) + { + Mutex::Locker locker (GetInstrumentationRuntimeMutex ()); + InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances (); + + InstrumentationRuntimeInstances::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; +} + +InstrumentationRuntimeGetType +PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex (uint32_t idx) +{ + Mutex::Locker locker (GetInstrumentationRuntimeMutex ()); + InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances (); + if (idx < instances.size()) + return instances[idx].get_type_callback; + return NULL; +} + +InstrumentationRuntimeCreateInstance +PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex (uint32_t idx) +{ + Mutex::Locker locker (GetInstrumentationRuntimeMutex ()); + InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances (); + if (idx < instances.size()) + return instances[idx].create_callback; + return NULL; +} + + +InstrumentationRuntimeCreateInstance +PluginManager::GetInstrumentationRuntimeCreateCallbackForPluginName (const ConstString &name) +{ + if (name) + { + Mutex::Locker locker (GetInstrumentationRuntimeMutex ()); + InstrumentationRuntimeInstances &instances = GetInstrumentationRuntimeInstances (); + + InstrumentationRuntimeInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (name == pos->name) + return pos->create_callback; + } + } + return NULL; +} + +#pragma mark PluginManager + void PluginManager::DebuggerInitialize (Debugger &debugger) { diff --git a/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp new file mode 100644 index 00000000000..26d01345b34 --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp @@ -0,0 +1,300 @@ +//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "AddressSanitizerRuntime.h" + +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Core/Module.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Target/InstrumentationRuntimeStopInfo.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" + +using namespace lldb; +using namespace lldb_private; + +lldb::InstrumentationRuntimeSP +AddressSanitizerRuntime::CreateInstance (const lldb::ProcessSP &process_sp) +{ + return InstrumentationRuntimeSP(new AddressSanitizerRuntime(process_sp)); +} + +void +AddressSanitizerRuntime::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "AddressSanitizer instrumentation runtime plugin.", + CreateInstance, + GetTypeStatic); +} + +void +AddressSanitizerRuntime::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +AddressSanitizerRuntime::GetPluginNameStatic() +{ + return ConstString("AddressSanitizer"); +} + +lldb::InstrumentationRuntimeType +AddressSanitizerRuntime::GetTypeStatic() +{ + return eInstrumentationRuntimeTypeAddressSanitizer; +} + +AddressSanitizerRuntime::AddressSanitizerRuntime(const ProcessSP &process_sp) : + m_is_active(false), + m_runtime_module(), + m_process(process_sp), + m_breakpoint_id(0) +{ +} + +AddressSanitizerRuntime::~AddressSanitizerRuntime() +{ + Deactivate(); +} + +bool ModuleContainsASanRuntime(Module * module) +{ + SymbolContextList sc_list; + const bool include_symbols = true; + const bool append = true; + const bool include_inlines = true; + + size_t num_matches = module->FindFunctions(ConstString("__asan_get_alloc_stack"), NULL, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list); + + return num_matches > 0; +} + +void +AddressSanitizerRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list) +{ + if (IsActive()) + return; + + if (m_runtime_module) { + Activate(); + return; + } + + Mutex::Locker modules_locker(module_list.GetMutex()); + const size_t num_modules = module_list.GetSize(); + for (size_t i = 0; i < num_modules; ++i) + { + Module *module_pointer = module_list.GetModulePointerAtIndexUnlocked(i); + const FileSpec & file_spec = module_pointer->GetFileSpec(); + if (! file_spec) + continue; + + static RegularExpression g_asan_runtime_regex("libclang_rt.asan_(.*)_dynamic\\.dylib"); + if (g_asan_runtime_regex.Execute (file_spec.GetFilename().GetCString()) || module_pointer->IsExecutable()) + { + if (ModuleContainsASanRuntime(module_pointer)) + { + m_runtime_module = module_pointer->shared_from_this(); + Activate(); + return; + } + } + } +} + +bool +AddressSanitizerRuntime::IsActive() +{ + return m_is_active; +} + +#define RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC 2*1000*1000 + +const char * +address_sanitizer_retrieve_report_data_command = R"( + struct { + int present; + void *pc, *bp, *sp, *address; + int access_type; + size_t access_size; + const char *description; + } t; + + t.present = ((int (*) ())__asan_report_present)(); + t.pc = ((void * (*) ())__asan_get_report_pc)(); + /* commented out because rdar://problem/18533301 + t.bp = ((void * (*) ())__asan_get_report_bp)(); + t.sp = ((void * (*) ())__asan_get_report_sp)(); + */ + t.address = ((void * (*) ())__asan_get_report_address)(); + t.description = ((const char * (*) ())__asan_get_report_description)(); + t.access_type = ((int (*) ())__asan_get_report_access_type)(); + t.access_size = ((size_t (*) ())__asan_get_report_access_size)(); + + t; +)"; + +StructuredData::ObjectSP +AddressSanitizerRuntime::RetrieveReportData() +{ + ThreadSP thread_sp = m_process->GetThreadList().GetSelectedThread(); + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + + if (!frame_sp) + return StructuredData::ObjectSP(); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(RETRIEVE_REPORT_DATA_FUNCTION_TIMEOUT_USEC); + + ValueObjectSP return_value_sp; + if (m_process->GetTarget().EvaluateExpression(address_sanitizer_retrieve_report_data_command, frame_sp.get(), return_value_sp, options) != eExpressionCompleted) + return StructuredData::ObjectSP(); + + int present = return_value_sp->GetValueForExpressionPath(".present")->GetValueAsUnsigned(0); + if (present != 1) + return StructuredData::ObjectSP(); + + addr_t pc = return_value_sp->GetValueForExpressionPath(".pc")->GetValueAsUnsigned(0); + addr_t bp = return_value_sp->GetValueForExpressionPath(".bp")->GetValueAsUnsigned(0); + addr_t sp = return_value_sp->GetValueForExpressionPath(".sp")->GetValueAsUnsigned(0); + addr_t address = return_value_sp->GetValueForExpressionPath(".address")->GetValueAsUnsigned(0); + addr_t access_type = return_value_sp->GetValueForExpressionPath(".access_type")->GetValueAsUnsigned(0); + addr_t access_size = return_value_sp->GetValueForExpressionPath(".access_size")->GetValueAsUnsigned(0); + addr_t description_ptr = return_value_sp->GetValueForExpressionPath(".description")->GetValueAsUnsigned(0); + std::string description; + Error error; + m_process->ReadCStringFromMemory(description_ptr, description, error); + + StructuredData::Dictionary *dict = new StructuredData::Dictionary(); + dict->AddStringItem("instrumentation_class", "AddressSanitizer"); + dict->AddStringItem("stop_type", "fatal_error"); + dict->AddIntegerItem("pc", pc); + dict->AddIntegerItem("bp", bp); + dict->AddIntegerItem("sp", sp); + dict->AddIntegerItem("address", address); + dict->AddIntegerItem("access_type", access_type); + dict->AddIntegerItem("access_size", access_size); + dict->AddStringItem("description", description); + + return StructuredData::ObjectSP(dict); +} + +std::string +AddressSanitizerRuntime::FormatDescription(StructuredData::ObjectSP report) +{ + std::string description = report->GetAsDictionary()->GetValueForKey("description")->GetAsString()->GetValue(); + if (description == "heap-use-after-free") { + return "Use of deallocated memory detected"; + } else if (description == "heap-buffer-overflow") { + return "Heap buffer overflow detected"; + } else if (description == "stack-buffer-underflow") { + return "Stack buffer underflow detected"; + } else if (description == "initialization-order-fiasco") { + return "Initialization order problem detected"; + } else if (description == "stack-buffer-overflow") { + return "Stack buffer overflow detected"; + } else if (description == "stack-use-after-return") { + return "Use of returned stack memory detected"; + } else if (description == "use-after-poison") { + return "Use of poisoned memory detected"; + } else if (description == "container-overflow") { + return "Container overflow detected"; + } else if (description == "stack-use-after-scope") { + return "Use of out-of-scope stack memory detected"; + } else if (description == "global-buffer-overflow") { + return "Global buffer overflow detected"; + } else if (description == "unknown-crash") { + return "Invalid memory access detected"; + } + + // for unknown report codes just show the code + return description; +} + +bool +AddressSanitizerRuntime::NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, user_id_t break_id, user_id_t break_loc_id) +{ + assert (baton && "null baton"); + if (!baton) + return false; + + AddressSanitizerRuntime *const instance = static_cast<AddressSanitizerRuntime*>(baton); + + StructuredData::ObjectSP report = instance->RetrieveReportData(); + std::string description; + if (report) { + description = instance->FormatDescription(report); + } + ThreadSP thread = context->exe_ctx_ref.GetThreadSP(); + thread->SetStopInfo(InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(*thread, description.c_str(), report)); + + instance->m_runtime_module->ReportWarning("AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.\n"); + + // Return true to stop the target, false to just let the target run. + return true; +} + +void +AddressSanitizerRuntime::Activate() +{ + if (m_is_active) + return; + + ConstString symbol_name ("__asan::AsanDie()"); + const Symbol *symbol = m_runtime_module->FindFirstSymbolWithNameAndType (symbol_name, eSymbolTypeCode); + + if (symbol == NULL) + return; + + if (!symbol->GetAddress().IsValid()) + return; + + Target &target = m_process->GetTarget(); + addr_t symbol_address = symbol->GetAddress().GetOpcodeLoadAddress(&target); + + if (symbol_address == LLDB_INVALID_ADDRESS) + return; + + bool internal = true; + bool hardware = false; + Breakpoint *breakpoint = m_process->GetTarget().CreateBreakpoint(symbol_address, internal, hardware).get(); + breakpoint->SetCallback (AddressSanitizerRuntime::NotifyBreakpointHit, this, true); + breakpoint->SetBreakpointKind ("address-sanitizer-report"); + m_breakpoint_id = breakpoint->GetID(); + + m_runtime_module->ReportWarning("AddressSanitizer debugger support is active. Memory error breakpoint has been installed and you can now use the 'memory history' command.\n"); + + m_is_active = true; +} + +void +AddressSanitizerRuntime::Deactivate() +{ + if (m_breakpoint_id != LLDB_INVALID_BREAK_ID) + { + m_process->GetTarget().RemoveBreakpointByID(m_breakpoint_id); + m_breakpoint_id = LLDB_INVALID_BREAK_ID; + } + m_is_active = false; +} diff --git a/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h new file mode 100644 index 00000000000..69c134cbeda --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h @@ -0,0 +1,86 @@ +//===-- AddressSanitizerRuntime.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_AddressSanitizerRuntime_h_ +#define liblldb_AddressSanitizerRuntime_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/StructuredData.h" + +namespace lldb_private { + +class AddressSanitizerRuntime : public lldb_private::InstrumentationRuntime +{ +public: + + static lldb::InstrumentationRuntimeSP + CreateInstance (const lldb::ProcessSP &process_sp); + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static lldb::InstrumentationRuntimeType + GetTypeStatic(); + + virtual + ~AddressSanitizerRuntime(); + + virtual lldb_private::ConstString + GetPluginName() { return GetPluginNameStatic(); } + + virtual lldb::InstrumentationRuntimeType + GetType() { return GetTypeStatic(); } + + virtual uint32_t + GetPluginVersion() { return 1; } + + virtual void + ModulesDidLoad(lldb_private::ModuleList &module_list); + + virtual bool + IsActive(); + +private: + + AddressSanitizerRuntime(const lldb::ProcessSP &process_sp); + + void + Activate(); + + void + Deactivate(); + + static bool + NotifyBreakpointHit(void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + + StructuredData::ObjectSP + RetrieveReportData(); + + std::string + FormatDescription(StructuredData::ObjectSP report); + + bool m_is_active; + lldb::ModuleSP m_runtime_module; + lldb::ProcessSP m_process; + lldb::user_id_t m_breakpoint_id; + +}; + +} // namespace lldb_private + +#endif // liblldb_InstrumentationRuntime_h_ diff --git a/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt new file mode 100644 index 00000000000..becc0fd8604 --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginInstrumentationRuntimeAddressSanitizer + AddressSanitizerRuntime.cpp + ) diff --git a/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile new file mode 100644 index 00000000000..030aec17b02 --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/InstrumentationRuntime/AddressSanitizer 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 := lldbPluginInstrumentationRuntimeAddressSanitizer +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt new file mode 100644 index 00000000000..8ee303b2535 --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(AddressSanitizer) diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index bfd4d47c034..f534b33bad2 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -9,6 +9,8 @@ add_lldb_library(lldbTarget FileAction.cpp JITLoader.cpp JITLoaderList.cpp + InstrumentationRuntime.cpp + InstrumentationRuntimeStopInfo.cpp LanguageRuntime.cpp Memory.cpp MemoryHistory.cpp diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp new file mode 100644 index 00000000000..b3b2393b023 --- /dev/null +++ b/lldb/source/Target/InstrumentationRuntime.cpp @@ -0,0 +1,48 @@ +//===-- InstrumentationRuntime.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/lldb-private.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/InstrumentationRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +void +InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list, lldb_private::Process *process, InstrumentationRuntimeCollection &runtimes) +{ + InstrumentationRuntimeCreateInstance create_callback = NULL; + InstrumentationRuntimeGetType get_type_callback; + for (uint32_t idx = 0; ; ++idx) + { + create_callback = PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx); + if (create_callback == NULL) + break; + get_type_callback = PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx); + InstrumentationRuntimeType type = get_type_callback(); + + InstrumentationRuntimeCollection::iterator pos; + pos = runtimes.find (type); + if (pos == runtimes.end()) { + runtimes[type] = create_callback(process->shared_from_this()); + } + } +} + +void +InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list) +{ +} + +bool +InstrumentationRuntime::IsActive() +{ + return false; +} diff --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp new file mode 100644 index 00000000000..cdbf93b5f72 --- /dev/null +++ b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp @@ -0,0 +1,36 @@ +//===-- InstrumentationRuntimeStopInfo.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/InstrumentationRuntimeStopInfo.h" + +#include "lldb/lldb-private.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/InstrumentationRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data) : + StopInfo(thread, 0) +{ + m_extended_info = additional_data; + m_description = description; +} + +const char * +InstrumentationRuntimeStopInfo::GetDescription () +{ + return m_description.c_str(); +} + +StopInfoSP +InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additionalData) +{ + return StopInfoSP(new InstrumentationRuntimeStopInfo(thread, description, additionalData)); +} diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index dbdbbe22c90..d337d8110c8 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -48,6 +48,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanBase.h" +#include "lldb/Target/InstrumentationRuntime.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" using namespace lldb; @@ -843,6 +844,7 @@ Process::Finalize() m_memory_cache.Clear(); m_allocated_memory_cache.Clear(); m_language_runtimes.clear(); + m_instrumentation_runtimes.clear(); m_next_event_action_ap.reset(); //#ifdef LLDB_CONFIGURATION_DEBUG // StreamFile s(stdout, false); @@ -5983,6 +5985,7 @@ Process::DidExec () m_image_tokens.clear(); m_allocated_memory_cache.Clear(); m_language_runtimes.clear(); + m_instrumentation_runtimes.clear(); m_thread_list.DiscardThreadPlans(); m_memory_cache.Clear(true); DoDidExec(); @@ -6033,13 +6036,24 @@ Process::ResolveIndirectFunction(const Address *address, Error &error) void Process::ModulesDidLoad (ModuleList &module_list) { - SystemRuntime *sys_runtime = GetSystemRuntime(); - if (sys_runtime) - { - sys_runtime->ModulesDidLoad (module_list); - } + SystemRuntime *sys_runtime = GetSystemRuntime(); + if (sys_runtime) + { + sys_runtime->ModulesDidLoad (module_list); + } + + GetJITLoaders().ModulesDidLoad (module_list); + + // Give runtimes a chance to be created. + InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes); + + // Tell runtimes about new modules. + for (auto pos = m_instrumentation_runtimes.begin(); pos != m_instrumentation_runtimes.end(); ++pos) + { + InstrumentationRuntimeSP runtime = pos->second; + runtime->ModulesDidLoad(module_list); + } - GetJITLoaders().ModulesDidLoad (module_list); } ThreadCollectionSP diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index a37a4079ff1..b7cf11cfb7d 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -40,7 +40,8 @@ StopInfo::StopInfo (Thread &thread, uint64_t value) : m_resume_id (thread.GetProcess()->GetResumeID()), m_value (value), m_override_should_notify (eLazyBoolCalculate), - m_override_should_stop (eLazyBoolCalculate) + m_override_should_stop (eLazyBoolCalculate), + m_extended_info() { } diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index f4b15f5c9d2..17f06194fc1 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -2086,6 +2086,7 @@ Thread::StopReasonAsCString (lldb::StopReason reason) case eStopReasonExec: return "exec"; case eStopReasonPlanComplete: return "plan complete"; case eStopReasonThreadExiting: return "thread exiting"; + case eStopReasonInstrumentation: return "instrumentation break"; } @@ -2165,17 +2166,28 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint } bool -Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json) +Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo) { DumpUsingSettingsFormat (strm, 0); strm.Printf("\n"); StructuredData::ObjectSP thread_info = GetExtendedInfo(); - - if (thread_info && print_json) + StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo(); + + if (print_json_thread || print_json_stopinfo) { - thread_info->Dump (strm); - strm.Printf("\n"); + if (thread_info && print_json_thread) + { + thread_info->Dump (strm); + strm.Printf("\n"); + } + + if (stop_info && print_json_stopinfo) + { + stop_info->Dump (strm); + strm.Printf("\n"); + } + return true; } diff --git a/lldb/source/lldb.cpp b/lldb/source/lldb.cpp index cb2af8a081d..99a54b2a4e6 100644 --- a/lldb/source/lldb.cpp +++ b/lldb/source/lldb.cpp @@ -93,6 +93,7 @@ #include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "Plugins/MemoryHistory/asan/MemoryHistoryASan.h" +#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h" using namespace lldb; using namespace lldb_private; @@ -156,6 +157,7 @@ lldb_private::Initialize () JITLoaderGDB::Initialize(); ProcessElfCore::Initialize(); MemoryHistoryASan::Initialize(); + AddressSanitizerRuntime::Initialize(); #if defined (__APPLE__) //---------------------------------------------------------------------- @@ -247,6 +249,7 @@ lldb_private::Terminate () JITLoaderGDB::Terminate(); ProcessElfCore::Terminate(); MemoryHistoryASan::Terminate(); + AddressSanitizerRuntime::Terminate(); #if defined (__APPLE__) DynamicLoaderMacOSXDYLD::Terminate(); diff --git a/lldb/test/functionalities/asan/TestAsan.py b/lldb/test/functionalities/asan/TestMemoryHistory.py index f8a3131d235..f8a3131d235 100644 --- a/lldb/test/functionalities/asan/TestAsan.py +++ b/lldb/test/functionalities/asan/TestMemoryHistory.py diff --git a/lldb/test/functionalities/asan/TestReportData.py b/lldb/test/functionalities/asan/TestReportData.py new file mode 100644 index 00000000000..7cf5a42cb44 --- /dev/null +++ b/lldb/test/functionalities/asan/TestReportData.py @@ -0,0 +1,92 @@ +""" +Test the AddressSanitizer runtime support for report breakpoint and data extraction. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil +import json + +class AsanTestReportDataCase(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") + @skipIfRemote + @dsym_test + def test_with_dsym (self): + compiler = self.findBuiltClang () + self.buildDsym (None, compiler) + self.asan_tests () + + @skipIfRemote + @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') + self.line_crash = line_number('main.c', '// BOOM 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("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']) + + # no extended info when we have no ASan report + thread = self.dbg.GetSelectedTarget().process.GetSelectedThread() + s = lldb.SBStream() + self.assertFalse(thread.GetStopReasonExtendedInfoAsJSON(s)) + + self.runCmd("continue") + + self.expect("thread list", "Process should be stopped due to ASan report", + substrs = ['stopped', 'stop reason = Use of deallocated memory detected']) + + self.assertEqual(self.dbg.GetSelectedTarget().process.GetSelectedThread().GetStopReason(), lldb.eStopReasonInstrumentation) + + self.expect("bt", "The backtrace should show the crashing line", + substrs = ['main.c:%d' % self.line_crash]) + + self.expect("thread info -s", "The extended stop info should contain the ASan provided fields", + substrs = ["access_size", "access_type", "address", "pc", "description", "heap-use-after-free"]) + + output_lines = self.res.GetOutput().split('\n') + json_line = output_lines[2] + data = json.loads(json_line) + self.assertEqual(data["description"], "heap-use-after-free") + self.assertEqual(data["instrumentation_class"], "AddressSanitizer") + self.assertEqual(data["stop_type"], "fatal_error") + + # now let's try the SB API + process = self.dbg.GetSelectedTarget().process + thread = process.GetSelectedThread() + + s = lldb.SBStream() + self.assertTrue(thread.GetStopReasonExtendedInfoAsJSON(s)) + s = s.GetData() + data2 = json.loads(s) + self.assertEqual(data, data2) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/asan/main.c b/lldb/test/functionalities/asan/main.c index 4e873cca417..fab760e49f0 100644 --- a/lldb/test/functionalities/asan/main.c +++ b/lldb/test/functionalities/asan/main.c @@ -28,7 +28,7 @@ int main (int argc, char const *argv[]) printf("Hello world!\n"); // break line - pointer[0] = 'A'; // BOOM + pointer[0] = 'A'; // BOOM line return 0; } |