diff options
285 files changed, 8898 insertions, 4823 deletions
diff --git a/include/lldb/API/SBLaunchInfo.h b/include/lldb/API/SBLaunchInfo.h new file mode 100644 index 000000000000..a5921ab90d48 --- /dev/null +++ b/include/lldb/API/SBLaunchInfo.h @@ -0,0 +1,186 @@ +//===-- SBLaunchInfo.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_SBLaunchInfo_h_ +#define LLDB_SBLaunchInfo_h_ + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class SBPlatform; +class SBTarget; + +class SBLaunchInfo +{ +public: + SBLaunchInfo (const char **argv); + + ~SBLaunchInfo(); + + lldb::pid_t + GetProcessID(); + + uint32_t + GetUserID(); + + uint32_t + GetGroupID(); + + bool + UserIDIsValid (); + + bool + GroupIDIsValid (); + + void + SetUserID (uint32_t uid); + + void + SetGroupID (uint32_t gid); + + SBFileSpec + GetExecutableFile (); + + //---------------------------------------------------------------------- + /// Set the executable file that will be used to launch the process and + /// optionally set it as the first argument in the argument vector. + /// + /// This only needs to be specified if clients wish to carefully control + /// the exact path will be used to launch a binary. If you create a + /// target with a symlink, that symlink will get resolved in the target + /// and the resolved path will get used to launch the process. Calling + /// this function can help you still launch your process using the + /// path of your choice. + /// + /// If this function is not called prior to launching with + /// SBTarget::Launch(...), the target will use the resolved executable + /// path that was used to create the target. + /// + /// @param[in] exe_file + /// The override path to use when launching the executable. + /// + /// @param[in] add_as_first_arg + /// If true, then the path will be inserted into the argument vector + /// prior to launching. Otherwise the argument vector will be left + /// alone. + //---------------------------------------------------------------------- + void + SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg); + + + //---------------------------------------------------------------------- + /// Get the listener that will be used to receive process events. + /// + /// If no listener has been set via a call to + /// SBLaunchInfo::SetListener(), then an invalid SBListener will be + /// returned (SBListener::IsValid() will return false). If a listener + /// has been set, then the valid listener object will be returned. + //---------------------------------------------------------------------- + SBListener + GetListener (); + + //---------------------------------------------------------------------- + /// Set the listener that will be used to receive process events. + /// + /// By default the SBDebugger, which has a listener, that the SBTarget + /// belongs to will listen for the process events. Calling this function + /// allows a different listener to be used to listen for process events. + //---------------------------------------------------------------------- + void + SetListener (SBListener &listener); + + uint32_t + GetNumArguments (); + + const char * + GetArgumentAtIndex (uint32_t idx); + + void + SetArguments (const char **argv, bool append); + + uint32_t + GetNumEnvironmentEntries (); + + const char * + GetEnvironmentEntryAtIndex (uint32_t idx); + + void + SetEnvironmentEntries (const char **envp, bool append); + + void + Clear (); + + const char * + GetWorkingDirectory () const; + + void + SetWorkingDirectory (const char *working_dir); + + uint32_t + GetLaunchFlags (); + + void + SetLaunchFlags (uint32_t flags); + + const char * + GetProcessPluginName (); + + void + SetProcessPluginName (const char *plugin_name); + + const char * + GetShell (); + + void + SetShell (const char * path); + + uint32_t + GetResumeCount (); + + void + SetResumeCount (uint32_t c); + + bool + AddCloseFileAction (int fd); + + bool + AddDuplicateFileAction (int fd, int dup_fd); + + bool + AddOpenFileAction (int fd, const char *path, bool read, bool write); + + bool + AddSuppressFileAction (int fd, bool read, bool write); + + void + SetLaunchEventData (const char *data); + + const char * + GetLaunchEventData () const; + + bool + GetDetachOnError() const; + + void + SetDetachOnError(bool enable); + +protected: + friend class SBPlatform; + friend class SBTarget; + + lldb_private::ProcessLaunchInfo & + ref (); + + ProcessLaunchInfoSP m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBLaunchInfo_h_ diff --git a/include/lldb/API/SBPlatform.h b/include/lldb/API/SBPlatform.h index 16a546d81f9b..42b2d0492895 100644 --- a/include/lldb/API/SBPlatform.h +++ b/include/lldb/API/SBPlatform.h @@ -12,11 +12,15 @@ #include "lldb/API/SBDefines.h" +#include <functional> + struct PlatformConnectOptions; struct PlatformShellCommand; namespace lldb { + class SBLaunchInfo; + class SBPlatformConnectOptions { public: @@ -171,6 +175,12 @@ namespace lldb { Run (SBPlatformShellCommand &shell_command); SBError + Launch (SBLaunchInfo &launch_info); + + SBError + Kill (const lldb::pid_t pid); + + SBError MakeDirectory (const char *path, uint32_t file_permissions = eFilePermissionsDirectoryDefault); uint32_t @@ -190,6 +200,9 @@ namespace lldb { void SetSP (const lldb::PlatformSP& platform_sp); + SBError + ExecuteConnected (const std::function<lldb_private::Error(const lldb::PlatformSP&)>& func); + lldb::PlatformSP m_opaque_sp; }; diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h index a628467caa43..322cf04159ff 100644 --- a/include/lldb/API/SBTarget.h +++ b/include/lldb/API/SBTarget.h @@ -15,6 +15,7 @@ #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpecList.h" +#include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBSymbolContextList.h" #include "lldb/API/SBType.h" #include "lldb/API/SBValue.h" @@ -24,166 +25,6 @@ namespace lldb { class SBPlatform; -class SBLaunchInfo -{ -public: - SBLaunchInfo (const char **argv); - - ~SBLaunchInfo(); - - uint32_t - GetUserID(); - - uint32_t - GetGroupID(); - - bool - UserIDIsValid (); - - bool - GroupIDIsValid (); - - void - SetUserID (uint32_t uid); - - void - SetGroupID (uint32_t gid); - - SBFileSpec - GetExecutableFile (); - - //---------------------------------------------------------------------- - /// Set the executable file that will be used to launch the process and - /// optionally set it as the first argument in the argument vector. - /// - /// This only needs to be specified if clients wish to carefully control - /// the exact path will be used to launch a binary. If you create a - /// target with a symlink, that symlink will get resolved in the target - /// and the resolved path will get used to launch the process. Calling - /// this function can help you still launch your process using the - /// path of your choice. - /// - /// If this function is not called prior to launching with - /// SBTarget::Launch(...), the target will use the resolved executable - /// path that was used to create the target. - /// - /// @param[in] exe_file - /// The override path to use when launching the executable. - /// - /// @param[in] add_as_first_arg - /// If true, then the path will be inserted into the argument vector - /// prior to launching. Otherwise the argument vector will be left - /// alone. - //---------------------------------------------------------------------- - void - SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg); - - - //---------------------------------------------------------------------- - /// Get the listener that will be used to receive process events. - /// - /// If no listener has been set via a call to - /// SBLaunchInfo::SetListener(), then an invalid SBListener will be - /// returned (SBListener::IsValid() will return false). If a listener - /// has been set, then the valid listener object will be returned. - //---------------------------------------------------------------------- - SBListener - GetListener (); - - //---------------------------------------------------------------------- - /// Set the listener that will be used to receive process events. - /// - /// By default the SBDebugger, which has a listener, that the SBTarget - /// belongs to will listen for the process events. Calling this function - /// allows a different listener to be used to listen for process events. - //---------------------------------------------------------------------- - void - SetListener (SBListener &listener); - - uint32_t - GetNumArguments (); - - const char * - GetArgumentAtIndex (uint32_t idx); - - void - SetArguments (const char **argv, bool append); - - uint32_t - GetNumEnvironmentEntries (); - - const char * - GetEnvironmentEntryAtIndex (uint32_t idx); - - void - SetEnvironmentEntries (const char **envp, bool append); - - void - Clear (); - - const char * - GetWorkingDirectory () const; - - void - SetWorkingDirectory (const char *working_dir); - - uint32_t - GetLaunchFlags (); - - void - SetLaunchFlags (uint32_t flags); - - const char * - GetProcessPluginName (); - - void - SetProcessPluginName (const char *plugin_name); - - const char * - GetShell (); - - void - SetShell (const char * path); - - uint32_t - GetResumeCount (); - - void - SetResumeCount (uint32_t c); - - bool - AddCloseFileAction (int fd); - - bool - AddDuplicateFileAction (int fd, int dup_fd); - - bool - AddOpenFileAction (int fd, const char *path, bool read, bool write); - - bool - AddSuppressFileAction (int fd, bool read, bool write); - - void - SetLaunchEventData (const char *data); - - const char * - GetLaunchEventData () const; - - bool - GetDetachOnError() const; - - void - SetDetachOnError(bool enable); - -protected: - friend class SBTarget; - - lldb_private::ProcessLaunchInfo & - ref (); - - ProcessLaunchInfoSP m_opaque_sp; -}; - class SBAttachInfo { public: diff --git a/include/lldb/API/SBType.h b/include/lldb/API/SBType.h index 303ddff6dc09..7990fc0696a9 100644 --- a/include/lldb/API/SBType.h +++ b/include/lldb/API/SBType.h @@ -153,6 +153,9 @@ public: IsArrayType (); bool + IsVectorType (); + + bool IsTypedefType (); lldb::SBType @@ -175,6 +178,9 @@ public: lldb::SBType GetArrayElementType (); + + lldb::SBType + GetVectorElementType (); lldb::SBType GetCanonicalType(); diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h index 61acc061aebc..883571a3ce9a 100644 --- a/include/lldb/Breakpoint/Breakpoint.h +++ b/include/lldb/Breakpoint/Breakpoint.h @@ -714,6 +714,19 @@ protected: bool IgnoreCountShouldStop (); + void + IncrementHitCount() + { + m_hit_count++; + } + + void + DecrementHitCount() + { + assert (m_hit_count > 0); + m_hit_count--; + } + private: // This one should only be used by Target to copy breakpoints from target to target - primarily from the dummy // target to prime new targets. @@ -733,7 +746,10 @@ private: BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. std::string m_kind_description; bool m_resolve_indirect_symbols; - + uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been hit. This is kept + // separately from the locations hit counts, since locations can go away when + // their backing library gets unloaded, and we would lose hit counts. + void SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind); diff --git a/include/lldb/Breakpoint/BreakpointLocation.h b/include/lldb/Breakpoint/BreakpointLocation.h index 8d5ebce411df..642256386785 100644 --- a/include/lldb/Breakpoint/BreakpointLocation.h +++ b/include/lldb/Breakpoint/BreakpointLocation.h @@ -390,6 +390,7 @@ protected: friend class BreakpointSite; friend class BreakpointLocationList; friend class Process; + friend class StopInfoBreakpoint; //------------------------------------------------------------------ /// Set the breakpoint site for this location to \a bp_site_sp. @@ -417,6 +418,9 @@ private: void BumpHitCount(); + void + UndoBumpHitCount(); + //------------------------------------------------------------------ // Constructors and Destructors diff --git a/include/lldb/Breakpoint/StoppointLocation.h b/include/lldb/Breakpoint/StoppointLocation.h index 452c6388c82d..32a1dbd4386e 100644 --- a/include/lldb/Breakpoint/StoppointLocation.h +++ b/include/lldb/Breakpoint/StoppointLocation.h @@ -134,6 +134,9 @@ protected: ++m_hit_count; } + void + DecrementHitCount (); + private: //------------------------------------------------------------------ // For StoppointLocation only diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h index 694e204cdc0d..93630f043822 100644 --- a/include/lldb/Core/ArchSpec.h +++ b/include/lldb/Core/ArchSpec.h @@ -277,6 +277,21 @@ public: } //------------------------------------------------------------------ + /// Merges fields from another ArchSpec into this ArchSpec. + /// + /// This will use the supplied ArchSpec to fill in any fields of + /// the triple in this ArchSpec which were unspecified. This can + /// be used to refine a generic ArchSpec with a more specific one. + /// For example, if this ArchSpec's triple is something like + /// i386-unknown-unknown-unknown, and we have a triple which is + /// x64-pc-windows-msvc, then merging that triple into this one + /// will result in the triple i386-pc-windows-msvc. + /// + //------------------------------------------------------------------ + void + MergeFrom(const ArchSpec &other); + + //------------------------------------------------------------------ /// Sets this ArchSpec according to the given architecture name. /// /// The architecture name can be one of the generic system default diff --git a/include/lldb/Core/Broadcaster.h b/include/lldb/Core/Broadcaster.h index 64b12ca8a938..6d54b1b43133 100644 --- a/include/lldb/Core/Broadcaster.h +++ b/include/lldb/Core/Broadcaster.h @@ -419,12 +419,7 @@ public: HijackBroadcaster (Listener *listener, uint32_t event_mask = UINT32_MAX); bool - IsHijackedForEvent (uint32_t event_mask) - { - if (m_hijacking_listeners.size() > 0) - return (event_mask & m_hijacking_masks.back()) != 0; - return false; - } + IsHijackedForEvent (uint32_t event_mask); //------------------------------------------------------------------ /// Restore the state of the Broadcaster from a previous hijack attempt. diff --git a/include/lldb/Core/Connection.h b/include/lldb/Core/Connection.h index 775e0c846f85..a7b911ac382f 100644 --- a/include/lldb/Core/Connection.h +++ b/include/lldb/Core/Connection.h @@ -12,6 +12,7 @@ // C Includes // C++ Includes +#include <string> // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" @@ -133,13 +134,13 @@ public: /// /// Subclasses must override this function. /// - /// @param[in] src - /// A source buffer that must be at least \a src_len bytes + /// @param[in] dst + /// A desination buffer that must be at least \a dst_len bytes /// long. /// - /// @param[in] src_len + /// @param[in] dst_len /// The number of bytes to attempt to write, and also the - /// number of bytes are currently available in \a src. + /// number of bytes are currently available in \a dst. /// /// @param[out] error_ptr /// A pointer to an error object that should be given an @@ -150,7 +151,18 @@ public: /// The number of bytes actually Written. //------------------------------------------------------------------ virtual size_t - Write (const void *buffer, size_t length, lldb::ConnectionStatus &status, Error *error_ptr) = 0; + Write (const void *dst, size_t dst_len, lldb::ConnectionStatus &status, Error *error_ptr) = 0; + + //------------------------------------------------------------------ + /// Returns a URI that describes this connection object + /// + /// Subclasses may override this function. + /// + /// @return + /// Returns URI or an empty string if disconnecteds + //------------------------------------------------------------------ + virtual std::string + GetURI() = 0; private: //------------------------------------------------------------------ diff --git a/include/lldb/Core/ConnectionMachPort.h b/include/lldb/Core/ConnectionMachPort.h index 04ec7f69136b..78eb78cb95f4 100644 --- a/include/lldb/Core/ConnectionMachPort.h +++ b/include/lldb/Core/ConnectionMachPort.h @@ -56,6 +56,9 @@ public: lldb::ConnectionStatus &status, lldb_private::Error *error_ptr); + virtual std::string + GetURI(); + lldb::ConnectionStatus BootstrapCheckIn (const char *port_name, lldb_private::Error *error_ptr); @@ -83,6 +86,7 @@ protected: mach_port_t m_port; private: + std::string m_uri; DISALLOW_COPY_AND_ASSIGN (ConnectionMachPort); diff --git a/include/lldb/Core/ConnectionSharedMemory.h b/include/lldb/Core/ConnectionSharedMemory.h index 0f9cdcb8a92d..48e62142954e 100644 --- a/include/lldb/Core/ConnectionSharedMemory.h +++ b/include/lldb/Core/ConnectionSharedMemory.h @@ -53,6 +53,9 @@ public: virtual size_t Write (const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr); + virtual std::string + GetURI(); + lldb::ConnectionStatus Open (bool create, const char *name, size_t size, Error *error_ptr); diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h index 15c832f4bf66..9a3f9736fdca 100644 --- a/include/lldb/Core/Debugger.h +++ b/include/lldb/Core/Debugger.h @@ -19,6 +19,7 @@ #include "lldb/lldb-public.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Communication.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/Listener.h" #include "lldb/Core/SourceManager.h" @@ -158,8 +159,6 @@ public: // To get the target's source manager, call GetSourceManager on the target instead. SourceManager & GetSourceManager (); - -public: lldb::TargetSP GetSelectedTarget () @@ -224,6 +223,12 @@ public: ConstString GetTopIOHandlerControlSequence(char ch); + const char * + GetIOHandlerCommandPrefix(); + + const char * + GetIOHandlerHelpPrologue(); + bool HideTopIOHandler(); @@ -243,15 +248,7 @@ public: GetDebuggerAtIndex (size_t index); static bool - FormatPrompt (const char *format, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s, - ValueObject* valobj = NULL); - - static bool - FormatDisassemblerAddress (const char *format, + FormatDisassemblerAddress (const FormatEntity::Entry *format, const SymbolContext *sc, const SymbolContext *prev_sc, const ExecutionContext *exe_ctx, @@ -296,13 +293,13 @@ public: bool GetAutoConfirm () const; - const char * + const FormatEntity::Entry * GetDisassemblyFormat() const; - const char * + const FormatEntity::Entry * GetFrameFormat() const; - const char * + const FormatEntity::Entry * GetThreadFormat() const; lldb::ScriptLanguage @@ -352,7 +349,6 @@ public: bool GetNotifyVoid () const; - const ConstString & GetInstanceName() diff --git a/include/lldb/Core/Disassembler.h b/include/lldb/Core/Disassembler.h index b0b841b0a925..64d35e67bfd0 100644 --- a/include/lldb/Core/Disassembler.h +++ b/include/lldb/Core/Disassembler.h @@ -117,7 +117,7 @@ public: /// the InstructionList. /// Only needed if show_address is true. /// - /// @param[in] disassembly_addr_format_spec + /// @param[in] disassembly_addr_format /// The format specification for how addresses are printed. /// Only needed if show_address is true. //------------------------------------------------------------------ @@ -130,7 +130,7 @@ public: const ExecutionContext* exe_ctx, const SymbolContext *sym_ctx, const SymbolContext *prev_sym_ctx, - const char *disassembly_addr_format_spec); + const FormatEntity::Entry *disassembly_addr_format); virtual bool DoesBranch () = 0; @@ -457,7 +457,7 @@ protected: //------------------------------------------------------------------ // Classes that inherit from Disassembler can see and modify these //------------------------------------------------------------------ - const ArchSpec m_arch; + ArchSpec m_arch; InstructionList m_instruction_list; lldb::addr_t m_base_addr; std::string m_flavor; diff --git a/include/lldb/Core/FormatEntity.h b/include/lldb/Core/FormatEntity.h new file mode 100644 index 000000000000..32ff9ea4e3eb --- /dev/null +++ b/include/lldb/Core/FormatEntity.h @@ -0,0 +1,260 @@ +//===-- FormatEntity.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_FormatEntity_h_ +#define liblldb_FormatEntity_h_ +#if defined(__cplusplus) + +#include <string> +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Core/Error.h" + +namespace llvm +{ + class StringRef; +} + +namespace lldb_private +{ + class FormatEntity + { + public: + struct Entry + { + enum class Type { + Invalid, + ParentNumber, + ParentString, + InsertString, + Root, + String, + Scope, + Variable, + VariableSynthetic, + ScriptVariable, + ScriptVariableSynthetic, + AddressLoad, + AddressFile, + AddressLoadOrFile, + ProcessID, + ProcessFile, + ScriptProcess, + ThreadID, + ThreadProtocolID, + ThreadIndexID, + ThreadName, + ThreadQueue, + ThreadStopReason, + ThreadReturnValue, + ThreadCompletedExpression, + ScriptThread, + ThreadInfo, + TargetArch, + ScriptTarget, + ModuleFile, + File, + FrameIndex, + FrameRegisterPC, + FrameRegisterSP, + FrameRegisterFP, + FrameRegisterFlags, + FrameRegisterByName, + ScriptFrame, + FunctionID, + FunctionDidChange, + FunctionInitialFunction, + FunctionName, + FunctionNameWithArgs, + FunctionNameNoArgs, + FunctionAddrOffset, + FunctionAddrOffsetConcrete, + FunctionLineOffset, + FunctionPCOffset, + LineEntryFile, + LineEntryLineNumber, + LineEntryStartAddress, + LineEntryEndAddress, + CurrentPCArrow + }; + + enum FormatType + { + None, + UInt32, + UInt64, + CString + }; + + struct Definition + { + const char *name; + const char *string; // Insert this exact string into the output + Entry::Type type; + FormatType format_type; // uint32_t, uint64_t, cstr, or anything that can be formatted by printf or lldb::Format + uint64_t data; + uint32_t num_children; + Definition *children; // An array of "num_children" Definition entries, + bool keep_separator; + }; + + Entry (Type t = Type::Invalid, + const char *s = NULL, + const char *f = NULL) : + string (s ? s : ""), + printf_format (f ? f : ""), + children (), + definition (NULL), + type (t), + fmt (lldb::eFormatDefault), + number (0), + deref (false) + { + } + + Entry (llvm::StringRef s); + Entry (char ch); + + void + AppendChar (char ch); + + void + AppendText (const llvm::StringRef &s); + + void + AppendText (const char *cstr); + + void + AppendEntry (const Entry &&entry) + { + children.push_back(entry); + } + + void + Clear () + { + string.clear(); + printf_format.clear(); + children.clear(); + definition = NULL; + type = Type::Invalid; + fmt = lldb::eFormatDefault; + number = 0; + deref = false; + } + + static const char * + TypeToCString (Type t); + + void + Dump (Stream &s, int depth = 0) const; + + bool + operator == (const Entry &rhs) const + { + if (string != rhs.string) + return false; + if (printf_format != rhs.printf_format) + return false; + const size_t n = children.size(); + const size_t m = rhs.children.size(); + for (size_t i=0; i < std::min<size_t>(n, m); ++i) + { + if (!(children[i] == rhs.children[i])) + return false; + } + if (children != rhs.children) + return false; + if (definition != rhs.definition) + return false; + if (type != rhs.type) + return false; + if (fmt != rhs.fmt) + return false; + if (deref != rhs.deref) + return false; + return true; + } + + std::string string; + std::string printf_format; + std::vector<Entry> children; + Definition *definition; + Type type; + lldb::Format fmt; + lldb::addr_t number; + bool deref; + }; + + static bool + Format (const Entry &entry, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function); + + static bool + FormatStringRef (const llvm::StringRef &format, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function); + + static bool + FormatCString (const char *format, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function); + + static Error + Parse (const llvm::StringRef &format, Entry &entry); + + static Error + ExtractVariableInfo (llvm::StringRef &format_str, + llvm::StringRef &variable_name, + llvm::StringRef &variable_format); + + static size_t + AutoComplete (const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches); + + //---------------------------------------------------------------------- + // Format the current elements into the stream \a s. + // + // The root element will be stripped off and the format str passed in + // will be either an empty string (print a description of this object), + // or contain a . separated series like a domain name that identifies + // further sub elements to display. + //---------------------------------------------------------------------- + static bool + FormatFileSpec (const FileSpec &file, Stream &s, llvm::StringRef elements, llvm::StringRef element_format); + protected: + + static Error + ParseInternal (llvm::StringRef &format, Entry &parent_entry, uint32_t depth); + + }; + +} +#endif // #if defined(__cplusplus) +#endif // liblldb_FormatEntity_h_ diff --git a/include/lldb/Core/Mangled.h b/include/lldb/Core/Mangled.h index 2f3df6afd8dc..87b23799882f 100644 --- a/include/lldb/Core/Mangled.h +++ b/include/lldb/Core/Mangled.h @@ -290,6 +290,25 @@ public: void SetValue (const ConstString &name); + //---------------------------------------------------------------------- + /// Get the language only if it is definitive what the language is from + /// the mangling. + /// + /// For a mangled name to have a language it must have both a mangled + /// and a demangled name and it must be definitive from the mangling + /// what the language is. + /// + /// Standard C function names will return eLanguageTypeUnknown because + /// they aren't mangled and it isn't clear what language the name + /// represents (there will be no mangled name). + /// + /// @return + /// The language for the mangled/demangled name, eLanguageTypeUnknown + /// if there is no mangled or demangled counterpart. + //---------------------------------------------------------------------- + lldb::LanguageType + GetLanguage (); + private: //---------------------------------------------------------------------- /// Mangled member variables. diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h index bfde7cbc5db9..60fbb989502e 100644 --- a/include/lldb/Core/Module.h +++ b/include/lldb/Core/Module.h @@ -941,17 +941,8 @@ public: const ConstString &object_name); bool - GetIsDynamicLinkEditor () const - { - return m_is_dynamic_loader_module; - } - - void - SetIsDynamicLinkEditor (bool b) - { - m_is_dynamic_loader_module = b; - } - + GetIsDynamicLinkEditor (); + ClangASTContext & GetClangASTContext (); @@ -1124,8 +1115,7 @@ protected: bool m_did_load_objfile:1, m_did_load_symbol_vendor:1, m_did_parse_uuid:1, - m_did_init_ast:1, - m_is_dynamic_loader_module:1; + m_did_init_ast:1; mutable bool m_file_has_changed:1, m_first_file_changed_log:1; /// See if the module was modified after it was initially opened. diff --git a/include/lldb/Core/RegularExpression.h b/include/lldb/Core/RegularExpression.h index 00d8310b4806..a58d17b4a794 100644 --- a/include/lldb/Core/RegularExpression.h +++ b/include/lldb/Core/RegularExpression.h @@ -121,23 +121,6 @@ public: //------------------------------------------------------------------ RegularExpression (); - //------------------------------------------------------------------ - /// Constructor that takes a regular expression with flags. - /// - /// Constructor that compiles \a re using \a flags and stores the - /// resulting compiled regular expression into this object. - /// - /// @param[in] re - /// A c string that represents the regular expression to - /// compile. - /// - /// @param[in] flags - /// Flags that are passed to the \c regcomp() function. - //------------------------------------------------------------------ - explicit - RegularExpression (const char* re, int flags); - - // This one uses flags = REG_EXTENDED. explicit RegularExpression (const char* re); @@ -157,7 +140,7 @@ public: /// Compile a regular expression. /// /// Compile a regular expression using the supplied regular - /// expression text and flags. The compiled regular expression lives + /// expression text. The compiled regular expression lives /// in this object so that it can be readily used for regular /// expression matches. Execute() can be called after the regular /// expression is compiled. Any previously compiled regular @@ -167,9 +150,6 @@ public: /// A NULL terminated C string that represents the regular /// expression to compile. /// - /// @param[in] flags - /// Flags that are passed to the \c regcomp() function. - /// /// @return /// \b true if the regular expression compiles successfully, /// \b false otherwise. @@ -177,9 +157,6 @@ public: bool Compile (const char* re); - bool - Compile (const char* re, int flags); - //------------------------------------------------------------------ /// Executes a regular expression. /// @@ -187,8 +164,7 @@ public: /// expression that is already in this object against the match /// string \a s. If any parens are used for regular expression /// matches \a match_count should indicate the number of regmatch_t - /// values that are present in \a match_ptr. The regular expression - /// will be executed using the \a execute_flags + /// values that are present in \a match_ptr. /// /// @param[in] string /// The string to match against the compile regular expression. @@ -198,15 +174,12 @@ public: /// properly initialized with the desired number of maximum /// matches, or NULL if no parenthesized matching is needed. /// - /// @param[in] execute_flags - /// Flags to pass to the \c regexec() function. - /// /// @return /// \b true if \a string matches the compiled regular /// expression, \b false otherwise. //------------------------------------------------------------------ bool - Execute (const char* string, Match *match = NULL, int execute_flags = 0) const; + Execute (const char* string, Match *match = NULL) const; size_t GetErrorAsCString (char *err_str, size_t err_str_max_len) const; @@ -233,12 +206,6 @@ public: const char* GetText () const; - int - GetCompileFlags () const - { - return m_compile_flags; - } - //------------------------------------------------------------------ /// Test if valid. /// @@ -256,7 +223,6 @@ public: { Free(); m_re.clear(); - m_compile_flags = 0; m_comp_err = 1; } @@ -276,7 +242,6 @@ private: std::string m_re; ///< A copy of the original regular expression text int m_comp_err; ///< Error code for the regular expression compilation regex_t m_preg; ///< The compiled regular expression - int m_compile_flags; ///< Stores the flags from the last compile. }; } // namespace lldb_private diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h index fa96c8989913..b50adfb69564 100644 --- a/include/lldb/Core/ValueObject.h +++ b/include/lldb/Core/ValueObject.h @@ -527,9 +527,14 @@ public: virtual lldb::ModuleSP GetModule(); - virtual ValueObject* + ValueObject* GetRoot (); + // Given a ValueObject, loop over itself and its parent, and its parent's parent, .. + // until either the given callback returns false, or you end up at a null pointer + ValueObject* + FollowParentChain (std::function<bool(ValueObject*)>); + virtual bool GetDeclaration (Declaration &decl); @@ -875,6 +880,9 @@ public: virtual lldb::LanguageType GetPreferredDisplayLanguage (); + void + SetPreferredDisplayLanguage (lldb::LanguageType); + lldb::TypeSummaryImplSP GetSummaryFormat() { @@ -1106,6 +1114,8 @@ protected: llvm::SmallVector<uint8_t, 16> m_value_checksum; + lldb::LanguageType m_preferred_display_language; + bool m_value_is_valid:1, m_value_did_change:1, m_children_count_valid:1, diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h index 49c5601dc0e5..aa784add7409 100644 --- a/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -140,6 +140,9 @@ public: return (UpdateValueIfNeeded(), m_provides_value == eLazyBoolYes); } + virtual bool + SetValueFromCString (const char *value_str, Error& error); + protected: virtual bool UpdateValue (); diff --git a/include/lldb/DataFormatters/TypeSummary.h b/include/lldb/DataFormatters/TypeSummary.h index 2d4e03ad9b5d..8b90dd0c4895 100644 --- a/include/lldb/DataFormatters/TypeSummary.h +++ b/include/lldb/DataFormatters/TypeSummary.h @@ -23,6 +23,8 @@ #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/ValueObject.h" #include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Symbol/Type.h" @@ -372,31 +374,27 @@ namespace lldb_private { // simple string-based summaries, using ${var to show data struct StringSummaryFormat : public TypeSummaryImpl { - std::string m_format; + std::string m_format_str; + FormatEntity::Entry m_format; + Error m_error; StringSummaryFormat(const TypeSummaryImpl::Flags& flags, const char* f); + virtual + ~StringSummaryFormat() + { + } + const char* GetSummaryString () const { - return m_format.c_str(); + return m_format_str.c_str(); } void - SetSummaryString (const char* data) - { - if (data) - m_format.assign(data); - else - m_format.clear(); - } - - virtual - ~StringSummaryFormat() - { - } - + SetSummaryString (const char* f); + virtual bool FormatObject(ValueObject *valobj, std::string& dest, diff --git a/include/lldb/Expression/ASTResultSynthesizer.h b/include/lldb/Expression/ASTResultSynthesizer.h index 79709de3546a..410a862fc12a 100644 --- a/include/lldb/Expression/ASTResultSynthesizer.h +++ b/include/lldb/Expression/ASTResultSynthesizer.h @@ -91,7 +91,7 @@ public: //---------------------------------------------------------------------- /// Passthrough stub //---------------------------------------------------------------------- - void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired); + void HandleVTable(clang::CXXRecordDecl *RD); //---------------------------------------------------------------------- /// Passthrough stub diff --git a/include/lldb/Expression/ASTStructExtractor.h b/include/lldb/Expression/ASTStructExtractor.h index 9e467797a398..25193744c9e0 100644 --- a/include/lldb/Expression/ASTStructExtractor.h +++ b/include/lldb/Expression/ASTStructExtractor.h @@ -99,7 +99,7 @@ public: //---------------------------------------------------------------------- /// Passthrough stub //---------------------------------------------------------------------- - void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired); + void HandleVTable(clang::CXXRecordDecl *RD); //---------------------------------------------------------------------- /// Passthrough stub diff --git a/include/lldb/Expression/IRExecutionUnit.h b/include/lldb/Expression/IRExecutionUnit.h index c15c65c92a3b..bd1a795a158e 100644 --- a/include/lldb/Expression/IRExecutionUnit.h +++ b/include/lldb/Expression/IRExecutionUnit.h @@ -207,6 +207,9 @@ private: DisassembleFunction (Stream &stream, lldb::ProcessSP &process_sp); + void + ReportSymbolLookupError(const ConstString &name); + class MemoryManager : public llvm::SectionMemoryManager { public: @@ -282,10 +285,10 @@ private: //------------------------------------------------------------------ /// Passthrough interface stub //------------------------------------------------------------------ + virtual uint64_t getSymbolAddress(const std::string &Name); + virtual void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true) { - return m_default_mm_ap->getPointerToNamedFunction(Name, AbortOnFailure); - } + bool AbortOnFailure = true); private: std::unique_ptr<SectionMemoryManager> m_default_mm_ap; ///< The memory allocator to use in actually creating space. All calls are passed through to it. IRExecutionUnit &m_parent; ///< The execution unit this is a proxy for. @@ -390,6 +393,7 @@ private: std::vector<std::string> m_cpu_features; llvm::SmallVector<JittedFunction, 1> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code const ConstString m_name; + std::vector<ConstString> m_failed_lookups; std::atomic<bool> m_did_jit; diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h index 2738679b5e03..8219cc06fdc2 100644 --- a/include/lldb/Host/File.h +++ b/include/lldb/Host/File.h @@ -42,7 +42,8 @@ public: 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 - eOpenoptionDontFollowSymlinks = (1u << 7) + eOpenoptionDontFollowSymlinks = (1u << 7), + eOpenOptionCloseOnExec = (1u << 8) // Close the file when executing a new process }; static mode_t diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h index ce12689fc047..9a68c698c826 100644 --- a/include/lldb/Host/Host.h +++ b/include/lldb/Host/Host.h @@ -246,9 +246,6 @@ public: static const lldb_private::UnixSignalsSP& GetUnixSignals (); - static lldb::pid_t - LaunchApplication (const FileSpec &app_file_spec); - static Error LaunchProcess (ProcessLaunchInfo &launch_info); diff --git a/include/lldb/Host/PipeBase.h b/include/lldb/Host/PipeBase.h index 8cad2507d32c..5ef2bb530281 100644 --- a/include/lldb/Host/PipeBase.h +++ b/include/lldb/Host/PipeBase.h @@ -14,6 +14,7 @@ #include <string> #include "lldb/Core/Error.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" namespace lldb_private @@ -25,6 +26,7 @@ class PipeBase virtual Error CreateNew(bool child_process_inherit) = 0; virtual Error CreateNew(llvm::StringRef name, bool child_process_inherit) = 0; + virtual Error CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name) = 0; virtual Error OpenAsReader(llvm::StringRef name, bool child_process_inherit) = 0; diff --git a/include/lldb/Host/Socket.h b/include/lldb/Host/Socket.h index 77069ae35f79..ee85f85fcaf2 100644 --- a/include/lldb/Host/Socket.h +++ b/include/lldb/Host/Socket.h @@ -70,22 +70,35 @@ public: int GetOption (int level, int option_name, int &option_value); int SetOption (int level, int option_name, int option_value); - static uint16_t GetPortNumber(const NativeSocket& socket); - uint16_t GetPortNumber () const; + // returns port number or 0 if error + static uint16_t GetLocalPortNumber (const NativeSocket& socket); + + // returns port number or 0 if error + uint16_t GetLocalPortNumber () const; + + // returns ip address string or empty string if error + std::string GetLocalIPAddress () const; + + // must be connected + // returns port number or 0 if error + uint16_t GetRemotePortNumber () const; + + // must be connected + // returns ip address string or empty string if error + std::string GetRemoteIPAddress () const; NativeSocket GetNativeSocket () const { return m_socket; } - SocketProtocol GetSocketProtocol() const { return m_protocol; } + SocketProtocol GetSocketProtocol () const { return m_protocol; } virtual Error Read (void *buf, size_t &num_bytes); virtual Error Write (const void *buf, size_t &num_bytes); - virtual Error PreDisconnect(); - virtual Error Close(); + virtual Error PreDisconnect (); + virtual Error Close (); - virtual bool IsValid() const { return m_socket != kInvalidSocketValue; } - virtual WaitableHandle GetWaitableHandle(); + virtual bool IsValid () const { return m_socket != kInvalidSocketValue; } + virtual WaitableHandle GetWaitableHandle (); -protected: static bool DecodeHostAndPort (llvm::StringRef host_and_port, std::string &host_str, @@ -93,7 +106,7 @@ protected: int32_t& port, Error *error_ptr); - +protected: SocketProtocol m_protocol; NativeSocket m_socket; SocketAddress m_udp_send_sockaddr; // Send address used for UDP connections. diff --git a/include/lldb/Host/SocketAddress.h b/include/lldb/Host/SocketAddress.h index 3598a42a82d0..9666f56489f6 100644 --- a/include/lldb/Host/SocketAddress.h +++ b/include/lldb/Host/SocketAddress.h @@ -31,6 +31,7 @@ typedef ADDRESS_FAMILY sa_family_t; // C++ Includes // Other libraries and framework includes // Project includes +#include <string> namespace lldb_private { @@ -100,6 +101,12 @@ public: SetFamily (sa_family_t family); //------------------------------------------------------------------ + // Get the address + //------------------------------------------------------------------ + std::string + GetIPAddress () const; + + //------------------------------------------------------------------ // Get the port if the socket address for the family has a port //------------------------------------------------------------------ uint16_t diff --git a/include/lldb/Host/StringConvert.h b/include/lldb/Host/StringConvert.h new file mode 100644 index 000000000000..3cc260cf2be1 --- /dev/null +++ b/include/lldb/Host/StringConvert.h @@ -0,0 +1,45 @@ +//===-- StringConvert.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_StringConvert_h_ +#define liblldb_StringConvert_h_ + +// C Includes +#include <stdint.h> + +// C++ Includes + +// Other libraries and framework includes +// Project includes + +namespace lldb_private { + +namespace StringConvert { + +//---------------------------------------------------------------------- +/// @namespace StringConvert StringConvert.h "lldb/Host/StringConvert.h" +/// @brief Utility classes for converting strings into Integers +//---------------------------------------------------------------------- + +int32_t +ToSInt32 (const char *s, int32_t fail_value = 0, int base = 0, bool *success_ptr = nullptr); + +uint32_t +ToUInt32 (const char *s, uint32_t fail_value = 0, int base = 0, bool *success_ptr = nullptr); + +int64_t +ToSInt64 (const char *s, int64_t fail_value = 0, int base = 0, bool *success_ptr = nullptr); + +uint64_t +ToUInt64 (const char *s, uint64_t fail_value = 0, int base = 0, bool *success_ptr = nullptr); + +} // namespace StringConvert +} // namespace lldb_private + +#endif diff --git a/source/Host/common/NativeBreakpoint.h b/include/lldb/Host/common/NativeBreakpoint.h index 367003b94e35..367003b94e35 100644 --- a/source/Host/common/NativeBreakpoint.h +++ b/include/lldb/Host/common/NativeBreakpoint.h diff --git a/source/Host/common/NativeBreakpointList.h b/include/lldb/Host/common/NativeBreakpointList.h index 51617330d075..51617330d075 100644 --- a/source/Host/common/NativeBreakpointList.h +++ b/include/lldb/Host/common/NativeBreakpointList.h diff --git a/source/Host/common/NativeProcessProtocol.h b/include/lldb/Host/common/NativeProcessProtocol.h index 19d8f353b26f..83c14a5ab37a 100644 --- a/source/Host/common/NativeProcessProtocol.h +++ b/include/lldb/Host/common/NativeProcessProtocol.h @@ -18,6 +18,7 @@ #include "lldb/Host/Mutex.h" #include "NativeBreakpointList.h" +#include "NativeWatchpointList.h" namespace lldb_private { @@ -130,6 +131,9 @@ namespace lldb_private //---------------------------------------------------------------------- // Watchpoint functions //---------------------------------------------------------------------- + virtual const NativeWatchpointList::WatchpointMap& + GetWatchpointMap () const; + virtual uint32_t GetMaxWatchpoints () const; @@ -295,6 +299,7 @@ namespace lldb_private Mutex m_delegates_mutex; std::vector<NativeDelegate*> m_delegates; NativeBreakpointList m_breakpoint_list; + NativeWatchpointList m_watchpoint_list; int m_terminal_fd; uint32_t m_stop_id; diff --git a/include/lldb/Target/NativeRegisterContext.h b/include/lldb/Host/common/NativeRegisterContext.h index fa4ab013f234..e9c03e3c20a4 100644 --- a/include/lldb/Target/NativeRegisterContext.h +++ b/include/lldb/Host/common/NativeRegisterContext.h @@ -15,6 +15,7 @@ // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" +#include "lldb/Host/common/NativeWatchpointList.h" namespace lldb_private { @@ -44,6 +45,9 @@ public: virtual uint32_t GetRegisterCount () const = 0; + virtual uint32_t + GetUserRegisterCount () const = 0; + virtual const RegisterInfo * GetRegisterInfoAtIndex (uint32_t reg) const = 0; @@ -92,6 +96,9 @@ public: virtual bool ClearHardwareWatchpoint (uint32_t hw_index); + virtual Error + ClearAllHardwareWatchpoints (); + virtual bool HardwareSingleStep (bool enable); diff --git a/include/lldb/Target/NativeRegisterContextRegisterInfo.h b/include/lldb/Host/common/NativeRegisterContextRegisterInfo.h index 5631005ca56e..b2a29de4e5a4 100644 --- a/include/lldb/Target/NativeRegisterContextRegisterInfo.h +++ b/include/lldb/Host/common/NativeRegisterContextRegisterInfo.h @@ -31,6 +31,9 @@ namespace lldb_private uint32_t GetRegisterCount () const override; + uint32_t + GetUserRegisterCount () const override; + const RegisterInfo * GetRegisterInfoAtIndex (uint32_t reg_index) const override; diff --git a/source/Host/common/NativeThreadProtocol.h b/include/lldb/Host/common/NativeThreadProtocol.h index 15ecffe8b82d..954ffb36a94f 100644 --- a/source/Host/common/NativeThreadProtocol.h +++ b/include/lldb/Host/common/NativeThreadProtocol.h @@ -53,10 +53,7 @@ namespace lldb_private RestoreAllRegisters (lldb::DataBufferSP &data_sp); virtual bool - GetStopReason (ThreadStopInfo &stop_info) = 0; - - virtual uint32_t - TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const; + GetStopReason (ThreadStopInfo &stop_info, std::string& description) = 0; lldb::tid_t GetID() const diff --git a/include/lldb/Host/common/NativeWatchpointList.h b/include/lldb/Host/common/NativeWatchpointList.h new file mode 100644 index 000000000000..7b310e5a0db0 --- /dev/null +++ b/include/lldb/Host/common/NativeWatchpointList.h @@ -0,0 +1,47 @@ +//===-- NativeWatchpointList.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_NativeWatchpointList_h_ +#define liblldb_NativeWatchpointList_h_ + +#include "lldb/lldb-private-forward.h" +#include "lldb/Core/Error.h" + +#include <map> + +namespace lldb_private +{ + struct NativeWatchpoint + { + lldb::addr_t m_addr; + size_t m_size; + uint32_t m_watch_flags; + bool m_hardware; + }; + + class NativeWatchpointList + { + public: + Error + Add (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware); + + Error + Remove (lldb::addr_t addr); + + using WatchpointMap = std::map<lldb::addr_t, NativeWatchpoint>; + + const WatchpointMap& + GetWatchpointMap () const; + + private: + WatchpointMap m_watchpoints; + }; +} + +#endif // ifndef liblldb_NativeWatchpointList_h_ diff --git a/source/Host/common/SoftwareBreakpoint.h b/include/lldb/Host/common/SoftwareBreakpoint.h index 1fed19eca612..1fed19eca612 100644 --- a/source/Host/common/SoftwareBreakpoint.h +++ b/include/lldb/Host/common/SoftwareBreakpoint.h diff --git a/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h index 4d326d71fa75..660b9d169bfc 100644 --- a/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h +++ b/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h @@ -50,6 +50,8 @@ class ConnectionFileDescriptor : public Connection virtual size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr); + virtual std::string GetURI(); + lldb::ConnectionStatus BytesAvailable(uint32_t timeout_usec, Error *error_ptr); bool InterruptRead(); @@ -75,7 +77,7 @@ class ConnectionFileDescriptor : public Connection void CloseCommandPipe(); - lldb::ConnectionStatus SocketListen(const char *host_and_port, Error *error_ptr); + lldb::ConnectionStatus SocketListenAndAccept(const char *host_and_port, Error *error_ptr); lldb::ConnectionStatus ConnectTCP(const char *host_and_port, Error *error_ptr); @@ -99,6 +101,8 @@ class ConnectionFileDescriptor : public Connection bool m_waiting_for_accept; bool m_child_processes_inherit; + std::string m_uri; + private: DISALLOW_COPY_AND_ASSIGN(ConnectionFileDescriptor); }; diff --git a/include/lldb/Host/posix/PipePosix.h b/include/lldb/Host/posix/PipePosix.h index 0ab3ff7f6775..fbdac66149d6 100644 --- a/include/lldb/Host/posix/PipePosix.h +++ b/include/lldb/Host/posix/PipePosix.h @@ -36,6 +36,8 @@ public: Error CreateNew(llvm::StringRef name, bool child_process_inherit) override; Error + CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name) override; + Error OpenAsReader(llvm::StringRef name, bool child_process_inherit) override; Error OpenAsWriterWithTimeout(llvm::StringRef name, bool child_process_inherit, const std::chrono::microseconds &timeout) override; diff --git a/include/lldb/Interpreter/Args.h b/include/lldb/Interpreter/Args.h index 1071bd6fd047..fe29df468de7 100644 --- a/include/lldb/Interpreter/Args.h +++ b/include/lldb/Interpreter/Args.h @@ -347,18 +347,6 @@ public: bool trailing = true, bool return_null_if_empty = true); - static int32_t - StringToSInt32 (const char *s, int32_t fail_value = 0, int base = 0, bool *success_ptr = NULL); - - static uint32_t - StringToUInt32 (const char *s, uint32_t fail_value = 0, int base = 0, bool *success_ptr = NULL); - - static int64_t - StringToSInt64 (const char *s, int64_t fail_value = 0, int base = 0, bool *success_ptr = NULL); - - static uint64_t - StringToUInt64 (const char *s, uint64_t fail_value = 0, int base = 0, bool *success_ptr = NULL); - static bool UInt64ValueIsValidForByteSize (uint64_t uval64, size_t total_byte_size) { diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h index baaa271a4285..20b6ff95be8b 100644 --- a/include/lldb/Interpreter/CommandInterpreter.h +++ b/include/lldb/Interpreter/CommandInterpreter.h @@ -224,6 +224,7 @@ public: eCommandTypesBuiltin = 0x0001, // native commands such as "frame" eCommandTypesUserDef = 0x0002, // scripted commands eCommandTypesAliases = 0x0004, // aliases such as "po" + eCommandTypesHidden = 0x0008, // commands prefixed with an underscore eCommandTypesAllThem = 0xFFFF // all commands }; @@ -431,6 +432,11 @@ public: StreamString &help_string); void + OutputFormattedHelpText (Stream &strm, + const char *prefix, + const char *help_text); + + void OutputFormattedHelpText (Stream &stream, const char *command_word, const char *separator, @@ -607,6 +613,9 @@ public: bool asynchronously, void *baton); + const char * + GetCommandPrefix (); + //------------------------------------------------------------------ // Properties //------------------------------------------------------------------ diff --git a/include/lldb/Interpreter/OptionGroupPlatform.h b/include/lldb/Interpreter/OptionGroupPlatform.h index 970ad328ccb7..f7de50c86a56 100644 --- a/include/lldb/Interpreter/OptionGroupPlatform.h +++ b/include/lldb/Interpreter/OptionGroupPlatform.h @@ -102,8 +102,10 @@ public: SetSDKBuild (const ConstString &sdk_build) { m_sdk_build = sdk_build; - } - + } + + bool + PlatformMatches(const lldb::PlatformSP &platform_sp) const; protected: std::string m_platform_name; diff --git a/include/lldb/Interpreter/OptionValue.h b/include/lldb/Interpreter/OptionValue.h index 0e8f23453a8a..787430a96ef5 100644 --- a/include/lldb/Interpreter/OptionValue.h +++ b/include/lldb/Interpreter/OptionValue.h @@ -17,6 +17,7 @@ #include "lldb/lldb-defines.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" +#include "lldb/Core/FormatEntity.h" namespace lldb_private { @@ -45,7 +46,8 @@ namespace lldb_private { eTypeSInt64, eTypeString, eTypeUInt64, - eTypeUUID + eTypeUUID, + eTypeFormatEntity } Type; enum { @@ -309,7 +311,13 @@ namespace lldb_private { const OptionValueUUID * GetAsUUID () const; - + + OptionValueFormatEntity * + GetAsFormatEntity (); + + const OptionValueFormatEntity * + GetAsFormatEntity () const; + bool GetBooleanValue (bool fail_value = false) const; @@ -341,6 +349,9 @@ namespace lldb_private { bool SetFormatValue (lldb::Format new_value); + const FormatEntity::Entry * + GetFormatEntity () const; + const RegularExpression * GetRegexValue () const; diff --git a/include/lldb/Interpreter/OptionValueFormatEntity.h b/include/lldb/Interpreter/OptionValueFormatEntity.h new file mode 100644 index 000000000000..cc988998bda0 --- /dev/null +++ b/include/lldb/Interpreter/OptionValueFormatEntity.h @@ -0,0 +1,107 @@ +//===-- OptionValueFormatEntity.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_OptionValueFormatEntity_h_ +#define liblldb_OptionValueFormatEntity_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/FormatEntity.h" +#include "lldb/Interpreter/OptionValue.h" + +namespace lldb_private { + +class OptionValueFormatEntity : public OptionValue +{ +public: + OptionValueFormatEntity (const char *default_format); + + virtual + ~OptionValueFormatEntity() + { + } + + //--------------------------------------------------------------------- + // Virtual subclass pure virtual overrides + //--------------------------------------------------------------------- + + OptionValue::Type + GetType () const override + { + return eTypeFormatEntity; + } + + void + DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) override; + + Error + SetValueFromCString (const char *value, + VarSetOperationType op = eVarSetOperationAssign) override; + + bool + Clear () override; + + lldb::OptionValueSP + DeepCopy () const override; + + size_t + AutoComplete (CommandInterpreter &interpreter, + const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) override; + + //--------------------------------------------------------------------- + // Subclass specific functions + //--------------------------------------------------------------------- + + FormatEntity::Entry & + GetCurrentValue() + { + return m_current_entry; + } + + const FormatEntity::Entry & + GetCurrentValue() const + { + return m_current_entry; + } + + void + SetCurrentValue (const FormatEntity::Entry &value) + { + m_current_entry = value; + } + + FormatEntity::Entry & + GetDefaultValue() + { + return m_default_entry; + } + + const FormatEntity::Entry & + GetDefaultValue() const + { + return m_default_entry; + } + + +protected: + std::string m_current_format; + std::string m_default_format; + FormatEntity::Entry m_current_entry; + FormatEntity::Entry m_default_entry; +}; + +} // namespace lldb_private + +#endif // liblldb_OptionValueFormatEntity_h_ diff --git a/include/lldb/Interpreter/OptionValueProperties.h b/include/lldb/Interpreter/OptionValueProperties.h index a67ea5d66e54..6f7f4995ed15 100644 --- a/include/lldb/Interpreter/OptionValueProperties.h +++ b/include/lldb/Interpreter/OptionValueProperties.h @@ -15,6 +15,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/ConstString.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/UniqueCStringMap.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Interpreter/Property.h" @@ -191,6 +192,9 @@ public: bool SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value); + const FormatEntity::Entry * + GetPropertyAtIndexAsFormatEntity (const ExecutionContext *exe_ctx, uint32_t idx); + const RegularExpression * GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const; diff --git a/include/lldb/Interpreter/OptionValueRegex.h b/include/lldb/Interpreter/OptionValueRegex.h index bb8c4588e22a..295bb98b69e6 100644 --- a/include/lldb/Interpreter/OptionValueRegex.h +++ b/include/lldb/Interpreter/OptionValueRegex.h @@ -24,9 +24,9 @@ namespace lldb_private { class OptionValueRegex : public OptionValue { public: - OptionValueRegex (const char *value = NULL, uint32_t regex_flags = 0) : + OptionValueRegex (const char *value = NULL) : OptionValue(), - m_regex (value, regex_flags) + m_regex (value) { } @@ -75,10 +75,10 @@ public: } void - SetCurrentValue (const char *value, uint32_t regex_flags) + SetCurrentValue (const char *value) { if (value && value[0]) - m_regex.Compile (value, regex_flags); + m_regex.Compile (value); else m_regex.Clear(); } diff --git a/include/lldb/Interpreter/OptionValues.h b/include/lldb/Interpreter/OptionValues.h index c66fc4dab2f6..2ccab994674b 100644 --- a/include/lldb/Interpreter/OptionValues.h +++ b/include/lldb/Interpreter/OptionValues.h @@ -21,6 +21,7 @@ #include "lldb/Interpreter/OptionValueFileSpec.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueFormat.h" +#include "lldb/Interpreter/OptionValueFormatEntity.h" #include "lldb/Interpreter/OptionValuePathMappings.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/OptionValueRegex.h" diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h index 35ba9491ded0..1b4b88161927 100644 --- a/include/lldb/Interpreter/ScriptInterpreter.h +++ b/include/lldb/Interpreter/ScriptInterpreter.h @@ -240,7 +240,13 @@ public: bool m_set_lldb_globals; bool m_maskout_errors; }; - + + virtual bool + Interrupt() + { + return false; + } + virtual bool ExecuteOneLine (const char *command, CommandReturnObject *result, @@ -290,13 +296,13 @@ public: } virtual bool - GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token = NULL) + GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token = NULL) { return false; } virtual bool - GenerateTypeScriptFunction (StringList &input, std::string& output, void* name_token = NULL) + GenerateTypeScriptFunction (StringList &input, std::string& output, const void* name_token = NULL) { return false; } @@ -308,13 +314,13 @@ public: } virtual bool - GenerateTypeSynthClass (StringList &input, std::string& output, void* name_token = NULL) + GenerateTypeSynthClass (StringList &input, std::string& output, const void* name_token = NULL) { return false; } virtual bool - GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token = NULL) + GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token = NULL) { return false; } diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h index edcc4c44facb..94ed16e02ca2 100644 --- a/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -41,125 +41,128 @@ public: ~ScriptInterpreterPython (); bool + Interrupt() override; + + bool ExecuteOneLine (const char *command, CommandReturnObject *result, - const ExecuteScriptOptions &options = ExecuteScriptOptions()); + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; void - ExecuteInterpreterLoop (); + ExecuteInterpreterLoop () override; bool ExecuteOneLineWithReturn (const char *in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, - const ExecuteScriptOptions &options = ExecuteScriptOptions()); + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; lldb_private::Error ExecuteMultipleLines (const char *in_string, - const ExecuteScriptOptions &options = ExecuteScriptOptions()); + const ExecuteScriptOptions &options = ExecuteScriptOptions()) override; Error - ExportFunctionDefinitionToInterpreter (StringList &function_def); + ExportFunctionDefinitionToInterpreter (StringList &function_def) override; bool - GenerateTypeScriptFunction (StringList &input, std::string& output, void* name_token = NULL); + GenerateTypeScriptFunction (StringList &input, std::string& output, const void* name_token = NULL) override; bool - GenerateTypeSynthClass (StringList &input, std::string& output, void* name_token = NULL); + GenerateTypeSynthClass (StringList &input, std::string& output, const void* name_token = NULL) override; bool - GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token = NULL); + GenerateTypeSynthClass (const char* oneliner, std::string& output, const void* name_token = NULL) override; // use this if the function code is just a one-liner script bool - GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token = NULL); + GenerateTypeScriptFunction (const char* oneliner, std::string& output, const void* name_token = NULL) override; - virtual bool - GenerateScriptAliasFunction (StringList &input, std::string& output); + bool + GenerateScriptAliasFunction (StringList &input, std::string& output) override; lldb::ScriptInterpreterObjectSP CreateSyntheticScriptedProvider (const char *class_name, - lldb::ValueObjectSP valobj); + lldb::ValueObjectSP valobj) override; lldb::ScriptInterpreterObjectSP - virtual CreateScriptedThreadPlan (const char *class_name, - lldb::ThreadPlanSP thread_plan); + CreateScriptedThreadPlan (const char *class_name, + lldb::ThreadPlanSP thread_plan) override; - virtual bool + bool ScriptedThreadPlanExplainsStop (lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, - bool &script_error); - virtual bool + bool &script_error) override; + bool ScriptedThreadPlanShouldStop (lldb::ScriptInterpreterObjectSP implementor_sp, Event *event, - bool &script_error); - virtual lldb::StateType + bool &script_error) override; + lldb::StateType ScriptedThreadPlanGetRunState (lldb::ScriptInterpreterObjectSP implementor_sp, - bool &script_error); + bool &script_error) override; - virtual lldb::ScriptInterpreterObjectSP + lldb::ScriptInterpreterObjectSP OSPlugin_CreatePluginObject (const char *class_name, - lldb::ProcessSP process_sp); + lldb::ProcessSP process_sp) override; - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp); + lldb::ScriptInterpreterObjectSP + OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; - virtual lldb::ScriptInterpreterObjectSP - OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp); + lldb::ScriptInterpreterObjectSP + OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) override; - virtual lldb::ScriptInterpreterObjectSP + lldb::ScriptInterpreterObjectSP OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, - lldb::tid_t thread_id); + lldb::tid_t thread_id) override; - virtual lldb::ScriptInterpreterObjectSP + lldb::ScriptInterpreterObjectSP OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid, - lldb::addr_t context); + lldb::addr_t context) override; - virtual lldb::ScriptInterpreterObjectSP + lldb::ScriptInterpreterObjectSP LoadPluginModule (const FileSpec& file_spec, - lldb_private::Error& error); + lldb_private::Error& error) override; - virtual lldb::ScriptInterpreterObjectSP + lldb::ScriptInterpreterObjectSP GetDynamicSettings (lldb::ScriptInterpreterObjectSP plugin_module_sp, Target* target, const char* setting_name, - lldb_private::Error& error); + lldb_private::Error& error) override; - virtual size_t - CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor); + size_t + CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor) override; - virtual lldb::ValueObjectSP - GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx); + lldb::ValueObjectSP + GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx) override; - virtual int - GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name); + int + GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name) override; - virtual bool - UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor); + bool + UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override; - virtual bool - MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor); + bool + MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor) override; - virtual lldb::ValueObjectSP - GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor); + lldb::ValueObjectSP + GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor) override; - virtual bool + bool RunScriptBasedCommand(const char* impl_function, const char* args, ScriptedCommandSynchronicity synchronicity, lldb_private::CommandReturnObject& cmd_retobj, Error& error, - const lldb_private::ExecutionContext& exe_ctx); + const lldb_private::ExecutionContext& exe_ctx) override; Error - GenerateFunction(const char *signature, const StringList &input); + GenerateFunction(const char *signature, const StringList &input) override; Error - GenerateBreakpointCommandCallbackData (StringList &input, std::string& output); + GenerateBreakpointCommandCallbackData (StringList &input, std::string& output) override; bool - GenerateWatchpointCommandCallbackData (StringList &input, std::string& output); + GenerateWatchpointCommandCallbackData (StringList &input, std::string& output) override; // static size_t // GenerateBreakpointOptionsCommandCallback (void *baton, @@ -186,21 +189,21 @@ public: StoppointCallbackContext *context, lldb::user_id_t watch_id); - virtual bool + bool GetScriptedSummary (const char *function_name, lldb::ValueObjectSP valobj, lldb::ScriptInterpreterObjectSP& callee_wrapper_sp, const TypeSummaryOptions& options, - std::string& retval); + std::string& retval) override; - virtual void - Clear (); + void + Clear () override; - virtual bool - GetDocumentationForItem (const char* item, std::string& dest); + bool + GetDocumentationForItem (const char* item, std::string& dest) override; - virtual bool - CheckObjectExists (const char* name) + bool + CheckObjectExists (const char* name) override { if (!name || !name[0]) return false; @@ -208,76 +211,76 @@ public: return GetDocumentationForItem (name,temp); } - virtual bool + bool RunScriptFormatKeyword (const char* impl_function, Process* process, std::string& output, - Error& error); + Error& error) override; - virtual bool + bool RunScriptFormatKeyword (const char* impl_function, Thread* thread, std::string& output, - Error& error); + Error& error) override; - virtual bool + bool RunScriptFormatKeyword (const char* impl_function, Target* target, std::string& output, - Error& error); + Error& error) override; - virtual bool + bool RunScriptFormatKeyword (const char* impl_function, StackFrame* frame, std::string& output, - Error& error); + Error& error) override; - virtual bool + bool RunScriptFormatKeyword (const char* impl_function, ValueObject* value, std::string& output, - Error& error); + Error& error) override; - virtual bool + bool LoadScriptingModule (const char* filename, bool can_reload, bool init_session, lldb_private::Error& error, - lldb::ScriptInterpreterObjectSP* module_sp = nullptr); + lldb::ScriptInterpreterObjectSP* module_sp = nullptr) override; - virtual lldb::ScriptInterpreterObjectSP - MakeScriptObject (void* object); + lldb::ScriptInterpreterObjectSP + MakeScriptObject (void* object) override; - virtual std::unique_ptr<ScriptInterpreterLocker> - AcquireInterpreterLock (); + std::unique_ptr<ScriptInterpreterLocker> + AcquireInterpreterLock () override; void CollectDataForBreakpointCommandCallback (std::vector<BreakpointOptions *> &bp_options_vec, - CommandReturnObject &result); + CommandReturnObject &result) override; void CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, - CommandReturnObject &result); + CommandReturnObject &result) override; /// Set the callback body text into the callback for the breakpoint. Error SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *callback_body); + const char *callback_body) override; void SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, - const char *function_name); + const char *function_name) override; /// Set a one-liner as the callback for the watchpoint. void SetWatchpointCommandCallback (WatchpointOptions *wp_options, - const char *oneliner); + const char *oneliner) override; StringList ReadCommandInputFromUser (FILE *in_file); virtual void - ResetOutputFileHandle (FILE *new_fh); + ResetOutputFileHandle (FILE *new_fh) override; static void InitializePrivate (); @@ -331,11 +334,11 @@ public: //---------------------------------------------------------------------- // IOHandlerDelegate //---------------------------------------------------------------------- - virtual void - IOHandlerActivated (IOHandler &io_handler); + void + IOHandlerActivated (IOHandler &io_handler) override; - virtual void - IOHandlerInputComplete (IOHandler &io_handler, std::string &data); + void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override; protected: @@ -448,6 +451,26 @@ public: }; protected: + uint32_t + IsExecutingPython () const + { + return m_lock_count > 0; + } + + uint32_t + IncrementLockCount() + { + return ++m_lock_count; + } + + uint32_t + DecrementLockCount() + { + if (m_lock_count > 0) + --m_lock_count; + return m_lock_count; + } + enum ActiveIOHandler { eIOHandlerNone, eIOHandlerBreakpoint, @@ -480,6 +503,7 @@ protected: bool m_session_is_active; bool m_pty_slave_is_open; bool m_valid_session; + uint32_t m_lock_count; PyThreadState *m_command_thread_state; }; } // namespace lldb_private diff --git a/include/lldb/Symbol/ClangASTType.h b/include/lldb/Symbol/ClangASTType.h index ef23a8be645b..94c768780a00 100644 --- a/include/lldb/Symbol/ClangASTType.h +++ b/include/lldb/Symbol/ClangASTType.h @@ -97,6 +97,10 @@ public: bool *is_incomplete) const; bool + IsVectorType (ClangASTType *element_type, + uint64_t *size) const; + + bool IsArrayOfScalarType () const; bool @@ -347,10 +351,10 @@ public: //---------------------------------------------------------------------- uint64_t - GetByteSize () const; + GetByteSize (ExecutionContext *exe_ctx) const; uint64_t - GetBitSize () const; + GetBitSize (ExecutionContext *exe_ctx) const; lldb::Encoding GetEncoding (uint64_t &count) const; diff --git a/include/lldb/Symbol/ObjectFile.h b/include/lldb/Symbol/ObjectFile.h index bdc6ae8c9e81..8bcf92de42e5 100644 --- a/include/lldb/Symbol/ObjectFile.h +++ b/include/lldb/Symbol/ObjectFile.h @@ -767,6 +767,23 @@ public: return 0; } + + //------------------------------------------------------------------ + /// Return true if this file is a dynamic link editor (dyld) + /// + /// Often times dyld has symbols that mirror symbols in libc and + /// other shared libraries (like "malloc" and "free") and the user + /// does _not_ want to stop in these shared libraries by default. + /// We can ask the ObjectFile if it is such a file and should be + /// avoided for things like settings breakpoints and doing function + /// lookups for expressions. + //------------------------------------------------------------------ + virtual bool + GetIsDynamicLinkEditor() + { + return false; + } + //------------------------------------------------------------------ // Member Functions //------------------------------------------------------------------ diff --git a/include/lldb/Symbol/SymbolContext.h b/include/lldb/Symbol/SymbolContext.h index d40d1453cb17..64490627b84d 100644 --- a/include/lldb/Symbol/SymbolContext.h +++ b/include/lldb/Symbol/SymbolContext.h @@ -347,6 +347,7 @@ public: Block * block; ///< The Block for a given query LineEntry line_entry; ///< The LineEntry for a given query Symbol * symbol; ///< The Symbol for a given query + Variable * variable; ///< The global variable matching the given query }; diff --git a/include/lldb/Target/FileAction.h b/include/lldb/Target/FileAction.h index 228a9e6098c1..4015cbb5ea89 100644 --- a/include/lldb/Target/FileAction.h +++ b/include/lldb/Target/FileAction.h @@ -1,4 +1,4 @@ -//===-- ProcessLaunchInfo.h -------------------------------------*- C++ -*-===// +//===-- FileAction.h --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // diff --git a/include/lldb/Target/LanguageRuntime.h b/include/lldb/Target/LanguageRuntime.h index 0aaa67c2382c..d5ed81956475 100644 --- a/include/lldb/Target/LanguageRuntime.h +++ b/include/lldb/Target/LanguageRuntime.h @@ -102,6 +102,13 @@ public: virtual lldb::SearchFilterSP CreateExceptionSearchFilter (); + + virtual bool + GetTypeBitSize (const ClangASTType& clang_type, + uint64_t &size) + { + return false; + } protected: //------------------------------------------------------------------ diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h index a3fee91428fa..42a391478e3e 100644 --- a/include/lldb/Target/ObjCLanguageRuntime.h +++ b/include/lldb/Target/ObjCLanguageRuntime.h @@ -20,6 +20,7 @@ // Project includes #include "lldb/lldb-private.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Symbol/Type.h" @@ -514,6 +515,10 @@ public: m_negative_complete_class_cache.clear(); } + virtual bool + GetTypeBitSize (const ClangASTType& clang_type, + uint64_t &size); + protected: //------------------------------------------------------------------ // Classes that inherit from ObjCLanguageRuntime can see and modify these @@ -610,11 +615,13 @@ private: typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; typedef HashToISAMap::iterator HashToISAIterator; + typedef ThreadSafeDenseMap<void*, uint64_t> TypeSizeCache; MsgImplMap m_impl_cache; LazyBool m_has_new_literals_and_indexing; ISAToDescriptorMap m_isa_to_descriptor; HashToISAMap m_hash_to_isa_map; + TypeSizeCache m_type_size_cache; protected: uint32_t m_isa_to_descriptor_stop_id; diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h index 8b14cc2a0ece..f4596bd00f0b 100644 --- a/include/lldb/Target/Platform.h +++ b/include/lldb/Target/Platform.h @@ -28,7 +28,7 @@ // TODO pull NativeDelegate class out of NativeProcessProtocol so we // can just forward ref the NativeDelegate rather than include it here. -#include "../../../source/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeProcessProtocol.h" namespace lldb_private { @@ -380,6 +380,12 @@ namespace lldb_private { LaunchProcess (ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ + /// Kill process on a platform. + //------------------------------------------------------------------ + virtual Error + KillProcess (const lldb::pid_t pid); + + //------------------------------------------------------------------ /// Lets a platform answer if it is compatible with a given /// architecture and the target triple contained within. //------------------------------------------------------------------ @@ -569,7 +575,7 @@ namespace lldb_private { // Appends the platform-specific options required to find the modules for the current platform. virtual void - AddClangModuleCompilationOptions (std::vector<std::string> &options); + AddClangModuleCompilationOptions (Target *target, std::vector<std::string> &options); ConstString GetWorkingDirectory (); @@ -952,8 +958,7 @@ namespace lldb_private { uint32_t m_update_os_version; ArchSpec m_system_arch; // The architecture of the kernel or the remote platform typedef std::map<uint32_t, ConstString> IDToNameMap; - Mutex m_uid_map_mutex; - Mutex m_gid_map_mutex; + Mutex m_mutex; // Mutex for modifying Platform data structures that should only be used for non-reentrant code IDToNameMap m_uid_map; IDToNameMap m_gid_map; size_t m_max_uid_name_len; @@ -967,7 +972,6 @@ namespace lldb_private { std::string m_local_cache_directory; std::vector<ConstString> m_trap_handlers; bool m_calculated_trap_handlers; - Mutex m_trap_handler_mutex; //------------------------------------------------------------------ /// Ask the Platform subclass to fill in the list of trap handler names @@ -988,7 +992,7 @@ namespace lldb_private { const char * GetCachedUserName (uint32_t uid) { - Mutex::Locker locker (m_uid_map_mutex); + Mutex::Locker locker (m_mutex); IDToNameMap::iterator pos = m_uid_map.find (uid); if (pos != m_uid_map.end()) { @@ -1004,7 +1008,7 @@ namespace lldb_private { const char * SetCachedUserName (uint32_t uid, const char *name, size_t name_len) { - Mutex::Locker locker (m_uid_map_mutex); + Mutex::Locker locker (m_mutex); ConstString const_name (name); m_uid_map[uid] = const_name; if (m_max_uid_name_len < name_len) @@ -1016,7 +1020,7 @@ namespace lldb_private { void SetUserNameNotFound (uint32_t uid) { - Mutex::Locker locker (m_uid_map_mutex); + Mutex::Locker locker (m_mutex); m_uid_map[uid] = ConstString(); } @@ -1024,14 +1028,14 @@ namespace lldb_private { void ClearCachedUserNames () { - Mutex::Locker locker (m_uid_map_mutex); + Mutex::Locker locker (m_mutex); m_uid_map.clear(); } const char * GetCachedGroupName (uint32_t gid) { - Mutex::Locker locker (m_gid_map_mutex); + Mutex::Locker locker (m_mutex); IDToNameMap::iterator pos = m_gid_map.find (gid); if (pos != m_gid_map.end()) { @@ -1047,7 +1051,7 @@ namespace lldb_private { const char * SetCachedGroupName (uint32_t gid, const char *name, size_t name_len) { - Mutex::Locker locker (m_gid_map_mutex); + Mutex::Locker locker (m_mutex); ConstString const_name (name); m_gid_map[gid] = const_name; if (m_max_gid_name_len < name_len) @@ -1059,14 +1063,14 @@ namespace lldb_private { void SetGroupNameNotFound (uint32_t gid) { - Mutex::Locker locker (m_gid_map_mutex); + Mutex::Locker locker (m_mutex); m_gid_map[gid] = ConstString(); } void ClearCachedGroupNames () { - Mutex::Locker locker (m_gid_map_mutex); + Mutex::Locker locker (m_mutex); m_gid_map.clear(); } diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h index e04de511c797..6608391b94fd 100644 --- a/include/lldb/Target/Process.h +++ b/include/lldb/Target/Process.h @@ -678,13 +678,16 @@ public: bool IsLastResumeForUserExpression () const { + // If we haven't yet resumed the target, then it can't be for a user expression... + if (m_resume_id == 0) + return false; + return m_resume_id == m_last_user_expression_resume; } void SetRunningUserExpression (bool on) { - // REMOVEME printf ("Setting running user expression %s at resume id %d - value: %d.\n", on ? "on" : "off", m_resume_id, m_running_user_expression); if (on) m_running_user_expression++; else @@ -3177,6 +3180,7 @@ protected: lldb::IOHandlerSP m_process_input_reader; Communication m_stdio_communication; Mutex m_stdio_communication_mutex; + bool m_stdio_disable; /// Remember process launch setting std::string m_stdout_data; std::string m_stderr_data; Mutex m_profile_data_comm_mutex; diff --git a/include/lldb/Utility/AnsiTerminal.h b/include/lldb/Utility/AnsiTerminal.h index 036950c1bd45..9a5117ae74ea 100644 --- a/include/lldb/Utility/AnsiTerminal.h +++ b/include/lldb/Utility/AnsiTerminal.h @@ -50,37 +50,6 @@ namespace lldb_utility { namespace ansi { - const char *k_escape_start = "\033["; - const char *k_escape_end = "m"; - - const char *k_fg_black = "30"; - const char *k_fg_red = "31"; - const char *k_fg_green = "32"; - const char *k_fg_yellow = "33"; - const char *k_fg_blue = "34"; - const char *k_fg_purple = "35"; - const char *k_fg_cyan = "36"; - const char *k_fg_white = "37"; - - const char *k_bg_black = "40"; - const char *k_bg_red = "41"; - const char *k_bg_green = "42"; - const char *k_bg_yellow = "43"; - const char *k_bg_blue = "44"; - const char *k_bg_purple = "45"; - const char *k_bg_cyan = "46"; - const char *k_bg_white = "47"; - - const char *k_ctrl_normal = "0"; - const char *k_ctrl_bold = "1"; - const char *k_ctrl_faint = "2"; - const char *k_ctrl_italic = "3"; - const char *k_ctrl_underline = "4"; - const char *k_ctrl_slow_blink = "5"; - const char *k_ctrl_fast_blink = "6"; - const char *k_ctrl_negative = "7"; - const char *k_ctrl_conceal = "8"; - const char *k_ctrl_crossed_out = "9"; inline std::string FormatAnsiTerminalCodes(const char *format, bool do_color = true) diff --git a/include/lldb/Utility/ProcessStructReader.h b/include/lldb/Utility/ProcessStructReader.h index 7b05d93151aa..d053b702462e 100644 --- a/include/lldb/Utility/ProcessStructReader.h +++ b/include/lldb/Utility/ProcessStructReader.h @@ -59,7 +59,7 @@ namespace lldb_private { // no support for bitfields in here (yet) if (is_bitfield) return; - auto size = field_type.GetByteSize(); + auto size = field_type.GetByteSize(nullptr); // no support for things larger than a uint64_t (yet) if (size > 8) return; @@ -67,7 +67,7 @@ namespace lldb_private { size_t byte_index = static_cast<size_t>(bit_offset / 8); m_fields[const_name] = FieldImpl{field_type, byte_index, static_cast<size_t>(size)}; } - size_t total_size = struct_type.GetByteSize(); + size_t total_size = struct_type.GetByteSize(nullptr); lldb::DataBufferSP buffer_sp(new DataBufferHeap(total_size,0)); Error error; process->ReadMemoryFromInferior(base_addr, diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h index 87ee14875734..f70ee0cd7b28 100644 --- a/include/lldb/lldb-enumerations.h +++ b/include/lldb/lldb-enumerations.h @@ -290,7 +290,11 @@ namespace lldb { eSymbolContextBlock = (1u << 4), ///< Set when the deepest \a block is requested from a query, or was located in query results eSymbolContextLineEntry = (1u << 5), ///< Set when \a line_entry is requested from a query, or was located in query results eSymbolContextSymbol = (1u << 6), ///< Set when \a symbol is requested from a query, or was located in query results - eSymbolContextEverything = ((eSymbolContextSymbol << 1) - 1u) ///< Indicates to try and lookup everything up during a query. + eSymbolContextEverything = ((eSymbolContextSymbol << 1) - 1u), ///< Indicates to try and lookup everything up during a routine symbol context query. + eSymbolContextVariable = (1u << 7) ///< Set when \a global or static variable is requested from a query, or was located in query results. + ///< eSymbolContextVariable is potentially expensive to lookup so it isn't included in + ///< eSymbolContextEverything which stops it from being used during frame PC lookups and + ///< many other potential address to symbol context lookups. } SymbolContextItem; typedef enum Permissions @@ -374,6 +378,8 @@ namespace lldb { eLanguageTypeUPC = 0x0012, ///< Unified Parallel C. eLanguageTypeD = 0x0013, ///< D. eLanguageTypePython = 0x0014, ///< Python. + // NOTE: The below are DWARF5 constants, subject to change upon + // completion of the DWARF5 specification eLanguageTypeOpenCL = 0x0015, ///< OpenCL. eLanguageTypeGo = 0x0016, ///< Go. eLanguageTypeModula3 = 0x0017, ///< Modula 3. @@ -386,6 +392,9 @@ namespace lldb { eLanguageTypeSwift = 0x001e, ///< Swift. eLanguageTypeJulia = 0x001f, ///< Julia. eLanguageTypeDylan = 0x0020, ///< Dylan. + eLanguageTypeC_plus_plus_14 = 0x0021, ///< ISO C++:2014. + eLanguageTypeFortran03 = 0x0022, ///< ISO Fortran 2003. + eLanguageTypeFortran08 = 0x0023, ///< ISO Fortran 2008. eNumLanguageTypes } LanguageType; diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h index 1ecb2f179bb2..53f59dd62096 100644 --- a/include/lldb/lldb-forward.h +++ b/include/lldb/lldb-forward.h @@ -146,6 +146,7 @@ class OptionValueEnumeration; class OptionValueFileSpec; class OptionValueFileSpecList; class OptionValueFormat; +class OptionValueFormatEntity; class OptionValuePathMappings; class OptionValueProperties; class OptionValueRegex; diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp index eccc4e29aadf..6158418d2f2a 100644 --- a/source/API/SBInstruction.cpp +++ b/source/API/SBInstruction.cpp @@ -178,8 +178,9 @@ SBInstruction::GetDescription (lldb::SBStream &s) module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc); // Use the "ref()" instead of the "get()" accessor in case the SBStream // didn't have a stream already created, one will get created... - const char *disassemble_format = "${addr-file-or-load}: "; - m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, disassemble_format); + FormatEntity::Entry format; + FormatEntity::Parse("${addr}: ", format); + m_opaque_sp->Dump (&s.ref(), 0, true, false, NULL, &sc, NULL, &format); return true; } return false; @@ -199,8 +200,9 @@ SBInstruction::Print (FILE *out) if (module_sp) module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc); StreamFile out_stream (out, false); - const char *disassemble_format = "${addr-file-or-load}: "; - m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, disassemble_format); + FormatEntity::Entry format; + FormatEntity::Parse("${addr}: ", format); + m_opaque_sp->Dump (&out_stream, 0, true, false, NULL, &sc, NULL, &format); } } diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp index 31585b3e6868..812824b4d2e5 100644 --- a/source/API/SBInstructionList.cpp +++ b/source/API/SBInstructionList.cpp @@ -102,7 +102,8 @@ SBInstructionList::GetDescription (lldb::SBStream &description) // exist already inside description... Stream &sref = description.ref(); const uint32_t max_opcode_byte_size = m_opaque_sp->GetInstructionList().GetMaxOpcocdeByteSize(); - const char *disassemble_format = "${addr-file-or-load}: "; + FormatEntity::Entry format; + FormatEntity::Parse("${addr}: ", format); SymbolContext sc; SymbolContext prev_sc; for (size_t i=0; i<num_instructions; ++i) @@ -119,7 +120,7 @@ SBInstructionList::GetDescription (lldb::SBStream &description) module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc); } - inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, disassemble_format); + inst->Dump (&sref, max_opcode_byte_size, true, false, NULL, &sc, &prev_sc, &format); sref.EOL(); } return true; diff --git a/source/API/SBLaunchInfo.cpp b/source/API/SBLaunchInfo.cpp new file mode 100644 index 000000000000..dcb0e1b488ba --- /dev/null +++ b/source/API/SBLaunchInfo.cpp @@ -0,0 +1,278 @@ +//===-- SBLaunchInfo.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-python.h" + +#include "lldb/API/SBLaunchInfo.h" + +#include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBListener.h" +#include "lldb/Target/ProcessLaunchInfo.h" + +using namespace lldb; +using namespace lldb_private; + +SBLaunchInfo::SBLaunchInfo (const char **argv) : + m_opaque_sp(new ProcessLaunchInfo()) +{ + m_opaque_sp->GetFlags().Reset (eLaunchFlagDebug | eLaunchFlagDisableASLR); + if (argv && argv[0]) + m_opaque_sp->GetArguments().SetArguments(argv); +} + +SBLaunchInfo::~SBLaunchInfo() +{ +} + +lldb_private::ProcessLaunchInfo & +SBLaunchInfo::ref () +{ + return *m_opaque_sp; +} + +lldb::pid_t +SBLaunchInfo::GetProcessID() +{ + return m_opaque_sp->GetProcessID(); +} + +uint32_t +SBLaunchInfo::GetUserID() +{ + return m_opaque_sp->GetUserID(); +} + +uint32_t +SBLaunchInfo::GetGroupID() +{ + return m_opaque_sp->GetGroupID(); +} + +bool +SBLaunchInfo::UserIDIsValid () +{ + return m_opaque_sp->UserIDIsValid(); +} + +bool +SBLaunchInfo::GroupIDIsValid () +{ + return m_opaque_sp->GroupIDIsValid(); +} + +void +SBLaunchInfo::SetUserID (uint32_t uid) +{ + m_opaque_sp->SetUserID (uid); +} + +void +SBLaunchInfo::SetGroupID (uint32_t gid) +{ + m_opaque_sp->SetGroupID (gid); +} + +SBFileSpec +SBLaunchInfo::GetExecutableFile () +{ + return SBFileSpec (m_opaque_sp->GetExecutableFile()); +} + +void +SBLaunchInfo::SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg) +{ + m_opaque_sp->SetExecutableFile(exe_file.ref(), add_as_first_arg); +} + +SBListener +SBLaunchInfo::GetListener () +{ + return SBListener(m_opaque_sp->GetListener()); +} + +void +SBLaunchInfo::SetListener (SBListener &listener) +{ + m_opaque_sp->SetListener(listener.GetSP()); +} + +uint32_t +SBLaunchInfo::GetNumArguments () +{ + return m_opaque_sp->GetArguments().GetArgumentCount(); +} + +const char * +SBLaunchInfo::GetArgumentAtIndex (uint32_t idx) +{ + return m_opaque_sp->GetArguments().GetArgumentAtIndex(idx); +} + +void +SBLaunchInfo::SetArguments (const char **argv, bool append) +{ + if (append) + { + if (argv) + m_opaque_sp->GetArguments().AppendArguments(argv); + } + else + { + if (argv) + m_opaque_sp->GetArguments().SetArguments(argv); + else + m_opaque_sp->GetArguments().Clear(); + } +} + +uint32_t +SBLaunchInfo::GetNumEnvironmentEntries () +{ + return m_opaque_sp->GetEnvironmentEntries().GetArgumentCount(); +} + +const char * +SBLaunchInfo::GetEnvironmentEntryAtIndex (uint32_t idx) +{ + return m_opaque_sp->GetEnvironmentEntries().GetArgumentAtIndex(idx); +} + +void +SBLaunchInfo::SetEnvironmentEntries (const char **envp, bool append) +{ + if (append) + { + if (envp) + m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp); + } + else + { + if (envp) + m_opaque_sp->GetEnvironmentEntries().SetArguments(envp); + else + m_opaque_sp->GetEnvironmentEntries().Clear(); + } +} + +void +SBLaunchInfo::Clear () +{ + m_opaque_sp->Clear(); +} + +const char * +SBLaunchInfo::GetWorkingDirectory () const +{ + return m_opaque_sp->GetWorkingDirectory(); +} + +void +SBLaunchInfo::SetWorkingDirectory (const char *working_dir) +{ + m_opaque_sp->SetWorkingDirectory(working_dir); +} + +uint32_t +SBLaunchInfo::GetLaunchFlags () +{ + return m_opaque_sp->GetFlags().Get(); +} + +void +SBLaunchInfo::SetLaunchFlags (uint32_t flags) +{ + m_opaque_sp->GetFlags().Reset(flags); +} + +const char * +SBLaunchInfo::GetProcessPluginName () +{ + return m_opaque_sp->GetProcessPluginName(); +} + +void +SBLaunchInfo::SetProcessPluginName (const char *plugin_name) +{ + return m_opaque_sp->SetProcessPluginName (plugin_name); +} + +const char * +SBLaunchInfo::GetShell () +{ + // Constify this string so that it is saved in the string pool. Otherwise + // it would be freed when this function goes out of scope. + ConstString shell(m_opaque_sp->GetShell().GetPath().c_str()); + return shell.AsCString(); +} + +void +SBLaunchInfo::SetShell (const char * path) +{ + m_opaque_sp->SetShell (FileSpec(path, false)); +} + +uint32_t +SBLaunchInfo::GetResumeCount () +{ + return m_opaque_sp->GetResumeCount(); +} + +void +SBLaunchInfo::SetResumeCount (uint32_t c) +{ + m_opaque_sp->SetResumeCount (c); +} + +bool +SBLaunchInfo::AddCloseFileAction (int fd) +{ + return m_opaque_sp->AppendCloseFileAction(fd); +} + +bool +SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd) +{ + return m_opaque_sp->AppendDuplicateFileAction(fd, dup_fd); +} + +bool +SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write) +{ + return m_opaque_sp->AppendOpenFileAction(fd, path, read, write); +} + +bool +SBLaunchInfo::AddSuppressFileAction (int fd, bool read, bool write) +{ + return m_opaque_sp->AppendSuppressFileAction(fd, read, write); +} + +void +SBLaunchInfo::SetLaunchEventData (const char *data) +{ + m_opaque_sp->SetLaunchEventData (data); +} + +const char * +SBLaunchInfo::GetLaunchEventData () const +{ + return m_opaque_sp->GetLaunchEventData (); +} + +void +SBLaunchInfo::SetDetachOnError (bool enable) +{ + m_opaque_sp->SetDetachOnError (enable); +} + +bool +SBLaunchInfo::GetDetachOnError () const +{ + return m_opaque_sp->GetDetachOnError (); +} diff --git a/source/API/SBPlatform.cpp b/source/API/SBPlatform.cpp index d3e769ae675b..b23891d39c21 100644 --- a/source/API/SBPlatform.cpp +++ b/source/API/SBPlatform.cpp @@ -10,6 +10,7 @@ #include "lldb/API/SBPlatform.h" #include "lldb/API/SBError.h" #include "lldb/API/SBFileSpec.h" +#include "lldb/API/SBLaunchInfo.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Error.h" #include "lldb/Host/File.h" @@ -17,6 +18,8 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Platform.h" +#include <functional> + using namespace lldb; using namespace lldb_private; @@ -484,104 +487,108 @@ SBError SBPlatform::Put (SBFileSpec &src, SBFileSpec &dst) { - SBError sb_error; - - PlatformSP platform_sp(GetSP()); - if (platform_sp) - { - if (src.Exists()) + return ExecuteConnected( + [&](const lldb::PlatformSP& 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; + } + + return platform_sp->PutFile(src.ref(), dst.ref(), permissions); + } + + Error error; + error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + return error; + }); +} + +SBError +SBPlatform::Install (SBFileSpec &src, + SBFileSpec &dst) +{ + return ExecuteConnected( + [&](const lldb::PlatformSP& platform_sp) + { + if (src.Exists()) + return platform_sp->Install(src.ref(), dst.ref()); + + Error error; + error.SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); + return error; + }); +} + + +SBError +SBPlatform::Run (SBPlatformShellCommand &shell_command) +{ + return ExecuteConnected( + [&](const lldb::PlatformSP& platform_sp) { - uint32_t permissions = src.ref().GetPermissions(); - if (permissions == 0) + const char *command = shell_command.GetCommand(); + if (!command) + return Error("invalid shell command (empty)"); + + const char *working_dir = shell_command.GetWorkingDirectory(); + if (working_dir == NULL) { - if (src.ref().GetFileType() == FileSpec::eFileTypeDirectory) - permissions = eFilePermissionsDirectoryDefault; - else - permissions = eFilePermissionsFileDefault; + working_dir = platform_sp->GetWorkingDirectory().GetCString(); + if (working_dir) + shell_command.SetWorkingDirectory(working_dir); } + return 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); + }); +} - sb_error.ref() = platform_sp->PutFile(src.ref(), - dst.ref(), - permissions); - } - else +SBError +SBPlatform::Launch (SBLaunchInfo &launch_info) +{ + return ExecuteConnected( + [&](const lldb::PlatformSP& platform_sp) { - sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); - } - } - else - { - sb_error.SetErrorString("invalid platform"); - } - return sb_error; + return platform_sp->LaunchProcess(launch_info.ref()); + }); } SBError -SBPlatform::Install (SBFileSpec &src, - SBFileSpec &dst) +SBPlatform::Kill (const lldb::pid_t pid) { - SBError sb_error; - PlatformSP platform_sp(GetSP()); - if (platform_sp) - { - if (src.Exists()) - { - sb_error.ref() = platform_sp->Install(src.ref(), dst.ref()); - } - else + return ExecuteConnected( + [&](const lldb::PlatformSP& platform_sp) { - sb_error.ref().SetErrorStringWithFormat("'src' argument doesn't exist: '%s'", src.ref().GetPath().c_str()); - } - } - else - { - sb_error.SetErrorString("invalid platform"); - } - return sb_error; + return platform_sp->KillProcess(pid); + }); } - SBError -SBPlatform::Run (SBPlatformShellCommand &shell_command) +SBPlatform::ExecuteConnected (const std::function<Error(const lldb::PlatformSP&)>& func) { SBError sb_error; - PlatformSP platform_sp(GetSP()); + const auto 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)"); - } - } + sb_error.ref() = func(platform_sp); else - { sb_error.SetErrorString("not connected"); - } } else - { sb_error.SetErrorString("invalid platform"); - } - return sb_error; + + return sb_error; } SBError diff --git a/source/API/SBStream.cpp b/source/API/SBStream.cpp index f5b5c08411c7..f50334f74189 100644 --- a/source/API/SBStream.cpp +++ b/source/API/SBStream.cpp @@ -70,6 +70,9 @@ SBStream::Printf (const char *format, ...) void SBStream::RedirectToFile (const char *path, bool append) { + if (path == nullptr) + return; + std::string local_data; if (m_opaque_ap.get()) { @@ -104,6 +107,9 @@ SBStream::RedirectToFile (const char *path, bool append) void SBStream::RedirectToFileHandle (FILE *fh, bool transfer_fh_ownership) { + if (fh == nullptr) + return; + std::string local_data; if (m_opaque_ap.get()) { diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp index b87b1acf45df..b13d8289560f 100644 --- a/source/API/SBTarget.cpp +++ b/source/API/SBTarget.cpp @@ -66,259 +66,6 @@ using namespace lldb_private; #define DEFAULT_DISASM_BYTE_SIZE 32 -SBLaunchInfo::SBLaunchInfo (const char **argv) : - m_opaque_sp(new ProcessLaunchInfo()) -{ - m_opaque_sp->GetFlags().Reset (eLaunchFlagDebug | eLaunchFlagDisableASLR); - if (argv && argv[0]) - m_opaque_sp->GetArguments().SetArguments(argv); -} - -SBLaunchInfo::~SBLaunchInfo() -{ -} - -lldb_private::ProcessLaunchInfo & -SBLaunchInfo::ref () -{ - return *m_opaque_sp; -} - - -uint32_t -SBLaunchInfo::GetUserID() -{ - return m_opaque_sp->GetUserID(); -} - -uint32_t -SBLaunchInfo::GetGroupID() -{ - return m_opaque_sp->GetGroupID(); -} - -bool -SBLaunchInfo::UserIDIsValid () -{ - return m_opaque_sp->UserIDIsValid(); -} - -bool -SBLaunchInfo::GroupIDIsValid () -{ - return m_opaque_sp->GroupIDIsValid(); -} - -void -SBLaunchInfo::SetUserID (uint32_t uid) -{ - m_opaque_sp->SetUserID (uid); -} - -void -SBLaunchInfo::SetGroupID (uint32_t gid) -{ - m_opaque_sp->SetGroupID (gid); -} - -SBFileSpec -SBLaunchInfo::GetExecutableFile () -{ - return SBFileSpec (m_opaque_sp->GetExecutableFile()); -} - -void -SBLaunchInfo::SetExecutableFile (SBFileSpec exe_file, bool add_as_first_arg) -{ - m_opaque_sp->SetExecutableFile(exe_file.ref(), add_as_first_arg); -} - -SBListener -SBLaunchInfo::GetListener () -{ - return SBListener(m_opaque_sp->GetListener()); -} - -void -SBLaunchInfo::SetListener (SBListener &listener) -{ - m_opaque_sp->SetListener(listener.GetSP()); -} - -uint32_t -SBLaunchInfo::GetNumArguments () -{ - return m_opaque_sp->GetArguments().GetArgumentCount(); -} - -const char * -SBLaunchInfo::GetArgumentAtIndex (uint32_t idx) -{ - return m_opaque_sp->GetArguments().GetArgumentAtIndex(idx); -} - -void -SBLaunchInfo::SetArguments (const char **argv, bool append) -{ - if (append) - { - if (argv) - m_opaque_sp->GetArguments().AppendArguments(argv); - } - else - { - if (argv) - m_opaque_sp->GetArguments().SetArguments(argv); - else - m_opaque_sp->GetArguments().Clear(); - } -} - -uint32_t -SBLaunchInfo::GetNumEnvironmentEntries () -{ - return m_opaque_sp->GetEnvironmentEntries().GetArgumentCount(); -} - -const char * -SBLaunchInfo::GetEnvironmentEntryAtIndex (uint32_t idx) -{ - return m_opaque_sp->GetEnvironmentEntries().GetArgumentAtIndex(idx); -} - -void -SBLaunchInfo::SetEnvironmentEntries (const char **envp, bool append) -{ - if (append) - { - if (envp) - m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp); - } - else - { - if (envp) - m_opaque_sp->GetEnvironmentEntries().SetArguments(envp); - else - m_opaque_sp->GetEnvironmentEntries().Clear(); - } -} - -void -SBLaunchInfo::Clear () -{ - m_opaque_sp->Clear(); -} - -const char * -SBLaunchInfo::GetWorkingDirectory () const -{ - return m_opaque_sp->GetWorkingDirectory(); -} - -void -SBLaunchInfo::SetWorkingDirectory (const char *working_dir) -{ - m_opaque_sp->SetWorkingDirectory(working_dir); -} - -uint32_t -SBLaunchInfo::GetLaunchFlags () -{ - return m_opaque_sp->GetFlags().Get(); -} - -void -SBLaunchInfo::SetLaunchFlags (uint32_t flags) -{ - m_opaque_sp->GetFlags().Reset(flags); -} - -const char * -SBLaunchInfo::GetProcessPluginName () -{ - return m_opaque_sp->GetProcessPluginName(); -} - -void -SBLaunchInfo::SetProcessPluginName (const char *plugin_name) -{ - return m_opaque_sp->SetProcessPluginName (plugin_name); -} - -const char * -SBLaunchInfo::GetShell () -{ - // Constify this string so that it is saved in the string pool. Otherwise - // it would be freed when this function goes out of scope. - ConstString shell(m_opaque_sp->GetShell().GetPath().c_str()); - return shell.AsCString(); -} - -void -SBLaunchInfo::SetShell (const char * path) -{ - m_opaque_sp->SetShell (FileSpec(path, false)); -} - -uint32_t -SBLaunchInfo::GetResumeCount () -{ - return m_opaque_sp->GetResumeCount(); -} - -void -SBLaunchInfo::SetResumeCount (uint32_t c) -{ - m_opaque_sp->SetResumeCount (c); -} - -bool -SBLaunchInfo::AddCloseFileAction (int fd) -{ - return m_opaque_sp->AppendCloseFileAction(fd); -} - -bool -SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd) -{ - return m_opaque_sp->AppendDuplicateFileAction(fd, dup_fd); -} - -bool -SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write) -{ - return m_opaque_sp->AppendOpenFileAction(fd, path, read, write); -} - -bool -SBLaunchInfo::AddSuppressFileAction (int fd, bool read, bool write) -{ - return m_opaque_sp->AppendSuppressFileAction(fd, read, write); -} - -void -SBLaunchInfo::SetLaunchEventData (const char *data) -{ - m_opaque_sp->SetLaunchEventData (data); -} - -const char * -SBLaunchInfo::GetLaunchEventData () const -{ - return m_opaque_sp->GetLaunchEventData (); -} - -void -SBLaunchInfo::SetDetachOnError (bool enable) -{ - m_opaque_sp->SetDetachOnError (enable); -} - -bool -SBLaunchInfo::GetDetachOnError () const -{ - return m_opaque_sp->GetDetachOnError (); -} SBAttachInfo::SBAttachInfo () : m_opaque_sp (new ProcessAttachInfo()) @@ -729,6 +476,9 @@ SBTarget::Launch { Mutex::Locker api_locker (target_sp->GetAPIMutex()); + if (stop_at_entry) + launch_flags |= eLaunchFlagStopAtEntry; + if (getenv("LLDB_LAUNCH_FLAG_DISABLE_ASLR")) launch_flags |= eLaunchFlagDisableASLR; diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp index 6524d10fb705..9fe0d029496c 100644 --- a/source/API/SBThread.cpp +++ b/source/API/SBThread.cpp @@ -1491,7 +1491,8 @@ SBThread::GetDescription (SBStream &description) const ExecutionContext exe_ctx (m_opaque_sp.get()); if (exe_ctx.HasThreadScope()) { - strm.Printf("SBThread: tid = 0x%4.4" PRIx64, exe_ctx.GetThreadPtr()->GetID()); + exe_ctx.GetThreadPtr()->DumpUsingSettingsFormat(strm, LLDB_INVALID_THREAD_ID); + //strm.Printf("SBThread: tid = 0x%4.4" PRIx64, exe_ctx.GetThreadPtr()->GetID()); } else strm.PutCString ("No value"); diff --git a/source/API/SBType.cpp b/source/API/SBType.cpp index 8a0f5d848a3d..31a4eba8bf33 100644 --- a/source/API/SBType.cpp +++ b/source/API/SBType.cpp @@ -143,7 +143,7 @@ SBType::GetByteSize() if (!IsValid()) return 0; - return m_opaque_sp->GetClangASTType(false).GetByteSize(); + return m_opaque_sp->GetClangASTType(false).GetByteSize(nullptr); } @@ -164,6 +164,14 @@ SBType::IsArrayType() } bool +SBType::IsVectorType() +{ + if (!IsValid()) + return false; + return m_opaque_sp->GetClangASTType(true).IsVectorType(nullptr, nullptr); +} + +bool SBType::IsReferenceType() { if (!IsValid()) @@ -220,7 +228,20 @@ SBType::GetArrayElementType() return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetClangASTType(true).GetArrayElementType()))); } -bool +SBType +SBType::GetVectorElementType () +{ + SBType type_sb; + if (IsValid()) + { + ClangASTType vector_element_type; + if (m_opaque_sp->GetClangASTType(true).IsVectorType(&vector_element_type, nullptr)) + type_sb.SetSP(TypeImplSP(new TypeImpl(vector_element_type))); + } + return type_sb; +} + +bool SBType::IsFunctionType () { if (!IsValid()) diff --git a/source/API/SBTypeCategory.cpp b/source/API/SBTypeCategory.cpp index 9fe4dad01a9f..66cf46236c65 100644 --- a/source/API/SBTypeCategory.cpp +++ b/source/API/SBTypeCategory.cpp @@ -353,7 +353,7 @@ SBTypeCategory::AddTypeSummary (SBTypeNameSpecifier type_name, // this should eventually be fixed by deciding a final location in the LLDB object space for formatters if (summary.IsFunctionCode()) { - void *name_token = (void*)ConstString(type_name.GetName()).GetCString(); + const void *name_token = (const void*)ConstString(type_name.GetName()).GetCString(); const char* script = summary.GetData(); StringList input; input.SplitIntoLines(script, strlen(script)); uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers(); @@ -461,7 +461,7 @@ SBTypeCategory::AddTypeSynthetic (SBTypeNameSpecifier type_name, // this should eventually be fixed by deciding a final location in the LLDB object space for formatters if (synth.IsClassCode()) { - void *name_token = (void*)ConstString(type_name.GetName()).GetCString(); + const void *name_token = (const void*)ConstString(type_name.GetName()).GetCString(); const char* script = synth.GetData(); StringList input; input.SplitIntoLines(script, strlen(script)); uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers(); diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp index 0d3d7ad956ee..edecb93944ad 100644 --- a/source/API/SBValue.cpp +++ b/source/API/SBValue.cpp @@ -608,7 +608,8 @@ SBValue::GetValueDidChange () lldb::ValueObjectSP value_sp(GetSP(locker)); if (value_sp) { - result = value_sp->GetValueDidChange (); + if (value_sp->UpdateValueIfNeeded(false)) + result = value_sp->GetValueDidChange (); } if (log) log->Printf ("SBValue(%p)::GetValueDidChange() => %i", diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp index bc269cdb95ac..beb0f6bc5a6e 100644 --- a/source/Breakpoint/Breakpoint.cpp +++ b/source/Breakpoint/Breakpoint.cpp @@ -60,7 +60,8 @@ Breakpoint::Breakpoint(Target &target, m_resolver_sp (resolver_sp), m_options (), m_locations (*this), - m_resolve_indirect_symbols(resolve_indirect_symbols) + m_resolve_indirect_symbols(resolve_indirect_symbols), + m_hit_count(0) { m_being_created = false; } @@ -72,7 +73,8 @@ Breakpoint::Breakpoint (Target &new_target, Breakpoint &source_bp) : m_name_list (source_bp.m_name_list), m_options (source_bp.m_options), m_locations(*this), - m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols) + m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols), + m_hit_count(0) { // Now go through and copy the filter & resolver: m_resolver_sp = source_bp.m_resolver_sp->CopyForBreakpoint(*this); @@ -207,7 +209,7 @@ Breakpoint::IgnoreCountShouldStop () uint32_t Breakpoint::GetHitCount () const { - return m_locations.GetHitCount(); + return m_hit_count; } bool diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp index 11ecfecc5bc7..85233c9374cb 100644 --- a/source/Breakpoint/BreakpointLocation.cpp +++ b/source/Breakpoint/BreakpointLocation.cpp @@ -477,7 +477,22 @@ void BreakpointLocation::BumpHitCount() { if (IsEnabled()) + { + // Step our hit count, and also step the hit count of the owner. IncrementHitCount(); + m_owner.IncrementHitCount(); + } +} + +void +BreakpointLocation::UndoBumpHitCount() +{ + if (IsEnabled()) + { + // Step our hit count, and also step the hit count of the owner. + DecrementHitCount(); + m_owner.DecrementHitCount(); + } } bool diff --git a/source/Breakpoint/StoppointLocation.cpp b/source/Breakpoint/StoppointLocation.cpp index 9d8d9241253a..35e5979bd9e7 100644 --- a/source/Breakpoint/StoppointLocation.cpp +++ b/source/Breakpoint/StoppointLocation.cpp @@ -46,3 +46,10 @@ StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, uint32_t byte StoppointLocation::~StoppointLocation() { } + +void +StoppointLocation::DecrementHitCount () +{ + assert (m_hit_count > 0); + --m_hit_count; +} diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp index 3d4b3aff6fff..025524b3b9a5 100644 --- a/source/Commands/CommandObjectBreakpoint.cpp +++ b/source/Commands/CommandObjectBreakpoint.cpp @@ -19,6 +19,7 @@ #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" @@ -140,7 +141,7 @@ public: break; case 'C': - m_column = Args::StringToUInt32 (option_arg, 0); + m_column = StringConvert::ToUInt32 (option_arg, 0); break; case 'c': @@ -166,6 +167,7 @@ public: case eLanguageTypeC_plus_plus: case eLanguageTypeC_plus_plus_03: case eLanguageTypeC_plus_plus_11: + case eLanguageTypeC_plus_plus_14: m_language = eLanguageTypeC_plus_plus; break; case eLanguageTypeObjC: @@ -207,7 +209,7 @@ public: case 'i': { - m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_ignore_count == UINT32_MAX) error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); break; @@ -229,7 +231,7 @@ public: break; case 'l': - m_line_num = Args::StringToUInt32 (option_arg, 0); + m_line_num = StringConvert::ToUInt32 (option_arg, 0); break; case 'M': @@ -276,7 +278,7 @@ public: case 't' : { - m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); + m_thread_id = StringConvert::ToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); if (m_thread_id == LLDB_INVALID_THREAD_ID) error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); } @@ -297,7 +299,7 @@ public: case 'x': { - m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_thread_index = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_thread_id == UINT32_MAX) error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); @@ -838,7 +840,7 @@ public: break; case 'i': { - m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_ignore_count == UINT32_MAX) error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); } @@ -865,7 +867,7 @@ public: } else { - m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); + m_thread_id = StringConvert::ToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); if (m_thread_id == LLDB_INVALID_THREAD_ID) error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); else @@ -896,7 +898,7 @@ public: } else { - m_thread_index = Args::StringToUInt32 (option_arg, UINT32_MAX, 0); + m_thread_index = StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0); if (m_thread_id == UINT32_MAX) error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); else @@ -1555,7 +1557,7 @@ public: break; case 'l': - m_line_num = Args::StringToUInt32 (option_arg, 0); + m_line_num = StringConvert::ToUInt32 (option_arg, 0); break; default: diff --git a/source/Commands/CommandObjectDisassemble.cpp b/source/Commands/CommandObjectDisassemble.cpp index 8124ce1ef93b..2ba47be1ecf0 100644 --- a/source/Commands/CommandObjectDisassemble.cpp +++ b/source/Commands/CommandObjectDisassemble.cpp @@ -19,7 +19,7 @@ #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" #include "lldb/Core/SourceManager.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -76,13 +76,13 @@ CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, c break; case 'C': - num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success); + num_lines_context = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg); break; case 'c': - num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success); + num_instructions = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg); break; diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp index b4c559c81cc5..e87399f97baa 100644 --- a/source/Commands/CommandObjectExpression.cpp +++ b/source/Commands/CommandObjectExpression.cpp @@ -15,7 +15,6 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Interpreter/Args.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" @@ -24,6 +23,7 @@ #include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Core/Debugger.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -119,7 +119,7 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int { bool success; uint32_t result; - result = Args::StringToUInt32(option_arg, 0, 0, &success); + result = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (success) timeout = result; else diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp index ce540a5c3100..4458a692a189 100644 --- a/source/Commands/CommandObjectFrame.cpp +++ b/source/Commands/CommandObjectFrame.cpp @@ -27,6 +27,7 @@ #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -119,7 +120,7 @@ public: switch (short_option) { case 'r': - relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success); + relative_frame_offset = StringConvert::ToSInt32 (option_arg, INT32_MIN, 0, &success); if (!success) error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg); break; @@ -246,7 +247,7 @@ protected: { const char *frame_idx_cstr = command.GetArgumentAtIndex(0); bool success = false; - frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0, &success); + frame_idx = StringConvert::ToUInt32 (frame_idx_cstr, UINT32_MAX, 0, &success); if (!success) { result.AppendErrorWithFormat ("invalid frame index argument '%s'", frame_idx_cstr); diff --git a/source/Commands/CommandObjectGUI.cpp b/source/Commands/CommandObjectGUI.cpp index 3d05335e92e4..359d6d2892d0 100644 --- a/source/Commands/CommandObjectGUI.cpp +++ b/source/Commands/CommandObjectGUI.cpp @@ -42,10 +42,22 @@ CommandObjectGUI::DoExecute (Args& args, CommandReturnObject &result) if (args.GetArgumentCount() == 0) { Debugger &debugger = m_interpreter.GetDebugger(); - IOHandlerSP io_handler_sp (new IOHandlerCursesGUI (debugger)); - if (io_handler_sp) - debugger.PushIOHandler(io_handler_sp); - result.SetStatus (eReturnStatusSuccessFinishResult); + + lldb::StreamFileSP input_sp = debugger.GetInputFile(); + if (input_sp && + input_sp->GetFile().GetIsRealTerminal() && + input_sp->GetFile().GetIsInteractive()) + { + IOHandlerSP io_handler_sp (new IOHandlerCursesGUI (debugger)); + if (io_handler_sp) + debugger.PushIOHandler(io_handler_sp); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendError("the gui command requires an interactive terminal."); + result.SetStatus (eReturnStatusFailed); + } } else { diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp index f73d9d23b574..b02515e2d1e8 100644 --- a/source/Commands/CommandObjectHelp.cpp +++ b/source/Commands/CommandObjectHelp.cpp @@ -54,9 +54,10 @@ CommandObjectHelp::~CommandObjectHelp() OptionDefinition CommandObjectHelp::CommandOptions::g_option_table[] = { - { LLDB_OPT_SET_ALL, false, "show-aliases", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Show aliases in the command list."}, + { LLDB_OPT_SET_ALL, false, "hide-aliases", 'a', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Hide aliases in the command list."}, { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Hide user-defined commands from the list."}, - { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } + { LLDB_OPT_SET_ALL, false, "show-hidden-commands", 'h', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Include commands prefixed with an underscore."}, + { 0, false, NULL, 0, 0, 0, NULL, 0, eArgTypeNone, NULL } }; bool @@ -75,6 +76,8 @@ CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result) cmd_types |= CommandInterpreter::eCommandTypesAliases; if (m_options.m_show_user_defined) cmd_types |= CommandInterpreter::eCommandTypesUserDef; + if (m_options.m_show_hidden) + cmd_types |= CommandInterpreter::eCommandTypesHidden; result.SetStatus (eReturnStatusSuccessFinishNoResult); m_interpreter.GetHelp (result, cmd_types); // General help @@ -136,17 +139,19 @@ CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result) else if (!sub_cmd_obj) { result.AppendErrorWithFormat("'%s' is not a known command.\n" - "Try 'help' to see a current list of commands.\n", - cmd_string.c_str()); + "Try '%shelp' to see a current list of commands.\n", + cmd_string.c_str(), + m_interpreter.GetCommandPrefix()); result.SetStatus (eReturnStatusFailed); return false; } else { result.GetOutputStream().Printf("'%s' is not a known command.\n" - "Try 'help' to see a current list of commands.\n" + "Try '%shelp' to see a current list of commands.\n" "The closest match is '%s'. Help on it follows.\n\n", cmd_string.c_str(), + m_interpreter.GetCommandPrefix(), sub_cmd_obj->GetCommandName()); } } @@ -183,8 +188,9 @@ CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result) else { result.AppendErrorWithFormat - ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", - command.GetArgumentAtIndex(0)); + ("'%s' is not a known command.\nTry '%shelp' to see a current list of commands.\n", + command.GetArgumentAtIndex(0), + m_interpreter.GetCommandPrefix()); result.SetStatus (eReturnStatusFailed); } } diff --git a/source/Commands/CommandObjectHelp.h b/source/Commands/CommandObjectHelp.h index 6e8f9d4cbc7b..7db659c472c9 100644 --- a/source/Commands/CommandObjectHelp.h +++ b/source/Commands/CommandObjectHelp.h @@ -62,11 +62,14 @@ public: switch (short_option) { case 'a': - m_show_aliases = true; + m_show_aliases = false; break; case 'u': m_show_user_defined = false; break; + case 'h': + m_show_hidden = true; + break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -78,8 +81,9 @@ public: void OptionParsingStarting () { - m_show_aliases = false; + m_show_aliases = true; m_show_user_defined = true; + m_show_hidden = false; } const OptionDefinition* @@ -95,7 +99,8 @@ public: // Instance variables to hold the values for command options. bool m_show_aliases; - bool m_show_user_defined; + bool m_show_user_defined; + bool m_show_hidden; }; virtual Options * diff --git a/source/Commands/CommandObjectLog.cpp b/source/Commands/CommandObjectLog.cpp index 7d32cc6d08a5..aa09f53c792b 100644 --- a/source/Commands/CommandObjectLog.cpp +++ b/source/Commands/CommandObjectLog.cpp @@ -29,6 +29,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/Debugger.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -444,7 +445,7 @@ protected: if (strcasecmp(sub_command, "enable") == 0) { bool success; - uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success); + uint32_t depth = StringConvert::ToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success); if (success) { Timer::SetDisplayDepth (depth); diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp index 6c06ec831830..dac6dd81651b 100644 --- a/source/Commands/CommandObjectMemory.cpp +++ b/source/Commands/CommandObjectMemory.cpp @@ -24,6 +24,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -566,7 +567,7 @@ protected: --pointer_count; } - m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize(); + m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize(nullptr); if (m_format_options.GetByteSizeValue() == 0) { @@ -689,7 +690,7 @@ protected: if (m_format_options.GetFormatValue().OptionWasSet() == false) m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault); - bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue(); + bytes_read = clang_ast_type.GetByteSize(nullptr) * m_format_options.GetCountValue().GetCurrentValue(); } else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString) { @@ -1113,7 +1114,7 @@ protected: 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()) + switch (result_sp->GetClangType().GetByteSize(nullptr)) { case 1: { uint8_t byte = (uint8_t)value; @@ -1293,7 +1294,7 @@ public: case 'o': { bool success; - m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success); + m_infile_offset = StringConvert::ToUInt64(option_arg, 0, 0, &success); if (!success) { error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg); @@ -1446,7 +1447,7 @@ protected: if (m_memory_options.m_infile) { size_t length = SIZE_MAX; - if (item_byte_size > 0) + if (item_byte_size > 1) length = item_byte_size; lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length)); if (data_sp) @@ -1539,7 +1540,7 @@ protected: case eFormatPointer: // Decode hex bytes - uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); + uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 16, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); @@ -1567,7 +1568,7 @@ protected: break; case eFormatBinary: - uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); + uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 2, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); @@ -1607,7 +1608,7 @@ protected: break; case eFormatDecimal: - sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); + sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); @@ -1624,7 +1625,7 @@ protected: break; case eFormatUnsigned: - uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); + uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); @@ -1641,7 +1642,7 @@ protected: break; case eFormatOctal: - uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); + uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 8, &success); if (!success) { result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp index d176d52cb487..959c5cd1d0d7 100644 --- a/source/Commands/CommandObjectPlatform.cpp +++ b/source/Commands/CommandObjectPlatform.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandOptionValidators.h" @@ -104,7 +105,7 @@ public: case 'v': { bool ok; - uint32_t perms = Args::StringToUInt32(option_arg, 777, 8, &ok); + uint32_t perms = StringConvert::ToUInt32(option_arg, 777, 8, &ok); if (!ok) error.SetErrorStringWithFormat("invalid value for permissions: %s", option_arg); else @@ -248,6 +249,8 @@ protected: PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch)); if (platform_sp) { + m_interpreter.GetDebugger().GetPlatformList().SetSelectedPlatform(platform_sp); + platform_sp->GetStatus (result.GetOutputStream()); result.SetStatus (eReturnStatusSuccessFinishResult); } @@ -613,7 +616,7 @@ public: std::string cmd_line; args.GetCommandString(cmd_line); uint32_t mode; - const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r'); + const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r'); if (options_permissions) mode = options_permissions->m_permissions; else @@ -682,7 +685,7 @@ public: std::string cmd_line; args.GetCommandString(cmd_line); mode_t perms; - const OptionPermissions* options_permissions = (OptionPermissions*)m_options.GetGroupWithOption('r'); + const OptionPermissions* options_permissions = (const OptionPermissions*)m_options.GetGroupWithOption('r'); if (options_permissions) perms = options_permissions->m_permissions; else @@ -751,7 +754,7 @@ public: { std::string cmd_line; args.GetCommandString(cmd_line); - const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX); + const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); Error error; bool success = platform_sp->CloseFile(fd, error); if (success) @@ -803,7 +806,7 @@ public: { std::string cmd_line; args.GetCommandString(cmd_line); - const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX); + const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); std::string buffer(m_options.m_count,0); Error error; uint32_t retcode = platform_sp->ReadFile(fd, m_options.m_offset, &buffer[0], m_options.m_count, error); @@ -849,12 +852,12 @@ protected: switch (short_option) { case 'o': - m_offset = Args::StringToUInt32(option_arg, 0, 0, &success); + m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); break; case 'c': - m_count = Args::StringToUInt32(option_arg, 0, 0, &success); + m_count = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); break; @@ -930,7 +933,7 @@ public: std::string cmd_line; args.GetCommandString(cmd_line); Error error; - const lldb::user_id_t fd = Args::StringToUInt64(cmd_line.c_str(), UINT64_MAX); + const lldb::user_id_t fd = StringConvert::ToUInt64(cmd_line.c_str(), UINT64_MAX); uint32_t retcode = platform_sp->WriteFile (fd, m_options.m_offset, &m_options.m_data[0], @@ -977,7 +980,7 @@ protected: switch (short_option) { case 'o': - m_offset = Args::StringToUInt32(option_arg, 0, 0, &success); + m_offset = StringConvert::ToUInt32(option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid offset: '%s'", option_arg); break; @@ -1537,37 +1540,37 @@ protected: switch (short_option) { case 'p': - match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); + match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg); break; case 'P': - match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); + match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg); break; case 'u': - match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg); break; case 'U': - match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg); break; case 'g': - match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg); break; case 'G': - match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success)); + match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success)); if (!success) error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg); break; @@ -1730,7 +1733,7 @@ protected: for (size_t i=0; i<argc; ++ i) { const char *arg = args.GetArgumentAtIndex(i); - lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success); + lldb::pid_t pid = StringConvert::ToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success); if (success) { ProcessInstanceInfo proc_info; @@ -1805,7 +1808,7 @@ public: { case 'p': { - lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); + lldb::pid_t pid = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); if (!success || pid == LLDB_INVALID_PROCESS_ID) { error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg); @@ -2055,7 +2058,7 @@ public: case 't': { bool success; - timeout = Args::StringToUInt32(option_value, 10, 10, &success); + timeout = StringConvert::ToUInt32(option_value, 10, 10, &success); if (!success) error.SetErrorStringWithFormat("could not convert \"%s\" to a numeric value.", option_value); break; @@ -2278,19 +2281,16 @@ CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &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))); -#endif LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter))); LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter))); LoadSubCommand ("target-install", CommandObjectSP (new CommandObjectPlatformInstall (interpreter))); } - //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp index ec7b478fbecc..d47311e5cb5f 100644 --- a/source/Commands/CommandObjectProcess.cpp +++ b/source/Commands/CommandObjectProcess.cpp @@ -22,6 +22,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -353,7 +354,7 @@ public: case 'p': { - lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); + lldb::pid_t pid = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); if (!success || pid == LLDB_INVALID_PROCESS_ID) { error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg); @@ -488,6 +489,8 @@ protected: DoExecute (Args& command, CommandReturnObject &result) { + PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform()); + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); // N.B. The attach should be synchronous. It doesn't help much to get the prompt back between initiating the attach // and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop @@ -526,122 +529,130 @@ protected: ModuleSP old_exec_module_sp = target->GetExecutableModule(); ArchSpec old_arch_spec = target->GetArchitecture(); + ProcessSP process_sp; + Error error; if (command.GetArgumentCount()) { result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); result.SetStatus (eReturnStatusFailed); + return false; } - else + + m_interpreter.UpdateExecutionContext(nullptr); + ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack")); + m_options.attach_info.SetHijackListener(listener_sp); + + // If no process info was specified, then use the target executable + // name as the process to attach to by default + if (!m_options.attach_info.ProcessInfoSpecified ()) { - if (state != eStateConnected) + if (old_exec_module_sp) + m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename(); + + if (!m_options.attach_info.ProcessInfoSpecified ()) { - const char *plugin_name = m_options.attach_info.GetProcessPluginName(); - process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get(); + error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option"); } + } - if (process) + if (error.Success()) + { + if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess()) + { + target->SetPlatform(platform_sp); + process = platform_sp->Attach(m_options.attach_info, m_interpreter.GetDebugger(), target, error).get(); + } + else { - Error error; - // If no process info was specified, then use the target executable - // name as the process to attach to by default - if (!m_options.attach_info.ProcessInfoSpecified ()) + if (state != eStateConnected) { - if (old_exec_module_sp) - m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename(); - - if (!m_options.attach_info.ProcessInfoSpecified ()) - { - error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option"); - } + const char *plugin_name = m_options.attach_info.GetProcessPluginName(); + process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, nullptr).get(); + if (process == nullptr) + error.SetErrorStringWithFormat("failed to create process using plugin %s", plugin_name); } - - if (error.Success()) + if (process) { - // Update the execution context so the current target and process are now selected - // in case we interrupt - m_interpreter.UpdateExecutionContext(NULL); - ListenerSP listener_sp (new Listener("lldb.CommandObjectProcessAttach.DoExecute.attach.hijack")); - m_options.attach_info.SetHijackListener(listener_sp); process->HijackProcessEvents(listener_sp.get()); - error = process->Attach (m_options.attach_info); - - if (error.Success()) - { - result.SetStatus (eReturnStatusSuccessContinuingNoResult); - StreamString stream; - StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get(), &stream); - - process->RestoreProcessEvents(); - - result.SetDidChangeProcessState (true); - - if (stream.GetData()) - result.AppendMessage(stream.GetData()); - - if (state == eStateStopped) - { - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - const char *exit_desc = process->GetExitDescription(); - if (exit_desc) - result.AppendErrorWithFormat ("attach failed: %s", exit_desc); - else - result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); - process->Destroy(); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString()); - result.SetStatus (eReturnStatusFailed); - } + error = process->Attach(m_options.attach_info); } } } - - if (result.Succeeded()) + + if (error.Success() && process != nullptr) { - // Okay, we're done. Last step is to warn if the executable module has changed: - char new_path[PATH_MAX]; - ModuleSP new_exec_module_sp (target->GetExecutableModule()); - if (!old_exec_module_sp) + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + StreamString stream; + StateType state = process->WaitForProcessToStop (nullptr, nullptr, false, listener_sp.get(), &stream); + + process->RestoreProcessEvents(); + result.SetDidChangeProcessState (true); + + if (stream.GetData()) + result.AppendMessage(stream.GetData()); + + if (state == eStateStopped) { - // We might not have a module if we attached to a raw pid... - if (new_exec_module_sp) - { - new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX); - result.AppendMessageWithFormat("Executable module set to \"%s\".\n", new_path); - } + result.SetStatus (eReturnStatusSuccessFinishNoResult); } - else if (old_exec_module_sp->GetFileSpec() != new_exec_module_sp->GetFileSpec()) - { - char old_path[PATH_MAX]; - - old_exec_module_sp->GetFileSpec().GetPath (old_path, PATH_MAX); - new_exec_module_sp->GetFileSpec().GetPath (new_path, PATH_MAX); - - result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n", - old_path, new_path); - } - - if (!old_arch_spec.IsValid()) + else { - result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().GetTriple().getTriple().c_str()); + const char *exit_desc = process->GetExitDescription(); + if (exit_desc) + result.AppendErrorWithFormat ("attach failed: %s", exit_desc); + else + result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); + process->Destroy(); + result.SetStatus (eReturnStatusFailed); } - else if (!old_arch_spec.IsExactMatch(target->GetArchitecture())) + } + else + { + result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + + if (!result.Succeeded()) + return false; + + // Okay, we're done. Last step is to warn if the executable module has changed: + char new_path[PATH_MAX]; + ModuleSP new_exec_module_sp (target->GetExecutableModule()); + if (!old_exec_module_sp) + { + // We might not have a module if we attached to a raw pid... + if (new_exec_module_sp) { - result.AppendWarningWithFormat("Architecture changed from %s to %s.\n", - old_arch_spec.GetTriple().getTriple().c_str(), - target->GetArchitecture().GetTriple().getTriple().c_str()); + new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX); + result.AppendMessageWithFormat("Executable module set to \"%s\".\n", new_path); } + } + else if (old_exec_module_sp->GetFileSpec() != new_exec_module_sp->GetFileSpec()) + { + char old_path[PATH_MAX]; - // This supports the use-case scenario of immediately continuing the process once attached. - if (m_options.attach_info.GetContinueOnceAttached()) - m_interpreter.HandleCommand("process continue", eLazyBoolNo, result); + old_exec_module_sp->GetFileSpec().GetPath (old_path, PATH_MAX); + new_exec_module_sp->GetFileSpec().GetPath (new_path, PATH_MAX); + + result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n", + old_path, new_path); + } + + if (!old_arch_spec.IsValid()) + { + result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().GetTriple().getTriple().c_str()); } + else if (!old_arch_spec.IsExactMatch(target->GetArchitecture())) + { + result.AppendWarningWithFormat("Architecture changed from %s to %s.\n", + old_arch_spec.GetTriple().getTriple().c_str(), + target->GetArchitecture().GetTriple().getTriple().c_str()); + } + + // This supports the use-case scenario of immediately continuing the process once attached. + if (m_options.attach_info.GetContinueOnceAttached()) + m_interpreter.HandleCommand("process continue", eLazyBoolNo, result); + return result.Succeeded(); } @@ -714,7 +725,7 @@ protected: switch (short_option) { case 'i': - m_ignore = Args::StringToUInt32 (option_arg, 0, 0, &success); + m_ignore = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat ("invalid value for ignore option: \"%s\", should be a number.", option_arg); break; @@ -1297,7 +1308,7 @@ protected: for (uint32_t i=0; i<argc; ++i) { const char *image_token_cstr = command.GetArgumentAtIndex(i); - uint32_t image_token = Args::StringToUInt32(image_token_cstr, LLDB_INVALID_IMAGE_TOKEN, 0); + uint32_t image_token = StringConvert::ToUInt32(image_token_cstr, LLDB_INVALID_IMAGE_TOKEN, 0); if (image_token == LLDB_INVALID_IMAGE_TOKEN) { result.AppendErrorWithFormat ("invalid image index argument '%s'", image_token_cstr); @@ -1371,7 +1382,7 @@ protected: const char *signal_name = command.GetArgumentAtIndex(0); if (::isxdigit (signal_name[0])) - signo = Args::StringToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0); + signo = StringConvert::ToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0); else signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name); @@ -1754,7 +1765,7 @@ public: else { // If the value isn't 'true' or 'false', it had better be 0 or 1. - real_value = Args::StringToUInt32 (option.c_str(), 3); + real_value = StringConvert::ToUInt32 (option.c_str(), 3); if (real_value != 0 && real_value != 1) okay = false; } diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp index 8fb03e69ac42..a88a9b1f0cac 100644 --- a/source/Commands/CommandObjectSource.cpp +++ b/source/Commands/CommandObjectSource.cpp @@ -15,7 +15,6 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Interpreter/Args.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FileLineResolver.h" #include "lldb/Core/Module.h" @@ -24,6 +23,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Host/FileSpec.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" @@ -63,7 +63,7 @@ class CommandObjectSourceInfo : public CommandObjectParsed switch (short_option) { case 'l': - start_line = Args::StringToUInt32 (option_arg, 0); + start_line = StringConvert::ToUInt32 (option_arg, 0); if (start_line == 0) error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); break; @@ -171,13 +171,13 @@ class CommandObjectSourceList : public CommandObjectParsed switch (short_option) { case 'l': - start_line = Args::StringToUInt32 (option_arg, 0); + start_line = StringConvert::ToUInt32 (option_arg, 0); if (start_line == 0) error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg); break; case 'c': - num_lines = Args::StringToUInt32 (option_arg, 0); + num_lines = StringConvert::ToUInt32 (option_arg, 0); if (num_lines == 0) error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg); break; diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp index 0d9ffda1e96b..9188283966f1 100644 --- a/source/Commands/CommandObjectTarget.cpp +++ b/source/Commands/CommandObjectTarget.cpp @@ -27,6 +27,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" @@ -159,7 +160,6 @@ public: NULL), m_option_group (interpreter), m_arch_option (), - m_platform_options(true), // Do include the "--platform" option in the platform settings by passing true m_core_file (LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."), m_platform_path (LLDB_OPT_SET_1, false, "platform-path", 'P', 0, eArgTypePath, "Path to the remote file to use for this target."), m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable."), @@ -180,7 +180,6 @@ public: m_arguments.push_back (arg); m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_platform_path, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -282,70 +281,83 @@ protected: bool must_set_platform_path = false; Debugger &debugger = m_interpreter.GetDebugger(); - PlatformSP platform_sp(debugger.GetPlatformList().GetSelectedPlatform ()); - if (remote_file) + TargetSP target_sp; + const char *arch_cstr = m_arch_option.GetArchitectureName(); + const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue(); + Error error (debugger.GetTargetList().CreateTarget (debugger, + file_path, + arch_cstr, + get_dependent_files, + NULL, + target_sp)); + + if (target_sp) { - // I have a remote file.. two possible cases - if (file_spec && file_spec.Exists()) + // Only get the platform after we create the target because we might have + // switched platforms depending on what the arguments were to CreateTarget() + // we can't rely on the selected platform. + + PlatformSP platform_sp = target_sp->GetPlatform(); + + if (remote_file) { - // if the remote file does not exist, push it there - if (!platform_sp->GetFileExists (remote_file)) + if (platform_sp) { - Error err = platform_sp->PutFile(file_spec, remote_file); - if (err.Fail()) + // I have a remote file.. two possible cases + if (file_spec && file_spec.Exists()) { - result.AppendError(err.AsCString()); - result.SetStatus (eReturnStatusFailed); - return false; + // if the remote file does not exist, push it there + if (!platform_sp->GetFileExists (remote_file)) + { + Error err = platform_sp->PutFile(file_spec, remote_file); + if (err.Fail()) + { + result.AppendError(err.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } } - } - } - else - { - // there is no local file and we need one - // in order to make the remote ---> local transfer we need a platform - // TODO: if the user has passed in a --platform argument, use it to fetch the right platform - if (!platform_sp) - { - result.AppendError("unable to perform remote debugging without a platform"); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (file_path) - { - // copy the remote file to the local file - Error err = platform_sp->GetFile(remote_file, file_spec); - if (err.Fail()) + else { - result.AppendError(err.AsCString()); - result.SetStatus (eReturnStatusFailed); - return false; + // there is no local file and we need one + // in order to make the remote ---> local transfer we need a platform + // TODO: if the user has passed in a --platform argument, use it to fetch the right platform + if (!platform_sp) + { + result.AppendError("unable to perform remote debugging without a platform"); + result.SetStatus (eReturnStatusFailed); + return false; + } + if (file_path) + { + // copy the remote file to the local file + Error err = platform_sp->GetFile(remote_file, file_spec); + if (err.Fail()) + { + result.AppendError(err.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // make up a local file + result.AppendError("remote --> local transfer without local path is not implemented yet"); + result.SetStatus (eReturnStatusFailed); + return false; + } } } else { - // make up a local file - result.AppendError("remote --> local transfer without local path is not implemented yet"); + result.AppendError("no platform found for target"); result.SetStatus (eReturnStatusFailed); return false; } } - } - TargetSP target_sp; - const char *arch_cstr = m_arch_option.GetArchitectureName(); - const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue(); - Error error (debugger.GetTargetList().CreateTarget (debugger, -// remote_file ? remote_file : file_spec, - file_path, - arch_cstr, - get_dependent_files, - &m_platform_options, - target_sp)); - - if (target_sp) - { if (symfile || remote_file) { ModuleSP module_sp (target_sp->GetExecutableModule()); @@ -426,7 +438,7 @@ protected: } else { - result.AppendErrorWithFormat("'%s' takes exactly one executable path argument, or use the --core-file option.\n", m_cmd_name.c_str()); + result.AppendErrorWithFormat("'%s' takes exactly one executable path argument, or use the --core option.\n", m_cmd_name.c_str()); result.SetStatus (eReturnStatusFailed); } return result.Succeeded(); @@ -435,7 +447,6 @@ protected: private: OptionGroupOptions m_option_group; OptionGroupArchitecture m_arch_option; - OptionGroupPlatform m_platform_options; OptionGroupFile m_core_file; OptionGroupFile m_platform_path; OptionGroupFile m_symbol_file; @@ -522,7 +533,7 @@ protected: { bool success = false; const char *target_idx_arg = args.GetArgumentAtIndex(0); - uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success); + uint32_t target_idx = StringConvert::ToUInt32 (target_idx_arg, UINT32_MAX, 0, &success); if (success) { TargetList &target_list = m_interpreter.GetDebugger().GetTargetList(); @@ -629,7 +640,7 @@ protected: for (uint32_t arg_idx = 0; success && arg_idx < argc; ++arg_idx) { const char *target_idx_arg = args.GetArgumentAtIndex(arg_idx); - uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success); + uint32_t target_idx = StringConvert::ToUInt32 (target_idx_arg, UINT32_MAX, 0, &success); if (success) { if (target_idx < num_targets) @@ -1260,7 +1271,7 @@ protected: { bool success = false; - uint32_t insert_idx = Args::StringToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success); + uint32_t insert_idx = StringConvert::ToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success); if (!success) { @@ -2963,7 +2974,7 @@ protected: { ConstString const_sect_name(sect_name); bool success = false; - addr_t load_addr = Args::StringToUInt64(load_addr_cstr, LLDB_INVALID_ADDRESS, 0, &success); + addr_t load_addr = StringConvert::ToUInt64(load_addr_cstr, LLDB_INVALID_ADDRESS, 0, &success); if (success) { SectionSP section_sp (section_list->FindSectionByName(const_sect_name)); @@ -3890,7 +3901,7 @@ public: break; case 'o': - m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS); + m_offset = StringConvert::ToUInt64(option_arg, LLDB_INVALID_ADDRESS); if (m_offset == LLDB_INVALID_ADDRESS) error.SetErrorStringWithFormat ("invalid offset string '%s'", option_arg); break; @@ -3910,7 +3921,7 @@ public: break; case 'l': - m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX); + m_line_number = StringConvert::ToUInt32(option_arg, UINT32_MAX); if (m_line_number == UINT32_MAX) error.SetErrorStringWithFormat ("invalid line number string '%s'", option_arg); else if (m_line_number == 0) @@ -4078,7 +4089,7 @@ public: if (LookupAddressInModule (m_interpreter, result.GetOutputStream(), module, - eSymbolContextEverything, + eSymbolContextEverything | (m_options.m_verbose ? eSymbolContextVariable : 0), m_options.m_addr, m_options.m_offset, m_options.m_verbose)) @@ -4873,7 +4884,7 @@ public: break; case 'e': - m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success); + m_line_end = StringConvert::ToUInt32 (option_arg, UINT_MAX, 0, &success); if (!success) { error.SetErrorStringWithFormat ("invalid end line number: \"%s\"", option_arg); @@ -4883,7 +4894,7 @@ public: break; case 'l': - m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success); + m_line_start = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success) { error.SetErrorStringWithFormat ("invalid start line number: \"%s\"", option_arg); @@ -4912,7 +4923,7 @@ public: break; case 't' : { - m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); + m_thread_id = StringConvert::ToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); if (m_thread_id == LLDB_INVALID_THREAD_ID) error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); m_thread_specified = true; @@ -4928,7 +4939,7 @@ public: break; case 'x': { - m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_thread_index = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_thread_id == UINT32_MAX) error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); m_thread_specified = true; @@ -5233,7 +5244,7 @@ protected: bool success; for (size_t i = 0; i < num_args; i++) { - lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); + lldb::user_id_t user_id = StringConvert::ToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); if (!success) { result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); @@ -5302,7 +5313,7 @@ protected: { for (size_t i = 0; i < num_args; i++) { - lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); + lldb::user_id_t user_id = StringConvert::ToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); if (!success) { result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index bace4e58b4ad..199d16b85205 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/State.h" #include "lldb/Core/SourceManager.h" #include "lldb/Host/Host.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/Options.h" @@ -95,7 +96,7 @@ public: { bool success; - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); + uint32_t thread_idx = StringConvert::ToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); if (!success) { result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); @@ -178,7 +179,7 @@ public: case 'c': { bool success; - int32_t input_count = Args::StringToSInt32 (option_arg, -1, 0, &success); + int32_t input_count = StringConvert::ToSInt32 (option_arg, -1, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option); if (input_count < -1) @@ -190,7 +191,7 @@ public: case 's': { bool success; - m_start = Args::StringToUInt32 (option_arg, 0, 0, &success); + m_start = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option); } @@ -384,7 +385,7 @@ public: case 'c': { - m_step_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_step_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_step_count == UINT32_MAX) error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); break; @@ -522,7 +523,7 @@ protected: else { const char *thread_idx_cstr = command.GetArgumentAtIndex(0); - uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32); + uint32_t step_thread_idx = StringConvert::ToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32); if (step_thread_idx == LLDB_INVALID_INDEX32) { result.AppendErrorWithFormat ("invalid thread index '%s'.\n", thread_idx_cstr); @@ -812,7 +813,7 @@ public: { bool success; const int base = 0; - uint32_t thread_idx = Args::StringToUInt32 (command.GetArgumentAtIndex(i), LLDB_INVALID_INDEX32, base, &success); + uint32_t thread_idx = StringConvert::ToUInt32 (command.GetArgumentAtIndex(i), LLDB_INVALID_INDEX32, base, &success); if (success) { Thread *thread = process->GetThreadList().FindThreadByIndexID(thread_idx).get(); @@ -984,9 +985,17 @@ public: switch (short_option) { + case 'a': + { + ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); + lldb::addr_t tmp_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); + if (error.Success()) + m_until_addrs.push_back(tmp_addr); + } + break; case 't': { - m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32); + m_thread_idx = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_INDEX32); if (m_thread_idx == LLDB_INVALID_INDEX32) { error.SetErrorStringWithFormat ("invalid thread index '%s'", option_arg); @@ -995,7 +1004,7 @@ public: break; case 'f': { - m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID); + m_frame_idx = StringConvert::ToUInt32 (option_arg, LLDB_INVALID_FRAME_ID); if (m_frame_idx == LLDB_INVALID_FRAME_ID) { error.SetErrorStringWithFormat ("invalid frame index '%s'", option_arg); @@ -1030,6 +1039,7 @@ public: m_thread_idx = LLDB_INVALID_THREAD_ID; m_frame_idx = 0; m_stop_others = false; + m_until_addrs.clear(); } const OptionDefinition* @@ -1040,6 +1050,7 @@ public: uint32_t m_step_thread_idx; bool m_stop_others; + std::vector<lldb::addr_t> m_until_addrs; // Options table: Required for subclasses of Options. @@ -1051,7 +1062,7 @@ public: CommandObjectThreadUntil (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "thread until", - "Run the current or specified thread until it reaches a given line number or leaves the current function.", + "Run the current or specified thread until it reaches a given line number or address or leaves the current function.", NULL, eFlagRequiresThread | eFlagTryTargetAPILock | @@ -1110,23 +1121,33 @@ protected: else { Thread *thread = NULL; - uint32_t line_number; + std::vector<uint32_t> line_numbers; - if (command.GetArgumentCount() != 1) + if (command.GetArgumentCount() >= 1) { - result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax()); - result.SetStatus (eReturnStatusFailed); - return false; + size_t num_args = command.GetArgumentCount(); + for (size_t i = 0; i < num_args; i++) + { + uint32_t line_number; + line_number = StringConvert::ToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX); + if (line_number == UINT32_MAX) + { + result.AppendErrorWithFormat ("invalid line number: '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + line_numbers.push_back(line_number); + } } - - line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX); - if (line_number == UINT32_MAX) + else if (m_options.m_until_addrs.empty()) { - result.AppendErrorWithFormat ("invalid line number: '%s'.\n", command.GetArgumentAtIndex(0)); + result.AppendErrorWithFormat ("No line number or address provided:\n%s", GetSyntax()); result.SetStatus (eReturnStatusFailed); return false; } + if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) { thread = process->GetThreadList().GetSelectedThread().get(); @@ -1188,27 +1209,40 @@ protected: Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize()); - line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr); bool all_in_function = true; - - while (index_ptr <= end_ptr) + + line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr); + + for (uint32_t line_number : line_numbers) { - LineEntry line_entry; - const bool exact = false; - index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, exact, &line_entry); - if (index_ptr == UINT32_MAX) - break; - - addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(target); - if (address != LLDB_INVALID_ADDRESS) + uint32_t start_idx_ptr = index_ptr; + while (start_idx_ptr <= end_ptr) { - if (fun_addr_range.ContainsLoadAddress (address, target)) - address_list.push_back (address); - else - all_in_function = false; + LineEntry line_entry; + const bool exact = false; + start_idx_ptr = sc.comp_unit->FindLineEntry(start_idx_ptr, line_number, sc.comp_unit, exact, &line_entry); + if (start_idx_ptr == UINT32_MAX) + break; + + addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(target); + if (address != LLDB_INVALID_ADDRESS) + { + if (fun_addr_range.ContainsLoadAddress (address, target)) + address_list.push_back (address); + else + all_in_function = false; + } + start_idx_ptr++; } - index_ptr++; + } + + for (lldb::addr_t address : m_options.m_until_addrs) + { + if (fun_addr_range.ContainsLoadAddress (address, target)) + address_list.push_back (address); + else + all_in_function = false; } if (address_list.size() == 0) @@ -1290,7 +1324,8 @@ CommandObjectThreadUntil::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0"}, { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation"}, -{ LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, NULL, g_duo_running_mode, 0, eArgTypeRunMode,"Determine how to run other threads while stepping this one"}, +{ LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, NULL, g_duo_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping this one"}, +{ LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, "Run until we reach the specified address, or leave the function - can be specified multiple times."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1351,7 +1386,7 @@ protected: return false; } - uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0); + uint32_t index_id = StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get(); if (new_thread == NULL) @@ -1796,12 +1831,12 @@ public: return Error("only one source file expected."); break; case 'l': - m_line_num = Args::StringToUInt32 (option_arg, 0, 0, &success); + m_line_num = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success || m_line_num == 0) return Error("invalid line number: '%s'.", option_arg); break; case 'b': - m_line_offset = Args::StringToSInt32 (option_arg, 0, 0, &success); + m_line_offset = StringConvert::ToSInt32 (option_arg, 0, 0, &success); if (!success) return Error("invalid line offset: '%s'.", option_arg); break; @@ -2120,7 +2155,7 @@ public: } bool success; - uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); + uint32_t thread_plan_idx = StringConvert::ToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); if (!success) { result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.", diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp index ca5fe98ccb31..bef59ca30b3c 100644 --- a/source/Commands/CommandObjectWatchpoint.cpp +++ b/source/Commands/CommandObjectWatchpoint.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandCompletions.h" @@ -639,7 +640,7 @@ public: { case 'i': { - m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); + m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); if (m_ignore_count == UINT32_MAX) error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); } diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp index a79becbf49c4..d449d0b21438 100644 --- a/source/Core/Address.cpp +++ b/source/Core/Address.cpp @@ -654,7 +654,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum if (module_sp) { SymbolContext sc; - module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc); + module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything | eSymbolContextVariable, sc); if (sc.function || sc.symbol) { bool show_stop_context = true; @@ -712,7 +712,7 @@ Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Dum if (module_sp) { SymbolContext sc; - module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc); + module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything | eSymbolContextVariable, sc); if (sc.symbol) { // If we have just a symbol make sure it is in the same section diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index e7a5e489af19..015f76bffbb5 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -765,6 +765,19 @@ ArchSpec::SetTriple (const char *triple_cstr, Platform *platform) return IsValid(); } +void +ArchSpec::MergeFrom(const ArchSpec &other) +{ + if (GetTriple().getVendor() == llvm::Triple::UnknownVendor && !TripleVendorWasSpecified()) + GetTriple().setVendor(other.GetTriple().getVendor()); + if (GetTriple().getOS() == llvm::Triple::UnknownOS && !TripleOSWasSpecified()) + GetTriple().setOS(other.GetTriple().getOS()); + if (GetTriple().getArch() == llvm::Triple::UnknownArch) + GetTriple().setArch(other.GetTriple().getArch()); + if (GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment) + GetTriple().setEnvironment(other.GetTriple().getEnvironment()); +} + bool ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub) { diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp index dc37516c29c2..1cbbde20e7f6 100644 --- a/source/Core/Broadcaster.cpp +++ b/source/Core/Broadcaster.cpp @@ -303,6 +303,16 @@ Broadcaster::HijackBroadcaster (Listener *listener, uint32_t event_mask) return true; } +bool +Broadcaster::IsHijackedForEvent (uint32_t event_mask) +{ + Mutex::Locker event_types_locker(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) + return (event_mask & m_hijacking_masks.back()) != 0; + return false; +} + void Broadcaster::RestoreBroadcaster () { diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp index 05ada9872b5b..fe29814be420 100644 --- a/source/Core/ConnectionMachPort.cpp +++ b/source/Core/ConnectionMachPort.cpp @@ -107,6 +107,7 @@ ConnectionMachPort::Connect (const char *s, Error *error_ptr) { if (error_ptr) error_ptr->Clear(); + m_uri.assign(s); } else { @@ -209,6 +210,7 @@ ConnectionMachPort::Disconnect (Error *error_ptr) error_ptr->SetError (kret, eErrorTypeMachKernel); m_port = MACH_PORT_TYPE_NONE; } + m_uri.clear(); return eConnectionStatusSuccess; } @@ -256,6 +258,12 @@ ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &st return 0; } +std::string +ConnectionMachPort::GetURI() +{ + return m_uri; +} + ConnectionStatus ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) { diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp index 1cbee20cd94a..d3dfa3cd8d56 100644 --- a/source/Core/ConnectionSharedMemory.cpp +++ b/source/Core/ConnectionSharedMemory.cpp @@ -107,6 +107,13 @@ ConnectionSharedMemory::Write (const void *src, size_t src_len, ConnectionStatus return 0; } +std::string +ConnectionSharedMemory::GetURI() +{ + // TODO: fix when Connect is fixed? + return ""; +} + ConnectionStatus ConnectionSharedMemory::BytesAvailable (uint32_t timeout_usec, Error *error_ptr) { diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp index 37d24e0dec00..85f8d3c65cd9 100644 --- a/source/Core/ConstString.cpp +++ b/source/Core/ConstString.cpp @@ -11,7 +11,7 @@ #include "lldb/Host/Mutex.h" #include "llvm/ADT/StringMap.h" -#include <mutex> +#include <mutex> // std::once using namespace lldb_private; diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index c7342ade6cad..f25a3f41825f 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "lldb/lldb-private.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegisterValue.h" @@ -130,24 +131,23 @@ g_language_enumerators[] = static PropertyDefinition g_properties[] = { -{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, -{ "disassembly-format", OptionValue::eTypeString , true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, -{ "frame-format", OptionValue::eTypeString , true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, -{ "notify-void", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, -{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, -{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, -{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, -{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, -{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, -{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, -{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, -{ "thread-format", OptionValue::eTypeString , true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, -{ "use-external-editor", OptionValue::eTypeBoolean, true, false, NULL, NULL, "Whether to use an external editor or not." }, -{ "use-color", OptionValue::eTypeBoolean, true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, -{ "auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, -{ "escape-non-printables", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, - - { NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL } +{ "auto-confirm", OptionValue::eTypeBoolean , true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." }, +{ "disassembly-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_DISASSEMBLY_FORMAT, NULL, "The default disassembly format string to use when disassembling instruction sequences." }, +{ "frame-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_FRAME_FORMAT, NULL, "The default frame format string to use when displaying stack frame information for threads." }, +{ "notify-void", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Notify the user explicitly if an expression returns void (default: false)." }, +{ "prompt", OptionValue::eTypeString , true, OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", NULL, "The debugger command line prompt displayed for the user." }, +{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." }, +{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." }, +{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." }, +{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." }, +{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." }, +{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." }, +{ "thread-format", OptionValue::eTypeFormatEntity, true, 0 , DEFAULT_THREAD_FORMAT, NULL, "The default thread format string to use when displaying thread information." }, +{ "use-external-editor", OptionValue::eTypeBoolean , true, false, NULL, NULL, "Whether to use an external editor or not." }, +{ "use-color", OptionValue::eTypeBoolean , true, true , NULL, NULL, "Whether to use Ansi color codes or not." }, +{ "auto-one-line-summaries", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically display small structs in one-liner format (default: true)." }, +{ "escape-non-printables", OptionValue::eTypeBoolean , true, true, NULL, NULL, "If true, LLDB will automatically escape non-printable and escape characters when formatting strings." }, +{ NULL, OptionValue::eTypeInvalid , true, 0 , NULL, NULL, NULL } }; enum @@ -242,18 +242,18 @@ Debugger::GetAutoConfirm () const return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); } -const char * +const FormatEntity::Entry * Debugger::GetDisassemblyFormat() const { const uint32_t idx = ePropertyDisassemblyFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } -const char * +const FormatEntity::Entry * Debugger::GetFrameFormat() const { const uint32_t idx = ePropertyFrameFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } bool @@ -282,11 +282,11 @@ Debugger::SetPrompt(const char *p) GetCommandInterpreter().UpdatePrompt(new_prompt); } -const char * +const FormatEntity::Entry * Debugger::GetThreadFormat() const { const uint32_t idx = ePropertyThreadFormat; - return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value); + return m_collection_sp->GetPropertyAtIndexAsFormatEntity(NULL, idx); } lldb::ScriptLanguage @@ -927,6 +927,18 @@ Debugger::GetTopIOHandlerControlSequence(char ch) return m_input_reader_stack.GetTopIOHandlerControlSequence (ch); } +const char * +Debugger::GetIOHandlerCommandPrefix() +{ + return m_input_reader_stack.GetTopIOHandlerCommandPrefix(); +} + +const char * +Debugger::GetIOHandlerHelpPrologue() +{ + return m_input_reader_stack.GetTopIOHandlerHelpPrologue(); +} + void Debugger::RunIOHandler (const IOHandlerSP& reader_sp) { @@ -1214,1691 +1226,25 @@ TestPromptFormats (StackFrame *frame) } #endif -static bool -ScanFormatDescriptor (const char* var_name_begin, - const char* var_name_end, - const char** var_name_final, - const char** percent_position, - Format* custom_format, - ValueObject::ValueObjectRepresentationStyle* val_obj_display) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - *percent_position = ::strchr(var_name_begin,'%'); - if (!*percent_position || *percent_position > var_name_end) - { - if (log) - log->Printf("[ScanFormatDescriptor] no format descriptor in string, skipping"); - *var_name_final = var_name_end; - } - else - { - *var_name_final = *percent_position; - std::string format_name(*var_name_final+1, var_name_end-*var_name_final-1); - if (log) - log->Printf("[ScanFormatDescriptor] parsing %s as a format descriptor", format_name.c_str()); - if ( !FormatManager::GetFormatFromCString(format_name.c_str(), - true, - *custom_format) ) - { - if (log) - log->Printf("[ScanFormatDescriptor] %s is an unknown format", format_name.c_str()); - - switch (format_name.front()) - { - case '@': // if this is an @ sign, print ObjC description - *val_obj_display = ValueObject::eValueObjectRepresentationStyleLanguageSpecific; - break; - case 'V': // if this is a V, print the value using the default format - *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - break; - case 'L': // if this is an L, print the location of the value - *val_obj_display = ValueObject::eValueObjectRepresentationStyleLocation; - break; - case 'S': // if this is an S, print the summary after all - *val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; - break; - case '#': // if this is a '#', print the number of children - *val_obj_display = ValueObject::eValueObjectRepresentationStyleChildrenCount; - break; - case 'T': // if this is a 'T', print the type - *val_obj_display = ValueObject::eValueObjectRepresentationStyleType; - break; - case 'N': // if this is a 'N', print the name - *val_obj_display = ValueObject::eValueObjectRepresentationStyleName; - break; - case '>': // if this is a '>', print the name - *val_obj_display = ValueObject::eValueObjectRepresentationStyleExpressionPath; - break; - default: - if (log) - log->Printf("ScanFormatDescriptor] %s is an error, leaving the previous value alone", format_name.c_str()); - break; - } - } - // a good custom format tells us to print the value using it - else - { - if (log) - log->Printf("[ScanFormatDescriptor] will display value for this VO"); - *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - } - if (log) - log->Printf("[ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d", - *custom_format, - *val_obj_display); - return true; -} - -static bool -ScanBracketedRange (const char* var_name_begin, - const char* var_name_end, - const char* var_name_final, - const char** open_bracket_position, - const char** separator_position, - const char** close_bracket_position, - const char** var_name_final_if_array_range, - int64_t* index_lower, - int64_t* index_higher) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - *open_bracket_position = ::strchr(var_name_begin,'['); - if (*open_bracket_position && *open_bracket_position < var_name_final) - { - *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield - *close_bracket_position = ::strchr(*open_bracket_position,']'); - // as usual, we assume that [] will come before % - //printf("trying to expand a []\n"); - *var_name_final_if_array_range = *open_bracket_position; - if (*close_bracket_position - *open_bracket_position == 1) - { - if (log) - log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data"); - *index_lower = 0; - } - else if (*separator_position == NULL || *separator_position > var_name_end) - { - char *end = NULL; - *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); - *index_higher = *index_lower; - if (log) - log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", *index_lower); - } - else if (*close_bracket_position && *close_bracket_position < var_name_end) - { - char *end = NULL; - *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); - *index_higher = ::strtoul (*separator_position+1, &end, 0); - if (log) - log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", *index_lower, *index_higher); - } - else - { - if (log) - log->Printf("[ScanBracketedRange] expression is erroneous, cannot extract indices out of it"); - return false; - } - if (*index_lower > *index_higher && *index_higher > 0) - { - if (log) - log->Printf("[ScanBracketedRange] swapping indices"); - int64_t temp = *index_lower; - *index_lower = *index_higher; - *index_higher = temp; - } - } - else if (log) - log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely"); - return true; -} - -template <typename T> -static bool RunScriptFormatKeyword(Stream &s, ScriptInterpreter *script_interpreter, T t, const std::string& script_name) -{ - if (script_interpreter) - { - Error script_error; - std::string script_output; - - if (script_interpreter->RunScriptFormatKeyword(script_name.c_str(), t, script_output, script_error) && script_error.Success()) - { - s.Printf("%s", script_output.c_str()); - return true; - } - else - { - s.Printf("<error: %s>",script_error.AsCString()); - } - } - return false; -} - -static ValueObjectSP -ExpandIndexedExpression (ValueObject* valobj, - size_t index, - StackFrame* frame, - bool deref_pointer) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - const char* ptr_deref_format = "[%d]"; - std::string ptr_deref_buffer(10,0); - ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index); - if (log) - log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str()); - const char* first_unparsed; - ValueObject::GetValueForExpressionPathOptions options; - ValueObject::ExpressionPathEndResultType final_value_type; - ValueObject::ExpressionPathScanEndReason reason_to_stop; - ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); - ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(), - &first_unparsed, - &reason_to_stop, - &final_value_type, - options, - &what_next); - if (!item) - { - if (log) - log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - } - else - { - if (log) - log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - } - return item; -} - -static inline bool -IsToken(const char *var_name_begin, const char *var) -{ - return (::strncmp (var_name_begin, var, strlen(var)) == 0); -} - -static bool -IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &format, const char *default_format, - const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr) -{ - int var_len = strlen(var); - if (::strncmp (var_name_begin, var, var_len) == 0) - { - var_name_begin += var_len; - if (*var_name_begin == '}') - { - format = default_format; - return true; - } - else if (*var_name_begin == '%') - { - // Allow format specifiers: x|X|u with optional width specifiers. - // ${thread.id%x} ; hex - // ${thread.id%X} ; uppercase hex - // ${thread.id%u} ; unsigned decimal - // ${thread.id%8.8X} ; width.precision + specifier - // ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id) - int dot_count = 0; - const char *specifier = NULL; - int width_precision_length = 0; - const char *width_precision = ++var_name_begin; - while (isdigit(*var_name_begin) || *var_name_begin == '.') - { - dot_count += (*var_name_begin == '.'); - if (dot_count > 1) - break; - var_name_begin++; - width_precision_length++; - } - - if (IsToken (var_name_begin, "tid}")) - { - Target *target = Target::GetTargetFromContexts (exe_ctx_ptr, sc_ptr); - if (target) - { - ArchSpec arch (target->GetArchitecture ()); - llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS; - if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux)) - specifier = PRIu64; - } - if (!specifier) - { - format = default_format; - return true; - } - } - else if (IsToken (var_name_begin, "x}")) - specifier = PRIx64; - else if (IsToken (var_name_begin, "X}")) - specifier = PRIX64; - else if (IsToken (var_name_begin, "u}")) - specifier = PRIu64; - - if (specifier) - { - format = "%"; - if (width_precision_length) - format += std::string(width_precision, width_precision_length); - format += specifier; - return true; - } - } - } - return false; -} - -// Find information for the "thread.info.*" specifiers in a format string -static bool -FormatThreadExtendedInfoRecurse -( - const char *var_name_begin, - StructuredData::ObjectSP thread_info_dictionary, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - Stream &s -) -{ - bool var_success = false; - std::string token_format; - - llvm::StringRef var_name(var_name_begin); - size_t percent_idx = var_name.find('%'); - size_t close_curly_idx = var_name.find('}'); - llvm::StringRef path = var_name; - llvm::StringRef formatter = var_name; - - // 'path' will be the dot separated list of objects to transverse up until we hit - // a close curly brace, a percent sign, or an end of string. - if (percent_idx != llvm::StringRef::npos || close_curly_idx != llvm::StringRef::npos) - { - if (percent_idx != llvm::StringRef::npos && close_curly_idx != llvm::StringRef::npos) - { - if (percent_idx < close_curly_idx) - { - path = var_name.slice(0, percent_idx); - formatter = var_name.substr (percent_idx); - } - else - { - path = var_name.slice(0, close_curly_idx); - formatter = var_name.substr (close_curly_idx); - } - } - else if (percent_idx != llvm::StringRef::npos) - { - path = var_name.slice(0, percent_idx); - formatter = var_name.substr (percent_idx); - } - else if (close_curly_idx != llvm::StringRef::npos) - { - path = var_name.slice(0, close_curly_idx); - formatter = var_name.substr (close_curly_idx); - } - } - - StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path); - - if (value.get()) - { - if (value->GetType() == StructuredData::Type::eTypeInteger) - { - if (IsTokenWithFormat (formatter.str().c_str(), "", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), value->GetAsInteger()->GetValue()); - var_success = true; - } - } - else if (value->GetType() == StructuredData::Type::eTypeFloat) - { - s.Printf ("%f", value->GetAsFloat()->GetValue()); - var_success = true; - } - else if (value->GetType() == StructuredData::Type::eTypeString) - { - s.Printf("%s", value->GetAsString()->GetValue().c_str()); - var_success = true; - } - else if (value->GetType() == StructuredData::Type::eTypeArray) - { - if (value->GetAsArray()->GetSize() > 0) - { - s.Printf ("%zu", value->GetAsArray()->GetSize()); - var_success = true; - } - } - else if (value->GetType() == StructuredData::Type::eTypeDictionary) - { - s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); - var_success = true; - } - } - - return var_success; -} - - -static bool -FormatPromptRecurse -( - const char *format, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s, - const char **end, - ValueObject* valobj, - bool function_changed, - bool initial_function -) -{ - ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers - bool success = true; - const char *p; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); - - for (p = format; *p != '\0'; ++p) - { - if (realvalobj) - { - valobj = realvalobj; - realvalobj = NULL; - } - size_t non_special_chars = ::strcspn (p, "${}\\"); - if (non_special_chars > 0) - { - if (success) - s.Write (p, non_special_chars); - p += non_special_chars; - } - - if (*p == '\0') - { - break; - } - else if (*p == '{') - { - // Start a new scope that must have everything it needs if it is to - // to make it into the final output stream "s". If you want to make - // a format that only prints out the function or symbol name if there - // is one in the symbol context you can use: - // "{function =${function.name}}" - // The first '{' starts a new scope that end with the matching '}' at - // the end of the string. The contents "function =${function.name}" - // will then be evaluated and only be output if there is a function - // or symbol with a valid name. - StreamString sub_strm; - - ++p; // Skip the '{' - - if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj, function_changed, initial_function)) - { - // The stream had all it needed - s.Write(sub_strm.GetData(), sub_strm.GetSize()); - } - if (*p != '}') - { - success = false; - break; - } - } - else if (*p == '}') - { - // End of a enclosing scope - break; - } - else if (*p == '$') - { - // We have a prompt variable to print - ++p; - if (*p == '{') - { - ++p; - const char *var_name_begin = p; - const char *var_name_end = ::strchr (p, '}'); - - if (var_name_end && var_name_begin < var_name_end) - { - // if we have already failed to parse, skip this variable - if (success) - { - const char *cstr = NULL; - std::string token_format; - Address format_addr; - - // normally "addr" means print a raw address but - // "file-addr-or-load-addr" means print a module + file addr if there's no load addr - bool print_file_addr_or_load_addr = false; - bool addr_offset_concrete_func_only = false; - bool addr_offset_print_with_no_padding = false; - bool calculate_format_addr_function_offset = false; - // Set reg_kind and reg_num to invalid values - RegisterKind reg_kind = kNumRegisterKinds; - uint32_t reg_num = LLDB_INVALID_REGNUM; - FileSpec format_file_spec; - const RegisterInfo *reg_info = NULL; - RegisterContext *reg_ctx = NULL; - bool do_deref_pointer = false; - ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; - ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain; - - // Each variable must set success to true below... - bool var_success = false; - switch (var_name_begin[0]) - { - case '*': - case 'v': - case 's': - { - if (!valobj) - break; - - if (log) - log->Printf("[Debugger::FormatPrompt] initial string: %s",var_name_begin); - - // check for *var and *svar - if (*var_name_begin == '*') - { - do_deref_pointer = true; - var_name_begin++; - if (log) - log->Printf("[Debugger::FormatPrompt] found a deref, new string is: %s",var_name_begin); - } - - if (*var_name_begin == 's') - { - if (!valobj->IsSynthetic()) - valobj = valobj->GetSyntheticValue().get(); - if (!valobj) - break; - var_name_begin++; - if (log) - log->Printf("[Debugger::FormatPrompt] found a synthetic, new string is: %s",var_name_begin); - } - - // should be a 'v' by now - if (*var_name_begin != 'v') - break; - - if (log) - log->Printf("[Debugger::FormatPrompt] string I am working with: %s",var_name_begin); - - ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? - ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); - ValueObject::GetValueForExpressionPathOptions options; - options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren(); - ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary; - ValueObject* target = NULL; - Format custom_format = eFormatInvalid; - const char* var_name_final = NULL; - const char* var_name_final_if_array_range = NULL; - const char* close_bracket_position = NULL; - int64_t index_lower = -1; - int64_t index_higher = -1; - bool is_array_range = false; - const char* first_unparsed; - bool was_plain_var = false; - bool was_var_format = false; - bool was_var_indexed = false; - - if (!valobj) break; - // simplest case ${var}, just print valobj's value - if (IsToken (var_name_begin, "var}")) - { - was_plain_var = true; - target = valobj; - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - else if (IsToken (var_name_begin, "var.script:")) - { - var_name_begin += ::strlen("var.script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = valobj->GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, valobj, script_name)) - var_success = true; - break; - } - else if (IsToken (var_name_begin,"var%")) - { - was_var_format = true; - // this is a variable with some custom format applied to it - const char* percent_position; - target = valobj; - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - ScanFormatDescriptor (var_name_begin, - var_name_end, - &var_name_final, - &percent_position, - &custom_format, - &val_obj_display); - } - // this is ${var.something} or multiple .something nested - else if (IsToken (var_name_begin, "var")) - { - if (IsToken (var_name_begin, "var[")) - was_var_indexed = true; - const char* percent_position; - ScanFormatDescriptor (var_name_begin, - var_name_end, - &var_name_final, - &percent_position, - &custom_format, - &val_obj_display); - - const char* open_bracket_position; - const char* separator_position; - ScanBracketedRange (var_name_begin, - var_name_end, - var_name_final, - &open_bracket_position, - &separator_position, - &close_bracket_position, - &var_name_final_if_array_range, - &index_lower, - &index_higher); - - Error error; - - std::string expr_path(var_name_final-var_name_begin-1,0); - memcpy(&expr_path[0], var_name_begin+3,var_name_final-var_name_begin-3); - - if (log) - log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str()); - - target = valobj->GetValueForExpressionPath(expr_path.c_str(), - &first_unparsed, - &reason_to_stop, - &final_value_type, - options, - &what_next).get(); - - if (!target) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - break; - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d," - " final_value_type %d", - first_unparsed, reason_to_stop, final_value_type); - target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get(); - } - } - else - break; - - is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange || - final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange); - - do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference); - - if (do_deref_pointer && !is_array_range) - { - // I have not deref-ed yet, let's do it - // this happens when we are not going through GetValueForVariableExpressionPath - // to get to the target ValueObject - Error error; - target = target->Dereference(error).get(); - if (error.Fail()) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \ - break; - } - do_deref_pointer = false; - } - - if (!target) - { - if (log) - log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression"); - break; - } - - // we do not want to use the summary for a bitfield of type T:n - // if we were originally dealing with just a T - that would get - // us into an endless recursion - if (target->IsBitfield() && was_var_indexed) - { - // TODO: check for a (T:n)-specific summary - we should still obey that - StreamString bitfield_name; - bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize()); - lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false)); - if (!DataVisualization::GetSummaryForType(type_sp)) - val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; - } - - // TODO use flags for these - const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL); - bool is_array = (type_info_flags & eTypeIsArray) != 0; - bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; - bool is_aggregate = target->GetClangType().IsAggregateType(); - - if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions - { - StreamString str_temp; - if (log) - log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range"); - - if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format)) - { - // try to use the special cases - var_success = target->DumpPrintableRepresentation(str_temp, - val_obj_display, - custom_format); - if (log) - log->Printf("[Debugger::FormatPrompt] special cases did%s match", var_success ? "" : "n't"); - - // should not happen - if (var_success) - s << str_temp.GetData(); - var_success = true; - break; - } - else - { - if (was_plain_var) // if ${var} - { - s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); - } - else if (is_pointer) // if pointer, value is the address stored - { - target->DumpPrintableRepresentation (s, - val_obj_display, - custom_format, - ValueObject::ePrintableRepresentationSpecialCasesDisable); - } - var_success = true; - break; - } - } - - // if directly trying to print ${var}, and this is an aggregate, display a nice - // type @ location message - if (is_aggregate && was_plain_var) - { - s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); - var_success = true; - break; - } - - // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it - if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue))) - { - s << "<invalid use of aggregate type>"; - var_success = true; - break; - } - - if (!is_array_range) - { - if (log) - log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output"); - var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] checking if I can handle as array"); - if (!is_array && !is_pointer) - break; - if (log) - log->Printf("[Debugger::FormatPrompt] handle as array"); - const char* special_directions = NULL; - StreamString special_directions_writer; - if (close_bracket_position && (var_name_end-close_bracket_position > 1)) - { - ConstString additional_data; - additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1); - special_directions_writer.Printf("${%svar%s}", - do_deref_pointer ? "*" : "", - additional_data.GetCString()); - special_directions = special_directions_writer.GetData(); - } - - // let us display items index_lower thru index_higher of this array - s.PutChar('['); - var_success = true; - - if (index_higher < 0) - index_higher = valobj->GetNumChildren() - 1; - - uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); - - for (;index_lower<=index_higher;index_lower++) - { - ValueObject* item = ExpandIndexedExpression (target, - index_lower, - exe_ctx->GetFramePtr(), - false).get(); - - if (!item) - { - if (log) - log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index_lower); - } - else - { - if (log) - log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions); - } - - if (!special_directions) - var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); - else - var_success &= FormatPromptRecurse(special_directions, sc, exe_ctx, addr, s, NULL, item, function_changed, initial_function); - - if (--max_num_children == 0) - { - s.PutCString(", ..."); - break; - } - - if (index_lower < index_higher) - s.PutChar(','); - } - s.PutChar(']'); - } - } - break; - case 'a': - if (IsToken (var_name_begin, "addr-file-or-load}")) - { - print_file_addr_or_load_addr = true; - } - if (IsToken (var_name_begin, "addr}") - || IsToken (var_name_begin, "addr-file-or-load}")) - { - if (addr && addr->IsValid()) - { - var_success = true; - format_addr = *addr; - } - } - break; - - case 'p': - if (IsToken (var_name_begin, "process.")) - { - if (exe_ctx) - { - Process *process = exe_ctx->GetProcessPtr(); - if (process) - { - var_name_begin += ::strlen ("process."); - if (IsTokenWithFormat (var_name_begin, "id", token_format, "%" PRIu64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), process->GetID()); - var_success = true; - } - else if ((IsToken (var_name_begin, "name}")) || - (IsToken (var_name_begin, "file.basename}")) || - (IsToken (var_name_begin, "file.fullpath}"))) - { - Module *exe_module = process->GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - if (var_name_begin[0] == 'n' || var_name_begin[5] == 'f') - { - format_file_spec.GetFilename() = exe_module->GetFileSpec().GetFilename(); - var_success = (bool)format_file_spec; - } - else - { - format_file_spec = exe_module->GetFileSpec(); - var_success = (bool)format_file_spec; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, process, script_name)) - var_success = true; - } - } - } - } - break; - - case 't': - if (IsToken (var_name_begin, "thread.")) - { - if (exe_ctx) - { - Thread *thread = exe_ctx->GetThreadPtr(); - if (thread) - { - var_name_begin += ::strlen ("thread."); - if (IsTokenWithFormat (var_name_begin, "id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), thread->GetID()); - var_success = true; - } - else if (IsTokenWithFormat (var_name_begin, "protocol_id", token_format, "0x%4.4" PRIx64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), thread->GetProtocolID()); - var_success = true; - } - else if (IsTokenWithFormat (var_name_begin, "index", token_format, "%" PRIu64, exe_ctx, sc)) - { - s.Printf(token_format.c_str(), (uint64_t)thread->GetIndexID()); - var_success = true; - } - else if (IsToken (var_name_begin, "name}")) - { - cstr = thread->GetName(); - var_success = cstr && cstr[0]; - if (var_success) - s.PutCString(cstr); - } - else if (IsToken (var_name_begin, "queue}")) - { - cstr = thread->GetQueueName(); - var_success = cstr && cstr[0]; - if (var_success) - s.PutCString(cstr); - } - else if (IsToken (var_name_begin, "stop-reason}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - cstr = stop_info_sp->GetDescription(); - if (cstr && cstr[0]) - { - s.PutCString(cstr); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "return-value}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); - if (return_valobj_sp) - { - return_valobj_sp->Dump(s); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "completed-expression}")) - { - StopInfoSP stop_info_sp = thread->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp); - if (expression_var_sp && expression_var_sp->GetValueObject()) - { - expression_var_sp->GetValueObject()->Dump(s); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = thread->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name)) - var_success = true; - } - else if (IsToken (var_name_begin, "info.")) - { - var_name_begin += ::strlen("info."); - StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); - if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary) - { - var_success = FormatThreadExtendedInfoRecurse (var_name_begin, object_sp, sc, exe_ctx, s); - } - } - } - } - } - else if (IsToken (var_name_begin, "target.")) - { - // TODO: hookup properties -// if (!target_properties_sp) -// { -// Target *target = Target::GetTargetFromContexts (exe_ctx, sc); -// if (target) -// target_properties_sp = target->GetProperties(); -// } -// -// if (target_properties_sp) -// { -// var_name_begin += ::strlen ("target."); -// const char *end_property = strchr(var_name_begin, '}'); -// if (end_property) -// { -// ConstString property_name(var_name_begin, end_property - var_name_begin); -// std::string property_value (target_properties_sp->GetPropertyValue(property_name)); -// if (!property_value.empty()) -// { -// s.PutCString (property_value.c_str()); -// var_success = true; -// } -// } -// } - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - if (target) - { - var_name_begin += ::strlen ("target."); - if (IsToken (var_name_begin, "arch}")) - { - ArchSpec arch (target->GetArchitecture ()); - if (arch.IsValid()) - { - s.PutCString (arch.GetArchitectureName()); - var_success = true; - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, target, script_name)) - var_success = true; - } - } - } - break; - - case 'm': - if (IsToken (var_name_begin, "module.")) - { - if (sc && sc->module_sp.get()) - { - Module *module = sc->module_sp.get(); - var_name_begin += ::strlen ("module."); - - if (IsToken (var_name_begin, "file.")) - { - if (module->GetFileSpec()) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = module->GetFileSpec().GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = module->GetFileSpec(); - var_success = (bool)format_file_spec; - } - } - } - } - } - break; - - - case 'f': - if (IsToken (var_name_begin, "file.")) - { - if (sc && sc->comp_unit != NULL) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = sc->comp_unit->GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = *sc->comp_unit; - var_success = (bool)format_file_spec; - } - } - } - else if (IsToken (var_name_begin, "frame.")) - { - if (exe_ctx) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - if (frame) - { - var_name_begin += ::strlen ("frame."); - if (IsToken (var_name_begin, "index}")) - { - s.Printf("%u", frame->GetFrameIndex()); - var_success = true; - } - else if (IsToken (var_name_begin, "pc}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_PC; - var_success = true; - } - else if (IsToken (var_name_begin, "sp}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_SP; - var_success = true; - } - else if (IsToken (var_name_begin, "fp}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_FP; - var_success = true; - } - else if (IsToken (var_name_begin, "flags}")) - { - reg_kind = eRegisterKindGeneric; - reg_num = LLDB_REGNUM_GENERIC_FLAGS; - var_success = true; - } - else if (IsToken (var_name_begin, "reg.")) - { - reg_ctx = frame->GetRegisterContext().get(); - if (reg_ctx) - { - var_name_begin += ::strlen ("reg."); - if (var_name_begin < var_name_end) - { - std::string reg_name (var_name_begin, var_name_end); - reg_info = reg_ctx->GetRegisterInfoByName (reg_name.c_str()); - if (reg_info) - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "script:")) - { - var_name_begin += ::strlen("script:"); - std::string script_name(var_name_begin,var_name_end); - ScriptInterpreter* script_interpreter = frame->GetThread()->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (RunScriptFormatKeyword (s, script_interpreter, frame, script_name)) - var_success = true; - } - } - } - } - else if (IsToken (var_name_begin, "function.")) - { - if (sc && (sc->function != NULL || sc->symbol != NULL)) - { - var_name_begin += ::strlen ("function."); - if (IsToken (var_name_begin, "id}")) - { - if (sc->function) - s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); - else - s.Printf("symbol[%u]", sc->symbol->GetID()); - - var_success = true; - } - if (IsToken (var_name_begin, "changed}") && function_changed) - { - var_success = true; - } - if (IsToken (var_name_begin, "initial-function}") && initial_function) - { - var_success = true; - } - else if (IsToken (var_name_begin, "name}")) - { - if (sc->function) - cstr = sc->function->GetName().AsCString (NULL); - else if (sc->symbol) - cstr = sc->symbol->GetName().AsCString (NULL); - if (cstr) - { - s.PutCString(cstr); - - if (sc->block) - { - Block *inline_block = sc->block->GetContainingInlinedBlock (); - if (inline_block) - { - const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo(); - if (inline_info) - { - s.PutCString(" [inlined] "); - inline_info->GetName().Dump(&s); - } - } - } - var_success = true; - } - } - else if (IsToken (var_name_begin, "name-without-args}")) - { - ConstString name; - if (sc->function) - name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); - else if (sc->symbol) - name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); - if (name) - { - s.PutCString(name.GetCString()); - var_success = true; - } - } - else if (IsToken (var_name_begin, "name-with-args}")) - { - // Print the function name with arguments in it - - if (sc->function) - { - var_success = true; - ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; - cstr = sc->function->GetName().AsCString (NULL); - if (cstr) - { - const InlineFunctionInfo *inline_info = NULL; - VariableListSP variable_list_sp; - bool get_function_vars = true; - if (sc->block) - { - Block *inline_block = sc->block->GetContainingInlinedBlock (); - - if (inline_block) - { - get_function_vars = false; - inline_info = sc->block->GetInlinedFunctionInfo(); - if (inline_info) - variable_list_sp = inline_block->GetBlockVariableList (true); - } - } - - if (get_function_vars) - { - variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true); - } - - if (inline_info) - { - s.PutCString (cstr); - s.PutCString (" [inlined] "); - cstr = inline_info->GetName().GetCString(); - } - - VariableList args; - if (variable_list_sp) - variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args); - if (args.GetSize() > 0) - { - const char *open_paren = strchr (cstr, '('); - const char *close_paren = nullptr; - const char *generic = strchr(cstr, '<'); - // if before the arguments list begins there is a template sign - // then scan to the end of the generic args before you try to find - // the arguments list - if (generic && open_paren && generic < open_paren) - { - int generic_depth = 1; - ++generic; - for (; - *generic && generic_depth > 0; - generic++) - { - if (*generic == '<') - generic_depth++; - if (*generic == '>') - generic_depth--; - } - if (*generic) - open_paren = strchr(generic, '('); - else - open_paren = nullptr; - } - if (open_paren) - { - if (IsToken (open_paren, "(anonymous namespace)")) - { - open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '('); - if (open_paren) - close_paren = strchr (open_paren, ')'); - } - else - close_paren = strchr (open_paren, ')'); - } - - if (open_paren) - s.Write(cstr, open_paren - cstr + 1); - else - { - s.PutCString (cstr); - s.PutChar ('('); - } - const size_t num_args = args.GetSize(); - for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) - { - std::string buffer; - - VariableSP var_sp (args.GetVariableAtIndex (arg_idx)); - ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp)); - const char *var_representation = nullptr; - const char *var_name = var_value_sp->GetName().GetCString(); - if (var_value_sp->GetClangType().IsAggregateType() && - DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) - { - static StringSummaryFormat format(TypeSummaryImpl::Flags() - .SetHideItemNames(false) - .SetShowMembersOneLiner(true), - ""); - format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); - var_representation = buffer.c_str(); - } - else - var_representation = var_value_sp->GetValueAsCString(); - if (arg_idx > 0) - s.PutCString (", "); - if (var_value_sp->GetError().Success()) - { - if (var_representation) - s.Printf ("%s=%s", var_name, var_representation); - else - s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString()); - } - else - s.Printf ("%s=<unavailable>", var_name); - } - - if (close_paren) - s.PutCString (close_paren); - else - s.PutChar(')'); - - } - else - { - s.PutCString(cstr); - } - } - } - else if (sc->symbol) - { - cstr = sc->symbol->GetName().AsCString (NULL); - if (cstr) - { - s.PutCString(cstr); - var_success = true; - } - } - } - else if (IsToken (var_name_begin, "addr-offset}") - || IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) - { - if (IsToken (var_name_begin, "concrete-only-addr-offset-no-padding}")) - { - addr_offset_print_with_no_padding = true; - addr_offset_concrete_func_only = true; - } - var_success = addr != NULL; - if (var_success) - { - format_addr = *addr; - calculate_format_addr_function_offset = true; - } - } - else if (IsToken (var_name_begin, "line-offset}")) - { - var_success = sc->line_entry.range.GetBaseAddress().IsValid(); - if (var_success) - { - format_addr = sc->line_entry.range.GetBaseAddress(); - calculate_format_addr_function_offset = true; - } - } - else if (IsToken (var_name_begin, "pc-offset}")) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - var_success = frame != NULL; - if (var_success) - { - format_addr = frame->GetFrameCodeAddress(); - calculate_format_addr_function_offset = true; - } - } - } - } - break; - - case 'l': - if (IsToken (var_name_begin, "line.")) - { - if (sc && sc->line_entry.IsValid()) - { - var_name_begin += ::strlen ("line."); - if (IsToken (var_name_begin, "file.")) - { - var_name_begin += ::strlen ("file."); - - if (IsToken (var_name_begin, "basename}")) - { - format_file_spec.GetFilename() = sc->line_entry.file.GetFilename(); - var_success = (bool)format_file_spec; - } - else if (IsToken (var_name_begin, "fullpath}")) - { - format_file_spec = sc->line_entry.file; - var_success = (bool)format_file_spec; - } - } - else if (IsTokenWithFormat (var_name_begin, "number", token_format, "%" PRIu64, exe_ctx, sc)) - { - var_success = true; - s.Printf(token_format.c_str(), (uint64_t)sc->line_entry.line); - } - else if ((IsToken (var_name_begin, "start-addr}")) || - (IsToken (var_name_begin, "end-addr}"))) - { - var_success = sc && sc->line_entry.range.GetBaseAddress().IsValid(); - if (var_success) - { - format_addr = sc->line_entry.range.GetBaseAddress(); - if (var_name_begin[0] == 'e') - format_addr.Slide (sc->line_entry.range.GetByteSize()); - } - } - } - } - break; - case 'c': - if (IsToken (var_name_begin, "current-pc-arrow")) - { - if (addr && exe_ctx && exe_ctx->GetFramePtr()) - { - RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP(); - if (reg_ctx.get()) - { - addr_t pc_loadaddr = reg_ctx->GetPC(); - if (pc_loadaddr != LLDB_INVALID_ADDRESS) - { - Address pc; - pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr()); - if (pc == *addr) - { - s.Printf ("-> "); - var_success = true; - } - } - } - if (var_success == false) - { - s.Printf(" "); - var_success = true; - } - } - var_success = true; - } - break; - } - - if (var_success) - { - // If format addr is valid, then we need to print an address - if (reg_num != LLDB_INVALID_REGNUM) - { - StackFrame *frame = exe_ctx->GetFramePtr(); - // We have a register value to display... - if (reg_num == LLDB_REGNUM_GENERIC_PC && reg_kind == eRegisterKindGeneric) - { - format_addr = frame->GetFrameCodeAddress(); - } - else - { - if (reg_ctx == NULL) - reg_ctx = frame->GetRegisterContext().get(); - - if (reg_ctx) - { - if (reg_kind != kNumRegisterKinds) - reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); - reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num); - var_success = reg_info != NULL; - } - } - } - - if (reg_info != NULL) - { - RegisterValue reg_value; - var_success = reg_ctx->ReadRegister (reg_info, reg_value); - if (var_success) - { - reg_value.Dump(&s, reg_info, false, false, eFormatDefault); - } - } - - if (format_file_spec) - { - s << format_file_spec; - } - - // If format addr is valid, then we need to print an address - if (format_addr.IsValid()) - { - var_success = false; - - if (calculate_format_addr_function_offset) - { - Address func_addr; - - if (sc) - { - if (sc->function) - { - func_addr = sc->function->GetAddressRange().GetBaseAddress(); - if (sc->block && addr_offset_concrete_func_only == false) - { - // Check to make sure we aren't in an inline - // function. If we are, use the inline block - // range that contains "format_addr" since - // blocks can be discontiguous. - Block *inline_block = sc->block->GetContainingInlinedBlock (); - AddressRange inline_range; - if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range)) - func_addr = inline_range.GetBaseAddress(); - } - } - else if (sc->symbol && sc->symbol->ValueIsAddress()) - func_addr = sc->symbol->GetAddress(); - } - - if (func_addr.IsValid()) - { - const char *addr_offset_padding = " "; - if (addr_offset_print_with_no_padding) - { - addr_offset_padding = ""; - } - if (func_addr.GetSection() == format_addr.GetSection()) - { - addr_t func_file_addr = func_addr.GetFileAddress(); - addr_t addr_file_addr = format_addr.GetFileAddress(); - if (addr_file_addr > func_file_addr) - s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr); - else if (addr_file_addr < func_file_addr) - s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr); - var_success = true; - } - else - { - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - if (target) - { - addr_t func_load_addr = func_addr.GetLoadAddress (target); - addr_t addr_load_addr = format_addr.GetLoadAddress (target); - if (addr_load_addr > func_load_addr) - s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr); - else if (addr_load_addr < func_load_addr) - s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr); - var_success = true; - } - } - } - } - else - { - Target *target = Target::GetTargetFromContexts (exe_ctx, sc); - addr_t vaddr = LLDB_INVALID_ADDRESS; - if (exe_ctx && !target->GetSectionLoadList().IsEmpty()) - vaddr = format_addr.GetLoadAddress (target); - if (vaddr == LLDB_INVALID_ADDRESS) - vaddr = format_addr.GetFileAddress (); - - if (vaddr != LLDB_INVALID_ADDRESS) - { - int addr_width = 0; - if (exe_ctx && target) - { - addr_width = target->GetArchitecture().GetAddressByteSize() * 2; - } - if (addr_width == 0) - addr_width = 16; - if (print_file_addr_or_load_addr) - { - format_addr.Dump (&s, exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0); - } - else - { - s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr); - } - var_success = true; - } - } - } - } - - if (var_success == false) - success = false; - } - p = var_name_end; - } - else - break; - } - else - { - // We got a dollar sign with no '{' after it, it must just be a dollar sign - s.PutChar(*p); - } - } - else if (*p == '\\') - { - ++p; // skip the slash - switch (*p) - { - case 'a': s.PutChar ('\a'); break; - case 'b': s.PutChar ('\b'); break; - case 'f': s.PutChar ('\f'); break; - case 'n': s.PutChar ('\n'); break; - case 'r': s.PutChar ('\r'); break; - case 't': s.PutChar ('\t'); break; - case 'v': s.PutChar ('\v'); break; - case '\'': s.PutChar ('\''); break; - case '\\': s.PutChar ('\\'); break; - case '0': - // 1 to 3 octal chars - { - // Make a string that can hold onto the initial zero char, - // up to 3 octal digits, and a terminating NULL. - char oct_str[5] = { 0, 0, 0, 0, 0 }; - - int i; - for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i) - oct_str[i] = p[i]; - - // We don't want to consume the last octal character since - // the main for loop will do this for us, so we advance p by - // one less than i (even if i is zero) - p += i - 1; - unsigned long octal_value = ::strtoul (oct_str, NULL, 8); - if (octal_value <= UINT8_MAX) - { - s.PutChar((char)octal_value); - } - } - break; - - case 'x': - // hex number in the format - if (isxdigit(p[1])) - { - ++p; // Skip the 'x' - - // Make a string that can hold onto two hex chars plus a - // NULL terminator - char hex_str[3] = { 0,0,0 }; - hex_str[0] = *p; - if (isxdigit(p[1])) - { - ++p; // Skip the first of the two hex chars - hex_str[1] = *p; - } - - unsigned long hex_value = strtoul (hex_str, NULL, 16); - if (hex_value <= UINT8_MAX) - s.PutChar ((char)hex_value); - } - else - { - s.PutChar('x'); - } - break; - - default: - // Just desensitize any other character by just printing what - // came after the '\' - s << *p; - break; - - } - - } - } - if (end) - *end = p; - return success; -} - bool -Debugger::FormatPrompt -( - const char *format, - const SymbolContext *sc, - const ExecutionContext *exe_ctx, - const Address *addr, - Stream &s, - ValueObject* valobj -) -{ - bool use_color = exe_ctx ? exe_ctx->GetTargetRef().GetDebugger().GetUseColor() : true; - std::string format_str = lldb_utility::ansi::FormatAnsiTerminalCodes (format, use_color); - if (format_str.length()) - format = format_str.c_str(); - return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, valobj, false, false); -} - -bool -Debugger::FormatDisassemblerAddress (const char *format, +Debugger::FormatDisassemblerAddress (const FormatEntity::Entry *format, const SymbolContext *sc, const SymbolContext *prev_sc, const ExecutionContext *exe_ctx, const Address *addr, Stream &s) { - if (format == NULL && exe_ctx != NULL && exe_ctx->HasTargetScope()) + FormatEntity::Entry format_entry; + + if (format == NULL) { - format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); + if (exe_ctx != NULL && exe_ctx->HasTargetScope()) + format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); + if (format == NULL) + { + FormatEntity::Parse("${addr}: ", format_entry); + format = &format_entry; + } } bool function_changed = false; bool initial_function = false; @@ -2930,7 +1276,7 @@ Debugger::FormatDisassemblerAddress (const char *format, { initial_function = true; } - return FormatPromptRecurse (format, sc, exe_ctx, addr, s, NULL, NULL, function_changed, initial_function); + return FormatEntity::Format(*format, s, sc, exe_ctx, addr, NULL, function_changed, initial_function); } diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp index 649f0c5bcb26..14fbee149a52 100644 --- a/source/Core/Disassembler.cpp +++ b/source/Core/Disassembler.cpp @@ -471,12 +471,7 @@ Disassembler::PrintInstructions } const bool show_bytes = (options & eOptionShowBytes) != 0; - const char *disassembly_format = "${addr-file-or-load}: "; - if (exe_ctx.HasTargetScope()) - { - disassembly_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat (); - } - inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, disassembly_format); + inst->Dump (&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, NULL); strm.EOL(); } else @@ -566,7 +561,7 @@ Instruction::Dump (lldb_private::Stream *s, const ExecutionContext* exe_ctx, const SymbolContext *sym_ctx, const SymbolContext *prev_sym_ctx, - const char *disassembly_addr_format_spec) + const FormatEntity::Entry *disassembly_addr_format) { size_t opcode_column_width = 7; const size_t operand_column_width = 25; @@ -577,7 +572,7 @@ Instruction::Dump (lldb_private::Stream *s, if (show_address) { - Debugger::FormatDisassemblerAddress (disassembly_addr_format_spec, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss); + Debugger::FormatDisassemblerAddress (disassembly_addr_format, sym_ctx, prev_sym_ctx, exe_ctx, &m_address, ss); } if (show_bytes) @@ -985,18 +980,26 @@ InstructionList::Dump (Stream *s, { const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize(); collection::const_iterator pos, begin, end; - const char *disassemble_format = "${addr-file-or-load}: "; - if (exe_ctx) + + const FormatEntity::Entry *disassembly_format = NULL; + FormatEntity::Entry format; + if (exe_ctx && exe_ctx->HasTargetScope()) + { + disassembly_format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat (); + } + else { - disassemble_format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat (); + FormatEntity::Parse("${addr}: ", format); + disassembly_format = &format; } + for (begin = m_instructions.begin(), end = m_instructions.end(), pos = begin; pos != end; ++pos) { if (pos != begin) s->EOL(); - (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassemble_format); + (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx, NULL, NULL, disassembly_format); } } @@ -1169,6 +1172,24 @@ Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) : m_flavor.assign("default"); else m_flavor.assign(flavor); + + // If this is an arm variant that can only include thumb (T16, T32) + // instructions, force the arch triple to be "thumbv.." instead of + // "armv..." + if (arch.GetTriple().getArch() == llvm::Triple::arm + && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m + || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em + || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) + { + std::string thumb_arch_name (arch.GetTriple().getArchName().str()); + // Replace "arm" with "thumb" so we get all thumb variants correct + if (thumb_arch_name.size() > 3) + { + thumb_arch_name.erase(0, 3); + thumb_arch_name.insert(0, "thumb"); + } + m_arch.SetTriple (thumb_arch_name.c_str()); + } } //---------------------------------------------------------------------- diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp index 03cfd41b288d..5b0bbe273603 100644 --- a/source/Core/Error.cpp +++ b/source/Core/Error.cpp @@ -146,7 +146,7 @@ void Error::Clear () { m_code = 0; - m_type = eErrorTypeGeneric; + m_type = eErrorTypeInvalid; m_string.clear(); } diff --git a/source/Core/FormatEntity.cpp b/source/Core/FormatEntity.cpp new file mode 100644 index 000000000000..48b2c2ddbf72 --- /dev/null +++ b/source/Core/FormatEntity.cpp @@ -0,0 +1,2511 @@ +//===-- FormatEntity.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Core/FormatEntity.h" + +#include "lldb/Core/Address.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/LineEntry.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/AnsiTerminal.h" + +using namespace lldb; +using namespace lldb_private; + + +enum FileKind +{ + FileError = 0, + Basename, + Dirname, + Fullpath +}; + +#define ENTRY(n,t,f) { n, NULL, FormatEntity::Entry::Type::t, FormatEntity::Entry::FormatType::f, 0,0,NULL, false} +#define ENTRY_VALUE(n,t,f,v) { n, NULL, FormatEntity::Entry::Type::t, FormatEntity::Entry::FormatType::f, v,0,NULL, false} +#define ENTRY_CHILDREN(n,t,f,c) { n, NULL, FormatEntity::Entry::Type::t, FormatEntity::Entry::FormatType::f, 0,llvm::array_lengthof(c),c, false} +#define ENTRY_CHILDREN_KEEP_SEP(n,t,f,c) { n, NULL, FormatEntity::Entry::Type::t, FormatEntity::Entry::FormatType::f, 0,llvm::array_lengthof(c),c, true} +#define ENTRY_STRING(n,s) { n, s, FormatEntity::Entry::Type::InsertString, FormatEntity::Entry::FormatType::None, 0,0, NULL, false} +static FormatEntity::Entry::Definition g_string_entry[] = +{ + ENTRY("*", ParentString, None) +}; + +static FormatEntity::Entry::Definition g_addr_entries[] = +{ + ENTRY ("load", AddressLoad , UInt64), + ENTRY ("file", AddressFile , UInt64), + ENTRY ("load", AddressLoadOrFile, UInt64), +}; + +static FormatEntity::Entry::Definition g_file_child_entries[] = +{ + ENTRY_VALUE("basename", ParentNumber, CString, FileKind::Basename), + ENTRY_VALUE("dirname", ParentNumber, CString, FileKind::Dirname), + ENTRY_VALUE("fullpath", ParentNumber, CString, FileKind::Fullpath) +}; + +static FormatEntity::Entry::Definition g_frame_child_entries[] = +{ + + ENTRY ("index", FrameIndex , UInt32), + ENTRY ("pc" , FrameRegisterPC , UInt64), + ENTRY ("fp" , FrameRegisterFP , UInt64), + ENTRY ("sp" , FrameRegisterSP , UInt64), + ENTRY ("flags", FrameRegisterFlags, UInt64), + ENTRY_CHILDREN ("reg", FrameRegisterByName, UInt64, g_string_entry), +}; + +static FormatEntity::Entry::Definition g_function_child_entries[] = +{ + ENTRY ("id" , FunctionID , UInt64), + ENTRY ("name" , FunctionName , CString), + ENTRY ("name-without-args" , FunctionNameNoArgs , CString), + ENTRY ("name-with-args" , FunctionNameWithArgs , CString), + ENTRY ("addr-offset" , FunctionAddrOffset , UInt64), + ENTRY ("concrete-only-addr-offset-no-padding", FunctionAddrOffsetConcrete, UInt64), + ENTRY ("line-offset" , FunctionLineOffset , UInt64), + ENTRY ("pc-offset" , FunctionPCOffset , UInt64) +}; + +static FormatEntity::Entry::Definition g_line_child_entries[] = +{ + ENTRY_CHILDREN("file", LineEntryFile , None , g_file_child_entries), + ENTRY("number" , LineEntryLineNumber , UInt32), + ENTRY("start-addr" , LineEntryStartAddress, UInt64), + ENTRY("end-addr" , LineEntryEndAddress , UInt64), +}; + +static FormatEntity::Entry::Definition g_module_child_entries[] = +{ + ENTRY_CHILDREN("file", ModuleFile, None, g_file_child_entries), +}; + +static FormatEntity::Entry::Definition g_process_child_entries[] = +{ + ENTRY ( "id" , ProcessID , UInt64 ), + ENTRY_VALUE ( "name" , ProcessFile , CString , FileKind::Basename), + ENTRY_CHILDREN ( "file" , ProcessFile , None , g_file_child_entries), +}; + +static FormatEntity::Entry::Definition g_svar_child_entries[] = +{ + ENTRY ( "*" , ParentString , None) +}; + +static FormatEntity::Entry::Definition g_var_child_entries[] = +{ + ENTRY ( "*" , ParentString , None) +}; + +static FormatEntity::Entry::Definition g_thread_child_entries[] = +{ + ENTRY ( "id" , ThreadID , UInt64 ), + ENTRY ( "protocol_id" , ThreadProtocolID , UInt64 ), + ENTRY ( "index" , ThreadIndexID , UInt32 ), + ENTRY_CHILDREN ( "info" , ThreadInfo , None , g_string_entry), + ENTRY ( "queue" , ThreadQueue , CString ), + ENTRY ( "name" , ThreadName , CString ), + ENTRY ( "stop-reason" , ThreadStopReason , CString ), + ENTRY ( "return-value" , ThreadReturnValue , CString ), + ENTRY ( "completed-expression", ThreadCompletedExpression , CString ), +}; + +static FormatEntity::Entry::Definition g_target_child_entries[] = +{ + ENTRY ( "arch" , TargetArch , CString ), +}; + +#define _TO_STR2(_val) #_val +#define _TO_STR(_val) _TO_STR2(_val) + +static FormatEntity::Entry::Definition g_ansi_fg_entries[] = +{ + ENTRY_STRING ("black" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END), + ENTRY_STRING ("red" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END), + ENTRY_STRING ("green" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END), + ENTRY_STRING ("yellow" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END), + ENTRY_STRING ("blue" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END), + ENTRY_STRING ("purple" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END), + ENTRY_STRING ("cyan" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END), + ENTRY_STRING ("white" , ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END), +}; + +static FormatEntity::Entry::Definition g_ansi_bg_entries[] = +{ + ENTRY_STRING ("black" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END), + ENTRY_STRING ("red" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END), + ENTRY_STRING ("green" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END), + ENTRY_STRING ("yellow" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END), + ENTRY_STRING ("blue" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END), + ENTRY_STRING ("purple" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END), + ENTRY_STRING ("cyan" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END), + ENTRY_STRING ("white" , ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END), +}; + +static FormatEntity::Entry::Definition g_ansi_entries[] = +{ + ENTRY_CHILDREN ( "fg" , Invalid , None , g_ansi_fg_entries), + ENTRY_CHILDREN ( "bg" , Invalid , None , g_ansi_bg_entries), + ENTRY_STRING ( "normal" , ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END), + ENTRY_STRING ( "bold" , ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END), + ENTRY_STRING ( "faint" , ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END), + ENTRY_STRING ( "italic" , ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END), + ENTRY_STRING ( "underline" , ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END), + ENTRY_STRING ( "slow-blink" , ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END), + ENTRY_STRING ( "fast-blink" , ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END), + ENTRY_STRING ( "negative" , ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END), + ENTRY_STRING ( "conceal" , ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END), + ENTRY_STRING ( "crossed-out" , ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END), + +}; + +static FormatEntity::Entry::Definition g_script_child_entries[] = +{ + ENTRY ( "frame" , ScriptFrame , None), + ENTRY ( "process" , ScriptProcess , None), + ENTRY ( "target" , ScriptTarget , None), + ENTRY ( "thread" , ScriptThread , None), + ENTRY ( "var" , ScriptVariable , None), + ENTRY ( "svar" , ScriptVariableSynthetic , None), + ENTRY ( "thread" , ScriptThread , None), +}; + +static FormatEntity::Entry::Definition g_top_level_entries[] = +{ + ENTRY_CHILDREN ("addr" , AddressLoadOrFile , UInt64 , g_addr_entries), + ENTRY ("addr-file-or-load" , AddressLoadOrFile , UInt64 ), + ENTRY_CHILDREN ("ansi" , Invalid , None , g_ansi_entries), + ENTRY ("current-pc-arrow" , CurrentPCArrow , CString ), + ENTRY_CHILDREN ("file" , File , CString , g_file_child_entries), + ENTRY_CHILDREN ("frame" , Invalid , None , g_frame_child_entries), + ENTRY_CHILDREN ("function" , Invalid , None , g_function_child_entries), + ENTRY_CHILDREN ("line" , Invalid , None , g_line_child_entries), + ENTRY_CHILDREN ("module" , Invalid , None , g_module_child_entries), + ENTRY_CHILDREN ("process" , Invalid , None , g_process_child_entries), + ENTRY_CHILDREN ("script" , Invalid , None , g_script_child_entries), + ENTRY_CHILDREN_KEEP_SEP ("svar" , VariableSynthetic , None , g_svar_child_entries), + ENTRY_CHILDREN ("thread" , Invalid , None , g_thread_child_entries), + ENTRY_CHILDREN ("target" , Invalid , None , g_target_child_entries), + ENTRY_CHILDREN_KEEP_SEP ("var" , Variable , None , g_var_child_entries), +}; + +static FormatEntity::Entry::Definition g_root = ENTRY_CHILDREN ("<root>", Root, None, g_top_level_entries); + + +FormatEntity::Entry::Entry (llvm::StringRef s) : + string (s.data(), s.size()), + printf_format (), + children (), + definition (NULL), + type (Type::String), + fmt (lldb::eFormatDefault), + number (0), + deref (false) +{ +} + +FormatEntity::Entry::Entry (char ch) : + string (1, ch), + printf_format (), + children (), + definition (NULL), + type (Type::String), + fmt (lldb::eFormatDefault), + number (0), + deref (false) +{ +} + +void +FormatEntity::Entry::AppendChar (char ch) +{ + if (children.empty() || children.back().type != Entry::Type::String) + children.push_back(Entry(ch)); + else + children.back().string.append(1, ch); +} + +void +FormatEntity::Entry::AppendText (const llvm::StringRef &s) +{ + if (children.empty() || children.back().type != Entry::Type::String) + children.push_back(Entry(s)); + else + children.back().string.append(s.data(), s.size()); +} + +void +FormatEntity::Entry::AppendText (const char *cstr) +{ + return AppendText (llvm::StringRef(cstr)); +} + + +Error +FormatEntity::Parse (const llvm::StringRef &format_str, Entry &entry) +{ + entry.Clear(); + entry.type = Entry::Type::Root; + llvm::StringRef modifiable_format (format_str); + return ParseInternal (modifiable_format, entry, 0); +} + +#define ENUM_TO_CSTR(eee) case FormatEntity::Entry::Type::eee: return #eee + +const char * +FormatEntity::Entry::TypeToCString (Type t) +{ + switch (t) + { + ENUM_TO_CSTR(Invalid); + ENUM_TO_CSTR(ParentNumber); + ENUM_TO_CSTR(ParentString); + ENUM_TO_CSTR(InsertString); + ENUM_TO_CSTR(Root); + ENUM_TO_CSTR(String); + ENUM_TO_CSTR(Scope); + ENUM_TO_CSTR(Variable); + ENUM_TO_CSTR(VariableSynthetic); + ENUM_TO_CSTR(ScriptVariable); + ENUM_TO_CSTR(ScriptVariableSynthetic); + ENUM_TO_CSTR(AddressLoad); + ENUM_TO_CSTR(AddressFile); + ENUM_TO_CSTR(AddressLoadOrFile); + ENUM_TO_CSTR(ProcessID); + ENUM_TO_CSTR(ProcessFile); + ENUM_TO_CSTR(ScriptProcess); + ENUM_TO_CSTR(ThreadID); + ENUM_TO_CSTR(ThreadProtocolID); + ENUM_TO_CSTR(ThreadIndexID); + ENUM_TO_CSTR(ThreadName); + ENUM_TO_CSTR(ThreadQueue); + ENUM_TO_CSTR(ThreadStopReason); + ENUM_TO_CSTR(ThreadReturnValue); + ENUM_TO_CSTR(ThreadCompletedExpression); + ENUM_TO_CSTR(ScriptThread); + ENUM_TO_CSTR(ThreadInfo); + ENUM_TO_CSTR(TargetArch); + ENUM_TO_CSTR(ScriptTarget); + ENUM_TO_CSTR(ModuleFile); + ENUM_TO_CSTR(File); + ENUM_TO_CSTR(FrameIndex); + ENUM_TO_CSTR(FrameRegisterPC); + ENUM_TO_CSTR(FrameRegisterSP); + ENUM_TO_CSTR(FrameRegisterFP); + ENUM_TO_CSTR(FrameRegisterFlags); + ENUM_TO_CSTR(FrameRegisterByName); + ENUM_TO_CSTR(ScriptFrame); + ENUM_TO_CSTR(FunctionID); + ENUM_TO_CSTR(FunctionDidChange); + ENUM_TO_CSTR(FunctionInitialFunction); + ENUM_TO_CSTR(FunctionName); + ENUM_TO_CSTR(FunctionNameWithArgs); + ENUM_TO_CSTR(FunctionNameNoArgs); + ENUM_TO_CSTR(FunctionAddrOffset); + ENUM_TO_CSTR(FunctionAddrOffsetConcrete); + ENUM_TO_CSTR(FunctionLineOffset); + ENUM_TO_CSTR(FunctionPCOffset); + ENUM_TO_CSTR(LineEntryFile); + ENUM_TO_CSTR(LineEntryLineNumber); + ENUM_TO_CSTR(LineEntryStartAddress); + ENUM_TO_CSTR(LineEntryEndAddress); + ENUM_TO_CSTR(CurrentPCArrow); + } + return "???"; +} + +#undef ENUM_TO_CSTR + +void +FormatEntity::Entry::Dump (Stream &s, int depth) const +{ + s.Printf ("%*.*s%-20s: ", depth * 2, depth * 2, "", TypeToCString(type)); + if (fmt != eFormatDefault) + s.Printf ("lldb-format = %s, ", FormatManager::GetFormatAsCString (fmt)); + if (!string.empty()) + s.Printf ("string = \"%s\"", string.c_str()); + if (!printf_format.empty()) + s.Printf ("printf_format = \"%s\"", printf_format.c_str()); + if (number != 0) + s.Printf ("number = %" PRIu64 " (0x%" PRIx64 "), ", number, number); + if (deref) + s.Printf ("deref = true, "); + s.EOL(); + for (const auto &child : children) + { + child.Dump(s, depth + 1); + } +} + + +template <typename T> +static bool RunScriptFormatKeyword(Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + T t, + const char *script_function_name) +{ + Target *target = Target::GetTargetFromContexts (exe_ctx, sc); + + if (target) + { + ScriptInterpreter *script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + if (script_interpreter) + { + Error error; + std::string script_output; + + if (script_interpreter->RunScriptFormatKeyword(script_function_name, t, script_output, error) && error.Success()) + { + s.Printf("%s", script_output.c_str()); + return true; + } + else + { + s.Printf("<error: %s>",error.AsCString()); + } + } + } + return false; +} + +static bool +DumpAddress (Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address &addr, + bool print_file_addr_or_load_addr) +{ + Target *target = Target::GetTargetFromContexts (exe_ctx, sc); + addr_t vaddr = LLDB_INVALID_ADDRESS; + if (exe_ctx && !target->GetSectionLoadList().IsEmpty()) + vaddr = addr.GetLoadAddress (target); + if (vaddr == LLDB_INVALID_ADDRESS) + vaddr = addr.GetFileAddress (); + + if (vaddr != LLDB_INVALID_ADDRESS) + { + int addr_width = 0; + if (exe_ctx && target) + { + addr_width = target->GetArchitecture().GetAddressByteSize() * 2; + } + if (addr_width == 0) + addr_width = 16; + if (print_file_addr_or_load_addr) + { + ExecutionContextScope *exe_scope = NULL; + if (exe_ctx) + exe_scope = exe_ctx->GetBestExecutionContextScope(); + addr.Dump (&s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, 0); + } + else + { + s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr); + } + return true; + } + return false; +} + +static bool +DumpAddressOffsetFromFunction (Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address &format_addr, + bool concrete_only, + bool no_padding) +{ + if (format_addr.IsValid()) + { + Address func_addr; + + if (sc) + { + if (sc->function) + { + func_addr = sc->function->GetAddressRange().GetBaseAddress(); + if (sc->block && !concrete_only) + { + // Check to make sure we aren't in an inline + // function. If we are, use the inline block + // range that contains "format_addr" since + // blocks can be discontiguous. + Block *inline_block = sc->block->GetContainingInlinedBlock (); + AddressRange inline_range; + if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range)) + func_addr = inline_range.GetBaseAddress(); + } + } + else if (sc->symbol && sc->symbol->ValueIsAddress()) + func_addr = sc->symbol->GetAddress(); + } + + if (func_addr.IsValid()) + { + const char *addr_offset_padding = no_padding ? "" : " "; + + if (func_addr.GetSection() == format_addr.GetSection()) + { + addr_t func_file_addr = func_addr.GetFileAddress(); + addr_t addr_file_addr = format_addr.GetFileAddress(); + if (addr_file_addr > func_file_addr) + s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_file_addr - func_file_addr); + else if (addr_file_addr < func_file_addr) + s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_file_addr - addr_file_addr); + return true; + } + else + { + Target *target = Target::GetTargetFromContexts (exe_ctx, sc); + if (target) + { + addr_t func_load_addr = func_addr.GetLoadAddress (target); + addr_t addr_load_addr = format_addr.GetLoadAddress (target); + if (addr_load_addr > func_load_addr) + s.Printf("%s+%s%" PRIu64, addr_offset_padding, addr_offset_padding, addr_load_addr - func_load_addr); + else if (addr_load_addr < func_load_addr) + s.Printf("%s-%s%" PRIu64, addr_offset_padding, addr_offset_padding, func_load_addr - addr_load_addr); + return true; + } + } + } + } + return false; +} + +static bool +ScanBracketedRange (llvm::StringRef subpath, + size_t& close_bracket_index, + const char*& var_name_final_if_array_range, + int64_t& index_lower, + int64_t& index_higher) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + close_bracket_index = llvm::StringRef::npos; + const size_t open_bracket_index = subpath.find('['); + if (open_bracket_index == llvm::StringRef::npos) + { + if (log) + log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely"); + return false; + } + + close_bracket_index = subpath.find(']', open_bracket_index + 1); + + if (close_bracket_index == llvm::StringRef::npos) + { + if (log) + log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely"); + return false; + } + else + { + var_name_final_if_array_range = subpath.data() + open_bracket_index; + + if (close_bracket_index - open_bracket_index == 1) + { + if (log) + log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data"); + index_lower = 0; + } + else + { + const size_t separator_index = subpath.find('-', open_bracket_index + 1); + + if (separator_index == llvm::StringRef::npos) + { + const char *index_lower_cstr = subpath.data() + open_bracket_index + 1; + index_lower = ::strtoul (index_lower_cstr, NULL, 0); + index_higher = index_lower; + if (log) + log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", index_lower); + } + else + { + const char *index_lower_cstr = subpath.data() + open_bracket_index + 1; + const char *index_higher_cstr = subpath.data() + separator_index + 1; + index_lower = ::strtoul (index_lower_cstr, NULL, 0); + index_higher = ::strtoul (index_higher_cstr, NULL, 0); + if (log) + log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", index_lower, index_higher); + } + if (index_lower > index_higher && index_higher > 0) + { + if (log) + log->Printf("[ScanBracketedRange] swapping indices"); + const int64_t temp = index_lower; + index_lower = index_higher; + index_higher = temp; + } + } + } + return true; +} + +static bool +DumpFile (Stream &s, const FileSpec &file, FileKind file_kind) +{ + switch (file_kind) + { + case FileKind::FileError: + break; + + case FileKind::Basename: + if (file.GetFilename()) + { + s << file.GetFilename(); + return true; + } + break; + + case FileKind::Dirname: + if (file.GetDirectory()) + { + s << file.GetDirectory(); + return true; + } + break; + + case FileKind::Fullpath: + if (file) + { + s << file; + return true; + } + break; + } + return false; +} + +static bool +DumpRegister (Stream &s, + StackFrame *frame, + RegisterKind reg_kind, + uint32_t reg_num, + Format format) + +{ + if (frame) + { + RegisterContext *reg_ctx = frame->GetRegisterContext().get(); + + if (reg_ctx) + { + const uint32_t lldb_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); + if (lldb_reg_num != LLDB_INVALID_REGNUM) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (lldb_reg_num); + if (reg_info) + { + RegisterValue reg_value; + if (reg_ctx->ReadRegister (reg_info, reg_value)) + { + reg_value.Dump(&s, reg_info, false, false, format); + return true; + } + } + } + } + } + return false; +} + + +static ValueObjectSP +ExpandIndexedExpression (ValueObject* valobj, + size_t index, + StackFrame* frame, + bool deref_pointer) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + const char* ptr_deref_format = "[%d]"; + std::string ptr_deref_buffer(10,0); + ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index); + if (log) + log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str()); + const char* first_unparsed; + ValueObject::GetValueForExpressionPathOptions options; + ValueObject::ExpressionPathEndResultType final_value_type; + ValueObject::ExpressionPathScanEndReason reason_to_stop; + ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); + ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(), + &first_unparsed, + &reason_to_stop, + &final_value_type, + options, + &what_next); + if (!item) + { + if (log) + log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d," + " final_value_type %d", + first_unparsed, reason_to_stop, final_value_type); + } + else + { + if (log) + log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d," + " final_value_type %d", + first_unparsed, reason_to_stop, final_value_type); + } + return item; +} + +static char +ConvertValueObjectStyleToChar(ValueObject::ValueObjectRepresentationStyle style) +{ + switch (style) + { + case ValueObject::eValueObjectRepresentationStyleLanguageSpecific: return '@'; + case ValueObject::eValueObjectRepresentationStyleValue: return 'V'; + case ValueObject::eValueObjectRepresentationStyleLocation: return 'L'; + case ValueObject::eValueObjectRepresentationStyleSummary: return 'S'; + case ValueObject::eValueObjectRepresentationStyleChildrenCount: return '#'; + case ValueObject::eValueObjectRepresentationStyleType: return 'T'; + case ValueObject::eValueObjectRepresentationStyleName: return 'N'; + case ValueObject::eValueObjectRepresentationStyleExpressionPath: return '>'; + } + return '\0'; +} + +static bool +DumpValue (Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const FormatEntity::Entry &entry, + ValueObject *valobj) +{ + if (valobj == NULL) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); + Format custom_format = eFormatInvalid; + ValueObject::ValueObjectRepresentationStyle val_obj_display = entry.string.empty() ? ValueObject::eValueObjectRepresentationStyleValue : ValueObject::eValueObjectRepresentationStyleSummary; + + bool do_deref_pointer = entry.deref; + bool is_script = false; + switch (entry.type) + { + case FormatEntity::Entry::Type::ScriptVariable: + is_script = true; + break; + + case FormatEntity::Entry::Type::Variable: + custom_format = entry.fmt; + val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; + break; + + case FormatEntity::Entry::Type::ScriptVariableSynthetic: + is_script = true; + // Fall through + case FormatEntity::Entry::Type::VariableSynthetic: + custom_format = entry.fmt; + val_obj_display = (ValueObject::ValueObjectRepresentationStyle)entry.number; + if (!valobj->IsSynthetic()) + { + valobj = valobj->GetSyntheticValue().get(); + if (valobj == nullptr) + return false; + } + break; + + default: + return false; + } + + if (valobj == NULL) + return false; + + ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? + ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing); + ValueObject::GetValueForExpressionPathOptions options; + options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren(); + ValueObject* target = NULL; + const char* var_name_final_if_array_range = NULL; + size_t close_bracket_index = llvm::StringRef::npos; + int64_t index_lower = -1; + int64_t index_higher = -1; + bool is_array_range = false; + const char* first_unparsed; + bool was_plain_var = false; + bool was_var_format = false; + bool was_var_indexed = false; + ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; + ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain; + + if (is_script) + { + return RunScriptFormatKeyword (s, sc, exe_ctx, valobj, entry.string.c_str()); + } + + llvm::StringRef subpath (entry.string); + // simplest case ${var}, just print valobj's value + if (entry.string.empty()) + { + if (entry.printf_format.empty() && entry.fmt == eFormatDefault && entry.number == ValueObject::eValueObjectRepresentationStyleValue) + was_plain_var = true; + else + was_var_format = true; + target = valobj; + } + else // this is ${var.something} or multiple .something nested + { + if (entry.string[0] == '[') + was_var_indexed = true; + ScanBracketedRange (subpath, + close_bracket_index, + var_name_final_if_array_range, + index_lower, + index_higher); + + Error error; + + const std::string &expr_path = entry.string; + + if (log) + log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str()); + + target = valobj->GetValueForExpressionPath(expr_path.c_str(), + &first_unparsed, + &reason_to_stop, + &final_value_type, + options, + &what_next).get(); + + if (!target) + { + if (log) + log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d," + " final_value_type %d", + first_unparsed, reason_to_stop, final_value_type); + return false; + } + else + { + if (log) + log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d," + " final_value_type %d", + first_unparsed, reason_to_stop, final_value_type); + target = target->GetQualifiedRepresentationIfAvailable(target->GetDynamicValueType(), true).get(); + } + } + + + is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange || + final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange); + + do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference); + + if (do_deref_pointer && !is_array_range) + { + // I have not deref-ed yet, let's do it + // this happens when we are not going through GetValueForVariableExpressionPath + // to get to the target ValueObject + Error error; + target = target->Dereference(error).get(); + if (error.Fail()) + { + if (log) + log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \ + return false; + } + do_deref_pointer = false; + } + + if (!target) + { + if (log) + log->Printf("[Debugger::FormatPrompt] could not calculate target for prompt expression"); + return false; + } + + // we do not want to use the summary for a bitfield of type T:n + // if we were originally dealing with just a T - that would get + // us into an endless recursion + if (target->IsBitfield() && was_var_indexed) + { + // TODO: check for a (T:n)-specific summary - we should still obey that + StreamString bitfield_name; + bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize()); + lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false)); + if (val_obj_display == ValueObject::eValueObjectRepresentationStyleSummary && !DataVisualization::GetSummaryForType(type_sp)) + val_obj_display = ValueObject::eValueObjectRepresentationStyleValue; + } + + // TODO use flags for these + const uint32_t type_info_flags = target->GetClangType().GetTypeInfo(NULL); + bool is_array = (type_info_flags & eTypeIsArray) != 0; + bool is_pointer = (type_info_flags & eTypeIsPointer) != 0; + bool is_aggregate = target->GetClangType().IsAggregateType(); + + if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) // this should be wrong, but there are some exceptions + { + StreamString str_temp; + if (log) + log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range"); + + if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format)) + { + // try to use the special cases + bool success = target->DumpPrintableRepresentation(str_temp, + val_obj_display, + custom_format); + if (log) + log->Printf("[Debugger::FormatPrompt] special cases did%s match", success ? "" : "n't"); + + // should not happen + if (success) + s << str_temp.GetData(); + return true; + } + else + { + if (was_plain_var) // if ${var} + { + s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); + } + else if (is_pointer) // if pointer, value is the address stored + { + target->DumpPrintableRepresentation (s, + val_obj_display, + custom_format, + ValueObject::ePrintableRepresentationSpecialCasesDisable); + } + return true; + } + } + + // if directly trying to print ${var}, and this is an aggregate, display a nice + // type @ location message + if (is_aggregate && was_plain_var) + { + s << target->GetTypeName() << " @ " << target->GetLocationAsCString(); + return true; + } + + // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it + if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue))) + { + s << "<invalid use of aggregate type>"; + return true; + } + + if (!is_array_range) + { + if (log) + log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output"); + return target->DumpPrintableRepresentation(s,val_obj_display, custom_format); + } + else + { + if (log) + log->Printf("[Debugger::FormatPrompt] checking if I can handle as array"); + if (!is_array && !is_pointer) + return false; + if (log) + log->Printf("[Debugger::FormatPrompt] handle as array"); + llvm::StringRef special_directions; + if (close_bracket_index != llvm::StringRef::npos && subpath.size() > close_bracket_index) + { + ConstString additional_data (subpath.drop_front(close_bracket_index+1)); + StreamString special_directions_stream; + special_directions_stream.Printf("${%svar%s", + do_deref_pointer ? "*" : "", + additional_data.GetCString()); + + if (entry.fmt != eFormatDefault) + { + const char format_char = FormatManager::GetFormatAsFormatChar(entry.fmt); + if (format_char != '\0') + special_directions_stream.Printf("%%%c", format_char); + else + { + const char *format_cstr = FormatManager::GetFormatAsCString(entry.fmt); + special_directions_stream.Printf("%%%s", format_cstr); + } + } + else if (entry.number != 0) + { + const char style_char = ConvertValueObjectStyleToChar ((ValueObject::ValueObjectRepresentationStyle)entry.number); + if (style_char) + special_directions_stream.Printf("%%%c", style_char); + } + special_directions_stream.PutChar('}'); + special_directions = llvm::StringRef(special_directions_stream.GetString()); + } + + // let us display items index_lower thru index_higher of this array + s.PutChar('['); + + if (index_higher < 0) + index_higher = valobj->GetNumChildren() - 1; + + uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); + + bool success = true; + for (int64_t index = index_lower;index<=index_higher; ++index) + { + ValueObject* item = ExpandIndexedExpression (target, + index, + exe_ctx->GetFramePtr(), + false).get(); + + if (!item) + { + if (log) + log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index); + } + else + { + if (log) + log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions.data() ? special_directions.data() : ""); + } + + if (special_directions.empty()) + { + success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); + } + else + { + success &= FormatEntity::FormatStringRef(special_directions, s, sc, exe_ctx, NULL, item, false, false); + } + + if (--max_num_children == 0) + { + s.PutCString(", ..."); + break; + } + + if (index < index_higher) + s.PutChar(','); + } + s.PutChar(']'); + return success; + } + +} + +static bool +DumpRegister (Stream &s, + StackFrame *frame, + const char *reg_name, + Format format) + +{ + if (frame) + { + RegisterContext *reg_ctx = frame->GetRegisterContext().get(); + + if (reg_ctx) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); + if (reg_info) + { + RegisterValue reg_value; + if (reg_ctx->ReadRegister (reg_info, reg_value)) + { + reg_value.Dump(&s, reg_info, false, false, format); + return true; + } + } + } + } + return false; +} + +static bool +FormatThreadExtendedInfoRecurse(const FormatEntity::Entry &entry, + const StructuredData::ObjectSP &thread_info_dictionary, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + Stream &s) +{ + llvm::StringRef path(entry.string); + + StructuredData::ObjectSP value = thread_info_dictionary->GetObjectForDotSeparatedPath (path); + + if (value.get()) + { + if (value->GetType() == StructuredData::Type::eTypeInteger) + { + const char *token_format = "0x%4.4" PRIx64; + if (!entry.printf_format.empty()) + token_format = entry.printf_format.c_str(); + s.Printf(token_format, value->GetAsInteger()->GetValue()); + return true; + } + else if (value->GetType() == StructuredData::Type::eTypeFloat) + { + s.Printf ("%f", value->GetAsFloat()->GetValue()); + return true; + } + else if (value->GetType() == StructuredData::Type::eTypeString) + { + s.Printf("%s", value->GetAsString()->GetValue().c_str()); + return true; + } + else if (value->GetType() == StructuredData::Type::eTypeArray) + { + if (value->GetAsArray()->GetSize() > 0) + { + s.Printf ("%zu", value->GetAsArray()->GetSize()); + return true; + } + } + else if (value->GetType() == StructuredData::Type::eTypeDictionary) + { + s.Printf ("%zu", value->GetAsDictionary()->GetKeys()->GetAsArray()->GetSize()); + return true; + } + } + + return false; +} + + +static inline bool +IsToken(const char *var_name_begin, const char *var) +{ + return (::strncmp (var_name_begin, var, strlen(var)) == 0); +} + +bool +FormatEntity::FormatStringRef (const llvm::StringRef &format_str, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function) +{ + if (!format_str.empty()) + { + FormatEntity::Entry root; + Error error = FormatEntity::Parse(format_str, root); + if (error.Success()) + { + return FormatEntity::Format (root, + s, + sc, + exe_ctx, + addr, + valobj, + function_changed, + initial_function); + } + } + return false; + +} +bool +FormatEntity::FormatCString (const char *format, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function) +{ + if (format && format[0]) + { + FormatEntity::Entry root; + llvm::StringRef format_str(format); + Error error = FormatEntity::Parse(format_str, root); + if (error.Success()) + { + return FormatEntity::Format (root, + s, + sc, + exe_ctx, + addr, + valobj, + function_changed, + initial_function); + } + } + return false; +} + +bool +FormatEntity::Format (const Entry &entry, + Stream &s, + const SymbolContext *sc, + const ExecutionContext *exe_ctx, + const Address *addr, + ValueObject* valobj, + bool function_changed, + bool initial_function) +{ + switch (entry.type) + { + case Entry::Type::Invalid: + case Entry::Type::ParentNumber: // Only used for FormatEntity::Entry::Definition encoding + case Entry::Type::ParentString: // Only used for FormatEntity::Entry::Definition encoding + case Entry::Type::InsertString: // Only used for FormatEntity::Entry::Definition encoding + return false; + + case Entry::Type::Root: + for (const auto &child : entry.children) + { + if (Format (child, + s, + sc, + exe_ctx, + addr, + valobj, + function_changed, + initial_function) == false) + { + return false; // If any item of root fails, then the formatting fails + } + } + return true; // Only return true if all items succeeded + + case Entry::Type::String: + s.PutCString(entry.string.c_str()); + return true; + + case Entry::Type::Scope: + { + StreamString scope_stream; + bool success = false; + for (const auto &child : entry.children) + { + success = Format (child, scope_stream, sc, exe_ctx, addr, valobj, function_changed, initial_function); + if (!success) + break; + } + // Only if all items in a scope succeed, then do we + // print the output into the main stream + if (success) + s.Write(scope_stream.GetString().data(), scope_stream.GetString().size()); + } + return true; // Scopes always successfully print themselves + + case Entry::Type::Variable: + case Entry::Type::VariableSynthetic: + case Entry::Type::ScriptVariable: + case Entry::Type::ScriptVariableSynthetic: + if (DumpValue(s, sc, exe_ctx, entry, valobj)) + return true; + return false; + + case Entry::Type::AddressFile: + case Entry::Type::AddressLoad: + case Entry::Type::AddressLoadOrFile: + if (addr && addr->IsValid() && DumpAddress(s, sc, exe_ctx, *addr, entry.type == Entry::Type::AddressLoadOrFile)) + return true; + return false; + + case Entry::Type::ProcessID: + if (exe_ctx) + { + Process *process = exe_ctx->GetProcessPtr(); + if (process) + { + const char *format = "%" PRIu64; + if (!entry.printf_format.empty()) + format = entry.printf_format.c_str(); + s.Printf(format, process->GetID()); + return true; + } + } + return false; + + case Entry::Type::ProcessFile: + if (exe_ctx) + { + Process *process = exe_ctx->GetProcessPtr(); + if (process) + { + Module *exe_module = process->GetTarget().GetExecutableModulePointer(); + if (exe_module) + { + if (DumpFile(s, exe_module->GetFileSpec(), (FileKind)entry.number)) + return true; + } + } + } + return false; + + case Entry::Type::ScriptProcess: + if (exe_ctx) + { + Process *process = exe_ctx->GetProcessPtr(); + if (process) + return RunScriptFormatKeyword (s, sc, exe_ctx, process, entry.string.c_str()); + } + return false; + + + case Entry::Type::ThreadID: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + const char *format = "0x%4.4" PRIx64; + if (!entry.printf_format.empty()) + { + // Watch for the special "tid" format... + if (entry.printf_format == "tid") + { + bool handled = false; + Target &target = thread->GetProcess()->GetTarget(); + ArchSpec arch (target.GetArchitecture ()); + llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS; + if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux)) + { + handled = true; + format = "%" PRIu64; + } + } + else + { + format = entry.printf_format.c_str(); + } + } + s.Printf(format, thread->GetID()); + return true; + } + } + return false; + + case Entry::Type::ThreadProtocolID: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + const char *format = "0x%4.4" PRIx64; + if (!entry.printf_format.empty()) + format = entry.printf_format.c_str(); + s.Printf(format, thread->GetProtocolID()); + return true; + } + } + return false; + + case Entry::Type::ThreadIndexID: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + const char *format = "%" PRIu32; + if (!entry.printf_format.empty()) + format = entry.printf_format.c_str(); + s.Printf(format, thread->GetIndexID()); + return true; + } + } + return false; + + case Entry::Type::ThreadName: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + const char *cstr = thread->GetName(); + if (cstr && cstr[0]) + { + s.PutCString(cstr); + return true; + } + } + } + return false; + + case Entry::Type::ThreadQueue: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + const char *cstr = thread->GetQueueName(); + if (cstr && cstr[0]) + { + s.PutCString(cstr); + return true; + } + } + } + return false; + + case Entry::Type::ThreadStopReason: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + StopInfoSP stop_info_sp = thread->GetStopInfo (); + if (stop_info_sp && stop_info_sp->IsValid()) + { + const char *cstr = stop_info_sp->GetDescription(); + if (cstr && cstr[0]) + { + s.PutCString(cstr); + return true; + } + } + } + } + return false; + + case Entry::Type::ThreadReturnValue: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + StopInfoSP stop_info_sp = thread->GetStopInfo (); + if (stop_info_sp && stop_info_sp->IsValid()) + { + ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp); + if (return_valobj_sp) + { + return_valobj_sp->Dump(s); + return true; + } + } + } + } + return false; + + case Entry::Type::ThreadCompletedExpression: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + StopInfoSP stop_info_sp = thread->GetStopInfo (); + if (stop_info_sp && stop_info_sp->IsValid()) + { + ClangExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable (stop_info_sp); + if (expression_var_sp && expression_var_sp->GetValueObject()) + { + expression_var_sp->GetValueObject()->Dump(s); + return true; + } + } + } + } + return false; + + case Entry::Type::ScriptThread: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + return RunScriptFormatKeyword (s, sc, exe_ctx, thread, entry.string.c_str()); + } + return false; + + case Entry::Type::ThreadInfo: + if (exe_ctx) + { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) + { + StructuredData::ObjectSP object_sp = thread->GetExtendedInfo(); + if (object_sp && object_sp->GetType() == StructuredData::Type::eTypeDictionary) + { + if (FormatThreadExtendedInfoRecurse (entry, object_sp, sc, exe_ctx, s)) + return true; + } + } + } + return false; + + case Entry::Type::TargetArch: + if (exe_ctx) + { + Target *target = exe_ctx->GetTargetPtr(); + if (target) + { + const ArchSpec &arch = target->GetArchitecture (); + if (arch.IsValid()) + { + s.PutCString (arch.GetArchitectureName()); + return true; + } + } + } + return false; + + case Entry::Type::ScriptTarget: + if (exe_ctx) + { + Target *target = exe_ctx->GetTargetPtr(); + if (target) + return RunScriptFormatKeyword (s, sc, exe_ctx, target, entry.string.c_str()); + } + return false; + + case Entry::Type::ModuleFile: + if (sc) + { + Module *module = sc->module_sp.get(); + if (module) + { + if (DumpFile(s, module->GetFileSpec(), (FileKind)entry.number)) + return true; + } + } + return false; + + case Entry::Type::File: + if (sc) + { + CompileUnit *cu = sc->comp_unit; + if (cu) + { + // CompileUnit is a FileSpec + if (DumpFile(s, *cu, (FileKind)entry.number)) + return true; + } + } + return false; + + case Entry::Type::FrameIndex: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + const char *format = "%" PRIu32; + if (!entry.printf_format.empty()) + format = entry.printf_format.c_str(); + s.Printf(format, frame->GetFrameIndex()); + return true; + } + } + return false; + + case Entry::Type::FrameRegisterPC: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + const Address &pc_addr = frame->GetFrameCodeAddress(); + if (pc_addr.IsValid()) + { + if (DumpAddress(s, sc, exe_ctx, pc_addr, false)) + return true; + } + } + } + return false; + + case Entry::Type::FrameRegisterSP: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + if (DumpRegister (s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, (lldb::Format)entry.number)) + return true; + } + } + return false; + + case Entry::Type::FrameRegisterFP: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + if (DumpRegister (s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, (lldb::Format)entry.number)) + return true; + } + } + return false; + + case Entry::Type::FrameRegisterFlags: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + if (DumpRegister (s, frame, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, (lldb::Format)entry.number)) + return true; + } + } + return false; + + + case Entry::Type::FrameRegisterByName: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + if (DumpRegister (s, frame, entry.string.c_str(), (lldb::Format)entry.number)) + return true; + } + } + return false; + + case Entry::Type::ScriptFrame: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + return RunScriptFormatKeyword (s, sc, exe_ctx, frame, entry.string.c_str()); + } + return false; + + case Entry::Type::FunctionID: + if (sc) + { + if (sc->function) + { + s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID()); + return true; + } + else if (sc->symbol) + { + s.Printf("symbol[%u]", sc->symbol->GetID()); + return true; + } + } + return false; + + case Entry::Type::FunctionDidChange: + return function_changed; + + case Entry::Type::FunctionInitialFunction: + return initial_function; + + case Entry::Type::FunctionName: + { + const char *name = NULL; + if (sc->function) + name = sc->function->GetName().AsCString (NULL); + else if (sc->symbol) + name = sc->symbol->GetName().AsCString (NULL); + if (name) + { + s.PutCString(name); + + if (sc->block) + { + Block *inline_block = sc->block->GetContainingInlinedBlock (); + if (inline_block) + { + const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo(); + if (inline_info) + { + s.PutCString(" [inlined] "); + inline_info->GetName().Dump(&s); + } + } + } + return true; + } + } + return false; + + case Entry::Type::FunctionNameNoArgs: + { + ConstString name; + if (sc->function) + name = sc->function->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); + else if (sc->symbol) + name = sc->symbol->GetMangled().GetName (Mangled::ePreferDemangledWithoutArguments); + if (name) + { + s.PutCString(name.GetCString()); + return true; + } + } + return false; + + case Entry::Type::FunctionNameWithArgs: + { + // Print the function name with arguments in it + if (sc->function) + { + ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL; + const char *cstr = sc->function->GetName().AsCString (NULL); + if (cstr) + { + const InlineFunctionInfo *inline_info = NULL; + VariableListSP variable_list_sp; + bool get_function_vars = true; + if (sc->block) + { + Block *inline_block = sc->block->GetContainingInlinedBlock (); + + if (inline_block) + { + get_function_vars = false; + inline_info = sc->block->GetInlinedFunctionInfo(); + if (inline_info) + variable_list_sp = inline_block->GetBlockVariableList (true); + } + } + + if (get_function_vars) + { + variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true); + } + + if (inline_info) + { + s.PutCString (cstr); + s.PutCString (" [inlined] "); + cstr = inline_info->GetName().GetCString(); + } + + VariableList args; + if (variable_list_sp) + variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args); + if (args.GetSize() > 0) + { + const char *open_paren = strchr (cstr, '('); + const char *close_paren = nullptr; + const char *generic = strchr(cstr, '<'); + // if before the arguments list begins there is a template sign + // then scan to the end of the generic args before you try to find + // the arguments list + if (generic && open_paren && generic < open_paren) + { + int generic_depth = 1; + ++generic; + for (; + *generic && generic_depth > 0; + generic++) + { + if (*generic == '<') + generic_depth++; + if (*generic == '>') + generic_depth--; + } + if (*generic) + open_paren = strchr(generic, '('); + else + open_paren = nullptr; + } + if (open_paren) + { + if (IsToken (open_paren, "(anonymous namespace)")) + { + open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '('); + if (open_paren) + close_paren = strchr (open_paren, ')'); + } + else + close_paren = strchr (open_paren, ')'); + } + + if (open_paren) + s.Write(cstr, open_paren - cstr + 1); + else + { + s.PutCString (cstr); + s.PutChar ('('); + } + const size_t num_args = args.GetSize(); + for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx) + { + std::string buffer; + + VariableSP var_sp (args.GetVariableAtIndex (arg_idx)); + ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp)); + const char *var_representation = nullptr; + const char *var_name = var_value_sp->GetName().GetCString(); + if (var_value_sp->GetClangType().IsAggregateType() && + DataVisualization::ShouldPrintAsOneLiner(*var_value_sp.get())) + { + static StringSummaryFormat format(TypeSummaryImpl::Flags() + .SetHideItemNames(false) + .SetShowMembersOneLiner(true), + ""); + format.FormatObject(var_value_sp.get(), buffer, TypeSummaryOptions()); + var_representation = buffer.c_str(); + } + else + var_representation = var_value_sp->GetValueAsCString(); + if (arg_idx > 0) + s.PutCString (", "); + if (var_value_sp->GetError().Success()) + { + if (var_representation) + s.Printf ("%s=%s", var_name, var_representation); + else + s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString()); + } + else + s.Printf ("%s=<unavailable>", var_name); + } + + if (close_paren) + s.PutCString (close_paren); + else + s.PutChar(')'); + + } + else + { + s.PutCString(cstr); + } + return true; + } + } + else if (sc->symbol) + { + const char *cstr = sc->symbol->GetName().AsCString (NULL); + if (cstr) + { + s.PutCString(cstr); + return true; + } + } + } + return false; + + case Entry::Type::FunctionAddrOffset: + if (addr) + { + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, false, false)) + return true; + } + return false; + + case Entry::Type::FunctionAddrOffsetConcrete: + if (addr) + { + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, *addr, true, true)) + return true; + } + return false; + + case Entry::Type::FunctionLineOffset: + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, sc->line_entry.range.GetBaseAddress(), false, false)) + return true; + return false; + + case Entry::Type::FunctionPCOffset: + if (exe_ctx) + { + StackFrame *frame = exe_ctx->GetFramePtr(); + if (frame) + { + if (DumpAddressOffsetFromFunction (s, sc, exe_ctx, frame->GetFrameCodeAddress(), false, false)) + return true; + } + } + return false; + + case Entry::Type::LineEntryFile: + if (sc && sc->line_entry.IsValid()) + { + Module *module = sc->module_sp.get(); + if (module) + { + if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number)) + return true; + } + } + return false; + + case Entry::Type::LineEntryLineNumber: + if (sc && sc->line_entry.IsValid()) + { + const char *format = "%" PRIu32; + if (!entry.printf_format.empty()) + format = entry.printf_format.c_str(); + s.Printf(format, sc->line_entry.line); + return true; + } + return false; + + case Entry::Type::LineEntryStartAddress: + case Entry::Type::LineEntryEndAddress: + if (sc && sc->line_entry.range.GetBaseAddress().IsValid()) + { + Address addr = sc->line_entry.range.GetBaseAddress(); + + if (entry.type == Entry::Type::LineEntryEndAddress) + addr.Slide(sc->line_entry.range.GetByteSize()); + if (DumpAddress(s, sc, exe_ctx, addr, false)) + return true; + } + return false; + + case Entry::Type::CurrentPCArrow: + if (addr && exe_ctx && exe_ctx->GetFramePtr()) + { + RegisterContextSP reg_ctx = exe_ctx->GetFramePtr()->GetRegisterContextSP(); + if (reg_ctx.get()) + { + addr_t pc_loadaddr = reg_ctx->GetPC(); + if (pc_loadaddr != LLDB_INVALID_ADDRESS) + { + Address pc; + pc.SetLoadAddress (pc_loadaddr, exe_ctx->GetTargetPtr()); + if (pc == *addr) + { + s.Printf ("-> "); + return true; + } + } + } + s.Printf(" "); + return true; + } + return false; + } + return false; +} + +static bool +DumpCommaSeparatedChildEntryNames (Stream &s, const FormatEntity::Entry::Definition *parent) +{ + if (parent->children) + { + const size_t n = parent->num_children; + for (size_t i=0; i<n; ++i) + { + if (i > 0) + s.PutCString(", "); + s.Printf ("\"%s\"", parent->children[i].name); + } + return true; + } + return false; +} + + +static Error +ParseEntry (const llvm::StringRef &format_str, + const FormatEntity::Entry::Definition *parent, + FormatEntity::Entry &entry) +{ + Error error; + + const size_t sep_pos = format_str.find_first_of(".[:"); + const char sep_char = (sep_pos == llvm::StringRef::npos) ? '\0' : format_str[sep_pos]; + llvm::StringRef key = format_str.substr(0, sep_pos); + + const size_t n = parent->num_children; + for (size_t i=0; i<n; ++i) + { + const FormatEntity::Entry::Definition *entry_def = parent->children + i; + if (key.equals(entry_def->name) || entry_def->name[0] == '*') + { + llvm::StringRef value; + if (sep_char) + value = format_str.substr(sep_pos + (entry_def->keep_separator ? 0 : 1)); + switch (entry_def->type) + { + case FormatEntity::Entry::Type::ParentString: + entry.string = std::move(format_str.str()); + return error; // Success + + case FormatEntity::Entry::Type::ParentNumber: + entry.number = entry_def->data; + return error; // Success + + case FormatEntity::Entry::Type::InsertString: + entry.type = entry_def->type; + entry.string = entry_def->string; + return error; // Success + + default: + entry.type = entry_def->type; + break; + } + + if (value.empty()) + { + if (entry_def->type == FormatEntity::Entry::Type::Invalid) + { + if (entry_def->children) + { + StreamString error_strm; + error_strm.Printf("'%s' can't be specified on its own, you must access one of its children: ", entry_def->name); + DumpCommaSeparatedChildEntryNames (error_strm, entry_def); + error.SetErrorStringWithFormat("%s", error_strm.GetString().c_str()); + } + else if (sep_char == ':') + { + // Any value whose separator is a with a ':' means this value has a string argument + // that needs to be stored in the entry (like "${script.var:}"). + // In this case the string value is the empty string which is ok. + } + else + { + error.SetErrorStringWithFormat("%s", "invalid entry definitions"); + } + } + } + else + { + if (entry_def->children) + { + error = ParseEntry (value, entry_def, entry); + } + else if (sep_char == ':') + { + // Any value whose separator is a with a ':' means this value has a string argument + // that needs to be stored in the entry (like "${script.var:modulename.function}") + entry.string = std::move(value.str()); + } + else + { + error.SetErrorStringWithFormat("'%s' followed by '%s' but it has no children", + key.str().c_str(), + value.str().c_str()); + } + } + return error; + } + } + StreamString error_strm; + if (parent->type == FormatEntity::Entry::Type::Root) + error_strm.Printf("invalid top level item '%s'. Valid top level items are: ", key.str().c_str()); + else + error_strm.Printf("invalid member '%s' in '%s'. Valid members are: ", key.str().c_str(), parent->name); + DumpCommaSeparatedChildEntryNames (error_strm, parent); + error.SetErrorStringWithFormat("%s", error_strm.GetString().c_str()); + return error; +} + + +static const FormatEntity::Entry::Definition * +FindEntry (const llvm::StringRef &format_str, const FormatEntity::Entry::Definition *parent, llvm::StringRef &remainder) +{ + Error error; + + std::pair<llvm::StringRef, llvm::StringRef> p = format_str.split('.'); + const size_t n = parent->num_children; + for (size_t i=0; i<n; ++i) + { + const FormatEntity::Entry::Definition *entry_def = parent->children + i; + if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') + { + if (p.second.empty()) + { + if (format_str.back() == '.') + remainder = format_str.drop_front(format_str.size() - 1); + else + remainder = llvm::StringRef(); // Exact match + return entry_def; + } + else + { + if (entry_def->children) + { + return FindEntry (p.second, entry_def, remainder); + } + else + { + remainder = p.second; + return entry_def; + } + } + } + } + remainder = format_str; + return parent; +} + +Error +FormatEntity::ParseInternal (llvm::StringRef &format, Entry &parent_entry, uint32_t depth) +{ + Error error; + while (!format.empty() && error.Success()) + { + const size_t non_special_chars = format.find_first_of("${}\\"); + + if (non_special_chars == llvm::StringRef::npos) + { + // No special characters, just string bytes so add them and we are done + parent_entry.AppendText(format); + return error; + } + + if (non_special_chars > 0) + { + // We have a special character, so add all characters before these as a plain string + parent_entry.AppendText(format.substr(0,non_special_chars)); + format = format.drop_front(non_special_chars); + } + + switch (format[0]) + { + case '\0': + return error; + + case '{': + { + format = format.drop_front(); // Skip the '{' + Entry scope_entry(Entry::Type::Scope); + error = FormatEntity::ParseInternal (format, scope_entry, depth+1); + if (error.Fail()) + return error; + parent_entry.AppendEntry(std::move(scope_entry)); + } + break; + + case '}': + if (depth == 0) + error.SetErrorString("unmatched '}' character"); + else + format = format.drop_front(); // Skip the '}' as we are at the end of the scope + return error; + + case '\\': + { + format = format.drop_front(); // Skip the '\' character + if (format.empty()) + { + error.SetErrorString("'\\' character was not followed by another character"); + return error; + } + + const char desens_char = format[0]; + format = format.drop_front(); // Skip the desensitized char character + switch (desens_char) + { + case 'a': parent_entry.AppendChar('\a'); break; + case 'b': parent_entry.AppendChar('\b'); break; + case 'f': parent_entry.AppendChar('\f'); break; + case 'n': parent_entry.AppendChar('\n'); break; + case 'r': parent_entry.AppendChar('\r'); break; + case 't': parent_entry.AppendChar('\t'); break; + case 'v': parent_entry.AppendChar('\v'); break; + case '\'': parent_entry.AppendChar('\''); break; + case '\\': parent_entry.AppendChar('\\'); break; + case '0': + // 1 to 3 octal chars + { + // Make a string that can hold onto the initial zero char, + // up to 3 octal digits, and a terminating NULL. + char oct_str[5] = { 0, 0, 0, 0, 0 }; + + int i; + for (i=0; (format[i] >= '0' && format[i] <= '7') && i<4; ++i) + oct_str[i] = format[i]; + + // We don't want to consume the last octal character since + // the main for loop will do this for us, so we advance p by + // one less than i (even if i is zero) + format = format.drop_front(i); + unsigned long octal_value = ::strtoul (oct_str, NULL, 8); + if (octal_value <= UINT8_MAX) + { + parent_entry.AppendChar((char)octal_value); + } + else + { + error.SetErrorString("octal number is larger than a single byte"); + return error; + } + } + break; + + case 'x': + // hex number in the format + if (isxdigit(format[0])) + { + // Make a string that can hold onto two hex chars plus a + // NULL terminator + char hex_str[3] = { 0,0,0 }; + hex_str[0] = format[0]; + + format = format.drop_front(); + + if (isxdigit(format[0])) + { + hex_str[1] = format[0]; + format = format.drop_front(); + } + + unsigned long hex_value = strtoul (hex_str, NULL, 16); + if (hex_value <= UINT8_MAX) + { + parent_entry.AppendChar((char)hex_value); + } + else + { + error.SetErrorString("hex number is larger than a single byte"); + return error; + } + } + else + { + parent_entry.AppendChar(desens_char); + } + break; + + default: + // Just desensitize any other character by just printing what + // came after the '\' + parent_entry.AppendChar(desens_char); + break; + } + } + break; + + case '$': + if (format.size() == 1) + { + // '$' at the end of a format string, just print the '$' + parent_entry.AppendText("$"); + } + else + { + format = format.drop_front(); // Skip the '$' + + if (format[0] == '{') + { + format = format.drop_front(); // Skip the '{' + + llvm::StringRef variable, variable_format; + error = FormatEntity::ExtractVariableInfo (format, variable, variable_format); + if (error.Fail()) + return error; + bool verify_is_thread_id = false; + Entry entry; + if (!variable_format.empty()) + { + entry.printf_format = std::move(variable_format.str()); + + // If the format contains a '%' we are going to assume this is + // a printf style format. So if you want to format your thread ID + // using "0x%llx" you can use: + // ${thread.id%0x%llx} + // + // If there is no '%' in the format, then it is assumed to be a + // LLDB format name, or one of the extended formats specified in + // the switch statement below. + + if (entry.printf_format.find('%') == std::string::npos) + { + bool clear_printf = false; + + if (FormatManager::GetFormatFromCString(entry.printf_format.c_str(), + false, + entry.fmt)) + { + // We have an LLDB format, so clear the printf format + clear_printf = true; + } + else if (entry.printf_format.size() == 1) + { + switch (entry.printf_format[0]) + { + case '@': // if this is an @ sign, print ObjC description + entry.number = ValueObject::eValueObjectRepresentationStyleLanguageSpecific; + clear_printf = true; + break; + case 'V': // if this is a V, print the value using the default format + entry.number = ValueObject::eValueObjectRepresentationStyleValue; + clear_printf = true; + break; + case 'L': // if this is an L, print the location of the value + entry.number = ValueObject::eValueObjectRepresentationStyleLocation; + clear_printf = true; + break; + case 'S': // if this is an S, print the summary after all + entry.number = ValueObject::eValueObjectRepresentationStyleSummary; + clear_printf = true; + break; + case '#': // if this is a '#', print the number of children + entry.number = ValueObject::eValueObjectRepresentationStyleChildrenCount; + clear_printf = true; + break; + case 'T': // if this is a 'T', print the type + entry.number = ValueObject::eValueObjectRepresentationStyleType; + clear_printf = true; + break; + case 'N': // if this is a 'N', print the name + entry.number = ValueObject::eValueObjectRepresentationStyleName; + clear_printf = true; + break; + case '>': // if this is a '>', print the expression path + entry.number = ValueObject::eValueObjectRepresentationStyleExpressionPath; + clear_printf = true; + break; + default: + error.SetErrorStringWithFormat("invalid format: '%s'", entry.printf_format.c_str()); + return error; + } + } + else if (FormatManager::GetFormatFromCString(entry.printf_format.c_str(), + true, + entry.fmt)) + { + clear_printf = true; + } + else if (entry.printf_format == "tid") + { + verify_is_thread_id = true; + } + else + { + error.SetErrorStringWithFormat("invalid format: '%s'", entry.printf_format.c_str()); + return error; + } + + // Our format string turned out to not be a printf style format + // so lets clear the string + if (clear_printf) + entry.printf_format.clear(); + } + } + + // Check for dereferences + if (variable[0] == '*') + { + entry.deref = true; + variable = variable.drop_front(); + } + + error = ParseEntry (variable, &g_root, entry); + if (error.Fail()) + return error; + + if (verify_is_thread_id) + { + if (entry.type != Entry::Type::ThreadID && + entry.type != Entry::Type::ThreadProtocolID) + { + error.SetErrorString("the 'tid' format can only be used on ${thread.id} and ${thread.protocol_id}"); + } + } + + switch (entry.type) + { + case Entry::Type::Variable: + case Entry::Type::VariableSynthetic: + if (entry.number == 0) + { + if (entry.string.empty()) + entry.number = ValueObject::eValueObjectRepresentationStyleValue; + else + entry.number = ValueObject::eValueObjectRepresentationStyleSummary; + } + break; + default: + // Make sure someone didn't try to dereference anything but ${var} or ${svar} + if (entry.deref) + { + error.SetErrorStringWithFormat("${%s} can't be dereferenced, only ${var} and ${svar} can.", variable.str().c_str()); + return error; + } + } + // Check if this entry just wants to insert a constant string + // value into the parent_entry, if so, insert the string with + // AppendText, else append the entry to the parent_entry. + if (entry.type == Entry::Type::InsertString) + parent_entry.AppendText(entry.string.c_str()); + else + parent_entry.AppendEntry(std::move(entry)); + } + } + break; + } + } + return error; +} + + +Error +FormatEntity::ExtractVariableInfo (llvm::StringRef &format_str, llvm::StringRef &variable_name, llvm::StringRef &variable_format) +{ + Error error; + variable_name = llvm::StringRef(); + variable_format = llvm::StringRef(); + + const size_t paren_pos = format_str.find_first_of('}'); + if (paren_pos != llvm::StringRef::npos) + { + const size_t percent_pos = format_str.find_first_of('%'); + if (percent_pos < paren_pos) + { + if (percent_pos > 0) + { + if (percent_pos > 1) + variable_name = format_str.substr(0, percent_pos); + variable_format = format_str.substr(percent_pos + 1, paren_pos - (percent_pos + 1)); + } + } + else + { + variable_name = format_str.substr(0, paren_pos); + } + // Strip off elements and the formatting and the trailing '}' + format_str = format_str.substr(paren_pos + 1); + } + else + { + error.SetErrorStringWithFormat("missing terminating '}' character for '${%s'", format_str.str().c_str()); + } + return error; +} + +bool +FormatEntity::FormatFileSpec (const FileSpec &file_spec, Stream &s, llvm::StringRef variable_name, llvm::StringRef variable_format) +{ + if (variable_name.empty() || variable_name.equals(".fullpath")) + { + file_spec.Dump(&s); + return true; + } + else if (variable_name.equals(".basename")) + { + s.PutCString(file_spec.GetFilename().AsCString("")); + return true; + } + else if (variable_name.equals(".dirname")) + { + s.PutCString(file_spec.GetFilename().AsCString("")); + return true; + } + return false; +} + +static std::string +MakeMatch (const llvm::StringRef &prefix, const char *suffix) +{ + std::string match(prefix.str()); + match.append(suffix); + return std::move(match); +} + +static void +AddMatches (const FormatEntity::Entry::Definition *def, + const llvm::StringRef &prefix, + const llvm::StringRef &match_prefix, + StringList &matches) +{ + const size_t n = def->num_children; + if (n > 0) + { + for (size_t i=0; i<n; ++i) + { + std::string match = std::move(prefix.str()); + if (match_prefix.empty()) + matches.AppendString(MakeMatch (prefix, def->children[i].name)); + else if (strncmp(def->children[i].name, match_prefix.data(), match_prefix.size()) == 0) + matches.AppendString(MakeMatch (prefix, def->children[i].name + match_prefix.size())); + } + } +} +size_t +FormatEntity::AutoComplete (const char *s, + int match_start_point, + int max_return_elements, + bool &word_complete, + StringList &matches) +{ + word_complete = false; + llvm::StringRef str(s + match_start_point); + matches.Clear(); + + const size_t dollar_pos = str.rfind('$'); + if (dollar_pos != llvm::StringRef::npos) + { + // Hitting TAB after $ at the end of the string add a "{" + if (dollar_pos == str.size() - 1) + { + std::string match = std::move(str.str()); + match.append("{"); + matches.AppendString(std::move(match)); + } + else if (str[dollar_pos + 1] == '{') + { + const size_t close_pos = str.find('}', dollar_pos + 2); + if (close_pos == llvm::StringRef::npos) + { + const size_t format_pos = str.find('%', dollar_pos + 2); + if (format_pos == llvm::StringRef::npos) + { + llvm::StringRef partial_variable (str.substr(dollar_pos + 2)); + if (partial_variable.empty()) + { + // Suggest all top level entites as we are just past "${" + AddMatches(&g_root, str, llvm::StringRef(), matches); + } + else + { + // We have a partially specified variable, find it + llvm::StringRef remainder; + const FormatEntity::Entry::Definition* entry_def = FindEntry (partial_variable, &g_root, remainder); + if (entry_def) + { + const size_t n = entry_def->num_children; + + if (remainder.empty()) + { + // Exact match + if (n > 0) + { + // "${thread.info" <TAB> + matches.AppendString(std::move(MakeMatch (str, "."))); + } + else + { + // "${thread.id" <TAB> + matches.AppendString(std::move(MakeMatch (str, "}"))); + word_complete = true; + } + } + else if (remainder.equals(".")) + { + // "${thread." <TAB> + AddMatches(entry_def, str, llvm::StringRef(), matches); + } + else + { + // We have a partial match + // "${thre" <TAB> + AddMatches(entry_def, str, remainder, matches); + } + } + } + } + } + } + } + return matches.GetSize(); +} diff --git a/source/Core/IOHandler.cpp b/source/Core/IOHandler.cpp index 21ba965ba212..747fd4411d4d 100644 --- a/source/Core/IOHandler.cpp +++ b/source/Core/IOHandler.cpp @@ -3217,6 +3217,8 @@ public: FrameTreeDelegate () : TreeDelegate() { + FormatEntity::Parse ("frame #${frame.index}: {${function.name}${function.pc-offset}}}", + m_format); } virtual ~FrameTreeDelegate() @@ -3236,9 +3238,7 @@ public: StreamString strm; const SymbolContext &sc = frame_sp->GetSymbolContext(eSymbolContextEverything); ExecutionContext exe_ctx (frame_sp); - //const char *frame_format = "frame #${frame.index}: ${module.file.basename}{`${function.name}${function.pc-offset}}}"; - const char *frame_format = "frame #${frame.index}: {${function.name}${function.pc-offset}}}"; - if (Debugger::FormatPrompt (frame_format, &sc, &exe_ctx, NULL, strm)) + if (FormatEntity::Format(m_format, strm, &sc, &exe_ctx, NULL, NULL, false, false)) { int right_pad = 1; window.PutCStringTruncated(strm.GetString().c_str(), right_pad); @@ -3265,6 +3265,8 @@ public: } return false; } +protected: + FormatEntity::Entry m_format; }; class ThreadTreeDelegate : public TreeDelegate @@ -3276,6 +3278,8 @@ public: m_tid (LLDB_INVALID_THREAD_ID), m_stop_id (UINT32_MAX) { + FormatEntity::Parse ("thread #${thread.index}: tid = ${thread.id}{, stop reason = ${thread.stop-reason}}", + m_format); } virtual @@ -3306,8 +3310,7 @@ public: { StreamString strm; ExecutionContext exe_ctx (thread_sp); - const char *format = "thread #${thread.index}: tid = ${thread.id}{, stop reason = ${thread.stop-reason}}"; - if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm)) + if (FormatEntity::Format (m_format, strm, NULL, &exe_ctx, NULL, NULL, false, false)) { int right_pad = 1; window.PutCStringTruncated(strm.GetString().c_str(), right_pad); @@ -3383,6 +3386,8 @@ protected: std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp; lldb::user_id_t m_tid; uint32_t m_stop_id; + FormatEntity::Entry m_format; + }; class ThreadsTreeDelegate : public TreeDelegate @@ -3394,6 +3399,8 @@ public: m_debugger (debugger), m_stop_id (UINT32_MAX) { + FormatEntity::Parse("process ${process.id}{, name = ${process.name}}", + m_format); } virtual @@ -3415,8 +3422,7 @@ public: { StreamString strm; ExecutionContext exe_ctx (process_sp); - const char *format = "process ${process.id}{, name = ${process.name}}"; - if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm)) + if (FormatEntity::Format (m_format, strm, NULL, &exe_ctx, NULL, NULL, false, false)) { int right_pad = 1; window.PutCStringTruncated(strm.GetString().c_str(), right_pad); @@ -3472,6 +3478,8 @@ protected: std::shared_ptr<ThreadTreeDelegate> m_thread_delegate_sp; Debugger &m_debugger; uint32_t m_stop_id; + FormatEntity::Entry m_format; + }; class ValueObjectListDelegate : public WindowDelegate @@ -4635,6 +4643,8 @@ public: StatusBarWindowDelegate (Debugger &debugger) : m_debugger (debugger) { + FormatEntity::Parse("Thread: ${thread.id%tid}", + m_format); } virtual @@ -4659,8 +4669,7 @@ public: if (StateIsStoppedState(state, true)) { StreamString strm; - const char *format = "Thread: ${thread.id%tid}"; - if (thread && Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm)) + if (thread && FormatEntity::Format (m_format, strm, NULL, &exe_ctx, NULL, NULL, false, false)) { window.MoveCursor (40, 0); window.PutCStringTruncated(strm.GetString().c_str(), 1); @@ -4686,6 +4695,7 @@ public: protected: Debugger &m_debugger; + FormatEntity::Entry m_format; }; class SourceFileWindowDelegate : public WindowDelegate diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp index d205d363b764..fe4cfb366c88 100644 --- a/source/Core/Log.cpp +++ b/source/Core/Log.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C Includes #include <stdio.h> #include <stdarg.h> @@ -20,7 +18,6 @@ // Other libraries and framework includes // Project includes -#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" @@ -219,7 +216,6 @@ Log::LogIf (uint32_t bits, const char *format, ...) } } - //---------------------------------------------------------------------- // Printing of errors that are not fatal. //---------------------------------------------------------------------- diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp index c0ab66cd2880..e1598d30e4e5 100644 --- a/source/Core/Mangled.cpp +++ b/source/Core/Mangled.cpp @@ -10,8 +10,9 @@ // FreeBSD9-STABLE requires this to know about size_t in cxxabi.h #include <cstddef> -#if defined(_MSC_VER) -// Cannot enable the builtin demangler on msvc as it does not support the cpp11 within the implementation. +#if defined(_MSC_VER) +#include "lldb/Host/windows/windows.h" +#include <Dbghelp.h> #elif defined (__FreeBSD__) #define LLDB_USE_BUILTIN_DEMANGLER #else @@ -4998,7 +4999,11 @@ static inline bool cstring_is_mangled (const char *s) { if (s) - return s[0] == '_' && s[1] == 'Z'; +#if defined(_MSC_VER) + return (s[0] == '?'); +#else + return (s[0] == '_' && s[1] == 'Z'); +#endif return false; } @@ -5226,15 +5231,27 @@ Mangled::GetDemangledName () const if (!demangled_name) demangled_name = __cxa_demangle (mangled_cstr, NULL, NULL, NULL); #elif defined(_MSC_VER) - // Cannot demangle on msvc. - char *demangled_name = nullptr; + char *demangled_name = (char *)::malloc(1024); + ::ZeroMemory(demangled_name, 1024); + DWORD result = ::UnDecorateSymbolName(mangled_cstr, demangled_name, 1023, + UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected keywords + UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc keywords + UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications + UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers + UNDNAME_NO_MS_KEYWORDS // Strip all MS extension keywords + ); + if (result == 0) + { + free (demangled_name); + demangled_name = nullptr; + } #else char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL); #endif if (demangled_name) { - m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled); + m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled); free (demangled_name); } } @@ -5335,6 +5352,21 @@ Mangled::MemorySize () const return m_mangled.MemorySize() + m_demangled.MemorySize(); } +lldb::LanguageType +Mangled::GetLanguage () +{ + ConstString mangled = GetMangledName(); + if (mangled) + { + if (GetDemangledName()) + { + if (cstring_is_mangled(mangled.GetCString())) + return lldb::eLanguageTypeC_plus_plus; + } + } + return lldb::eLanguageTypeUnknown; +} + //---------------------------------------------------------------------- // Dump OBJ to the supplied stream S. //---------------------------------------------------------------------- diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp index 900eea2e0419..891bd87a20d4 100644 --- a/source/Core/Module.cpp +++ b/source/Core/Module.cpp @@ -152,7 +152,6 @@ Module::Module (const ModuleSpec &module_spec) : m_did_load_symbol_vendor (false), m_did_parse_uuid (false), m_did_init_ast (false), - m_is_dynamic_loader_module (false), m_file_has_changed (false), m_first_file_changed_log (false) { @@ -257,7 +256,6 @@ Module::Module(const FileSpec& file_spec, m_did_load_symbol_vendor (false), m_did_parse_uuid (false), m_did_init_ast (false), - m_is_dynamic_loader_module (false), m_file_has_changed (false), m_first_file_changed_log (false) { @@ -304,7 +302,6 @@ Module::Module () : m_did_load_symbol_vendor (false), m_did_parse_uuid (false), m_did_init_ast (false), - m_is_dynamic_loader_module (false), m_file_has_changed (false), m_first_file_changed_log (false) { @@ -1304,10 +1301,14 @@ Module::GetObjectFile() data_offset); if (m_objfile_sp) { - // Once we get the object file, update our module with the object file's + // Once we get the object file, update our module with the object file's // architecture since it might differ in vendor/os if some parts were - // unknown. - m_objfile_sp->GetArchitecture (m_arch); + // unknown. But since the matching arch might already be more specific + // than the generic COFF architecture, only merge in those values that + // overwrite unspecified unknown values. + ArchSpec new_arch; + m_objfile_sp->GetArchitecture(new_arch); + m_arch.MergeFrom(new_arch); } else { @@ -1732,7 +1733,7 @@ Module::PrepareForFunctionNameLookup (const ConstString &name, if (CPPLanguageRuntime::ExtractContextAndIdentifier (name_cstr, context, basename)) lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase); else - lookup_name_type_mask = eFunctionNameTypeFull; + lookup_name_type_mask |= eFunctionNameTypeFull; } else { @@ -1821,3 +1822,13 @@ Module::CreateJITModule (const lldb::ObjectFileJITDelegateSP &delegate_sp) return ModuleSP(); } +bool +Module::GetIsDynamicLinkEditor() +{ + ObjectFile * obj_file = GetObjectFile (); + + if (obj_file) + return obj_file->GetIsDynamicLinkEditor(); + + return false; +} diff --git a/source/Core/RegisterValue.cpp b/source/Core/RegisterValue.cpp index 91f5bea805c6..272c1eecf920 100644 --- a/source/Core/RegisterValue.cpp +++ b/source/Core/RegisterValue.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamString.h" #include "lldb/Interpreter/Args.h" +#include "lldb/Host/StringConvert.h" using namespace lldb; using namespace lldb_private; @@ -467,7 +468,7 @@ RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *va case eEncodingUint: if (byte_size <= sizeof (uint64_t)) { - uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); + uint64_t uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str); else if (!Args::UInt64ValueIsValidForByteSize (uval64, byte_size)) @@ -488,7 +489,7 @@ RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *va case eEncodingSint: if (byte_size <= sizeof (long long)) { - uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); + uint64_t sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str); else if (!Args::SInt64ValueIsValidForByteSize (sval64, byte_size)) diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp index 54924d069537..3f712e1b2daa 100644 --- a/source/Core/RegularExpression.cpp +++ b/source/Core/RegularExpression.cpp @@ -7,36 +7,34 @@ // //===----------------------------------------------------------------------===// +#include <string.h> #include "lldb/Core/RegularExpression.h" #include "llvm/ADT/StringRef.h" -#include <string.h> +#include "lldb/Core/Error.h" -using namespace lldb_private; //---------------------------------------------------------------------- -// Default constructor +// Enable enhanced mode if it is available. This allows for things like +// \d for digit, \s for space, and many more, but it isn't available +// everywhere. //---------------------------------------------------------------------- -RegularExpression::RegularExpression() : - m_re(), - m_comp_err (1), - m_preg(), - m_compile_flags(REG_EXTENDED) -{ - memset(&m_preg,0,sizeof(m_preg)); -} +#if defined(REG_ENHANCED) +#define DEFAULT_COMPILE_FLAGS (REG_ENHANCED|REG_EXTENDED) +#else +#define DEFAULT_COMPILE_FLAGS (REG_EXTENDED) +#endif + +using namespace lldb_private; //---------------------------------------------------------------------- -// Constructor that compiles "re" using "flags" and stores the -// resulting compiled regular expression into this object. +// Default constructor //---------------------------------------------------------------------- -RegularExpression::RegularExpression(const char* re, int flags) : +RegularExpression::RegularExpression() : m_re(), m_comp_err (1), - m_preg(), - m_compile_flags(flags) + m_preg() { memset(&m_preg,0,sizeof(m_preg)); - Compile(re); } //---------------------------------------------------------------------- @@ -46,8 +44,7 @@ RegularExpression::RegularExpression(const char* re, int flags) : RegularExpression::RegularExpression(const char* re) : m_re(), m_comp_err (1), - m_preg(), - m_compile_flags(REG_EXTENDED) + m_preg() { memset(&m_preg,0,sizeof(m_preg)); Compile(re); @@ -56,16 +53,14 @@ RegularExpression::RegularExpression(const char* re) : RegularExpression::RegularExpression(const RegularExpression &rhs) { memset(&m_preg,0,sizeof(m_preg)); - Compile(rhs.GetText(), rhs.GetCompileFlags()); + Compile(rhs.GetText()); } const RegularExpression & RegularExpression::operator= (const RegularExpression &rhs) { if (&rhs != this) - { - Compile (rhs.GetText(), rhs.GetCompileFlags()); - } + Compile (rhs.GetText()); return *this; } //---------------------------------------------------------------------- @@ -94,19 +89,12 @@ RegularExpression::~RegularExpression() bool RegularExpression::Compile(const char* re) { - return Compile (re, m_compile_flags); -} - -bool -RegularExpression::Compile(const char* re, int flags) -{ Free(); - m_compile_flags = flags; if (re && re[0]) { m_re = re; - m_comp_err = ::regcomp (&m_preg, re, flags); + m_comp_err = ::regcomp (&m_preg, re, DEFAULT_COMPILE_FLAGS); } else { @@ -126,7 +114,7 @@ RegularExpression::Compile(const char* re, int flags) // will be executed using the "execute_flags". //--------------------------------------------------------------------- bool -RegularExpression::Execute(const char* s, Match *match, int execute_flags) const +RegularExpression::Execute (const char* s, Match *match) const { int err = 1; if (s != NULL && m_comp_err == 0) @@ -137,7 +125,7 @@ RegularExpression::Execute(const char* s, Match *match, int execute_flags) const s, match->GetSize(), match->GetData(), - execute_flags); + 0); } else { @@ -145,7 +133,7 @@ RegularExpression::Execute(const char* s, Match *match, int execute_flags) const s, 0, NULL, - execute_flags); + 0); } } diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp index 1bfe6f2f1baf..0e9b98dc4ab6 100644 --- a/source/Core/Scalar.cpp +++ b/source/Core/Scalar.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Host/Endian.h" +#include "lldb/Host/StringConvert.h" #include "Plugins/Process/Utility/InstructionUtils.h" @@ -1790,7 +1791,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by case eEncodingUint: if (byte_size <= sizeof (unsigned long long)) { - uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); + uint64_t uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str); else if (!UIntValueIsValidForSize (uval64, byte_size)) @@ -1819,7 +1820,7 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by case eEncodingSint: if (byte_size <= sizeof (long long)) { - uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); + uint64_t sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str); else if (!SIntValueIsValidForSize (sval64, byte_size)) diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp index 2285ca954457..9f8dd629e3d4 100644 --- a/source/Core/StreamFile.cpp +++ b/source/Core/StreamFile.cpp @@ -49,7 +49,8 @@ StreamFile::StreamFile (FILE *fh, bool transfer_ownership) : StreamFile::StreamFile (const char *path) : Stream (), - m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, lldb::eFilePermissionsFileDefault) + m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionCloseOnExec, + lldb::eFilePermissionsFileDefault) { } diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp index db33fce4a03e..a416d0745a69 100644 --- a/source/Core/Value.cpp +++ b/source/Core/Value.cpp @@ -277,7 +277,7 @@ Value::GetValueByteSize (Error *error_ptr) { const ClangASTType &ast_type = GetClangType(); if (ast_type.IsValid()) - byte_size = ast_type.GetByteSize(); + byte_size = ast_type.GetByteSize(nullptr); } break; } @@ -434,7 +434,7 @@ Value::GetValueAsData (ExecutionContext *exe_ctx, lldb::Encoding type_encoding = ast_type.GetEncoding(type_encoding_count); if (type_encoding == eEncodingUint || type_encoding == eEncodingSint) - limit_byte_size = ast_type.GetByteSize(); + limit_byte_size = ast_type.GetByteSize(nullptr); } if (m_value.GetData (data, limit_byte_size)) diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp index fa5fb14db05b..b72e5c3f18c6 100644 --- a/source/Core/ValueObject.cpp +++ b/source/Core/ValueObject.cpp @@ -99,6 +99,7 @@ ValueObject::ValueObject (ValueObject &parent) : m_user_id_of_forced_summary(), m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid), m_value_checksum(), + m_preferred_display_language(lldb::eLanguageTypeUnknown), m_value_is_valid (false), m_value_did_change (false), m_children_count_valid (false), @@ -149,6 +150,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope, m_user_id_of_forced_summary(), m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type), m_value_checksum(), + m_preferred_display_language(lldb::eLanguageTypeUnknown), m_value_is_valid (false), m_value_did_change (false), m_children_count_valid (false), @@ -969,7 +971,9 @@ ValueObject::GetPointeeData (DataExtractor& data, if (item_count == 0) return 0; - const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(); + ExecutionContext exe_ctx (GetExecutionContextRef()); + + const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize(&exe_ctx); const uint64_t bytes = item_count * item_type_size; const uint64_t offset = item_idx * item_type_size; @@ -1045,7 +1049,7 @@ ValueObject::GetPointeeData (DataExtractor& data, break; case eAddressTypeHost: { - const uint64_t max_bytes = GetClangType().GetByteSize(); + const uint64_t max_bytes = GetClangType().GetByteSize(&exe_ctx); if (max_bytes > offset) { size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes); @@ -1505,14 +1509,14 @@ ValueObject::GetValueAsSigned (int64_t fail_value, bool *success) { if (success) *success = true; - return scalar.SLongLong(fail_value); + return scalar.SLongLong(fail_value); } // fallthrough, otherwise... } if (success) *success = false; - return fail_value; + return fail_value; } // if any more "special cases" are added to ValueObject::DumpPrintableRepresentation() please keep @@ -2220,10 +2224,12 @@ ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type if (!can_create) return ValueObjectSP(); + ExecutionContext exe_ctx (GetExecutionContextRef()); + ValueObjectChild *synthetic_child = new ValueObjectChild(*this, type, name_const_str, - type.GetByteSize(), + type.GetByteSize(&exe_ctx), offset, 0, 0, @@ -2261,10 +2267,12 @@ ValueObject::GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool c const bool is_base_class = true; + ExecutionContext exe_ctx (GetExecutionContextRef()); + ValueObjectChild *synthetic_child = new ValueObjectChild(*this, type, name_const_str, - type.GetByteSize(), + type.GetByteSize(&exe_ctx), offset, 0, 0, @@ -4128,16 +4136,22 @@ ValueObject::GetRoot () { if (m_root) return m_root; - ValueObject* parent = m_parent; - if (!parent) - return (m_root = this); - while (parent->m_parent) + return (m_root = FollowParentChain( [] (ValueObject* vo) -> bool { + return (vo->m_parent != nullptr); + })); +} + +ValueObject* +ValueObject::FollowParentChain (std::function<bool(ValueObject*)> f) +{ + ValueObject* vo = this; + while (vo) { - if (parent->m_root) - return (m_root = parent->m_root); - parent = parent->m_parent; + if (f(vo) == false) + break; + vo = vo->m_parent; } - return (m_root = parent); + return vo; } AddressType @@ -4181,24 +4195,33 @@ ValueObject::GetFormat () const lldb::LanguageType ValueObject::GetPreferredDisplayLanguage () { - lldb::LanguageType type = lldb::eLanguageTypeUnknown; - if (GetRoot()) + lldb::LanguageType type = m_preferred_display_language; + if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { - if (GetRoot() == this) + if (GetRoot()) { - if (StackFrameSP frame_sp = GetFrameSP()) + if (GetRoot() == this) { - const SymbolContext& sc(frame_sp->GetSymbolContext(eSymbolContextCompUnit)); - if (CompileUnit* cu = sc.comp_unit) - type = cu->GetLanguage(); + if (StackFrameSP frame_sp = GetFrameSP()) + { + const SymbolContext& sc(frame_sp->GetSymbolContext(eSymbolContextCompUnit)); + if (CompileUnit* cu = sc.comp_unit) + type = cu->GetLanguage(); + } + } + else + { + type = GetRoot()->GetPreferredDisplayLanguage(); } - } - else - { - type = GetRoot()->GetPreferredDisplayLanguage(); } } - return type; + return (m_preferred_display_language = type); // only compute it once +} + +void +ValueObject::SetPreferredDisplayLanguage (lldb::LanguageType lt) +{ + m_preferred_display_language = lt; } bool diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp index fc870d726221..e8b477a74a52 100644 --- a/source/Core/ValueObjectConstResult.cpp +++ b/source/Core/ValueObjectConstResult.cpp @@ -256,8 +256,10 @@ ValueObjectConstResult::GetValueType() const uint64_t ValueObjectConstResult::GetByteSize() { + ExecutionContext exe_ctx(GetExecutionContextRef()); + if (m_byte_size == 0) - m_byte_size = GetClangType().GetByteSize(); + SetByteSize(GetClangType().GetByteSize(&exe_ctx)); return m_byte_size; } diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp index 1b8ec8083f8f..89b98a1db1ba 100644 --- a/source/Core/ValueObjectDynamicValue.cpp +++ b/source/Core/ValueObjectDynamicValue.cpp @@ -127,7 +127,7 @@ ValueObjectDynamicValue::GetByteSize() { const bool success = UpdateValueIfNeeded(false); if (success && m_dynamic_type_info.HasType()) - return m_value.GetValueByteSize(NULL); + return m_value.GetValueByteSize(nullptr); else return m_parent->GetByteSize(); } diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp index 5fbe87b66522..9f1953138f62 100644 --- a/source/Core/ValueObjectMemory.cpp +++ b/source/Core/ValueObjectMemory.cpp @@ -169,7 +169,7 @@ ValueObjectMemory::GetByteSize() { if (m_type_sp) return m_type_sp->GetByteSize(); - return m_clang_type.GetByteSize (); + return m_clang_type.GetByteSize (nullptr); } lldb::ValueType diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp index dafe73a5e57e..e266267981b8 100644 --- a/source/Core/ValueObjectSyntheticFilter.cpp +++ b/source/Core/ValueObjectSyntheticFilter.cpp @@ -298,3 +298,9 @@ ValueObjectSynthetic::CanProvideValue () return true; return m_parent->CanProvideValue(); } + +bool +ValueObjectSynthetic::SetValueFromCString (const char *value_str, Error& error) +{ + return m_parent->SetValueFromCString(value_str, error); +} diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp index ab74a50e7cd5..ed2aeb3d9634 100644 --- a/source/Core/ValueObjectVariable.cpp +++ b/source/Core/ValueObjectVariable.cpp @@ -105,12 +105,14 @@ ValueObjectVariable::CalculateNumChildren() uint64_t ValueObjectVariable::GetByteSize() { + ExecutionContext exe_ctx(GetExecutionContextRef()); + ClangASTType type(GetClangType()); if (!type.IsValid()) return 0; - return type.GetByteSize(); + return type.GetByteSize(&exe_ctx); } lldb::ValueType diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp index 04cdadf5a98f..5aa8289794c1 100644 --- a/source/DataFormatters/CXXFormatterFunctions.cpp +++ b/source/DataFormatters/CXXFormatterFunctions.cpp @@ -317,7 +317,7 @@ lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Strea return false; ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar); - const uint32_t wchar_size = wchar_clang_type.GetBitSize(); + const uint32_t wchar_size = wchar_clang_type.GetBitSize(nullptr); ReadStringAndDumpToStreamOptions options(valobj); options.SetLocation(data_addr); diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp index 01799cef5e4e..ae52b3309ed8 100644 --- a/source/DataFormatters/FormatManager.cpp +++ b/source/DataFormatters/FormatManager.cpp @@ -251,6 +251,8 @@ FormatManager::GetPossibleMatches (ValueObject& valobj, do { lldb::ProcessSP process_sp = valobj.GetProcessSP(); + if (!process_sp) + break; ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime(); if (runtime == nullptr) break; diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp index 26bbcf91242f..728ad84341f0 100644 --- a/source/DataFormatters/LibCxx.cpp +++ b/source/DataFormatters/LibCxx.cpp @@ -14,6 +14,7 @@ #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" +#include "lldb/Core/FormatEntity.h" #include "lldb/Core/Stream.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" @@ -139,7 +140,7 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si return ValueObjectSP(); } bool bit_set = ((byte & mask) != 0); - DataBufferSP buffer_sp(new DataBufferHeap(m_bool_type.GetByteSize(),0)); + DataBufferSP buffer_sp(new DataBufferHeap(m_bool_type.GetByteSize(nullptr),0)); if (bit_set && buffer_sp && buffer_sp->GetBytes()) *(buffer_sp->GetBytes()) = 1; // regardless of endianness, anything non-zero is true StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); @@ -460,5 +461,5 @@ lldb_private::formatters::LibcxxContainerSummaryProvider (ValueObject& valobj, S return false; stream.Printf("0x%016" PRIx64 " ", value); } - return Debugger::FormatPrompt("size=${svar%#}", NULL, NULL, NULL, stream, &valobj); + return FormatEntity::FormatStringRef("size=${svar%#}", stream, NULL, NULL, NULL, &valobj, false, false); } diff --git a/source/DataFormatters/LibCxxInitializerList.cpp b/source/DataFormatters/LibCxxInitializerList.cpp index e76b0bec95ce..91f1f90507a7 100644 --- a/source/DataFormatters/LibCxxInitializerList.cpp +++ b/source/DataFormatters/LibCxxInitializerList.cpp @@ -107,7 +107,7 @@ lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() if (kind != lldb::eTemplateArgumentKindType || false == m_element_type.IsValid()) return false; - m_element_size = m_element_type.GetByteSize(); + m_element_size = m_element_type.GetByteSize(nullptr); if (m_element_size > 0) m_start = m_backend.GetChildMemberWithName(g___begin_,true).get(); // store raw pointers or end up with a circular dependency diff --git a/source/DataFormatters/LibCxxVector.cpp b/source/DataFormatters/LibCxxVector.cpp index 26c62afbed2b..d0e6be486d65 100644 --- a/source/DataFormatters/LibCxxVector.cpp +++ b/source/DataFormatters/LibCxxVector.cpp @@ -115,7 +115,7 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() if (!data_type_finder_sp) return false; m_element_type = data_type_finder_sp->GetClangType().GetPointeeType(); - m_element_size = m_element_type.GetByteSize(); + m_element_size = m_element_type.GetByteSize(nullptr); if (m_element_size > 0) { diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp index ff089af58cb7..4c9cd582e642 100644 --- a/source/DataFormatters/TypeSummary.cpp +++ b/source/DataFormatters/TypeSummary.cpp @@ -86,13 +86,30 @@ m_flags(flags) StringSummaryFormat::StringSummaryFormat (const TypeSummaryImpl::Flags& flags, const char *format_cstr) : -TypeSummaryImpl(flags), -m_format() + TypeSummaryImpl(flags), + m_format_str() { - if (format_cstr) - m_format.assign(format_cstr); + SetSummaryString (format_cstr); } +void +StringSummaryFormat::SetSummaryString (const char* format_cstr) +{ + m_format.Clear(); + if (format_cstr && format_cstr[0]) + { + m_format_str = format_cstr; + m_error = FormatEntity::Parse(format_cstr, m_format); + } + else + { + m_format_str.clear(); + m_error.Clear(); + } +} + + + bool StringSummaryFormat::FormatObject (ValueObject *valobj, std::string& retval, @@ -120,7 +137,7 @@ StringSummaryFormat::FormatObject (ValueObject *valobj, } else { - if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, valobj)) + if (FormatEntity::Format(m_format, s, &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), valobj, false, false)) { retval.assign(s.GetString()); return true; @@ -138,7 +155,10 @@ StringSummaryFormat::GetDescription () { StreamString sstr; - sstr.Printf ("`%s`%s%s%s%s%s%s%s", m_format.c_str(), + sstr.Printf ("`%s`%s%s%s%s%s%s%s%s%s", + m_format_str.c_str(), + m_error.Fail() ? " error: " : "", + m_error.Fail() ? m_error.AsCString() : "", Cascades() ? "" : " (not cascading)", !DoesPrintChildren(nullptr) ? "" : " (show children)", !DoesPrintValue(nullptr) ? " (hide value)" : "", @@ -153,8 +173,8 @@ CXXFunctionSummaryFormat::CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags Callback impl, const char* description) : TypeSummaryImpl(flags), -m_impl(impl), -m_description(description ? description : "") + m_impl(impl), + m_description(description ? description : "") { } diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp index 13c1c7508b68..b150b2bb6ee3 100644 --- a/source/DataFormatters/TypeSynthetic.cpp +++ b/source/DataFormatters/TypeSynthetic.cpp @@ -68,18 +68,24 @@ size_t TypeFilterImpl::FrontEnd::GetIndexOfChildWithName (const ConstString &name) { const char* name_cstr = name.GetCString(); - for (size_t i = 0; i < filter->GetCount(); i++) + if (name_cstr) { - const char* expr_cstr = filter->GetExpressionPathAtIndex(i); - if (expr_cstr) + for (size_t i = 0; i < filter->GetCount(); i++) { - if (*expr_cstr == '.') - expr_cstr++; - else if (*expr_cstr == '-' && *(expr_cstr+1) == '>') - expr_cstr += 2; + const char* expr_cstr = filter->GetExpressionPathAtIndex(i); + if (expr_cstr) + { + if (*expr_cstr == '.') + expr_cstr++; + else if (*expr_cstr == '-' && *(expr_cstr+1) == '>') + expr_cstr += 2; + } + if (expr_cstr) + { + if (!::strcmp(name_cstr, expr_cstr)) + return i; + } } - if (!::strcmp(name_cstr, expr_cstr)) - return i; } return UINT32_MAX; } diff --git a/source/Expression/ASTResultSynthesizer.cpp b/source/Expression/ASTResultSynthesizer.cpp index 2f14721100bc..c3d42cb49ec5 100644 --- a/source/Expression/ASTResultSynthesizer.cpp +++ b/source/Expression/ASTResultSynthesizer.cpp @@ -480,10 +480,10 @@ ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) } void -ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD) { if (m_passthrough) - m_passthrough->HandleVTable(RD, DefinitionRequired); + m_passthrough->HandleVTable(RD); } void diff --git a/source/Expression/ASTStructExtractor.cpp b/source/Expression/ASTStructExtractor.cpp index 2a8b7bc7d8ec..98628dbc92be 100644 --- a/source/Expression/ASTStructExtractor.cpp +++ b/source/Expression/ASTStructExtractor.cpp @@ -186,10 +186,10 @@ ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) } void -ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +ASTStructExtractor::HandleVTable(CXXRecordDecl *RD) { if (m_passthrough) - m_passthrough->HandleVTable(RD, DefinitionRequired); + m_passthrough->HandleVTable(RD); } void diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp index 4906108401af..d05d9b99df07 100644 --- a/source/Expression/ClangExpressionParser.cpp +++ b/source/Expression/ClangExpressionParser.cpp @@ -329,7 +329,6 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope, m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), module_name, m_compiler->getCodeGenOpts(), - m_compiler->getTargetOpts(), *m_llvm_context)); } diff --git a/source/Expression/ClangModulesDeclVendor.cpp b/source/Expression/ClangModulesDeclVendor.cpp index 46adaaff33ce..0800b52e7e99 100644 --- a/source/Expression/ClangModulesDeclVendor.cpp +++ b/source/Expression/ClangModulesDeclVendor.cpp @@ -7,8 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Core/StreamString.h" +#include <mutex> // std::once + #include "lldb/Expression/ClangModulesDeclVendor.h" + +#include "lldb/Core/StreamString.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -22,7 +25,6 @@ #include "clang/Sema/Lookup.h" #include "clang/Serialization/ASTReader.h" -#include <mutex> using namespace lldb_private; @@ -289,7 +291,7 @@ ClangModulesDeclVendor::Create(Target &target) "-Werror=non-modular-include-in-framework-module" }; - target.GetPlatform()->AddClangModuleCompilationOptions(compiler_invocation_arguments); + target.GetPlatform()->AddClangModuleCompilationOptions(&target, compiler_invocation_arguments); compiler_invocation_arguments.push_back(ModuleImportBufferName); diff --git a/source/Expression/ExpressionSourceCode.cpp b/source/Expression/ExpressionSourceCode.cpp index 080562e51e91..b3f335f1b314 100644 --- a/source/Expression/ExpressionSourceCode.cpp +++ b/source/Expression/ExpressionSourceCode.cpp @@ -41,13 +41,17 @@ typedef __UINTPTR_TYPE__ uintptr_t; typedef __SIZE_TYPE__ size_t; typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef unsigned short unichar; +extern "C" +{ + int printf(const char * __restrict, ...); +} )"; bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method, ExecutionContext &exe_ctx) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; - static ConstString g_platform_ios_simulator ("PlatformiOSSimulator"); + static ConstString g_platform_ios_simulator ("ios-simulator"); if (Target *target = exe_ctx.GetTargetPtr()) { diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp index e7cb728778e6..9ca9e25907b6 100644 --- a/source/Expression/IRExecutionUnit.cpp +++ b/source/Expression/IRExecutionUnit.cpp @@ -199,28 +199,8 @@ IRExecutionUnit::DisassembleFunction (Stream &stream, disassembler_sp->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false, false); InstructionList &instruction_list = disassembler_sp->GetInstructionList(); - const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize(); - const char *disassemble_format = "${addr-file-or-load}: "; - if (exe_ctx.HasTargetScope()) - { - disassemble_format = exe_ctx.GetTargetRef().GetDebugger().GetDisassemblyFormat(); - } - - for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize(); - instruction_index < num_instructions; - ++instruction_index) - { - Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get(); - instruction->Dump (&stream, - max_opcode_byte_size, - true, - true, - &exe_ctx, - NULL, - NULL, - disassemble_format); - stream.PutChar('\n'); - } + instruction_list.Dump(&stream, true, true, &exe_ctx); + // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions. // I'll fix that but for now, just clear the list and it will go away nicely. disassembler_sp->GetInstructionList().Clear(); @@ -239,6 +219,12 @@ static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, void *Con } void +IRExecutionUnit::ReportSymbolLookupError(const ConstString &name) +{ + m_failed_lookups.push_back(name); +} + +void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr, lldb::addr_t &func_end) @@ -369,6 +355,33 @@ IRExecutionUnit::GetRunnableInfo(Error &error, ReportAllocations(*m_execution_engine_ap); WriteData(process_sp); + if (m_failed_lookups.size()) + { + StreamString ss; + + ss.PutCString("Couldn't lookup symbols:\n"); + + bool emitNewLine = false; + + for (const ConstString &failed_lookup : m_failed_lookups) + { + if (emitNewLine) + ss.PutCString("\n"); + emitNewLine = true; + ss.PutCString(" "); + ss.PutCString(Mangled(failed_lookup).GetDemangledName().AsCString()); + } + + m_failed_lookups.clear(); + + error.SetErrorString(ss.GetData()); + + return; + } + + m_function_load_addr = LLDB_INVALID_ADDRESS; + m_function_end_load_addr = LLDB_INVALID_ADDRESS; + for (JittedFunction &jitted_function : m_jitted_functions) { jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr); @@ -604,6 +617,114 @@ IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size, return return_value; } +uint64_t +IRExecutionUnit::MemoryManager::getSymbolAddress(const std::string &Name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + + SymbolContextList sc_list; + + ExecutionContextScope *exe_scope = m_parent.GetBestExecutionContextScope(); + + lldb::TargetSP target_sp = exe_scope->CalculateTarget(); + + const char *name = Name.c_str(); + + ConstString bare_name_cs(name); + ConstString name_cs; + + if (name[0] == '_') + name_cs = ConstString(name + 1); + + if (!target_sp) + { + if (log) + log->Printf("IRExecutionUnit::getSymbolAddress(Name=\"%s\") = <no target>", + Name.c_str()); + + m_parent.ReportSymbolLookupError(name_cs); + + return 0xbad0bad0; + } + + uint32_t num_matches = 0; + lldb::ProcessSP process_sp = exe_scope->CalculateProcess(); + + if (!name_cs.IsEmpty()) + { + target_sp->GetImages().FindSymbolsWithNameAndType(name_cs, lldb::eSymbolTypeAny, sc_list); + num_matches = sc_list.GetSize(); + } + + if (!num_matches) + { + target_sp->GetImages().FindSymbolsWithNameAndType(bare_name_cs, lldb::eSymbolTypeAny, sc_list); + num_matches = sc_list.GetSize(); + } + + lldb::addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; + + for (uint32_t i=0; i<num_matches && (symbol_load_addr == 0 || symbol_load_addr == LLDB_INVALID_ADDRESS); i++) + { + SymbolContext sym_ctx; + sc_list.GetContextAtIndex(i, sym_ctx); + + if (sym_ctx.symbol->GetType() == lldb::eSymbolTypeUndefined) + continue; + + const Address *sym_address = &sym_ctx.symbol->GetAddress(); + + if (!sym_address || !sym_address->IsValid()) + continue; + + symbol_load_addr = sym_ctx.symbol->ResolveCallableAddress(*target_sp); + + if (symbol_load_addr == LLDB_INVALID_ADDRESS) + { + symbol_load_addr = sym_ctx.symbol->GetAddress().GetLoadAddress(target_sp.get()); + } + } + + if (symbol_load_addr == LLDB_INVALID_ADDRESS && process_sp && name_cs) + { + // Try the Objective-C language runtime. + + ObjCLanguageRuntime *runtime = process_sp->GetObjCLanguageRuntime(); + + if (runtime) + symbol_load_addr = runtime->LookupRuntimeSymbol(name_cs); + } + + if (symbol_load_addr == LLDB_INVALID_ADDRESS) + { + if (log) + log->Printf("IRExecutionUnit::getSymbolAddress(Name=\"%s\") = <not found>", + name); + + m_parent.ReportSymbolLookupError(bare_name_cs); + + return 0xbad0bad0; + } + + if (log) + log->Printf("IRExecutionUnit::getSymbolAddress(Name=\"%s\") = %" PRIx64, + name, + symbol_load_addr); + + if (symbol_load_addr == 0) + return 0xbad00add; + + return symbol_load_addr; +} + +void * +IRExecutionUnit::MemoryManager::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { + assert (sizeof(void *) == 8); + + return (void*)getSymbolAddress(Name); +} + lldb::addr_t IRExecutionUnit::GetRemoteAddressForLocal (lldb::addr_t local_address) { diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp index 8e75c32183ec..42390b35fdde 100644 --- a/source/Expression/IRForTarget.cpp +++ b/source/Expression/IRForTarget.cpp @@ -590,7 +590,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function) &result_decl->getASTContext()); } - if (m_result_type.GetBitSize() == 0) + if (m_result_type.GetBitSize(nullptr) == 0) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); @@ -617,7 +617,7 @@ IRForTarget::CreateResultVariable (llvm::Function &llvm_function) if (log) log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64, m_result_name.GetCString(), - m_result_type.GetByteSize()); + m_result_type.GetByteSize(nullptr)); // Construct a new result global and set up its metadata @@ -1518,7 +1518,7 @@ IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr) value_type = global_variable->getType(); } - const uint64_t value_size = clang_type.GetByteSize(); + const uint64_t value_size = clang_type.GetByteSize(nullptr); lldb::offset_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull; if (log) diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp index b11921635e5a..f1f2f99eed5e 100644 --- a/source/Expression/Materializer.cpp +++ b/source/Expression/Materializer.cpp @@ -49,7 +49,7 @@ Materializer::AddStructMember (Entity &entity) void Materializer::Entity::SetSizeAndAlignmentFromType (ClangASTType &type) { - m_size = type.GetByteSize(); + m_size = type.GetByteSize(nullptr); uint32_t bit_alignment = type.GetTypeBitAlign(); @@ -780,7 +780,7 @@ public: const lldb::addr_t load_addr = process_address + m_offset; - size_t byte_size = m_type.GetByteSize(); + size_t byte_size = m_type.GetByteSize(nullptr); size_t bit_align = m_type.GetTypeBitAlign(); size_t byte_align = (bit_align + 7) / 8; diff --git a/source/Host/common/Editline.cpp b/source/Host/common/Editline.cpp index b82fbea90c6c..a127d58b2767 100644 --- a/source/Host/common/Editline.cpp +++ b/source/Host/common/Editline.cpp @@ -24,6 +24,20 @@ using namespace lldb_private; using namespace lldb_private::line_editor; +// Workaround for what looks like an OS X-specific issue, but other platforms +// may benefit from something similar if issues arise. The libedit library +// doesn't explicitly initialize the curses termcap library, which it gets away +// with until TERM is set to VT100 where it stumbles over an implementation +// assumption that may not exist on other platforms. The setupterm() function +// would normally require headers that don't work gracefully in this context, so +// the function declaraction has been hoisted here. +#if defined(__APPLE__) +extern "C" { + int setupterm(char *term, int fildes, int *errret); +} +#define USE_SETUPTERM_WORKAROUND +#endif + // Editline uses careful cursor management to achieve the illusion of editing a multi-line block of text // with a single line editor. Preserving this illusion requires fairly careful management of cursor // state. Read and understand the relationship between DisplayInput(), MoveCursor(), SetCurrentLine(), @@ -1313,6 +1327,10 @@ Editline::GetLine (std::string &line, bool &interrupted) m_editor_getting_char = false; m_revert_cursor_index = -1; +#ifdef USE_SETUPTERM_WORKAROUND + setupterm((char *)0, fileno(m_output_file), (int *)0); +#endif + int count; auto input = el_wgets (m_editline, &count); @@ -1359,6 +1377,9 @@ Editline::GetLines (int first_line_number, StringList &lines, bool &interrupted) m_revert_cursor_index = -1; while (m_editor_status == EditorStatus::Editing) { +#ifdef USE_SETUPTERM_WORKAROUND + setupterm((char *)0, fileno(m_output_file), (int *)0); +#endif int count; m_current_line_rows = -1; el_wpush (m_editline, EditLineConstString("\x1b[^")); // Revert to the existing line content diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp index c3c77835ce86..946f3dd6fef5 100644 --- a/source/Host/common/File.cpp +++ b/source/Host/common/File.cpp @@ -288,6 +288,8 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) #ifndef _WIN32 if (options & eOpenOptionNonBlocking) oflag |= O_NONBLOCK; + if (options & eOpenOptionCloseOnExec) + oflag |= O_CLOEXEC; #else oflag |= O_BINARY; #endif @@ -742,8 +744,9 @@ File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP if (num_bytes > bytes_left) num_bytes = bytes_left; + size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); std::unique_ptr<DataBufferHeap> data_heap_ap; - data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0')); + data_heap_ap.reset(new DataBufferHeap(num_bytes_plus_nul_char, '\0')); if (data_heap_ap.get()) { @@ -752,8 +755,8 @@ File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP { // Make sure we read exactly what we asked for and if we got // less, adjust the array - if (num_bytes < data_heap_ap->GetByteSize()) - data_heap_ap->SetByteSize(num_bytes); + if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize()) + data_heap_ap->SetByteSize(num_bytes_plus_nul_char); data_buffer_sp.reset(data_heap_ap.release()); return error; } diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp index 0af0556d30c9..6a6de53cd311 100644 --- a/source/Host/common/FileSpec.cpp +++ b/source/Host/common/FileSpec.cpp @@ -65,7 +65,7 @@ FileSpec::ResolveUsername (llvm::SmallVectorImpl<char> &path) if (path.empty() || path[0] != '~') return; - llvm::StringRef path_str(path.data()); + llvm::StringRef path_str(path.data(), path.size()); size_t slash_pos = path_str.find_first_of("/", 1); if (slash_pos == 1 || path.size() == 1) { @@ -240,6 +240,12 @@ void FileSpec::Normalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) return; std::replace(path.begin(), path.end(), '\\', '/'); + // Windows path can have \\ slashes which can be changed by replace + // call above to //. Here we remove the duplicate. + auto iter = std::unique ( path.begin(), path.end(), + []( char &c1, char &c2 ){ + return (c1 == '/' && c2 == '/');}); + path.erase(iter, path.end()); } void FileSpec::DeNormalize(llvm::SmallVectorImpl<char> &path, PathSyntax syntax) @@ -1330,8 +1336,7 @@ FileSpec::IsSourceImplementationFile () const ConstString extension (GetFileNameExtension()); if (extension) { - static RegularExpression g_source_file_regex ("^(c|m|mm|cpp|c\\+\\+|cxx|cc|cp|s|asm|f|f77|f90|f95|f03|for|ftn|fpp|ada|adb|ads)$", - REG_EXTENDED | REG_ICASE); + static RegularExpression g_source_file_regex ("^([cC]|[mM]|[mM][mM]|[cC][pP][pP]|[cC]\\+\\+|[cC][xX][xX]|[cC][cC]|[cC][pP]|[sS]|[aA][sS][mM]|[fF]|[fF]77|[fF]90|[fF]95|[fF]03|[fF][oO][rR]|[fF][tT][nN]|[fF][pP][pP]|[aA][dD][aA]|[aA][dD][bB]|[aA][dD][sS])$"); return g_source_file_regex.Execute (extension.GetCString()); } return false; diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index c8daa175d1bd..30f5c8683060 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-python.h" - // C includes #include <errno.h> #include <limits.h> @@ -48,20 +46,21 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Core/ArchSpec.h" -#include "lldb/Core/Debugger.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" -#include "lldb/Core/Module.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/HostProcess.h" #include "lldb/Host/MonitoringProcessLauncher.h" +#include "lldb/Host/Predicate.h" #include "lldb/Host/ProcessLauncher.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/lldb-private-forward.h" +#include "llvm/Support/FileSystem.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Target/TargetList.h" +#include "lldb/Target/UnixSignals.h" #include "lldb/Utility/CleanUp.h" +#include "llvm/ADT/SmallString.h" #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" @@ -170,7 +169,7 @@ MonitorChildProcessThreadFunction (void *arg) { log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); if (log) - log->Printf("%s ::wait_pid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options); + log->Printf("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i)...", function, pid, options); // Wait for all child processes #if !defined(__ANDROID__) && !defined(__ANDROID_NDK__) @@ -233,9 +232,9 @@ MonitorChildProcessThreadFunction (void *arg) if (log) log->Printf ("%s ::waitpid (pid = %" PRIi32 ", &status, options = %i) => pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", function, - wait_pid, - options, pid, + options, + wait_pid, status, status_cstr, signal, @@ -1053,12 +1052,6 @@ Host::SetCrashDescription (const char *description) { } -lldb::pid_t -Host::LaunchApplication (const FileSpec &app_file_spec) -{ - return LLDB_INVALID_PROCESS_ID; -} - #endif #if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__NetBSD__) diff --git a/source/Host/common/HostInfoBase.cpp b/source/Host/common/HostInfoBase.cpp index d65b79698384..9816c1ebf080 100644 --- a/source/Host/common/HostInfoBase.cpp +++ b/source/Host/common/HostInfoBase.cpp @@ -23,60 +23,56 @@ #include "llvm/Support/raw_ostream.h" #include <thread> +#include <mutex> // std::once using namespace lldb; using namespace lldb_private; namespace { -void -CleanupProcessSpecificLLDBTempDir() -{ - // Get the process specific LLDB temporary directory and delete it. - FileSpec tmpdir_file_spec; - if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) - return; - - // Remove the LLDB temporary directory if we have one. Set "recurse" to - // true to all files that were created for the LLDB process can be cleaned up. - FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true); -} + void + CleanupProcessSpecificLLDBTempDir() + { + // Get the process specific LLDB temporary directory and delete it. + FileSpec tmpdir_file_spec; + if (!HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + return; + + // Remove the LLDB temporary directory if we have one. Set "recurse" to + // true to all files that were created for the LLDB process can be cleaned up. + FileSystem::DeleteDirectory(tmpdir_file_spec.GetDirectory().GetCString(), true); + } -struct HostInfoBaseFields -{ - uint32_t m_number_cpus; - std::string m_vendor_string; - std::string m_os_string; - std::string m_host_triple; - - ArchSpec m_host_arch_32; - ArchSpec m_host_arch_64; - - FileSpec m_lldb_so_dir; - FileSpec m_lldb_support_exe_dir; - FileSpec m_lldb_headers_dir; - FileSpec m_lldb_python_dir; - FileSpec m_lldb_clang_resource_dir; - FileSpec m_lldb_system_plugin_dir; - FileSpec m_lldb_user_plugin_dir; - FileSpec m_lldb_tmp_dir; -}; - -HostInfoBaseFields *g_fields = nullptr; -} + //---------------------------------------------------------------------- + // The HostInfoBaseFields is a work around for windows not supporting + // static variables correctly in a thread safe way. Really each of the + // variables in HostInfoBaseFields should live in the functions in which + // they are used and each one should be static, but the work around is + // in place to avoid this restriction. Ick. + //---------------------------------------------------------------------- -#define COMPUTE_LLDB_PATH(compute_function, member_var) \ - { \ - static bool is_initialized = false; \ - static bool success = false; \ - if (!is_initialized) \ - { \ - is_initialized = true; \ - success = HostInfo::compute_function(member_var); \ - } \ - if (success) \ - result = &member_var; \ - } + struct HostInfoBaseFields + { + uint32_t m_number_cpus; + std::string m_vendor_string; + std::string m_os_string; + std::string m_host_triple; + + ArchSpec m_host_arch_32; + ArchSpec m_host_arch_64; + + FileSpec m_lldb_so_dir; + FileSpec m_lldb_support_exe_dir; + FileSpec m_lldb_headers_dir; + FileSpec m_lldb_python_dir; + FileSpec m_lldb_clang_resource_dir; + FileSpec m_lldb_system_plugin_dir; + FileSpec m_lldb_user_plugin_dir; + FileSpec m_lldb_tmp_dir; + }; + + HostInfoBaseFields *g_fields = nullptr; +} void HostInfoBase::Initialize() @@ -87,13 +83,10 @@ HostInfoBase::Initialize() uint32_t HostInfoBase::GetNumberCPUS() { - static bool is_initialized = false; - if (!is_initialized) - { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { g_fields->m_number_cpus = std::thread::hardware_concurrency(); - is_initialized = true; - } - + }); return g_fields->m_number_cpus; } @@ -106,53 +99,40 @@ HostInfoBase::GetMaxThreadNameLength() llvm::StringRef HostInfoBase::GetVendorString() { - static bool is_initialized = false; - if (!is_initialized) - { - const ArchSpec &host_arch = HostInfo::GetArchitecture(); - const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName(); - g_fields->m_vendor_string.assign(str_ref.begin(), str_ref.end()); - is_initialized = true; - } + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_vendor_string = std::move(HostInfo::GetArchitecture().GetTriple().getVendorName().str()); + }); return g_fields->m_vendor_string; } llvm::StringRef HostInfoBase::GetOSString() { - static bool is_initialized = false; - if (!is_initialized) - { - const ArchSpec &host_arch = HostInfo::GetArchitecture(); - const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName(); - g_fields->m_os_string.assign(str_ref.begin(), str_ref.end()); - is_initialized = true; - } + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_os_string = std::move(HostInfo::GetArchitecture().GetTriple().getOSName()); + }); return g_fields->m_os_string; } llvm::StringRef HostInfoBase::GetTargetTriple() { - static bool is_initialized = false; - if (!is_initialized) - { - const ArchSpec &host_arch = HostInfo::GetArchitecture(); - g_fields->m_host_triple = host_arch.GetTriple().getTriple(); - is_initialized = true; - } + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_fields->m_host_triple = HostInfo::GetArchitecture().GetTriple().getTriple(); + }); return g_fields->m_host_triple; } const ArchSpec & HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) { - static bool is_initialized = false; - if (!is_initialized) - { + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32, g_fields->m_host_arch_64); - is_initialized = true; - } + }); // If an explicit 32 or 64-bit architecture was requested, return that. if (arch_kind == eArchKind32) @@ -174,52 +154,123 @@ HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) return false; #endif - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); FileSpec *result = nullptr; switch (type) { case lldb::ePathTypeLLDBShlibDir: - COMPUTE_LLDB_PATH(ComputeSharedLibraryDirectory, g_fields->m_lldb_so_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_so_dir; + } break; case lldb::ePathTypeSupportExecutableDir: - COMPUTE_LLDB_PATH(ComputeSupportExeDirectory, g_fields->m_lldb_support_exe_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", - g_fields->m_lldb_support_exe_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", + g_fields->m_lldb_support_exe_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_support_exe_dir; + } break; case lldb::ePathTypeHeaderDir: - COMPUTE_LLDB_PATH(ComputeHeaderDirectory, g_fields->m_lldb_headers_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_headers_dir; + } break; case lldb::ePathTypePythonDir: - COMPUTE_LLDB_PATH(ComputePythonDirectory, g_fields->m_lldb_python_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_python_dir; + } break; case lldb::ePathTypeClangDir: - COMPUTE_LLDB_PATH(ComputeClangDirectory, g_fields->m_lldb_clang_resource_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_clang_resource_dir; + } break; case lldb::ePathTypeLLDBSystemPlugins: - COMPUTE_LLDB_PATH(ComputeSystemPluginsDirectory, g_fields->m_lldb_system_plugin_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", - g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", + g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_system_plugin_dir; + } break; case lldb::ePathTypeLLDBUserPlugins: - COMPUTE_LLDB_PATH(ComputeUserPluginsDirectory, g_fields->m_lldb_user_plugin_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", - g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", + g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_user_plugin_dir; + } break; case lldb::ePathTypeLLDBTempSystemDir: - COMPUTE_LLDB_PATH(ComputeTempFileDirectory, g_fields->m_lldb_tmp_dir) - if (log) - log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str()); + { + static std::once_flag g_once_flag; + static bool success = false; + std::call_once(g_once_flag, []() { + success = HostInfo::ComputeTempFileDirectory (g_fields->m_lldb_tmp_dir); + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) + log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_tmp_dir.GetPath().c_str()); + }); + if (success) + result = &g_fields->m_lldb_tmp_dir; + } break; } @@ -327,6 +378,7 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6 arch_32.SetTriple(triple); break; + case llvm::Triple::ppc64: case llvm::Triple::x86_64: arch_64.SetTriple(triple); arch_32.SetTriple(triple.get32BitArchVariant()); @@ -335,7 +387,6 @@ HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_6 case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::sparcv9: - case llvm::Triple::ppc64: arch_64.SetTriple(triple); break; } diff --git a/source/Host/common/NativeBreakpoint.cpp b/source/Host/common/NativeBreakpoint.cpp index 284d7d11d6ce..622b4eab1726 100644 --- a/source/Host/common/NativeBreakpoint.cpp +++ b/source/Host/common/NativeBreakpoint.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "NativeBreakpoint.h" +#include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/lldb-defines.h" #include "lldb/Core/Error.h" diff --git a/source/Host/common/NativeBreakpointList.cpp b/source/Host/common/NativeBreakpointList.cpp index ecd0624bde09..94d0b3756da4 100644 --- a/source/Host/common/NativeBreakpointList.cpp +++ b/source/Host/common/NativeBreakpointList.cpp @@ -1,4 +1,4 @@ -//===-- NativeBreakpointList.h ----------------------------------*- C++ -*-===// +//===-- NativeBreakpointList.cpp --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "NativeBreakpointList.h" +#include "lldb/Host/common/NativeBreakpointList.h" #include "lldb/Core/Log.h" -#include "NativeBreakpoint.h" +#include "lldb/Host/common/NativeBreakpoint.h" using namespace lldb; using namespace lldb_private; diff --git a/source/Host/common/NativeProcessProtocol.cpp b/source/Host/common/NativeProcessProtocol.cpp index e192f19a8896..ff7310d2d45a 100644 --- a/source/Host/common/NativeProcessProtocol.cpp +++ b/source/Host/common/NativeProcessProtocol.cpp @@ -7,17 +7,17 @@ // //===----------------------------------------------------------------------===// -#include "NativeProcessProtocol.h" +#include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/lldb-enumerations.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" -#include "lldb/Target/NativeRegisterContext.h" +#include "lldb/Host/common/NativeRegisterContext.h" -#include "NativeThreadProtocol.h" -#include "SoftwareBreakpoint.h" +#include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Host/common/SoftwareBreakpoint.h" using namespace lldb; using namespace lldb_private; @@ -39,6 +39,7 @@ NativeProcessProtocol::NativeProcessProtocol (lldb::pid_t pid) : m_delegates_mutex (Mutex::eMutexTypeRecursive), m_delegates (), m_breakpoint_list (), + m_watchpoint_list (), m_terminal_fd (-1), m_stop_id (0) { @@ -159,6 +160,12 @@ NativeProcessProtocol::GetByteOrder (lldb::ByteOrder &byte_order) const return true; } +const NativeWatchpointList::WatchpointMap& +NativeProcessProtocol::GetWatchpointMap () const +{ + return m_watchpoint_list.GetWatchpointMap(); +} + uint32_t NativeProcessProtocol::GetMaxWatchpoints () const { @@ -199,9 +206,6 @@ NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t w Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - // FIXME save the watchpoint on the set of process watchpoint vars - // so we can add them to a thread each time a new thread is registered. - // Update the thread list UpdateThreads (); @@ -261,15 +265,12 @@ NativeProcessProtocol::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t w return thread_error; } } - return Error (); + return m_watchpoint_list.Add (addr, size, watch_flags, hardware); } Error NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) { - // FIXME remove the watchpoint on the set of process watchpoint vars - // so we can add them to a thread each time a new thread is registered. - // Update the thread list UpdateThreads (); @@ -292,7 +293,8 @@ NativeProcessProtocol::RemoveWatchpoint (lldb::addr_t addr) overall_error = thread_error; } } - return overall_error; + const Error error = m_watchpoint_list.Remove(addr); + return overall_error.Fail() ? overall_error : error; } bool @@ -400,6 +402,10 @@ void NativeProcessProtocol::SetState (lldb::StateType state, bool notify_delegates) { Mutex::Locker locker (m_state_mutex); + + if (state == m_state) + return; + m_state = state; if (StateIsStoppedState (state, false)) diff --git a/source/Target/NativeRegisterContext.cpp b/source/Host/common/NativeRegisterContext.cpp index d84e2279a459..42a9c91a63a0 100644 --- a/source/Target/NativeRegisterContext.cpp +++ b/source/Host/common/NativeRegisterContext.cpp @@ -7,15 +7,15 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Target/NativeRegisterContext.h" +#include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" #include "lldb/lldb-private-log.h" -#include "Host/common/NativeProcessProtocol.h" -#include "Host/common/NativeThreadProtocol.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" using namespace lldb; using namespace lldb_private; @@ -297,6 +297,12 @@ NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) return false; } +Error +NativeRegisterContext::ClearAllHardwareWatchpoints () +{ + return Error ("not implemented"); +} + bool NativeRegisterContext::HardwareSingleStep (bool enable) { diff --git a/source/Target/NativeRegisterContextRegisterInfo.cpp b/source/Host/common/NativeRegisterContextRegisterInfo.cpp index e37014546646..0d7c6eced757 100644 --- a/source/Target/NativeRegisterContextRegisterInfo.cpp +++ b/source/Host/common/NativeRegisterContextRegisterInfo.cpp @@ -9,7 +9,7 @@ #include "lldb/lldb-types.h" #include "lldb/lldb-private-forward.h" -#include "lldb/Target/NativeRegisterContextRegisterInfo.h" +#include "lldb/Host/common/NativeRegisterContextRegisterInfo.h" using namespace lldb_private; @@ -28,6 +28,12 @@ NativeRegisterContextRegisterInfo::GetRegisterCount () const return m_register_info_interface_up->GetRegisterCount (); } +uint32_t +NativeRegisterContextRegisterInfo::GetUserRegisterCount () const +{ + return m_register_info_interface_up->GetUserRegisterCount (); +} + const RegisterInfo * NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const { diff --git a/source/Host/common/NativeThreadProtocol.cpp b/source/Host/common/NativeThreadProtocol.cpp index 6cef5b1fa2d2..ea406e9ef2c6 100644 --- a/source/Host/common/NativeThreadProtocol.cpp +++ b/source/Host/common/NativeThreadProtocol.cpp @@ -7,11 +7,11 @@ // //===----------------------------------------------------------------------===// -#include "NativeThreadProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" -#include "NativeProcessProtocol.h" -#include "lldb/Target/NativeRegisterContext.h" -#include "SoftwareBreakpoint.h" +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/common/SoftwareBreakpoint.h" using namespace lldb; using namespace lldb_private; @@ -73,25 +73,3 @@ NativeThreadProtocol::GetProcess () { return m_process_wp.lock (); } - -uint32_t -NativeThreadProtocol::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const -{ - // Default: no translation. Do the real translation where there - // is access to the host signal numbers. - switch (stop_info.reason) - { - case eStopReasonSignal: - return stop_info.details.signal.signo; - break; - - case eStopReasonException: - // FIXME verify the way to specify pass-thru here. - return static_cast<uint32_t> (stop_info.details.exception.type); - break; - - default: - assert (0 && "unexpected stop_info.reason found"); - return 0; - } -} diff --git a/source/Host/common/NativeWatchpointList.cpp b/source/Host/common/NativeWatchpointList.cpp new file mode 100644 index 000000000000..209d213b8e50 --- /dev/null +++ b/source/Host/common/NativeWatchpointList.cpp @@ -0,0 +1,35 @@ +//===-- NativeWatchpointList.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/Host/common/NativeWatchpointList.h" + +#include "lldb/Core/Log.h" + +using namespace lldb; +using namespace lldb_private; + +Error +NativeWatchpointList::Add (addr_t addr, size_t size, uint32_t watch_flags, bool hardware) +{ + m_watchpoints[addr] = {addr, size, watch_flags, hardware}; + return Error (); +} + +Error +NativeWatchpointList::Remove (addr_t addr) +{ + m_watchpoints.erase(addr); + return Error (); +} + +const NativeWatchpointList::WatchpointMap& +NativeWatchpointList::GetWatchpointMap () const +{ + return m_watchpoints; +} diff --git a/source/Host/common/Socket.cpp b/source/Host/common/Socket.cpp index a6118eef7b79..b5559fffb45d 100644 --- a/source/Host/common/Socket.cpp +++ b/source/Host/common/Socket.cpp @@ -15,8 +15,8 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/SocketAddress.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" -#include "lldb/Interpreter/Args.h" #ifdef __ANDROID_NDK__ #include <linux/tcp.h> @@ -190,7 +190,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inhe Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("ConnectionFileDescriptor::SocketListen (%s)", host_and_port.data()); + log->Printf ("Socket::TcpListen (%s)", host_and_port.data()); std::string host_str; std::string port_str; @@ -222,7 +222,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inhe // as port zero is a special code for "find an open port // for me". if (port == 0) - port = listen_socket->GetPortNumber(); + port = listen_socket->GetLocalPortNumber(); // Set the port predicate since when doing a listen://<host>:<port> // it often needs to accept the incoming connection which is a blocking @@ -230,7 +230,7 @@ Error Socket::TcpListen(llvm::StringRef host_and_port, bool child_processes_inhe // us to wait for the port predicate to be set to a non-zero value from // another thread in an efficient manor. if (predicate) - predicate->SetValue(port, eBroadcastAlways); + predicate->SetValue (port, eBroadcastAlways); socket = listen_socket.release(); } @@ -533,13 +533,18 @@ Socket::DecodeHostAndPort(llvm::StringRef host_and_port, if (regex_match.GetMatchAtIndex (host_and_port.data(), 1, host_str) && regex_match.GetMatchAtIndex (host_and_port.data(), 2, port_str)) { - port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN); - if (port != INT32_MIN) + bool ok = false; + port = StringConvert::ToUInt32 (port_str.c_str(), UINT32_MAX, 10, &ok); + if (ok && port < UINT16_MAX) { if (error_ptr) error_ptr->Clear(); return true; } + // port is too large + if (error_ptr) + error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port.data()); + return false; } } @@ -547,10 +552,13 @@ Socket::DecodeHostAndPort(llvm::StringRef host_and_port, // a port with an empty host. host_str.clear(); port_str.clear(); - port = Args::StringToSInt32(host_and_port.data(), INT32_MIN); - if (port != INT32_MIN) + bool ok = false; + port = StringConvert::ToUInt32 (host_and_port.data(), UINT32_MAX, 10, &ok); + if (ok && port < UINT16_MAX) { port_str = host_and_port; + if (error_ptr) + error_ptr->Clear(); return true; } @@ -688,7 +696,7 @@ int Socket::SetOption(int level, int option_name, int option_value) return ::setsockopt(m_socket, level, option_name, option_value_p, sizeof(option_value)); } -uint16_t Socket::GetPortNumber(const NativeSocket& socket) +uint16_t Socket::GetLocalPortNumber(const NativeSocket& socket) { // We bound to port zero, so we need to figure out which port we actually bound to if (socket >= 0) @@ -702,7 +710,47 @@ uint16_t Socket::GetPortNumber(const NativeSocket& socket) } // Return the port number that is being used by the socket. -uint16_t Socket::GetPortNumber() const +uint16_t Socket::GetLocalPortNumber() const { - return GetPortNumber(m_socket); + return GetLocalPortNumber (m_socket); } + +std::string Socket::GetLocalIPAddress () const +{ + // We bound to port zero, so we need to figure out which port we actually bound to + if (m_socket >= 0) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getsockname (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress (); + } + return ""; +} + +uint16_t Socket::GetRemotePortNumber () const +{ + if (m_socket >= 0) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort (); + } + return 0; +} + +std::string Socket::GetRemoteIPAddress () const +{ + // We bound to port zero, so we need to figure out which port we actually bound to + if (m_socket >= 0) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getpeername (m_socket, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetIPAddress (); + } + return ""; +} + + diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp index 6231631934df..fd7fbac952e3 100644 --- a/source/Host/common/SocketAddress.cpp +++ b/source/Host/common/SocketAddress.cpp @@ -21,6 +21,58 @@ // Other libraries and framework includes // Project includes +// WindowsXP needs an inet_ntop implementation +#ifdef _WIN32 + +#ifndef INET6_ADDRSTRLEN // might not be defined in older Windows SDKs +#define INET6_ADDRSTRLEN 46 +#endif + +// TODO: implement shortened form "::" for runs of zeros +const char* inet_ntop(int af, const void * src, + char * dst, socklen_t size) +{ + if (size==0) + { + return nullptr; + } + + switch (af) + { + case AF_INET: + { + { + const char* formatted = inet_ntoa(*static_cast<const in_addr*>(src)); + if (formatted && strlen(formatted) < size) + { + strncpy(dst, formatted, size); + return dst; + } + } + return nullptr; + case AF_INET6: + { + char tmp[INET6_ADDRSTRLEN] = {0}; + const uint16_t* src16 = static_cast<const uint16_t*>(src); + int full_size = _snprintf(tmp, sizeof(tmp), + "%x:%x:%x:%x:%x:%x:%x:%x", + ntohs(src16[0]), ntohs(src16[1]), ntohs(src16[2]), ntohs(src16[3]), + ntohs(src16[4]), ntohs(src16[5]), ntohs(src16[6]), ntohs(src16[7]) + ); + if (full_size < static_cast<int>(size)) + { + strncpy(dst,tmp,size); + return dst; + } + return nullptr; + } + } + } + return nullptr; +} +#endif + + using namespace lldb_private; //---------------------------------------------------------------------- @@ -124,6 +176,26 @@ SocketAddress::SetFamily (sa_family_t family) #endif } +std::string +SocketAddress::GetIPAddress () const +{ + char str[INET6_ADDRSTRLEN] = {0}; + switch (GetFamily()) + { + case AF_INET: + if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv4.sin_addr, str, sizeof(str))) + { + return str; + } + case AF_INET6: + if (inet_ntop(GetFamily(), &m_socket_addr.sa_ipv6.sin6_addr, str, sizeof(str))) + { + return str; + } + } + return ""; +} + uint16_t SocketAddress::GetPort () const { diff --git a/source/Host/common/SoftwareBreakpoint.cpp b/source/Host/common/SoftwareBreakpoint.cpp index d9d1fa67156f..67f472b88f5c 100644 --- a/source/Host/common/SoftwareBreakpoint.cpp +++ b/source/Host/common/SoftwareBreakpoint.cpp @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// -#include "SoftwareBreakpoint.h" +#include "lldb/Host/common/SoftwareBreakpoint.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Host/Debug.h" #include "lldb/Host/Mutex.h" -#include "NativeProcessProtocol.h" +#include "lldb/Host/common/NativeProcessProtocol.h" using namespace lldb_private; diff --git a/source/Host/common/StringConvert.cpp b/source/Host/common/StringConvert.cpp new file mode 100644 index 000000000000..0a8e75f4b877 --- /dev/null +++ b/source/Host/common/StringConvert.cpp @@ -0,0 +1,93 @@ +//===-- StringConvert.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <stdlib.h> + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Host/StringConvert.h" + +namespace lldb_private { + +namespace StringConvert { + +int32_t +ToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = nullptr; + const long sval = ::strtol (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); + return (int32_t)sval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +uint32_t +ToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = nullptr; + const unsigned long uval = ::strtoul (s, &end, base); + if (*end == '\0') + { + if (success_ptr) + *success_ptr = (uval <= UINT32_MAX); + return (uint32_t)uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +int64_t +ToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = nullptr; + int64_t uval = ::strtoll (s, &end, base); + if (*end == '\0') + { + if (success_ptr) *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +uint64_t +ToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) +{ + if (s && s[0]) + { + char *end = nullptr; + uint64_t uval = ::strtoull (s, &end, base); + if (*end == '\0') + { + if (success_ptr) *success_ptr = true; + return uval; // All characters were used, return the result + } + } + if (success_ptr) *success_ptr = false; + return fail_value; +} + +} +} diff --git a/source/Host/common/ThreadLauncher.cpp b/source/Host/common/ThreadLauncher.cpp index ec7da325bf92..c19a23361d81 100644 --- a/source/Host/common/ThreadLauncher.cpp +++ b/source/Host/common/ThreadLauncher.cpp @@ -38,6 +38,16 @@ ThreadLauncher::LaunchThread(llvm::StringRef name, lldb::thread_func_t thread_fu error.SetError(::GetLastError(), eErrorTypeWin32); #else + + // ASAN instrumentation adds a lot of bookkeeping overhead on stack frames. +#if __has_feature(address_sanitizer) + const size_t eight_megabytes = 8 * 1024 * 1024; + if (min_stack_byte_size < eight_megabytes) + { + min_stack_byte_size += eight_megabytes; + } +#endif + pthread_attr_t *thread_attr_ptr = NULL; pthread_attr_t thread_attr; bool destroy_attr = false; diff --git a/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 38ddc0a49220..fe70c33bf5ae 100644 --- a/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -19,6 +19,7 @@ #include "lldb/Host/IOObject.h" #include "lldb/Host/SocketAddress.h" #include "lldb/Host/Socket.h" +#include "lldb/Host/StringConvert.h" // C Includes #include <errno.h> @@ -41,6 +42,7 @@ #include "lldb/lldb-private-log.h" #include "lldb/Core/Communication.h" #include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Socket.h" @@ -142,7 +144,7 @@ ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) if (strstr(s, "listen://") == s) { // listen://HOST:PORT - return SocketListen(s + strlen("listen://"), error_ptr); + return SocketListenAndAccept(s + strlen("listen://"), error_ptr); } else if (strstr(s, "accept://") == s) { @@ -173,7 +175,7 @@ ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) // that is already opened (possibly from a service or other source). s += strlen("fd://"); bool success = false; - int fd = Args::StringToSInt32(s, -1, 0, &success); + int fd = StringConvert::ToSInt32(s, -1, 0, &success); if (success) { @@ -219,6 +221,7 @@ ConnectionFileDescriptor::Connect(const char *s, Error *error_ptr) m_read_sp.reset(new File(fd, false)); m_write_sp.reset(new File(fd, false)); } + m_uri.assign(s); return eConnectionStatusSuccess; } } @@ -351,6 +354,7 @@ ConnectionFileDescriptor::Disconnect(Error *error_ptr) if (error_ptr) *error_ptr = error.Fail() ? error : error2; + m_uri.clear(); m_shutting_down = false; return status; } @@ -510,6 +514,12 @@ ConnectionFileDescriptor::Write(const void *src, size_t src_len, ConnectionStatu return bytes_sent; } +std::string +ConnectionFileDescriptor::GetURI() +{ + return m_uri; +} + // This ConnectionFileDescriptor::BytesAvailable() uses select(). // // PROS: @@ -700,7 +710,12 @@ ConnectionFileDescriptor::NamedSocketAccept(const char *socket_name, Error *erro *error_ptr = error; m_write_sp.reset(socket); m_read_sp = m_write_sp; - return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; + if (error.Fail()) + { + return eConnectionStatusError; + } + m_uri.assign(socket_name); + return eConnectionStatusSuccess; } ConnectionStatus @@ -712,11 +727,16 @@ ConnectionFileDescriptor::NamedSocketConnect(const char *socket_name, Error *err *error_ptr = error; m_write_sp.reset(socket); m_read_sp = m_write_sp; - return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; + if (error.Fail()) + { + return eConnectionStatusError; + } + m_uri.assign(socket_name); + return eConnectionStatusSuccess; } ConnectionStatus -ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr) +ConnectionFileDescriptor::SocketListenAndAccept(const char *s, Error *error_ptr) { m_port_predicate.SetValue(0, eBroadcastNever); @@ -741,7 +761,14 @@ ConnectionFileDescriptor::SocketListen(const char *s, Error *error_ptr) m_write_sp.reset(socket); m_read_sp = m_write_sp; - return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; + if (error.Fail()) + { + return eConnectionStatusError; + } + StreamString strm; + strm.Printf("connect://%s:%u",socket->GetRemoteIPAddress().c_str(), socket->GetRemotePortNumber()); + m_uri.swap(strm.GetString()); + return eConnectionStatusSuccess; } ConnectionStatus @@ -753,7 +780,12 @@ ConnectionFileDescriptor::ConnectTCP(const char *s, Error *error_ptr) *error_ptr = error; m_write_sp.reset(socket); m_read_sp = m_write_sp; - return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; + if (error.Fail()) + { + return eConnectionStatusError; + } + m_uri.assign(s); + return eConnectionStatusSuccess; } ConnectionStatus @@ -766,7 +798,12 @@ ConnectionFileDescriptor::ConnectUDP(const char *s, Error *error_ptr) *error_ptr = error; m_write_sp.reset(send_socket); m_read_sp.reset(recv_socket); - return (error.Success()) ? eConnectionStatusSuccess : eConnectionStatusError; + if (error.Fail()) + { + return eConnectionStatusError; + } + m_uri.assign(s); + return eConnectionStatusSuccess; } uint16_t diff --git a/source/Host/posix/PipePosix.cpp b/source/Host/posix/PipePosix.cpp index 02838ec5124e..1650f1e7979b 100644 --- a/source/Host/posix/PipePosix.cpp +++ b/source/Host/posix/PipePosix.cpp @@ -9,12 +9,16 @@ #include "lldb/Host/posix/PipePosix.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" #include <functional> #include <thread> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> @@ -183,6 +187,37 @@ PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) } Error +PipePosix::CreateWithUniqueName(llvm::StringRef prefix, bool child_process_inherit, llvm::SmallVectorImpl<char>& name) +{ + llvm::SmallString<PATH_MAX> named_pipe_path; + llvm::SmallString<PATH_MAX> pipe_spec((prefix + ".%%%%%%").str()); + FileSpec tmpdir_file_spec; + tmpdir_file_spec.Clear(); + if (HostInfo::GetLLDBPath(ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); + } + else + { + tmpdir_file_spec.AppendPathComponent("/tmp"); + tmpdir_file_spec.AppendPathComponent(pipe_spec.c_str()); + } + + // It's possible that another process creates the target path after we've + // verified it's available but before we create it, in which case we + // should try again. + Error error; + do { + llvm::sys::fs::createUniqueFile(tmpdir_file_spec.GetPath().c_str(), named_pipe_path); + error = CreateNew(named_pipe_path, child_process_inherit); + } while (error.GetError() == EEXIST); + + if (error.Success()) + name = named_pipe_path; + return error; +} + +Error PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit) { if (CanRead() || CanWrite()) diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp index 93933802f57c..4f0219fb858b 100644 --- a/source/Interpreter/Args.cpp +++ b/source/Interpreter/Args.cpp @@ -19,14 +19,13 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Process.h" -//#include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" -//#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; @@ -166,7 +165,7 @@ Args::SetCommandString (const char *command) if (command && command[0]) { static const char *k_space_separators = " \t"; - static const char *k_space_separators_with_slash_and_quotes = " \t \\'\""; + static const char *k_escapable_characters = " \t\\'\""; const char *arg_end = nullptr; const char *arg_pos; for (arg_pos = command; @@ -202,7 +201,7 @@ Args::SetCommandString (const char *command) do { - arg_end = ::strcspn (arg_pos, k_space_separators_with_slash_and_quotes) + arg_pos; + arg_end = ::strcspn (arg_pos, k_escapable_characters) + arg_pos; switch (arg_end[0]) { @@ -216,7 +215,6 @@ Args::SetCommandString (const char *command) arg.append (arg_piece_start); arg_complete = true; break; - case '\\': // Backslash character switch (arg_end[1]) @@ -228,22 +226,21 @@ Args::SetCommandString (const char *command) break; default: - if (quote_char == '\0') + // Only consider this two-character sequence an escape sequence if we're unquoted and + // the character after the backslash is a whitelisted escapable character. Otherwise + // leave the character sequence untouched. + if (quote_char == '\0' && (nullptr != strchr(k_escapable_characters, arg_end[1]))) { arg.append (arg_piece_start, arg_end - arg_piece_start); - if (arg_end[1] != '\0') - { - arg.append (arg_end + 1, 1); - arg_pos = arg_end + 2; - arg_piece_start = arg_pos; - } + arg.append (arg_end + 1, 1); + arg_pos = arg_end + 2; + arg_piece_start = arg_pos; } else arg_pos = arg_end + 2; break; } break; - case '"': case '\'': case '`': @@ -722,77 +719,6 @@ Args::Clear () m_args_quote_char.clear(); } -int32_t -Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - const long sval = ::strtol (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN)); - return (int32_t)sval; // All characters were used, return the result - } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} - -uint32_t -Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - const unsigned long uval = ::strtoul (s, &end, base); - if (*end == '\0') - { - if (success_ptr) - *success_ptr = (uval <= UINT32_MAX); - return (uint32_t)uval; // All characters were used, return the result - } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} - - -int64_t -Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - int64_t uval = ::strtoll (s, &end, base); - if (*end == '\0') - { - if (success_ptr) *success_ptr = true; - return uval; // All characters were used, return the result - } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} - -uint64_t -Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr) -{ - if (s && s[0]) - { - char *end = nullptr; - uint64_t uval = ::strtoull (s, &end, base); - if (*end == '\0') - { - if (success_ptr) *success_ptr = true; - return uval; // All characters were used, return the result - } - } - if (success_ptr) *success_ptr = false; - return fail_value; -} - lldb::addr_t Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr) { @@ -878,7 +804,7 @@ Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::add if (regex_match.GetMatchAtIndex(s, 3, str)) { - offset = Args::StringToUInt64(str.c_str(), 0, 0, &success); + offset = StringConvert::ToUInt64(str.c_str(), 0, 0, &success); if (success) { diff --git a/source/Interpreter/CommandHistory.cpp b/source/Interpreter/CommandHistory.cpp index 26996a625642..bbe64b446acc 100644 --- a/source/Interpreter/CommandHistory.cpp +++ b/source/Interpreter/CommandHistory.cpp @@ -7,8 +7,10 @@ // //===----------------------------------------------------------------------===// +#include <inttypes.h> + #include "lldb/Interpreter/CommandHistory.h" -#include "lldb/Interpreter/Args.h" +#include "lldb/Host/StringConvert.h" using namespace lldb; using namespace lldb_private; @@ -47,7 +49,7 @@ CommandHistory::FindString (const char* input_str) const if (input_str[1] == '-') { bool success; - size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success); + size_t idx = StringConvert::ToUInt32 (input_str+2, 0, 0, &success); if (!success) return nullptr; if (idx > m_history.size()) @@ -66,7 +68,7 @@ CommandHistory::FindString (const char* input_str) const else { bool success; - uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success); + uint32_t idx = StringConvert::ToUInt32 (input_str+1, 0, 0, &success); if (!success) return nullptr; if (idx >= m_history.size()) diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp index 176a1fc9a3b0..6318b80a29ed 100644 --- a/source/Interpreter/CommandInterpreter.cpp +++ b/source/Interpreter/CommandInterpreter.cpp @@ -1170,17 +1170,25 @@ void CommandInterpreter::GetHelp (CommandReturnObject &result, uint32_t cmd_types) { + const char * help_prologue = GetDebugger().GetIOHandlerHelpPrologue(); + if (help_prologue != NULL) + { + OutputFormattedHelpText(result.GetOutputStream(), NULL, help_prologue); + } + CommandObject::CommandMap::const_iterator pos; size_t max_len = FindLongestCommandWord (m_command_dict); if ( (cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin ) { - - result.AppendMessage("The following is a list of built-in, permanent debugger commands:"); + result.AppendMessage("Debugger commands:"); result.AppendMessage(""); for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) { + if (!(cmd_types & eCommandTypesHidden) && (pos->first.compare(0, 1, "_") == 0)) + continue; + OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(), max_len); } @@ -1190,8 +1198,9 @@ CommandInterpreter::GetHelp (CommandReturnObject &result, if (!m_alias_dict.empty() && ( (cmd_types & eCommandTypesAliases) == eCommandTypesAliases )) { - result.AppendMessage("The following is a list of your current command abbreviations " - "(see 'help command alias' for more info):"); + result.AppendMessageWithFormat("Current command abbreviations " + "(type '%shelp command alias' for more info):\n", + GetCommandPrefix()); result.AppendMessage(""); max_len = FindLongestCommandWord (m_alias_dict); @@ -1212,7 +1221,7 @@ CommandInterpreter::GetHelp (CommandReturnObject &result, if (!m_user_dict.empty() && ( (cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef )) { - result.AppendMessage ("The following is a list of your current user-defined commands:"); + result.AppendMessage ("Current user-defined commands:"); result.AppendMessage(""); max_len = FindLongestCommandWord (m_user_dict); for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) @@ -1223,7 +1232,8 @@ CommandInterpreter::GetHelp (CommandReturnObject &result, result.AppendMessage(""); } - result.AppendMessage("For more information on any particular command, try 'help <command-name>'."); + result.AppendMessageWithFormat("For more information on any command, type '%shelp <command-name>'.\n", + GetCommandPrefix()); } CommandObject * @@ -2496,6 +2506,13 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) } } +const char * +CommandInterpreter::GetCommandPrefix() +{ + const char * prefix = GetDebugger().GetIOHandlerCommandPrefix(); + return prefix == NULL ? "" : prefix; +} + PlatformSP CommandInterpreter::GetPlatform (bool prefer_target_platform) { @@ -2887,84 +2904,74 @@ CommandInterpreter::SetSynchronous (bool value) void CommandInterpreter::OutputFormattedHelpText (Stream &strm, - const char *word_text, - const char *separator, - const char *help_text, - size_t max_word_len) + const char *prefix, + const char *help_text) { const uint32_t max_columns = m_debugger.GetTerminalWidth(); - - int indent_size = max_word_len + strlen (separator) + 2; - - strm.IndentMore (indent_size); - - StreamString text_strm; - text_strm.Printf ("%-*s %s %s", (int)max_word_len, word_text, separator, help_text); - - size_t len = text_strm.GetSize(); - const char *text = text_strm.GetData(); - if (text[len - 1] == '\n') - { - text_strm.EOL(); - len = text_strm.GetSize(); - } - - if (len < max_columns) - { - // Output it as a single line. - strm.Printf ("%s", text); - } - else - { - // We need to break it up into multiple lines. - bool first_line = true; - int text_width; - size_t start = 0; - size_t end = start; - const size_t final_end = strlen (text); - - while (end < final_end) - { - if (first_line) - text_width = max_columns - 1; - else - text_width = max_columns - indent_size - 1; - - // Don't start the 'text' on a space, since we're already outputting the indentation. - if (!first_line) + if (prefix == NULL) + prefix = ""; + + size_t prefix_width = strlen(prefix); + size_t line_width_max = max_columns - prefix_width; + const char *help_text_end = help_text + strlen(help_text); + const char *line_start = help_text; + if (line_width_max < 16) + line_width_max = help_text_end - help_text + prefix_width; + + strm.IndentMore (prefix_width); + while (line_start < help_text_end) + { + // Break each line at the first newline or last space/tab before + // the maximum number of characters that fit on a line. Lines with no + // natural break are left unbroken to wrap. + const char *line_end = help_text_end; + const char *line_scan = line_start; + const char *line_scan_end = help_text_end; + while (line_scan < line_scan_end) + { + char next = *line_scan; + if (next == '\t' || next == ' ') { - while ((start < final_end) && (text[start] == ' ')) - start++; + line_end = line_scan; + line_scan_end = line_start + line_width_max; } - - end = start + text_width; - if (end > final_end) - end = final_end; - else + else if (next == '\n' || next == '\0') { - // If we're not at the end of the text, make sure we break the line on white space. - while (end > start - && text[end] != ' ' && text[end] != '\t' && text[end] != '\n') - end--; - assert (end > 0); + line_end = line_scan; + break; } - - const size_t sub_len = end - start; - if (start != 0) - strm.EOL(); - if (!first_line) - strm.Indent(); - else - first_line = false; - assert (start <= final_end); - assert (start + sub_len <= final_end); - if (sub_len > 0) - strm.Write (text + start, sub_len); - start = end + 1; + ++line_scan; } + + // Prefix the first line, indent subsequent lines to line up + if (line_start == help_text) + strm.Write (prefix, prefix_width); + else + strm.Indent(); + strm.Write (line_start, line_end - line_start); + strm.EOL(); + + // When a line breaks at whitespace consume it before continuing + line_start = line_end; + char next = *line_start; + if (next == '\n') + ++line_start; + else while (next == ' ' || next == '\t') + next = *(++line_start); } - strm.EOL(); - strm.IndentLess(indent_size); + strm.IndentLess (prefix_width); +} + +void +CommandInterpreter::OutputFormattedHelpText (Stream &strm, + const char *word_text, + const char *separator, + const char *help_text, + size_t max_word_len) +{ + StreamString prefix_stream; + prefix_stream.Printf (" %-*s %s ", (int)max_word_len, word_text, separator); + OutputFormattedHelpText (strm, prefix_stream.GetData(), help_text); } void @@ -3222,6 +3229,13 @@ CommandInterpreter::IOHandlerInterrupt (IOHandler &io_handler) return true; // Don't do any updating when we are running } } + + ScriptInterpreter *script_interpreter = GetScriptInterpreter (false); + if (script_interpreter) + { + if (script_interpreter->Interrupt()) + return true; + } return false; } diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp index efc7c33fa8f6..bde7f58b4cb0 100644 --- a/source/Interpreter/CommandObjectRegexCommand.cpp +++ b/source/Interpreter/CommandObjectRegexCommand.cpp @@ -111,7 +111,7 @@ CommandObjectRegexCommand::AddRegexCommand (const char *re_cstr, const char *com { m_entries.resize(m_entries.size() + 1); // Only add the regular expression if it compiles - if (m_entries.back().regex.Compile (re_cstr, REG_EXTENDED)) + if (m_entries.back().regex.Compile (re_cstr)) { m_entries.back().command.assign (command_cstr); return true; diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp index 7e5e1245a79f..6bb36552d06b 100644 --- a/source/Interpreter/OptionGroupPlatform.cpp +++ b/source/Interpreter/OptionGroupPlatform.cpp @@ -147,3 +147,38 @@ OptionGroupPlatform::SetOptionValue (CommandInterpreter &interpreter, } return error; } + +bool +OptionGroupPlatform::PlatformMatches(const lldb::PlatformSP &platform_sp) const +{ + if (platform_sp) + { + if (!m_platform_name.empty()) + { + if (platform_sp->GetName() != ConstString(m_platform_name.c_str())) + return false; + } + + if (m_sdk_build && m_sdk_build != platform_sp->GetSDKBuild()) + return false; + + if (m_sdk_sysroot && m_sdk_sysroot != platform_sp->GetSDKRootDirectory()) + return false; + + if (m_os_version_major != UINT32_MAX) + { + uint32_t major, minor, update; + if (platform_sp->GetOSVersion (major, minor, update)) + { + if (m_os_version_major != major) + return false; + if (m_os_version_minor != minor) + return false; + if (m_os_version_update != update) + return false; + } + } + return true; + } + return false; +} diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp index b6c63fa44c40..72d7ff597ab2 100644 --- a/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -16,6 +16,7 @@ // Other libraries and framework includes // Project includes #include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Target/Target.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Utility/Utils.h" @@ -89,13 +90,13 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter, case 'A': ignore_cap = true; break; case 'D': - max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success); + max_depth = StringConvert::ToUInt32 (option_arg, UINT32_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid max depth '%s'", option_arg); break; case 'P': - ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); + ptr_depth = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg); break; @@ -103,7 +104,7 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter, case 'Y': if (option_arg) { - no_summary_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); + no_summary_depth = StringConvert::ToUInt32 (option_arg, 0, 0, &success); if (!success) error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg); } diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp index a08a6127db15..1e4ea23cc075 100644 --- a/source/Interpreter/OptionValue.cpp +++ b/source/Interpreter/OptionValue.cpp @@ -222,6 +222,22 @@ OptionValue::GetAsFormat () const return nullptr; } +OptionValueFormatEntity * +OptionValue::GetAsFormatEntity () +{ + if (GetType () == OptionValue::eTypeFormatEntity) + return static_cast<OptionValueFormatEntity *>(this); + return nullptr; +} + +const OptionValueFormatEntity * +OptionValue::GetAsFormatEntity () const +{ + if (GetType () == OptionValue::eTypeFormatEntity) + return static_cast<const OptionValueFormatEntity *>(this); + return nullptr; +} + OptionValuePathMappings * OptionValue::GetAsPathMappings () { @@ -452,6 +468,15 @@ OptionValue::SetFormatValue (lldb::Format new_value) return false; } +const FormatEntity::Entry * +OptionValue::GetFormatEntity () const +{ + const OptionValueFormatEntity *option_value = GetAsFormatEntity(); + if (option_value) + return &option_value->GetCurrentValue(); + return nullptr; +} + const RegularExpression * OptionValue::GetRegexValue () const { @@ -563,6 +588,7 @@ OptionValue::GetBuiltinTypeAsCString (Type t) case eTypeFileSpec: return "file"; case eTypeFileSpecList: return "file-list"; case eTypeFormat: return "format"; + case eTypeFormatEntity: return "format-string"; case eTypePathMap: return "path-map"; case eTypeProperties: return "properties"; case eTypeRegex: return "regex"; @@ -583,15 +609,16 @@ OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t lldb::OptionValueSP value_sp; switch (type_mask) { - case 1u << eTypeArch: value_sp.reset(new OptionValueArch()); break; - case 1u << eTypeBoolean: value_sp.reset(new OptionValueBoolean(false)); break; - case 1u << eTypeChar: value_sp.reset(new OptionValueChar('\0')); break; - case 1u << eTypeFileSpec: value_sp.reset(new OptionValueFileSpec()); break; - case 1u << eTypeFormat: value_sp.reset(new OptionValueFormat(eFormatInvalid)); break; - case 1u << eTypeSInt64: value_sp.reset(new OptionValueSInt64()); break; - case 1u << eTypeString: value_sp.reset(new OptionValueString()); break; - case 1u << eTypeUInt64: value_sp.reset(new OptionValueUInt64()); break; - case 1u << eTypeUUID: value_sp.reset(new OptionValueUUID()); break; + case 1u << eTypeArch: value_sp.reset(new OptionValueArch()); break; + case 1u << eTypeBoolean: value_sp.reset(new OptionValueBoolean(false)); break; + case 1u << eTypeChar: value_sp.reset(new OptionValueChar('\0')); break; + case 1u << eTypeFileSpec: value_sp.reset(new OptionValueFileSpec()); break; + case 1u << eTypeFormat: value_sp.reset(new OptionValueFormat(eFormatInvalid)); break; + case 1u << eTypeFormatEntity: value_sp.reset(new OptionValueFormatEntity(NULL)); break; + case 1u << eTypeSInt64: value_sp.reset(new OptionValueSInt64()); break; + case 1u << eTypeString: value_sp.reset(new OptionValueString()); break; + case 1u << eTypeUInt64: value_sp.reset(new OptionValueUInt64()); break; + case 1u << eTypeUUID: value_sp.reset(new OptionValueUUID()); break; } if (value_sp) diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp index c0d48c1e7bd2..86d49c9ba3b4 100644 --- a/source/Interpreter/OptionValueArray.cpp +++ b/source/Interpreter/OptionValueArray.cpp @@ -14,6 +14,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Core/Stream.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" using namespace lldb; @@ -97,7 +98,7 @@ OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx, sub_value = end_bracket + 1; std::string index_str (name+1, end_bracket); const size_t array_count = m_values.size(); - int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr); + int32_t idx = StringConvert::ToSInt32(index_str.c_str(), INT32_MAX, 0, nullptr); if (idx != INT32_MAX) { ; @@ -177,7 +178,7 @@ OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) case eVarSetOperationInsertAfter: if (argc > 1) { - uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); + uint32_t idx = StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX); const uint32_t count = GetSize(); if (idx > count) { @@ -225,7 +226,7 @@ OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) for (i=0; i<argc; ++i) { const size_t idx = - Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); + StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX); if (idx >= size) { all_indexes_valid = false; @@ -274,7 +275,7 @@ OptionValueArray::SetArgs (const Args &args, VarSetOperationType op) case eVarSetOperationReplace: if (argc > 1) { - uint32_t idx = Arg |