diff options
149 files changed, 6582 insertions, 2698 deletions
diff --git a/include/lldb/API/SBDebugger.h b/include/lldb/API/SBDebugger.h index 518cbf67c932..80e6969cbd3a 100644 --- a/include/lldb/API/SBDebugger.h +++ b/include/lldb/API/SBDebugger.h @@ -10,9 +10,11 @@ #ifndef LLDB_SBDebugger_h_ #define LLDB_SBDebugger_h_ -#include "lldb/API/SBDefines.h" #include <stdio.h> +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBPlatform.h" + namespace lldb { class SBDebugger @@ -153,6 +155,12 @@ public: void SetSelectedTarget (SBTarget& target); + lldb::SBPlatform + GetSelectedPlatform(); + + void + SetSelectedPlatform(lldb::SBPlatform &platform); + lldb::SBSourceManager GetSourceManager (); diff --git a/include/lldb/API/SBError.h b/include/lldb/API/SBError.h index a6d3dacb4549..12b34ec6dbc3 100644 --- a/include/lldb/API/SBError.h +++ b/include/lldb/API/SBError.h @@ -72,6 +72,7 @@ protected: friend class SBCommunication; friend class SBHostOS; friend class SBInputReader; + friend class SBPlatform; friend class SBProcess; friend class SBThread; friend class SBTarget; diff --git a/include/lldb/API/SBExpressionOptions.h b/include/lldb/API/SBExpressionOptions.h index eed9ed528bef..6a3a640432f6 100644 --- a/include/lldb/API/SBExpressionOptions.h +++ b/include/lldb/API/SBExpressionOptions.h @@ -65,6 +65,12 @@ public: void SetTryAllThreads (bool run_others = true); + bool + GetTrapExceptions () const; + + void + SetTrapExceptions (bool trap_exceptions = true); + protected: SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); diff --git a/include/lldb/API/SBFileSpec.h b/include/lldb/API/SBFileSpec.h index e44abe4759c6..5d4447f74e64 100644 --- a/include/lldb/API/SBFileSpec.h +++ b/include/lldb/API/SBFileSpec.h @@ -45,6 +45,12 @@ public: const char * GetDirectory() const; + void + SetFilename(const char *filename); + + void + SetDirectory(const char *directory); + uint32_t GetPath (char *dst_path, size_t dst_len) const; @@ -65,6 +71,7 @@ private: friend class SBLineEntry; friend class SBModule; friend class SBModuleSpec; + friend class SBPlatform; friend class SBProcess; friend class SBSourceManager; friend class SBThread; diff --git a/include/lldb/API/SBModule.h b/include/lldb/API/SBModule.h index a3c4879aa2f9..f5955b39734d 100644 --- a/include/lldb/API/SBModule.h +++ b/include/lldb/API/SBModule.h @@ -76,6 +76,42 @@ public: bool SetPlatformFileSpec (const lldb::SBFileSpec &platform_file); + //------------------------------------------------------------------ + /// Get accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// @return + /// A file specification object. + //------------------------------------------------------------------ + lldb::SBFileSpec + GetRemoteInstallFileSpec (); + + //------------------------------------------------------------------ + /// Set accessor for the remote install path for a module. + /// + /// When debugging to a remote platform by connecting to a remote + /// platform, the install path of the module can be set. If the + /// install path is set, every time the process is about to launch + /// the target will install this module on the remote platform prior + /// to launching. + /// + /// If \a file specifies a full path to an install location, the + /// module will be installed to this path. If the path is relative + /// (no directory specified, or the path is partial like "usr/lib" + /// or "./usr/lib", then the install path will be resolved using + /// the platform's current working directory as the base path. + /// + /// @param[in] + /// A file specification object. + //------------------------------------------------------------------ + bool + SetRemoteInstallFileSpec (lldb::SBFileSpec &file); + lldb::ByteOrder GetByteOrder (); diff --git a/include/lldb/API/SBPlatform.h b/include/lldb/API/SBPlatform.h new file mode 100644 index 000000000000..16a546d81f9b --- /dev/null +++ b/include/lldb/API/SBPlatform.h @@ -0,0 +1,198 @@ +//===-- SBPlatform.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBPlatform_h_ +#define LLDB_SBPlatform_h_ + +#include "lldb/API/SBDefines.h" + +struct PlatformConnectOptions; +struct PlatformShellCommand; + +namespace lldb { + + class SBPlatformConnectOptions + { + public: + SBPlatformConnectOptions (const char *url); + + SBPlatformConnectOptions (const SBPlatformConnectOptions &rhs); + + ~SBPlatformConnectOptions (); + + void + operator=(const SBPlatformConnectOptions &rhs); + + const char * + GetURL(); + + void + SetURL(const char *url); + + bool + GetRsyncEnabled(); + + void + EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_remote_hostname); + + void + DisableRsync (); + + const char * + GetLocalCacheDirectory(); + + void + SetLocalCacheDirectory(const char *path); + protected: + PlatformConnectOptions *m_opaque_ptr; + }; + + class SBPlatformShellCommand + { + public: + SBPlatformShellCommand (const char *shell_command); + + SBPlatformShellCommand (const SBPlatformShellCommand &rhs); + + ~SBPlatformShellCommand(); + + void + Clear(); + + const char * + GetCommand(); + + void + SetCommand(const char *shell_command); + + const char * + GetWorkingDirectory (); + + void + SetWorkingDirectory (const char *path); + + uint32_t + GetTimeoutSeconds (); + + void + SetTimeoutSeconds (uint32_t sec); + + int + GetSignal (); + + int + GetStatus (); + + const char * + GetOutput (); + + protected: + friend class SBPlatform; + + PlatformShellCommand *m_opaque_ptr; + }; + + class SBPlatform + { + public: + + SBPlatform (); + + SBPlatform (const char *platform_name); + + ~SBPlatform(); + + bool + IsValid () const; + + void + Clear (); + + const char * + GetWorkingDirectory(); + + bool + SetWorkingDirectory(const char *path); + + const char * + GetName (); + + SBError + ConnectRemote (SBPlatformConnectOptions &connect_options); + + void + DisconnectRemote (); + + bool + IsConnected(); + + //---------------------------------------------------------------------- + // The following functions will work if the platform is connected + //---------------------------------------------------------------------- + const char * + GetTriple(); + + const char * + GetHostname (); + + const char * + GetOSBuild (); + + const char * + GetOSDescription (); + + uint32_t + GetOSMajorVersion (); + + uint32_t + GetOSMinorVersion (); + + uint32_t + GetOSUpdateVersion (); + + SBError + Put (SBFileSpec &src, SBFileSpec &dst); + + SBError + Get (SBFileSpec &src, SBFileSpec &dst); + + SBError + Install (SBFileSpec& src, SBFileSpec& dst); + + SBError + Run (SBPlatformShellCommand &shell_command); + + SBError + MakeDirectory (const char *path, uint32_t file_permissions = eFilePermissionsDirectoryDefault); + + uint32_t + GetFilePermissions (const char *path); + + SBError + SetFilePermissions (const char *path, uint32_t file_permissions); + + protected: + + friend class SBDebugger; + friend class SBTarget; + + lldb::PlatformSP + GetSP () const; + + void + SetSP (const lldb::PlatformSP& platform_sp); + + lldb::PlatformSP m_opaque_sp; + }; + +} // namespace lldb + +#endif // LLDB_SBPlatform_h_ diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h index 7bcf91c16d77..b41c11811549 100644 --- a/include/lldb/API/SBTarget.h +++ b/include/lldb/API/SBTarget.h @@ -268,6 +268,23 @@ public: GetProcess (); //------------------------------------------------------------------ + /// Install any binaries that need to be installed. + /// + /// This function does nothing when debugging on the host system. + /// When connected to remote platforms, the target's main executable + /// and any modules that have their remote install path set will be + /// installed on the remote platform. If the main executable doesn't + /// have an install location set, it will be installed in the remote + /// platform's working directory. + /// + /// @return + /// An error describing anything that went wrong during + /// installation. + //------------------------------------------------------------------ + SBError + Install(); + + //------------------------------------------------------------------ /// Launch a new process. /// /// Launch a new process by spawning a new process using the diff --git a/include/lldb/API/SBThread.h b/include/lldb/API/SBThread.h index d062d7121303..6542dca1f95a 100644 --- a/include/lldb/API/SBThread.h +++ b/include/lldb/API/SBThread.h @@ -202,7 +202,10 @@ public: GetStatus (lldb::SBStream &status) const; SBThread - GetExtendedBacktrace (const char *type); + GetExtendedBacktraceThread (const char *type); + + uint32_t + GetExtendedBacktraceOriginatingIndexID (); protected: friend class SBBreakpoint; diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h index 30cc3314af3a..e82d6eacf7a8 100644 --- a/include/lldb/Breakpoint/Breakpoint.h +++ b/include/lldb/Breakpoint/Breakpoint.h @@ -311,6 +311,24 @@ public: //------------------------------------------------------------------ lldb::BreakpointLocationSP GetLocationAtIndex (size_t index); + + //------------------------------------------------------------------ + /// Removes all invalid breakpoint locations. + /// + /// Removes all breakpoint locations with architectures that aren't + /// compatible with \a arch. Also remove any breakpoint locations + /// with whose locations have address where the section has been + /// deleted (module and object files no longer exist). + /// + /// This is typically used after the process calls exec, or anytime + /// the architecture of the target changes. + /// + /// @param[in] arch + /// If valid, check the module in each breakpoint to make sure + /// they are compatible, otherwise, ignore architecture. + //------------------------------------------------------------------ + void + RemoveInvalidLocations (const ArchSpec &arch); //------------------------------------------------------------------ // The next section deals with various breakpoint options. diff --git a/include/lldb/Breakpoint/BreakpointList.h b/include/lldb/Breakpoint/BreakpointList.h index c6708db118df..27f80d0ffe09 100644 --- a/include/lldb/Breakpoint/BreakpointList.h +++ b/include/lldb/Breakpoint/BreakpointList.h @@ -132,6 +132,25 @@ public: bool Remove (lldb::break_id_t breakID, bool notify); + + //------------------------------------------------------------------ + /// Removes all invalid breakpoint locations. + /// + /// Removes all breakpoint locations in the list with architectures + /// that aren't compatible with \a arch. Also remove any breakpoint + /// locations with whose locations have address where the section + /// has been deleted (module and object files no longer exist). + /// + /// This is typically used after the process calls exec, or anytime + /// the architecture of the target changes. + /// + /// @param[in] arch + /// If valid, check the module in each breakpoint to make sure + /// they are compatible, otherwise, ignore architecture. + //------------------------------------------------------------------ + void + RemoveInvalidLocations (const ArchSpec &arch); + void SetEnabledAll (bool enabled); diff --git a/include/lldb/Breakpoint/BreakpointLocationList.h b/include/lldb/Breakpoint/BreakpointLocationList.h index 1cba23d9118e..b25208659c7f 100644 --- a/include/lldb/Breakpoint/BreakpointLocationList.h +++ b/include/lldb/Breakpoint/BreakpointLocationList.h @@ -250,6 +250,9 @@ protected: bool RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp); + + void + RemoveInvalidLocations (const ArchSpec &arch); typedef std::vector<lldb::BreakpointLocationSP> collection; typedef std::map<lldb_private::Address, @@ -257,7 +260,7 @@ protected: Address::ModulePointerAndOffsetLessThanFunctionObject> addr_map; Breakpoint &m_owner; - collection m_locations; + collection m_locations; // Vector of locations, sorted by ID addr_map m_address_to_location; mutable Mutex m_mutex; lldb::break_id_t m_next_id; diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h index da7cc5c03d38..322019395ae7 100644 --- a/include/lldb/Core/Address.h +++ b/include/lldb/Core/Address.h @@ -534,6 +534,16 @@ public: bool CalculateSymbolContextLineEntry (LineEntry &line_entry) const; + //------------------------------------------------------------------ + // Returns true if the section should be valid, but isn't because + // the shared pointer to the section can't be reconstructed from + // a weak pointer that contains a valid weak reference to a section. + // Returns false if the section weak pointer has no reference to + // a section, or if the section is still valid + //------------------------------------------------------------------ + bool + SectionWasDeleted() const; + protected: //------------------------------------------------------------------ // Member variables. @@ -550,7 +560,7 @@ protected: // have a valid section. //------------------------------------------------------------------ bool - SectionWasDeleted() const; + SectionWasDeletedPrivate() const; }; diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h index 671b378df807..a3c6d5eeb93d 100644 --- a/include/lldb/Core/Debugger.h +++ b/include/lldb/Core/Debugger.h @@ -17,9 +17,6 @@ #include <stack> #include "lldb/lldb-public.h" - -#include "lldb/API/SBDefines.h" - #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Communication.h" #include "lldb/Core/InputReaderStack.h" @@ -55,6 +52,10 @@ friend class SourceManager; // For GetSourceFileCache. public: + typedef lldb::DynamicLibrarySP (*LoadPluginCallbackType) (const lldb::DebuggerSP &debugger_sp, + const FileSpec& spec, + Error& error); + static lldb::DebuggerSP CreateInstance (lldb::LogOutputCallback log_callback = NULL, void *baton = NULL); @@ -65,7 +66,7 @@ public: FindTargetWithProcess (Process *process); static void - Initialize (); + Initialize (LoadPluginCallbackType load_plugin_callback); static void Terminate (); @@ -333,9 +334,7 @@ public: { return m_instance_name; } - - typedef bool (*LLDBCommandPluginInit) (lldb::SBDebugger& debugger); - + bool LoadPlugin (const FileSpec& spec, Error& error); @@ -377,6 +376,7 @@ protected: LogStreamMap m_log_streams; lldb::StreamSP m_log_callback_stream_sp; ConstString m_instance_name; + static LoadPluginCallbackType g_load_plugin_callback; typedef std::vector<lldb::DynamicLibrarySP> LoadedPluginsList; LoadedPluginsList m_loaded_plugins; diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h index 1473fb90cf85..cae5a30be704 100644 --- a/include/lldb/Core/Module.h +++ b/include/lldb/Core/Module.h @@ -570,6 +570,18 @@ public: } const FileSpec & + GetRemoteInstallFileSpec () const + { + return m_remote_install_file; + } + + void + SetRemoteInstallFileSpec (const FileSpec &file) + { + m_remote_install_file = file; + } + + const FileSpec & GetSymbolFileFileSpec () const { return m_symfile_spec; @@ -1059,6 +1071,7 @@ protected: lldb_private::UUID m_uuid; ///< Each module is assumed to have a unique identifier to help match it up to debug symbols. FileSpec m_file; ///< The file representation on disk for this module (if there is one). FileSpec m_platform_file;///< The path to the module on the platform on which it is being debugged + FileSpec m_remote_install_file; ///< If set when debugging on remote platforms, this module will be installed at this location FileSpec m_symfile_spec; ///< If this path is valid, then this is the file that _will_ be used as the symbol file for this module ConstString m_object_name; ///< The name an object within this module that is selected, or empty of the module is represented by \a m_file. uint64_t m_object_offset; diff --git a/include/lldb/DataFormatters/CXXFormatterFunctions.h b/include/lldb/DataFormatters/CXXFormatterFunctions.h index 433c2a3c407b..415ef9be59ef 100644 --- a/include/lldb/DataFormatters/CXXFormatterFunctions.h +++ b/include/lldb/DataFormatters/CXXFormatterFunctions.h @@ -17,6 +17,8 @@ #include "lldb/Core/ConstString.h" #include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/TypeSynthetic.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "clang/AST/ASTContext.h" diff --git a/include/lldb/DataFormatters/FormatCache.h b/include/lldb/DataFormatters/FormatCache.h index bd9e20ccc9ee..1505d7c46189 100644 --- a/include/lldb/DataFormatters/FormatCache.h +++ b/include/lldb/DataFormatters/FormatCache.h @@ -18,6 +18,7 @@ // Project includes #include "lldb/lldb-public.h" #include "lldb/Core/ConstString.h" +#include "lldb/Host/Mutex.h" #include "lldb/DataFormatters/FormatClasses.h" namespace lldb_private { diff --git a/include/lldb/DataFormatters/FormatClasses.h b/include/lldb/DataFormatters/FormatClasses.h index 6d9a50e8f2c5..651160371c69 100644 --- a/include/lldb/DataFormatters/FormatClasses.h +++ b/include/lldb/DataFormatters/FormatClasses.h @@ -10,9 +10,6 @@ #ifndef lldb_FormatClasses_h_ #define lldb_FormatClasses_h_ -// C Includes -#include <stdint.h> - // C++ Includes #include <string> #include <vector> @@ -23,17 +20,86 @@ #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" -#include "lldb/Core/ValueObject.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Symbol/Type.h" -#include "lldb/DataFormatters/TypeFormat.h" -#include "lldb/DataFormatters/TypeSummary.h" -#include "lldb/DataFormatters/TypeSynthetic.h" - namespace lldb_private { +class FormattersMatchCandidate +{ +public: + + FormattersMatchCandidate (ConstString name, + uint32_t reason, + bool strip_ptr, + bool strip_ref, + bool strip_tydef) : + m_type_name(name), + m_reason(reason), + m_stripped_pointer(strip_ptr), + m_stripped_reference(strip_ref), + m_stripped_typedef(strip_tydef) + { + } + + ~FormattersMatchCandidate () + {} + + ConstString + GetTypeName () const + { + return m_type_name; + } + + uint32_t + GetReason () const + { + return m_reason; + } + + bool + DidStripPointer () const + { + return m_stripped_pointer; + } + + bool + DidStripReference () const + { + return m_stripped_reference; + } + + bool + DidStripTypedef () const + { + return m_stripped_typedef; + } + + template <class Formatter> + bool + IsMatch (const std::shared_ptr<Formatter>& formatter_sp) const + { + if (!formatter_sp) + return false; + if (formatter_sp->Cascades() == false && DidStripTypedef()) + return false; + if (formatter_sp->SkipsPointers() && DidStripPointer()) + return false; + if (formatter_sp->SkipsReferences() && DidStripReference()) + return false; + return true; + } + +private: + ConstString m_type_name; + uint32_t m_reason; + bool m_stripped_pointer; + bool m_stripped_reference; + bool m_stripped_typedef; +}; + +typedef std::vector<FormattersMatchCandidate> FormattersMatchVector; + class TypeNameSpecifierImpl { public: diff --git a/include/lldb/DataFormatters/FormatManager.h b/include/lldb/DataFormatters/FormatManager.h index 3c90c993e0c4..750e53008318 100644 --- a/include/lldb/DataFormatters/FormatManager.h +++ b/include/lldb/DataFormatters/FormatManager.h @@ -19,6 +19,7 @@ #include "lldb/lldb-enumerations.h" #include "lldb/DataFormatters/FormatCache.h" +#include "lldb/DataFormatters/FormatClasses.h" #include "lldb/DataFormatters/FormatNavigator.h" #include "lldb/DataFormatters/TypeCategory.h" #include "lldb/DataFormatters/TypeCategoryMap.h" @@ -213,7 +214,36 @@ public: { } + static FormattersMatchVector + GetPossibleMatches (ValueObject& valobj, + lldb::DynamicValueType use_dynamic) + { + FormattersMatchVector matches; + GetPossibleMatches (valobj, + valobj.GetClangType(), + lldb_private::eFormatterChoiceCriterionDirectChoice, + use_dynamic, + matches, + false, + false, + false, + true); + return matches; + } + private: + + static void + GetPossibleMatches (ValueObject& valobj, + ClangASTType clang_type, + uint32_t reason, + lldb::DynamicValueType use_dynamic, + FormattersMatchVector& entries, + bool did_strip_ptr, + bool did_strip_ref, + bool did_strip_typedef, + bool root_level = false); + FormatCache m_format_cache; NamedSummariesMap m_named_summaries_map; std::atomic<uint32_t> m_last_revision; diff --git a/include/lldb/DataFormatters/FormatNavigator.h b/include/lldb/DataFormatters/FormatNavigator.h index cd5f6824e199..1b82776fb28c 100644 --- a/include/lldb/DataFormatters/FormatNavigator.h +++ b/include/lldb/DataFormatters/FormatNavigator.h @@ -26,6 +26,9 @@ #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/TypeFormat.h" +#include "lldb/DataFormatters/TypeSummary.h" +#include "lldb/DataFormatters/TypeSynthetic.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangASTType.h" @@ -459,228 +462,29 @@ protected: } return false; } - - bool - Get_BitfieldMatch (ValueObject& valobj, - ConstString typeName, - MapValueType& entry, - uint32_t& reason) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - // for bitfields, append size to the typename so one can custom format them - StreamString sstring; - sstring.Printf("%s:%d",typeName.AsCString(),valobj.GetBitfieldBitSize()); - ConstString bitfieldname = ConstString(sstring.GetData()); - if (log) - log->Printf("[Get_BitfieldMatch] appended bitfield info, final result is %s", bitfieldname.GetCString()); - if (Get(bitfieldname, entry)) - { - if (log) - log->Printf("[Get_BitfieldMatch] bitfield direct match found, returning"); - return true; - } - else - { - reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField; - if (log) - log->Printf("[Get_BitfieldMatch] no bitfield direct match"); - return false; - } - } - - bool Get_ObjC (ValueObject& valobj, - MapValueType& entry) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - lldb::ProcessSP process_sp = valobj.GetProcessSP(); - ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime(); - if (runtime == NULL) - { - if (log) - log->Printf("[Get_ObjC] no valid ObjC runtime, skipping dynamic"); - return false; - } - ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj)); - if (!objc_class_sp) - { - if (log) - log->Printf("[Get_ObjC] invalid ISA, skipping dynamic"); - return false; - } - ConstString name (objc_class_sp->GetClassName()); - if (log) - log->Printf("[Get_ObjC] dynamic type inferred is %s - looking for direct dynamic match", name.GetCString()); - if (Get(name, entry)) - { - if (log) - log->Printf("[Get_ObjC] direct dynamic match found, returning"); - return true; - } - if (log) - log->Printf("[Get_ObjC] no dynamic match"); - return false; - } - + bool - Get_Impl (ValueObject& valobj, - ClangASTType clang_type, - MapValueType& entry, - lldb::DynamicValueType use_dynamic, - uint32_t& reason) + Get (const FormattersMatchVector& candidates, + MapValueType& entry, + uint32_t *reason) { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - - if (!clang_type.IsValid()) - { - if (log) - log->Printf("[Get_Impl] type is invalid, returning"); - return false; - } - - clang_type = clang_type.RemoveFastQualifiers(); - - ConstString typeName(clang_type.GetConstTypeName()); - - if (valobj.GetBitfieldBitSize() > 0) + for (const FormattersMatchCandidate& candidate : candidates) { - if (Get_BitfieldMatch(valobj, typeName, entry, reason)) - return true; - } - - if (log) - log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s", - m_name.c_str(), - valobj.GetName().AsCString(), - typeName.AsCString()); - - if (Get(typeName, entry)) - { - if (log) - log->Printf("[Get] direct match found, returning"); - return true; - } - if (log) - log->Printf("[Get_Impl] no direct match"); - - // strip pointers and references and see if that helps - if (clang_type.IsReferenceType()) - { - if (log) - log->Printf("[Get_Impl] stripping reference"); - if (Get_Impl(valobj, clang_type.GetNonReferenceType(), entry, use_dynamic, reason) && !entry->SkipsReferences()) + if (Get(candidate.GetTypeName(),entry)) { - reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference; - return true; - } - } - else if (clang_type.IsPointerType()) - { - if (log) - log->Printf("[Get_Impl] stripping pointer"); - if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers()) - { - reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference; - return true; - } - } - - bool canBeObjCDynamic = valobj.GetClangType().IsPossibleDynamicType (NULL, - false, // no C++ - true); // yes ObjC - - if (canBeObjCDynamic) - { - if (use_dynamic != lldb::eNoDynamicValues) - { - if (log) - log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type"); - if (Get_ObjC(valobj,entry)) + if (candidate.IsMatch(entry) == false) { - reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery; - return true; + entry.reset(); + continue; } - } - if (log) - log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer"); - if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers()) - { - reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference; - return true; - } - } - - // try to strip typedef chains - if (clang_type.IsTypedefType()) - { - if (log) - log->Printf("[Get_Impl] stripping typedef"); - if ((Get_Impl(valobj, clang_type.GetTypedefedType(), entry, use_dynamic, reason)) && entry->Cascades()) - { - reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs; - return true; - } - } - - // out of luck here - return false; - } - - // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size) - // but the type can change (e.g. stripping pointers, ...) - bool Get (ValueObject& valobj, - ClangASTType clang_type, - MapValueType& entry, - lldb::DynamicValueType use_dynamic, - uint32_t& reason) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - - if (Get_Impl (valobj, clang_type, entry, use_dynamic, reason)) - return true; - - // try going to the unqualified type - do { - if (log) - log->Printf("[Get] trying the unqualified type"); - if (!clang_type.IsValid()) - break; - - ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType(); - if (!unqual_clang_ast_type.IsValid()) - { - if (log) - log->Printf("[Get] could not get the unqual_clang_ast_type"); - break; - } - if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType()) - { - if (log) - log->Printf("[Get] unqualified type is there and is not the same, let's try"); - if (Get_Impl (valobj, unqual_clang_ast_type,entry, use_dynamic, reason)) - return true; - } - else if (log) - log->Printf("[Get] unqualified type same as original type"); - } while(false); - - // if all else fails, go to static type - if (valobj.IsDynamic()) - { - if (log) - log->Printf("[Get] going to static value"); - lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue()); - if (static_value_sp) - { - if (log) - log->Printf("[Get] has a static value - actually use it"); - if (Get(*static_value_sp.get(), static_value_sp->GetClangType(), entry, use_dynamic, reason)) + else { - reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue; + if(reason) + *reason = candidate.GetReason(); return true; } } } - return false; } }; diff --git a/include/lldb/DataFormatters/TypeCategory.h b/include/lldb/DataFormatters/TypeCategory.h index 6461c4e97e4e..082395a04616 100644 --- a/include/lldb/DataFormatters/TypeCategory.h +++ b/include/lldb/DataFormatters/TypeCategory.h @@ -18,6 +18,7 @@ #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" +#include "lldb/DataFormatters/FormatClasses.h" #include "lldb/DataFormatters/FormatNavigator.h" namespace lldb_private { @@ -177,23 +178,22 @@ namespace lldb_private { return m_enabled_position; } - bool Get (ValueObject& valobj, + const FormattersMatchVector& candidates, lldb::TypeFormatImplSP& entry, - lldb::DynamicValueType use_dynamic, uint32_t* reason = NULL); bool Get (ValueObject& valobj, + const FormattersMatchVector& candidates, lldb::TypeSummaryImplSP& entry, - lldb::DynamicValueType use_dynamic, uint32_t* reason = NULL); bool Get (ValueObject& valobj, + const FormattersMatchVector& candidates, lldb::SyntheticChildrenSP& entry, - lldb::DynamicValueType use_dynamic, uint32_t* reason = NULL); void diff --git a/include/lldb/Expression/ClangFunction.h b/include/lldb/Expression/ClangFunction.h index 9cb22ed15cb5..9c14ddb53230 100644 --- a/include/lldb/Expression/ClangFunction.h +++ b/include/lldb/Expression/ClangFunction.h @@ -227,143 +227,6 @@ public: Stream &errors); //------------------------------------------------------------------ - /// [Static] Execute a function, passing it a single void* parameter. - /// ClangFunction uses this to call the wrapper function. - /// - /// @param[in] exe_ctx - /// The execution context to insert the function and its arguments - /// into. - /// - /// @param[in] function_address - /// The address of the function in the target process. - /// - /// @param[in] void_arg - /// The value of the void* parameter. - /// - /// @param[in] stop_others - /// True if other threads should pause during execution. - /// - /// @param[in] try_all_threads - /// If the timeout expires, true if other threads should run. If - /// the function may try to take locks, this is useful. - /// - /// @param[in] unwind_on_error - /// If true, and the execution stops before completion, we unwind the - /// function call, and return the program state to what it was before the - /// execution. If false, we leave the program in the stopped state. - /// - /// @param[in] timeout_usec - /// Timeout value (0 for no timeout). If try_all_threads is true, then we - /// will try on one thread for the lesser of .25 sec and half the total timeout. - /// then switch to running all threads, otherwise this will be the total timeout. - /// - /// @param[in] errors - /// The stream to write errors to. - /// - /// @param[in] this_arg - /// If non-NULL, the function is invoked like a C++ method, with the - /// value pointed to by the pointer as its 'this' argument. - /// - /// @return - /// Returns one of the ExecutionResults enum indicating function call status. - //------------------------------------------------------------------ - static ExecutionResults - ExecuteFunction (ExecutionContext &exe_ctx, - lldb::addr_t function_address, - lldb::addr_t &void_arg, - bool stop_others, - bool try_all_threads, - bool unwind_on_error, - bool ignore_breakpoints, - uint32_t timeout_usec, - Stream &errors, - lldb::addr_t* this_arg = 0); - - //------------------------------------------------------------------ - /// Run the function this ClangFunction was created with. - /// - /// This simple version will run the function stopping other threads - /// for a fixed timeout period (1000 usec) and if it does not complete, - /// we halt the process and try with all threads running. - /// - /// @param[in] exe_ctx - /// The thread & process in which this function will run. - /// - /// @param[in] errors - /// Errors will be written here if there are any. - /// - /// @param[out] results - /// The result value will be put here after running the function. - /// - /// @return - /// Returns one of the ExecutionResults enum indicating function call status. - //------------------------------------------------------------------ - ExecutionResults - ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, - Value &results); - - //------------------------------------------------------------------ - /// Run the function this ClangFunction was created with. - /// - /// This simple version will run the function obeying the stop_others - /// argument. There is no timeout. - /// - /// @param[in] exe_ctx - /// The thread & process in which this function will run. - /// - /// @param[in] errors - /// Errors will be written here if there are any. - /// - /// @param[in] stop_others - /// If \b true, run only this thread, if \b false let all threads run. - /// - /// @param[out] results - /// The result value will be put here after running the function. - /// - /// @return - /// Returns one of the ExecutionResults enum indicating function call status. - //------------------------------------------------------------------ - ExecutionResults - ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, bool stop_others, - Value &results); - - //------------------------------------------------------------------ - /// Run the function this ClangFunction was created with. - /// - /// This simple version will run the function on one thread. If \a timeout_usec - /// is not zero, we time out after that timeout. If \a try_all_threads is true, then we will - /// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned. - /// - /// @param[in] exe_ctx - /// The thread & process in which this function will run. - /// - /// @param[in] errors - /// Errors will be written here if there are any. - /// - /// @param[in] timeout_usec - /// Timeout value (0 for no timeout). If try_all_threads is true, then we - /// will try on one thread for the lesser of .25 sec and half the total timeout. - /// then switch to running all threads, otherwise this will be the total timeout. - /// - /// @param[in] try_all_threads - /// If \b true, run only this thread, if \b false let all threads run. - /// - /// @param[out] results - /// The result value will be put here after running the function. - /// - /// @return - /// Returns one of the ExecutionResults enum indicating function call status. - //------------------------------------------------------------------ - ExecutionResults - ExecuteFunction(ExecutionContext &exe_ctx, - Stream &errors, - uint32_t single_thread_timeout_usec, - bool try_all_threads, - Value &results); - - //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. /// /// This is the full version. @@ -381,17 +244,8 @@ public: /// @param[in] errors /// Errors will be written here if there are any. /// - /// @param[in] stop_others - /// If \b true, run only this thread, if \b false let all threads run. - /// - /// @param[in] timeout_usec - /// Timeout value (0 for no timeout). If try_all_threads is true, then we - /// will try on one thread for the lesser of .25 sec and half the total timeout. - /// then switch to running all threads, otherwise this will be the total timeout. - /// - /// - /// @param[in] try_all_threads - /// If \b true, run only this thread, if \b false let all threads run. + /// @param[in] options + /// The options for this expression execution. /// /// @param[out] results /// The result value will be put here after running the function. @@ -402,63 +256,11 @@ public: ExecutionResults ExecuteFunction(ExecutionContext &exe_ctx, lldb::addr_t *args_addr_ptr, - Stream &errors, - bool stop_others, - uint32_t timeout_usec, - bool try_all_threads, - bool unwind_on_error, - bool ignore_breakpoints, + const EvaluateExpressionOptions &options, + Stream &errors, Value &results); //------------------------------------------------------------------ - /// [static] Get a thread plan to run a function. - /// - /// @param[in] exe_ctx - /// The execution context to insert the function and its arguments - /// into. - /// - /// @param[in] func_addr - /// The address of the function in the target process. - /// - /// @param[in] args_addr_ref - /// The value of the void* parameter. - /// - /// @param[in] errors - /// The stream to write errors to. - /// - /// @param[in] stop_others - /// True if other threads should pause during execution. - /// - /// @param[in] unwind_on_error - /// True if the thread plan may simply be discarded if an error occurs. - /// - /// @param[in] ignore_breakpoints - /// True if the expression execution will ignore breakpoint hits and continue executing. - /// - /// @param[in] this_arg - /// If non-NULL (and cmd_arg is NULL), the function is invoked like a C++ - /// method, with the value pointed to by the pointer as its 'this' - /// argument. - /// - /// @param[in] cmd_arg - /// If non-NULL, the function is invoked like an Objective-C method, with - /// this_arg in the 'self' slot and cmd_arg in the '_cmd' slot - /// - /// @return - /// A ThreadPlan for executing the function. - //------------------------------------------------------------------ - static ThreadPlan * - GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, - lldb::addr_t func_addr, - lldb::addr_t &args_addr_ref, - Stream &errors, - bool stop_others, - bool unwind_on_error, - bool ignore_breakpoints, - lldb::addr_t *this_arg = 0, - lldb::addr_t *cmd_arg = 0); - - //------------------------------------------------------------------ /// Get a thread plan to run the function this ClangFunction was created with. /// /// @param[in] exe_ctx @@ -468,8 +270,8 @@ public: /// @param[in] func_addr /// The address of the function in the target process. /// - /// @param[in] args_addr_ref - /// The value of the void* parameter. + /// @param[in] args_addr + /// The address of the argument struct. /// /// @param[in] errors /// The stream to write errors to. @@ -485,20 +287,9 @@ public: //------------------------------------------------------------------ ThreadPlan * GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, - lldb::addr_t &args_addr_ref, - Stream &errors, - bool stop_others, - bool unwind_on_error = true, - bool ignore_breakpoints = true) - { - return ClangFunction::GetThreadPlanToCallFunction (exe_ctx, - m_jit_start_addr, - args_addr_ref, - errors, - stop_others, - unwind_on_error, - ignore_breakpoints); - } + lldb::addr_t args_addr, + const EvaluateExpressionOptions &options, + Stream &errors); //------------------------------------------------------------------ /// Get the result of the function from its struct diff --git a/include/lldb/Expression/ClangUserExpression.h b/include/lldb/Expression/ClangUserExpression.h index b8c3c128acf4..83fdf1c21955 100644 --- a/include/lldb/Expression/ClangUserExpression.h +++ b/include/lldb/Expression/ClangUserExpression.h @@ -150,10 +150,6 @@ public: ClangUserExpressionSP &shared_ptr_to_me, lldb::ClangExpressionVariableSP &result); - ThreadPlan * - GetThreadPlanToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx); - //------------------------------------------------------------------ /// Apply the side effects of the function to program state. /// diff --git a/include/lldb/Host/Debug.h b/include/lldb/Host/Debug.h new file mode 100644 index 000000000000..2cb758e1b733 --- /dev/null +++ b/include/lldb/Host/Debug.h @@ -0,0 +1,406 @@ +//===-- Debug.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_Debug_h_ +#define liblldb_Debug_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Mutex.h" +#include <vector> + +namespace lldb_private { + + //------------------------------------------------------------------ + // Tells a thread what it needs to do when the process is resumed. + //------------------------------------------------------------------ + struct ResumeAction + { + lldb::tid_t tid; // The thread ID that this action applies to, LLDB_INVALID_THREAD_ID for the default thread action + lldb::StateType state; // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping. + int signal; // When resuming this thread, resume it with this signal if this value is > 0 + }; + + //------------------------------------------------------------------ + // A class that contains instructions for all threads for + // NativeProcessProtocol::Resume(). Each thread can either run, stay + // suspended, or step when the process is resumed. We optionally + // have the ability to also send a signal to the thread when the + // action is run or step. + //------------------------------------------------------------------ + class ResumeActionList + { + public: + ResumeActionList () : + m_actions (), + m_signal_handled () + { + } + + ResumeActionList (lldb::StateType default_action, int signal) : + m_actions(), + m_signal_handled () + { + SetDefaultThreadActionIfNeeded (default_action, signal); + } + + + ResumeActionList (const ResumeAction *actions, size_t num_actions) : + m_actions (), + m_signal_handled () + { + if (actions && num_actions) + { + m_actions.assign (actions, actions + num_actions); + m_signal_handled.assign (num_actions, false); + } + } + + ~ResumeActionList() + { + } + + bool + IsEmpty() const + { + return m_actions.empty(); + } + + void + Append (const ResumeAction &action) + { + m_actions.push_back (action); + m_signal_handled.push_back (false); + } + + void + AppendAction (lldb::tid_t tid, + lldb::StateType state, + int signal = 0) + { + ResumeAction action = { tid, state, signal }; + Append (action); + } + + void + AppendResumeAll () + { + AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateRunning); + } + + void + AppendSuspendAll () + { + AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStopped); + } + + void + AppendStepAll () + { + AppendAction (LLDB_INVALID_THREAD_ID, lldb::eStateStepping); + } + + const ResumeAction * + GetActionForThread (lldb::tid_t tid, bool default_ok) const + { + const size_t num_actions = m_actions.size(); + for (size_t i=0; i<num_actions; ++i) + { + if (m_actions[i].tid == tid) + return &m_actions[i]; + } + if (default_ok && tid != LLDB_INVALID_THREAD_ID) + return GetActionForThread (LLDB_INVALID_THREAD_ID, false); + return NULL; + } + + size_t + NumActionsWithState (lldb::StateType state) const + { + size_t count = 0; + const size_t num_actions = m_actions.size(); + for (size_t i=0; i<num_actions; ++i) + { + if (m_actions[i].state == state) + ++count; + } + return count; + } + + bool + SetDefaultThreadActionIfNeeded (lldb::StateType action, int signal) + { + if (GetActionForThread (LLDB_INVALID_THREAD_ID, true) == NULL) + { + // There isn't a default action so we do need to set it. + ResumeAction default_action = {LLDB_INVALID_THREAD_ID, action, signal }; + m_actions.push_back (default_action); + m_signal_handled.push_back (false); + return true; // Return true as we did add the default action + } + return false; + } + + void + SetSignalHandledForThread (lldb::tid_t tid) const + { + if (tid != LLDB_INVALID_THREAD_ID) + { + const size_t num_actions = m_actions.size(); + for (size_t i=0; i<num_actions; ++i) + { + if (m_actions[i].tid == tid) + m_signal_handled[i] = true; + } + } + } + + const ResumeAction * + GetFirst() const + { + return m_actions.data(); + } + + size_t + GetSize () const + { + return m_actions.size(); + } + + void + Clear() + { + m_actions.clear(); + m_signal_handled.clear(); + } + + protected: + std::vector<ResumeAction> m_actions; + mutable std::vector<bool> m_signal_handled; + }; + + struct ThreadStopInfo + { + lldb::StopReason reason; + union + { + // eStopTypeSignal + struct + { + uint32_t signo; + } signal; + + // eStopTypeException + struct + { + uint64_t type; + uint32_t data_count; + lldb::addr_t data[2]; + } exception; + } details; + }; + + //------------------------------------------------------------------ + // NativeThreadProtocol + //------------------------------------------------------------------ + class NativeThreadProtocol { + + public: + NativeThreadProtocol (NativeProcessProtocol *process, lldb::tid_t tid) : + m_process (process), + m_tid (tid) + { + } + + virtual ~NativeThreadProtocol() + { + } + virtual const char *GetName() = 0; + virtual lldb::StateType GetState () = 0; + virtual Error ReadRegister (uint32_t reg, RegisterValue ®_value) = 0; + virtual Error WriteRegister (uint32_t reg, const RegisterValue ®_value) = 0; + virtual Error SaveAllRegisters (lldb::DataBufferSP &data_sp) = 0; + virtual Error RestoreAllRegisters (lldb::DataBufferSP &data_sp) = 0; + virtual bool GetStopReason (ThreadStopInfo &stop_info) = 0; + + lldb::tid_t + GetID() const + { + return m_tid; + } + protected: + NativeProcessProtocol *m_process; + lldb::tid_t m_tid; + }; + + + //------------------------------------------------------------------ + // NativeProcessProtocol + //------------------------------------------------------------------ + class NativeProcessProtocol { + public: + + static NativeProcessProtocol * + CreateInstance (lldb::pid_t pid); + + // lldb_private::Host calls should be used to launch a process for debugging, and + // then the process should be attached to. When attaching to a process + // lldb_private::Host calls should be used to locate the process to attach to, + // and then this function should be called. + NativeProcessProtocol (lldb::pid_t pid) : + m_pid (pid), + m_threads(), + m_threads_mutex (Mutex::eMutexTypeRecursive), + m_state (lldb::eStateInvalid), + m_exit_status(0), + m_exit_description() + { + } + + public: + virtual ~NativeProcessProtocol () + { + } + + virtual Error Resume (const ResumeActionList &resume_actions) = 0; + virtual Error Halt () = 0; + virtual Error Detach () = 0; + virtual Error Signal (int signo) = 0; + virtual Error Kill () = 0; + + virtual Error ReadMemory (lldb::addr_t addr, void *buf, lldb::addr_t size, lldb::addr_t &bytes_read) = 0; + virtual Error WriteMemory (lldb::addr_t addr, const void *buf, lldb::addr_t size, lldb::addr_t &bytes_written) = 0; + virtual Error AllocateMemory (lldb::addr_t size, uint32_t permissions, lldb::addr_t &addr) = 0; + virtual Error DeallocateMemory (lldb::addr_t addr) = 0; + + virtual lldb::addr_t GetSharedLibraryInfoAddress () = 0; + + virtual bool IsAlive () = 0; + virtual size_t UpdateThreads () = 0; + virtual bool GetArchitecture (ArchSpec &arch) = 0; + + //---------------------------------------------------------------------- + // Breakpoint functions + //---------------------------------------------------------------------- + virtual Error SetBreakpoint (lldb::addr_t addr, size_t size, bool hardware) = 0; + virtual Error RemoveBreakpoint (lldb::addr_t addr, size_t size) = 0; + + //---------------------------------------------------------------------- + // Watchpoint functions + //---------------------------------------------------------------------- + virtual uint32_t GetMaxWatchpoints () = 0; + virtual Error SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) = 0; + virtual Error RemoveWatchpoint (lldb::addr_t addr) = 0; + + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + lldb::pid_t + GetID() const + { + return m_pid; + } + + lldb::StateType + GetState () const + { + return m_state; + } + + bool + IsRunning () const + { + return m_state == lldb::eStateRunning || IsStepping(); + } + + bool + IsStepping () const + { + return m_state == lldb::eStateStepping; + } + + bool + CanResume () const + { + return m_state == lldb::eStateStopped; + } + + + void + SetState (lldb::StateType state) + { + m_state = state; + } + + //---------------------------------------------------------------------- + // Exit Status + //---------------------------------------------------------------------- + virtual bool + GetExitStatus (int *status) + { + if (m_state == lldb::eStateExited) + { + *status = m_exit_status; + return true; + } + *status = 0; + return false; + } + virtual bool + SetExitStatus (int status, const char *exit_description) + { + // Exit status already set + if (m_state == lldb::eStateExited) + return false; + m_state = lldb::eStateExited; + m_exit_status = status; + if (exit_description && exit_description[0]) + m_exit_description = exit_description; + else + m_exit_description.clear(); + return true; + } + + //---------------------------------------------------------------------- + // Access to threads + //---------------------------------------------------------------------- + lldb::NativeThreadProtocolSP + GetThreadAtIndex (uint32_t idx) + { + Mutex::Locker locker(m_threads_mutex); + if (idx < m_threads.size()) + return m_threads[idx]; + return lldb::NativeThreadProtocolSP(); + } + + lldb::NativeThreadProtocolSP + GetThreadByID (lldb::tid_t tid) + { + Mutex::Locker locker(m_threads_mutex); + for (auto thread_sp : m_threads) + { + if (thread_sp->GetID() == tid) + return thread_sp; + } + return lldb::NativeThreadProtocolSP(); + } + + protected: + lldb::pid_t m_pid; + std::vector<lldb::NativeThreadProtocolSP> m_threads; + mutable Mutex m_threads_mutex; + lldb::StateType m_state; + int m_exit_status; + std::string m_exit_description; + }; + +} +#endif // #ifndef liblldb_Debug_h_ diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h index 7ca582402b32..607efa029c09 100644 --- a/include/lldb/Host/File.h +++ b/include/lldb/Host/File.h @@ -40,46 +40,13 @@ public: eOpenOptionTruncate = (1u << 3), // Truncate file when opening eOpenOptionNonBlocking = (1u << 4), // File reads eOpenOptionCanCreate = (1u << 5), // Create file if doesn't already exist - eOpenOptionCanCreateNewOnly = (1u << 6) // Can create file only if it doesn't already exist + eOpenOptionCanCreateNewOnly = (1u << 6), // Can create file only if it doesn't already exist + eOpenoptionDontFollowSymlinks = (1u << 7) }; static mode_t ConvertOpenOptionsForPOSIXOpen (uint32_t open_options); - enum Permissions - { - ePermissionsUserRead = (1u << 8), - ePermissionsUserWrite = (1u << 7), - ePermissionsUserExecute = (1u << 6), - ePermissionsGroupRead = (1u << 5), - ePermissionsGroupWrite = (1u << 4), - ePermissionsGroupExecute = (1u << 3), - ePermissionsWorldRead = (1u << 2), - ePermissionsWorldWrite = (1u << 1), - ePermissionsWorldExecute = (1u << 0), - - ePermissionsUserRW = (ePermissionsUserRead | ePermissionsUserWrite | 0 ), - ePermissionsUserRX = (ePermissionsUserRead | 0 | ePermissionsUserExecute ), - ePermissionsUserRWX = (ePermissionsUserRead | ePermissionsUserWrite | ePermissionsUserExecute ), - - ePermissionsGroupRW = (ePermissionsGroupRead | ePermissionsGroupWrite | 0 ), - ePermissionsGroupRX = (ePermissionsGroupRead | 0 | ePermissionsGroupExecute ), - ePermissionsGroupRWX = (ePermissionsGroupRead | ePermissionsGroupWrite | ePermissionsGroupExecute ), - - ePermissionsWorldRW = (ePermissionsWorldRead | ePermissionsWorldWrite | 0 ), - ePermissionsWorldRX = (ePermissionsWorldRead | 0 | ePermissionsWorldExecute ), - ePermissionsWorldRWX = (ePermissionsWorldRead | ePermissionsWorldWrite | ePermissionsWorldExecute ), - - ePermissionsEveryoneR = (ePermissionsUserRead | ePermissionsGroupRead | ePermissionsWorldRead ), - ePermissionsEveryoneW = (ePermissionsUserWrite | ePermissionsGroupWrite | ePermissionsWorldWrite ), - ePermissionsEveryoneX = (ePermissionsUserExecute | ePermissionsGroupExecute | ePermissionsWorldExecute ), - - ePermissionsEveryoneRW = (ePermissionsEveryoneR | ePermissionsEveryoneW | 0 ), - ePermissionsEveryoneRX = (ePermissionsEveryoneR | 0 | ePermissionsEveryoneX ), - ePermissionsEveryoneRWX = (ePermissionsEveryoneR | ePermissionsEveryoneW | ePermissionsEveryoneX ), - ePermissionsDefault = (ePermissionsUserRW | ePermissionsGroupRead) - }; - File() : m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), @@ -120,7 +87,7 @@ public: //------------------------------------------------------------------ File (const char *path, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); //------------------------------------------------------------------ /// Constructor with FileSpec. @@ -142,7 +109,7 @@ public: //------------------------------------------------------------------ File (const FileSpec& filespec, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); File (int fd, bool tranfer_ownership) : m_descriptor (fd), @@ -236,7 +203,7 @@ public: Error Open (const char *path, uint32_t options, - uint32_t permissions = ePermissionsDefault); + uint32_t permissions = lldb::eFilePermissionsFileDefault); Error Close (); diff --git a/include/lldb/Host/FileSpec.h b/include/lldb/Host/FileSpec.h index dfc6b711ae4a..086c8f200567 100644 --- a/include/lldb/Host/FileSpec.h +++ b/include/lldb/Host/FileSpec.h @@ -420,6 +420,21 @@ public: FileType GetFileType () const; + //------------------------------------------------------------------ + /// Return the current permissions of the path. + /// + /// Returns a bitmask for the current permissions of the file + /// ( zero or more of the permission bits defined in + /// File::Permissions). + /// + /// @return + /// Zero if the file doesn't exist or we are unable to get + /// information for the file, otherwise one or more permission + /// bits from the File::Permissions enumeration. + //------------------------------------------------------------------ + uint32_t + GetPermissions () const; + bool IsDirectory () const { @@ -636,7 +651,7 @@ public: void RemoveLastPathComponent (); - const char* + ConstString GetLastPathComponent () const; //------------------------------------------------------------------ diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h index 1d667dee5a20..fe0f6f62b3bc 100644 --- a/include/lldb/Host/Host.h +++ b/include/lldb/Host/Host.h @@ -510,13 +510,28 @@ public: const char *symbol_name, Error &error); - static uint32_t - MakeDirectory (const char* path, mode_t mode); + static Error + MakeDirectory (const char* path, uint32_t mode); + + static Error + GetFilePermissions (const char* path, uint32_t &file_permissions); + + static Error + SetFilePermissions (const char* path, uint32_t file_permissions); + static Error + Symlink (const char *src, const char *dst); + + static Error + Readlink (const char *path, char *buf, size_t buf_len); + + static Error + Unlink (const char *path); + static lldb::user_id_t OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error); static bool diff --git a/include/lldb/Host/OptionParser.h b/include/lldb/Host/OptionParser.h index 410e4d9f9468..ca83eeb1ed77 100644 --- a/include/lldb/Host/OptionParser.h +++ b/include/lldb/Host/OptionParser.h @@ -10,6 +10,10 @@ #ifndef liblldb_OptionParser_h_ #define liblldb_OptionParser_h_ +#include <string> + +struct option; + namespace lldb_private { typedef struct Option @@ -46,6 +50,7 @@ public: static char* GetOptionArgument(); static int GetOptionIndex(); static int GetOptionErrorCause(); + static std::string GetShortOptionString(struct option *long_options); }; } diff --git a/include/lldb/Interpreter/PythonDataObjects.h b/include/lldb/Interpreter/PythonDataObjects.h index a54318159d14..2762d452c0c8 100644 --- a/include/lldb/Interpreter/PythonDataObjects.h +++ b/include/lldb/Interpreter/PythonDataObjects.h @@ -19,11 +19,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Flags.h" #include "lldb/Interpreter/OptionValue.h" -#if defined (__APPLE__) -#include <Python/Python.h> -#else -#include <Python.h> -#endif +#include "lldb/lldb-python.h" namespace lldb_private { diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h index 4b3dc61f3ee8..b729cb628007 100644 --- a/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -17,12 +17,7 @@ #else -#if defined (__APPLE__) -#include <Python/Python.h> -#else -#include <Python.h> -#endif - +#include "lldb/lldb-python.h" #include "lldb/lldb-private.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Core/InputReader.h" diff --git a/include/lldb/Symbol/TypeList.h b/include/lldb/Symbol/TypeList.h index be7d35482da0..4f3f2c9bdbeb 100644 --- a/include/lldb/Symbol/TypeList.h +++ b/include/lldb/Symbol/TypeList.h @@ -12,6 +12,7 @@ #include "lldb/lldb-private.h" #include "lldb/Symbol/Type.h" +#include "lldb/Utility/Iterable.h" #include <map> #include <functional> @@ -51,6 +52,15 @@ public: lldb::TypeSP GetTypeAtIndex(uint32_t idx); + + typedef std::multimap<lldb::user_id_t, lldb::TypeSP> collection; + typedef AdaptedIterable<collection, lldb::TypeSP, map_adapter> TypeIterable; + + TypeIterable + Types () + { + return TypeIterable(m_types); + } void ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const; @@ -75,7 +85,6 @@ public: RemoveMismatchedTypes (lldb::TypeClass type_class); private: - typedef std::multimap<lldb::user_id_t, lldb::TypeSP> collection; typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; diff --git a/include/lldb/Target/ABI.h b/include/lldb/Target/ABI.h index 16f8ee7fc7d7..cc6c46cf0ec9 100644 --- a/include/lldb/Target/ABI.h +++ b/include/lldb/Target/ABI.h @@ -18,6 +18,8 @@ #include "lldb/Core/PluginInterface.h" #include "lldb/lldb-private.h" +#include "llvm/ADT/ArrayRef.h" + namespace lldb_private { class ABI : @@ -35,12 +37,7 @@ public: lldb::addr_t sp, lldb::addr_t functionAddress, lldb::addr_t returnAddress, - lldb::addr_t *arg1_ptr = NULL, - lldb::addr_t *arg2_ptr = NULL, - lldb::addr_t *arg3_ptr = NULL, - lldb::addr_t *arg4_ptr = NULL, - lldb::addr_t *arg5_ptr = NULL, - lldb::addr_t *arg6_ptr = NULL) const = 0; + llvm::ArrayRef<lldb::addr_t> args) const = 0; virtual bool GetArgumentValues (Thread &thread, diff --git a/include/lldb/Target/LanguageRuntime.h b/include/lldb/Target/LanguageRuntime.h index 93c0437da75d..0aaa67c2382c 100644 --- a/include/lldb/Target/LanguageRuntime.h +++ b/include/lldb/Target/LanguageRuntime.h @@ -67,6 +67,12 @@ public: } virtual bool + ExceptionBreakpointsAreSet () + { + return false; + } + + virtual bool ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) { return false; diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h index 93cd67d66659..355c0528bed8 100644 --- a/include/lldb/Target/Platform.h +++ b/include/lldb/Target/Platform.h @@ -40,7 +40,8 @@ namespace lldb_private { /// @li listing and getting info for existing processes /// @li attaching and possibly debugging the platform's kernel //---------------------------------------------------------------------- - class Platform : public PluginInterface + class Platform : + public PluginInterface { public: @@ -214,8 +215,7 @@ namespace lldb_private { bool GetOSKernelDescription (std::string &s); - // Returns the the hostname if we are connected, else the short plugin - // name. + // Returns the the name of the platform ConstString GetName (); @@ -269,6 +269,15 @@ namespace lldb_private { { return ArchSpec(); // Return an invalid architecture } + + virtual ConstString + GetRemoteWorkingDirectory() + { + return m_working_dir; + } + + virtual bool + SetRemoteWorkingDirectory(const ConstString &path); virtual const char * GetUserName (uint32_t uid); @@ -384,10 +393,13 @@ namespace lldb_private { } //------------------------------------------------------------------ - /// Subclasses should NOT need to implement this function as it uses - /// the Platform::LaunchProcess() followed by Platform::Attach () + /// Subclasses do not need to implement this function as it uses + /// the Platform::LaunchProcess() followed by Platform::Attach (). + /// Remote platforms will want to subclass this function in order + /// to be able to intercept STDIO and possibly launch a separate + /// process that will debug the debuggee. //------------------------------------------------------------------ - lldb::ProcessSP + virtual lldb::ProcessSP DebugProcess (ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -542,6 +554,12 @@ namespace lldb_private { { m_sdk_build = sdk_build; } + + ConstString + GetWorkingDirectory (); + + bool + SetWorkingDirectory (const ConstString &path); // There may be modules that we don't want to find by default for operations like "setting breakpoint by name". // The platform will return "true" from this call if the passed in module happens to be one of these. @@ -552,23 +570,19 @@ namespace lldb_private { return false; } - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode) - { - return UINT32_MAX; - } - - // this need not be virtual: the core behavior is in - // MakeDirectory(std::string,mode_t) - uint32_t - MakeDirectory (const FileSpec &spec, - mode_t mode); + virtual Error + MakeDirectory (const char *path, uint32_t permissions); + virtual Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual Error + SetFilePermissions (const char *path, uint32_t file_permissions); + virtual lldb::user_id_t OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { return UINT64_MAX; @@ -610,28 +624,54 @@ namespace lldb_private { } virtual Error + GetFile (const FileSpec& source, + const FileSpec& destination); + + virtual Error PutFile (const FileSpec& source, const FileSpec& destination, uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX); - + + virtual Error + CreateSymlink (const char *src, // The name of the link is in src + const char *dst);// The symlink points to dst + + //---------------------------------------------------------------------- + /// Install a file or directory to the remote system. + /// + /// Install is similar to Platform::PutFile(), but it differs in that if + /// an application/framework/shared library is installed on a remote + /// platform and the remote platform requires something to be done to + /// register the application/framework/shared library, then this extra + /// registration can be done. + /// + /// @param[in] src + /// The source file/directory to install on the remote system. + /// + /// @param[in] dst + /// The destination file/directory where \a src will be installed. + /// If \a dst has no filename specified, then its filename will + /// be set from \a src. It \a dst has no directory specified, it + /// will use the platform working directory. If \a dst has a + /// directory specified, but the directory path is relative, the + /// platform working directory will be prepended to the relative + /// directory. + /// + /// @return + /// An error object that describes anything that went wrong. + //---------------------------------------------------------------------- + virtual Error + Install (const FileSpec& src, const FileSpec& dst); + virtual size_t GetEnvironment (StringList &environment); - virtual Error - GetFile (const FileSpec& source, - const FileSpec& destination); - virtual bool GetFileExists (const lldb_private::FileSpec& file_spec); - virtual uint32_t - GetFilePermissions (const lldb_private::FileSpec &file_spec, - Error &error) - { - error.SetErrorStringWithFormat ("Platform::GetFilePermissions() is not supported in the %s platform", GetName().GetCString()); - return 0; - } + virtual Error + Unlink (const char *path); virtual bool GetSupportsRSync () @@ -806,6 +846,7 @@ namespace lldb_private { bool m_system_arch_set_while_connected; ConstString m_sdk_sysroot; // the root location of where the SDK files are all located ConstString m_sdk_build; + ConstString m_working_dir; // The working directory which is used when installing modules that have no install path set std::string m_remote_url; std::string m_name; uint32_t m_major_os_version; diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h index aa7b5edc5af1..cda9b4f57118 100644 --- a/include/lldb/Target/Process.h +++ b/include/lldb/Target/Process.h @@ -1745,7 +1745,7 @@ public: /// the error object is success. //------------------------------------------------------------------ virtual Error - Launch (const ProcessLaunchInfo &launch_info); + Launch (ProcessLaunchInfo &launch_info); virtual Error LoadCore (); @@ -2502,11 +2502,7 @@ public: ExecutionResults RunThreadPlan (ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, - bool stop_others, - bool run_others, - bool unwind_on_error, - bool ignore_breakpoints, - uint32_t timeout_usec, + const EvaluateExpressionOptions &options, Stream &errors); static const char * @@ -3304,6 +3300,23 @@ public: { return m_thread_list; } + + // When ExtendedBacktraces are requested, the HistoryThreads that are + // created need an owner -- they're saved here in the Process. The + // threads in this list are not iterated over - driver programs need to + // request the extended backtrace calls starting from a root concrete + // thread one by one. + ThreadList & + GetExtendedThreadList () + { + return m_extended_thread_list; + } + + ThreadList::ThreadIterable + Threads () + { + return m_thread_list.Threads(); + } uint32_t GetNextThreadIndexID (uint64_t thread_id); @@ -3670,6 +3683,8 @@ protected: ThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with ThreadList m_thread_list; ///< The threads for this process as the user will see them. This is usually the same as ///< m_thread_list_real, but might be different if there is an OS plug-in creating memory threads + ThreadList m_extended_thread_list; ///< Owner for extended threads that may be generated, cleared on natural stops + uint32_t m_extended_thread_stop_id; ///< The natural stop id when extended_thread_list was last updated std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver. std::vector<lldb::addr_t> m_image_tokens; Listener &m_listener; diff --git a/include/lldb/Target/RegisterCheckpoint.h b/include/lldb/Target/RegisterCheckpoint.h new file mode 100644 index 000000000000..3e61e1490d4b --- /dev/null +++ b/include/lldb/Target/RegisterCheckpoint.h @@ -0,0 +1,71 @@ +//===-- RegisterCheckpoint.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_RegisterCheckpoint_h_ +#define liblldb_RegisterCheckpoint_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Core/UserID.h" +#include "lldb/Target/StackID.h" + +namespace lldb_private { + + // Inherit from UserID in case pushing/popping all register values can be + // done using a 64 bit integer that holds a baton/cookie instead of actually + // having to read all register values into a buffer + class RegisterCheckpoint : public UserID + { + public: + + enum class Reason { + // An expression is about to be run on the thread if the protocol that + // talks to the debuggee supports checkpointing the registers using a + // push/pop then the UserID base class in the RegisterCheckpoint can + // be used to store the baton/cookie that refers to the remote saved + // state. + eExpression, + // The register checkpoint wants the raw register bytes, so they must + // be read into m_data_sp, or the save/restore checkpoint should fail. + eDataBackup + }; + + RegisterCheckpoint(Reason reason) : + UserID(0), + m_data_sp (), + m_reason(reason) + { + } + + ~RegisterCheckpoint() + { + } + + lldb::DataBufferSP & + GetData() + { + return m_data_sp; + } + + const lldb::DataBufferSP & + GetData() const + { + return m_data_sp; + } + + protected: + lldb::DataBufferSP m_data_sp; + Reason m_reason; + + // Make RegisterCheckpointSP if you wish to share the data in this class. + DISALLOW_COPY_AND_ASSIGN(RegisterCheckpoint); + }; + +} // namespace lldb_private + +#endif // liblldb_RegisterCheckpoint_h_ diff --git a/include/lldb/Target/RegisterContext.h b/include/lldb/Target/RegisterContext.h index 7da462700110..421acc03cb22 100644 --- a/include/lldb/Target/RegisterContext.h +++ b/include/lldb/Target/RegisterContext.h @@ -59,6 +59,18 @@ public: virtual bool WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0; + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp) + { + return false; + } + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) + { + return false; + } + // These two functions are used to implement "push" and "pop" of register states. They are used primarily // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues. @@ -67,10 +79,10 @@ public: // so these API's should only be used when this behavior is needed. virtual bool - ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0; - + ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); + virtual bool - WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0; + WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); bool CopyFromRegisterContext (lldb::RegisterContextSP context); diff --git a/include/lldb/Target/SystemRuntime.h b/include/lldb/Target/SystemRuntime.h index 6c0a4205d5f2..7a0703e6cc34 100644 --- a/include/lldb/Target/SystemRuntime.h +++ b/include/lldb/Target/SystemRuntime.h @@ -127,7 +127,7 @@ public: /// An empty vector may be returned if no thread origin extended /// backtrace capabilities are available. //------------------------------------------------------------------ - virtual std::vector<ConstString> + virtual const std::vector<ConstString> & GetExtendedBacktraceTypes (); //------------------------------------------------------------------ @@ -158,13 +158,16 @@ public: /// An empty ThreadSP will be returned if no thread origin is available. //------------------------------------------------------------------ virtual lldb::ThreadSP - GetExtendedBacktrace (lldb::ThreadSP thread, ConstString type); + GetExtendedBacktraceThread (lldb::ThreadSP thread, ConstString type); protected: //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ Process *m_process; + + std::vector<ConstString> m_types; + private: DISALLOW_COPY_AND_ASSIGN (SystemRuntime); }; diff --git a/include/lldb/Target/Target.h b/include/lldb/Target/Target.h index 1c90ea6f15eb..d874891a6aff 100644 --- a/include/lldb/Target/Target.h +++ b/include/lldb/Target/Target.h @@ -189,8 +189,10 @@ public: m_unwind_on_error(true), m_ignore_breakpoints (false), m_keep_in_memory(false), - m_run_others(true), + m_try_others(true), + m_stop_others(true), m_debug(false), + m_trap_exceptions(true), m_use_dynamic(lldb::eNoDynamicValues), m_timeout_usec(default_timeout) {} @@ -201,11 +203,10 @@ public: return m_execution_policy; } - EvaluateExpressionOptions& + void SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways) { m_execution_policy = policy; - return *this; } lldb::LanguageType @@ -214,11 +215,10 @@ public: return m_language; } - EvaluateExpressionOptions& + void SetLanguage(lldb::LanguageType language) { m_language = language; - return *this; } bool @@ -227,11 +227,10 @@ public: return m_coerce_to_id; } - EvaluateExpressionOptions& + void SetCoerceToId (bool coerce = true) { m_coerce_to_id = coerce; - return *this; } bool @@ -240,11 +239,10 @@ public: return m_unwind_on_error; } - EvaluateExpressionOptions& + void SetUnwindOnError (bool unwind = false) { m_unwind_on_error = unwind; - return *this; } bool @@ -253,11 +251,10 @@ public: return m_ignore_breakpoints; } - EvaluateExpressionOptions& + void SetIgnoreBreakpoints (bool ignore = false) { m_ignore_breakpoints = ignore; - return *this; } bool @@ -266,11 +263,10 @@ public: return m_keep_in_memory; } - EvaluateExpressionOptions& + void SetKeepInMemory (bool keep = true) { m_keep_in_memory = keep; - return *this; } lldb::DynamicValueType @@ -279,11 +275,10 @@ public: return m_use_dynamic; } - EvaluateExpressionOptions& + void SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget) { m_use_dynamic = dynamic; - return *this; } uint32_t @@ -292,24 +287,34 @@ public: return m_timeout_usec; } - EvaluateExpressionOptions& + void SetTimeoutUsec (uint32_t timeout = 0) { m_timeout_usec = timeout; - return *this; } bool - GetRunOthers () const + GetTryAllThreads () const { - return m_run_others; + return m_try_others; } - EvaluateExpressionOptions& - SetRunOthers (bool run_others = true) + void + SetTryAllThreads (bool try_others = true) + { + m_try_others = try_others; + } + + bool + GetStopOthers () const + { + return m_stop_others; + } + + void + SetStopOthers (bool stop_others = true) { - m_run_others = run_others; - return *this; + m_stop_others = stop_others; } bool @@ -318,11 +323,22 @@ public: return m_debug; } - EvaluateExpressionOptions& + void SetDebug(bool b) { m_debug = b; - return *this; + } + + bool + GetTrapExceptions() const + { + return m_trap_exceptions; + } + + void + SetTrapExceptions (bool b) + { + m_trap_exceptions = b; } private: @@ -332,8 +348,10 @@ private: bool m_unwind_on_error; bool m_ignore_breakpoints; bool m_keep_in_memory; - bool m_run_others; + bool m_try_others; + bool m_stop_others; bool m_debug; + bool m_trap_exceptions; lldb::DynamicValueType m_use_dynamic; uint32_t m_timeout_usec; }; @@ -741,9 +759,23 @@ public: SymbolsDidLoad (ModuleList &module_list); void - ClearModules(); + ClearModules(bool delete_locations); //------------------------------------------------------------------ + /// Called as the last function in Process::DidExec(). + /// + /// Process::DidExec() will clear a lot of state in the process, + /// then try to reload a dynamic loader plugin to discover what + /// binaries are currently available and then this function should + /// be called to allow the target to do any cleanup after everything + /// has been figured out. It can remove breakpoints that no longer + /// make sense as the exec might have changed the target + /// architecture, and unloaded some modules that might get deleted. + //------------------------------------------------------------------ + void + DidExec (); + + //------------------------------------------------------------------ /// Gets the module for the main executable. /// /// Each process has a notion of a main executable that is the file @@ -1009,6 +1041,12 @@ public: ClangASTImporter * GetClangASTImporter(); + //---------------------------------------------------------------------- + // Install any files through the platform that need be to installed + // prior to launching or attaching. + //---------------------------------------------------------------------- + Error + Install(ProcessLaunchInfo *launch_info); // Since expressions results can persist beyond the lifetime of a process, // and the const expression results are available after a process is gone, diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h index 7dac37caa200..4f78b0fe6998 100644 --- a/include/lldb/Target/Thread.h +++ b/include/lldb/Target/Thread.h @@ -17,6 +17,7 @@ #include "lldb/Core/UserID.h" #include "lldb/Core/UserSettingsController.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/RegisterCheckpoint.h" #include "lldb/Target/StackFrameList.h" #define LLDB_THREAD_MAX_STOP_EXC_DATA 8 @@ -130,79 +131,12 @@ public: DISALLOW_COPY_AND_ASSIGN (ThreadEventData); }; - // TODO: You shouldn't just checkpoint the register state alone, so this should get - // moved to protected. To do that ThreadStateCheckpoint needs to be returned as a token... - class RegisterCheckpoint - { - public: - - RegisterCheckpoint() : - m_stack_id (), - m_data_sp () - { - } - - RegisterCheckpoint (const StackID &stack_id) : - m_stack_id (stack_id), - m_data_sp () - { - } - - ~RegisterCheckpoint() - { - } - - const RegisterCheckpoint& - operator= (const RegisterCheckpoint &rhs) - { - if (this != &rhs) - { - this->m_stack_id = rhs.m_stack_id; - this->m_data_sp = rhs.m_data_sp; - } - return *this; - } - - RegisterCheckpoint (const RegisterCheckpoint &rhs) : - m_stack_id (rhs.m_stack_id), - m_data_sp (rhs.m_data_sp) - { - } - - const StackID & - GetStackID() - { - return m_stack_id; - } - - void - SetStackID (const StackID &stack_id) - { - m_stack_id = stack_id; - } - - lldb::DataBufferSP & - GetData() - { - return m_data_sp; - } - - const lldb::DataBufferSP & - GetData() const - { - return m_data_sp; - } - - protected: - StackID m_stack_id; - lldb::DataBufferSP m_data_sp; - }; struct ThreadStateCheckpoint { uint32_t orig_stop_id; // Dunno if I need this yet but it is an interesting bit of data. lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you might continue with the wrong signals. - RegisterCheckpoint register_backup; // You need to restore the registers, of course... + lldb::RegisterCheckpointSP register_backup_sp; // You need to restore the registers, of course... uint32_t current_inlined_depth; lldb::addr_t current_inlined_pc; }; @@ -339,18 +273,33 @@ public: return NULL; } + virtual void + SetName (const char *name) + { + } + virtual lldb::queue_id_t GetQueueID () { return LLDB_INVALID_QUEUE_ID; } + virtual void + SetQueueID (lldb::queue_id_t new_val) + { + } + virtual const char * GetQueueName () { return NULL; } + virtual void + SetQueueName (const char *name) + { + } + virtual uint32_t GetStackFrameCount() { @@ -529,21 +478,6 @@ public: QueueFundamentalPlan (bool abort_other_plans); //------------------------------------------------------------------ - /// Queues the plan used to step over a breakpoint at the current PC of \a thread. - /// The default version returned by Process handles trap based breakpoints, and - /// will disable the breakpoint, single step over it, then re-enable it. - /// - /// @param[in] abort_other_plans - /// \b true if we discard the currently queued plans and replace them with this one. - /// Otherwise this plan will go on the end of the plan stack. - /// - /// @return - /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued. - //------------------------------------------------------------------ - virtual lldb::ThreadPlanSP - QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans); - - //------------------------------------------------------------------ /// Queues the plan used to step one instruction from the current PC of \a thread. /// /// @param[in] step_over @@ -728,14 +662,6 @@ public: bool stop_others, uint32_t frame_idx); - virtual lldb::ThreadPlanSP - QueueThreadPlanForCallFunction (bool abort_other_plans, - Address& function, - lldb::addr_t arg, - bool stop_other_threads, - bool unwind_on_error = false, - bool ignore_breakpoints = true); - //------------------------------------------------------------------ // Thread Plan accessors: //------------------------------------------------------------------ @@ -879,7 +805,7 @@ public: void SetTracer (lldb::ThreadPlanTracerSP &tracer_sp); - + //------------------------------------------------------------------ // Get the thread index ID. The index ID that is guaranteed to not // be re-used by a process. They start at 1 and increase with each @@ -888,8 +814,25 @@ public: //------------------------------------------------------------------ uint32_t GetIndexID () const; - - + + //------------------------------------------------------------------ + // Get the originating thread's index ID. + // In the case of an "extended" thread -- a thread which represents + // the stack that enqueued/spawned work that is currently executing -- + // we need to provide the IndexID of the thread that actually did + // this work. We don't want to just masquerade as that thread's IndexID + // by using it in our own IndexID because that way leads to madness - + // but the driver program which is iterating over extended threads + // may ask for the OriginatingThreadID to display that information + // to the user. + // Normal threads will return the same thing as GetIndexID(); + //------------------------------------------------------------------ + virtual uint32_t + GetExtendedBacktraceOriginatingIndexID () + { + return GetIndexID (); + } + //------------------------------------------------------------------ // The API ID is often the same as the Thread::GetID(), but not in // all cases. Thread::GetID() is the user visible thread ID that @@ -1001,6 +944,33 @@ public: void SetShouldReportStop (Vote vote); + //---------------------------------------------------------------------- + /// Sets the extended backtrace token for this thread + /// + /// Some Thread subclasses may maintain a token to help with providing + /// an extended backtrace. The SystemRuntime plugin will set/request this. + /// + /// @param [in] token + //---------------------------------------------------------------------- + virtual void + SetExtendedBacktraceToken (uint64_t token) { } + + //---------------------------------------------------------------------- + /// Gets the extended backtrace token for this thread + /// + /// Some Thread subclasses may maintain a token to help with providing + /// an extended backtrace. The SystemRuntime plugin will set/request this. + /// + /// @return + /// The token needed by the SystemRuntime to create an extended backtrace. + /// LLDB_INVALID_ADDRESS is returned if no token is available. + //---------------------------------------------------------------------- + virtual uint64_t + GetExtendedBacktraceToken () + { + return LLDB_INVALID_ADDRESS; + } + protected: friend class ThreadPlan; @@ -1027,16 +997,6 @@ protected: typedef std::vector<lldb::ThreadPlanSP> plan_stack; - virtual bool - SaveFrameZeroState (RegisterCheckpoint &checkpoint); - - virtual bool - RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint); - - // register_data_sp must be a DataSP passed to ReadAllRegisterValues. - bool - ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp); - virtual lldb_private::Unwind * GetUnwinder (); @@ -1058,12 +1018,6 @@ protected: lldb::StackFrameListSP GetStackFrameList (); - struct ThreadState - { - uint32_t orig_stop_id; - lldb::StopInfoSP stop_info_sp; - RegisterCheckpoint register_backup; - }; //------------------------------------------------------------------ // Classes that inherit from Process can see and modify these diff --git a/include/lldb/Target/ThreadList.h b/include/lldb/Target/ThreadList.h index ddf49b002ecf..f4dfdb23ec0f 100644 --- a/include/lldb/Target/ThreadList.h +++ b/include/lldb/Target/ThreadList.h @@ -14,6 +14,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/UserID.h" +#include "lldb/Utility/Iterable.h" // FIXME: Currently this is a thread list with lots of functionality for use only by @@ -69,6 +70,15 @@ public: // is a unique index assigned lldb::ThreadSP GetThreadAtIndex (uint32_t idx, bool can_update = true); + + typedef std::vector<lldb::ThreadSP> collection; + typedef LockingAdaptedIterable<collection, lldb::ThreadSP, vector_adapter> ThreadIterable; + + ThreadIterable + Threads () + { + return ThreadIterable(m_threads, GetMutex()); + } lldb::ThreadSP FindThreadByID (lldb::tid_t tid, bool can_update = true); @@ -145,7 +155,6 @@ protected: void NotifySelectedThreadChanged (lldb::tid_t tid); - typedef std::vector<lldb::ThreadSP> collection; //------------------------------------------------------------------ // Classes that inherit from Process can see and modify these //------------------------------------------------------------------ diff --git a/include/lldb/Target/ThreadPlanCallFunction.h b/include/lldb/Target/ThreadPlanCallFunction.h index 7b8efb60b880..18f1d0facbf6 100644 --- a/include/lldb/Target/ThreadPlanCallFunction.h +++ b/include/lldb/Target/ThreadPlanCallFunction.h @@ -18,6 +18,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" +#include "llvm/ADT/ArrayRef.h" + namespace lldb_private { class ThreadPlanCallFunction : public ThreadPlan @@ -29,25 +31,8 @@ public: ThreadPlanCallFunction (Thread &thread, const Address &function, const ClangASTType &return_type, - lldb::addr_t arg, - bool stop_other_threads, - bool unwind_on_error = true, - bool ignore_breakpoints = false, - lldb::addr_t *this_arg = 0, - lldb::addr_t *cmd_arg = 0); - - ThreadPlanCallFunction (Thread &thread, - const Address &function, - const ClangASTType &return_type, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints, - lldb::addr_t *arg1_ptr = NULL, - lldb::addr_t *arg2_ptr = NULL, - lldb::addr_t *arg3_ptr = NULL, - lldb::addr_t *arg4_ptr = NULL, - lldb::addr_t *arg5_ptr = NULL, - lldb::addr_t *arg6_ptr = NULL); + llvm::ArrayRef<lldb::addr_t> args, + const EvaluateExpressionOptions &options); virtual ~ThreadPlanCallFunction (); @@ -171,10 +156,13 @@ private: bool m_valid; bool m_stop_other_threads; + bool m_unwind_on_error; + bool m_ignore_breakpoints; + bool m_debug_execution; + bool m_trap_exceptions; Address m_function_addr; Address m_start_addr; lldb::addr_t m_function_sp; - Thread::RegisterCheckpoint m_register_backup; lldb::ThreadPlanSP m_subplan_sp; LanguageRuntime *m_cxx_language_runtime; LanguageRuntime *m_objc_language_runtime; @@ -187,9 +175,9 @@ private: ClangASTType m_return_type; lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that. + bool m_should_clear_objc_exception_bp; + bool m_should_clear_cxx_exception_bp; lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown; - bool m_unwind_on_error; - bool m_ignore_breakpoints; DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction); }; diff --git a/include/lldb/Target/ThreadPlanCallUserExpression.h b/include/lldb/Target/ThreadPlanCallUserExpression.h index 7a7ec33049e0..5eb7cc1cd452 100644 --- a/include/lldb/Target/ThreadPlanCallUserExpression.h +++ b/include/lldb/Target/ThreadPlanCallUserExpression.h @@ -20,6 +20,8 @@ #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "llvm/ADT/ArrayRef.h" + namespace lldb_private { class ThreadPlanCallUserExpression : public ThreadPlanCallFunction @@ -27,12 +29,8 @@ class ThreadPlanCallUserExpression : public ThreadPlanCallFunction public: ThreadPlanCallUserExpression (Thread &thread, Address &function, - lldb::addr_t arg, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints, - lldb::addr_t *this_arg, - lldb::addr_t *cmd_arg, + llvm::ArrayRef<lldb::addr_t> args, + const EvaluateExpressionOptions &options, ClangUserExpression::ClangUserExpressionSP &user_expression_sp); virtual diff --git a/include/lldb/Utility/Iterable.h b/include/lldb/Utility/Iterable.h new file mode 100644 index 000000000000..9b91cae37eef --- /dev/null +++ b/include/lldb/Utility/Iterable.h @@ -0,0 +1,225 @@ +//===-- Iterable.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_Iterable_h_ +#define liblldb_Iterable_h_ + +#include "lldb/Host/Mutex.h" + +namespace lldb_private +{ + +template <typename I, typename E> E map_adapter(I &iter) +{ + return iter->second; +} + +template <typename I, typename E> E vector_adapter(I &iter) +{ + return *iter; +} + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> class AdaptedConstIterator +{ +public: + typedef typename C::const_iterator BackingIterator; +private: + BackingIterator m_iter; +public: + // Wrapping constructor + AdaptedConstIterator (BackingIterator backing_iterator) : + m_iter(backing_iterator) + { + } + + // Default-constructible + AdaptedConstIterator () : + m_iter() + { + } + + // Copy-constructible + AdaptedConstIterator (const AdaptedConstIterator &rhs) : + m_iter(rhs.m_iter) + { + } + + // Copy-assignable + AdaptedConstIterator &operator= (const AdaptedConstIterator &rhs) + { + m_iter = rhs.m_iter; + return *this; + } + + // Destructible + ~AdaptedConstIterator () { } + + // Comparable + bool operator== (const AdaptedConstIterator &rhs) + { + return m_iter == rhs.m_iter; + } + + bool operator!= (const AdaptedConstIterator &rhs) + { + return m_iter != rhs.m_iter; + } + + // Rvalue dereferenceable + E operator* () + { + return (*A)(m_iter); + } + + E operator-> () + { + return (*A)(m_iter); + } + + // Offset dereferenceable + E operator[] (typename BackingIterator::difference_type offset) + { + return AdaptedConstIterator(m_iter + offset); + } + + // Incrementable + AdaptedConstIterator &operator++ () + { + m_iter++; + return *this; + } + + // Decrementable + AdaptedConstIterator &operator-- () + { + m_iter--; + return *this; + } + + // Compound assignment + AdaptedConstIterator &operator+= (typename BackingIterator::difference_type offset) + { + m_iter += offset; + return *this; + } + + AdaptedConstIterator &operator-= (typename BackingIterator::difference_type offset) + { + m_iter -= offset; + return *this; + } + + // Arithmetic + AdaptedConstIterator operator+ (typename BackingIterator::difference_type offset) + { + return AdaptedConstIterator(m_iter + offset); + } + + AdaptedConstIterator operator- (typename BackingIterator::difference_type offset) + { + return AdaptedConstIterator(m_iter - offset); + } + + // Comparable + bool operator< (AdaptedConstIterator &rhs) + { + return m_iter < rhs.m_iter; + } + + bool operator<= (AdaptedConstIterator &rhs) + { + return m_iter <= rhs.m_iter; + } + + bool operator> (AdaptedConstIterator &rhs) + { + return m_iter > rhs.m_iter; + } + + bool operator>= (AdaptedConstIterator &rhs) + { + return m_iter >= rhs.m_iter; + } + + friend AdaptedConstIterator operator+(typename BackingIterator::difference_type, AdaptedConstIterator &); + friend typename BackingIterator::difference_type operator-(AdaptedConstIterator &, AdaptedConstIterator &); + friend void swap(AdaptedConstIterator &, AdaptedConstIterator &); +}; + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> +AdaptedConstIterator<C, E, A> operator+ (typename AdaptedConstIterator<C, E, A>::BackingIterator::difference_type offset, AdaptedConstIterator<C, E, A> &rhs) +{ + return rhs.operator+(offset); +} + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> +typename AdaptedConstIterator<C, E, A>::BackingIterator::difference_type operator- (AdaptedConstIterator<C, E, A> &lhs, AdaptedConstIterator<C, E, A> &rhs) +{ + return(lhs.m_iter - rhs.m_iter); +} + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> +void swap (AdaptedConstIterator<C, E, A> &lhs, AdaptedConstIterator<C, E, A> &rhs) +{ + std::swap(lhs.m_iter, rhs.m_iter); +} + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> class AdaptedIterable +{ +private: + const C &m_container; +public: + AdaptedIterable (const C &container) : + m_container(container) + { + } + + AdaptedConstIterator<C, E, A> begin () + { + return AdaptedConstIterator<C, E, A>(m_container.begin()); + } + + AdaptedConstIterator<C, E, A> end () + { + return AdaptedConstIterator<C, E, A>(m_container.end()); + } +}; + +template <typename C, typename E, E (*A)(typename C::const_iterator &)> class LockingAdaptedIterable : public AdaptedIterable<C, E, A> +{ +private: + Mutex *m_mutex = nullptr; +public: + LockingAdaptedIterable (C &container, Mutex &mutex) : + AdaptedIterable<C,E,A>(container), + m_mutex(&mutex) + { + m_mutex->Lock(); + } + + LockingAdaptedIterable (LockingAdaptedIterable &&rhs) : + AdaptedIterable<C,E,A>(rhs), + m_mutex(rhs.m_mutex) + { + rhs.m_mutex = NULL; + } + + ~LockingAdaptedIterable () + { + if (m_mutex) + m_mutex->Unlock(); + } + +private: + DISALLOW_COPY_AND_ASSIGN(LockingAdaptedIterable); +}; + +} + +#endif diff --git a/include/lldb/Utility/PythonPointer.h b/include/lldb/Utility/PythonPointer.h index f782f7f1313c..fe90670fd2e1 100644 --- a/include/lldb/Utility/PythonPointer.h +++ b/include/lldb/Utility/PythonPointer.h @@ -12,11 +12,7 @@ #include <algorithm> -#if defined (__APPLE__) -#include <Python/Python.h> -#else -#include <Python.h> -#endif +#include "lldb/lldb-python.h" namespace lldb_private { diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h index ae8c92be900b..0b341575be46 100644 --- a/include/lldb/lldb-enumerations.h +++ b/include/lldb/lldb-enumerations.h @@ -684,6 +684,48 @@ namespace lldb { eAddressClassRuntime } AddressClass; + //---------------------------------------------------------------------- + // File Permissions + // + // Designed to mimic the unix file permission bits so they can be + // used with functions that set 'mode_t' to certain values for + // permissions. + //---------------------------------------------------------------------- + typedef enum FilePermissions + { + eFilePermissionsUserRead = (1u << 8), + eFilePermissionsUserWrite = (1u << 7), + eFilePermissionsUserExecute = (1u << 6), + eFilePermissionsGroupRead = (1u << 5), + eFilePermissionsGroupWrite = (1u << 4), + eFilePermissionsGroupExecute = (1u << 3), + eFilePermissionsWorldRead = (1u << 2), + eFilePermissionsWorldWrite = (1u << 1), + eFilePermissionsWorldExecute = (1u << 0), + + eFilePermissionsUserRW = (eFilePermissionsUserRead | eFilePermissionsUserWrite | 0 ), + eFileFilePermissionsUserRX = (eFilePermissionsUserRead | 0 | eFilePermissionsUserExecute ), + eFilePermissionsUserRWX = (eFilePermissionsUserRead | eFilePermissionsUserWrite | eFilePermissionsUserExecute ), + + eFilePermissionsGroupRW = (eFilePermissionsGroupRead | eFilePermissionsGroupWrite | 0 ), + eFilePermissionsGroupRX = (eFilePermissionsGroupRead | 0 | eFilePermissionsGroupExecute ), + eFilePermissionsGroupRWX = (eFilePermissionsGroupRead | eFilePermissionsGroupWrite | eFilePermissionsGroupExecute ), + + eFilePermissionsWorldRW = (eFilePermissionsWorldRead | eFilePermissionsWorldWrite | 0 ), + eFilePermissionsWorldRX = (eFilePermissionsWorldRead | 0 | eFilePermissionsWorldExecute ), + eFilePermissionsWorldRWX = (eFilePermissionsWorldRead | eFilePermissionsWorldWrite | eFilePermissionsWorldExecute ), + + eFilePermissionsEveryoneR = (eFilePermissionsUserRead | eFilePermissionsGroupRead | eFilePermissionsWorldRead ), + eFilePermissionsEveryoneW = (eFilePermissionsUserWrite | eFilePermissionsGroupWrite | eFilePermissionsWorldWrite ), + eFilePermissionsEveryoneX = (eFilePermissionsUserExecute | eFilePermissionsGroupExecute | eFilePermissionsWorldExecute ), + + eFilePermissionsEveryoneRW = (eFilePermissionsEveryoneR | eFilePermissionsEveryoneW | 0 ), + eFilePermissionsEveryoneRX = (eFilePermissionsEveryoneR | 0 | eFilePermissionsEveryoneX ), + eFilePermissionsEveryoneRWX = (eFilePermissionsEveryoneR | eFilePermissionsEveryoneW | eFilePermissionsEveryoneX ), + eFilePermissionsFileDefault = eFilePermissionsUserRW, + eFilePermissionsDirectoryDefault = eFilePermissionsUserRWX, + } FilePermissions; + } // namespace lldb diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h index cd8a5c2e8130..68d85f081e25 100644 --- a/include/lldb/lldb-forward.h +++ b/include/lldb/lldb-forward.h @@ -97,6 +97,7 @@ class FileSpecList; class Flags; class TypeCategoryImpl; class FormatManager; +class FormattersMatchCandidate; class FuncUnwinders; class Function; class FunctionInfo; @@ -162,6 +163,7 @@ class PythonDictionary; class PythonInteger; class PythonObject; class PythonString; +class RegisterCheckpoint; class RegisterContext; class RegisterLocation; class RegisterLocationList; @@ -329,6 +331,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP; typedef std::weak_ptr<lldb_private::Process> ProcessWP; typedef std::shared_ptr<lldb_private::Property> PropertySP; + typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP; typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP; typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP; typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP; diff --git a/include/lldb/lldb-private-enumerations.h b/include/lldb/lldb-private-enumerations.h index e523b912eac6..98919422be58 100644 --- a/include/lldb/lldb-private-enumerations.h +++ b/include/lldb/lldb-private-enumerations.h @@ -133,7 +133,8 @@ typedef enum ExecutionResults eExecutionDiscarded, eExecutionInterrupted, eExecutionHitBreakpoint, - eExecutionTimedOut + eExecutionTimedOut, + eExecutionStoppedForDebug } ExecutionResults; typedef enum ObjCRuntimeVersions { diff --git a/include/lldb/lldb-python.h b/include/lldb/lldb-python.h index 229e3967e4a5..ce5c8176a3c3 100644 --- a/include/lldb/lldb-python.h +++ b/include/lldb/lldb-python.h @@ -18,11 +18,7 @@ #else -#if defined (__APPLE__) -#include <Python/Python.h> -#else #include <Python.h> -#endif #endif // LLDB_DISABLE_PYTHON diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp index 88c991b72054..10c0b7dea208 100644 --- a/source/API/SBDebugger.cpp +++ b/source/API/SBDebugger.cpp @@ -38,6 +38,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" #include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Host/DynamicLibrary.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/OptionGroupPlatform.h" @@ -47,6 +48,41 @@ using namespace lldb; using namespace lldb_private; + +static lldb::DynamicLibrarySP +LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error) +{ + lldb::DynamicLibrarySP dynlib_sp(new lldb_private::DynamicLibrary(spec)); + if (dynlib_sp && dynlib_sp->IsValid()) + { + typedef bool (*LLDBCommandPluginInit) (lldb::SBDebugger& debugger); + + lldb::SBDebugger debugger_sb(debugger_sp); + // This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) function. + // TODO: mangle this differently for your system - on OSX, the first underscore needs to be removed and the second one stays + LLDBCommandPluginInit init_func = dynlib_sp->GetSymbol<LLDBCommandPluginInit>("_ZN4lldb16PluginInitializeENS_10SBDebuggerE"); + if (init_func) + { + if (init_func(debugger_sb)) + return dynlib_sp; + else + error.SetErrorString("plug-in refused to load (lldb::PluginInitialize(lldb::SBDebugger) returned false)"); + } + else + { + error.SetErrorString("plug-in is missing the required initialization: lldb::PluginInitialize(lldb::SBDebugger)"); + } + } + else + { + if (spec.Exists()) + error.SetErrorString("this file does not represent a loadable dylib"); + else + error.SetErrorString("no such file"); + } + return lldb::DynamicLibrarySP(); +} + void SBDebugger::Initialize () { @@ -57,7 +93,7 @@ SBDebugger::Initialize () SBCommandInterpreter::InitializeSWIG (); - Debugger::Initialize(); + Debugger::Initialize(LoadPlugin); } void @@ -804,6 +840,42 @@ SBDebugger::SetSelectedTarget (SBTarget &sb_target) } } +SBPlatform +SBDebugger::GetSelectedPlatform() +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + SBPlatform sb_platform; + DebuggerSP debugger_sp(m_opaque_sp); + if (debugger_sp) + { + sb_platform.SetSP(debugger_sp->GetPlatformList().GetSelectedPlatform()); + } + if (log) + { + log->Printf ("SBDebugger(%p)::GetSelectedPlatform () => SBPlatform(%p): %s", m_opaque_sp.get(), + sb_platform.GetSP().get(), sb_platform.GetName()); + } + return sb_platform; +} + +void +SBDebugger::SetSelectedPlatform(SBPlatform &sb_platform) +{ + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + DebuggerSP debugger_sp(m_opaque_sp); + if (debugger_sp) + { + debugger_sp->GetPlatformList().SetSelectedPlatform(sb_platform.GetSP()); + } + if (log) + { + log->Printf ("SBDebugger(%p)::SetSelectedPlatform (SBPlatform(%p) %s)", m_opaque_sp.get(), + sb_platform.GetSP().get(), sb_platform.GetName()); + } +} + void SBDebugger::DispatchInput (void* baton, const void *data, size_t data_len) { diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp index 127b0cf13cdc..ae1c8f99df30 100644 --- a/source/API/SBExpressionOptions.cpp +++ b/source/API/SBExpressionOptions.cpp @@ -104,13 +104,25 @@ SBExpressionOptions::SetTimeoutInMicroSeconds (uint32_t timeout) bool SBExpressionOptions::GetTryAllThreads () const { - return m_opaque_ap->GetRunOthers (); + return m_opaque_ap->GetTryAllThreads (); } void SBExpressionOptions::SetTryAllThreads (bool run_others) { - m_opaque_ap->SetRunOthers (run_others); + m_opaque_ap->SetTryAllThreads (run_others); +} + +bool +SBExpressionOptions::GetTrapExceptions () const +{ + return m_opaque_ap->GetTrapExceptions (); +} + +void +SBExpressionOptions::SetTrapExceptions (bool trap_exceptions) +{ + m_opaque_ap->SetTrapExceptions (trap_exceptions); } EvaluateExpressionOptions * diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp index fc207d071dbc..4fd2866c9b05 100644 --- a/source/API/SBFileSpec.cpp +++ b/source/API/SBFileSpec.cpp @@ -121,6 +121,24 @@ SBFileSpec::GetDirectory() const return s; } +void +SBFileSpec::SetFilename(const char *filename) +{ + if (filename && filename[0]) + m_opaque_ap->GetFilename().SetCString(filename); + else + m_opaque_ap->GetFilename().Clear(); +} + +void +SBFileSpec::SetDirectory(const char *directory) +{ + if (directory && directory[0]) + m_opaque_ap->GetDirectory().SetCString(directory); + else + m_opaque_ap->GetDirectory().Clear(); +} + uint32_t SBFileSpec::GetPath (char *dst_path, size_t dst_len) const { diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp index 5f5fc9292cdb..0285cf304d4d 100644 --- a/source/API/SBModule.cpp +++ b/source/API/SBModule.cpp @@ -162,6 +162,27 @@ SBModule::SetPlatformFileSpec (const lldb::SBFileSpec &platform_file) return result; } +lldb::SBFileSpec +SBModule::GetRemoteInstallFileSpec () +{ + SBFileSpec sb_file_spec; + ModuleSP module_sp (GetSP ()); + if (module_sp) + sb_file_spec.SetFileSpec (module_sp->GetRemoteInstallFileSpec()); + return sb_file_spec; +} + +bool +SBModule::SetRemoteInstallFileSpec (lldb::SBFileSpec &file) +{ + ModuleSP module_sp (GetSP ()); + if (module_sp) + { + module_sp->SetRemoteInstallFileSpec(file.ref()); + return true; + } + return false; +} const uint8_t * diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp new file mode 100644 index 000000000000..9914852cead7 --- /dev/null +++ b/source/API/SBPlatform.cpp @@ -0,0 +1,632 @@ +//===-- SBPlatform.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/API/SBPlatform.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Error.h" +#include "lldb/Host/File.h" +#include "lldb/Interpreter/Args.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Platform.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// PlatformConnectOptions +//---------------------------------------------------------------------- +struct PlatformConnectOptions { + PlatformConnectOptions(const char *url = NULL) : + m_url(), + m_rsync_options(), + m_rsync_remote_path_prefix(), + m_rsync_enabled(false), + m_rsync_omit_hostname_from_remote_path(false), + m_local_cache_directory () + { + if (url && url[0]) + m_url = url; + } + + ~PlatformConnectOptions() + { + } + + std::string m_url; + std::string m_rsync_options; + std::string m_rsync_remote_path_prefix; + bool m_rsync_enabled; + bool m_rsync_omit_hostname_from_remote_path; + ConstString m_local_cache_directory; +}; + +//---------------------------------------------------------------------- +// PlatformShellCommand +//---------------------------------------------------------------------- +struct PlatformShellCommand { + PlatformShellCommand(const char *shell_command = NULL) : + m_command(), + m_working_dir(), + m_status(0), + m_signo(0), + m_timeout_sec(UINT32_MAX) + { + if (shell_command && shell_command[0]) + m_command = shell_command; + } + + ~PlatformShellCommand() + { + } + + std::string m_command; + std::string m_working_dir; + std::string m_output; + int m_status; + int m_signo; + uint32_t m_timeout_sec; +}; +//---------------------------------------------------------------------- +// SBPlatformConnectOptions +//---------------------------------------------------------------------- +SBPlatformConnectOptions::SBPlatformConnectOptions (const char *url) : + m_opaque_ptr(new PlatformConnectOptions(url)) +{ + +} + +SBPlatformConnectOptions::SBPlatformConnectOptions(const SBPlatformConnectOptions &rhs) : + m_opaque_ptr(new PlatformConnectOptions()) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +SBPlatformConnectOptions::~SBPlatformConnectOptions () +{ + delete m_opaque_ptr; +} + +void +SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +const char * +SBPlatformConnectOptions::GetURL() +{ + if (m_opaque_ptr->m_url.empty()) + return NULL; + return m_opaque_ptr->m_url.c_str(); +} + +void +SBPlatformConnectOptions::SetURL(const char *url) +{ + if (url && url[0]) + m_opaque_ptr->m_url = url; + else + m_opaque_ptr->m_url.clear(); +} + +bool +SBPlatformConnectOptions::GetRsyncEnabled() +{ + return m_opaque_ptr->m_rsync_enabled; +} + +void +SBPlatformConnectOptions::EnableRsync (const char *options, + const char *remote_path_prefix, + bool omit_hostname_from_remote_path) +{ + m_opaque_ptr->m_rsync_enabled = true; + m_opaque_ptr->m_rsync_omit_hostname_from_remote_path = omit_hostname_from_remote_path; + if (remote_path_prefix && remote_path_prefix[0]) + m_opaque_ptr->m_rsync_remote_path_prefix = remote_path_prefix; + else + m_opaque_ptr->m_rsync_remote_path_prefix.clear(); + + if (options && options[0]) + m_opaque_ptr->m_rsync_options = options; + else + m_opaque_ptr->m_rsync_options.clear(); + +} + +void +SBPlatformConnectOptions::DisableRsync () +{ + m_opaque_ptr->m_rsync_enabled = false; +} + +const char * +SBPlatformConnectOptions::GetLocalCacheDirectory() +{ + return m_opaque_ptr->m_local_cache_directory.GetCString(); +} + +void +SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) +{ + if (path && path[0]) + m_opaque_ptr->m_local_cache_directory.SetCString(path); + else + m_opaque_ptr->m_local_cache_directory = ConstString(); +} + +//---------------------------------------------------------------------- +// SBPlatformShellCommand +//---------------------------------------------------------------------- +SBPlatformShellCommand::SBPlatformShellCommand (const char *shell_command) : + m_opaque_ptr(new PlatformShellCommand(shell_command)) +{ +} + +SBPlatformShellCommand::SBPlatformShellCommand (const SBPlatformShellCommand &rhs) : + m_opaque_ptr(new PlatformShellCommand()) +{ + *m_opaque_ptr = *rhs.m_opaque_ptr; +} + +SBPlatformShellCommand::~SBPlatformShellCommand() +{ + delete m_opaque_ptr; +} + +void +SBPlatformShellCommand::Clear() +{ + m_opaque_ptr->m_output = std::move(std::string()); + m_opaque_ptr->m_status = 0; + m_opaque_ptr->m_signo = 0; +} + +const char * +SBPlatformShellCommand::GetCommand() +{ + if (m_opaque_ptr->m_command.empty()) + return NULL; + return m_opaque_ptr->m_command.c_str(); +} + +void +SBPlatformShellCommand::SetCommand(const char *shell_command) +{ + if (shell_command && shell_command[0]) + m_opaque_ptr->m_command = shell_command; + else + m_opaque_ptr->m_command.clear(); +} + +const char * +SBPlatformShellCommand::GetWorkingDirectory () +{ + if (m_opaque_ptr->m_working_dir.empty()) + return NULL; + return m_opaque_ptr->m_working_dir.c_str(); +} + +void +SBPlatformShellCommand::SetWorkingDirectory (const char *path) +{ + if (path && path[0]) + m_opaque_ptr->m_working_dir = path; + else + m_opaque_ptr->m_working_dir.clear(); +} + +uint32_t +SBPlatformShellCommand::GetTimeoutSeconds () +{ + return m_opaque_ptr->m_timeout_sec; +} + +void +SBPlatformShellCommand::SetTimeoutSeconds (uint32_t sec) +{ + m_opaque_ptr->m_timeout_sec = sec; +} + +int +SBPlatformShellCommand::GetSignal () +{ + return m_opaque_ptr->m_signo; +} + +int +SBPlatformShellCommand::GetStatus () +{ + return m_opaque_ptr->m_status; +} + +const char * +SBPlatformShellCommand::GetOutput () +{ + if (m_opaque_ptr->m_output.empty()) + return NULL; + return m_opaque_ptr->m_output.c_str(); +} + +//---------------------------------------------------------------------- +// SBPlatform +//---------------------------------------------------------------------- +SBPlatform::SBPlatform () : + m_opaque_sp () +{ + +} + +SBPlatform::SBPlatform (const char *platform_name) : + m_opaque_sp () +{ + Error error; + m_opaque_sp = Platform::Create (platform_name, error); +} + +SBPlatform::~SBPlatform() +{ +} + +bool +SBPlatform::IsValid () const +{ + return m_opaque_sp.get() != NULL; +} + +void +SBPlatform::Clear () +{ + m_opaque_sp.reset(); +} + +const char * +SBPlatform::GetName () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetName().GetCString(); + return NULL; +} + +lldb::PlatformSP +SBPlatform::GetSP () const +{ + return m_opaque_sp; +} + +void +SBPlatform::SetSP (const lldb::PlatformSP& platform_sp) +{ + m_opaque_sp = platform_sp; +} + +const char * +SBPlatform::GetWorkingDirectory() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetWorkingDirectory().GetCString(); + return NULL; +} + +bool +SBPlatform::SetWorkingDirectory(const char *path) +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (path) + platform_sp->SetWorkingDirectory(ConstString(path)); + else + platform_sp->SetWorkingDirectory(ConstString()); + return true; + } + return false; +} + +SBError +SBPlatform::ConnectRemote (SBPlatformConnectOptions &connect_options) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp && connect_options.GetURL()) + { + Args args; + args.AppendArgument(connect_options.GetURL()); + sb_error.ref() = platform_sp->ConnectRemote(args); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +void +SBPlatform::DisconnectRemote () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + platform_sp->DisconnectRemote(); +} + +bool +SBPlatform::IsConnected() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + platform_sp->IsConnected(); + return false; +} + +const char * +SBPlatform::GetTriple() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + ArchSpec arch(platform_sp->GetRemoteSystemArchitecture()); + if (arch.IsValid()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); + } + } + return NULL; +} + +const char * +SBPlatform::GetOSBuild() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + std::string s; + if (platform_sp->GetOSBuildString(s)) + { + if (!s.empty()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(s.c_str()).GetCString(); + } + } + } + return NULL; +} + +const char * +SBPlatform::GetOSDescription() +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + std::string s; + if (platform_sp->GetOSKernelDescription(s)) + { + if (!s.empty()) + { + // Const-ify the string so we don't need to worry about the lifetime of the string + return ConstString(s.c_str()).GetCString(); + } + } + } + return NULL; +} + +const char * +SBPlatform::GetHostname () +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + return platform_sp->GetHostname(); + return NULL; +} + +uint32_t +SBPlatform::GetOSMajorVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return major; + return UINT32_MAX; + +} + +uint32_t +SBPlatform::GetOSMinorVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return minor; + return UINT32_MAX; +} + +uint32_t +SBPlatform::GetOSUpdateVersion () +{ + uint32_t major, minor, update; + PlatformSP platform_sp(GetSP()); + if (platform_sp && platform_sp->GetOSVersion(major, minor, update)) + return update; + return UINT32_MAX; +} + +SBError +SBPlatform::Get (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->GetFile(src.ref(), dst.ref()); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::Put (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (src.Exists()) + { + uint32_t permissions = src.ref().GetPermissions(); + if (permissions == 0) + { + if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory) + permissions = eFilePermissionsDirectoryDefault; + else + permissions = eFilePermissionsFileDefault; + } + + sb_error.ref() = platform_sp->PutFile(src.ref(), + dst.ref(), + permissions); + } + else + { + sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::Install (SBFileSpec &src, + SBFileSpec &dst) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (src.Exists()) + { + sb_error.ref() = platform_sp->Install(src.ref(), dst.ref()); + } + else + { + sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + + +SBError +SBPlatform::Run (SBPlatformShellCommand &shell_command) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + if (platform_sp->IsConnected()) + { + const char *command = shell_command.GetCommand(); + if (command) + { + const char *working_dir = shell_command.GetWorkingDirectory(); + if (working_dir == NULL) + { + working_dir = platform_sp->GetWorkingDirectory().GetCString(); + if (working_dir) + shell_command.SetWorkingDirectory(working_dir); + } + sb_error.ref() = platform_sp->RunShellCommand(command, + working_dir, + &shell_command.m_opaque_ptr->m_status, + &shell_command.m_opaque_ptr->m_signo, + &shell_command.m_opaque_ptr->m_output, + shell_command.m_opaque_ptr->m_timeout_sec); + } + else + { + sb_error.SetErrorString("invalid shell command (empty)"); + } + } + else + { + sb_error.SetErrorString("not connected"); + } + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +SBError +SBPlatform::MakeDirectory (const char *path, uint32_t file_permissions) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->MakeDirectory(path, file_permissions); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; +} + +uint32_t +SBPlatform::GetFilePermissions (const char *path) +{ + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + uint32_t file_permissions = 0; + platform_sp->GetFilePermissions(path, file_permissions); + return file_permissions; + } + return 0; + +} + +SBError +SBPlatform::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + SBError sb_error; + PlatformSP platform_sp(GetSP()); + if (platform_sp) + { + sb_error.ref() = platform_sp->SetFilePermissions(path, file_permissions); + } + else + { + sb_error.SetErrorString("invalid platform"); + } + return sb_error; + +} + diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp index d690da7eed87..557006f24345 100644 --- a/source/API/SBProcess.cpp +++ b/source/API/SBProcess.cpp @@ -1278,7 +1278,7 @@ SBProcess::GetExtendedBacktraceTypeAtIndex (uint32_t idx) if (process_sp && process_sp->GetSystemRuntime()) { SystemRuntime *runtime = process_sp->GetSystemRuntime(); - std::vector<ConstString> names = runtime->GetExtendedBacktraceTypes(); + const std::vector<ConstString> &names = runtime->GetExtendedBacktraceTypes(); if (idx < names.size()) { return names[idx].AsCString(); diff --git a/source/API/SBStream.cpp b/source/API/SBStream.cpp index dc8eb05ab0ba..531ab9f463ce 100644 --- a/source/API/SBStream.cpp +++ b/source/API/SBStream.cpp @@ -82,7 +82,7 @@ SBStream::RedirectToFile (const char *path, bool append) uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; if (append) open_options |= File::eOpenOptionAppend; - stream_file->GetFile().Open (path, open_options, File::ePermissionsDefault); + stream_file->GetFile().Open (path, open_options, lldb::eFilePermissionsFileDefault); m_opaque_ap.reset (stream_file); diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp index cff6e4e2de36..c8bc2171436d 100644 --- a/source/API/SBTarget.cpp +++ b/source/API/SBTarget.cpp @@ -605,6 +605,19 @@ SBTarget::LaunchSimple error); } +SBError +SBTarget::Install() +{ + SBError sb_error; + TargetSP target_sp(GetSP()); + if (target_sp) + { + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + sb_error.ref() = target_sp->Install(NULL); + } + return sb_error; +} + SBProcess SBTarget::Launch ( diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp index 4b54b1c0c1c6..4170d5b230bb 100644 --- a/source/API/SBThread.cpp +++ b/source/API/SBThread.cpp @@ -433,7 +433,6 @@ SBThread::SetThread (const ThreadSP& lldb_object_sp) m_opaque_sp->SetThreadSP (lldb_object_sp); } - lldb::tid_t SBThread::GetThreadID () const { @@ -1283,7 +1282,7 @@ SBThread::GetDescription (SBStream &description) const } SBThread -SBThread::GetExtendedBacktrace (const char *type) +SBThread::GetExtendedBacktraceThread (const char *type) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); Mutex::Locker api_locker; @@ -1295,24 +1294,50 @@ SBThread::GetExtendedBacktrace (const char *type) Process::StopLocker stop_locker; if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock())) { - ThreadSP real_thread(exe_ctx.GetThreadPtr()); + ThreadSP real_thread(exe_ctx.GetThreadSP()); if (real_thread) { ConstString type_const (type); - SystemRuntime *runtime = exe_ctx.GetProcessPtr()->GetSystemRuntime(); - if (runtime) + Process *process = exe_ctx.GetProcessPtr(); + if (process) { - ThreadSP origin_thread = runtime->GetExtendedBacktrace (real_thread, type_const); - sb_origin_thread.SetThread (origin_thread); + SystemRuntime *runtime = process->GetSystemRuntime(); + if (runtime) + { + ThreadSP new_thread_sp (runtime->GetExtendedBacktraceThread (real_thread, type_const)); + if (new_thread_sp) + { + // Save this in the Process' ExtendedThreadList so a strong pointer retains the + // object. + process->GetExtendedThreadList().AddThread (new_thread_sp); + sb_origin_thread.SetThread (new_thread_sp); + if (log) + { + const char *queue_name = new_thread_sp->GetQueueName(); + if (queue_name == NULL) + queue_name = ""; + log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => new extended Thread created (%p) with queue_id 0x%" PRIx64 " queue name '%s'", exe_ctx.GetThreadPtr(), new_thread_sp.get(), new_thread_sp->GetQueueID(), queue_name); + } + } + } } } } else { if (log) - log->Printf ("SBThread(%p)::GetExtendedBacktrace() => error: process is running", exe_ctx.GetThreadPtr()); + log->Printf ("SBThread(%p)::GetExtendedBacktraceThread() => error: process is running", exe_ctx.GetThreadPtr()); } } return sb_origin_thread; } + +uint32_t +SBThread::GetExtendedBacktraceOriginatingIndexID () +{ + ThreadSP thread_sp(m_opaque_sp->GetThreadSP()); + if (thread_sp) + return thread_sp->GetExtendedBacktraceOriginatingIndexID(); + return LLDB_INVALID_INDEX32; +} diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp index e07205e360b1..32c0b1066f8e 100644 --- a/source/Breakpoint/Breakpoint.cpp +++ b/source/Breakpoint/Breakpoint.cpp @@ -114,6 +114,12 @@ Breakpoint::GetLocationAtIndex (size_t index) return m_locations.GetByIndex(index); } +void +Breakpoint::RemoveInvalidLocations (const ArchSpec &arch) +{ + m_locations.RemoveInvalidLocations(arch); +} + // For each of the overall options we need to decide how they propagate to // the location options. This will determine the precedence of options on // the breakpoint vs. its locations. diff --git a/source/Breakpoint/BreakpointList.cpp b/source/Breakpoint/BreakpointList.cpp index c6030d60ca04..147ad36b0407 100644 --- a/source/Breakpoint/BreakpointList.cpp +++ b/source/Breakpoint/BreakpointList.cpp @@ -69,12 +69,20 @@ BreakpointList::Remove (break_id_t break_id, bool notify) } void +BreakpointList::RemoveInvalidLocations (const ArchSpec &arch) +{ + Mutex::Locker locker(m_mutex); + for (const auto &bp_sp : m_breakpoints) + bp_sp->RemoveInvalidLocations(arch); +} + + +void BreakpointList::SetEnabledAll (bool enabled) { Mutex::Locker locker(m_mutex); - bp_collection::iterator pos, end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - (*pos)->SetEnabled (enabled); + for (const auto &bp_sp : m_breakpoints) + bp_sp->SetEnabled (enabled); } @@ -163,10 +171,8 @@ BreakpointList::Dump (Stream *s) const s->Indent(); s->Printf("BreakpointList with %u Breakpoints:\n", (uint32_t)m_breakpoints.size()); s->IndentMore(); - bp_collection::const_iterator pos; - bp_collection::const_iterator end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - (*pos)->Dump(s); + for (const auto &bp_sp : m_breakpoints) + bp_sp->Dump(s); s->IndentLess(); } @@ -207,10 +213,8 @@ void BreakpointList::UpdateBreakpoints (ModuleList& module_list, bool added, bool delete_locations) { Mutex::Locker locker(m_mutex); - bp_collection::iterator end = m_breakpoints.end(); - bp_collection::iterator pos; - for (pos = m_breakpoints.begin(); pos != end; ++pos) - (*pos)->ModulesChanged (module_list, added, delete_locations); + for (const auto &bp_sp : m_breakpoints) + bp_sp->ModulesChanged (module_list, added, delete_locations); } @@ -218,10 +222,8 @@ void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp) { Mutex::Locker locker(m_mutex); - bp_collection::iterator end = m_breakpoints.end(); - bp_collection::iterator pos; - for (pos = m_breakpoints.begin(); pos != end; ++pos) - (*pos)->ModuleReplaced (old_module_sp, new_module_sp); + for (const auto &bp_sp : m_breakpoints) + bp_sp->ModuleReplaced (old_module_sp, new_module_sp); } @@ -229,10 +231,8 @@ void BreakpointList::ClearAllBreakpointSites () { Mutex::Locker locker(m_mutex); - bp_collection::iterator end = m_breakpoints.end(); - bp_collection::iterator pos; - for (pos = m_breakpoints.begin(); pos != end; ++pos) - (*pos)->ClearAllBreakpointSites (); + for (const auto &bp_sp : m_breakpoints) + bp_sp->ClearAllBreakpointSites (); } diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp index 17568c28b507..5009e862d84b 100644 --- a/source/Breakpoint/BreakpointLocation.cpp +++ b/source/Breakpoint/BreakpointLocation.cpp @@ -295,7 +295,7 @@ BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error) EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); - options.SetRunOthers(true); + options.SetTryAllThreads(true); Error expr_error; diff --git a/source/Breakpoint/BreakpointLocationList.cpp b/source/Breakpoint/BreakpointLocationList.cpp index 341b09716301..0c4c54d2f16c 100644 --- a/source/Breakpoint/BreakpointLocationList.cpp +++ b/source/Breakpoint/BreakpointLocationList.cpp @@ -13,8 +13,11 @@ // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointLocationList.h" + #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Target/Target.h" @@ -74,19 +77,25 @@ BreakpointLocationList::FindIDByAddress (const Address &addr) return LLDB_INVALID_BREAK_ID; } +static bool +Compare (BreakpointLocationSP lhs, lldb::break_id_t val) +{ + return lhs->GetID() < val; +} + BreakpointLocationSP BreakpointLocationList::FindByID (lldb::break_id_t break_id) const { BreakpointLocationSP bp_loc_sp; Mutex::Locker locker (m_mutex); - // We never remove a breakpoint locations, so the ID can be translated into - // the location index by subtracting 1 - uint32_t idx = break_id - 1; - if (idx <= m_locations.size()) - { - bp_loc_sp = m_locations[idx]; - } - return bp_loc_sp; + + collection::const_iterator begin = m_locations.begin(), end = m_locations.end(); + collection::const_iterator result; + result = std::lower_bound(begin, end, break_id, Compare); + if (result == end) + return bp_loc_sp; + else + return *(result); } size_t @@ -286,7 +295,41 @@ BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc return false; } - +void +BreakpointLocationList::RemoveInvalidLocations (const ArchSpec &arch) +{ + Mutex::Locker locker (m_mutex); + size_t idx = 0; + // Don't cache m_location.size() as it will change since we might + // remove locations from our vector... + while (idx < m_locations.size()) + { + BreakpointLocation *bp_loc = m_locations[idx].get(); + if (bp_loc->GetAddress().SectionWasDeleted()) + { + // Section was deleted which means this breakpoint comes from a module + // that is no longer valid, so we should remove it. + m_locations.erase(m_locations.begin() + idx); + continue; + } + if (arch.IsValid()) + { + ModuleSP module_sp (bp_loc->GetAddress().GetModule()); + if (module_sp) + { + if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) + { + // The breakpoint was in a module whose architecture is no longer + // compatible with "arch", so we need to remove it + m_locations.erase(m_locations.begin() + idx); + continue; + } + } + } + // Only increment the index if we didn't remove the locations at index "idx" + ++idx; + } +} void BreakpointLocationList::StartRecordingNewLocations (BreakpointLocationCollection &new_locations) diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp index 6d44f71b8d95..5ca44ff920d6 100644 --- a/source/Commands/CommandObjectExpression.cpp +++ b/source/Commands/CommandObjectExpression.cpp @@ -363,13 +363,13 @@ CommandObjectExpression::EvaluateExpression bool keep_in_memory = true; EvaluateExpressionOptions options; - options.SetCoerceToId(m_varobj_options.use_objc) - .SetUnwindOnError(m_command_options.unwind_on_error) - .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints) - .SetKeepInMemory(keep_in_memory) - .SetUseDynamic(m_varobj_options.use_dynamic) - .SetRunOthers(m_command_options.try_all_threads) - .SetDebug(m_command_options.debug); + options.SetCoerceToId(m_varobj_options.use_objc); + options.SetUnwindOnError(m_command_options.unwind_on_error); + options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints); + options.SetKeepInMemory(keep_in_memory); + options.SetUseDynamic(m_varobj_options.use_dynamic); + options.SetTryAllThreads(m_command_options.try_all_threads); + options.SetDebug(m_command_options.debug); if (m_command_options.timeout > 0) options.SetTimeoutUsec(m_command_options.timeout); diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp index 2ee275e11f66..cb7398fb9554 100644 --- a/source/Commands/CommandObjectMemory.cpp +++ b/source/Commands/CommandObjectMemory.cpp @@ -914,6 +914,311 @@ protected: ClangASTType m_prev_clang_ast_type; }; +OptionDefinition +g_memory_find_option_table[] = +{ + { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."}, + { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Use text to find a byte pattern."}, + { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many times to perform the search."}, + { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "dump-offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."}, +}; + +//---------------------------------------------------------------------- +// Find the specified data in memory +//---------------------------------------------------------------------- +class CommandObjectMemoryFind : public CommandObjectParsed +{ +public: + + class OptionGroupFindMemory : public OptionGroup + { + public: + OptionGroupFindMemory () : + OptionGroup(), + m_count(1), + m_offset(0) + { + } + + virtual + ~OptionGroupFindMemory () + { + } + + virtual uint32_t + GetNumDefinitions () + { + return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition); + } + + virtual const OptionDefinition* + GetDefinitions () + { + return g_memory_find_option_table; + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_arg) + { + Error error; + const int short_option = g_memory_find_option_table[option_idx].short_option; + + switch (short_option) + { + case 'e': + m_expr.SetValueFromCString(option_arg); + break; + + case 's': + m_string.SetValueFromCString(option_arg); + break; + + case 'c': + if (m_count.SetValueFromCString(option_arg).Fail()) + error.SetErrorString("unrecognized value for count"); + break; + + case 'o': + if (m_offset.SetValueFromCString(option_arg).Fail()) + error.SetErrorString("unrecognized value for dump-offset"); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + return error; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + m_expr.Clear(); + m_string.Clear(); + m_count.Clear(); + } + + OptionValueString m_expr; + OptionValueString m_string; + OptionValueUInt64 m_count; + OptionValueUInt64 m_offset; + }; + + CommandObjectMemoryFind (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "memory find", + "Find a value in the memory of the process being debugged.", + NULL, + eFlagRequiresProcess | eFlagProcessMustBeLaunched), + m_option_group (interpreter), + m_memory_options () + { + CommandArgumentEntry arg1; + CommandArgumentEntry arg2; + CommandArgumentData addr_arg; + CommandArgumentData value_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); + + // Define the first (and only) variant of this arg. + value_arg.arg_type = eArgTypeValue; + value_arg.arg_repetition = eArgRepeatPlus; + + // There is only one variant this argument could be; put it into the argument entry. + arg2.push_back (value_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg1); + m_arguments.push_back (arg2); + + m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectMemoryFind () + { + } + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid + Process *process = m_exe_ctx.GetProcessPtr(); + + const size_t argc = command.GetArgumentCount(); + + if (argc != 2) + { + result.AppendError("two addresses needed for memory find"); + return false; + } + + Error error; + lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error); + if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) + { + result.AppendError("invalid low address"); + return false; + } + lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error); + if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) + { + result.AppendError("invalid low address"); + return false; + } + + if (high_addr <= low_addr) + { + result.AppendError("starting address must be smaller than ending address"); + return false; + } + + lldb::addr_t found_location = LLDB_INVALID_ADDRESS; + + DataBufferHeap buffer; + + if (m_memory_options.m_string.OptionWasSet()) + buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue())); + else if (m_memory_options.m_expr.OptionWasSet()) + { + StackFrame* frame = m_exe_ctx.GetFramePtr(); + ValueObjectSP result_sp; + if (process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp) && result_sp.get()) + { + uint64_t value = result_sp->GetValueAsUnsigned(0); + switch (result_sp->GetClangType().GetByteSize()) + { + case 1: { + uint8_t byte = (uint8_t)value; + buffer.CopyData(&byte,1); + } + break; + case 2: { + uint16_t word = (uint16_t)value; + buffer.CopyData(&word,2); + } + break; + case 4: { + uint32_t lword = (uint32_t)value; + buffer.CopyData(&lword,4); + } + break; + case 8: { + buffer.CopyData(&value, 8); + } + break; + case 3: + case 5: + case 6: + case 7: + result.AppendError("unknown type. pass a string instead"); + return false; + default: + result.AppendError("do not know how to deal with larger than 8 byte result types. pass a string instead"); + return false; + } + } + else + { + result.AppendError("expression evaluation failed. pass a string instead?"); + return false; + } + } + else + { + result.AppendError("please pass either a block of text, or an expression to evaluate."); + return false; + } + + size_t count = m_memory_options.m_count.GetCurrentValue(); + found_location = low_addr; + bool ever_found = false; + while (count) + { + found_location = Search(found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize()); + if (found_location == LLDB_INVALID_ADDRESS) + { + if (!ever_found) + { + result.AppendMessage("Your data was not found within the range.\n"); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + } + else + result.AppendMessage("No more matches found within the range.\n"); + break; + } + result.AppendMessageWithFormat("Your data was found at location: 0x%" PRIx64 "\n", found_location); + + DataBufferHeap dumpbuffer(32,0); + process->ReadMemory(found_location+m_memory_options.m_offset.GetCurrentValue(), dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error); + if (!error.Fail()) + { + DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), process->GetByteOrder(), process->GetAddressByteSize()); + data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1, dumpbuffer.GetByteSize(), 16, found_location+m_memory_options.m_offset.GetCurrentValue(), 0, 0); + result.GetOutputStream().EOL(); + } + + --count; + found_location++; + ever_found = true; + } + + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + return true; + } + + lldb::addr_t + Search (lldb::addr_t low, + lldb::addr_t high, + uint8_t* buffer, + size_t buffer_size) + { + Process *process = m_exe_ctx.GetProcessPtr(); + DataBufferHeap heap(buffer_size, 0); + lldb::addr_t fictional_ptr = low; + for (auto ptr = low; + low < high; + fictional_ptr++) + { + Error error; + if (ptr == low || buffer_size == 1) + process->ReadMemory(ptr, heap.GetBytes(), buffer_size, error); + else + { + memmove(heap.GetBytes(), heap.GetBytes()+1, buffer_size-1); + process->ReadMemory(ptr, heap.GetBytes()+buffer_size-1, 1, error); + } + if (error.Fail()) + return LLDB_INVALID_ADDRESS; + if (memcmp(heap.GetBytes(), buffer, buffer_size) == 0) + return fictional_ptr; + if (ptr == low) + ptr += buffer_size; + else + ptr += 1; + } + return LLDB_INVALID_ADDRESS; + } + + OptionGroupOptions m_option_group; + OptionGroupFindMemory m_memory_options; +}; + OptionDefinition g_memory_write_option_table[] = @@ -922,7 +1227,6 @@ g_memory_write_option_table[] = { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."}, }; - //---------------------------------------------------------------------- // Write memory to the inferior process //---------------------------------------------------------------------- @@ -948,13 +1252,13 @@ public: { return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition); } - + virtual const OptionDefinition* GetDefinitions () { return g_memory_write_option_table; } - + virtual Error SetOptionValue (CommandInterpreter &interpreter, uint32_t option_idx, @@ -962,7 +1266,7 @@ public: { Error error; const int short_option = g_memory_write_option_table[option_idx].short_option; - + switch (short_option) { case 'i': @@ -973,7 +1277,7 @@ public: error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg); } break; - + case 'o': { bool success; @@ -1374,6 +1678,7 @@ CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) : "A set of commands for operating on memory.", "memory <subcommand> [<subcommand-options>]") { + LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter))); LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter))); LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); } diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp index ace1ef5b53fb..5e842bf848a3 100644 --- a/source/Commands/CommandObjectPlatform.cpp +++ b/source/Commands/CommandObjectPlatform.cpp @@ -22,6 +22,7 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupPlatform.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" @@ -119,31 +120,31 @@ public: m_permissions = perms; } case 'r': - m_permissions |= File::ePermissionsUserRead; + m_permissions |= lldb::eFilePermissionsUserRead; break; case 'w': - m_permissions |= File::ePermissionsUserWrite; + m_permissions |= lldb::eFilePermissionsUserWrite; break; case 'x': - m_permissions |= File::ePermissionsUserExecute; + m_permissions |= lldb::eFilePermissionsUserExecute; break; case 'R': - m_permissions |= File::ePermissionsGroupRead; + m_permissions |= lldb::eFilePermissionsGroupRead; break; case 'W': - m_permissions |= File::ePermissionsGroupWrite; + m_permissions |= lldb::eFilePermissionsGroupWrite; break; case 'X': - m_permissions |= File::ePermissionsGroupExecute; + m_permissions |= lldb::eFilePermissionsGroupExecute; break; case 'd': - m_permissions |= File::ePermissionsWorldRead; + m_permissions |= lldb::eFilePermissionsWorldRead; break; case 't': - m_permissions |= File::ePermissionsWorldWrite; + m_permissions |= lldb::eFilePermissionsWorldWrite; break; case 'e': - m_permissions |= File::ePermissionsWorldExecute; + m_permissions |= lldb::eFilePermissionsWorldExecute; break; default: @@ -524,6 +525,65 @@ protected: }; //---------------------------------------------------------------------- +// "platform settings" +//---------------------------------------------------------------------- +class CommandObjectPlatformSettings : public CommandObjectParsed +{ +public: + CommandObjectPlatformSettings (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "platform settings", + "Set settings for the current target's platform, or for a platform by name.", + "platform settings", + 0), + m_options (interpreter), + m_option_working_dir (LLDB_OPT_SET_1, false, "working-dir", 'w', 0, eArgTypePath, "The working directory for the platform.") + { + m_options.Append (&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + } + + virtual + ~CommandObjectPlatformSettings () + { + } + +protected: + virtual bool + DoExecute (Args& args, CommandReturnObject &result) + { + PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); + if (platform_sp) + { + if (m_option_working_dir.GetOptionValue().OptionWasSet()) + platform_sp->SetWorkingDirectory (ConstString(m_option_working_dir.GetOptionValue().GetCurrentValue().GetPath().c_str())); + } + else + { + result.AppendError ("no platform is currently selected"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } + + virtual Options * + GetOptions () + { + if (m_options.DidFinalize() == false) + { + m_options.Append(new OptionPermissions()); + m_options.Finalize(); + } + return &m_options; + } +protected: + + OptionGroupOptions m_options; + OptionGroupFile m_option_working_dir; + +}; + + +//---------------------------------------------------------------------- // "platform mkdir" //---------------------------------------------------------------------- class CommandObjectPlatformMkDir : public CommandObjectParsed @@ -552,15 +612,22 @@ public: { std::string cmd_line; args.GetCommandString(cmd_line); - mode_t perms; + uint32_t mode; const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r'); if (options_permissions) - perms = options_permissions->m_permissions; + mode = options_permissions->m_permissions; else - perms = 0000700 | 0000070 | 0000007; - uint32_t retcode = platform_sp->MakeDirectory(cmd_line,perms); - result.AppendMessageWithFormat("Status = %d\n",retcode); - result.SetStatus (eReturnStatusSuccessFinishResult); + mode = lldb::eFilePermissionsUserRWX | lldb::eFilePermissionsGroupRWX | lldb::eFilePermissionsWorldRX; + Error error = platform_sp->MakeDirectory(cmd_line.c_str(), mode); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendError(error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } } else { @@ -619,7 +686,7 @@ public: if (options_permissions) perms = options_permissions->m_permissions; else - perms = 0000700 | 0000070 | 0000007; + perms = lldb::eFilePermissionsUserRW | lldb::eFilePermissionsGroupRW | lldb::eFilePermissionsWorldRead; lldb::user_id_t fd = platform_sp->OpenFile(FileSpec(cmd_line.c_str(),false), File::eOpenOptionRead | File::eOpenOptionWrite | File::eOpenOptionAppend | File::eOpenOptionCanCreate, @@ -2129,82 +2196,6 @@ CommandObjectPlatformShell::CommandOptions::g_option_table[] = { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; -struct RecurseCopyBaton -{ - const std::string& destination; - const PlatformSP& platform_sp; - Error error; -}; - - -static FileSpec::EnumerateDirectoryResult -RecurseCopy_Callback (void *baton, - FileSpec::FileType file_type, - const FileSpec &spec) -{ - RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton; - switch (file_type) - { - case FileSpec::eFileTypePipe: - case FileSpec::eFileTypeSocket: - // we have no way to copy pipes and sockets - ignore them and continue - return FileSpec::eEnumerateDirectoryResultNext; - break; - - case FileSpec::eFileTypeSymbolicLink: - // what to do for symlinks? - return FileSpec::eEnumerateDirectoryResultNext; - break; - - case FileSpec::eFileTypeDirectory: - { - // make the new directory and get in there - FileSpec new_directory(rc_baton->destination.c_str(),false); - new_directory.AppendPathComponent(spec.GetLastPathComponent()); - uint32_t errcode = rc_baton->platform_sp->MakeDirectory(new_directory, 0777); - std::string new_directory_path (new_directory.GetPath()); - if (errcode != 0) - { - rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end",new_directory_path.c_str()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - - // now recurse - std::string local_path (spec.GetPath()); - RecurseCopyBaton rc_baton2 = { new_directory_path, rc_baton->platform_sp, Error() }; - FileSpec::EnumerateDirectory(local_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2); - if (rc_baton2.error.Fail()) - { - rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - return FileSpec::eEnumerateDirectoryResultNext; - } - break; - - case FileSpec::eFileTypeRegular: - { - // copy the file and keep going - std::string dest(rc_baton->destination); - dest.append(spec.GetFilename().GetCString()); - Error err = rc_baton->platform_sp->PutFile(spec, FileSpec(dest.c_str(), false)); - if (err.Fail()) - { - rc_baton->error.SetErrorString(err.AsCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - return FileSpec::eEnumerateDirectoryResultNext; - } - break; - - case FileSpec::eFileTypeInvalid: - case FileSpec::eFileTypeOther: - case FileSpec::eFileTypeUnknown: - rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s/%s", spec.GetDirectory().GetCString(), spec.GetFilename().GetCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - break; - } -} //---------------------------------------------------------------------- // "platform install" - install a target to a remote end @@ -2236,10 +2227,9 @@ public: return false; } // TODO: move the bulk of this code over to the platform itself - std::string local_thing(args.GetArgumentAtIndex(0)); - std::string remote_sandbox(args.GetArgumentAtIndex(1)); - FileSpec source(local_thing.c_str(), true); - if (source.Exists() == false) + FileSpec src(args.GetArgumentAtIndex(0), true); + FileSpec dst(args.GetArgumentAtIndex(1), false); + if (src.Exists() == false) { result.AppendError("source location does not exist or is not accessible"); result.SetStatus(eReturnStatusFailed); @@ -2252,75 +2242,21 @@ public: result.SetStatus (eReturnStatusFailed); return false; } - FileSpec::FileType source_type(source.GetFileType()); - if (source_type == FileSpec::eFileTypeDirectory) - { - if (platform_sp->GetSupportsRSync()) - { - FileSpec remote_folder(remote_sandbox.c_str(), false); - Error rsync_err = platform_sp->PutFile(source, remote_folder); - if (rsync_err.Success()) - { - result.SetStatus(eReturnStatusSuccessFinishResult); - return result.Succeeded(); - } - } - FileSpec remote_folder(remote_sandbox.c_str(), false); - remote_folder.AppendPathComponent(source.GetLastPathComponent()); - // TODO: default permissions are bad - uint32_t errcode = platform_sp->MakeDirectory(remote_folder, 0777); - if (errcode != 0) - { - result.AppendError("unable to setup target directory on remote end"); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - return result.Succeeded(); - } - // now recurse - std::string remote_folder_path (remote_folder.GetPath()); - Error err = RecurseCopy(source,remote_folder_path,platform_sp); - if (err.Fail()) - { - result.AppendError(err.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - else - result.SetStatus(eReturnStatusSuccessFinishResult); - return result.Succeeded(); - } - else if (source_type == FileSpec::eFileTypeRegular) + + Error error = platform_sp->Install(src, dst); + if (error.Success()) { - // just a plain file - push it to remote and be done - remote_sandbox.append(source.GetFilename().GetCString()); - FileSpec destination(remote_sandbox.c_str(),false); - Error err = platform_sp->PutFile(source, destination); - if (err.Success()) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - { - result.AppendError(err.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - return result.Succeeded(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { - result.AppendError("source is not a known type of file"); + result.AppendErrorWithFormat("install failed: %s", error.AsCString()); result.SetStatus(eReturnStatusFailed); - return result.Succeeded(); } + return result.Succeeded(); } private: - - Error - RecurseCopy (const FileSpec& source, - const std::string& destination, - const PlatformSP& platform_sp) - { - std::string source_path (source.GetPath()); - RecurseCopyBaton baton = { destination, platform_sp, Error() }; - FileSpec::EnumerateDirectory(source_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); - return baton.error; - } + }; //---------------------------------------------------------------------- @@ -2332,21 +2268,22 @@ CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) : "A set of commands to manage and create platforms.", "platform [connect|disconnect|info|list|status|select] ...") { - LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter))); - LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter))); - LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter))); - LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter))); - LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter))); + LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter))); + LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter))); + LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter))); + LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter))); + LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter))); + LoadSubCommand ("settings", CommandObjectSP (new CommandObjectPlatformSettings (interpreter))); #ifdef LLDB_CONFIGURATION_DEBUG - LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir (interpreter))); - LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile (interpreter))); - LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile (interpreter))); - LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize (interpreter))); - LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile (interpreter))); + LoadSubCommand ("mkdir", CommandObjectSP (new CommandObjectPlatformMkDir (interpreter))); + LoadSubCommand ("file", CommandObjectSP (new CommandObjectPlatformFile (interpreter))); + LoadSubCommand ("get-file", CommandObjectSP (new CommandObjectPlatformGetFile (interpreter))); + LoadSubCommand ("get-size", CommandObjectSP (new CommandObjectPlatformGetSize (interpreter))); + LoadSubCommand ("put-file", CommandObjectSP (new CommandObjectPlatformPutFile (interpreter))); #endif - LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter))); - LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter))); - LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter))); + LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter))); + LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter))); + LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter))); } diff --git a/source/Commands/CommandObjectPlugin.cpp b/source/Commands/CommandObjectPlugin.cpp index 1bc7632e2985..658c077bc3ea 100644 --- a/source/Commands/CommandObjectPlugin.cpp +++ b/source/Commands/CommandObjectPlugin.cpp @@ -11,10 +11,6 @@ #include "CommandObjectPlugin.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBCommandReturnObject.h" - #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -79,8 +75,6 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) { - typedef void (*LLDBCommandPluginInit) (lldb::SBDebugger debugger); - size_t argc = command.GetArgumentCount(); if (argc != 1) diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index 8bdec6e4573a..2933c78ca908 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -251,9 +251,11 @@ protected: // then you'll pick up that incorrect value. bool synchronous_execution = m_interpreter.GetSynchronous (); + PlatformSP platform_sp (target->GetPlatform()); + // Finalize the file actions, and if none were given, default to opening // up a pseudo terminal - const bool default_to_use_pty = true; + const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; m_options.launch_info.FinalizeFileActions (target, default_to_use_pty); if (state == eStateConnected) @@ -267,8 +269,6 @@ protected: if (!m_options.launch_info.GetArchitecture().IsValid()) m_options.launch_info.GetArchitecture() = target->GetArchitecture(); - - PlatformSP platform_sp (target->GetPlatform()); if (platform_sp && platform_sp->CanDebugProcess ()) { diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp index ef431e25c3d4..8e7e68aad39a 100644 --- a/source/Commands/CommandObjectTarget.cpp +++ b/source/Commands/CommandObjectTarget.cpp @@ -1796,10 +1796,8 @@ LookupTypeInModule (CommandInterpreter &interpreter, strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : ""); DumpFullpath (strm, &module->GetFileSpec(), 0); strm.PutCString(":\n"); - const uint32_t num_types = type_list.GetSize(); - for (uint32_t i=0; i<num_types; ++i) + for (TypeSP type_sp : type_list.Types()) { - TypeSP type_sp (type_list.GetTypeAtIndex(i)); if (type_sp) { // Resolve the clang type so that any forward references diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index f46a2219a509..10d661882c92 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -28,6 +28,7 @@ #include "lldb/Symbol/LineEntry.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" @@ -92,6 +93,13 @@ public: if (!success) error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option); } + case 'e': + { + bool success; + m_extended_backtrace = Args::StringToBoolean (option_arg, false, &success); + if (!success) + error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option); + } break; default: error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); @@ -106,6 +114,7 @@ public: { m_count = UINT32_MAX; m_start = 0; + m_extended_backtrace = false; } const OptionDefinition* @@ -121,6 +130,7 @@ public: // Instance variables to hold the values for command options. uint32_t m_count; uint32_t m_start; + bool m_extended_backtrace; }; CommandObjectThreadBacktrace (CommandInterpreter &interpreter) : @@ -160,6 +170,32 @@ public: } protected: + void + DoExtendedBacktrace (Thread *thread, CommandReturnObject &result) + { + SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime(); + if (runtime) + { + Stream &strm = result.GetOutputStream(); + const std::vector<ConstString> &types = runtime->GetExtendedBacktraceTypes(); + for (auto type : types) + { + ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread (thread->shared_from_this(), type); + if (ext_thread_sp && ext_thread_sp->IsValid ()) + { + const uint32_t num_frames_with_source = 0; + if (ext_thread_sp->GetStatus (strm, + m_options.m_start, + m_options.m_count, + num_frames_with_source)) + { + DoExtendedBacktrace (ext_thread_sp.get(), result); + } + } + } + } + } + virtual bool DoExecute (Args& command, CommandReturnObject &result) { @@ -178,29 +214,36 @@ protected: num_frames_with_source)) { result.SetStatus (eReturnStatusSuccessFinishResult); + if (m_options.m_extended_backtrace) + { + DoExtendedBacktrace (thread, result); + } } } else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) { Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - uint32_t num_threads = process->GetThreadList().GetSize(); - for (uint32_t i = 0; i < num_threads; i++) + uint32_t idx = 0; + for (ThreadSP thread_sp : process->Threads()) { - ThreadSP thread_sp = process->GetThreadList().GetThreadAtIndex(i); + if (idx != 0) + result.AppendMessage(""); + if (!thread_sp->GetStatus (strm, m_options.m_start, m_options.m_count, num_frames_with_source)) { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", i); + result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx); result.SetStatus (eReturnStatusFailed); return false; } + if (m_options.m_extended_backtrace) + { + DoExtendedBacktrace (thread_sp.get(), result); + } - if (i < num_threads - 1) - result.AppendMessage(""); - + ++idx; } } else @@ -244,6 +287,10 @@ protected: result.SetStatus (eReturnStatusFailed); return false; } + if (m_options.m_extended_backtrace) + { + DoExtendedBacktrace (thread_sps[i].get(), result); + } if (i < num_args - 1) result.AppendMessage(""); @@ -260,6 +307,7 @@ CommandObjectThreadBacktrace::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many frames to display (-1 for all)"}, { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace"}, +{ LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "Show the extended backtrace, if available"}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp index ae490e38149e..e55b2ee4d7d8 100644 --- a/source/Commands/CommandObjectWatchpoint.cpp +++ b/source/Commands/CommandObjectWatchpoint.cpp @@ -939,7 +939,7 @@ public: SetHelpLong( "Examples: \n\ \n\ - watchpoint set variable -w read_wriate my_global_var \n\ + watchpoint set variable -w read_write my_global_var \n\ # Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n"); CommandArgumentEntry arg; @@ -1256,11 +1256,11 @@ protected: // Use expression evaluation to arrive at the address to watch. EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(false) - .SetRunOthers(true) - .SetTimeoutUsec(0); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(false); + options.SetTryAllThreads(true); + options.SetTimeoutUsec(0); ExecutionResults expr_result = target->EvaluateExpression (expr, frame, diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp index 1e79f332ffc8..de2165cff84e 100644 --- a/source/Core/Address.cpp +++ b/source/Core/Address.cpp @@ -280,7 +280,7 @@ Address::GetFileAddress () const // address by adding the file base address to our offset return sect_file_addr + m_offset; } - else if (SectionWasDeleted()) + else if (SectionWasDeletedPrivate()) { // Used to have a valid section but it got deleted so the // offset doesn't mean anything without the section @@ -308,7 +308,7 @@ Address::GetLoadAddress (Target *target) const } } } - else if (SectionWasDeleted()) + else if (SectionWasDeletedPrivate()) { // Used to have a valid section but it got deleted so the // offset doesn't mean anything without the section @@ -783,6 +783,14 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum bool Address::SectionWasDeleted() const { + if (GetSection()) + return false; + return SectionWasDeletedPrivate(); +} + +bool +Address::SectionWasDeletedPrivate() const +{ lldb::SectionWP empty_section_wp; // If either call to "std::weak_ptr::owner_before(...) value returns true, this diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp index 8e80543b857b..5764a212ab43 100644 --- a/source/Core/ConnectionFileDescriptor.cpp +++ b/source/Core/ConnectionFileDescriptor.cpp @@ -53,6 +53,8 @@ #include "lldb/Core/Log.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/Timer.h" +#include "lldb/Host/Host.h" + using namespace lldb; using namespace lldb_private; @@ -1209,6 +1211,7 @@ ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *err saddr_un.sun_len = SUN_LEN (&saddr_un); #endif + Host::Unlink (socket_name); if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0) { if (::listen (listen_socket, 5) == 0) diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 3941d82d47b0..b57c6051a961 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -9,8 +9,6 @@ #include "lldb/lldb-python.h" -#include "lldb/API/SBDebugger.h" - #include "lldb/Core/Debugger.h" #include <map> @@ -46,6 +44,7 @@ #include "lldb/Target/TargetList.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -155,19 +154,7 @@ enum ePropertyAutoOneLineSummaries }; -// -//const char * -//Debugger::GetFrameFormat() const -//{ -// return m_properties_sp->GetFrameFormat(); -//} -//const char * -//Debugger::GetThreadFormat() const -//{ -// return m_properties_sp->GetThreadFormat(); -//} -// - +Debugger::LoadPluginCallbackType Debugger::g_load_plugin_callback = NULL; Error Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, @@ -373,8 +360,9 @@ Debugger::TestDebuggerRefCount () } void -Debugger::Initialize () +Debugger::Initialize (LoadPluginCallbackType load_plugin_callback) { + g_load_plugin_callback = load_plugin_callback; if (g_shared_debugger_refcount++ == 0) lldb_private::Initialize(); } @@ -412,31 +400,22 @@ Debugger::SettingsTerminate () bool Debugger::LoadPlugin (const FileSpec& spec, Error& error) { - lldb::DynamicLibrarySP dynlib_sp(new lldb_private::DynamicLibrary(spec)); - if (!dynlib_sp || dynlib_sp->IsValid() == false) + if (g_load_plugin_callback) { - if (spec.Exists()) - error.SetErrorString("this file does not represent a loadable dylib"); - else - error.SetErrorString("no such file"); - return false; - } - lldb::DebuggerSP debugger_sp(shared_from_this()); - lldb::SBDebugger debugger_sb(debugger_sp); - // This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) function. - // TODO: mangle this differently for your system - on OSX, the first underscore needs to be removed and the second one stays - LLDBCommandPluginInit init_func = dynlib_sp->GetSymbol<LLDBCommandPluginInit>("_ZN4lldb16PluginInitializeENS_10SBDebuggerE"); - if (!init_func) - { - error.SetErrorString("cannot find the initialization function lldb::PluginInitialize(lldb::SBDebugger)"); - return false; + lldb::DynamicLibrarySP dynlib_sp = g_load_plugin_callback (shared_from_this(), spec, error); + if (dynlib_sp) + { + m_loaded_plugins.push_back(dynlib_sp); + return true; + } } - if (init_func(debugger_sb)) + else { - m_loaded_plugins.push_back(dynlib_sp); - return true; + // The g_load_plugin_callback is registered in SBDebugger::Initialize() + // and if the public API layer isn't available (code is linking against + // all of the internal LLDB static libraries), then we can't load plugins + error.SetErrorString("Public API layer is not available"); } - error.SetErrorString("dylib refused to be loaded"); return false; } diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp index 189c3bc5531d..a41986de5143 100644 --- a/source/Core/Mangled.cpp +++ b/source/Core/Mangled.cpp @@ -10,7 +10,9 @@ // FreeBSD9-STABLE requires this to know about size_t in cxxabi.h #include <cstddef> -#if defined(_MSC_VER) || defined (__FreeBSD__) +#if defined(_MSC_VER) +// Cannot enable the builtin demangler on msvc as it does not support the cpp11 within the implementation. +#elif defined (__FreeBSD__) #define LLDB_USE_BUILTIN_DEMANGLER #else #include <cxxabi.h> @@ -4890,6 +4892,9 @@ Mangled::GetDemangledName () const // add it to our map. #ifdef LLDB_USE_BUILTIN_DEMANGLER char *demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL); +#elif defined(_MSC_VER) + // Cannot demangle on msvc. + char *demangled_name = nullptr; #else char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL); #endif diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp index 3f3be9360efa..f90a097416df 100644 --- a/source/Core/Module.cpp +++ b/source/Core/Module.cpp @@ -135,6 +135,7 @@ Module::Module (const ModuleSpec &module_spec) : m_uuid (), m_file (module_spec.GetFileSpec()), m_platform_file(module_spec.GetPlatformFileSpec()), + m_remote_install_file(), m_symfile_spec (module_spec.GetSymbolFileSpec()), m_object_name (module_spec.GetObjectName()), m_object_offset (module_spec.GetObjectOffset()), @@ -179,6 +180,7 @@ Module::Module(const FileSpec& file_spec, m_uuid (), m_file (file_spec), m_platform_file(), + m_remote_install_file (), m_symfile_spec (), m_object_name (), m_object_offset (object_offset), diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp index 9a4eb796dbea..2285ca954457 100644 --- a/source/Core/StreamFile.cpp +++ b/source/Core/StreamFile.cpp @@ -49,7 +49,7 @@ StreamFile::StreamFile (FILE *fh, bool transfer_ownership) : StreamFile::StreamFile (const char *path) : Stream (), - m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, File::ePermissionsDefault) + m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, lldb::eFilePermissionsFileDefault) { } diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp index 5767466f509d..a65b8f63e317 100644 --- a/source/Core/ValueObjectSyntheticFilter.cpp +++ b/source/Core/ValueObjectSyntheticFilter.cpp @@ -16,7 +16,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/ValueObject.h" -#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/TypeSynthetic.h" using namespace lldb_private; diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp index e00413556cc9..136c8c51e660 100644 --- a/source/DataFormatters/CXXFormatterFunctions.cpp +++ b/source/DataFormatters/CXXFormatterFunctions.cpp @@ -49,9 +49,9 @@ lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj, return false; EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(true); target->EvaluateExpression(expr.GetData(), stack_frame, @@ -83,10 +83,10 @@ lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj, return false; EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(true); + options.SetUseDynamic(lldb::eDynamicCanRunTarget); target->EvaluateExpression(expr.GetData(), stack_frame, @@ -121,10 +121,10 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, return valobj_sp; EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(true); + options.SetUseDynamic(lldb::eDynamicCanRunTarget); target->EvaluateExpression(expr.GetData(), stack_frame, @@ -158,10 +158,10 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, return valobj_sp; EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetKeepInMemory(true); + options.SetUseDynamic(lldb::eDynamicCanRunTarget); target->EvaluateExpression(expr.GetData(), stack_frame, diff --git a/source/DataFormatters/FormatClasses.cpp b/source/DataFormatters/FormatClasses.cpp index c67f86a7493d..f27b45b30491 100644 --- a/source/DataFormatters/FormatClasses.cpp +++ b/source/DataFormatters/FormatClasses.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" +#include "lldb/DataFormatters/FormatClasses.h" // C Includes @@ -16,17 +16,6 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" -#include "lldb/lldb-enumerations.h" - -#include "lldb/Core/Debugger.h" -#include "lldb/Core/StreamString.h" -#include "lldb/Core/Timer.h" -#include "lldb/DataFormatters/FormatClasses.h" -#include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/ClangASTType.h" -#include "lldb/Target/StackFrame.h" -#include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp index b4c4628b48a2..bec2edf5d5c2 100644 --- a/source/DataFormatters/FormatManager.cpp +++ b/source/DataFormatters/FormatManager.cpp @@ -163,6 +163,139 @@ FormatManager::GetFormatAsCString (Format format) return NULL; } +void +FormatManager::GetPossibleMatches (ValueObject& valobj, + ClangASTType clang_type, + uint32_t reason, + lldb::DynamicValueType use_dynamic, + FormattersMatchVector& entries, + bool did_strip_ptr, + bool did_strip_ref, + bool did_strip_typedef, + bool root_level) +{ + clang_type = clang_type.RemoveFastQualifiers(); + ConstString type_name(clang_type.GetConstTypeName()); + if (valobj.GetBitfieldBitSize() > 0) + { + StreamString sstring; + sstring.Printf("%s:%d",type_name.AsCString(),valobj.GetBitfieldBitSize()); + ConstString bitfieldname = ConstString(sstring.GetData()); + entries.push_back({bitfieldname,0,did_strip_ptr,did_strip_ref,did_strip_typedef}); + reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField; + } + entries.push_back({type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef}); + + if (clang_type.IsReferenceType()) + { + ClangASTType non_ref_type = clang_type.GetNonReferenceType(); + GetPossibleMatches(valobj, + non_ref_type, + reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference, + use_dynamic, + entries, + did_strip_ptr, + true, + did_strip_typedef); + } + else if (clang_type.IsPointerType()) + { + ClangASTType non_ptr_type = clang_type.GetPointeeType(); + GetPossibleMatches(valobj, + non_ptr_type, + reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference, + use_dynamic, + entries, + true, + did_strip_ref, + did_strip_typedef); + } + bool canBeObjCDynamic = clang_type.IsPossibleDynamicType (NULL, + false, // no C + true); // yes ObjC + + if (canBeObjCDynamic) + { + if (use_dynamic != lldb::eNoDynamicValues) + { + do + { + lldb::ProcessSP process_sp = valobj.GetProcessSP(); + ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime(); + if (runtime == nullptr) + break; + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj)); + if (!objc_class_sp) + break; + ConstString name (objc_class_sp->GetClassName()); + entries.push_back({name,reason | lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery,did_strip_ptr,did_strip_ref,did_strip_typedef}); + } while (false); + } + + ClangASTType non_ptr_type = clang_type.GetPointeeType(); + GetPossibleMatches(valobj, + non_ptr_type, + reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference, + use_dynamic, + entries, + true, + did_strip_ref, + did_strip_typedef); + } + + // try to strip typedef chains + if (clang_type.IsTypedefType()) + { + ClangASTType deffed_type = clang_type.GetTypedefedType(); + GetPossibleMatches(valobj, + deffed_type, + reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, + use_dynamic, + entries, + did_strip_ptr, + did_strip_ref, + true); + } + + if (root_level) + { + do { + if (!clang_type.IsValid()) + break; + + ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType(); + if (!unqual_clang_ast_type.IsValid()) + break; + if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType()) + GetPossibleMatches (valobj, + unqual_clang_ast_type, + reason, + use_dynamic, + entries, + did_strip_ptr, + did_strip_ref, + did_strip_typedef); + } while(false); + + + // if all else fails, go to static type + if (valobj.IsDynamic()) + { + lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue()); + if (static_value_sp) + GetPossibleMatches(*static_value_sp.get(), + static_value_sp->GetClangType(), + reason | lldb_private::eFormatterChoiceCriterionWentToStaticValue, + use_dynamic, + entries, + did_strip_ptr, + did_strip_ref, + did_strip_typedef, + true); + } + } +} + lldb::TypeFormatImplSP FormatManager::GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp) { diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp index cdc57f6bd937..21e104602a3f 100644 --- a/source/DataFormatters/LibCxx.cpp +++ b/source/DataFormatters/LibCxx.cpp @@ -35,10 +35,10 @@ m_options() { if (valobj_sp) Update(); - m_options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + m_options.SetCoerceToId(false); + m_options.SetUnwindOnError(true); + m_options.SetKeepInMemory(true); + m_options.SetUseDynamic(lldb::eDynamicCanRunTarget); } size_t diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp index e0f23cc35e3f..08e7d584003e 100644 --- a/source/DataFormatters/LibStdcpp.cpp +++ b/source/DataFormatters/LibStdcpp.cpp @@ -34,10 +34,10 @@ m_options() { if (valobj_sp) Update(); - m_options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + m_options.SetCoerceToId(false); + m_options.SetUnwindOnError(true); + m_options.SetKeepInMemory(true); + m_options.SetUseDynamic(lldb::eDynamicCanRunTarget); } size_t @@ -215,10 +215,10 @@ lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIte { if (valobj_sp) Update(); - m_options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetKeepInMemory(true) - .SetUseDynamic(lldb::eDynamicCanRunTarget); + m_options.SetCoerceToId(false); + m_options.SetUnwindOnError(true); + m_options.SetKeepInMemory(true); + m_options.SetUseDynamic(lldb::eDynamicCanRunTarget); } bool diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp index 05a5dda39e53..f53004df5c5f 100644 --- a/source/DataFormatters/NSDictionary.cpp +++ b/source/DataFormatters/NSDictionary.cpp @@ -218,8 +218,10 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn StreamString object_fetcher_expr; object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData()); lldb::ValueObjectSP child_sp; + EvaluateExpressionOptions options; + options.SetKeepInMemory(true); m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp, - EvaluateExpressionOptions().SetKeepInMemory(true)); + options); if (child_sp) child_sp->SetName(ConstString(idx_name.GetData())); return child_sp; diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp index 02eb2bfc124f..e6fe2a34a67b 100644 --- a/source/DataFormatters/NSSet.cpp +++ b/source/DataFormatters/NSSet.cpp @@ -249,6 +249,10 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx) if (idx >= num_children) return lldb::ValueObjectSP(); + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + if (m_children.empty()) { // do the scan phase @@ -260,7 +264,6 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx) while(tries < num_children) { obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); - ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); if (!process_sp) return lldb::ValueObjectSP(); Error error; @@ -286,12 +289,34 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx) SetItemDescriptor &set_item = m_children[idx]; if (!set_item.valobj_sp) { - // make the new ValueObject - StreamString expr; - expr.Printf("(id)%" PRIu64,set_item.item_ptr); + auto ptr_size = process_sp->GetAddressByteSize(); + DataBufferHeap buffer(ptr_size,0); + switch (ptr_size) + { + case 0: // architecture has no clue?? - fail + return lldb::ValueObjectSP(); + case 4: + *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; + break; + case 8: + *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; + break; + default: + assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); + } StreamString idx_name; idx_name.Printf("[%zu]",idx); - set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); + + DataExtractor data(buffer.GetBytes(), + buffer.GetByteSize(), + process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + + set_item.valobj_sp = + ValueObject::CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); } return set_item.valobj_sp; } @@ -392,6 +417,10 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) if (idx >= num_children) return lldb::ValueObjectSP(); + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + if (m_children.empty()) { // do the scan phase @@ -403,7 +432,6 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) while(tries < num_children) { obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); - ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); if (!process_sp) return lldb::ValueObjectSP(); Error error; @@ -429,12 +457,34 @@ lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) SetItemDescriptor &set_item = m_children[idx]; if (!set_item.valobj_sp) { - // make the new ValueObject - StreamString expr; - expr.Printf("(id)%" PRIu64,set_item.item_ptr); + auto ptr_size = process_sp->GetAddressByteSize(); + DataBufferHeap buffer(ptr_size,0); + switch (ptr_size) + { + case 0: // architecture has no clue?? - fail + return lldb::ValueObjectSP(); + case 4: + *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; + break; + case 8: + *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; + break; + default: + assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); + } StreamString idx_name; idx_name.Printf("[%zu]",idx); - set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); + + DataExtractor data(buffer.GetBytes(), + buffer.GetByteSize(), + process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + + set_item.valobj_sp = + ValueObject::CreateValueObjectFromData(idx_name.GetData(), + data, + m_exe_ctx_ref, + m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); } return set_item.valobj_sp; } diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp index 636000bb23ea..a02560e78780 100644 --- a/source/DataFormatters/TypeCategory.cpp +++ b/source/DataFormatters/TypeCategory.cpp @@ -39,15 +39,15 @@ m_name(name) bool TypeCategoryImpl::Get (ValueObject& valobj, + const FormattersMatchVector& candidates, lldb::TypeFormatImplSP& entry, - lldb::DynamicValueType use_dynamic, uint32_t* reason) { if (!IsEnabled()) return false; - if (GetValueNavigator()->Get(valobj, entry, use_dynamic, reason)) + if (GetValueNavigator()->Get(candidates, entry, reason)) return true; - bool regex = GetRegexValueNavigator()->Get(valobj, entry, use_dynamic, reason); + bool regex = GetRegexValueNavigator()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; @@ -55,25 +55,25 @@ TypeCategoryImpl::Get (ValueObject& valobj, bool TypeCategoryImpl::Get (ValueObject& valobj, + const FormattersMatchVector& candidates, lldb::TypeSummaryImplSP& entry, - lldb::DynamicValueType use_dynamic, uint32_t* reason) { if (!IsEnabled()) return false; - if (GetSummaryNavigator()->Get(valobj, entry, use_dynamic, reason)) + if (GetSummaryNavigator()->Get(candidates, entry, reason)) return true; - bool regex = GetRegexSummaryNavigator()->Get(valobj, entry, use_dynamic, reason); + bool regex = GetRegexSummaryNavigator()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; } bool -TypeCategoryImpl::Get(ValueObject& valobj, - lldb::SyntheticChildrenSP& entry_sp, - lldb::DynamicValueType use_dynamic, - uint32_t* reason) +TypeCategoryImpl::Get (ValueObject& valobj, + const FormattersMatchVector& candidates, + lldb::SyntheticChildrenSP& entry, + uint32_t* reason) { if (!IsEnabled()) return false; @@ -82,16 +82,16 @@ TypeCategoryImpl::Get(ValueObject& valobj, bool regex_filter = false; // first find both Filter and Synth, and then check which is most recent - if (!GetFilterNavigator()->Get(valobj, filter_sp, use_dynamic, &reason_filter)) - regex_filter = GetRegexFilterNavigator()->Get (valobj, filter_sp, use_dynamic, &reason_filter); + if (!GetFilterNavigator()->Get(candidates, filter_sp, &reason_filter)) + regex_filter = GetRegexFilterNavigator()->Get (candidates, filter_sp, &reason_filter); #ifndef LLDB_DISABLE_PYTHON bool regex_synth = false; uint32_t reason_synth = 0; bool pick_synth = false; ScriptedSyntheticChildren::SharedPointer synth; - if (!GetSyntheticNavigator()->Get(valobj, synth, use_dynamic, &reason_synth)) - regex_synth = GetRegexSyntheticNavigator()->Get (valobj, synth, use_dynamic, &reason_synth); + if (!GetSyntheticNavigator()->Get(candidates, synth, &reason_synth)) + regex_synth = GetRegexSyntheticNavigator()->Get (candidates, synth, &reason_synth); if (!filter_sp.get() && !synth.get()) return false; else if (!filter_sp.get() && synth.get()) @@ -111,27 +111,26 @@ TypeCategoryImpl::Get(ValueObject& valobj, { if (regex_synth && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter; - entry_sp = synth; + entry = synth; return true; } else { if (regex_filter && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter; - entry_sp = filter_sp; + entry = filter_sp; return true; } #else if (filter_sp) { - entry_sp = filter_sp; + entry = filter_sp; return true; } #endif return false; - } void diff --git a/source/DataFormatters/TypeCategoryMap.cpp b/source/DataFormatters/TypeCategoryMap.cpp index 621258806def..c6dba1b9f4bd 100644 --- a/source/DataFormatters/TypeCategoryMap.cpp +++ b/source/DataFormatters/TypeCategoryMap.cpp @@ -11,6 +11,9 @@ #include "lldb/DataFormatters/TypeCategoryMap.h" +#include "lldb/DataFormatters/FormatClasses.h" +#include "lldb/DataFormatters/FormatManager.h" + // C Includes // C++ Includes // Other libraries and framework includes @@ -187,13 +190,15 @@ TypeCategoryMap::GetFormat (ValueObject& valobj, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic); + for (begin = m_active_categories.begin(); begin != end; begin++) { lldb::TypeCategoryImplSP category_sp = *begin; lldb::TypeFormatImplSP current_format; if (log) log->Printf("\n[TypeCategoryMap::GetFormat] Trying to use category %s", category_sp->GetName()); - if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why)) + if (!category_sp->Get(valobj, matches, current_format, &reason_why)) continue; return current_format; } @@ -213,13 +218,15 @@ TypeCategoryMap::GetSummaryFormat (ValueObject& valobj, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic); + for (begin = m_active_categories.begin(); begin != end; begin++) { lldb::TypeCategoryImplSP category_sp = *begin; lldb::TypeSummaryImplSP current_format; if (log) log->Printf("\n[CategoryMap::GetSummaryFormat] Trying to use category %s", category_sp->GetName()); - if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why)) + if (!category_sp->Get(valobj, matches, current_format, &reason_why)) continue; return current_format; } @@ -241,13 +248,15 @@ TypeCategoryMap::GetSyntheticChildren (ValueObject& valobj, Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + FormattersMatchVector matches = FormatManager::GetPossibleMatches(valobj, use_dynamic); + for (begin = m_active_categories.begin(); begin != end; begin++) { lldb::TypeCategoryImplSP category_sp = *begin; lldb::SyntheticChildrenSP current_format; if (log) log->Printf("\n[CategoryMap::GetSyntheticChildren] Trying to use category %s", category_sp->GetName()); - if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why)) + if (!category_sp->Get(valobj, matches, current_format, &reason_why)) continue; return current_format; } diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp index b37044df9ecc..e707c60ffced 100644 --- a/source/Expression/ClangFunction.cpp +++ b/source/Expression/ClangFunction.cpp @@ -394,14 +394,9 @@ ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_add ThreadPlan * ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, - lldb::addr_t func_addr, - lldb::addr_t &args_addr, - Stream &errors, - bool stop_others, - bool unwind_on_error, - bool ignore_breakpoints, - lldb::addr_t *this_arg, - lldb::addr_t *cmd_arg) + lldb::addr_t args_addr, + const EvaluateExpressionOptions &options, + Stream &errors) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); @@ -418,16 +413,15 @@ ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx, // Okay, now run the function: - Address wrapper_address (func_addr); + Address wrapper_address (m_jit_start_addr); + + lldb::addr_t args = { args_addr }; + ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread, wrapper_address, ClangASTType(), - args_addr, - stop_others, - unwind_on_error, - ignore_breakpoints, - this_arg, - cmd_arg); + args, + options); new_plan->SetIsMasterPlan(true); new_plan->SetOkayToDiscard (false); return new_plan; @@ -479,63 +473,48 @@ ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_ } ExecutionResults -ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value &results) -{ - return ExecuteFunction (exe_ctx, errors, 1000, true, results); -} - -ExecutionResults -ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results) -{ - const bool try_all_threads = false; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads, - unwind_on_error, ignore_breakpoints, results); -} - -ExecutionResults ClangFunction::ExecuteFunction( ExecutionContext &exe_ctx, + lldb::addr_t *args_addr_ptr, + const EvaluateExpressionOptions &options, Stream &errors, - uint32_t timeout_usec, - bool try_all_threads, Value &results) { - const bool stop_others = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec, - try_all_threads, unwind_on_error, ignore_breakpoints, results); -} + using namespace clang; + ExecutionResults return_value = eExecutionSetupError; + + // ClangFunction::ExecuteFunction execution is always just to get the result. Do make sure we ignore + // breakpoints, unwind on error, and don't try to debug it. + EvaluateExpressionOptions real_options = options; + real_options.SetDebug(false); + real_options.SetUnwindOnError(true); + real_options.SetIgnoreBreakpoints(true); + + lldb::addr_t args_addr; + + if (args_addr_ptr != NULL) + args_addr = *args_addr_ptr; + else + args_addr = LLDB_INVALID_ADDRESS; + + if (CompileFunction(errors) != 0) + return eExecutionSetupError; + + if (args_addr == LLDB_INVALID_ADDRESS) + { + if (!InsertFunction(exe_ctx, args_addr, errors)) + return eExecutionSetupError; + } -// This is the static function -ExecutionResults -ClangFunction::ExecuteFunction ( - ExecutionContext &exe_ctx, - lldb::addr_t function_address, - lldb::addr_t &void_arg, - bool stop_others, - bool try_all_threads, - bool unwind_on_error, - bool ignore_breakpoints, - uint32_t timeout_usec, - Stream &errors, - lldb::addr_t *this_arg) -{ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); if (log) log->Printf("== [ClangFunction::ExecuteFunction] Executing function =="); - lldb::ThreadPlanSP call_plan_sp (ClangFunction::GetThreadPlanToCallFunction (exe_ctx, - function_address, - void_arg, - errors, - stop_others, - unwind_on_error, - ignore_breakpoints, - this_arg)); + lldb::ThreadPlanSP call_plan_sp (GetThreadPlanToCallFunction (exe_ctx, + args_addr, + real_options, + errors)); if (!call_plan_sp) return eExecutionSetupError; @@ -544,17 +523,14 @@ ClangFunction::ExecuteFunction ( if (exe_ctx.GetProcessPtr()) exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); - ExecutionResults results = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, call_plan_sp, - stop_others, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, - errors); + return_value = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, + call_plan_sp, + real_options, + errors); if (log) { - if (results != eExecutionCompleted) + if (return_value != eExecutionCompleted) { log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally =="); } @@ -567,50 +543,6 @@ ClangFunction::ExecuteFunction ( if (exe_ctx.GetProcessPtr()) exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); - return results; -} - -ExecutionResults -ClangFunction::ExecuteFunction( - ExecutionContext &exe_ctx, - lldb::addr_t *args_addr_ptr, - Stream &errors, - bool stop_others, - uint32_t timeout_usec, - bool try_all_threads, - bool unwind_on_error, - bool ignore_breakpoints, - Value &results) -{ - using namespace clang; - ExecutionResults return_value = eExecutionSetupError; - - lldb::addr_t args_addr; - - if (args_addr_ptr != NULL) - args_addr = *args_addr_ptr; - else - args_addr = LLDB_INVALID_ADDRESS; - - if (CompileFunction(errors) != 0) - return eExecutionSetupError; - - if (args_addr == LLDB_INVALID_ADDRESS) - { - if (!InsertFunction(exe_ctx, args_addr, errors)) - return eExecutionSetupError; - } - - return_value = ClangFunction::ExecuteFunction (exe_ctx, - m_jit_start_addr, - args_addr, - stop_others, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, - errors); - if (args_addr_ptr != NULL) *args_addr_ptr = args_addr; diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp index e4f2830ba259..d9ecd41be97a 100644 --- a/source/Expression/ClangUserExpression.cpp +++ b/source/Expression/ClangUserExpression.cpp @@ -716,35 +716,6 @@ ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream, return true; } -ThreadPlan * -ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx) -{ - lldb::addr_t struct_address; - - lldb::addr_t object_ptr = 0; - lldb::addr_t cmd_ptr = 0; - - PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr); - - // FIXME: This should really return a ThreadPlanCallUserExpression, in order to make sure that we don't release the - // ClangUserExpression resources before the thread plan finishes execution in the target. But because we are - // forcing unwind_on_error to be true here, in practical terms that can't happen. - - const bool stop_others = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = false; - return ClangFunction::GetThreadPlanToCallFunction (exe_ctx, - m_jit_start_addr, - struct_address, - error_stream, - stop_others, - unwind_on_error, - ignore_breakpoints, - (m_needs_object_ptr ? &object_ptr : NULL), - (m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL); -} - bool ClangUserExpression::FinalizeJITExecution (Stream &error_stream, ExecutionContext &exe_ctx, @@ -852,27 +823,22 @@ ClangUserExpression::Execute (Stream &error_stream, } else { - const uint32_t timeout_usec = options.GetTimeoutUsec(); - const bool debug = options.GetDebug(); - const bool unwind_on_error = debug ? false : options.DoesUnwindOnError(); - const bool ignore_breakpoints = debug ? false : options.DoesIgnoreBreakpoints(); - const bool stop_others = true; - const bool try_all_threads = options.GetRunOthers(); - lldb::BreakpointSP debug_bkpt_sp; - if (debug) - { - // TODO: push this down into the thread plan and let the plan manage it - debug_bkpt_sp = exe_ctx.GetTargetRef().CreateBreakpoint(m_jit_start_addr, false, false); - } Address wrapper_address (m_jit_start_addr); + + llvm::SmallVector <lldb::addr_t, 3> args; + + if (m_needs_object_ptr) { + args.push_back(object_ptr); + if (m_objectivec) + args.push_back(cmd_ptr); + } + + args.push_back(struct_address); + lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(), wrapper_address, - struct_address, - stop_others, - unwind_on_error, - ignore_breakpoints, - (m_needs_object_ptr ? &object_ptr : NULL), - ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL), + args, + options, shared_ptr_to_me)); if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream)) @@ -890,19 +856,10 @@ ClangUserExpression::Execute (Stream &error_stream, exe_ctx.GetProcessPtr()->SetRunningUserExpression(true); ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, - call_plan_sp, - stop_others, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, + call_plan_sp, + options, error_stream); - if (debug_bkpt_sp) - { - exe_ctx.GetTargetRef().RemoveBreakpointByID(debug_bkpt_sp->GetID()); - } - if (exe_ctx.GetProcessPtr()) exe_ctx.GetProcessPtr()->SetRunningUserExpression(false); @@ -922,16 +879,22 @@ ClangUserExpression::Execute (Stream &error_stream, if (error_desc) error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc); else - error_stream.Printf ("Execution was interrupted."); + error_stream.PutCString ("Execution was interrupted."); - if ((execution_result == eExecutionInterrupted && unwind_on_error) - || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints)) - error_stream.Printf ("\nThe process has been returned to the state before expression evaluation."); + if ((execution_result == eExecutionInterrupted && options.DoesUnwindOnError()) + || (execution_result == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints())) + error_stream.PutCString ("\nThe process has been returned to the state before expression evaluation."); else - error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation."); + error_stream.PutCString ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation."); return execution_result; } + else if (execution_result == eExecutionStoppedForDebug) + { + error_stream.PutCString ("Execution was halted at the first instruction of the expression function because \"debug\" was requested.\n" + "Use \"thread return -x\" to return to the state before expression evaluation."); + return execution_result; + } else if (execution_result != eExecutionCompleted) { error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result)); diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp index fb9522f0dc36..8731fbebd148 100644 --- a/source/Expression/Materializer.cpp +++ b/source/Expression/Materializer.cpp @@ -492,7 +492,10 @@ public: } else { - err.SetErrorStringWithFormat("size of variable %s disagrees with the ValueObject's size", m_variable_sp->GetName().AsCString()); + err.SetErrorStringWithFormat("size of variable %s (%" PRIu64 ") disagrees with the ValueObject's size (%" PRIu64 ")", + m_variable_sp->GetName().AsCString(), + m_variable_sp->GetType()->GetByteSize(), + data.GetByteSize()); } return; } diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index addd43515405..bbd11858aaba 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -1,4 +1,4 @@ -//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===// +//===-- File.cpp ------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "lldb/Host/File.h" #include <errno.h> @@ -237,6 +236,11 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) else if (read) { oflag |= O_RDONLY; + +#ifndef _WIN32 + if (options & eOpenoptionDontFollowSymlinks) + oflag |= O_NOFOLLOW; +#endif } #ifndef _WIN32 @@ -249,15 +253,15 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) mode_t mode = 0; if (oflag & O_CREAT) { - if (permissions & ePermissionsUserRead) mode |= S_IRUSR; - if (permissions & ePermissionsUserWrite) mode |= S_IWUSR; - if (permissions & ePermissionsUserExecute) mode |= S_IXUSR; - if (permissions & ePermissionsGroupRead) mode |= S_IRGRP; - if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP; - if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP; - if (permissions & ePermissionsWorldRead) mode |= S_IROTH; - if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH; - if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH; + if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR; + if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR; + if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR; + if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP; + if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP; + if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP; + if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH; + if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH; + if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH; } do @@ -284,7 +288,7 @@ File::GetPermissions (const char *path, Error &error) else { error.Clear(); - return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits + return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } } else @@ -309,7 +313,7 @@ File::GetPermissions(Error &error) const else { error.Clear(); - return file_stats.st_mode; // All bits from lldb_private::File::Permissions match those in POSIX mode bits + return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } } else diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp index 33de198072dc..48f1ac78d927 100644 --- a/source/Host/common/FileSpec.cpp +++ b/source/Host/common/FileSpec.cpp @@ -34,6 +34,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataBufferMemoryMap.h" #include "lldb/Core/RegularExpression.h" @@ -646,6 +647,15 @@ FileSpec::GetFileType () const return eFileTypeInvalid; } +uint32_t +FileSpec::GetPermissions () const +{ + uint32_t file_permissions = 0; + if (*this) + Host::GetFilePermissions(GetPath().c_str(), file_permissions); + return file_permissions; +} + TimeValue FileSpec::GetModificationTime () const { @@ -1161,26 +1171,26 @@ FileSpec::CopyByRemovingLastPathComponent () const return FileSpec(m_directory.GetCString(),resolve); } -const char* +ConstString FileSpec::GetLastPathComponent () const { - if (m_filename.IsEmpty() && m_directory.IsEmpty()) - return NULL; - if (m_filename.IsEmpty()) + if (m_filename) + return m_filename; + if (m_directory) { const char* dir_cstr = m_directory.GetCString(); const char* last_slash_ptr = ::strrchr(dir_cstr, '/'); if (last_slash_ptr == NULL) - return m_directory.GetCString(); + return m_directory; if (last_slash_ptr == dir_cstr) { if (last_slash_ptr[1] == 0) - return last_slash_ptr; + return ConstString(last_slash_ptr); else - return last_slash_ptr+1; + return ConstString(last_slash_ptr+1); } if (last_slash_ptr[1] != 0) - return last_slash_ptr+1; + return ConstString(last_slash_ptr+1); const char* penultimate_slash_ptr = last_slash_ptr; while (*penultimate_slash_ptr) { @@ -1190,10 +1200,10 @@ FileSpec::GetLastPathComponent () const if (*penultimate_slash_ptr == '/') break; } - ConstString new_path(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); - return new_path.AsCString(); + ConstString result(penultimate_slash_ptr+1,last_slash_ptr-penultimate_slash_ptr); + return result; } - return m_filename.GetCString(); + return ConstString(); } void diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index 296e4b40bf01..262776f6c719 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -22,6 +22,7 @@ #include <grp.h> #include <netdb.h> #include <pwd.h> +#include <sys/stat.h> #endif #if !defined (__GNU__) && !defined (_WIN32) @@ -33,6 +34,7 @@ #include <mach/mach_port.h> #include <mach/mach_init.h> #include <mach-o/dyld.h> +#include <AvailabilityMacros.h> #endif #if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) @@ -978,6 +980,7 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) // on linux this is assumed to be the "lldb" main executable. If LLDB on // linux is actually in a shared library (liblldb.so) then this function will // need to be modified to "do the right thing". + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST); switch (path_type) { @@ -988,6 +991,8 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) { FileSpec lldb_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)Host::GetLLDBPath)); g_lldb_so_dir = lldb_file_spec.GetDirectory(); + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_lldb_so_dir.GetCString()); } file_spec.GetDirectory() = g_lldb_so_dir; return (bool)file_spec.GetDirectory(); @@ -1011,7 +1016,11 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) if (framework_pos) { framework_pos += strlen("LLDB.framework"); -#if !defined (__arm__) +#if defined (__arm__) + // Shallow bundle + *framework_pos = '\0'; +#else + // Normal bundle ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path)); #endif } @@ -1019,6 +1028,8 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); g_lldb_support_exe_dir.SetCString(resolved_path); } + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_lldb_support_exe_dir.GetCString()); } file_spec.GetDirectory() = g_lldb_support_exe_dir; return (bool)file_spec.GetDirectory(); @@ -1051,6 +1062,8 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) // TODO: Anyone know how we can determine this for linux? Other systems?? g_lldb_headers_dir.SetCString ("/opt/local/include/lldb"); #endif + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_lldb_headers_dir.GetCString()); } file_spec.GetDirectory() = g_lldb_headers_dir; return (bool)file_spec.GetDirectory(); @@ -1096,6 +1109,10 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); g_lldb_python_dir.SetCString(resolved_path); } + + if (log) + log->Printf("Host::GetLLDBPath(ePathTypePythonDir) => '%s'", g_lldb_python_dir.GetCString()); + } file_spec.GetDirectory() = g_lldb_python_dir; return (bool)file_spec.GetDirectory(); @@ -1136,6 +1153,10 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str()); } #endif // __APPLE__ || __linux__ + + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_lldb_system_plugin_dir.GetCString()); + } if (g_lldb_system_plugin_dir) @@ -1194,6 +1215,8 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) if (lldb_file_spec.Exists()) g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str()); + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_lldb_user_plugin_dir.GetCString()); } file_spec.GetDirectory() = g_lldb_user_plugin_dir; return (bool)file_spec.GetDirectory(); @@ -1546,7 +1569,7 @@ Host::RunShellCommand (const char *command, return error; } -#if defined(__linux__) or defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) // The functions below implement process launching via posix_spawn() for Linux // and FreeBSD. @@ -1826,11 +1849,168 @@ Host::LaunchApplication (const FileSpec &app_file_spec) return LLDB_INVALID_PROCESS_ID; } -uint32_t -Host::MakeDirectory (const char* path, mode_t mode) +#endif + + +#ifdef LLDB_DISABLE_POSIX + +Error +Host::MakeDirectory (const char* path, uint32_t mode) +{ + Error error; + error.SetErrorStringWithFormat("%s in not implemented on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::GetFilePermissions (const char* path, uint32_t &file_permissions) { - return UINT32_MAX; + Error error; + error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; } + +Error +Host::SetFilePermissions (const char* path, uint32_t file_permissions) +{ + Error error; + error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Symlink (const char *src, const char *dst) +{ + Error error; + error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Readlink (const char *path, char *buf, size_t buf_len) +{ + Error error; + error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +Error +Host::Unlink (const char *path) +{ + Error error; + error.SetErrorStringWithFormat("%s is not supported on this host", __PRETTY_FUNCTION__); + return error; +} + +#else + +Error +Host::MakeDirectory (const char* path, uint32_t file_permissions) +{ + Error error; + if (path && path[0]) + { + if (::mkdir(path, file_permissions) != 0) + { + error.SetErrorToErrno(); + switch (error.GetError()) + { + case ENOENT: + { + // Parent directory doesn't exist, so lets make it if we can + FileSpec spec(path, false); + if (spec.GetDirectory() && spec.GetFilename()) + { + // Make the parent directory and try again + Error error2 = Host::MakeDirectory(spec.GetDirectory().GetCString(), file_permissions); + if (error2.Success()) + { + // Try and make the directory again now that the parent directory was made successfully + if (::mkdir(path, file_permissions) == 0) + error.Clear(); + else + error.SetErrorToErrno(); + } + } + } + break; + case EEXIST: + { + FileSpec path_spec(path, false); + if (path_spec.IsDirectory()) + error.Clear(); // It is a directory and it already exists + } + break; + } + } + } + else + { + error.SetErrorString("empty path"); + } + return error; +} + +Error +Host::GetFilePermissions (const char* path, uint32_t &file_permissions) +{ + Error error; + struct stat file_stats; + if (::stat (path, &file_stats) == 0) + { + // The bits in "st_mode" currently match the definitions + // for the file mode bits in unix. + file_permissions = file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + } + else + { + error.SetErrorToErrno(); + } + return error; +} + +Error +Host::SetFilePermissions (const char* path, uint32_t file_permissions) +{ + Error error; + if (::chmod(path, file_permissions) != 0) + error.SetErrorToErrno(); + return error; +} + +Error +Host::Symlink (const char *src, const char *dst) +{ + Error error; + if (::symlink(dst, src) == -1) + error.SetErrorToErrno(); + return error; +} + +Error +Host::Unlink (const char *path) +{ + Error error; + if (::unlink(path) == -1) + error.SetErrorToErrno(); + return error; +} + +Error +Host::Readlink (const char *path, char *buf, size_t buf_len) +{ + Error error; + ssize_t count = ::readlink(path, buf, buf_len); + if (count < 0) + error.SetErrorToErrno(); + else if (count < (buf_len-1)) + buf[count] = '\0'; // Success + else + error.SetErrorString("'buf' buffer is too small to contain link contents"); + return error; +} + + #endif typedef std::map<lldb::user_id_t, lldb::FileSP> FDToFileMap; @@ -1843,7 +2023,7 @@ FDToFileMap& GetFDToFileMap() lldb::user_id_t Host::OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { std::string path (file_spec.GetPath()); diff --git a/source/Host/common/OptionParser.cpp b/source/Host/common/OptionParser.cpp index 287292ee74af..ead044f53cf1 100644 --- a/source/Host/common/OptionParser.cpp +++ b/source/Host/common/OptionParser.cpp @@ -38,24 +38,70 @@ OptionParser::EnableError(bool error) } int -OptionParser::Parse(int argc, char * const argv [], - const char *optstring, - const Option *longopts, int *longindex) +OptionParser::Parse (int argc, + char * const argv [], + const char *optstring, + const Option *longopts, + int *longindex) { return getopt_long_only(argc, argv, optstring, (const option*)longopts, longindex); } -char* OptionParser::GetOptionArgument() +char* +OptionParser::GetOptionArgument() { return optarg; } -int OptionParser::GetOptionIndex() +int +OptionParser::GetOptionIndex() { return optind; } -int OptionParser::GetOptionErrorCause() +int +OptionParser::GetOptionErrorCause() { return optopt; } + +std::string +OptionParser::GetShortOptionString(struct option *long_options) +{ + std::string s; + int i=0; + bool done = false; + while (!done) + { + if (long_options[i].name == 0 && + long_options[i].has_arg == 0 && + long_options[i].flag == 0 && + long_options[i].val == 0) + { + done = true; + } + else + { + if (long_options[i].flag == NULL && + isalpha(long_options[i].val)) + { + s.append(1, (char)long_options[i].val); + switch (long_options[i].has_arg) + { + default: + case no_argument: + break; + + case optional_argument: + s.append(2, ':'); + break; + case required_argument: + s.append(1, ':'); + break; + } + } + ++i; + } + } + return s; +} diff --git a/source/Host/common/Symbols.cpp b/source/Host/common/Symbols.cpp index 7189269677d9..41f465abc836 100644 --- a/source/Host/common/Symbols.cpp +++ b/source/Host/common/Symbols.cpp @@ -61,9 +61,9 @@ Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec) uuid_str = uuid_str + ".debug"; } - // Get full path to our module. Needed to check debug files like this: - // /usr/lib/debug/usr/lib/libboost_date_time.so.1.46.1 - std::string module_filename = module_spec.GetFileSpec().GetPath(); + // Get directory of our module. Needed to check debug files like this: + // /usr/lib/debug/usr/lib/library.so.debug + std::string module_directory = module_spec.GetFileSpec().GetDirectory().AsCString(); size_t num_directories = debug_file_search_paths.GetSize(); for (size_t idx = 0; idx < num_directories; ++idx) @@ -79,7 +79,7 @@ Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec) files.push_back (dirname + "/" + symbol_filename); files.push_back (dirname + "/.debug/" + symbol_filename); files.push_back (dirname + "/.build-id/" + uuid_str); - files.push_back (dirname + module_filename); + files.push_back (dirname + module_directory + "/" + symbol_filename); const uint32_t num_files = files.size(); for (size_t idx_file = 0; idx_file < num_files; ++idx_file) diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp index ff94e0f60212..b6f34fd1f7fb 100644 --- a/source/Interpreter/Args.cpp +++ b/source/Interpreter/Args.cpp @@ -815,7 +815,7 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add options.SetCoerceToId(false); options.SetUnwindOnError(true); options.SetKeepInMemory(false); - options.SetRunOthers(true); + options.SetTryAllThreads(true); ExecutionResults expr_result = target->EvaluateExpression(s, exe_ctx->GetFramePtr(), diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index 794cc716bda5..a7c892d255e8 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -1434,12 +1434,12 @@ CommandInterpreter::PreprocessCommand (std::string &command) ValueObjectSP expr_result_valobj_sp; EvaluateExpressionOptions options; - options.SetCoerceToId(false) - .SetUnwindOnError(true) - .SetIgnoreBreakpoints(true) - .SetKeepInMemory(false) - .SetRunOthers(true) - .SetTimeoutUsec(0); + options.SetCoerceToId(false); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetKeepInMemory(false); + options.SetTryAllThreads(true); + options.SetTimeoutUsec(0); ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), exe_ctx.GetFramePtr(), @@ -1498,6 +1498,9 @@ CommandInterpreter::PreprocessCommand (std::string &command) case eExecutionTimedOut: error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str()); break; + case eExecutionStoppedForDebug: + error.SetErrorStringWithFormat("expression stop at entry point for debugging for the expression '%s'", expr_str.c_str()); + break; } } } diff --git a/source/Interpreter/PythonDataObjects.cpp b/source/Interpreter/PythonDataObjects.cpp index da4e085e2398..1e2bd2391191 100644 --- a/source/Interpreter/PythonDataObjects.cpp +++ b/source/Interpreter/PythonDataObjects.cpp @@ -15,11 +15,7 @@ #else -#if defined (__APPLE__) -#include <Python/Python.h> -#else -#include <Python.h> -#endif +#include "lldb/lldb-python.h" #include <stdio.h> diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp index fc76f0470d3a..fb60fedbe94b 100644 --- a/source/Interpreter/ScriptInterpreterPython.cpp +++ b/source/Interpreter/ScriptInterpreterPython.cpp @@ -15,12 +15,7 @@ #else -#if defined (__APPLE__) -#include <Python/Python.h> -#else -#include <Python.h> -#endif - +#include "lldb/lldb-python.h" #include "lldb/Interpreter/ScriptInterpreterPython.h" #include <stdlib.h> diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp index f27c294a4abd..abf873ff3dd1 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp @@ -198,12 +198,7 @@ ABIMacOSX_arm::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t function_addr, addr_t return_addr, - addr_t *arg1_ptr, - addr_t *arg2_ptr, - addr_t *arg3_ptr, - addr_t *arg4_ptr, - addr_t *arg5_ptr, - addr_t *arg6_ptr) const + llvm::ArrayRef<addr_t> args) const { RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) @@ -215,50 +210,45 @@ ABIMacOSX_arm::PrepareTrivialCall (Thread &thread, RegisterValue reg_value; - if (arg1_ptr) + const char *reg_names[] = { "r0", "r1", "r2", "r3" }; + + llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end(); + + for (size_t i = 0; i < (sizeof(reg_names) / sizeof(reg_names[0])); ++i) { - reg_value.SetUInt32(*arg1_ptr); - if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r0"), reg_value)) + if (ai == ae) + break; + + reg_value.SetUInt32(*ai); + if (!reg_ctx->WriteRegister(reg_ctx->GetRegisterInfoByName(reg_names[i]), reg_value)) return false; - - if (arg2_ptr) + + ++ai; + } + + if (ai != ae) + { + // Spill onto the stack + size_t num_stack_regs = ae - ai; + + sp -= (num_stack_regs * 4); + // Keep the stack 8 byte aligned, not that we need to + sp &= ~(8ull-1ull); + + // just using arg1 to get the right size + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + + addr_t arg_pos = sp; + + for (; ai != ae; ++ai) { - reg_value.SetUInt32(*arg2_ptr); - if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r1"), reg_value)) + reg_value.SetUInt32(*ai); + if (reg_ctx->WriteRegisterValueToMemory(reg_info, arg_pos, reg_info->byte_size, reg_value).Fail()) return false; - - if (arg3_ptr) - { - reg_value.SetUInt32(*arg3_ptr); - if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r2"), reg_value)) - return false; - if (arg4_ptr) - { - reg_value.SetUInt32(*arg4_ptr); - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3"); - if (!reg_ctx->WriteRegister (reg_info, reg_value)) - return false; - if (arg5_ptr) - { - // Keep the stack 8 byte aligned, not that we need to - sp -= 8; - sp &= ~(8ull-1ull); - reg_value.SetUInt32(*arg5_ptr); - if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp, reg_info->byte_size, reg_value).Fail()) - return false; - if (arg6_ptr) - { - reg_value.SetUInt32(*arg6_ptr); - if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp + 4, reg_info->byte_size, reg_value).Fail()) - return false; - } - } - } - } + arg_pos += reg_info->byte_size; } } - TargetSP target_sp (thread.CalculateTarget()); Address so_addr; diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h index 27cea85aaf6f..6f7b339e28a2 100644 --- a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h +++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h @@ -30,12 +30,7 @@ public: lldb::addr_t sp, lldb::addr_t func_addr, lldb::addr_t returnAddress, - lldb::addr_t *arg1_ptr = NULL, - lldb::addr_t *arg2_ptr = NULL, - lldb::addr_t *arg3_ptr = NULL, - lldb::addr_t *arg4_ptr = NULL, - lldb::addr_t *arg5_ptr = NULL, - lldb::addr_t *arg6_ptr = NULL) const; + llvm::ArrayRef<lldb::addr_t> args) const; virtual bool GetArgumentValues (lldb_private::Thread &thread, diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index ecf44b9c4f73..f360a182e065 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -260,12 +260,7 @@ ABIMacOSX_i386::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, - addr_t *arg1_ptr, - addr_t *arg2_ptr, - addr_t *arg3_ptr, - addr_t *arg4_ptr, - addr_t *arg5_ptr, - addr_t *arg6_ptr) const + llvm::ArrayRef<addr_t> args) const { RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) @@ -287,114 +282,25 @@ ABIMacOSX_i386::PrepareTrivialCall (Thread &thread, RegisterValue reg_value; // Write any arguments onto the stack - if (arg1_ptr) - { - sp -= 4; - if (arg2_ptr) - { - sp -= 4; - if (arg3_ptr) - { - sp -= 4; - if (arg4_ptr) - { - sp -= 4; - if (arg5_ptr) - { - sp -= 4; - if (arg6_ptr) - { - sp -= 4; - } - } - } - } - } - } - + sp -= 4 * args.size(); + // Align the SP sp &= ~(16ull-1ull); // 16-byte alignment - if (arg1_ptr) + addr_t arg_pos = sp; + + for (addr_t arg : args) { - reg_value.SetUInt32(*arg1_ptr); - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp, - reg_info_32->byte_size, + reg_value.SetUInt32(arg); + error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, + arg_pos, + reg_info_32->byte_size, reg_value); if (error.Fail()) return false; - - if (arg2_ptr) - { - reg_value.SetUInt32(*arg2_ptr); - // The register info used to write memory just needs to have the correct - // size of a 32 bit register, the actual register it pertains to is not - // important, just the size needs to be correct. Here we use "eax"... - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp + 4, - reg_info_32->byte_size, - reg_value); - if (error.Fail()) - return false; - - if (arg3_ptr) - { - reg_value.SetUInt32(*arg3_ptr); - // The register info used to write memory just needs to have the correct - // size of a 32 bit register, the actual register it pertains to is not - // important, just the size needs to be correct. Here we use "eax"... - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp + 8, - reg_info_32->byte_size, - reg_value); - if (error.Fail()) - return false; - - if (arg4_ptr) - { - reg_value.SetUInt32(*arg4_ptr); - // The register info used to write memory just needs to have the correct - // size of a 32 bit register, the actual register it pertains to is not - // important, just the size needs to be correct. Here we use "eax"... - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp + 12, - reg_info_32->byte_size, - reg_value); - if (error.Fail()) - return false; - if (arg5_ptr) - { - reg_value.SetUInt32(*arg5_ptr); - // The register info used to write memory just needs to have the correct - // size of a 32 bit register, the actual register it pertains to is not - // important, just the size needs to be correct. Here we use "eax"... - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp + 16, - reg_info_32->byte_size, - reg_value); - if (error.Fail()) - return false; - if (arg6_ptr) - { - reg_value.SetUInt32(*arg6_ptr); - // The register info used to write memory just needs to have the correct - // size of a 32 bit register, the actual register it pertains to is not - // important, just the size needs to be correct. Here we use "eax"... - error = reg_ctx->WriteRegisterValueToMemory (reg_info_32, - sp + 20, - reg_info_32->byte_size, - reg_value); - if (error.Fail()) - return false; - } - } - } - } - } + arg_pos += 4; } - // The return address is pushed onto the stack (yes after we just set the // alignment above!). sp -= 4; diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h index 5428d0c1e44e..a2eee280fa38 100644 --- a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h @@ -33,12 +33,7 @@ public: lldb::addr_t sp, lldb::addr_t func_addr, lldb::addr_t return_addr, - lldb::addr_t *arg1_ptr = NULL, - lldb::addr_t *arg2_ptr = NULL, - lldb::addr_t *arg3_ptr = NULL, - lldb::addr_t *arg4_ptr = NULL, - lldb::addr_t *arg5_ptr = NULL, - lldb::addr_t *arg6_ptr = NULL) const; + llvm::ArrayRef<lldb::addr_t> args) const; virtual bool PrepareNormalCall (lldb_private::Thread &thread, diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp index a8cf714a13b3..a8ef6a51399c 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp @@ -303,12 +303,7 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, - addr_t *arg1_ptr, - addr_t *arg2_ptr, - addr_t *arg3_ptr, - addr_t *arg4_ptr, - addr_t *arg5_ptr, - addr_t *arg6_ptr) const + llvm::ArrayRef<addr_t> args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -321,28 +316,8 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread, (uint64_t)func_addr, (uint64_t)return_addr); - if (arg1_ptr) - { - s.Printf (", arg1 = 0x%" PRIx64, (uint64_t)*arg1_ptr); - if (arg2_ptr) - { - s.Printf (", arg2 = 0x%" PRIx64, (uint64_t)*arg2_ptr); - if (arg3_ptr) - { - s.Printf (", arg3 = 0x%" PRIx64, (uint64_t)*arg3_ptr); - if (arg4_ptr) - { - s.Printf (", arg4 = 0x%" PRIx64, (uint64_t)*arg4_ptr); - if (arg5_ptr) - { - s.Printf (", arg5 = 0x%" PRIx64, (uint64_t)*arg5_ptr); - if (arg6_ptr) - s.Printf (", arg6 = 0x%" PRIx64, (uint64_t)*arg6_ptr); - } - } - } - } - } + for (int i = 0; i < args.size(); ++i) + s.Printf (", arg%d = 0x%" PRIx64, i + 1, args[i]); s.PutCString (")"); log->PutCString(s.GetString().c_str()); } @@ -352,62 +327,19 @@ ABISysV_x86_64::PrepareTrivialCall (Thread &thread, return false; const RegisterInfo *reg_info = NULL; - if (arg1_ptr) + + if (args.size() > 6) // TODO handle more than 6 arguments + return false; + + for (int i = 0; i < args.size(); ++i) { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); + reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) - log->Printf("About to write arg1 (0x%" PRIx64 ") into %s", (uint64_t)*arg1_ptr, reg_info->name); - - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg1_ptr)) + log->Printf("About to write arg%d (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); + if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; - - if (arg2_ptr) - { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2); - if (log) - log->Printf("About to write arg2 (0x%" PRIx64 ") into %s", (uint64_t)*arg2_ptr, reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg2_ptr)) - return false; - - if (arg3_ptr) - { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3); - if (log) - log->Printf("About to write arg3 (0x%" PRIx64 ") into %s", (uint64_t)*arg3_ptr, reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg3_ptr)) - return false; - - if (arg4_ptr) - { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4); - if (log) - log->Printf("About to write arg4 (0x%" PRIx64 ") into %s", (uint64_t)*arg4_ptr, reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg4_ptr)) - return false; - - if (arg5_ptr) - { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5); - if (log) - log->Printf("About to write arg5 (0x%" PRIx64 ") into %s", (uint64_t)*arg5_ptr, reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg5_ptr)) - return false; - - if (arg6_ptr) - { - reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6); - if (log) - log->Printf("About to write arg6 (0x%" PRIx64 ") into %s", (uint64_t)*arg6_ptr, reg_info->name); - if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg6_ptr)) - return false; - } - } - } - } - } } - // First, align the SP if (log) diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h index d9d6fd7af79a..5ccb6e5fa744 100644 --- a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h @@ -34,12 +34,7 @@ public: lldb::addr_t sp, lldb::addr_t functionAddress, lldb::addr_t returnAddress, - lldb::addr_t *arg1_ptr = NULL, - lldb::addr_t *arg2_ptr = NULL, - lldb::addr_t *arg3_ptr = NULL, - lldb::addr_t *arg4_ptr = NULL, - lldb::addr_t *arg5_ptr = NULL, - lldb::addr_t *arg6_ptr = NULL) const; + llvm::ArrayRef<lldb::addr_t> args) const; virtual bool GetArgumentValues (lldb_private::Thread &thread, diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index a3c294ae7a05..81e78847a1f3 100644 --- a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -1,4 +1,4 @@ -//===-- lldb_EmulateInstructionARM.h ------------------------------------*- C++ -*-===// +//===-- lldb_EmulateInstructionARM.h ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index d18b4c75ae7b..f3c2d63729ae 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -445,6 +445,12 @@ ItaniumABILanguageRuntime::ClearExceptionBreakpoints () } bool +ItaniumABILanguageRuntime::ExceptionBreakpointsAreSet () +{ + return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled(); +} + +bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) { if (!m_process) diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index 6b2c437de252..cd0a4b2c15eb 100644 --- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -71,6 +71,9 @@ namespace lldb_private { ClearExceptionBreakpoints (); virtual bool + ExceptionBreakpointsAreSet (); + + virtual bool ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason); virtual lldb::BreakpointResolverSP diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 163e713bedb2..7bdacfe14cde 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -16,6 +16,7 @@ #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Error.h" #include "lldb/Core/FileSpecList.h" +#include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -143,6 +144,44 @@ ELFRelocation::RelocSymbol64(const ELFRelocation &rel) } // end anonymous namespace +bool +ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) +{ + // Read all fields. + if (data.GetU32(offset, &n_namesz, 3) == NULL) + return false; + + // The name field is required to be nul-terminated, and n_namesz + // includes the terminating nul in observed implementations (contrary + // to the ELF-64 spec). A special case is needed for cores generated + // by some older Linux versions, which write a note named "CORE" + // without a nul terminator and n_namesz = 4. + if (n_namesz == 4) + { + char buf[4]; + if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4) + return false; + if (strncmp (buf, "CORE", 4) == 0) + { + n_name = "CORE"; + *offset += 4; + return true; + } + } + + const char *cstr = data.GetCStr(offset, llvm::RoundUpToAlignment (n_namesz, 4)); + if (cstr == NULL) + { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS)); + if (log) + log->Printf("Failed to parse note name lacking nul terminator"); + + return false; + } + n_name = cstr; + return true; +} + //------------------------------------------------------------------ // Static methods. //------------------------------------------------------------------ @@ -685,42 +724,26 @@ ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid) { // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id. // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId - struct - { - uint32_t name_len; // Length of note name - uint32_t desc_len; // Length of note descriptor - uint32_t type; // Type of note (1 is ABI_TAG, 3 is BUILD_ID) - } notehdr; lldb::offset_t offset = 0; static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h while (true) { - if (data.GetU32 (&offset, ¬ehdr, 3) == NULL) + ELFNote note = ELFNote(); + if (!note.Parse(data, &offset)) return false; - notehdr.name_len = llvm::RoundUpToAlignment (notehdr.name_len, 4); - notehdr.desc_len = llvm::RoundUpToAlignment (notehdr.desc_len, 4); - - lldb::offset_t offset_next_note = offset + notehdr.name_len + notehdr.desc_len; - // 16 bytes is UUID|MD5, 20 bytes is SHA1 - if ((notehdr.type == g_gnu_build_id) && (notehdr.name_len == 4) && - (notehdr.desc_len == 16 || notehdr.desc_len == 20)) + if (note.n_name == "GNU" && (note.n_type == g_gnu_build_id) && + (note.n_descsz == 16 || note.n_descsz == 20)) { - char name[4]; - if (data.GetU8 (&offset, name, 4) == NULL) + uint8_t uuidbuf[20]; + if (data.GetU8 (&offset, &uuidbuf, note.n_descsz) == NULL) return false; - if (!strcmp(name, "GNU")) - { - uint8_t uuidbuf[20]; - if (data.GetU8 (&offset, &uuidbuf, notehdr.desc_len) == NULL) - return false; - uuid.SetBytes (uuidbuf, notehdr.desc_len); - return true; - } + uuid.SetBytes (uuidbuf, note.n_descsz); + return true; } - offset = offset_next_note; + offset += llvm::RoundUpToAlignment(note.n_descsz, 4); } return false; } diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index ede886fb4f60..a2ab9b8f3703 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -20,6 +20,34 @@ #include "ELFHeader.h" +struct ELFNote +{ + elf::elf_word n_namesz; + elf::elf_word n_descsz; + elf::elf_word n_type; + + std::string n_name; + + ELFNote() : n_namesz(0), n_descsz(0), n_type(0) + { + } + + /// Parse an ELFNote entry from the given DataExtractor starting at position + /// \p offset. + /// + /// @param[in] data + /// The DataExtractor to read from. + /// + /// @param[in,out] offset + /// Pointer to an offset in the data. On return the offset will be + /// advanced by the number of bytes read. + /// + /// @return + /// True if the ELFRel entry was successfully read and false otherwise. + bool + Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); +}; + //------------------------------------------------------------------------------ /// @class ObjectFileELF /// @brief Generic ELF object file reader. diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 34316c484276..b5f92dcc3dcd 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -76,44 +76,56 @@ PlatformPOSIX::RunShellCommand (const char *command, // Shouldn't be N } } -uint32_t -PlatformPOSIX::MakeDirectory (const std::string &path, - mode_t mode) +Error +PlatformPOSIX::MakeDirectory (const char *path, uint32_t file_permissions) { - if (IsHost()) - { - return Host::MakeDirectory (path.c_str(), mode); - } - if (IsRemote() && m_remote_platform_sp) - return m_remote_platform_sp->MakeDirectory(path, mode); - return Platform::MakeDirectory(path,mode); + if (m_remote_platform_sp) + return m_remote_platform_sp->MakeDirectory(path, file_permissions); + else + return Platform::MakeDirectory(path ,file_permissions); +} + +Error +PlatformPOSIX::GetFilePermissions (const char *path, uint32_t &file_permissions) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetFilePermissions(path, file_permissions); + else + return Platform::GetFilePermissions(path ,file_permissions); +} + +Error +PlatformPOSIX::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->MakeDirectory(path, file_permissions); + else + return Platform::SetFilePermissions(path ,file_permissions); } lldb::user_id_t PlatformPOSIX::OpenFile (const FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { if (IsHost()) - { return Host::OpenFile(file_spec, flags, mode, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->OpenFile(file_spec, flags, mode, error); - return Platform::OpenFile(file_spec, flags, mode, error); + else + return Platform::OpenFile(file_spec, flags, mode, error); } bool PlatformPOSIX::CloseFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - { return Host::CloseFile(fd, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->CloseFile(fd, error); - return Platform::CloseFile(fd, error); + else + return Platform::CloseFile(fd, error); } uint64_t @@ -124,12 +136,11 @@ PlatformPOSIX::ReadFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - { return Host::ReadFile(fd, offset, dst, dst_len, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->ReadFile(fd, offset, dst, dst_len, error); - return Platform::ReadFile(fd, offset, dst, dst_len, error); + else + return Platform::ReadFile(fd, offset, dst, dst_len, error); } uint64_t @@ -140,13 +151,11 @@ PlatformPOSIX::WriteFile (lldb::user_id_t fd, Error &error) { if (IsHost()) - { return Host::WriteFile(fd, offset, src, src_len, error); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->WriteFile(fd, offset, src, src_len, error); - - return Platform::WriteFile(fd, offset, src, src_len, error); + else + return Platform::WriteFile(fd, offset, src, src_len, error); } static uint32_t @@ -184,6 +193,8 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, uint32_t uid, uint32_t gid) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (IsHost()) { if (FileSpec::Equal(source, destination, true)) @@ -213,7 +224,7 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, return Error("unable to perform chown"); return Error(); } - else if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) { if (GetSupportsRSync()) { @@ -244,7 +255,6 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, src_path.c_str(), GetHostname(), dst_path.c_str()); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("[PutFile] Running command: %s\n", command.GetData()); int retcode; @@ -263,20 +273,35 @@ PlatformPOSIX::PutFile (const lldb_private::FileSpec& source, } // if we are still here rsync has failed - let's try the slow way before giving up } + + if (log) + log->Printf ("PlatformPOSIX::PutFile(src='%s', dst='%s', uid=%u, gid=%u)", + source.GetPath().c_str(), + destination.GetPath().c_str(), + uid, + gid); // REMOVE THIS PRINTF PRIOR TO CHECKIN // open // read, write, read, write, ... // close // chown uid:gid dst - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("[PutFile] Using block by block transfer....\n"); - File source_file(source, File::eOpenOptionRead, File::ePermissionsUserRW); + if (log) + log->Printf("[PutFile] Using block by block transfer....\n"); + + uint32_t source_open_options = File::eOpenOptionRead; + if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) + source_open_options |= File::eOpenoptionDontFollowSymlinks; + + File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); + Error error; + uint32_t permissions = source_file.GetPermissions(error); + if (permissions == 0) + permissions = lldb::eFilePermissionsFileDefault; + if (!source_file.IsValid()) return Error("unable to open source file"); - Error error; lldb::user_id_t dest_file = OpenFile (destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, - File::ePermissionsUserRWX | File::ePermissionsGroupRX | File::ePermissionsWorldRX, + permissions, error); if (log) log->Printf ("dest_file = %" PRIu64 "\n", dest_file); @@ -314,45 +339,52 @@ lldb::user_id_t PlatformPOSIX::GetFileSize (const FileSpec& file_spec) { if (IsHost()) - { return Host::GetFileSize(file_spec); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileSize(file_spec); - return Platform::GetFileSize(file_spec); + else + return Platform::GetFileSize(file_spec); +} + +Error +PlatformPOSIX::CreateSymlink(const char *src, const char *dst) +{ + if (IsHost()) + return Host::Symlink(src, dst); + else if (m_remote_platform_sp) + return m_remote_platform_sp->CreateSymlink(src, dst); + else + return Platform::CreateSymlink(src, dst); } bool PlatformPOSIX::GetFileExists (const FileSpec& file_spec) { if (IsHost()) - { return file_spec.Exists(); - } - if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) return m_remote_platform_sp->GetFileExists(file_spec); - return Platform::GetFileExists(file_spec); + else + return Platform::GetFileExists(file_spec); } -uint32_t -PlatformPOSIX::GetFilePermissions (const lldb_private::FileSpec &file_spec, - lldb_private::Error &error) +Error +PlatformPOSIX::Unlink (const char *path) { if (IsHost()) - { - return File::GetPermissions(file_spec.GetPath().c_str(), error); - } - if (IsRemote() && m_remote_platform_sp) - return m_remote_platform_sp->GetFilePermissions(file_spec, error); - return Platform::GetFilePermissions(file_spec, error); - + return Host::Unlink (path); + else if (m_remote_platform_sp) + return m_remote_platform_sp->Unlink(path); + else + return Platform::Unlink(path); } - lldb_private::Error PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path */, - const lldb_private::FileSpec& destination /* local file path */) + const lldb_private::FileSpec& destination /* local file path */) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + // Check the args, first. std::string src_path (source.GetPath()); if (src_path.empty()) @@ -378,7 +410,7 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path return Error("unable to perform copy"); return Error(); } - else if (IsRemote() && m_remote_platform_sp) + else if (m_remote_platform_sp) { if (GetSupportsRSync()) { @@ -403,7 +435,6 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path m_remote_platform_sp->GetHostname(), src_path.c_str(), dst_path.c_str()); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("[GetFile] Running command: %s\n", command.GetData()); int retcode; @@ -421,22 +452,22 @@ PlatformPOSIX::GetFile (const lldb_private::FileSpec& source /* remote file path // read/write, read/write, read/write, ... // close src // close dst - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("[GetFile] Using block by block transfer....\n"); + if (log) + log->Printf("[GetFile] Using block by block transfer....\n"); Error error; user_id_t fd_src = OpenFile (source, File::eOpenOptionRead, - File::ePermissionsDefault, + lldb::eFilePermissionsFileDefault, error); if (fd_src == UINT64_MAX) return Error("unable to open source file"); - uint32_t permissions = GetFilePermissions(source, error); + uint32_t permissions = 0; + error = GetFilePermissions(source.GetPath().c_str(), permissions); if (permissions == 0) - permissions = File::ePermissionsDefault; + permissions = lldb::eFilePermissionsFileDefault; user_id_t fd_dst = Host::OpenFile(destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | File::eOpenOptionTruncate, @@ -539,3 +570,22 @@ PlatformPOSIX::CalculateMD5 (const FileSpec& file_spec, return m_remote_platform_sp->CalculateMD5(file_spec, low, high); return false; } + +lldb_private::ConstString +PlatformPOSIX::GetRemoteWorkingDirectory() +{ + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteWorkingDirectory(); + else + return Platform::GetRemoteWorkingDirectory(); +} + +bool +PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) +{ + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->SetRemoteWorkingDirectory(path); + else + return Platform::SetRemoteWorkingDirectory(path); +} + diff --git a/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 4119e452bf7f..336e0f90fcad 100644 --- a/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -43,7 +43,7 @@ public: virtual lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, lldb_private::Error &error); virtual bool @@ -68,9 +68,18 @@ public: GetFileSize (const lldb_private::FileSpec& file_spec); virtual lldb_private::Error + CreateSymlink(const char *src, const char *dst); + + virtual lldb_private::Error GetFile (const lldb_private::FileSpec& source, const lldb_private::FileSpec& destination); + virtual lldb_private::ConstString + GetRemoteWorkingDirectory(); + + virtual bool + SetRemoteWorkingDirectory(const lldb_private::ConstString &path); + virtual lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory @@ -79,16 +88,20 @@ public: std::string *command_output, // Pass NULL if you don't want the command output uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode); + virtual lldb_private::Error + MakeDirectory (const char *path, uint32_t mode); + virtual lldb_private::Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual lldb_private::Error + SetFilePermissions (const char *path, uint32_t file_permissions); + virtual bool GetFileExists (const lldb_private::FileSpec& file_spec); - virtual uint32_t - GetFilePermissions (const lldb_private::FileSpec &file_spec, - lldb_private::Error &error); + virtual lldb_private::Error + Unlink (const char *path); virtual std::string GetPlatformSpecificConnectionInformation(); diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 4aeec032d712..248abaf6fea7 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -194,6 +194,47 @@ PlatformRemoteGDBServer::GetRemoteSystemArchitecture () return m_gdb_client.GetSystemArchitecture(); } +lldb_private::ConstString +PlatformRemoteGDBServer::GetRemoteWorkingDirectory() +{ + if (IsConnected()) + { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + std::string cwd; + if (m_gdb_client.GetWorkingDir(cwd)) + { + ConstString working_dir(cwd.c_str()); + if (log) + log->Printf("PlatformRemoteGDBServer::GetRemoteWorkingDirectory() -> '%s'", working_dir.GetCString()); + return working_dir; + } + else + { + return ConstString(); + } + } + else + { + return Platform::GetRemoteWorkingDirectory(); + } +} + +bool +PlatformRemoteGDBServer::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) +{ + if (IsConnected()) + { + // Clear the working directory it case it doesn't get set correctly. This will + // for use to re-read it + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("PlatformRemoteGDBServer::SetRemoteWorkingDirectory('%s')", path.GetCString()); + return m_gdb_client.SetWorkingDir(path.GetCString()) == 0; + } + else + return Platform::SetRemoteWorkingDirectory(path); +} + bool PlatformRemoteGDBServer::IsConnected () const { @@ -220,8 +261,10 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args) { if (m_gdb_client.HandshakeWithServer(&error)) { - m_gdb_client.QueryNoAckModeSupported(); m_gdb_client.GetHostInfo(); + // If a working directory was set prior to connecting, send it down now + if (m_working_dir) + m_gdb_client.SetWorkingDir(m_working_dir.GetCString()); #if 0 m_gdb_client.TestPacketSpeed(10000); #endif @@ -229,6 +272,8 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args) else { m_gdb_client.Disconnect(); + if (error.Success()) + error.SetErrorString("handshake failed"); } } } @@ -237,11 +282,6 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args) error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>"); } } - - if (error.Success()) - { - - } return error; } @@ -324,7 +364,6 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) } // Send the environment and the program + arguments after we connect - const char **argv = launch_info.GetArguments().GetConstArgumentVector(); const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector(); if (envp) @@ -343,7 +382,7 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) m_gdb_client.SendLaunchArchPacket(arch_triple); const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5); - int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv); + int arg_packet_err = m_gdb_client.SendArgumentsPacket (launch_info); m_gdb_client.SetPacketTimeout (old_packet_timeout); if (arg_packet_err == 0) { @@ -367,6 +406,80 @@ PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info) } lldb::ProcessSP +PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error) +{ + lldb::ProcessSP process_sp; + if (IsRemote()) + { + if (IsConnected()) + { + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + + if (port == 0) + { + error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); + } + else + { + if (target == NULL) + { + TargetSP new_target_sp; + + error = debugger.GetTargetList().CreateTarget (debugger, + NULL, + NULL, + false, + NULL, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + + // The darwin always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + process_sp = target->CreateProcess (listener, "gdb-remote", NULL); + + if (process_sp) + { + char connect_url[256]; + const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); + const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); + int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; + const int connect_url_len = ::snprintf (connect_url, + sizeof(connect_url), + "connect://%s:%u", + override_hostname ? override_hostname : GetHostname (), + port + port_offset); + assert (connect_url_len < (int)sizeof(connect_url)); + error = process_sp->ConnectRemote (NULL, connect_url); + if (error.Success()) + error = process_sp->Launch(launch_info); + else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + m_gdb_client.KillSpawnedProcess(debugserver_pid); + } + } + } + } + else + { + error.SetErrorString("not connected to remote gdb server"); + } + } + return process_sp; + +} + +lldb::ProcessSP PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -441,17 +554,42 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, return process_sp; } -uint32_t -PlatformRemoteGDBServer::MakeDirectory (const std::string &path, - mode_t mode) +Error +PlatformRemoteGDBServer::MakeDirectory (const char *path, uint32_t mode) { - return m_gdb_client.MakeDirectory(path,mode); + Error error = m_gdb_client.MakeDirectory(path,mode); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::MakeDirectory(path='%s', mode=%o) error = %u (%s)", path, mode, error.GetError(), error.AsCString()); + return error; } + +Error +PlatformRemoteGDBServer::GetFilePermissions (const char *path, uint32_t &file_permissions) +{ + Error error = m_gdb_client.GetFilePermissions(path, file_permissions); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::GetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString()); + return error; +} + +Error +PlatformRemoteGDBServer::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + Error error = m_gdb_client.SetFilePermissions(path, file_permissions); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::SetFilePermissions(path='%s', file_permissions=%o) error = %u (%s)", path, file_permissions, error.GetError(), error.AsCString()); + return error; +} + + lldb::user_id_t PlatformRemoteGDBServer::OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, Error &error) { return m_gdb_client.OpenFile (file_spec, flags, mode, error); @@ -469,13 +607,6 @@ PlatformRemoteGDBServer::GetFileSize (const lldb_private::FileSpec& file_spec) return m_gdb_client.GetFileSize(file_spec); } -uint32_t -PlatformRemoteGDBServer::GetFilePermissions (const lldb_private::FileSpec &file_spec, - lldb_private::Error &error) -{ - return m_gdb_client.GetFilePermissions(file_spec, error); -} - uint64_t PlatformRemoteGDBServer::ReadFile (lldb::user_id_t fd, uint64_t offset, @@ -505,6 +636,27 @@ PlatformRemoteGDBServer::PutFile (const lldb_private::FileSpec& source, return Platform::PutFile(source,destination,uid,gid); } +Error +PlatformRemoteGDBServer::CreateSymlink (const char *src, // The name of the link is in src + const char *dst) // The symlink points to dst +{ + Error error = m_gdb_client.CreateSymlink (src, dst); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::CreateSymlink(src='%s', dst='%s') error = %u (%s)", src, dst, error.GetError(), error.AsCString()); + return error; +} + +Error +PlatformRemoteGDBServer::Unlink (const char *path) +{ + Error error = m_gdb_client.Unlink (path); + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("PlatformRemoteGDBServer::Unlink(path='%s') error = %u (%s)", path, error.GetError(), error.AsCString()); + return error; +} + bool PlatformRemoteGDBServer::GetFileExists (const lldb_private::FileSpec& file_spec) { diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 70db6bafacd2..808fb5ed61cc 100644 --- a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -89,6 +89,13 @@ public: LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info); virtual lldb::ProcessSP + DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one + lldb_private::Listener &listener, + lldb_private::Error &error); + + virtual lldb::ProcessSP Attach (lldb_private::ProcessAttachInfo &attach_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one @@ -115,6 +122,13 @@ public: virtual lldb_private::ArchSpec GetRemoteSystemArchitecture (); + virtual lldb_private::ConstString + GetRemoteWorkingDirectory(); + + virtual bool + SetRemoteWorkingDirectory(const lldb_private::ConstString &path); + + // Remote subclasses should override this and return a valid instance // name if connected. virtual const char * @@ -135,14 +149,20 @@ public: virtual lldb_private::Error DisconnectRemote (); - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode); + virtual lldb_private::Error + MakeDirectory (const char *path, uint32_t file_permissions); + + virtual lldb_private::Error + GetFilePermissions (const char *path, uint32_t &file_permissions); + + virtual lldb_private::Error + SetFilePermissions (const char *path, uint32_t file_permissions); + virtual lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, - mode_t mode, + uint32_t mode, lldb_private::Error &error); virtual bool @@ -172,12 +192,14 @@ public: uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX); + virtual lldb_private::Error + CreateSymlink (const char *src, const char *dst); + virtual bool GetFileExists (const lldb_private::FileSpec& file_spec); - - virtual uint32_t - GetFilePermissions (const lldb_private::FileSpec &file_spec, - lldb_private::Error &error); + + virtual lldb_private::Error + Unlink (const char *path); virtual lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 3833fa6baf85..ac5357916501 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -465,13 +465,12 @@ WriteFPROperation::Execute(ProcessMonitor *monitor) class ResumeOperation : public Operation { public: - ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) : - m_tid(tid), m_signo(signo), m_result(result) { } + ResumeOperation(uint32_t signo, bool &result) : + m_signo(signo), m_result(result) { } void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; uint32_t m_signo; bool &m_result; }; @@ -479,17 +478,18 @@ private: void ResumeOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); int data = 0; if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) data = m_signo; - if (PTRACE(PT_CONTINUE, m_tid, (caddr_t)1, data)) + if (PTRACE(PT_CONTINUE, pid, (caddr_t)1, data)) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) - log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno)); + log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", pid, strerror(errno)); m_result = false; } else @@ -502,13 +502,12 @@ ResumeOperation::Execute(ProcessMonitor *monitor) class SingleStepOperation : public Operation { public: - SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result) - : m_tid(tid), m_signo(signo), m_result(result) { } + SingleStepOperation(uint32_t signo, bool &result) + : m_signo(signo), m_result(result) { } void Execute(ProcessMonitor *monitor); private: - lldb::tid_t m_tid; uint32_t m_signo; bool &m_result; }; @@ -516,12 +515,13 @@ private: void SingleStepOperation::Execute(ProcessMonitor *monitor) { + lldb::pid_t pid = monitor->GetPID(); int data = 0; if (m_signo != LLDB_INVALID_SIGNAL_NUMBER) data = m_signo; - if (PTRACE(PT_STEP, m_tid, NULL, data)) + if (PTRACE(PT_STEP, pid, NULL, data)) m_result = false; else m_result = true; @@ -585,7 +585,7 @@ EventMessageOperation::Execute(ProcessMonitor *monitor) m_result = false; else { if (plwp.pl_flags & PL_FLAG_FORKED) { - m_message = (unsigned long *)plwp.pl_child_pid; + *m_message = plwp.pl_child_pid; m_result = true; } else m_result = false; @@ -953,7 +953,7 @@ ProcessMonitor::Launch(LaunchArgs *args) } goto FINISH; } - assert(WIFSTOPPED(status) && wpid == pid && + assert(WIFSTOPPED(status) && wpid == (::pid_t)pid && "Could not sync with inferior process."); #ifdef notyet @@ -1338,8 +1338,6 @@ ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info) void ProcessMonitor::ServeOperation(OperationArgs *args) { - int status; - ProcessMonitor *monitor = args->m_monitor; // We are finised with the arguments and are ready to go. Sync with the @@ -1467,15 +1465,15 @@ ProcessMonitor::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) } bool -ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) +ProcessMonitor::Resume(lldb::tid_t unused, uint32_t signo) { bool result; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); if (log) - log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid, + log->Printf ("ProcessMonitor::%s() resuming pid %" PRIu64 " with signal %s", __FUNCTION__, GetPID(), m_process->GetUnixSignals().GetSignalAsCString (signo)); - ResumeOperation op(tid, signo, result); + ResumeOperation op(signo, result); DoOperation(&op); if (log) log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false"); @@ -1483,10 +1481,10 @@ ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo) } bool -ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo) +ProcessMonitor::SingleStep(lldb::tid_t unused, uint32_t signo) { bool result; - SingleStepOperation op(tid, signo, result); + SingleStepOperation op(signo, result); DoOperation(&op); return result; } diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 4a9b48370444..44219c4eb9e3 100644 --- a/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -175,15 +175,15 @@ public: bool GetEventMessage(lldb::tid_t tid, unsigned long *message); - /// Resumes the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + /// Resumes the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. bool - Resume(lldb::tid_t tid, uint32_t signo); + Resume(lldb::tid_t unused, uint32_t signo); - /// Single steps the given thread. If @p signo is anything but - /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread. + /// Single steps the process. If @p signo is anything but + /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the process. bool - SingleStep(lldb::tid_t tid, uint32_t signo); + SingleStep(lldb::tid_t unused, uint32_t signo); /// Sends the inferior process a PTRACE_KILL signal. The inferior will /// still exists and can be interrogated. Once resumed it will exit as diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index 98e0bce68678..f833c9b47520 100644 --- a/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -377,8 +377,6 @@ RegisterContextPOSIXProcessMonitor_x86_64::WriteAllRegisterValues(const DataBuff success = WriteFPR(); if (success) { - success = true; - if (GetFPRType() == eXSAVE) { ByteOrder byte_order = GetByteOrder(); diff --git a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h index 1bab88cd5727..86abdba68db6 100644 --- a/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h +++ b/source/Plugins/Process/POSIX/RegisterInfos_x86_64.h @@ -94,14 +94,14 @@ g_register_infos_x86_64[] = // General purpose registers. GCC, DWARF, Generic, GDB DEFINE_GPR(rax, NULL, gcc_dwarf_rax_x86_64, gcc_dwarf_rax_x86_64, LLDB_INVALID_REGNUM, gdb_rax_x86_64), DEFINE_GPR(rbx, NULL, gcc_dwarf_rbx_x86_64, gcc_dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, gdb_rbx_x86_64), - DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_INVALID_REGNUM, gdb_rcx_x86_64), - DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_INVALID_REGNUM, gdb_rdx_x86_64), - DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_INVALID_REGNUM, gdb_rdi_x86_64), - DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_INVALID_REGNUM, gdb_rsi_x86_64), + DEFINE_GPR(rcx, "arg4", gcc_dwarf_rcx_x86_64, gcc_dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, gdb_rcx_x86_64), + DEFINE_GPR(rdx, "arg3", gcc_dwarf_rdx_x86_64, gcc_dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, gdb_rdx_x86_64), + DEFINE_GPR(rdi, "arg1", gcc_dwarf_rdi_x86_64, gcc_dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, gdb_rdi_x86_64), + DEFINE_GPR(rsi, "arg2", gcc_dwarf_rsi_x86_64, gcc_dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, gdb_rsi_x86_64), DEFINE_GPR(rbp, "fp", gcc_dwarf_rbp_x86_64, gcc_dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, gdb_rbp_x86_64), DEFINE_GPR(rsp, "sp", gcc_dwarf_rsp_x86_64, gcc_dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, gdb_rsp_x86_64), - DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_INVALID_REGNUM, gdb_r8_x86_64), - DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_INVALID_REGNUM, gdb_r9_x86_64), + DEFINE_GPR(r8, "arg5", gcc_dwarf_r8_x86_64, gcc_dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, gdb_r8_x86_64), + DEFINE_GPR(r9, "arg6", gcc_dwarf_r9_x86_64, gcc_dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, gdb_r9_x86_64), DEFINE_GPR(r10, NULL, gcc_dwarf_r10_x86_64, gcc_dwarf_r10_x86_64, LLDB_INVALID_REGNUM, gdb_r10_x86_64), DEFINE_GPR(r11, NULL, gcc_dwarf_r11_x86_64, gcc_dwarf_r11_x86_64, LLDB_INVALID_REGNUM, gdb_r11_x86_64), DEFINE_GPR(r12, NULL, gcc_dwarf_r12_x86_64, gcc_dwarf_r12_x86_64, LLDB_INVALID_REGNUM, gdb_r12_x86_64), diff --git a/source/Plugins/Process/Utility/HistoryThread.cpp b/source/Plugins/Process/Utility/HistoryThread.cpp new file mode 100644 index 000000000000..521136295fd5 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryThread.cpp @@ -0,0 +1,95 @@ +//===-- HistoryThread.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 "Plugins/Process/Utility/HistoryUnwind.h" +#include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/Process/Utility/RegisterContextHistory.h" + +#include "lldb/Core/Log.h" +#include "lldb/Target/StackFrameList.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + +HistoryThread::HistoryThread (lldb_private::Process &process, + lldb::tid_t tid, + std::vector<lldb::addr_t> pcs, + uint32_t stop_id, + bool stop_id_is_valid) : + Thread (process, LLDB_INVALID_THREAD_ID), + m_framelist_mutex(), + m_framelist(), + m_pcs (pcs), + m_stop_id (stop_id), + m_stop_id_is_valid (stop_id_is_valid), + m_extended_unwind_token (LLDB_INVALID_ADDRESS), + m_queue_name (), + m_thread_name (), + m_originating_unique_thread_id (tid), + m_queue_id (LLDB_INVALID_QUEUE_ID) +{ + m_unwinder_ap.reset (new HistoryUnwind (*this, pcs, stop_id, stop_id_is_valid)); + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p HistoryThread::HistoryThread", this); +} + +HistoryThread::~HistoryThread () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf ("%p HistoryThread::~HistoryThread (tid=0x%" PRIx64 ")", this, GetID()); + DestroyThread(); +} + +lldb::RegisterContextSP +HistoryThread::GetRegisterContext () +{ + RegisterContextSP rctx ; + if (m_pcs.size() > 0) + { + rctx.reset (new RegisterContextHistory (*this, 0, GetProcess()->GetAddressByteSize(), m_pcs[0])); + } + return rctx; + +} + +lldb::RegisterContextSP +HistoryThread::CreateRegisterContextForFrame (StackFrame *frame) +{ + return m_unwinder_ap->CreateRegisterContextForFrame (frame); +} + +lldb::StackFrameListSP +HistoryThread::GetStackFrameList () +{ + Mutex::Locker (m_framelist_mutex); + if (m_framelist.get() == NULL) + { + m_framelist.reset (new StackFrameList (*this, StackFrameListSP(), true)); + } + + return m_framelist; +} + +uint32_t +HistoryThread::GetExtendedBacktraceOriginatingIndexID () +{ + if (m_originating_unique_thread_id != LLDB_INVALID_THREAD_ID) + { + if (GetProcess()->HasAssignedIndexIDToThread (m_originating_unique_thread_id)) + { + return GetProcess()->AssignIndexIDToThread (m_originating_unique_thread_id); + } + } + return LLDB_INVALID_THREAD_ID; +} diff --git a/source/Plugins/Process/Utility/HistoryThread.h b/source/Plugins/Process/Utility/HistoryThread.h new file mode 100644 index 000000000000..01fdd1608706 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryThread.h @@ -0,0 +1,114 @@ +//===-- HistoryThread.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_HistoryThread_h_ +#define liblldb_HistoryThread_h_ + +#include "lldb/lldb-private.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/UserID.h" +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/StackFrameList.h" +#include "lldb/Target/Thread.h" + +namespace lldb_private { + +class HistoryThread : public lldb_private::Thread +{ +public: + HistoryThread (lldb_private::Process &process, lldb::tid_t tid, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid); + + virtual ~HistoryThread (); + + virtual lldb::RegisterContextSP + GetRegisterContext (); + + virtual lldb::RegisterContextSP + CreateRegisterContextForFrame (StackFrame *frame); + + virtual void + RefreshStateAfterStop() { } + + bool + CalculateStopInfo () { return false; } + + void + SetExtendedBacktraceToken (uint64_t token) + { + m_extended_unwind_token = token; + } + + uint64_t + GetExtendedBacktraceToken () + { + return m_extended_unwind_token; + } + + const char * + GetQueueName () + { + return m_queue_name.c_str(); + } + + void + SetQueueName (const char *name) + { + m_queue_name = name; + } + + lldb::queue_id_t + GetQueueID () + { + return m_queue_id; + } + + void + SetQueueID (lldb::queue_id_t queue) + { + m_queue_id = queue; + } + + const char * + GetThreadName () + { + return m_thread_name.c_str(); + } + + uint32_t + GetExtendedBacktraceOriginatingIndexID (); + + void + SetThreadName (const char *name) + { + m_thread_name = name; + } + +protected: + virtual lldb::StackFrameListSP + GetStackFrameList (); + + mutable Mutex m_framelist_mutex; + lldb::StackFrameListSP m_framelist; + std::vector<lldb::addr_t> m_pcs; + uint32_t m_stop_id; + bool m_stop_id_is_valid; + + uint64_t m_extended_unwind_token; + std::string m_queue_name; + std::string m_thread_name; + lldb::tid_t m_originating_unique_thread_id; + lldb::queue_id_t m_queue_id; +}; + +} // namespace lldb_private + +#endif // liblldb_HistoryThread_h_ diff --git a/source/Plugins/Process/Utility/HistoryUnwind.cpp b/source/Plugins/Process/Utility/HistoryUnwind.cpp new file mode 100644 index 000000000000..86665fd17b13 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -0,0 +1,79 @@ +//===-- HistoryUnwind.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 "Plugins/Process/Utility/RegisterContextHistory.h" +#include "Plugins/Process/Utility/HistoryUnwind.h" + +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +HistoryUnwind::HistoryUnwind (Thread &thread, + std::vector<lldb::addr_t> pcs, + uint32_t stop_id, + bool stop_id_is_valid) : + Unwind (thread), + m_pcs (pcs), + m_stop_id (stop_id), + m_stop_id_is_valid (stop_id_is_valid) +{ +} + +HistoryUnwind::~HistoryUnwind () +{ +} + +void +HistoryUnwind::DoClear () +{ + Mutex::Locker locker(m_unwind_mutex); + m_pcs.clear(); + m_stop_id_is_valid = false; +} + +lldb::RegisterContextSP +HistoryUnwind::DoCreateRegisterContextForFrame (StackFrame *frame) +{ + RegisterContextSP rctx; + if (frame) + { + addr_t pc = frame->GetFrameCodeAddress().GetLoadAddress (&frame->GetThread()->GetProcess()->GetTarget()); + if (pc != LLDB_INVALID_ADDRESS) + { + rctx.reset (new RegisterContextHistory (*frame->GetThread().get(), frame->GetConcreteFrameIndex(), + frame->GetThread()->GetProcess()->GetAddressByteSize(), pc)); + } + } + return rctx; +} + +bool +HistoryUnwind::DoGetFrameInfoAtIndex (uint32_t frame_idx, lldb::addr_t& cfa, lldb::addr_t& pc) +{ + Mutex::Locker (m_unwind_mutex); + if (frame_idx < m_pcs.size()) + { + cfa = frame_idx; + pc = m_pcs[frame_idx]; + return true; + } + return false; +} + +uint32_t +HistoryUnwind::DoGetFrameCount () +{ + return m_pcs.size(); +} diff --git a/source/Plugins/Process/Utility/HistoryUnwind.h b/source/Plugins/Process/Utility/HistoryUnwind.h new file mode 100644 index 000000000000..0661b8028608 --- /dev/null +++ b/source/Plugins/Process/Utility/HistoryUnwind.h @@ -0,0 +1,51 @@ +//===-- HistoryUnwind.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_HistoryUnwind_h_ +#define liblldb_HistoryUnwind_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Target/Unwind.h" + +namespace lldb_private { + +class HistoryUnwind : public lldb_private::Unwind +{ +public: + HistoryUnwind (Thread &thread, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid); + + virtual ~HistoryUnwind (); + +protected: + void + DoClear(); + + lldb::RegisterContextSP + DoCreateRegisterContextForFrame (StackFrame *frame); + + bool + DoGetFrameInfoAtIndex (uint32_t frame_idx, + lldb::addr_t& cfa, + lldb::addr_t& pc); + uint32_t + DoGetFrameCount (); + +private: + + std::vector<lldb::addr_t> m_pcs; + uint32_t m_stop_id; + bool m_stop_id_is_valid; +}; + +} // namespace lldb_private + +#endif // liblldb_HistoryUnwind_h_ diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 8b22d6457ada..6d1b04f7f1a7 100644 --- a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -59,11 +59,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, { const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; const bool use_inline_block_range = false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); addr_t prot_arg, flags_arg = 0; if (prot == eMmapProtNone) @@ -88,19 +90,13 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, { ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + lldb::addr_t args[] = { addr, length, prot_arg, flags_arg, fd, offset }; ThreadPlanCallFunction *call_function_thread_plan = new ThreadPlanCallFunction (*thread, mmap_range.GetBaseAddress(), clang_void_ptr_type, - stop_other_threads, - unwind_on_error, - ignore_breakpoints, - &addr, - &length, - &prot_arg, - &flags_arg, - &fd, - &offset); + args, + options); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { @@ -115,12 +111,8 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, ExecutionContext exe_ctx; frame->CalculateExecutionContext (exe_ctx); ExecutionResults result = process->RunThreadPlan (exe_ctx, - call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, + call_plan_sp, + options, error_strm); if (result == eExecutionCompleted) { @@ -169,56 +161,52 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, SymbolContext sc; if (sc_list.GetContextAtIndex(0, sc)) { - const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; - const bool use_inline_block_range = false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol; + const bool use_inline_block_range = false; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); - AddressRange munmap_range; - if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) - { - lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, + AddressRange munmap_range; + if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) + { + lldb::addr_t args[] = { addr, length }; + lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread, munmap_range.GetBaseAddress(), ClangASTType(), - stop_other_threads, - unwind_on_error, - ignore_breakpoints, - &addr, - &length)); - if (call_plan_sp) - { - StreamFile error_strm; - // This plan is a utility plan, so set it to discard itself when done. - call_plan_sp->SetIsMasterPlan (true); - call_plan_sp->SetOkayToDiscard(true); + args, + options)); + if (call_plan_sp) + { + StreamFile error_strm; + // This plan is a utility plan, so set it to discard itself when done. + call_plan_sp->SetIsMasterPlan (true); + call_plan_sp->SetOkayToDiscard(true); - StackFrame *frame = thread->GetStackFrameAtIndex (0).get(); - if (frame) - { - ExecutionContext exe_ctx; - frame->CalculateExecutionContext (exe_ctx); - ExecutionResults result = process->RunThreadPlan (exe_ctx, - call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, - error_strm); - if (result == eExecutionCompleted) - { - return true; - } - } - } - } - } - } + StackFrame *frame = thread->GetStackFrameAtIndex (0).get(); + if (frame) + { + ExecutionContext exe_ctx; + frame->CalculateExecutionContext (exe_ctx); + ExecutionResults result = process->RunThreadPlan (exe_ctx, + call_plan_sp, + options, + error_strm); + if (result == eExecutionCompleted) + { + return true; + } + } + } + } + } + } - return false; + return false; } bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { @@ -226,11 +214,13 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t if (thread == NULL || address == NULL) return false; - const bool stop_other_threads = true; - const bool unwind_on_error = true; - const bool ignore_breakpoints = true; - const bool try_all_threads = true; - const uint32_t timeout_usec = 500000; + EvaluateExpressionOptions options; + options.SetStopOthers(true); + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetTryAllThreads(true); + options.SetDebug (false); + options.SetTimeoutUsec(500000); ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -238,9 +228,8 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t = new ThreadPlanCallFunction (*thread, *address, clang_void_ptr_type, - stop_other_threads, - unwind_on_error, - ignore_breakpoints); + llvm::ArrayRef<addr_t>(), + options); lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { @@ -256,11 +245,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t frame->CalculateExecutionContext (exe_ctx); ExecutionResults result = process->RunThreadPlan (exe_ctx, call_plan_sp, - stop_other_threads, - try_all_threads, - unwind_on_error, - ignore_breakpoints, - timeout_usec, + options, error_strm); if (result == eExecutionCompleted) { diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.cpp b/source/Plugins/Process/Utility/RegisterContextHistory.cpp new file mode 100644 index 000000000000..b7adb202ba49 --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextHistory.cpp @@ -0,0 +1,138 @@ +//===-- RegisterContextHistory.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/Core/Address.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/DynamicLoader.h" + +#include "RegisterContextHistory.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextHistory::RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, addr_t pc_value) : +RegisterContext (thread, concrete_frame_idx), + m_pc_value (pc_value) +{ + m_reg_set0.name = "General Purpose Registers"; + m_reg_set0.short_name = "GPR"; + m_reg_set0.num_registers = 1; + m_reg_set0.registers = new uint32_t(0); + + m_pc_reg_info.name = "pc"; + m_pc_reg_info.alt_name = "pc"; + m_pc_reg_info.byte_offset = 0; + m_pc_reg_info.byte_size = address_byte_size; + m_pc_reg_info.encoding = eEncodingUint; + m_pc_reg_info.format = eFormatPointer; + m_pc_reg_info.invalidate_regs = NULL; + m_pc_reg_info.value_regs = NULL; + m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; + m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM; + m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM; +} + +RegisterContextHistory::~RegisterContextHistory () +{ + delete m_reg_set0.registers; + delete m_pc_reg_info.invalidate_regs; + delete m_pc_reg_info.value_regs; +} + +void +RegisterContextHistory::InvalidateAllRegisters () {} + +size_t +RegisterContextHistory::GetRegisterCount () +{ + return 1; +} + +const lldb_private::RegisterInfo * +RegisterContextHistory::GetRegisterInfoAtIndex (size_t reg) +{ + if (reg) + return NULL; + return &m_pc_reg_info; +} + +size_t +RegisterContextHistory::GetRegisterSetCount () +{ + return 1; +} + +const lldb_private::RegisterSet * +RegisterContextHistory::GetRegisterSet (size_t reg_set) +{ + if (reg_set) + return NULL; + return &m_reg_set0; +} + +bool +RegisterContextHistory::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) +{ + if (!reg_info) + return false; + uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric]; + if (reg_number == LLDB_REGNUM_GENERIC_PC) + { + value.SetUInt(m_pc_value, reg_info->byte_size); + return true; + } + return false; +} + +bool +RegisterContextHistory::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) +{ + return false; +} + +bool +RegisterContextHistory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextHistory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) +{ + return false; +} + +uint32_t +RegisterContextHistory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) +{ + if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC) + return 0; + return LLDB_INVALID_REGNUM; +} diff --git a/source/Plugins/Process/Utility/RegisterContextHistory.h b/source/Plugins/Process/Utility/RegisterContextHistory.h new file mode 100644 index 000000000000..58e16080b52e --- /dev/null +++ b/source/Plugins/Process/Utility/RegisterContextHistory.h @@ -0,0 +1,79 @@ +//===-- RegisterContextHistory.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef lldb_RegisterContextHistory_h_ +#define lldb_RegisterContextHistory_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Symbol/SymbolContext.h" + +namespace lldb_private { + +class RegisterContextHistory : public lldb_private::RegisterContext +{ +public: + typedef std::shared_ptr<RegisterContextHistory> SharedPtr; + + RegisterContextHistory (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size, lldb::addr_t pc_value); + + /// + // pure virtual functions from the base class that we must implement + /// + + virtual + ~RegisterContextHistory (); + + virtual void + InvalidateAllRegisters (); + + virtual size_t + GetRegisterCount (); + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (size_t reg); + + virtual size_t + GetRegisterSetCount (); + + virtual const lldb_private::RegisterSet * + GetRegisterSet (size_t reg_set); + + virtual bool + ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + virtual bool + ReadAllRegisterValues (lldb::DataBufferSP &data_sp); + + virtual bool + WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + + virtual uint32_t + ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); + +private: + //------------------------------------------------------------------ + // For RegisterContextLLDB only + //------------------------------------------------------------------ + + lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only) + lldb_private::RegisterInfo m_pc_reg_info; + + lldb::addr_t m_pc_value; + + DISALLOW_COPY_AND_ASSIGN (RegisterContextHistory); +}; +} // namespace lldb_private + +#endif // lldb_RegisterContextHistory_h_ diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp index acb3154f6290..93641ede1bc7 100644 --- a/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -363,71 +363,6 @@ enum { NT_FREEBSD_PROCSTAT_AUXV = 16 }; -/// Note Structure found in ELF core dumps. -/// This is PT_NOTE type program/segments in the core file. -struct ELFNote -{ - elf::elf_word n_namesz; - elf::elf_word n_descsz; - elf::elf_word n_type; - - std::string n_name; - - ELFNote() : n_namesz(0), n_descsz(0), n_type(0) - { - } - - /// Parse an ELFNote entry from the given DataExtractor starting at position - /// \p offset. - /// - /// @param[in] data - /// The DataExtractor to read from. - /// - /// @param[in,out] offset - /// Pointer to an offset in the data. On return the offset will be - /// advanced by the number of bytes read. - /// - /// @return - /// True if the ELFRel entry was successfully read and false otherwise. - bool - Parse(const DataExtractor &data, lldb::offset_t *offset) - { - // Read all fields. - if (data.GetU32(offset, &n_namesz, 3) == NULL) - return false; - - // The name field is required to be nul-terminated, and n_namesz - // includes the terminating nul in observed implementations (contrary - // to the ELF-64 spec). A special case is needed for cores generated - // by some older Linux versions, which write a note named "CORE" - // without a nul terminator and n_namesz = 4. - if (n_namesz == 4) - { - char buf[4]; - if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4) - return false; - if (strncmp (buf, "CORE", 4) == 0) - { - n_name = "CORE"; - *offset += 4; - return true; - } - } - - const char *cstr = data.GetCStr(offset, llvm::RoundUpToAlignment(n_namesz, 4)); - if (cstr == NULL) - { - Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); - if (log) - log->Printf("Failed to parse note name lacking nul terminator"); - - return false; - } - n_name = cstr; - return true; - } -}; - // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2ac7d20c6c60..2690992eeed3 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -65,6 +65,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), + m_supports_QSaveRegisterState (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -110,17 +111,35 @@ GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() bool GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) { + ResetDiscoverableSettings(); + // Start the read thread after we send the handshake ack since if we // fail to send the handshake ack, there is no reason to continue... if (SendAck()) - return true; - - if (error_ptr) - error_ptr->SetErrorString("failed to send the handshake ack"); + { + // The return value from QueryNoAckModeSupported() is true if the packet + // was sent and _any_ response (including UNIMPLEMENTED) was received), + // or false if no response was received. This quickly tells us if we have + // a live connection to a remote GDB server... + if (QueryNoAckModeSupported()) + { + return true; + } + else + { + if (error_ptr) + error_ptr->SetErrorString("failed to get reply to handshake packet"); + } + } + else + { + if (error_ptr) + error_ptr->SetErrorString("failed to send the handshake ack"); + } return false; } -void +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported () { if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -136,8 +155,10 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_send_acks = false; m_supports_not_sending_acks = eLazyBoolYes; } + return true; } } + return false; } void @@ -208,6 +229,7 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; + m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_qProcessInfo_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; @@ -987,19 +1009,43 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) } int -GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[]) -{ - if (argv && argv[0]) +GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) +{ + // Since we don't get the send argv0 separate from the executable path, we need to + // make sure to use the actual exectuable path found in the launch_info... + std::vector<const char *> argv; + FileSpec exe_file = launch_info.GetExecutableFile(); + std::string exe_path; + const char *arg = NULL; + const Args &launch_args = launch_info.GetArguments(); + if (exe_file) + exe_path = exe_file.GetPath(); + else + { + arg = launch_args.GetArgumentAtIndex(0); + if (arg) + exe_path = arg; + } + if (!exe_path.empty()) + { + argv.push_back(exe_path.c_str()); + for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) + { + if (arg) + argv.push_back(arg); + } + } + if (!argv.empty()) { StreamString packet; packet.PutChar('A'); - const char *arg; - for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i) + for (size_t i = 0, n = argv.size(); i < n; ++i) { + arg = argv[i]; const int arg_len = strlen(arg); if (i > 0) packet.PutChar(','); - packet.Printf("%i,%i,", arg_len * 2, i); + packet.Printf("%i,%i,", arg_len * 2, (int)i); packet.PutBytesAsRawHex8 (arg, arg_len); } @@ -1783,6 +1829,22 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) return -1; } +bool +GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) +{ + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) + { + if (response.IsUnsupportedResponse()) + return false; + if (response.IsErrorResponse()) + return false; + response.GetHexByteString (cwd); + return !cwd.empty(); + } + return false; +} + int GDBRemoteCommunicationClient::SetWorkingDir (char const *path) { @@ -2244,7 +2306,7 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; StreamString stream; - stream.PutCString("qLaunchGDBServer:port:0;"); + stream.PutCString("qLaunchGDBServer;"); std::string hostname; if (Host::GetHostname (hostname)) { @@ -2495,7 +2557,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish { lldb_private::StreamString stream; - stream.PutCString("qPlatform_RunCommand:"); + stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); stream.PutHex32(timeout_sec); @@ -2534,24 +2596,44 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // return Error("unable to send packet"); } -uint32_t -GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, - mode_t mode) +Error +GDBRemoteCommunicationClient::MakeDirectory (const char *path, + uint32_t file_permissions) { lldb_private::StreamString stream; - stream.PutCString("qPlatform_IO_MkDir:"); - stream.PutHex32(mode); + stream.PutCString("qPlatform_mkdir:"); + stream.PutHex32(file_permissions); stream.PutChar(','); - stream.PutBytesAsRawHex8(path.c_str(), path.size()); + stream.PutBytesAsRawHex8(path, strlen(path)); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) { - return response.GetHexMaxU32(false, UINT32_MAX); + return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } - return UINT32_MAX; + return Error(); + +} +Error +GDBRemoteCommunicationClient::SetFilePermissions (const char *path, + uint32_t file_permissions) +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_chmod:"); + stream.PutHex32(file_permissions); + stream.PutChar(','); + stream.PutBytesAsRawHex8(path, strlen(path)); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); + } + return Error(); + } static uint64_t @@ -2641,13 +2723,13 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp return UINT64_MAX; } -uint32_t -GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +Error +GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &file_permissions) { + Error error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); - std::string path (file_spec.GetPath()); - stream.PutCStringAsRawHex8(path.c_str()); + stream.PutCStringAsRawHex8(path); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; @@ -2656,29 +2738,34 @@ GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& f if (response.GetChar() != 'F') { error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); - return 0; } - const uint32_t mode = response.GetS32(-1); - if (mode == -1) + else { - if (response.GetChar() == ',') + const uint32_t mode = response.GetS32(-1); + if (mode == -1) { - int response_errno = response.GetS32(-1); - if (response_errno > 0) - error.SetError(response_errno, lldb::eErrorTypePOSIX); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } else error.SetErrorToGenericError(); } + else + { + file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } } - else - error.Clear(); - return mode & (S_IRWXU|S_IRWXG|S_IRWXO); } else { error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); } - return 0; + return error; } uint64_t @@ -2760,6 +2847,90 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, return 0; } +Error +GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:symlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(dst); + stream.PutChar(','); + stream.PutCStringAsRawHex8(src); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("symlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:symlink packet"); + } + return error; +} + +Error +GDBRemoteCommunicationClient::Unlink (const char *path) +{ + Error error; + lldb_private::StreamGDBRemote stream; + stream.PutCString("vFile:unlink:"); + // the unix symlink() command reverses its parameters where the dst if first, + // so we follow suit here + stream.PutCStringAsRawHex8(path); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() == 'F') + { + uint32_t result = response.GetU32(UINT32_MAX); + if (result != 0) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + } + } + else + { + // Should have returned with 'F<result>[,<errno>]' + error.SetErrorStringWithFormat("unlink failed"); + } + } + else + { + error.SetErrorString ("failed to send vFile:unlink packet"); + } + return error; +} + // Extension of host I/O packets to get whether a file exists. bool GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) @@ -2809,3 +2980,134 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s } return false; } + +bool +GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; + +} + + +bool +GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) +{ + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[64]; + int packet_len = 0; + // Get all registers in one packet + if (thread_suffix_supported) + packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); + else + packet_len = ::snprintf (packet, sizeof(packet), "g"); + assert (packet_len < ((int)sizeof(packet) - 1)); + return SendPacketAndWaitForResponse(packet, response, false); + } + } + return false; +} +bool +GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) +{ + save_id = 0; // Set to invalid save ID + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + m_supports_QSaveRegisterState = eLazyBoolYes; + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); + else + ::strncpy (packet, "QSaveRegisterState", sizeof(packet)); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling it again + m_supports_QSaveRegisterState = eLazyBoolNo; + } + + const uint32_t response_save_id = response.GetU32(0); + if (response_save_id != 0) + { + save_id = response_save_id; + return true; + } + } + } + } + return false; +} + +bool +GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) +{ + // We use the "m_supports_QSaveRegisterState" variable here becuase the + // QSaveRegisterState and QRestoreRegisterState packets must both be supported in + // order to be useful + if (m_supports_QSaveRegisterState == eLazyBoolNo) + return false; + + Mutex::Locker locker; + if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) + { + const bool thread_suffix_supported = GetThreadSuffixSupported(); + if (thread_suffix_supported || SetCurrentThread(tid)) + { + char packet[256]; + if (thread_suffix_supported) + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); + else + ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); + + StringExtractorGDBRemote response; + + if (SendPacketAndWaitForResponse(packet, response, false)) + { + if (response.IsOKResponse()) + { + return true; + } + else if (response.IsUnsupportedResponse()) + { + // This packet isn't supported, don't try calling this packet or + // QSaveRegisterState again... + m_supports_QSaveRegisterState = eLazyBoolNo; + } + } + } + } + return false; +} diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d5535bbb1df3..564afbb2911c 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -38,7 +38,6 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationClient(bool is_platform); - virtual ~GDBRemoteCommunicationClient(); //------------------------------------------------------------------ @@ -65,10 +64,16 @@ public: size_t packet_length, StringExtractorGDBRemote &response); - virtual bool + bool GetThreadSuffixSupported (); - void + // This packet is usually sent first and the boolean return value + // indicates if the packet was send and any response was received + // even in the response is UNIMPLEMENTED. If the packet failed to + // get a response, then false is returned. This quickly tells us + // if we were able to connect and communicte with the remote GDB + // server + bool QueryNoAckModeSupported (); void @@ -109,7 +114,7 @@ public: /// response was received. //------------------------------------------------------------------ int - SendArgumentsPacket (char const *argv[]); + SendArgumentsPacket (const lldb_private::ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the @@ -185,7 +190,10 @@ public: //------------------------------------------------------------------ /// Sets the working directory to \a path for a process that will - /// be launched with the 'A' packet. + /// be launched with the 'A' packet for non platform based + /// connections. If this packet is sent to a GDB server that + /// implements the platform, it will change the current working + /// directory for the platform process. /// /// @param[in] path /// The path to a directory to use when launching our processs @@ -196,6 +204,19 @@ public: int SetWorkingDir (char const *path); + //------------------------------------------------------------------ + /// Gets the current working directory of a remote platform GDB + /// server. + /// + /// @param[out] cwd + /// The current working directory on the remote platform. + /// + /// @return + /// Boolean for success + //------------------------------------------------------------------ + bool + GetWorkingDir (std::string &cwd); + lldb::addr_t AllocateMemory (size_t size, uint32_t permissions); @@ -356,45 +377,54 @@ public: return m_interrupt_sent; } - virtual lldb::user_id_t + lldb::user_id_t OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, mode_t mode, lldb_private::Error &error); - virtual bool + bool CloseFile (lldb::user_id_t fd, lldb_private::Error &error); - virtual lldb::user_id_t + lldb::user_id_t GetFileSize (const lldb_private::FileSpec& file_spec); - virtual uint32_t - GetFilePermissions(const lldb_private::FileSpec& file_spec, - lldb_private::Error &error); + lldb_private::Error + GetFilePermissions(const char *path, uint32_t &file_permissions); + + lldb_private::Error + SetFilePermissions(const char *path, uint32_t file_permissions); - virtual uint64_t + uint64_t ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, lldb_private::Error &error); - virtual uint64_t + uint64_t WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, lldb_private::Error &error); - virtual uint32_t - MakeDirectory (const std::string &path, - mode_t mode); + lldb_private::Error + CreateSymlink (const char *src, + const char *dst); - virtual bool + lldb_private::Error + Unlink (const char *path); + + lldb_private::Error + MakeDirectory (const char *path, + uint32_t mode); + + bool GetFileExists (const lldb_private::FileSpec& file_spec); - virtual lldb_private::Error + lldb_private::Error RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -402,7 +432,7 @@ public: std::string *command_output, // Pass NULL if you don't want the command output uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish - virtual bool + bool CalculateMD5 (const lldb_private::FileSpec& file_spec, uint64_t &high, uint64_t &low); @@ -411,6 +441,21 @@ public: HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process, StringExtractorGDBRemote &inputStringExtractor); + bool + ReadRegister(lldb::tid_t tid, + uint32_t reg_num, + StringExtractorGDBRemote &response); + + bool + ReadAllRegisters (lldb::tid_t tid, + StringExtractorGDBRemote &response); + + bool + SaveRegisterState (lldb::tid_t tid, uint32_t &save_id); + + bool + RestoreRegisterState (lldb::tid_t tid, uint32_t save_id); + protected: bool @@ -438,6 +483,7 @@ protected: lldb_private::LazyBool m_attach_or_wait_reply; lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; + lldb_private::LazyBool m_supports_QSaveRegisterState; bool m_supports_qProcessInfoPID:1, diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index df036cdcc8e0..7cc3a05304d4 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -47,27 +47,9 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_proc_infos (), m_proc_infos_index (0), - m_lo_port_num (0), - m_hi_port_num (0), - m_next_port (0), - m_use_port_range (false) + m_port_map (), + m_port_offset(0) { - // We seldom need to override the port number that the debugserver process - // starts with. We just pass in 0 to let the system choose a random port. - // In rare situation where the need arises, use two environment variables - // to override. - uint16_t lo_port_num = 0; - uint16_t hi_port_num = 0; - const char *lo_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_LO_PORT"); - if (lo_port_c_str) - lo_port_num = ::atoi(lo_port_c_str); - const char *hi_port_c_str = getenv("LLDB_PLATFORM_START_DEBUG_SERVER_HI_PORT"); - if (hi_port_c_str) - hi_port_num = ::atoi(hi_port_c_str); - if (lo_port_num && hi_port_num && lo_port_num < hi_port_num) - { - SetPortRange(lo_port_num, hi_port_num); - } } //---------------------------------------------------------------------- @@ -166,6 +148,9 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_qUserName: return Handle_qUserName (packet); + case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: + return Handle_qGetWorkingDir(packet); + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: return Handle_QEnvironment (packet); @@ -190,38 +175,47 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: return Handle_QStartNoAckMode (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_IO_MkDir: - return Handle_qPlatform_IO_MkDir (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: + return Handle_qPlatform_mkdir (packet); - case StringExtractorGDBRemote::eServerPacketType_qPlatform_RunCommand: - return Handle_qPlatform_RunCommand (packet); + case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: + return Handle_qPlatform_chmod (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Open: + case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: + return Handle_qPlatform_shell (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_open: return Handle_vFile_Open (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Close: + case StringExtractorGDBRemote::eServerPacketType_vFile_close: return Handle_vFile_Close (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pRead: + case StringExtractorGDBRemote::eServerPacketType_vFile_pread: return Handle_vFile_pRead (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_pWrite: + case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: return Handle_vFile_pWrite (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Size: + case StringExtractorGDBRemote::eServerPacketType_vFile_size: return Handle_vFile_Size (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Mode: + case StringExtractorGDBRemote::eServerPacketType_vFile_mode: return Handle_vFile_Mode (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Exists: + case StringExtractorGDBRemote::eServerPacketType_vFile_exists: return Handle_vFile_Exists (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_Stat: + case StringExtractorGDBRemote::eServerPacketType_vFile_stat: return Handle_vFile_Stat (packet); - case StringExtractorGDBRemote::eServerPacketType_vFile_MD5: + case StringExtractorGDBRemote::eServerPacketType_vFile_md5: return Handle_vFile_MD5 (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: + return Handle_vFile_symlink (packet); + + case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: + return Handle_vFile_unlink (packet); } return true; } @@ -329,12 +323,33 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#if defined(__APPLE__) + +#if defined(__arm__) + // For iOS devices, we are connected through a USB Mux so we never pretend + // to actually have a hostname as far as the remote lldb that is connecting + // to this lldb-platform is concerned + response.PutCString ("hostname:"); + response.PutCStringAsRawHex8("localhost"); + response.PutChar(';'); +#else // #if defined(__arm__) + if (Host::GetHostname (s)) + { + response.PutCString ("hostname:"); + response.PutCStringAsRawHex8(s.c_str()); + response.PutChar(';'); + } + +#endif // #if defined(__arm__) + +#else // #if defined(__APPLE__) if (Host::GetHostname (s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } +#endif // #if defined(__APPLE__) return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; } @@ -731,6 +746,7 @@ bool GDBRemoteCommunicationServer::DebugserverProcessReaped (lldb::pid_t pid) { Mutex::Locker locker (m_spawned_pids_mutex); + FreePortForProcess(pid); return m_spawned_pids.erase(pid) > 0; } bool @@ -764,105 +780,119 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp // with the TMPDIR environnement variable - char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX"; - if (::mkstemp (unix_socket_name) == -1) + packet.SetFilePos(::strlen ("qLaunchGDBServer;")); + std::string name; + std::string value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) { - error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); + if (name.compare ("host") == 0) + hostname.swap(value); + else if (name.compare ("port") == 0) + port = Args::StringToUInt32(value.c_str(), 0, 0); } - else - { - packet.SetFilePos(::strlen ("qLaunchGDBServer:")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = Args::StringToUInt32(value.c_str(), 0, 0); - } - if (port == UINT16_MAX) - port = GetAndUpdateNextPort(); + if (port == UINT16_MAX) + port = GetNextAvailablePort(); - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); - // Spawn a new thread to accept the port that gets bound after - // binding to port 0 (zero). - lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; + // Spawn a new thread to accept the port that gets bound after + // binding to port 0 (zero). + lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; + const char *unix_socket_name = NULL; + char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; - if (port == 0) + if (port == 0) + { + if (::mkstemp (unix_socket_name_buf) == 0) { + unix_socket_name = unix_socket_name_buf; + ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); accept_thread = Host::ThreadCreate (unix_socket_name, AcceptPortFromInferior, connect_url, &error); } + else + { + error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); + } + } - if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) + if (error.Success()) + { + // Spawn a debugserver and try to get the port it listens to. + ProcessLaunchInfo debugserver_launch_info; + StreamString host_and_port; + if (hostname.empty()) + hostname = "localhost"; + host_and_port.Printf("%s:%u", hostname.c_str(), port); + const char *host_and_port_cstr = host_and_port.GetString().c_str(); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); + + debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); + + error = StartDebugserverProcess (host_and_port_cstr, + unix_socket_name, + debugserver_launch_info); + + lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); + + + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { - // Spawn a debugserver and try to get the port it listens to. - ProcessLaunchInfo debugserver_launch_info; - StreamString host_and_port; - if (hostname.empty()) - hostname = "localhost"; - host_and_port.Printf("%s:%u", hostname.c_str(), port); - const char *host_and_port_cstr = host_and_port.GetString().c_str(); - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); - error = StartDebugserverProcess (host_and_port_cstr, - unix_socket_name, - debugserver_launch_info); - - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - { - { - Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); - } - Host::StartMonitoringChildProcess (ReapDebugserverProcess, this, debugserver_pid, false); - } + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(debugserver_pid); + if (port > 0) + AssociatePortWithProcess(port, debugserver_pid); + } + else + { + if (port > 0) + FreePort (port); + } - if (error.Success()) - { - bool success = false; + if (error.Success()) + { + bool success = false; - if (accept_thread) + if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) + { + thread_result_t accept_thread_result = NULL; + if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) { - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) + if (accept_thread_result) { - if (accept_thread_result) - { - port = (intptr_t)accept_thread_result; - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - } + port = (intptr_t)accept_thread_result; + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < sizeof(response)); + //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); + success = SendPacketNoLock (response, response_len) > 0; } } - else - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; + } + else + { + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < sizeof(response)); + //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); + success = SendPacketNoLock (response, response_len) > 0; - } - ::unlink (unix_socket_name); + } + Host::Unlink (unix_socket_name); - if (!success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return success; + if (!success) + { + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } + return success; + } + else if (accept_thread) + { + Host::Unlink (unix_socket_name); } } } @@ -896,7 +926,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } usleep (10000); } @@ -905,7 +935,7 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } Host::Kill (pid, SIGKILL); @@ -915,12 +945,12 @@ GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemo { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return true; + return SendOKResponse(); } usleep (10000); } } - return SendErrorResponse (10); + return SendErrorResponse (11); } bool @@ -944,7 +974,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); return SendOKResponse (); } - return SendErrorResponse (11); + return SendErrorResponse (12); } bool @@ -959,7 +989,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack m_process_launch_info.SetArchitecture(arch_spec); return SendOKResponse(); } - return SendErrorResponse(12); + return SendErrorResponse(13); } bool @@ -979,11 +1009,61 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p packet.SetFilePos(::strlen ("QSetWorkingDir:")); std::string path; packet.GetHexByteString(path); - m_process_launch_info.SwapWorkingDirectory (path); + if (m_is_platform) + { +#ifdef _WIN32 + // Not implemented on Windows + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_QSetWorkingDir unimplemented"); +#else + // If this packet is sent to a platform, then change the current working directory + if (::chdir(path.c_str()) != 0) + return SendErrorResponse(errno); +#endif + } + else + { + m_process_launch_info.SwapWorkingDirectory (path); + } return SendOKResponse (); } bool +GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) +{ + StreamString response; + + if (m_is_platform) + { + // If this packet is sent to a platform, then change the current working directory + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) == NULL) + { + return SendErrorResponse(errno); + } + else + { + response.PutBytesAsRawHex8(cwd, strlen(cwd)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + } + else + { + const char *working_dir = m_process_launch_info.GetWorkingDirectory(); + if (working_dir && working_dir[0]) + { + response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + SendPacketNoLock(response.GetData(), response.GetSize()); + return true; + } + else + { + return SendErrorResponse(14); + } + } +} + +bool GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -997,7 +1077,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (13); + return SendErrorResponse (15); } bool @@ -1014,7 +1094,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (14); + return SendErrorResponse (16); } bool @@ -1031,7 +1111,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } - return SendErrorResponse (15); + return SendErrorResponse (17); } bool @@ -1044,19 +1124,40 @@ GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote & } bool -GDBRemoteCommunicationServer::Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_IO_MkDir:")); + packet.SetFilePos(::strlen("qPlatform_mkdir:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() != ',') - return false; - std::string path; - packet.GetHexByteString(path); - uint32_t retcode = Host::MakeDirectory(path.c_str(),mode); - StreamString response; - response.PutHex32(retcode); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (packet.GetChar() == ',') + { + std::string path; + packet.GetHexByteString(path); + Error error = Host::MakeDirectory(path.c_str(),mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); + } + return SendErrorResponse(20); +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_chmod:")); + + mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); + if (packet.GetChar() == ',') + { + std::string path; + packet.GetHexByteString(path); + Error error = Host::SetFilePermissions (path.c_str(), mode); + if (error.Success()) + return SendPacketNoLock ("OK", 2); + else + return SendErrorResponse(error.GetError()); + } + return SendErrorResponse(19); } bool @@ -1065,24 +1166,28 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:open:")); std::string path; packet.GetHexByteStringTerminatedBy(path,','); - if (path.size() == 0) - return false; - if (packet.GetChar() != ',') - return false; - uint32_t flags = packet.GetHexMaxU32(false, UINT32_MAX); - if (packet.GetChar() != ',') - return false; - mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); - Error error; - int fd = ::open (path.c_str(), flags, mode); - const int save_errno = fd == -1 ? errno : 0; - StreamString response; - response.PutChar('F'); - response.Printf("%i", fd); - if (save_errno) - response.Printf(",%i", save_errno); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (!path.empty()) + { + if (packet.GetChar() == ',') + { + uint32_t flags = packet.GetHexMaxU32(false, 0); + if (packet.GetChar() == ',') + { + mode_t mode = packet.GetHexMaxU32(false, 0600); + Error error; + int fd = ::open (path.c_str(), flags, mode); + printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>"); + const int save_errno = fd == -1 ? errno : 0; + StreamString response; + response.PutChar('F'); + response.Printf("%i", fd); + if (save_errno) + response.Printf(",%i", save_errno); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + } + } + return SendErrorResponse(18); } bool @@ -1107,8 +1212,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack response.Printf("%i", err); if (save_errno) response.Printf(",%i", save_errno); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } bool @@ -1116,37 +1220,40 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack { #ifdef _WIN32 // Not implemented on Windows - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pRead() unimplemented"); #else StreamGDBRemote response; packet.SetFilePos(::strlen("vFile:pread:")); int fd = packet.GetS32(-1); - if (packet.GetChar() != ',') - return false; - uint64_t count = packet.GetU64(UINT64_MAX); - if (packet.GetChar() != ',') - return false; - uint64_t offset = packet.GetU64(UINT32_MAX); - if (count == UINT64_MAX) - { - response.Printf("F-1:%i", EINVAL); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; - } - std::string buffer(count, 0); - const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); - const int save_errno = bytes_read == -1 ? errno : 0; - response.PutChar('F'); - response.Printf("%zi", bytes_read); - if (save_errno) - response.Printf(",%i", save_errno); - else + if (packet.GetChar() == ',') { - response.PutChar(';'); - response.PutEscapedBytes(&buffer[0], bytes_read); + uint64_t count = packet.GetU64(UINT64_MAX); + if (packet.GetChar() == ',') + { + uint64_t offset = packet.GetU64(UINT32_MAX); + if (count == UINT64_MAX) + { + response.Printf("F-1:%i", EINVAL); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + + std::string buffer(count, 0); + const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); + const int save_errno = bytes_read == -1 ? errno : 0; + response.PutChar('F'); + response.Printf("%zi", bytes_read); + if (save_errno) + response.Printf(",%i", save_errno); + else + { + response.PutChar(';'); + response.PutEscapedBytes(&buffer[0], bytes_read); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(21); + #endif } @@ -1154,8 +1261,7 @@ bool GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // Not implemented on Windows - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_pWrite() unimplemented"); #else packet.SetFilePos(::strlen("vFile:pwrite:")); @@ -1163,27 +1269,28 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac response.PutChar('F'); int fd = packet.GetU32(UINT32_MAX); - if (packet.GetChar() != ',') - return false; - off_t offset = packet.GetU64(UINT32_MAX); - if (packet.GetChar() != ',') - return false; - std::string buffer; - if (packet.GetEscapedBinaryData(buffer)) - { - const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); - const int save_errno = bytes_written == -1 ? errno : 0; - response.Printf("%zi", bytes_written); - if (save_errno) - response.Printf(",%i", save_errno); - } - else + if (packet.GetChar() == ',') { - response.Printf ("-1,%i", EINVAL); + off_t offset = packet.GetU64(UINT32_MAX); + if (packet.GetChar() == ',') + { + std::string buffer; + if (packet.GetEscapedBinaryData(buffer)) + { + const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); + const int save_errno = bytes_written == -1 ? errno : 0; + response.Printf("%zi", bytes_written); + if (save_errno) + response.Printf(",%i", save_errno); + } + else + { + response.Printf ("-1,%i", EINVAL); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(27); #endif } @@ -1193,19 +1300,20 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:size:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); - StreamString response; - response.PutChar('F'); - response.PutHex64(retcode); - if (retcode == UINT64_MAX) + if (!path.empty()) { - response.PutChar(','); - response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() + lldb::user_id_t retcode = Host::GetFileSize(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutHex64(retcode); + if (retcode == UINT64_MAX) + { + response.PutChar(','); + response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() + } + return SendPacketNoLock(response.GetData(), response.GetSize()); } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(22); } bool @@ -1214,16 +1322,17 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe packet.SetFilePos(::strlen("vFile:mode:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - Error error; - const uint32_t mode = File::GetPermissions(path.c_str(), error); - StreamString response; - response.Printf("F%u", mode); - if (mode == 0 || error.Fail()) - response.Printf(",%i", (int)error.GetError()); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + if (!path.empty()) + { + Error error; + const uint32_t mode = File::GetPermissions(path.c_str(), error); + StreamString response; + response.Printf("F%u", mode); + if (mode == 0 || error.Fail()) + response.Printf(",%i", (int)error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + return SendErrorResponse(23); } bool @@ -1232,87 +1341,118 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac packet.SetFilePos(::strlen("vFile:exists:")); std::string path; packet.GetHexByteString(path); - if (path.empty()) - return false; - bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + if (!path.empty()) + { + bool retcode = Host::GetFileExists(FileSpec(path.c_str(), false)); + StreamString response; + response.PutChar('F'); + response.PutChar(','); + if (retcode) + response.PutChar('1'); + else + response.PutChar('0'); + return SendPacketNoLock(response.GetData(), response.GetSize()); + } + return SendErrorResponse(24); +} + +bool +GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("vFile:symlink:")); + std::string dst, src; + packet.GetHexByteStringTerminatedBy(dst, ','); + packet.GetChar(); // Skip ',' char + packet.GetHexByteString(src); + Error error = Host::Symlink(src.c_str(), dst.c_str()); StreamString response; - response.PutChar('F'); - response.PutChar(','); - if (retcode) - response.PutChar('1'); - else - response.PutChar('0'); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); } bool -GDBRemoteCommunicationServer::Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("qPlatform_RunCommand:")); + packet.SetFilePos(::strlen("vFile:unlink:")); + std::string path; + packet.GetHexByteString(path); + Error error = Host::Unlink(path.c_str()); + StreamString response; + response.Printf("F%u,%u", error.GetError(), error.GetError()); + return SendPacketNoLock(response.GetData(), response.GetSize()); +} + +bool +GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen("qPlatform_shell:")); std::string path; std::string working_dir; packet.GetHexByteStringTerminatedBy(path,','); - if (path.size() == 0) - return false; - if (packet.GetChar() != ',') - return false; - // FIXME: add timeout to qPlatform_RunCommand packet - // uint32_t timeout = packet.GetHexMaxU32(false, 32); - uint32_t timeout = 10; - if (packet.GetChar() == ',') - packet.GetHexByteString(working_dir); - int status, signo; - std::string output; - Error err = Host::RunShellCommand(path.c_str(), - working_dir.empty() ? NULL : working_dir.c_str(), - &status, &signo, &output, timeout); - StreamGDBRemote response; - if (err.Fail()) + if (!path.empty()) { - response.PutCString("F,"); - response.PutHex32(UINT32_MAX); - } - else - { - response.PutCString("F,"); - response.PutHex32(status); - response.PutChar(','); - response.PutHex32(signo); - response.PutChar(','); - response.PutEscapedBytes(output.c_str(), output.size()); + if (packet.GetChar() == ',') + { + // FIXME: add timeout to qPlatform_shell packet + // uint32_t timeout = packet.GetHexMaxU32(false, 32); + uint32_t timeout = 10; + if (packet.GetChar() == ',') + packet.GetHexByteString(working_dir); + int status, signo; + std::string output; + Error err = Host::RunShellCommand(path.c_str(), + working_dir.empty() ? NULL : working_dir.c_str(), + &status, &signo, &output, timeout); + StreamGDBRemote response; + if (err.Fail()) + { + response.PutCString("F,"); + response.PutHex32(UINT32_MAX); + } + else + { + response.PutCString("F,"); + response.PutHex32(status); + response.PutChar(','); + response.PutHex32(signo); + response.PutChar(','); + response.PutEscapedBytes(output.c_str(), output.size()); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); + } } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(24); } bool GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { - return false; + return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented"); } bool GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) { - packet.SetFilePos(::strlen("vFile:exists:")); + packet.SetFilePos(::strlen("vFile:MD5:")); std::string path; packet.GetHexByteString(path); - if (path.size() == 0) - return false; - uint64_t a,b; - StreamGDBRemote response; - if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + if (!path.empty()) { - response.PutCString("F,"); - response.PutCString("x"); - } - else - { - response.PutCString("F,"); - response.PutHex64(a); - response.PutHex64(b); + uint64_t a,b; + StreamGDBRemote response; + if (Host::CalculateMD5(FileSpec(path.c_str(),false),a,b) == false) + { + response.PutCString("F,"); + response.PutCString("x"); + } + else + { + response.PutCString("F,"); + response.PutHex64(a); + response.PutHex64(b); + } + return SendPacketNoLock(response.GetData(), response.GetSize()); } - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendErrorResponse(25); } + diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 64f6f8de1a21..721ea5012b33 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -26,6 +26,8 @@ class StringExtractorGDBRemote; class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: + typedef std::map<uint16_t, lldb::pid_t> PortMap; + enum { eBroadcastBitRunPacketSent = kLoUserBroadcastBit @@ -58,30 +60,85 @@ public: // Set both ports to zero to let the platform automatically bind to // a port chosen by the OS. void - SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num) + SetPortMap (PortMap &&port_map) { - m_lo_port_num = lo_port_num; - m_hi_port_num = hi_port_num; - m_next_port = m_lo_port_num; - m_use_port_range = true; + m_port_map = port_map; } - // If we are using a port range, get and update the next port to be used variable. - // Otherwise, just return 0. + //---------------------------------------------------------------------- + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return UINT16_MAX + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + //---------------------------------------------------------------------- uint16_t - GetAndUpdateNextPort () + GetNextAvailablePort () { - if (!m_use_port_range) - return 0; - uint16_t val = m_next_port; - if (++m_next_port > m_hi_port_num) - m_next_port = m_lo_port_num; - return val; + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any limitations + + for (auto &pair : m_port_map) + { + if (pair.second == LLDB_INVALID_PROCESS_ID) + { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; + } + } + return UINT16_MAX; } -protected: - //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap; + bool + AssociatePortWithProcess (uint16_t port, lldb::pid_t pid) + { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) + { + pos->second = pid; + return true; + } + return false; + } + + bool + FreePort (uint16_t port) + { + PortMap::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) + { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; + } + + bool + FreePortForProcess (lldb::pid_t pid) + { + if (!m_port_map.empty()) + { + for (auto &pair : m_port_map) + { + if (pair.second == pid) + { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } + } + } + return false; + } + void + SetPortOffset (uint16_t port_offset) + { + m_port_offset = port_offset; + } + +protected: lldb::thread_t m_async_thread; lldb_private::ProcessLaunchInfo m_process_launch_info; lldb_private::Error m_process_launch_error; @@ -89,11 +146,8 @@ protected: lldb_private::Mutex m_spawned_pids_mutex; lldb_private::ProcessInstanceInfoList m_proc_infos; uint32_t m_proc_infos_index; - uint16_t m_lo_port_num; - uint16_t m_hi_port_num; - //PortToPIDMap m_port_to_pid_map; - uint16_t m_next_port; - bool m_use_port_range; + PortMap m_port_map; + uint16_t m_port_offset; size_t @@ -121,7 +175,10 @@ protected: Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_IO_MkDir (StringExtractorGDBRemote &packet); + Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); + + bool + Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); bool Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); @@ -155,6 +212,9 @@ protected: bool Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); + + bool + Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); bool Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); @@ -188,6 +248,12 @@ protected: bool Handle_vFile_Exists (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_symlink (StringExtractorGDBRemote &packet); + + bool + Handle_vFile_unlink (StringExtractorGDBRemote &packet); bool Handle_vFile_Stat (StringExtractorGDBRemote &packet); @@ -196,7 +262,7 @@ protected: Handle_vFile_MD5 (StringExtractorGDBRemote &packet); bool - Handle_qPlatform_RunCommand (StringExtractorGDBRemote &packet); + Handle_qPlatform_shell (StringExtractorGDBRemote &packet); private: bool diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c4e468f89f35..c291df786d10 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -153,20 +153,13 @@ bool GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; - if (gdb_comm.GetThreadSuffixSupported()) - packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) + StringExtractorGDBRemote response; + if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), reg, response)) return PrivateSetRegisterValue (reg, response); - return false; } + bool GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) { @@ -185,93 +178,51 @@ GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataE if (!GetRegisterIsValid(reg)) { - Mutex::Locker locker; - if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register.")) + if (m_read_all_at_once) { - const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); - ProcessSP process_sp (m_thread.GetProcess()); - if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) + StringExtractorGDBRemote response; + if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) + return false; + if (response.IsNormalResponse()) + if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) + SetAllRegisterValid (true); + } + else if (reg_info->value_regs) + { + // Process this composite register request by delegating to the constituent + // primordial registers. + + // Index of the primordial register. + bool success = true; + for (uint32_t idx = 0; success; ++idx) { - char packet[64]; - StringExtractorGDBRemote response; - int packet_len = 0; - if (m_read_all_at_once) - { - // Get all registers in one packet - if (thread_suffix_supported) - packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); - else - packet_len = ::snprintf (packet, sizeof(packet), "g"); - assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false)) - { - if (response.IsNormalResponse()) - if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) - SetAllRegisterValid (true); - } - } - else if (reg_info->value_regs) - { - // Process this composite register request by delegating to the constituent - // primordial registers. - - // Index of the primordial register. - bool success = true; - for (uint32_t idx = 0; success; ++idx) - { - const uint32_t prim_reg = reg_info->value_regs[idx]; - if (prim_reg == LLDB_INVALID_REGNUM) - break; - // We have a valid primordial regsiter as our constituent. - // Grab the corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); - if (prim_reg_info == NULL) - success = false; - else - { - // Read the containing register if it hasn't already been read - if (!GetRegisterIsValid(prim_reg)) - success = GetPrimordialRegister(prim_reg_info, gdb_comm); - } - } - - if (success) - { - // If we reach this point, all primordial register requests have succeeded. - // Validate this composite register. - SetRegisterIsValid (reg_info, true); - } - } + const uint32_t prim_reg = reg_info->value_regs[idx]; + if (prim_reg == LLDB_INVALID_REGNUM) + break; + // We have a valid primordial regsiter as our constituent. + // Grab the corresponding register info. + const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + if (prim_reg_info == NULL) + success = false; else { - // Get each register individually - GetPrimordialRegister(reg_info, gdb_comm); + // Read the containing register if it hasn't already been read + if (!GetRegisterIsValid(prim_reg)) + success = GetPrimordialRegister(prim_reg_info, gdb_comm); } } + + if (success) + { + // If we reach this point, all primordial register requests have succeeded. + // Validate this composite register. + SetRegisterIsValid (reg_info, true); + } } else { -#if LLDB_CONFIGURATION_DEBUG - StreamString strm; - gdb_comm.DumpHistory(strm); - Host::SetCrashDescription (strm.GetData()); - assert (!"Didn't get sequence mutex for read register."); -#else - Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); - if (log) - { - if (log->GetVerbose()) - { - StreamString strm; - gdb_comm.DumpHistory(strm); - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData()); - } - else - { - log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name); - } - } -#endif + // Get each register individually + GetPrimordialRegister(reg_info, gdb_comm); } // Make sure we got a valid register value after reading it @@ -488,6 +439,54 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * return false; } +bool +GDBRemoteRegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) +{ + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + uint32_t save_id = 0; + if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) + { + reg_checkpoint.SetID(save_id); + reg_checkpoint.GetData().reset(); + return true; + } + else + { + reg_checkpoint.SetID(0); // Invalid save ID is zero + return ReadAllRegisterValues(reg_checkpoint.GetData()); + } +} + +bool +GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) +{ + uint32_t save_id = reg_checkpoint.GetID(); + if (save_id != 0) + { + ExecutionContext exe_ctx (CalculateThread()); + + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + if (process == NULL || thread == NULL) + return false; + + GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); + + return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); + } + else + { + return WriteAllRegisterValues(reg_checkpoint.GetData()); + } +} bool GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 7a49d693d44e..38f29bbca0de 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -91,6 +91,12 @@ public: virtual bool WriteAllRegisterValues (const lldb::DataBufferSP &data_sp); + virtual bool + ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); + + virtual bool + WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); + virtual uint32_t ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index aff9c7bc977c..7f1fbefc1b7e 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -820,7 +820,7 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ } const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10); - int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector()); + int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info); if (arg_packet_err == 0) { std::string error_str; @@ -926,15 +926,13 @@ ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) // then we aren't actually connected to anything, so try and do the // handshake with the remote GDB server and make sure that goes // alright. - if (!m_gdb_comm.HandshakeWithServer (NULL)) + if (!m_gdb_comm.HandshakeWithServer (&error)) { m_gdb_comm.Disconnect(); if (error.Success()) error.SetErrorString("not connected to remote gdb server"); return error; } - m_gdb_comm.ResetDiscoverableSettings(); - m_gdb_comm.QueryNoAckModeSupported (); m_gdb_comm.GetThreadSuffixSupported (); m_gdb_comm.GetListThreadsInStopReplySupported (); m_gdb_comm.GetHostInfo (); @@ -1158,6 +1156,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait } +bool +ProcessGDBRemote::SetExitStatus (int exit_status, const char *cstr) +{ + m_gdb_comm.Disconnect(); + return Process::SetExitStatus (exit_status, cstr); +} + void ProcessGDBRemote::DidAttach () { @@ -2787,6 +2792,7 @@ ProcessGDBRemote::MonitorDebugserverProcess void ProcessGDBRemote::KillDebugserverProcess () { + m_gdb_comm.Disconnect(); if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { Host::Kill (m_debugserver_pid, SIGINT); diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index b18ac5b1723e..35244074bab7 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -222,6 +222,13 @@ public: { return m_gdb_comm; } + + //---------------------------------------------------------------------- + // Override SetExitStatus so we can disconnect from the remote GDB server + //---------------------------------------------------------------------- + virtual bool + SetExitStatus (int exit_status, const char *cstr); + protected: friend class ThreadGDBRemote; diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp index a4968c455a68..daa3b0aa6666 100644 --- a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp +++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp @@ -32,6 +32,7 @@ DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data) dw_offset_t debug_ranges_offset = offset; while (Extract(dwarf2Data, &offset, range_list)) { + range_list.Sort(); m_range_map[debug_ranges_offset] = range_list; debug_ranges_offset = offset; } diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp index c089a7bb8db8..19edea4cb234 100644 --- a/source/Symbol/UnwindPlan.cpp +++ b/source/Symbol/UnwindPlan.cpp @@ -10,6 +10,7 @@ #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" @@ -373,6 +374,25 @@ UnwindPlan::SetPlanValidAddressRange (const AddressRange& range) bool UnwindPlan::PlanValidAtAddress (Address addr) { + // If this UnwindPlan has no rows, it is an invalid UnwindPlan. + if (GetRowCount() == 0) + { + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log) + log->Printf ("Testing if UnwindPlan is valid at pc 0x%" PRIx64 ": No unwind rows - is invalid."); + return false; + } + + // If the 0th Row of unwind instructions is missing, or if it doesn't provide + // a register to use to find the Canonical Frame Address, this is not a valid UnwindPlan. + if (GetRowAtIndex(0).get() == NULL || GetRowAtIndex(0)->GetCFARegister() == LLDB_INVALID_REGNUM) + { + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log) + log->Printf ("Testing if UnwindPlan is valid at pc 0x%" PRIx64 ": No CFA register - is invalid."); + return false; + } + if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0) return true; diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp index 75d94bd91ce3..66f9c0e552a8 100644 --- a/source/Target/Platform.cpp +++ b/source/Target/Platform.cpp @@ -237,6 +237,7 @@ Platform::Platform (bool is_host) : m_system_arch_set_while_connected (false), m_sdk_sysroot (), m_sdk_build (), + m_working_dir (), m_remote_url (), m_name (), m_major_os_version (UINT32_MAX), @@ -319,6 +320,10 @@ Platform::GetStatus (Stream &strm) strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); } + if (GetWorkingDirectory()) + { + strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); + } if (!IsConnected()) return; @@ -405,12 +410,332 @@ Platform::GetOSKernelDescription (std::string &s) } ConstString +Platform::GetWorkingDirectory () +{ + if (IsHost()) + { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) + return ConstString(cwd); + else + return ConstString(); + } + else + { + if (!m_working_dir) + m_working_dir = GetRemoteWorkingDirectory(); + return m_working_dir; + } +} + + +struct RecurseCopyBaton +{ + const FileSpec& dst; + Platform *platform_ptr; + Error error; +}; + + +static FileSpec::EnumerateDirectoryResult +RecurseCopy_Callback (void *baton, + FileSpec::FileType file_type, + const FileSpec &src) +{ + RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton; + switch (file_type) + { + case FileSpec::eFileTypePipe: + case FileSpec::eFileTypeSocket: + // we have no way to copy pipes and sockets - ignore them and continue + return FileSpec::eEnumerateDirectoryResultNext; + break; + + case FileSpec::eFileTypeDirectory: + { + // make the new directory and get in there + FileSpec dst_dir = rc_baton->dst; + if (!dst_dir.GetFilename()) + dst_dir.GetFilename() = src.GetLastPathComponent(); + std::string dst_dir_path (dst_dir.GetPath()); + Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir_path.c_str(), lldb::eFilePermissionsDirectoryDefault); + if (error.Fail()) + { + rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", dst_dir_path.c_str()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + } + + // now recurse + std::string src_dir_path (src.GetPath()); + + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); + RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() }; + FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2); + if (rc_baton2.error.Fail()) + { + rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + } + return FileSpec::eEnumerateDirectoryResultNext; + } + break; + + case FileSpec::eFileTypeSymbolicLink: + { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); + + char buf[PATH_MAX]; + + rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf)); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file.GetPath().c_str(), buf); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + return FileSpec::eEnumerateDirectoryResultNext; + } + break; + case FileSpec::eFileTypeRegular: + { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); + Error err = rc_baton->platform_ptr->PutFile(src, dst_file); + if (err.Fail()) + { + rc_baton->error.SetErrorString(err.AsCString()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + } + return FileSpec::eEnumerateDirectoryResultNext; + } + break; + + case FileSpec::eFileTypeInvalid: + case FileSpec::eFileTypeOther: + case FileSpec::eFileTypeUnknown: + rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + break; + } +} + +Error +Platform::Install (const FileSpec& src, const FileSpec& dst) +{ + Error error; + + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str()); + FileSpec fixed_dst(dst); + + if (!fixed_dst.GetFilename()) + fixed_dst.GetFilename() = src.GetFilename(); + + ConstString working_dir = GetWorkingDirectory(); + + if (dst) + { + if (dst.GetDirectory()) + { + const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; + if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') + { + fixed_dst.GetDirectory() = dst.GetDirectory(); + } + // If the fixed destination file doesn't have a directory yet, + // then we must have a relative path. We will resolve this relative + // path against the platform's working directory + if (!fixed_dst.GetDirectory()) + { + FileSpec relative_spec; + std::string path; + if (working_dir) + { + relative_spec.SetFile(working_dir.GetCString(), false); + relative_spec.AppendPathComponent(dst.GetPath().c_str()); + fixed_dst.GetDirectory() = relative_spec.GetDirectory(); + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); + return error; + } + } + } + else + { + if (working_dir) + { + fixed_dst.GetDirectory() = working_dir; + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); + return error; + } + } + } + else + { + if (working_dir) + { + fixed_dst.GetDirectory() = working_dir; + } + else + { + error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty"); + return error; + } + } + + if (log) + log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str()); + + if (GetSupportsRSync()) + { + error = PutFile(src, dst); + } + else + { + switch (src.GetFileType()) + { + case FileSpec::eFileTypeDirectory: + { + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + uint32_t permissions = src.GetPermissions(); + if (permissions == 0) + permissions = eFilePermissionsDirectoryDefault; + std::string dst_dir_path(fixed_dst.GetPath()); + error = MakeDirectory(dst_dir_path.c_str(), permissions); + if (error.Success()) + { + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(dst_dir_path.c_str()); + std::string src_dir_path (src.GetPath()); + RecurseCopyBaton baton = { recurse_dst, this, Error() }; + FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); + return baton.error; + } + } + break; + + case FileSpec::eFileTypeRegular: + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + error = PutFile(src, fixed_dst); + break; + + case FileSpec::eFileTypeSymbolicLink: + { + if (GetFileExists (fixed_dst)) + Unlink (fixed_dst.GetPath().c_str()); + char buf[PATH_MAX]; + error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf)); + if (error.Success()) + error = CreateSymlink(dst.GetPath().c_str(), buf); + } + break; + case FileSpec::eFileTypePipe: + error.SetErrorString("platform install doesn't handle pipes"); + break; + case FileSpec::eFileTypeSocket: + error.SetErrorString("platform install doesn't handle sockets"); + break; + case FileSpec::eFileTypeInvalid: + case FileSpec::eFileTypeUnknown: + case FileSpec::eFileTypeOther: + error.SetErrorString("platform install doesn't handle non file or directory items"); + break; + } + } + return error; +} + +bool +Platform::SetWorkingDirectory (const ConstString &path) +{ + if (IsHost()) + { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("Platform::SetWorkingDirectory('%s')", path.GetCString()); +#ifdef _WIN32 + // Not implemented on Windows + return false; +#else + if (path) + { + if (chdir(path.GetCString()) == 0) + return true; + } + return false; +#endif + } + else + { + m_working_dir.Clear(); + return SetRemoteWorkingDirectory(path); + } +} + +Error +Platform::MakeDirectory (const char *path, uint32_t permissions) +{ + if (IsHost()) + return Host::MakeDirectory (path, permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +Error +Platform::GetFilePermissions (const char *path, uint32_t &file_permissions) +{ + if (IsHost()) + return Host::GetFilePermissions(path, file_permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +Error +Platform::SetFilePermissions (const char *path, uint32_t file_permissions) +{ + if (IsHost()) + return Host::SetFilePermissions(path, file_permissions); + else + { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), __PRETTY_FUNCTION__); + return error; + } +} + +ConstString Platform::GetName () { - const char *name = GetHostname(); - if (name == NULL || name[0] == '\0') - return GetPluginName(); - return ConstString (name); + return GetPluginName(); } const char * @@ -424,6 +749,16 @@ Platform::GetHostname () return m_name.c_str(); } +bool +Platform::SetRemoteWorkingDirectory(const ConstString &path) +{ + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("Platform::SetRemoteWorkingDirectory('%s')", path.GetCString()); + m_working_dir = path; + return true; +} + const char * Platform::GetUserName (uint32_t uid) { @@ -779,14 +1114,6 @@ Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, return false; } -uint32_t -Platform::MakeDirectory (const FileSpec &spec, - mode_t mode) -{ - std::string path(spec.GetPath()); - return this->MakeDirectory(path,mode); -} - Error Platform::PutFile (const FileSpec& source, const FileSpec& destination, @@ -805,12 +1132,29 @@ Platform::GetFile (const FileSpec& source, return error; } +Error +Platform::CreateSymlink (const char *src, // The name of the link is in src + const char *dst)// The symlink points to dst +{ + Error error("unimplemented"); + return error; +} + bool Platform::GetFileExists (const lldb_private::FileSpec& file_spec) { return false; } +Error +Platform::Unlink (const char *path) +{ + Error error("unimplemented"); + return error; +} + + + lldb_private::Error Platform::RunShellCommand (const char *command, // Shouldn't be NULL const char *working_dir, // Pass NULL to use the current working directory diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 700afdb7981a..1de322aee148 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -1023,6 +1023,8 @@ Process::Process(Target &target, Listener &listener) : m_thread_mutex (Mutex::eMutexTypeRecursive), m_thread_list_real (this), m_thread_list (this), + m_extended_thread_list (this), + m_extended_thread_stop_id (0), m_notifications (), m_image_tokens (), m_listener (listener), @@ -1148,6 +1150,7 @@ Process::Finalize() m_dyld_ap.reset(); m_thread_list_real.Destroy(); m_thread_list.Destroy(); + m_extended_thread_list.Destroy(); std::vector<Notifications> empty_notifications; m_notifications.swap(empty_notifications); m_image_tokens.clear(); @@ -1591,6 +1594,13 @@ Process::UpdateThreadListIfNeeded () m_thread_list_real.Update(real_thread_list); m_thread_list.Update (new_thread_list); m_thread_list.SetStopID (stop_id); + + if (GetLastNaturalStopID () != m_extended_thread_stop_id) + { + // Clear any extended threads that we may have accumulated previously + m_extended_thread_list.Clear(); + m_extended_thread_stop_id = GetLastNaturalStopID (); + } } } } @@ -2103,12 +2113,37 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw } else { - // Report error for setting breakpoint... - m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - load_addr, - owner->GetBreakpoint().GetID(), - owner->GetID(), - error.AsCString() ? error.AsCString() : "unkown error"); + bool show_error = true; + switch (GetState()) + { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + show_error = false; + break; + + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + show_error = IsAlive(); + break; + } + + if (show_error) + { + // Report error for setting breakpoint... + m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", + load_addr, + owner->GetBreakpoint().GetID(), + owner->GetID(), + error.AsCString() ? error.AsCString() : "unkown error"); + } } } } @@ -2350,6 +2385,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site) size_t Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error) { + error.Clear(); if (!GetDisableMemoryCache()) { #if defined (VERIFY_MEMORY_READS) @@ -2873,7 +2909,7 @@ Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp) } Error -Process::Launch (const ProcessLaunchInfo &launch_info) +Process::Launch (ProcessLaunchInfo &launch_info) { Error error; m_abi_sp.reset(); @@ -2891,6 +2927,13 @@ Process::Launch (const ProcessLaunchInfo &launch_info) exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, sizeof(platform_exec_file_path)); if (exe_module->GetFileSpec().Exists()) { + // Install anything that might need to be installed prior to launching. + // For host systems, this will do nothing, but if we are connected to a + // remote platform it will install any needed binaries + error = GetTarget().Install(&launch_info); + if (error.Fail()) + return error; + if (PrivateStateThreadIsValid ()) PausePrivateStateThread (); @@ -4697,11 +4740,7 @@ Process::SettingsTerminate () ExecutionResults Process::RunThreadPlan (ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, - bool stop_others, - bool run_others, - bool unwind_on_error, - bool ignore_breakpoints, - uint32_t timeout_usec, + const EvaluateExpressionOptions &options, Stream &errors) { ExecutionResults return_value = eExecutionSetupError; @@ -4812,6 +4851,17 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense? + if (options.GetDebug()) + { + // In this case, we aren't actually going to run, we just want to stop right away. + // Flush this thread so we will refetch the stacks and show the correct backtrace. + // FIXME: To make this prettier we should invent some stop reason for this, but that + // is only cosmetic, and this functionality is only of use to lldb developers who can + // live with not pretty... + thread->Flush(); + return eExecutionStoppedForDebug; + } + Listener listener("lldb.process.listener.run-thread-plan"); lldb::EventSP event_to_broadcast_sp; @@ -4853,11 +4903,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, TimeValue one_thread_timeout = TimeValue::Now(); TimeValue final_timeout = one_thread_timeout; - if (run_others) + uint32_t timeout_usec = options.GetTimeoutUsec(); + if (options.GetTryAllThreads()) { // If we are running all threads then we take half the time to run all threads, bounded by // .25 sec. - if (timeout_usec == 0) + if (options.GetTimeoutUsec() == 0) one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec); else { @@ -4969,7 +5020,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, if (before_first_timeout) { - if (run_others) + if (options.GetTryAllThreads()) timeout_ptr = &one_thread_timeout; else { @@ -5085,7 +5136,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, if (log) log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription()); return_value = eExecutionHitBreakpoint; - if (!ignore_breakpoints) + if (!options.DoesIgnoreBreakpoints()) { event_to_broadcast_sp = event_sp; } @@ -5094,7 +5145,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, { if (log) log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete."); - if (!unwind_on_error) + if (!options.DoesUnwindOnError()) event_to_broadcast_sp = event_sp; return_value = eExecutionInterrupted; } @@ -5145,7 +5196,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, // either exit, or try with all threads running for the same timeout. if (log) { - if (run_others) + if (options.GetTryAllThreads()) { uint64_t remaining_time = final_timeout - TimeValue::Now(); if (before_first_timeout) @@ -5228,7 +5279,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, continue; } - if (!run_others) + if (!options.GetTryAllThreads()) { if (log) log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting."); @@ -5301,8 +5352,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, // 1) The execution successfully completed // 2) We hit a breakpoint, and ignore_breakpoints was true // 3) We got some other error, and discard_on_error was true - bool should_unwind = (return_value == eExecutionInterrupted && unwind_on_error) - || (return_value == eExecutionHitBreakpoint && ignore_breakpoints); + bool should_unwind = (return_value == eExecutionInterrupted && options.DoesUnwindOnError()) + || (return_value == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints()); if (return_value == eExecutionCompleted || should_unwind) @@ -5422,7 +5473,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, if (log) log->PutCString("Process::RunThreadPlan(): execution set up error."); - if (unwind_on_error) + if (options.DoesUnwindOnError()) { thread->DiscardThreadPlansUpToPlan (thread_plan_sp); thread_plan_sp->SetPrivate (orig_plan_private); @@ -5446,7 +5497,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, { if (log) log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course"); - if (unwind_on_error && thread_plan_sp) + if (options.DoesUnwindOnError() && thread_plan_sp) { if (log) log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set."); @@ -5518,6 +5569,9 @@ Process::ExecutionResultAsCString (ExecutionResults result) case eExecutionTimedOut: result_name = "eExecutionTimedOut"; break; + case eExecutionStoppedForDebug: + result_name = "eExecutionStoppedForDebug"; + break; } return result_name; } @@ -5633,7 +5687,7 @@ Process::DidExec () { Target &target = GetTarget(); target.CleanupProcess (); - target.ClearModules(); + target.ClearModules(false); m_dynamic_checkers_ap.reset(); m_abi_sp.reset(); m_system_runtime_ap.reset(); @@ -5649,5 +5703,9 @@ Process::DidExec () // Flush the process (threads and all stack frames) after running CompleteAttach() // in case the dynamic loader loaded things in new locations. Flush(); + + // After we figure out what was loaded/unloaded in CompleteAttach, + // we need to let the target know so it can do any cleanup it needs to. + target.DidExec(); } diff --git a/source/Target/RegisterContext.cpp b/source/Target/RegisterContext.cpp index 3d68ba8706c9..93dce3ea0edc 100644 --- a/source/Target/RegisterContext.cpp +++ b/source/Target/RegisterContext.cpp @@ -440,6 +440,18 @@ RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info, } +bool +RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) +{ + return ReadAllRegisterValues(reg_checkpoint.GetData()); +} + +bool +RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) +{ + return WriteAllRegisterValues(reg_checkpoint.GetData()); +} + TargetSP RegisterContext::CalculateTarget () { diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp index eaac3613c93d..631a77bd4951 100644 --- a/source/Target/StackFrameList.cpp +++ b/source/Target/StackFrameList.cpp @@ -301,7 +301,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx) if (reg_ctx_sp) { - const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); + const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); // There shouldn't be any way not to get the frame info for frame 0. // But if the unwinder can't make one, lets make one by hand with the // SP as the CFA and see if that gets any further. @@ -329,7 +329,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx) } else { - const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc); + const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); if (!success) { // We've gotten to the end of the stack. @@ -451,14 +451,17 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx) { if (end_idx < m_concrete_frames_fetched) return; - - uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); - if (num_frames <= end_idx + 1) + + if (unwinder) { - //Done unwinding. - m_concrete_frames_fetched = UINT32_MAX; + uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); + if (num_frames <= end_idx + 1) + { + //Done unwinding. + m_concrete_frames_fetched = UINT32_MAX; + } + m_frames.resize(num_frames); } - m_frames.resize(num_frames); } } diff --git a/source/Target/SystemRuntime.cpp b/source/Target/SystemRuntime.cpp index 7ce150f41273..5c07ed388ae4 100644 --- a/source/Target/SystemRuntime.cpp +++ b/source/Target/SystemRuntime.cpp @@ -33,7 +33,8 @@ SystemRuntime::FindPlugin (Process *process) // SystemRuntime constructor //---------------------------------------------------------------------- SystemRuntime::SystemRuntime(Process *process) : - m_process (process) + m_process (process), + m_types () { } @@ -59,15 +60,14 @@ SystemRuntime::ModulesDidLoad (ModuleList &module_list) { } -std::vector<ConstString> +const std::vector<ConstString> & SystemRuntime::GetExtendedBacktraceTypes () { - std::vector<ConstString> types; - return types; + return m_types; } ThreadSP -SystemRuntime::GetExtendedBacktrace (ThreadSP thread, ConstString type) +SystemRuntime::GetExtendedBacktraceThread (ThreadSP thread, ConstString type) { return ThreadSP(); } diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp index 18efd8cb7247..fd9626a5de8d 100644 --- a/source/Target/Target.cpp +++ b/source/Target/Target.cpp @@ -192,7 +192,7 @@ Target::Destroy() DeleteCurrentProcess (); m_platform_sp.reset(); m_arch.Clear(); - ClearModules(); + ClearModules(true); m_section_load_list.Clear(); const bool notify = false; m_breakpoint_list.RemoveAll(notify); @@ -1014,9 +1014,9 @@ LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target) } void -Target::ClearModules() +Target::ClearModules(bool delete_locations) { - ModulesDidUnload (m_images, true); + ModulesDidUnload (m_images, delete_locations); GetSectionLoadList().Clear(); m_images.Clear(); m_scratch_ast_context_ap.reset(); @@ -1025,10 +1025,18 @@ Target::ClearModules() } void +Target::DidExec () +{ + // When a process exec's we need to know about it so we can do some cleanup. + m_breakpoint_list.RemoveInvalidLocations(m_arch); + m_internal_breakpoint_list.RemoveInvalidLocations(m_arch); +} + +void Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET)); - ClearModules(); + ClearModules(false); if (executable_sp.get()) { @@ -1098,7 +1106,7 @@ Target::SetArchitecture (const ArchSpec &arch_spec) m_arch = arch_spec; ModuleSP executable_sp = GetExecutableModule (); - ClearModules(); + ClearModules(true); // Need to do something about unsetting breakpoints. if (executable_sp) @@ -2182,12 +2190,78 @@ Target::RunStopHooks () result.GetImmediateErrorStream()->Flush(); } +const TargetPropertiesSP & +Target::GetGlobalProperties() +{ + static TargetPropertiesSP g_settings_sp; + if (!g_settings_sp) + { + g_settings_sp.reset (new TargetProperties (NULL)); + } + return g_settings_sp; +} + +Error +Target::Install (ProcessLaunchInfo *launch_info) +{ + Error error; + PlatformSP platform_sp (GetPlatform()); + if (platform_sp) + { + if (platform_sp->IsRemote()) + { + if (platform_sp->IsConnected()) + { + // Install all files that have an install path, and always install the + // main executable when connected to a remote platform + const ModuleList& modules = GetImages(); + const size_t num_images = modules.GetSize(); + for (size_t idx = 0; idx < num_images; ++idx) + { + const bool is_main_executable = idx == 0; + ModuleSP module_sp(modules.GetModuleAtIndex(idx)); + if (module_sp) + { + FileSpec local_file (module_sp->GetFileSpec()); + if (local_file) + { + FileSpec remote_file (module_sp->GetRemoteInstallFileSpec()); + if (!remote_file) + { + if (is_main_executable) // TODO: add setting for always installing main executable??? + { + // Always install the main executable + remote_file.GetDirectory() = platform_sp->GetWorkingDirectory(); + remote_file.GetFilename() = module_sp->GetFileSpec().GetFilename(); + } + } + if (remote_file) + { + error = platform_sp->Install(local_file, remote_file); + if (error.Success()) + { + module_sp->SetPlatformFileSpec(remote_file); + if (is_main_executable) + { + if (launch_info) + launch_info->SetExecutableFile(remote_file, false); + } + } + else + break; + } + } + } + } + } + } + } + return error; +} //-------------------------------------------------------------- -// class Target::StopHook +// Target::StopHook //-------------------------------------------------------------- - - Target::StopHook::StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid) : UserID (uid), m_target_sp (target_sp), @@ -2519,6 +2593,9 @@ protected: mutable bool m_got_host_env; }; +//---------------------------------------------------------------------- +// TargetProperties +//---------------------------------------------------------------------- TargetProperties::TargetProperties (Target *target) : Properties () { @@ -2807,17 +2884,10 @@ TargetProperties::GetMemoryModuleLoadLevel() const } -const TargetPropertiesSP & -Target::GetGlobalProperties() -{ - static TargetPropertiesSP g_settings_sp; - if (!g_settings_sp) - { - g_settings_sp.reset (new TargetProperties (NULL)); - } - return g_settings_sp; -} +//---------------------------------------------------------------------- +// Target::TargetEventData +//---------------------------------------------------------------------- const ConstString & Target::TargetEventData::GetFlavorString () { diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp index 98c26019b4a1..07f5321990b2 100644 --- a/source/Target/Thread.cpp +++ b/source/Target/Thread.cpp @@ -496,7 +496,19 @@ Thread::ThreadStoppedForAReason (void) bool Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state) { - if (!SaveFrameZeroState(saved_state.register_backup)) + saved_state.register_backup_sp.reset(); + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); + if (frame_sp) + { + lldb::RegisterCheckpointSP reg_checkpoint_sp(new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression)); + if (reg_checkpoint_sp) + { + lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); + if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues (*reg_checkpoint_sp)) + saved_state.register_backup_sp = reg_checkpoint_sp; + } + } + if (!saved_state.register_backup_sp) return false; saved_state.stop_info_sp = GetStopInfo(); @@ -511,8 +523,26 @@ Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state) bool Thread::RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state) { - RestoreSaveFrameZero(saved_state.register_backup); - return true; + if (saved_state.register_backup_sp) + { + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); + if (frame_sp) + { + lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); + if (reg_ctx_sp) + { + bool ret = reg_ctx_sp->WriteAllRegisterValues (*saved_state.register_backup_sp); + + // Clear out all stack frames as our world just changed. + ClearStackFrames(); + reg_ctx_sp->InvalidateIfNeeded(true); + if (m_unwinder_ap.get()) + m_unwinder_ap->Clear(); + return ret; + } + } + } + return false; } bool @@ -1420,14 +1450,6 @@ Thread::QueueThreadPlanForStepInRange ThreadPlanSP -Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanStepOverBreakpoint (*this)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; -} - -ThreadPlanSP Thread::QueueThreadPlanForStepOut ( bool abort_other_plans, @@ -1470,25 +1492,6 @@ Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id, bool abort_othe } ThreadPlanSP -Thread::QueueThreadPlanForCallFunction (bool abort_other_plans, - Address& function, - lldb::addr_t arg, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this, - function, - ClangASTType(), - arg, - stop_other_threads, - unwind_on_error, - ignore_breakpoints)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; -} - -ThreadPlanSP Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans, Address &target_addr, bool stop_other_threads) @@ -1994,48 +1997,6 @@ Thread::GetStackFrameStatus (Stream& strm, num_frames_with_source); } -bool -Thread::SaveFrameZeroState (RegisterCheckpoint &checkpoint) -{ - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - checkpoint.SetStackID(frame_sp->GetStackID()); - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - return reg_ctx_sp->ReadAllRegisterValues (checkpoint.GetData()); - } - return false; -} - -bool -Thread::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint) -{ - return ResetFrameZeroRegisters (checkpoint.GetData()); -} - -bool -Thread::ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp) -{ - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - bool ret = reg_ctx_sp->WriteAllRegisterValues (register_data_sp); - - // Clear out all stack frames as our world just changed. - ClearStackFrames(); - reg_ctx_sp->InvalidateIfNeeded(true); - if (m_unwinder_ap.get()) - m_unwinder_ap->Clear(); - return ret; - } - } - return false; -} - Unwind * Thread::GetUnwinder () { diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp index c9baaafffd6a..854750b85817 100644 --- a/source/Target/ThreadPlanCallFunction.cpp +++ b/source/Target/ThreadPlanCallFunction.cpp @@ -55,8 +55,6 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread, if (!abi) return false; - TargetSP target_sp (thread.CalculateTarget()); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); SetBreakpoints(); @@ -74,7 +72,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread, return false; } - Module *exe_module = target_sp->GetExecutableModulePointer(); + Module *exe_module = GetTarget().GetExecutableModulePointer(); if (exe_module == NULL) { @@ -107,7 +105,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread, } } - start_load_addr = m_start_addr.GetLoadAddress (target_sp.get()); + start_load_addr = m_start_addr.GetLoadAddress (&GetTarget()); // Checkpoint the thread state so we can restore it later. if (log && log->GetVerbose()) @@ -120,7 +118,7 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread, log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData()); return false; } - function_load_addr = m_function_addr.GetLoadAddress (target_sp.get()); + function_load_addr = m_function_addr.GetLoadAddress (&GetTarget()); return true; } @@ -128,109 +126,36 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread, ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, const Address &function, const ClangASTType &return_type, - addr_t arg, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints, - addr_t *this_arg, - addr_t *cmd_arg) : + llvm::ArrayRef<addr_t> args, + const EvaluateExpressionOptions &options) : ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), m_valid (false), - m_stop_other_threads (stop_other_threads), + m_stop_other_threads (options.GetStopOthers()), + m_unwind_on_error (options.DoesUnwindOnError()), + m_ignore_breakpoints (options.DoesIgnoreBreakpoints()), + m_debug_execution (options.GetDebug()), + m_trap_exceptions (options.GetTrapExceptions()), m_function_addr (function), m_function_sp (0), m_return_type (return_type), m_takedown_done (false), - m_stop_address (LLDB_INVALID_ADDRESS), - m_unwind_on_error (unwind_on_error), - m_ignore_breakpoints (ignore_breakpoints) + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp (false), + m_stop_address (LLDB_INVALID_ADDRESS) { lldb::addr_t start_load_addr; ABI *abi; lldb::addr_t function_load_addr; if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr)) return; - - if (this_arg && cmd_arg) - { - if (!abi->PrepareTrivialCall (thread, - m_function_sp, - function_load_addr, - start_load_addr, - this_arg, - cmd_arg, - &arg)) - return; - } - else if (this_arg) - { - if (!abi->PrepareTrivialCall (thread, - m_function_sp, - function_load_addr, - start_load_addr, - this_arg, - &arg)) - return; - } - else - { - if (!abi->PrepareTrivialCall (thread, - m_function_sp, - function_load_addr, - start_load_addr, - &arg)) - return; - } - - ReportRegisterState ("Function call was set up. Register state was:"); - m_valid = true; -} - - -ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, - const Address &function, - const ClangASTType &return_type, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints, - addr_t *arg1_ptr, - addr_t *arg2_ptr, - addr_t *arg3_ptr, - addr_t *arg4_ptr, - addr_t *arg5_ptr, - addr_t *arg6_ptr) : - ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_valid (false), - m_stop_other_threads (stop_other_threads), - m_function_addr (function), - m_function_sp (0), - m_return_type (return_type), - m_takedown_done (false), - m_stop_address (LLDB_INVALID_ADDRESS), - m_unwind_on_error (unwind_on_error), - m_ignore_breakpoints (ignore_breakpoints) -{ - lldb::addr_t start_load_addr; - ABI *abi; - lldb::addr_t function_load_addr; - if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr)) + if (!abi->PrepareTrivialCall(thread, + m_function_sp, + function_load_addr, + start_load_addr, + args)) return; - if (!abi->PrepareTrivialCall (thread, - m_function_sp, - function_load_addr, - start_load_addr, - arg1_ptr, - arg2_ptr, - arg3_ptr, - arg4_ptr, - arg5_ptr, - arg6_ptr)) - { - return; - } - ReportRegisterState ("Function call was set up. Register state was:"); m_valid = true; @@ -299,7 +224,11 @@ ThreadPlanCallFunction::DoTakedown (bool success) m_takedown_done = true; m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); m_real_stop_info_sp = GetPrivateStopInfo (); - m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state); + if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) + { + if (log) + log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state", this); + } SetPlanComplete(success); ClearBreakpoints(); if (log && log->GetVerbose()) @@ -560,25 +489,34 @@ void ThreadPlanCallFunction::SetBreakpoints () { ProcessSP process_sp (m_thread.CalculateProcess()); - if (process_sp) + if (m_trap_exceptions && process_sp) { m_cxx_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC); if (m_cxx_language_runtime) + { + m_should_clear_cxx_exception_bp = !m_cxx_language_runtime->ExceptionBreakpointsAreSet(); m_cxx_language_runtime->SetExceptionBreakpoints(); + } if (m_objc_language_runtime) + { + m_should_clear_objc_exception_bp = !m_objc_language_runtime->ExceptionBreakpointsAreSet(); m_objc_language_runtime->SetExceptionBreakpoints(); + } } } void ThreadPlanCallFunction::ClearBreakpoints () { - if (m_cxx_language_runtime) - m_cxx_language_runtime->ClearExceptionBreakpoints(); - if (m_objc_language_runtime) - m_objc_language_runtime->ClearExceptionBreakpoints(); + if (m_trap_exceptions) + { + if (m_cxx_language_runtime && m_should_clear_cxx_exception_bp) + m_cxx_language_runtime->ClearExceptionBreakpoints(); + if (m_objc_language_runtime && m_should_clear_objc_exception_bp) + m_objc_language_runtime->ClearExceptionBreakpoints(); + } } bool @@ -586,21 +524,24 @@ ThreadPlanCallFunction::BreakpointsExplainStop() { StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if ((m_cxx_language_runtime && - m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)) - ||(m_objc_language_runtime && - m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))) + if (m_trap_exceptions) { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete."); - - SetPlanComplete(false); - - // If the user has set the ObjC language breakpoint, it would normally get priority over our internal - // catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here. - stop_info_sp->OverrideShouldStop (true); - return true; + if ((m_cxx_language_runtime && + m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)) + ||(m_objc_language_runtime && + m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))) + { + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); + if (log) + log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete."); + + SetPlanComplete(false); + + // If the user has set the ObjC language breakpoint, it would normally get priority over our internal + // catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here. + stop_info_sp->OverrideShouldStop (true); + return true; + } } return false; diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp index 70de1cbe86e1..827de3e6057a 100644 --- a/source/Target/ThreadPlanCallUserExpression.cpp +++ b/source/Target/ThreadPlanCallUserExpression.cpp @@ -38,14 +38,10 @@ using namespace lldb_private; ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, Address &function, - lldb::addr_t arg, - bool stop_other_threads, - bool unwind_on_error, - bool ignore_breakpoints, - lldb::addr_t *this_arg, - lldb::addr_t *cmd_arg, + llvm::ArrayRef<lldb::addr_t> args, + const EvaluateExpressionOptions &options, ClangUserExpression::ClangUserExpressionSP &user_expression_sp) : - ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, unwind_on_error, ignore_breakpoints, this_arg, cmd_arg), + ThreadPlanCallFunction (thread, function, ClangASTType(), args, options), m_user_expression_sp (user_expression_sp) { // User expressions are generally "User generated" so we should set them up to stop when done. diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp index c1f14bd216de..2cfd29f89196 100644 --- a/source/Target/ThreadPlanStepInRange.cpp +++ b/source/Target/ThreadPlanStepInRange.cpp @@ -132,9 +132,9 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr) bool stop_others; if (m_stop_others == lldb::eOnlyThisThread) - stop_others = false; - else stop_others = true; + else + stop_others = false; FrameComparison frame_order = CompareCurrentFrameToStartFrame(); diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp index d4ce470d56f3..9d2315708821 100644 --- a/source/Utility/StringExtractor.cpp +++ b/source/Utility/StringExtractor.cpp @@ -145,11 +145,10 @@ StringExtractor::GetChar (char fail_value) uint8_t StringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail) { - uint32_t i = m_index; - if ((i + 2) <= m_packet.size()) + if (GetBytesLeft() >= 2) { - const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i])]; - const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i+1])]; + const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index])]; + const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[m_index+1])]; if (hi_nibble < 16 && lo_nibble < 16) { m_index += 2; diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp index 6e32481ccc50..08e7af725650 100644 --- a/source/Utility/StringExtractorGDBRemote.cpp +++ b/source/Utility/StringExtractorGDBRemote.cpp @@ -117,6 +117,7 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'G': if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName; + if (PACKET_MATCHES ("qGetWorkingDir")) return eServerPacketType_qGetWorkingDir; break; case 'H': @@ -133,9 +134,10 @@ StringExtractorGDBRemote::GetServerPacketType () const break; case 'P': - if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID; - if (PACKET_STARTS_WITH ("qPlatform_RunCommand:")) return eServerPacketType_qPlatform_RunCommand; - if (PACKET_STARTS_WITH ("qPlatform_IO_MkDir:")) return eServerPacketType_qPlatform_IO_MkDir; + if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID; + if (PACKET_STARTS_WITH ("qPlatform_shell:")) return eServerPacketType_qPlatform_shell; + if (PACKET_STARTS_WITH ("qPlatform_mkdir:")) return eServerPacketType_qPlatform_mkdir; + if (PACKET_STARTS_WITH ("qPlatform_chmod:")) return eServerPacketType_qPlatform_chmod; break; @@ -151,15 +153,17 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'v': if (PACKET_STARTS_WITH("vFile:")) { - if (PACKET_STARTS_WITH("vFile:open:")) return eServerPacketType_vFile_Open; - else if (PACKET_STARTS_WITH("vFile:close:")) return eServerPacketType_vFile_Close; - else if (PACKET_STARTS_WITH("vFile:pread")) return eServerPacketType_vFile_pRead; - else if (PACKET_STARTS_WITH("vFile:pwrite")) return eServerPacketType_vFile_pWrite; - else if (PACKET_STARTS_WITH("vFile:size")) return eServerPacketType_vFile_Size; - else if (PACKET_STARTS_WITH("vFile:exists")) return eServerPacketType_vFile_Exists; - else if (PACKET_STARTS_WITH("vFile:stat")) return eServerPacketType_vFile_Stat; - else if (PACKET_STARTS_WITH("vFile:mode")) return eServerPacketType_vFile_Mode; - else if (PACKET_STARTS_WITH("vFile:MD5")) return eServerPacketType_vFile_MD5; + if (PACKET_STARTS_WITH("vFile:open:")) return eServerPacketType_vFile_open; + else if (PACKET_STARTS_WITH("vFile:close:")) return eServerPacketType_vFile_close; + else if (PACKET_STARTS_WITH("vFile:pread")) return eServerPacketType_vFile_pread; + else if (PACKET_STARTS_WITH("vFile:pwrite")) return eServerPacketType_vFile_pwrite; + else if (PACKET_STARTS_WITH("vFile:size")) return eServerPacketType_vFile_size; + else if (PACKET_STARTS_WITH("vFile:exists")) return eServerPacketType_vFile_exists; + else if (PACKET_STARTS_WITH("vFile:stat")) return eServerPacketType_vFile_stat; + else if (PACKET_STARTS_WITH("vFile:mode")) return eServerPacketType_vFile_mode; + else if (PACKET_STARTS_WITH("vFile:MD5")) return eServerPacketType_vFile_md5; + else if (PACKET_STARTS_WITH("vFile:symlink")) return eServerPacketType_vFile_symlink; + else if (PACKET_STARTS_WITH("vFile:unlink")) return eServerPacketType_vFile_unlink; } break; diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h index fe500ecda5d4..2379882e8bf8 100644 --- a/source/Utility/StringExtractorGDBRemote.h +++ b/source/Utility/StringExtractorGDBRemote.h @@ -58,6 +58,7 @@ public: eServerPacketType_qProcessInfoPID, eServerPacketType_qSpeedTest, eServerPacketType_qUserName, + eServerPacketType_qGetWorkingDir, eServerPacketType_QEnvironment, eServerPacketType_QLaunchArch, eServerPacketType_QSetDisableASLR, @@ -66,17 +67,20 @@ public: eServerPacketType_QSetSTDERR, eServerPacketType_QSetWorkingDir, eServerPacketType_QStartNoAckMode, - eServerPacketType_qPlatform_RunCommand, - eServerPacketType_qPlatform_IO_MkDir, - eServerPacketType_vFile_Open, - eServerPacketType_vFile_Close, - eServerPacketType_vFile_pRead, - eServerPacketType_vFile_pWrite, - eServerPacketType_vFile_Size, - eServerPacketType_vFile_Mode, - eServerPacketType_vFile_Exists, - eServerPacketType_vFile_MD5, - eServerPacketType_vFile_Stat + eServerPacketType_qPlatform_shell, + eServerPacketType_qPlatform_mkdir, + eServerPacketType_qPlatform_chmod, + eServerPacketType_vFile_open, + eServerPacketType_vFile_close, + eServerPacketType_vFile_pread, + eServerPacketType_vFile_pwrite, + eServerPacketType_vFile_size, + eServerPacketType_vFile_mode, + eServerPacketType_vFile_exists, + eServerPacketType_vFile_md5, + eServerPacketType_vFile_stat, + eServerPacketType_vFile_symlink, + eServerPacketType_vFile_unlink }; ServerPacketType diff --git a/source/lldb.cpp b/source/lldb.cpp index c69563773915..78e8208e0910 100644 --- a/source/lldb.cpp +++ b/source/lldb.cpp @@ -60,6 +60,7 @@ #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h" #include "Plugins/Platform/MacOSX/PlatformiOSSimulator.h" +#include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" #endif #include "Plugins/Process/mach-core/ProcessMachCore.h" @@ -139,6 +140,7 @@ lldb_private::Initialize () PlatformRemoteiOS::Initialize(); PlatformMacOSX::Initialize(); PlatformiOSSimulator::Initialize(); + SystemRuntimeMacOSX::Initialize(); #endif #if defined (__linux__) //---------------------------------------------------------------------- @@ -220,6 +222,7 @@ lldb_private::Terminate () PlatformDarwinKernel::Terminate(); PlatformRemoteiOS::Terminate(); PlatformiOSSimulator::Terminate(); + SystemRuntimeMacOSX::Terminate(); #endif Debugger::SettingsTerminate (); diff --git a/tools/lldb-platform/lldb-platform.cpp b/tools/lldb-platform/lldb-platform.cpp index 007e69c92814..bc9d62974771 100644 --- a/tools/lldb-platform/lldb-platform.cpp +++ b/tools/lldb-platform/lldb-platform.cpp @@ -21,11 +21,15 @@ // C++ Includes // Other libraries and framework includes +#include "lldb/lldb-private-log.h" #include "lldb/Core/Error.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/ConnectionMachPort.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h" #include "Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h" using namespace lldb; @@ -44,24 +48,32 @@ static struct option g_long_options[] = { "debug", no_argument, &g_debug, 1 }, { "verbose", no_argument, &g_verbose, 1 }, { "stay-alive", no_argument, &g_stay_alive, 1 }, - { "log-file", required_argument, NULL, 'l' }, - { "log-flags", required_argument, NULL, 'f' }, { "listen", required_argument, NULL, 'L' }, + { "port-offset", required_argument, NULL, 'p' }, + { "gdbserver-port", required_argument, NULL, 'P' }, + { "min-gdbserver-port", required_argument, NULL, 'm' }, + { "max-gdbserver-port", required_argument, NULL, 'M' }, + { "lldb-command", required_argument, NULL, 'c' }, { NULL, 0, NULL, 0 } }; +#if defined (__APPLE__) +#define LOW_PORT (IPPORT_RESERVED) +#define HIGH_PORT (IPPORT_HIFIRSTAUTO) +#else +#define LOW_PORT (1024u) +#define HIGH_PORT (49151u) +#endif + + //---------------------------------------------------------------------- // Watch for signals //---------------------------------------------------------------------- -int g_sigpipe_received = 0; void signal_handler(int signo) { switch (signo) { - case SIGPIPE: - g_sigpipe_received = 1; - break; case SIGHUP: // Use SIGINT first, if that does not work, use SIGHUP as a last resort. // And we should not call exit() here because it results in the global destructors @@ -86,130 +98,165 @@ int main (int argc, char *argv[]) { const char *progname = argv[0]; - signal (SIGPIPE, signal_handler); + signal (SIGPIPE, SIG_IGN); signal (SIGHUP, signal_handler); int long_option_index = 0; - StreamSP log_stream_sp; - Args log_args; Error error; std::string listen_host_port; int ch; - Debugger::Initialize(); + Debugger::Initialize(NULL); + + lldb::DebuggerSP debugger_sp = Debugger::CreateInstance (); + + debugger_sp->SetInputFileHandle(stdin, false); + debugger_sp->SetOutputFileHandle(stdout, false); + debugger_sp->SetErrorFileHandle(stderr, false); -// ConnectionMachPort a; -// ConnectionMachPort b; -// -// lldb::ConnectionStatus status; -// const char *bootstrap_service_name = "HelloWorld"; -// status = a.BootstrapCheckIn(bootstrap_service_name, &error); -// -// if (status != eConnectionStatusSuccess) -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 1; -// } -// status = b.BootstrapLookup (bootstrap_service_name, &error); -// if (status != eConnectionStatusSuccess) -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 2; -// } -// -// if (a.Write ("hello", 5, status, &error) == 5) -// { -// char buf[32]; -// memset(buf, 0, sizeof(buf)); -// if (b.Read (buf, 5, status, &error)) -// { -// printf("read returned bytes: %s", buf); -// } -// else -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 4; -// } -// } -// else -// { -// fprintf(stderr, "%s", error.AsCString()); -// return 3; -// } + GDBRemoteCommunicationServer::PortMap gdbserver_portmap; + int min_gdbserver_port = 0; + int max_gdbserver_port = 0; + uint16_t port_offset = 0; + + std::vector<std::string> lldb_commands; + bool show_usage = false; + int option_error = 0; - while ((ch = getopt_long_only(argc, argv, "l:f:L:", g_long_options, &long_option_index)) != -1) + std::string short_options(OptionParser::GetShortOptionString(g_long_options)); + +#if __GLIBC__ + optind = 0; +#else + optreset = 1; + optind = 1; +#endif + + while ((ch = getopt_long_only(argc, argv, short_options.c_str(), g_long_options, &long_option_index)) != -1) { -// DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", -// ch, (uint8_t)ch, -// g_long_options[long_option_index].name, -// g_long_options[long_option_index].has_arg ? '=' : ' ', -// optarg ? optarg : ""); switch (ch) { case 0: // Any optional that auto set themselves will return 0 break; - case 'l': // Set Log File - if (optarg && optarg[0]) + case 'L': + listen_host_port.append (optarg); + break; + + case 'p': { - if ((strcasecmp(optarg, "stdout") == 0) || (strcmp(optarg, "/dev/stdout") == 0)) + char *end = NULL; + long tmp_port_offset = strtoul(optarg, &end, 0); + if (end && *end == '\0') { - log_stream_sp.reset (new StreamFile (stdout, false)); + if (LOW_PORT <= tmp_port_offset && tmp_port_offset <= HIGH_PORT) + { + port_offset = (uint16_t)tmp_port_offset; + } + else + { + fprintf (stderr, "error: port offset %li is not in the valid user port range of %u - %u\n", tmp_port_offset, LOW_PORT, HIGH_PORT); + option_error = 5; + } } - else if ((strcasecmp(optarg, "stderr") == 0) || (strcmp(optarg, "/dev/stderr") == 0)) + else { - log_stream_sp.reset (new StreamFile (stderr, false)); + fprintf (stderr, "error: invalid port offset string %s\n", optarg); + option_error = 4; } - else + } + break; + + case 'P': + case 'm': + case 'M': + { + char *end = NULL; + long portnum = strtoul(optarg, &end, 0); + if (end && *end == '\0') { - FILE *log_file = fopen(optarg, "w"); - if (log_file) + if (LOW_PORT <= portnum && portnum <= HIGH_PORT) { - setlinebuf(log_file); - log_stream_sp.reset (new StreamFile (log_file, true)); + if (ch == 'P') + gdbserver_portmap[(uint16_t)portnum] = LLDB_INVALID_PROCESS_ID; + else if (ch == 'm') + min_gdbserver_port = portnum; + else + max_gdbserver_port = portnum; } else { - const char *errno_str = strerror(errno); - fprintf (stderr, "Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error"); + fprintf (stderr, "error: port number %li is not in the valid user port range of %u - %u\n", portnum, LOW_PORT, HIGH_PORT); + option_error = 1; } - } - + else + { + fprintf (stderr, "error: invalid port number string %s\n", optarg); + option_error = 2; + } } break; - - case 'f': // Log Flags - if (optarg && optarg[0]) - log_args.AppendArgument(optarg); - break; - - case 'L': - listen_host_port.append (optarg); + + case 'c': + lldb_commands.push_back(optarg); break; case 'h': /* fall-through is intentional */ case '?': - display_usage(progname); + show_usage = true; break; } } + + // Make a port map for a port range that was specified. + if (min_gdbserver_port < max_gdbserver_port) + { + for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) + gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; + } + else if (min_gdbserver_port != max_gdbserver_port) + { + fprintf (stderr, "error: --min-gdbserver-port (%u) is greater than --max-gdbserver-port (%u)\n", min_gdbserver_port, max_gdbserver_port); + option_error = 3; + + } + // Print usage and exit if no listening port is specified. if (listen_host_port.empty()) - display_usage(progname); + show_usage = true; - if (log_stream_sp) + if (show_usage || option_error) { - if (log_args.GetArgumentCount() == 0) - log_args.AppendArgument("default"); - ProcessGDBRemoteLog::EnableLog (log_stream_sp, 0,log_args.GetConstArgumentVector(), log_stream_sp.get()); + display_usage(progname); + exit(option_error); } - + // Skip any options we consumed with getopt_long_only argc -= optind; argv += optind; + // Execute any LLDB commands that we were asked to evaluate. + for (const auto &lldb_command : lldb_commands) + { + lldb_private::CommandReturnObject result; + printf("(lldb) %s\n", lldb_command.c_str()); + debugger_sp->GetCommandInterpreter().HandleCommand(lldb_command.c_str(), eLazyBoolNo, result); + const char *output = result.GetOutputData(); + if (output && output[0]) + puts(output); + } + do { GDBRemoteCommunicationServer gdb_server (true); + + if (port_offset > 0) + gdb_server.SetPortOffset(port_offset); + + if (!gdbserver_portmap.empty()) + { + gdb_server.SetPortMap(std::move(gdbserver_portmap)); + } + if (!listen_host_port.empty()) { std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); |