diff options
author | dim <dim@FreeBSD.org> | 2014-02-26 22:26:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-02-26 22:26:40 +0000 |
commit | 09b56e694e5d4e67943f0d9c4668282053726b9f (patch) | |
tree | c09cd2cd8b06020ff76cb9b8f704cb7490621bcd /contrib/llvm | |
parent | 7d9059111716cc2ad4ad6f2782a9a03edcd2a81f (diff) | |
parent | 6765240e8d836b50e2135e928456ed8923b220ad (diff) | |
download | FreeBSD-src-09b56e694e5d4e67943f0d9c4668282053726b9f.zip FreeBSD-src-09b56e694e5d4e67943f0d9c4668282053726b9f.tar.gz |
Merge from head up to r262536.
Diffstat (limited to 'contrib/llvm')
267 files changed, 19401 insertions, 9389 deletions
diff --git a/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h b/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h index 93bc3bc..b9c3198 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/LLDB.h @@ -33,13 +33,14 @@ #include "lldb/API/SBFrame.h" #include "lldb/API/SBFunction.h" #include "lldb/API/SBHostOS.h" -#include "lldb/API/SBInputReader.h" #include "lldb/API/SBInstruction.h" #include "lldb/API/SBInstructionList.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBListener.h" #include "lldb/API/SBModule.h" #include "lldb/API/SBProcess.h" +#include "lldb/API/SBQueue.h" +#include "lldb/API/SBQueueItem.h" #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h b/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h index c5e8cc6..58a7d2b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBAddress.h @@ -118,6 +118,7 @@ protected: friend class SBTarget; friend class SBThread; friend class SBValue; + friend class SBQueueItem; lldb_private::Address * operator->(); diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBCommandInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/API/SBCommandInterpreter.h index 9b2583c..184a6b4 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBCommandInterpreter.h @@ -122,6 +122,36 @@ public: SBCommandInterpreter (lldb_private::CommandInterpreter *interpreter_ptr = NULL); // Access using SBDebugger::GetCommandInterpreter(); + //---------------------------------------------------------------------- + /// Return true if the command interpreter is the active IO handler. + /// + /// This indicates that any input coming into the debugger handles will + /// go to the command interpreter and will result in LLDB command line + /// commands being executed. + //---------------------------------------------------------------------- + bool + IsActive (); + + //---------------------------------------------------------------------- + /// Get the string that needs to be written to the debugger stdin file + /// handle when a control character is typed. + /// + /// Some GUI programs will intercept "control + char" sequences and want + /// to have them do what normally would happen when using a real + /// terminal, so this function allows GUI programs to emulate this + /// functionality. + /// + /// @param[in] ch + /// The character that was typed along with the control key + /// + /// @return + /// The string that should be written into the file handle that is + /// feeding the input stream for the debugger, or NULL if there is + /// no string for this control key. + //---------------------------------------------------------------------- + const char * + GetIOHandlerControlSequence(char ch); + protected: lldb_private::CommandInterpreter & diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBDebugger.h b/contrib/llvm/tools/lldb/include/lldb/API/SBDebugger.h index 80e6969..2386ffc 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBDebugger.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBDebugger.h @@ -17,6 +17,16 @@ namespace lldb { + +class SBInputReader +{ +public: + SBInputReader(); + ~SBInputReader(); + SBError Initialize(lldb::SBDebugger&, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool); + void SetIsDone(bool); + bool IsActive() const; +}; class SBDebugger { public: @@ -231,12 +241,6 @@ public: void PushInputReader (lldb::SBInputReader &reader); - void - NotifyTopInputReader (lldb::InputReaderAction notification); - - bool - InputReaderIsTopReader (const lldb::SBInputReader &reader); - const char * GetInstanceName (); @@ -313,6 +317,10 @@ public: GetSyntheticForType (SBTypeNameSpecifier); #endif + void + RunCommandInterpreter (bool auto_handle_events, + bool spawn_thread); + private: friend class SBCommandInterpreter; diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h b/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h index 2cdf921..8779d43 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBDefines.h @@ -48,7 +48,6 @@ class SBFileSpecList; class SBFrame; class SBFunction; class SBHostOS; -class SBInputReader; class SBInstruction; class SBInstructionList; class SBLineEntry; diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBError.h b/contrib/llvm/tools/lldb/include/lldb/API/SBError.h index 12b34ec..25d7e81 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBError.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBError.h @@ -71,7 +71,6 @@ protected: friend class SBDebugger; friend class SBCommunication; friend class SBHostOS; - friend class SBInputReader; friend class SBPlatform; friend class SBProcess; friend class SBThread; diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBInputReader.h b/contrib/llvm/tools/lldb/include/lldb/API/SBInputReader.h deleted file mode 100644 index 61f7de4..0000000 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBInputReader.h +++ /dev/null @@ -1,97 +0,0 @@ -//===-- SBInputReader.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_SBInputReader_h_ -#define LLDB_SBInputReader_h_ - -#include "lldb/API/SBDefines.h" - -namespace lldb { - -class SBInputReader -{ -public: - - typedef size_t (*Callback) (void *baton, - SBInputReader *reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - SBInputReader (); - - SBInputReader (const lldb::InputReaderSP &reader_sp); - - SBInputReader (const lldb::SBInputReader &rhs); - - ~SBInputReader (); - - - SBError - Initialize (SBDebugger &debugger, - Callback callback, - void *callback_baton, - lldb::InputReaderGranularity granularity, - const char *end_token, - const char *prompt, - bool echo); - - bool - IsValid () const; - - const lldb::SBInputReader & - operator = (const lldb::SBInputReader &rhs); - - bool - IsActive () const; - - bool - IsDone () const; - - void - SetIsDone (bool value); - - InputReaderGranularity - GetGranularity (); - -protected: - friend class SBDebugger; - - lldb_private::InputReader * - operator->() const; - - lldb::InputReaderSP & - operator *(); - - const lldb::InputReaderSP & - operator *() const; - - lldb_private::InputReader * - get() const; - - lldb_private::InputReader & - ref() const; - -private: - - static size_t - PrivateCallback (void *baton, - lldb_private::InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - lldb::InputReaderSP m_opaque_sp; - Callback m_callback_function; - void *m_callback_baton; -}; - -} // namespace lldb - -#endif // LLDB_SBInputReader_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBModule.h b/contrib/llvm/tools/lldb/include/lldb/API/SBModule.h index f5955b3..e85654b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBModule.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBModule.h @@ -235,6 +235,25 @@ public: lldb::SBTypeList FindTypes (const char* type); + //------------------------------------------------------------------ + /// Get a type using its type ID. + /// + /// Each symbol file reader will assign different user IDs to their + /// types, but it is sometimes useful when debugging type issues to + /// be able to grab a type using its type ID. + /// + /// For DWARF debug info, the type ID is the DIE offset. + /// + /// @param[in] uid + /// The type user ID. + /// + /// @return + /// An SBType for the given type ID, or an empty SBType if the + /// type was not found. + //------------------------------------------------------------------ + lldb::SBType + GetTypeByID (lldb::user_id_t uid); + lldb::SBType GetBasicType(lldb::BasicType type); diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h b/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h index 4ecaeaa..f284671 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBProcess.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDefines.h" #include "lldb/API/SBError.h" #include "lldb/API/SBTarget.h" +#include "lldb/API/SBQueue.h" #include <stdio.h> namespace lldb { @@ -142,6 +143,15 @@ public: SetSelectedThreadByIndexID (uint32_t index_id); //------------------------------------------------------------------ + // Queue related functions + //------------------------------------------------------------------ + uint32_t + GetNumQueues (); + + lldb::SBQueue + GetQueueAtIndex (size_t index); + + //------------------------------------------------------------------ // Stepping related functions //------------------------------------------------------------------ @@ -312,6 +322,7 @@ protected: friend class SBTarget; friend class SBThread; friend class SBValue; + friend class lldb_private::QueueImpl; lldb::ProcessSP GetSP() const; diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBQueue.h b/contrib/llvm/tools/lldb/include/lldb/API/SBQueue.h new file mode 100644 index 0000000..6ab9aa0 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBQueue.h @@ -0,0 +1,83 @@ +//===-- SBQueue.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_SBQueue_h_ +#define LLDB_SBQueue_h_ + +#include <vector> + +#include "lldb/lldb-forward.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBQueueItem.h" + +namespace lldb { + +class SBQueue +{ +public: + SBQueue (); + + SBQueue (const QueueSP& queue_sp); + + SBQueue (const SBQueue& rhs); + + const SBQueue & + operator= (const lldb::SBQueue& rhs); + + ~SBQueue(); + + bool + IsValid() const; + + void + Clear (); + + lldb::SBProcess + GetProcess (); + + lldb::queue_id_t + GetQueueID () const; + + const char * + GetName () const; + + uint32_t + GetIndexID () const; + + uint32_t + GetNumThreads (); + + lldb::SBThread + GetThreadAtIndex (uint32_t); + + uint32_t + GetNumPendingItems (); + + lldb::SBQueueItem + GetPendingItemAtIndex (uint32_t); + +protected: + friend class SBProcess; + + void + SetQueue (const lldb::QueueSP& queue_sp); + + void + FetchThreads (); + + void + FetchItems (); + +private: + std::shared_ptr<lldb_private::QueueImpl> m_opaque_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBQueue_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBQueueItem.h b/contrib/llvm/tools/lldb/include/lldb/API/SBQueueItem.h new file mode 100644 index 0000000..355c5ac --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBQueueItem.h @@ -0,0 +1,58 @@ +//===-- SBQueueItem.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_SBQueueItem_h_ +#define LLDB_SBQueueItem_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBThread.h" + +namespace lldb { + +class SBQueueItem +{ +public: + SBQueueItem (); + + SBQueueItem (const lldb::QueueItemSP& queue_item_sp); + + ~SBQueueItem(); + + bool + IsValid() const; + + void + Clear (); + + lldb::QueueItemKind + GetKind () const; + + void + SetKind (lldb::QueueItemKind kind); + + lldb::SBAddress + GetAddress () const; + + void + SetAddress (lldb::SBAddress addr); + + void + SetQueueItem (const lldb::QueueItemSP& queue_item_sp); + + SBThread + GetExtendedBacktraceThread (const char *type); + +private: + lldb::QueueItemSP m_queue_item_sp; +}; + +} // namespace lldb + +#endif // LLDB_SBQueueItem_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h b/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h index b41c118..230dffc 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBTarget.h @@ -646,9 +646,47 @@ public: void Clear (); + //------------------------------------------------------------------ + /// Resolve a current load address into a section offset address. + /// + /// @param[in] vm_addr + /// A virtual address from the current process state that is to + /// be translated into a section offset address. + /// + /// @return + /// An SBAddress which will be valid if \a vm_addr was + /// successfully resolved into a section offset address, or an + /// invalid SBAddress if \a vm_addr doesn't resolve to a section + /// in a module. + //------------------------------------------------------------------ lldb::SBAddress ResolveLoadAddress (lldb::addr_t vm_addr); + //------------------------------------------------------------------ + /// Resolve a current load address into a section offset address + /// using the process stop ID to identify a time in the past. + /// + /// @param[in] stop_id + /// Each time a process stops, the process stop ID integer gets + /// incremented. These stop IDs are used to identify past times + /// and can be used in history objects as a cheap way to store + /// the time at which the sample was taken. Specifying + /// UINT32_MAX will always resolve the address using the + /// currently loaded sections. + /// + /// @param[in] vm_addr + /// A virtual address from the current process state that is to + /// be translated into a section offset address. + /// + /// @return + /// An SBAddress which will be valid if \a vm_addr was + /// successfully resolved into a section offset address, or an + /// invalid SBAddress if \a vm_addr doesn't resolve to a section + /// in a module. + //------------------------------------------------------------------ + lldb::SBAddress + ResolvePastLoadAddress (uint32_t stop_id, lldb::addr_t vm_addr); + SBSymbolContext ResolveSymbolContextForAddress (const SBAddress& addr, uint32_t resolve_scope); diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBThread.h b/contrib/llvm/tools/lldb/include/lldb/API/SBThread.h index 6542dca..04b6c86 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBThread.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBThread.h @@ -214,6 +214,8 @@ protected: friend class SBProcess; friend class SBDebugger; friend class SBValue; + friend class lldb_private::QueueImpl; + friend class SBQueueItem; void SetThread (const lldb::ThreadSP& lldb_object_sp); diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBType.h b/contrib/llvm/tools/lldb/include/lldb/API/SBType.h index 3729b2f..2cd9b44 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBType.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBType.h @@ -106,6 +106,9 @@ public: GetReferenceType(); lldb::SBType + GetTypedefedType(); + + lldb::SBType GetDereferencedType(); lldb::SBType diff --git a/contrib/llvm/tools/lldb/include/lldb/API/SBTypeFormat.h b/contrib/llvm/tools/lldb/include/lldb/API/SBTypeFormat.h index cd6345f..eb45ff2 100644 --- a/contrib/llvm/tools/lldb/include/lldb/API/SBTypeFormat.h +++ b/contrib/llvm/tools/lldb/include/lldb/API/SBTypeFormat.h @@ -22,6 +22,9 @@ public: SBTypeFormat (lldb::Format format, uint32_t options = 0); // see lldb::eTypeOption values + + SBTypeFormat (const char* type, + uint32_t options = 0); // see lldb::eTypeOption values SBTypeFormat (const lldb::SBTypeFormat &rhs); @@ -33,6 +36,9 @@ public: lldb::Format GetFormat (); + const char* + GetTypeName (); + uint32_t GetOptions(); @@ -40,6 +46,9 @@ public: SetFormat (lldb::Format); void + SetTypeName (const char*); + + void SetOptions (uint32_t); bool @@ -73,8 +82,15 @@ protected: SBTypeFormat (const lldb::TypeFormatImplSP &); + enum class Type + { + eTypeKeepSame, + eTypeFormat, + eTypeEnum + }; + bool - CopyOnWrite_Impl(); + CopyOnWrite_Impl(Type); }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h index e82d6ea..749ff8d 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -612,12 +612,30 @@ protected: /// Only the Target can make a breakpoint, and it owns the breakpoint lifespans. /// The constructor takes a filter and a resolver. Up in Target there are convenience /// variants that make breakpoints for some common cases. + /// + /// @param[in] target + /// The target in which the breakpoint will be set. + /// + /// @param[in] filter_sp + /// Shared pointer to the search filter that restricts the search domain of the breakpoint. + /// + /// @param[in] resolver_sp + /// Shared pointer to the resolver object that will determine breakpoint matches. + /// + /// @param hardware + /// If true, request a hardware breakpoint to be used to implement the breakpoint locations. + /// + /// @param resolve_indirect_symbols + /// If true, and the address of a given breakpoint location in this breakpoint is set on an + /// indirect symbol (i.e. Symbol::IsIndirect returns true) then the actual breakpoint site will + /// be set on the target of the indirect symbol. //------------------------------------------------------------------ // This is the generic constructor Breakpoint(Target &target, lldb::SearchFilterSP &filter_sp, lldb::BreakpointResolverSP &resolver_sp, - bool hardware); + bool hardware, + bool resolve_indirect_symbols = true); friend class BreakpointLocation; // To call the following two when determining whether to stop. @@ -643,6 +661,7 @@ private: BreakpointOptions m_options; // Settable breakpoint options BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. std::string m_kind_description; + bool m_resolve_indirect_symbols; void SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind); diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h index f4ba21a..ac4c28b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -321,7 +321,59 @@ public: //------------------------------------------------------------------ bool InvokeCallback (StoppointCallbackContext *context); + + //------------------------------------------------------------------ + /// Returns whether we should resolve Indirect functions in setting the breakpoint site + /// for this location. + /// + /// @return + /// \b true if the breakpoint SITE for this location should be set on the + /// resolved location for Indirect functions. + //------------------------------------------------------------------ + bool + ShouldResolveIndirectFunctions () + { + return m_should_resolve_indirect_functions; + } + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint site for this location was found by resolving + /// an indirect symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool + IsIndirect () + { + return m_is_indirect; + } + + void + SetIsIndirect (bool is_indirect) + { + m_is_indirect = is_indirect; + } + + //------------------------------------------------------------------ + /// Returns whether the address set in the breakpoint location was re-routed to the target of a + /// re-exported symbol. + /// + /// @return + /// \b true or \b false as given in the description above. + //------------------------------------------------------------------ + bool + IsReExported () + { + return m_is_reexported; + } + + void + SetIsReExported (bool is_reexported) + { + m_is_reexported = is_reexported; + } + protected: friend class BreakpointLocationList; friend class Process; @@ -375,12 +427,16 @@ private: Breakpoint &owner, const Address &addr, lldb::tid_t tid, - bool hardware); - + bool hardware, + bool check_for_resolver = true); + //------------------------------------------------------------------ // Data members: //------------------------------------------------------------------ bool m_being_created; + bool m_should_resolve_indirect_functions; + bool m_is_reexported; + bool m_is_indirect; Address m_address; ///< The address defining this location. Breakpoint &m_owner; ///< The breakpoint that produced this object. std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options. @@ -390,6 +446,12 @@ private: size_t m_condition_hash; ///< For testing whether the condition source code changed. void + SetShouldResolveIndirectFunctions (bool do_resolve) + { + m_should_resolve_indirect_functions = do_resolve; + } + + void SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind); DISALLOW_COPY_AND_ASSIGN (BreakpointLocation); diff --git a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocationList.h b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocationList.h index b252086..ec34641 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocationList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Breakpoint/BreakpointLocationList.h @@ -236,7 +236,7 @@ protected: /// Returns breakpoint location id. //------------------------------------------------------------------ lldb::BreakpointLocationSP - Create (const Address &addr); + Create (const Address &addr, bool resolve_indirect_symbols); void StartRecordingNewLocations(BreakpointLocationCollection &new_locations); @@ -246,6 +246,7 @@ protected: lldb::BreakpointLocationSP AddLocation (const Address &addr, + bool resolve_indirect_symbols, bool *new_location = NULL); bool diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h b/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h index 7f2fd77..1ccb385 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/ArchSpec.h @@ -13,6 +13,7 @@ #if defined(__cplusplus) #include "lldb/lldb-private.h" +#include "lldb/Core/ConstString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -90,6 +91,11 @@ public: eCore_x86_32_i486sx, eCore_x86_64_x86_64, + eCore_x86_64_x86_64h, // Haswell enabled x86_64 + eCore_hexagon_generic, + eCore_hexagon_hexagonv4, + eCore_hexagon_hexagonv5, + eCore_uknownMach32, eCore_uknownMach64, kNumCores, @@ -101,6 +107,7 @@ public: kCore_ppc_any, kCore_ppc64_any, kCore_x86_32_any, + kCore_hexagon_any, kCore_arm_first = eCore_arm_generic, kCore_arm_last = eCore_arm_xscale, @@ -115,7 +122,10 @@ public: kCore_ppc64_last = eCore_ppc64_ppc970_64, kCore_x86_32_first = eCore_x86_32_i386, - kCore_x86_32_last = eCore_x86_32_i486sx + kCore_x86_32_last = eCore_x86_32_i486sx, + + kCore_hexagon_first = eCore_hexagon_generic, + kCore_hexagon_last = eCore_hexagon_hexagonv5 }; //------------------------------------------------------------------ @@ -203,6 +213,27 @@ public: GetMachine () const; //------------------------------------------------------------------ + /// Returns the distribution id of the architecture. + /// + /// This will be something like "ubuntu", "fedora", etc. on Linux. + /// + /// @return A ConstString ref containing the distribution id, + /// potentially empty. + //------------------------------------------------------------------ + const ConstString& + GetDistributionId () const; + + //------------------------------------------------------------------ + /// Set the distribution id of the architecture. + /// + /// This will be something like "ubuntu", "fedora", etc. on Linux. + /// This should be the same value returned by + /// Host::GetDistributionId (). + ///------------------------------------------------------------------ + void + SetDistributionId (const char* distribution_id); + + //------------------------------------------------------------------ /// Tests if this ArchSpec is valid. /// /// @return True if the current architecture is valid, false @@ -400,6 +431,8 @@ protected: Core m_core; lldb::ByteOrder m_byte_order; + ConstString m_distribution_id; + // Called when m_def or m_entry are changed. Fills in all remaining // members with default values. void diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h b/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h index 98d4dfd..2dde550 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Communication.h @@ -286,6 +286,8 @@ public: virtual bool StopReadThread (Error *error_ptr = NULL); + virtual bool + JoinReadThread (Error *error_ptr = NULL); //------------------------------------------------------------------ /// Checks if there is a currently running read thread. /// diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ConnectionFileDescriptor.h b/contrib/llvm/tools/lldb/include/lldb/Core/ConnectionFileDescriptor.h index 3a2f0dd..15598c9 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/ConnectionFileDescriptor.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/ConnectionFileDescriptor.h @@ -11,9 +11,7 @@ #define liblldb_ConnectionFileDescriptor_h_ // C Includes -#ifdef _WIN32 -typedef unsigned short in_port_t; -#else +#ifndef _WIN32 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> @@ -68,14 +66,17 @@ public: // If the read file descriptor is a socket, then return // the port number that is being used by the socket. - in_port_t + uint16_t GetReadPort () const; // If the write file descriptor is a socket, then return // the port number that is being used by the socket. - in_port_t + uint16_t GetWritePort () const; + uint16_t + GetBoundPort (uint32_t timeout_sec); + protected: typedef enum @@ -95,7 +96,7 @@ protected: BytesAvailable (uint32_t timeout_usec, Error *error_ptr); lldb::ConnectionStatus - SocketListen (uint16_t listen_port_num, Error *error_ptr); + SocketListen (const char *host_and_port, Error *error_ptr); lldb::ConnectionStatus ConnectTCP (const char *host_and_port, Error *error_ptr); @@ -117,15 +118,16 @@ protected: FDType m_fd_send_type; FDType m_fd_recv_type; std::unique_ptr<SocketAddress> m_udp_send_sockaddr; - bool m_should_close_fd; // True if this class should close the file descriptor when it goes away. uint32_t m_socket_timeout_usec; int m_pipe_read; // A pipe that we select on the reading end of along with int m_pipe_write; // m_fd_recv so we can force ourselves out of the select. - Mutex m_mutex; + Mutex m_mutex; + Predicate<uint16_t> m_port_predicate; // Used when binding to port zero to wait for the thread that creates the socket, binds and listens to resolve the port number + bool m_should_close_fd; // True if this class should close the file descriptor when it goes away. bool m_shutting_down; // This marks that we are shutting down so if we get woken up from BytesAvailable // to disconnect, we won't try to read again. - static in_port_t + static uint16_t GetSocketPort (int fd); static int diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h b/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h index a3c6d5e..e80ec85 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Debugger.h @@ -19,9 +19,8 @@ #include "lldb/lldb-public.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Communication.h" -#include "lldb/Core/InputReaderStack.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Core/Listener.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/SourceManager.h" #include "lldb/Core/UserID.h" #include "lldb/Core/UserSettingsController.h" @@ -91,23 +90,25 @@ public: void SetAsyncExecution (bool async); - File & + lldb::StreamFileSP GetInputFile () { - return m_input_file.GetFile(); + return m_input_file_sp; } - File & + lldb::StreamFileSP GetOutputFile () { - return m_output_file.GetFile(); + return m_output_file_sp; } - File & + lldb::StreamFileSP GetErrorFile () { - return m_error_file.GetFile(); + return m_error_file_sp; } + + void SetInputFileHandle (FILE *fh, bool tranfer_ownership); @@ -124,18 +125,6 @@ public: void RestoreInputTerminalState(); - Stream& - GetOutputStream () - { - return m_output_file; - } - - Stream& - GetErrorStream () - { - return m_error_file; - } - lldb::StreamSP GetAsyncOutputStream (); @@ -200,24 +189,38 @@ public: void DispatchInputEndOfFile (); + //------------------------------------------------------------------ + // If any of the streams are not set, set them to the in/out/err + // stream of the top most input reader to ensure they at least have + // something + //------------------------------------------------------------------ void - DispatchInput (const char *bytes, size_t bytes_len); + AdoptTopIOHandlerFilesIfInvalid (lldb::StreamFileSP &in, + lldb::StreamFileSP &out, + lldb::StreamFileSP &err); void - WriteToDefaultReader (const char *bytes, size_t bytes_len); + PushIOHandler (const lldb::IOHandlerSP& reader_sp); + bool + PopIOHandler (const lldb::IOHandlerSP& reader_sp); + + // Synchronously run an input reader until it is done void - PushInputReader (const lldb::InputReaderSP& reader_sp); + RunIOHandler (const lldb::IOHandlerSP& reader_sp); + + bool + IsTopIOHandler (const lldb::IOHandlerSP& reader_sp); + + ConstString + GetTopIOHandlerControlSequence(char ch); bool - PopInputReader (const lldb::InputReaderSP& reader_sp); + HideTopIOHandler(); void - NotifyTopInputReader (lldb::InputReaderAction notification); + RefreshTopIOHandler(); - bool - InputReaderIsTopReader (const lldb::InputReaderSP& reader_sp); - static lldb::DebuggerSP FindDebuggerWithID (lldb::user_id_t id); @@ -240,7 +243,7 @@ public: void - CleanUpInputReaders (); + ClearIOHandlers (); static int TestDebuggerRefCount (); @@ -338,29 +341,65 @@ public: bool LoadPlugin (const FileSpec& spec, Error& error); + void + ExecuteIOHanders(); + + bool + IsForwardingEvents (); + + void + EnableForwardEvents (const lldb::ListenerSP &listener_sp); + + void + CancelForwardEvents (const lldb::ListenerSP &listener_sp); protected: - static void - DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len); + friend class CommandInterpreter; + + bool + StartEventHandlerThread(); - lldb::InputReaderSP - GetCurrentInputReader (); - void - ActivateInputReader (const lldb::InputReaderSP &reader_sp); + StopEventHandlerThread(); + + static lldb::thread_result_t + EventHandlerThread (lldb::thread_arg_t arg); bool - CheckIfTopInputReaderIsDone (); + StartIOHandlerThread(); + + void + StopIOHandlerThread(); + static lldb::thread_result_t + IOHandlerThread (lldb::thread_arg_t arg); + + void + DefaultEventHandler(); + + void + HandleBreakpointEvent (const lldb::EventSP &event_sp); + + void + HandleProcessEvent (const lldb::EventSP &event_sp); + + void + HandleThreadEvent (const lldb::EventSP &event_sp); + + size_t + GetProcessSTDOUT (Process *process, Stream *stream); + + size_t + GetProcessSTDERR (Process *process, Stream *stream); + SourceManager::SourceFileCache & GetSourceFileCache () { return m_source_file_cache; } - Communication m_input_comm; - StreamFile m_input_file; - StreamFile m_output_file; - StreamFile m_error_file; + lldb::StreamFileSP m_input_file_sp; + lldb::StreamFileSP m_output_file_sp; + lldb::StreamFileSP m_error_file_sp; TerminalState m_terminal_state; TargetList m_target_list; PlatformList m_platform_list; @@ -370,8 +409,7 @@ protected: // source file cache. std::unique_ptr<CommandInterpreter> m_command_interpreter_ap; - InputReaderStack m_input_reader_stack; - std::string m_input_reader_data; + IOHandlerStack m_input_reader_stack; typedef std::map<std::string, lldb::StreamWP> LogStreamMap; LogStreamMap m_log_streams; lldb::StreamSP m_log_callback_stream_sp; @@ -379,7 +417,10 @@ protected: static LoadPluginCallbackType g_load_plugin_callback; typedef std::vector<lldb::DynamicLibrarySP> LoadedPluginsList; LoadedPluginsList m_loaded_plugins; - + lldb::thread_t m_event_handler_thread; + lldb::thread_t m_io_handler_thread; + lldb::ListenerSP m_forward_listener_sp; + bool m_event_handler_thread_alive; void InstanceInitialize (); diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h b/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h index f434d56..06a703b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Disassembler.h @@ -175,6 +175,9 @@ public: uint32_t GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target); + uint32_t + GetIndexOfInstructionAtAddress (const Address &addr); + void Clear(); diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h b/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h new file mode 100644 index 0000000..78d1e74 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Core/IOHandler.h @@ -0,0 +1,662 @@ +//===-- IOHandler.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_IOHandler_h_ +#define liblldb_IOHandler_h_ + +#include <string.h> + +#include <stack> + +#include "lldb/lldb-public.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Flags.h" +#include "lldb/Core/StringList.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Host/Mutex.h" + +namespace curses +{ + class Application; + typedef std::unique_ptr<Application> ApplicationAP; +} + +namespace lldb_private { + + class IOHandler + { + public: + IOHandler (Debugger &debugger); + + IOHandler (Debugger &debugger, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, + uint32_t flags); + + virtual + ~IOHandler (); + + // Each IOHandler gets to run until it is done. It should read data + // from the "in" and place output into "out" and "err and return + // when done. + virtual void + Run () = 0; + + // Hide any characters that have been displayed so far so async + // output can be displayed. Refresh() will be called after the + // output has been displayed. + virtual void + Hide () = 0; + + // Called when the async output has been received in order to update + // the input reader (refresh the prompt and redisplay any current + // line(s) that are being edited + virtual void + Refresh () = 0; + + // Called when an input reader should relinquish its control so another + // can be pushed onto the IO handler stack, or so the current IO + // handler can pop itself off the stack + + virtual void + Cancel () = 0; + + // Called when CTRL+C is pressed which usually causes + // Debugger::DispatchInputInterrupt to be called. + + virtual void + Interrupt () = 0; + + virtual void + GotEOF() = 0; + + virtual bool + IsActive () + { + return m_active && !m_done; + } + + virtual void + SetIsDone (bool b) + { + m_done = b; + } + + virtual bool + GetIsDone () + { + return m_done; + } + + virtual void + Activate () + { + m_active = true; + } + + virtual void + Deactivate () + { + m_active = false; + } + + virtual const char * + GetPrompt () + { + // Prompt support isn't mandatory + return NULL; + } + + virtual bool + SetPrompt (const char *prompt) + { + // Prompt support isn't mandatory + return false; + } + + virtual ConstString + GetControlSequence (char ch) + { + return ConstString(); + } + + int + GetInputFD(); + + int + GetOutputFD(); + + int + GetErrorFD(); + + FILE * + GetInputFILE(); + + FILE * + GetOutputFILE(); + + FILE * + GetErrorFILE(); + + lldb::StreamFileSP & + GetInputStreamFile(); + + lldb::StreamFileSP & + GetOutputStreamFile(); + + lldb::StreamFileSP & + GetErrorStreamFile(); + + Debugger & + GetDebugger() + { + return m_debugger; + } + + void * + GetUserData () + { + return m_user_data; + } + + void + SetUserData (void *user_data) + { + m_user_data = user_data; + } + + Flags & + GetFlags () + { + return m_flags; + } + + const Flags & + GetFlags () const + { + return m_flags; + } + + //------------------------------------------------------------------ + /// Check if the input is being supplied interactively by a user + /// + /// This will return true if the input stream is a terminal (tty or + /// pty) and can cause IO handlers to do different things (like + /// for a comfirmation when deleting all breakpoints). + //------------------------------------------------------------------ + bool + GetIsInteractive (); + + //------------------------------------------------------------------ + /// Check if the input is coming from a real terminal. + /// + /// A real terminal has a valid size with a certain number of rows + /// and colums. If this function returns true, then terminal escape + /// sequences are expected to work (cursor movement escape sequences, + /// clearning lines, etc). + //------------------------------------------------------------------ + bool + GetIsRealTerminal (); + + protected: + Debugger &m_debugger; + lldb::StreamFileSP m_input_sp; + lldb::StreamFileSP m_output_sp; + lldb::StreamFileSP m_error_sp; + Flags m_flags; + void *m_user_data; + bool m_done; + bool m_active; + + private: + DISALLOW_COPY_AND_ASSIGN (IOHandler); + }; + + + //------------------------------------------------------------------ + /// A delegate class for use with IOHandler subclasses. + /// + /// The IOHandler delegate is designed to be mixed into classes so + /// they can use an IOHandler subclass to fetch input and notify the + /// object that inherits from this delegate class when a token is + /// received. + //------------------------------------------------------------------ + class IOHandlerDelegate + { + public: + enum class Completion { + None, + LLDBCommand, + Expression + }; + + IOHandlerDelegate (Completion completion = Completion::None) : + m_completion(completion), + m_io_handler_done (false) + { + } + + virtual + ~IOHandlerDelegate() + { + } + + virtual void + IOHandlerActivated (IOHandler &io_handler) + { + } + + virtual int + IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches); + + //------------------------------------------------------------------ + /// Called when a line or lines have been retrieved. + /// + /// This funtion can handle the current line and possibly call + /// IOHandler::SetIsDone(true) when the IO handler is done like when + /// "quit" is entered as a command, of when an empty line is + /// received. It is up to the delegate to determine when a line + /// should cause a IOHandler to exit. + //------------------------------------------------------------------ + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) = 0; + + //------------------------------------------------------------------ + /// Called when a line in \a lines has been updated when doing + /// multi-line input. + /// + /// @return + /// Return an enumeration to indicate the status of the current + /// line: + /// Success - The line is good and should be added to the + /// multiple lines + /// Error - There is an error with the current line and it + /// need to be re-edited before it is acceptable + /// Done - The lines collection is complete and ready to be + /// returned. + //------------------------------------------------------------------ + virtual LineStatus + IOHandlerLinesUpdated (IOHandler &io_handler, + StringList &lines, + uint32_t line_idx, + Error &error) + { + return LineStatus::Done; // Stop getting lines on the first line that is updated + // subclasses should do something more intelligent here. + // This function will not be called on IOHandler objects + // that are getting single lines. + } + + + virtual ConstString + GetControlSequence (char ch) + { + return ConstString(); + } + + protected: + Completion m_completion; // Support for common builtin completions + bool m_io_handler_done; + }; + + //---------------------------------------------------------------------- + // IOHandlerDelegateMultiline + // + // A IOHandlerDelegate that handles terminating multi-line input when + // the last line is equal to "end_line" which is specified in the + // constructor. + //---------------------------------------------------------------------- + class IOHandlerDelegateMultiline : + public IOHandlerDelegate + { + public: + IOHandlerDelegateMultiline (const char *end_line, + Completion completion = Completion::None) : + IOHandlerDelegate (completion), + m_end_line((end_line && end_line[0]) ? end_line : "") + { + } + + virtual + ~IOHandlerDelegateMultiline () + { + } + + virtual ConstString + GetControlSequence (char ch) + { + if (ch == 'd') + return ConstString (m_end_line + "\n"); + return ConstString(); + } + + virtual LineStatus + IOHandlerLinesUpdated (IOHandler &io_handler, + StringList &lines, + uint32_t line_idx, + Error &error) + { + if (line_idx == UINT32_MAX) + { + // Remove the last empty line from "lines" so it doesn't appear + // in our final expression and return true to indicate we are done + // getting lines + lines.PopBack(); + return LineStatus::Done; + } + else if (line_idx + 1 == lines.GetSize()) + { + // The last line was edited, if this line is empty, then we are done + // getting our multiple lines. + if (lines[line_idx] == m_end_line) + return LineStatus::Done; + } + return LineStatus::Success; + } + protected: + const std::string m_end_line; + }; + + + class IOHandlerEditline : public IOHandler + { + public: + IOHandlerEditline (Debugger &debugger, + const char *editline_name, // Used for saving history files + const char *prompt, + bool multi_line, + IOHandlerDelegate &delegate); + + IOHandlerEditline (Debugger &debugger, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, + uint32_t flags, + const char *editline_name, // Used for saving history files + const char *prompt, + bool multi_line, + IOHandlerDelegate &delegate); + + virtual + ~IOHandlerEditline (); + + virtual void + Run (); + + virtual void + Hide (); + + virtual void + Refresh (); + + virtual void + Cancel (); + + virtual void + Interrupt (); + + virtual void + GotEOF(); + + virtual void + Activate () + { + IOHandler::Activate(); + m_delegate.IOHandlerActivated(*this); + } + + virtual ConstString + GetControlSequence (char ch) + { + return m_delegate.GetControlSequence (ch); + } + + virtual const char * + GetPrompt (); + + virtual bool + SetPrompt (const char *prompt); + + bool + GetLine (std::string &line); + + bool + GetLines (StringList &lines); + + private: + static LineStatus + LineCompletedCallback (Editline *editline, + StringList &lines, + uint32_t line_idx, + Error &error, + void *baton); + + static int AutoCompleteCallback (const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches, + void *baton); + + protected: + std::unique_ptr<Editline> m_editline_ap; + IOHandlerDelegate &m_delegate; + std::string m_prompt; + bool m_multi_line; + }; + + class IOHandlerConfirm : + public IOHandlerEditline, + public IOHandlerDelegate + { + public: + IOHandlerConfirm (Debugger &debugger, + const char *prompt, + bool default_response); + + virtual + ~IOHandlerConfirm (); + + bool + GetResponse () const + { + return m_user_response; + } + + virtual int + IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches); + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data); + + protected: + const bool m_default_response; + bool m_user_response; + }; + + class IOHandlerCursesGUI : + public IOHandler + { + public: + IOHandlerCursesGUI (Debugger &debugger); + + virtual + ~IOHandlerCursesGUI (); + + virtual void + Run (); + + virtual void + Hide (); + + virtual void + Refresh (); + + virtual void + Cancel (); + + virtual void + Interrupt (); + + virtual void + GotEOF(); + + virtual void + Activate (); + + virtual void + Deactivate (); + + protected: + curses::ApplicationAP m_app_ap; + }; + + class IOHandlerCursesValueObjectList : + public IOHandler + { + public: + IOHandlerCursesValueObjectList (Debugger &debugger, ValueObjectList &valobj_list); + + virtual + ~IOHandlerCursesValueObjectList (); + + virtual void + Run (); + + virtual void + Hide (); + + virtual void + Refresh (); + + virtual void + Interrupt (); + + virtual void + GotEOF(); + protected: + ValueObjectList m_valobj_list; + }; + + class IOHandlerStack + { + public: + + IOHandlerStack () : + m_stack(), + m_mutex(Mutex::eMutexTypeRecursive), + m_top (NULL) + { + } + + ~IOHandlerStack () + { + } + + size_t + GetSize () const + { + Mutex::Locker locker (m_mutex); + return m_stack.size(); + } + + void + Push (const lldb::IOHandlerSP& sp) + { + if (sp) + { + Mutex::Locker locker (m_mutex); + m_stack.push (sp); + // Set m_top the non-locking IsTop() call + m_top = sp.get(); + } + } + + bool + IsEmpty () const + { + Mutex::Locker locker (m_mutex); + return m_stack.empty(); + } + + lldb::IOHandlerSP + Top () + { + lldb::IOHandlerSP sp; + { + Mutex::Locker locker (m_mutex); + if (!m_stack.empty()) + sp = m_stack.top(); + } + return sp; + } + + void + Pop () + { + Mutex::Locker locker (m_mutex); + if (!m_stack.empty()) + m_stack.pop(); + // Set m_top the non-locking IsTop() call + if (m_stack.empty()) + m_top = NULL; + else + m_top = m_stack.top().get(); + } + + Mutex & + GetMutex() + { + return m_mutex; + } + + bool + IsTop (const lldb::IOHandlerSP &io_handler_sp) const + { + return m_top == io_handler_sp.get(); + } + + ConstString + GetTopIOHandlerControlSequence (char ch) + { + if (m_top) + return m_top->GetControlSequence(ch); + return ConstString(); + } + + protected: + + std::stack<lldb::IOHandlerSP> m_stack; + mutable Mutex m_mutex; + IOHandler *m_top; + + private: + + DISALLOW_COPY_AND_ASSIGN (IOHandlerStack); + }; + +} // namespace lldb_private + +#endif // #ifndef liblldb_IOHandler_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/InputReader.h b/contrib/llvm/tools/lldb/include/lldb/Core/InputReader.h deleted file mode 100644 index fa86e9a..0000000 --- a/contrib/llvm/tools/lldb/include/lldb/Core/InputReader.h +++ /dev/null @@ -1,274 +0,0 @@ -//===-- InputReader.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_InputReader_h_ -#define liblldb_InputReader_h_ - -#include <string.h> - -#include "lldb/lldb-public.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/Core/Error.h" -#include "lldb/Core/StringList.h" -#include "lldb/Host/Predicate.h" - - -namespace lldb_private { - -class InputReader -{ -public: - - typedef size_t (*Callback) (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - struct HandlerData - { - InputReader& reader; - const char *bytes; - size_t bytes_len; - void* baton; - - HandlerData(InputReader& r, - const char* b, - size_t l, - void* t) : - reader(r), - bytes(b), - bytes_len(l), - baton(t) - { - } - - lldb::StreamSP - GetOutStream(); - - bool - GetBatchMode(); - }; - - struct InitializationParameters - { - private: - void* m_baton; - lldb::InputReaderGranularity m_token_size; - char* m_end_token; - char* m_prompt; - bool m_echo; - bool m_save_user_input; - public: - InitializationParameters() : - m_baton(NULL), - m_token_size(lldb::eInputReaderGranularityLine), - m_echo(true), - m_save_user_input(false) - { - SetEndToken("DONE"); - SetPrompt("> "); - } - - InitializationParameters& - SetEcho(bool e) - { - m_echo = e; - return *this; - } - - InitializationParameters& - SetSaveUserInput(bool s) - { - m_save_user_input = s; - return *this; - } - - InitializationParameters& - SetBaton(void* b) - { - m_baton = b; - return *this; - } - - InitializationParameters& - SetGranularity(lldb::InputReaderGranularity g) - { - m_token_size = g; - return *this; - } - - InitializationParameters& - SetEndToken(const char* e) - { - m_end_token = new char[strlen(e)+1]; - ::strcpy(m_end_token,e); - return *this; - } - - InitializationParameters& - SetPrompt(const char* p) - { - m_prompt = new char[strlen(p)+1]; - ::strcpy(m_prompt,p); - return *this; - } - - friend class InputReaderEZ; - - }; - - InputReader (Debugger &debugger); - - virtual - ~InputReader (); - - virtual Error - Initialize (Callback callback, - void *baton, - lldb::InputReaderGranularity token_size, - const char *end_token, - const char *prompt, - bool echo); - - virtual Error Initialize(void* baton, - lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine, - const char* end_token = "DONE", - const char *prompt = "> ", - bool echo = true) - { - return Error("unimplemented"); - } - - virtual Error - Initialize(InitializationParameters& params) - { - return Error("unimplemented"); - } - - // to use these handlers instead of the Callback function, you must subclass - // InputReaderEZ, and redefine the handlers for the events you care about - virtual void - ActivateHandler(HandlerData&) {} - - virtual void - DeactivateHandler(HandlerData&) {} - - virtual void - ReactivateHandler(HandlerData&) {} - - virtual void - AsynchronousOutputWrittenHandler(HandlerData&) {} - - virtual void - GotTokenHandler(HandlerData&) {} - - virtual void - InterruptHandler(HandlerData&) {} - - virtual void - EOFHandler(HandlerData&) {} - - virtual void - DoneHandler(HandlerData&) {} - - bool - IsDone () const - { - return m_done; - } - - void - SetIsDone (bool b) - { - m_done = b; - } - - lldb::InputReaderGranularity - GetGranularity () const - { - return m_granularity; - } - - bool - GetEcho () const - { - return m_echo; - } - - StringList& - GetUserInput() - { - return m_user_input; - } - - virtual bool - GetSaveUserInput() - { - return false; - } - - // Subclasses _can_ override this function to get input as it comes in - // without any granularity - virtual size_t - HandleRawBytes (const char *bytes, size_t bytes_len); - - Debugger & - GetDebugger() - { - return m_debugger; - } - - bool - IsActive () const - { - return m_active; - } - - const char * - GetPrompt () const; - - void - RefreshPrompt(); - - // If you want to read from an input reader synchronously, then just initialize the - // reader and then call WaitOnReaderIsDone, which will return when the reader is popped. - void - WaitOnReaderIsDone (); - - static const char * - GranularityAsCString (lldb::InputReaderGranularity granularity); - -protected: - friend class Debugger; - - void - Notify (lldb::InputReaderAction notification); - - Debugger &m_debugger; - Callback m_callback; - void *m_callback_baton; - std::string m_end_token; - std::string m_prompt; - lldb::InputReaderGranularity m_granularity; - bool m_done; - bool m_echo; - bool m_active; - Predicate<bool> m_reader_done; - StringList m_user_input; - bool m_save_user_input; - -private: - DISALLOW_COPY_AND_ASSIGN (InputReader); - -}; - -} // namespace lldb_private - -#endif // #ifndef liblldb_InputReader_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderEZ.h b/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderEZ.h deleted file mode 100644 index 85561b6..0000000 --- a/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderEZ.h +++ /dev/null @@ -1,87 +0,0 @@ -//===-- InputReaderEZ.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_InputReaderEZ_h_ -#define liblldb_InputReaderEZ_h_ - -#include "lldb/Core/InputReader.h" - -namespace lldb_private { - -class InputReaderEZ : public InputReader -{ - -private: - - static size_t Callback_Impl(void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); -public: - - InputReaderEZ (Debugger &debugger) : - InputReader(debugger) - {} - - virtual - ~InputReaderEZ (); - - using InputReader::Initialize; - virtual Error - Initialize(void* baton, - lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine, - const char* end_token = "DONE", - const char *prompt = "> ", - bool echo = true); - - virtual Error - Initialize(InitializationParameters& params); - - virtual void - ActivateHandler(HandlerData&) {} - - virtual void - DeactivateHandler(HandlerData&) {} - - virtual void - ReactivateHandler(HandlerData&) {} - - virtual void - AsynchronousOutputWrittenHandler(HandlerData&) {} - - virtual void - GotTokenHandler(HandlerData&) {} - - virtual void - InterruptHandler(HandlerData&) {} - - virtual void - EOFHandler(HandlerData&) {} - - virtual void - DoneHandler(HandlerData&) {} - - virtual bool - GetSaveUserInput() - { - return m_save_user_input; - } - -protected: - friend class Debugger; - -private: - DISALLOW_COPY_AND_ASSIGN (InputReaderEZ); - -}; - -} // namespace lldb_private - -#endif // #ifndef liblldb_InputReaderEZ_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderStack.h b/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderStack.h deleted file mode 100644 index a73b97c..0000000 --- a/contrib/llvm/tools/lldb/include/lldb/Core/InputReaderStack.h +++ /dev/null @@ -1,58 +0,0 @@ -//===-- InputReaderStack.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_InputReaderStack_h_ -#define liblldb_InputReaderStack_h_ - -#include <stack> - -#include "lldb/lldb-private.h" -#include "lldb/Host/Mutex.h" - -namespace lldb_private { - -class InputReaderStack -{ -public: - - InputReaderStack (); - - ~InputReaderStack (); - - size_t - GetSize () const; - - void - Push (const lldb::InputReaderSP& reader_sp); - - bool - IsEmpty () const; - - lldb::InputReaderSP - Top (); - - void - Pop (); - - Mutex & - GetStackMutex (); - -protected: - - std::stack<lldb::InputReaderSP> m_input_readers; - mutable Mutex m_input_readers_mutex; - -private: - - DISALLOW_COPY_AND_ASSIGN (InputReaderStack); -}; - -} // namespace lldb_private - -#endif // liblldb_InputReaderStack_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h b/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h index 80d249d..4b77ff1 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/MappedHash.h @@ -382,9 +382,9 @@ public: lldb::offset_t offset = m_header.Read (data, 0); if (offset != LLDB_INVALID_OFFSET && IsValid ()) { - m_hash_indexes = (uint32_t *)data.GetData (&offset, m_header.bucket_count * sizeof(uint32_t)); - m_hash_values = (uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t)); - m_hash_offsets = (uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t)); + m_hash_indexes = (const uint32_t *)data.GetData (&offset, m_header.bucket_count * sizeof(uint32_t)); + m_hash_values = (const uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t)); + m_hash_offsets = (const uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t)); } } @@ -542,9 +542,9 @@ public: protected: // Implementation agnostic information HeaderType m_header; - uint32_t *m_hash_indexes; - uint32_t *m_hash_values; - uint32_t *m_hash_offsets; + const uint32_t *m_hash_indexes; + const uint32_t *m_hash_values; + const uint32_t *m_hash_offsets; }; }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h index cae5a30..5665058 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Module.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Module.h @@ -113,10 +113,18 @@ public: /// @param[in] target /// The target in which to apply the section load addresses. /// - /// @param[in] offset - /// The offset to apply to all file addresses for all top - /// level sections in the object file as each section load - /// address is being set. + /// @param[in] value + /// if \a value_is_offset is true, then value is the offset to + /// apply to all file addresses for all top level sections in + /// the object file as each section load address is being set. + /// If \a value_is_offset is false, then "value" is the new + /// absolute base address for the image. + /// + /// @param[in] value_is_offset + /// If \b true, then \a value is an offset to apply to each + /// file address of each top level section. + /// If \b false, then \a value is the image base address that + /// will be used to rigidly slide all loadable sections. /// /// @param[out] changed /// If any section load addresses were changed in \a target, @@ -133,7 +141,8 @@ public: //------------------------------------------------------------------ bool SetLoadAddress (Target &target, - lldb::addr_t offset, + lldb::addr_t value, + bool value_is_offset, bool &changed); //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h b/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h index fd80231..57b8077 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/Opcode.h @@ -15,7 +15,9 @@ // C++ Includes // Other libraries and framework includes +#include "llvm/Support/MathExtras.h" // Project includes +#include "lldb/Host/Endian.h" #include "lldb/lldb-public.h" namespace lldb @@ -39,31 +41,31 @@ namespace lldb_private { eTypeBytes }; - Opcode () : m_type (eTypeInvalid) + Opcode () : m_byte_order (lldb::eByteOrderInvalid), m_type (eTypeInvalid) { } - Opcode (uint8_t inst) : m_type (eType8) + Opcode (uint8_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType8) { m_data.inst8 = inst; } - Opcode (uint16_t inst) : m_type (eType16) + Opcode (uint16_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType16) { m_data.inst16 = inst; } - Opcode (uint32_t inst) : m_type (eType32) + Opcode (uint32_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType32) { m_data.inst32 = inst; } - Opcode (uint64_t inst) : m_type (eType64) + Opcode (uint64_t inst, lldb::ByteOrder order) : m_byte_order (order), m_type (eType64) { m_data.inst64 = inst; } - Opcode (uint8_t *bytes, size_t length) + Opcode (uint8_t *bytes, size_t length) : m_byte_order (lldb::eByteOrderInvalid) { SetOpcodeBytes (bytes, length); } @@ -71,6 +73,7 @@ namespace lldb_private { void Clear() { + m_byte_order = lldb::eByteOrderInvalid; m_type = Opcode::eTypeInvalid; } Opcode::Type @@ -102,7 +105,7 @@ namespace lldb_private { { case Opcode::eTypeInvalid: break; case Opcode::eType8: return m_data.inst8; - case Opcode::eType16: return m_data.inst16; + case Opcode::eType16: return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; case Opcode::eType16_2: break; case Opcode::eType32: break; case Opcode::eType64: break; @@ -118,9 +121,9 @@ namespace lldb_private { { case Opcode::eTypeInvalid: break; case Opcode::eType8: return m_data.inst8; - case Opcode::eType16: return m_data.inst16; + case Opcode::eType16: return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; case Opcode::eType16_2: // passthrough - case Opcode::eType32: return m_data.inst32; + case Opcode::eType32: return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32; case Opcode::eType64: break; case Opcode::eTypeBytes: break; } @@ -134,48 +137,53 @@ namespace lldb_private { { case Opcode::eTypeInvalid: break; case Opcode::eType8: return m_data.inst8; - case Opcode::eType16: return m_data.inst16; + case Opcode::eType16: return GetEndianSwap() ? llvm::ByteSwap_16(m_data.inst16) : m_data.inst16; case Opcode::eType16_2: // passthrough - case Opcode::eType32: return m_data.inst32; - case Opcode::eType64: return m_data.inst64; + case Opcode::eType32: return GetEndianSwap() ? llvm::ByteSwap_32(m_data.inst32) : m_data.inst32; + case Opcode::eType64: return GetEndianSwap() ? llvm::ByteSwap_64(m_data.inst64) : m_data.inst64; case Opcode::eTypeBytes: break; } return invalid_opcode; } void - SetOpcode8 (uint8_t inst) + SetOpcode8 (uint8_t inst, lldb::ByteOrder order) { m_type = eType8; m_data.inst8 = inst; + m_byte_order = order; } void - SetOpcode16 (uint16_t inst) + SetOpcode16 (uint16_t inst, lldb::ByteOrder order) { m_type = eType16; m_data.inst16 = inst; + m_byte_order = order; } void - SetOpcode16_2 (uint32_t inst) + SetOpcode16_2 (uint32_t inst, lldb::ByteOrder order) { m_type = eType16_2; m_data.inst32 = inst; + m_byte_order = order; } void - SetOpcode32 (uint32_t inst) + SetOpcode32 (uint32_t inst, lldb::ByteOrder order) { m_type = eType32; m_data.inst32 = inst; + m_byte_order = order; } void - SetOpcode64 (uint64_t inst) + SetOpcode64 (uint64_t inst, lldb::ByteOrder order) { m_type = eType64; m_data.inst64 = inst; + m_byte_order = order; } void @@ -187,6 +195,7 @@ namespace lldb_private { m_data.inst.length = length; assert (length < sizeof (m_data.inst.bytes)); memcpy (m_data.inst.bytes, bytes, length); + m_byte_order = lldb::eByteOrderInvalid; } else { @@ -249,6 +258,15 @@ namespace lldb_private { lldb::ByteOrder GetDataByteOrder () const; + bool + GetEndianSwap() const + { + return (m_byte_order == lldb::eByteOrderBig && lldb::endian::InlHostByteOrder() == lldb::eByteOrderLittle) || + (m_byte_order == lldb::eByteOrderLittle && lldb::endian::InlHostByteOrder() == lldb::eByteOrderBig); + } + + lldb::ByteOrder m_byte_order; + Opcode::Type m_type; union { diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h b/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h index b850df7..d8c9ecc 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/SourceManager.h @@ -70,6 +70,15 @@ public: return m_source_map_mod_id; } + const char * + PeekLineData (uint32_t line); + + uint32_t + GetLineLength (uint32_t line, bool include_newline_chars); + + uint32_t + GetNumLines (); + protected: bool @@ -167,11 +176,11 @@ public: uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines); - -protected: - + FileSP GetFile (const FileSpec &file_spec); + +protected: //------------------------------------------------------------------ // Classes that inherit from SourceManager can see and modify these diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h b/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h index 0e3e9ee..a73a956 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/StreamAsynchronousIO.h @@ -13,7 +13,6 @@ #include <string> #include "lldb/Core/Stream.h" -#include "lldb/Core/StreamString.h" namespace lldb_private { @@ -35,7 +34,7 @@ public: private: Broadcaster &m_broadcaster; uint32_t m_broadcast_event_type; - StreamString m_accumulated_data; + std::string m_accumulated_data; }; } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h b/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h index 5503274..b68ab4b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/StringList.h @@ -34,6 +34,9 @@ public: AppendString (const std::string &s); void + AppendString (std::string &&s); + + void AppendString (const char *str); void @@ -51,6 +54,34 @@ public: size_t GetSize () const; + void + SetSize (size_t n) + { + m_strings.resize(n); + } + + size_t + GetMaxStringLength () const; + + std::string & + operator [](size_t idx) + { + // No bounds checking, verify "idx" is good prior to calling this function + return m_strings[idx]; + } + + const std::string & + operator [](size_t idx) const + { + // No bounds checking, verify "idx" is good prior to calling this function + return m_strings[idx]; + } + + void + PopBack () + { + m_strings.pop_back(); + } const char * GetStringAtIndex (size_t idx) const; @@ -64,6 +95,12 @@ public: LongestCommonPrefix (std::string &common_prefix); void + InsertStringAtIndex (size_t idx, const std::string &str); + + void + InsertStringAtIndex (size_t idx, std::string &&str); + + void InsertStringAtIndex (size_t id, const char *str); void @@ -73,11 +110,14 @@ public: RemoveBlankLines (); size_t + SplitIntoLines (const std::string &lines); + + size_t SplitIntoLines (const char *lines, size_t len); std::string CopyList(const char* item_preamble = NULL, - const char* items_sep = "\n"); + const char* items_sep = "\n") const; StringList& operator << (const char* str); diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h index 1ef4216..e2847c7 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObject.h @@ -499,6 +499,10 @@ public: GetValueAsCString (); virtual bool + GetValueAsCString (const lldb_private::TypeFormatImpl& format, + std::string& destination); + + bool GetValueAsCString (lldb::Format format, std::string& destination); @@ -615,7 +619,8 @@ public: DumpPrintableRepresentation (Stream& s, ValueObjectRepresentationStyle val_obj_display = eValueObjectRepresentationStyleSummary, lldb::Format custom_format = lldb::eFormatInvalid, - PrintableRepresentationSpecialCases special = ePrintableRepresentationSpecialCasesAllow); + PrintableRepresentationSpecialCases special = ePrintableRepresentationSpecialCasesAllow, + bool do_dump_error = true); bool GetValueIsValid () const; diff --git a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h index 5bfe40b..6565367 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Core/ValueObjectList.h @@ -75,6 +75,12 @@ public: void Swap (ValueObjectList &value_object_list); + void + Clear () + { + m_value_objects.clear(); + } + protected: typedef std::vector<lldb::ValueObjectSP> collection; //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h index 415ef9b..c53ef95 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h @@ -79,6 +79,9 @@ namespace lldb_private { bool LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::wstring + + bool + LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::shared_ptr<> and std::weak_ptr<> bool ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream); @@ -594,10 +597,11 @@ namespace lldb_private { virtual ~LibcxxVectorBoolSyntheticFrontEnd (); private: + ClangASTType m_bool_type; ExecutionContextRef m_exe_ctx_ref; uint64_t m_count; lldb::addr_t m_base_data_address; - EvaluateExpressionOptions m_options; + std::map<size_t,lldb::ValueObjectSP> m_children; }; SyntheticChildrenFrontEnd* LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP); diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatManager.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatManager.h index 750e530..24ec877 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatManager.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatManager.h @@ -20,7 +20,7 @@ #include "lldb/DataFormatters/FormatCache.h" #include "lldb/DataFormatters/FormatClasses.h" -#include "lldb/DataFormatters/FormatNavigator.h" +#include "lldb/DataFormatters/FormattersContainer.h" #include "lldb/DataFormatters/TypeCategory.h" #include "lldb/DataFormatters/TypeCategoryMap.h" @@ -44,7 +44,7 @@ public: FormatManager (); NamedSummariesMap& - GetNamedSummaryNavigator () + GetNamedSummaryContainer () { return m_named_summaries_map; } diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatNavigator.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h index 1b82776..de838d1 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormatNavigator.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -1,4 +1,4 @@ -//===-- FormatNavigator.h ----------------------------------------*- C++ -*-===// +//===-- FormattersContainer.h ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef lldb_FormatNavigator_h_ -#define lldb_FormatNavigator_h_ +#ifndef lldb_FormattersContainer_h_ +#define lldb_FormattersContainer_h_ // C Includes // C++ Includes @@ -104,7 +104,7 @@ GetValidTypeName_Impl (const ConstString& type) } template<typename KeyType, typename ValueType> -class FormatNavigator; +class FormattersContainer; template<typename KeyType, typename ValueType> class FormatMap @@ -243,13 +243,13 @@ protected: return m_map_mutex; } - friend class FormatNavigator<KeyType, ValueType>; + friend class FormattersContainer<KeyType, ValueType>; friend class FormatManager; }; template<typename KeyType, typename ValueType> -class FormatNavigator +class FormattersContainer { protected: typedef FormatMap<KeyType,ValueType> BackEndType; @@ -260,11 +260,11 @@ public: typedef typename MapType::key_type MapKeyType; typedef typename MapType::mapped_type MapValueType; typedef typename BackEndType::CallbackType CallbackType; - typedef typename std::shared_ptr<FormatNavigator<KeyType, ValueType> > SharedPointer; + typedef typename std::shared_ptr<FormattersContainer<KeyType, ValueType> > SharedPointer; friend class TypeCategoryImpl; - FormatNavigator(std::string name, + FormattersContainer(std::string name, IFormatChangeListener* lst) : m_format_map(lst), m_name(name), @@ -350,7 +350,7 @@ protected: std::string m_name; - DISALLOW_COPY_AND_ASSIGN(FormatNavigator); + DISALLOW_COPY_AND_ASSIGN(FormattersContainer); ConstString m_id_cs; @@ -470,6 +470,7 @@ protected: { for (const FormattersMatchCandidate& candidate : candidates) { + // FIXME: could we do the IsMatch() check first? if (Get(candidate.GetTypeName(),entry)) { if (candidate.IsMatch(entry) == false) @@ -491,4 +492,4 @@ protected: } // namespace lldb_private -#endif // lldb_FormatNavigator_h_ +#endif // lldb_FormattersContainer_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategory.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategory.h index 082395a..491fef2 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategory.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategory.h @@ -19,108 +19,131 @@ #include "lldb/lldb-enumerations.h" #include "lldb/DataFormatters/FormatClasses.h" -#include "lldb/DataFormatters/FormatNavigator.h" +#include "lldb/DataFormatters/FormattersContainer.h" -namespace lldb_private { - class TypeCategoryImpl +namespace lldb_private { + + template <typename FormatterImpl> + class FormatterContainerPair { - private: - typedef FormatNavigator<ConstString, TypeFormatImpl> ValueNavigator; - typedef FormatNavigator<lldb::RegularExpressionSP, TypeFormatImpl> RegexValueNavigator; + public: + typedef FormattersContainer<ConstString, FormatterImpl> ExactMatchContainer; + typedef FormattersContainer<lldb::RegularExpressionSP, FormatterImpl> RegexMatchContainer; - typedef FormatNavigator<ConstString, TypeSummaryImpl> SummaryNavigator; - typedef FormatNavigator<lldb::RegularExpressionSP, TypeSummaryImpl> RegexSummaryNavigator; + typedef typename ExactMatchContainer::MapType ExactMatchMap; + typedef typename RegexMatchContainer::MapType RegexMatchMap; + + typedef typename ExactMatchContainer::MapValueType MapValueType; - typedef FormatNavigator<ConstString, TypeFilterImpl> FilterNavigator; - typedef FormatNavigator<lldb::RegularExpressionSP, TypeFilterImpl> RegexFilterNavigator; + typedef typename ExactMatchContainer::SharedPointer ExactMatchContainerSP; + typedef typename RegexMatchContainer::SharedPointer RegexMatchContainerSP; -#ifndef LLDB_DISABLE_PYTHON - typedef FormatNavigator<ConstString, ScriptedSyntheticChildren> SynthNavigator; - typedef FormatNavigator<lldb::RegularExpressionSP, ScriptedSyntheticChildren> RegexSynthNavigator; -#endif // #ifndef LLDB_DISABLE_PYTHON - - typedef ValueNavigator::MapType ValueMap; - typedef RegexValueNavigator::MapType RegexValueMap; - - typedef SummaryNavigator::MapType SummaryMap; - typedef RegexSummaryNavigator::MapType RegexSummaryMap; + FormatterContainerPair (const char* exact_name, + const char* regex_name, + IFormatChangeListener* clist) : + m_exact_sp(new ExactMatchContainer(std::string(exact_name),clist)), + m_regex_sp(new RegexMatchContainer(std::string(regex_name),clist)) + { + } + + ~FormatterContainerPair () = default; + + ExactMatchContainerSP + GetExactMatch () const + { + return m_exact_sp; + } - typedef FilterNavigator::MapType FilterMap; - typedef RegexFilterNavigator::MapType RegexFilterMap; + RegexMatchContainerSP + GetRegexMatch () const + { + return m_regex_sp; + } + + private: + ExactMatchContainerSP m_exact_sp; + RegexMatchContainerSP m_regex_sp; + }; + class TypeCategoryImpl + { + private: + typedef FormatterContainerPair<TypeFormatImpl> FormatContainer; + typedef FormatterContainerPair<TypeSummaryImpl> SummaryContainer; + typedef FormatterContainerPair<TypeFilterImpl> FilterContainer; + #ifndef LLDB_DISABLE_PYTHON - typedef SynthNavigator::MapType SynthMap; - typedef RegexSynthNavigator::MapType RegexSynthMap; + typedef FormatterContainerPair<ScriptedSyntheticChildren> SynthContainer; #endif // #ifndef LLDB_DISABLE_PYTHON - + public: typedef uint16_t FormatCategoryItems; static const uint16_t ALL_ITEM_TYPES = UINT16_MAX; - typedef ValueNavigator::SharedPointer ValueNavigatorSP; - typedef RegexValueNavigator::SharedPointer RegexValueNavigatorSP; + typedef FormatContainer::ExactMatchContainerSP FormatContainerSP; + typedef FormatContainer::RegexMatchContainerSP RegexFormatContainerSP; - typedef SummaryNavigator::SharedPointer SummaryNavigatorSP; - typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP; + typedef SummaryContainer::ExactMatchContainerSP SummaryContainerSP; + typedef SummaryContainer::RegexMatchContainerSP RegexSummaryContainerSP; - typedef FilterNavigator::SharedPointer FilterNavigatorSP; - typedef RegexFilterNavigator::SharedPointer RegexFilterNavigatorSP; + typedef FilterContainer::ExactMatchContainerSP FilterContainerSP; + typedef FilterContainer::RegexMatchContainerSP RegexFilterContainerSP; #ifndef LLDB_DISABLE_PYTHON - typedef SynthNavigator::SharedPointer SynthNavigatorSP; - typedef RegexSynthNavigator::SharedPointer RegexSynthNavigatorSP; + typedef SynthContainer::ExactMatchContainerSP SynthContainerSP; + typedef SynthContainer::RegexMatchContainerSP RegexSynthContainerSP; #endif // #ifndef LLDB_DISABLE_PYTHON TypeCategoryImpl (IFormatChangeListener* clist, ConstString name); - ValueNavigatorSP - GetValueNavigator () + FormatContainerSP + GetTypeFormatsContainer () { - return ValueNavigatorSP(m_value_nav); + return m_format_cont.GetExactMatch(); } - RegexValueNavigatorSP - GetRegexValueNavigator () + RegexFormatContainerSP + GetRegexTypeFormatsContainer () { - return RegexValueNavigatorSP(m_regex_value_nav); + return m_format_cont.GetRegexMatch(); } - SummaryNavigatorSP - GetSummaryNavigator () + SummaryContainerSP + GetTypeSummariesContainer () { - return SummaryNavigatorSP(m_summary_nav); + return m_summary_cont.GetExactMatch(); } - RegexSummaryNavigatorSP - GetRegexSummaryNavigator () + RegexSummaryContainerSP + GetRegexTypeSummariesContainer () { - return RegexSummaryNavigatorSP(m_regex_summary_nav); + return m_summary_cont.GetRegexMatch(); } - FilterNavigatorSP - GetFilterNavigator () + FilterContainerSP + GetTypeFiltersContainer () { - return FilterNavigatorSP(m_filter_nav); + return m_filter_cont.GetExactMatch(); } - RegexFilterNavigatorSP - GetRegexFilterNavigator () + RegexFilterContainerSP + GetRegexTypeFiltersContainer () { - return RegexFilterNavigatorSP(m_regex_filter_nav); + return m_filter_cont.GetRegexMatch(); } - ValueNavigator::MapValueType + FormatContainer::MapValueType GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp); - SummaryNavigator::MapValueType + SummaryContainer::MapValueType GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp); - FilterNavigator::MapValueType + FilterContainer::MapValueType GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp); #ifndef LLDB_DISABLE_PYTHON - SynthNavigator::MapValueType + SynthContainer::MapValueType GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp); #endif @@ -130,32 +153,32 @@ namespace lldb_private { lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierForSummaryAtIndex (size_t index); - ValueNavigator::MapValueType + FormatContainer::MapValueType GetFormatAtIndex (size_t index); - SummaryNavigator::MapValueType + SummaryContainer::MapValueType GetSummaryAtIndex (size_t index); - FilterNavigator::MapValueType + FilterContainer::MapValueType GetFilterAtIndex (size_t index); lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierForFilterAtIndex (size_t index); #ifndef LLDB_DISABLE_PYTHON - SynthNavigatorSP - GetSyntheticNavigator () + SynthContainerSP + GetTypeSyntheticsContainer () { - return SynthNavigatorSP(m_synth_nav); + return m_synth_cont.GetExactMatch(); } - RegexSynthNavigatorSP - GetRegexSyntheticNavigator () + RegexSynthContainerSP + GetRegexTypeSyntheticsContainer () { - return RegexSynthNavigatorSP(m_regex_synth_nav); + return m_synth_cont.GetRegexMatch(); } - SynthNavigator::MapValueType + SynthContainer::MapValueType GetSyntheticAtIndex (size_t index); lldb::TypeNameSpecifierImplSP @@ -222,18 +245,14 @@ namespace lldb_private { typedef std::shared_ptr<TypeCategoryImpl> SharedPointer; private: - ValueNavigator::SharedPointer m_value_nav; - RegexValueNavigator::SharedPointer m_regex_value_nav; + FormatContainer m_format_cont; - SummaryNavigator::SharedPointer m_summary_nav; - RegexSummaryNavigator::SharedPointer m_regex_summary_nav; + SummaryContainer m_summary_cont; - FilterNavigator::SharedPointer m_filter_nav; - RegexFilterNavigator::SharedPointer m_regex_filter_nav; + FilterContainer m_filter_cont; #ifndef LLDB_DISABLE_PYTHON - SynthNavigator::SharedPointer m_synth_nav; - RegexSynthNavigator::SharedPointer m_regex_synth_nav; + SynthContainer m_synth_cont; #endif // #ifndef LLDB_DISABLE_PYTHON bool m_enabled; @@ -257,18 +276,18 @@ namespace lldb_private { friend class TypeCategoryMap; - friend class FormatNavigator<ConstString, TypeFormatImpl>; - friend class FormatNavigator<lldb::RegularExpressionSP, TypeFormatImpl>; + friend class FormattersContainer<ConstString, TypeFormatImpl>; + friend class FormattersContainer<lldb::RegularExpressionSP, TypeFormatImpl>; - friend class FormatNavigator<ConstString, TypeSummaryImpl>; - friend class FormatNavigator<lldb::RegularExpressionSP, TypeSummaryImpl>; + friend class FormattersContainer<ConstString, TypeSummaryImpl>; + friend class FormattersContainer<lldb::RegularExpressionSP, TypeSummaryImpl>; - friend class FormatNavigator<ConstString, TypeFilterImpl>; - friend class FormatNavigator<lldb::RegularExpressionSP, TypeFilterImpl>; + friend class FormattersContainer<ConstString, TypeFilterImpl>; + friend class FormattersContainer<lldb::RegularExpressionSP, TypeFilterImpl>; #ifndef LLDB_DISABLE_PYTHON - friend class FormatNavigator<ConstString, ScriptedSyntheticChildren>; - friend class FormatNavigator<lldb::RegularExpressionSP, ScriptedSyntheticChildren>; + friend class FormattersContainer<ConstString, ScriptedSyntheticChildren>; + friend class FormattersContainer<lldb::RegularExpressionSP, ScriptedSyntheticChildren>; #endif // #ifndef LLDB_DISABLE_PYTHON }; diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategoryMap.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategoryMap.h index 6bed187..88aaeb2 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategoryMap.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeCategoryMap.h @@ -18,7 +18,7 @@ #include "lldb/lldb-public.h" #include "lldb/lldb-enumerations.h" -#include "lldb/DataFormatters/FormatNavigator.h" +#include "lldb/DataFormatters/FormattersContainer.h" #include "lldb/DataFormatters/TypeCategory.h" namespace lldb_private { @@ -144,7 +144,7 @@ namespace lldb_private { return m_map_mutex; } - friend class FormatNavigator<KeyType, ValueType>; + friend class FormattersContainer<KeyType, ValueType>; friend class FormatManager; }; } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeFormat.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeFormat.h index 77135c4..20fa8f2 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeFormat.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeFormat.h @@ -130,15 +130,12 @@ namespace lldb_private { uint32_t m_flags; }; - TypeFormatImpl (lldb::Format f = lldb::eFormatInvalid, - const Flags& flags = Flags()); + TypeFormatImpl (const Flags& flags = Flags()); typedef std::shared_ptr<TypeFormatImpl> SharedPointer; typedef bool(*ValueCallback)(void*, ConstString, const lldb::TypeFormatImplSP&); - ~TypeFormatImpl () - { - } + virtual ~TypeFormatImpl () = default; bool Cascades () const @@ -173,6 +170,66 @@ namespace lldb_private { { m_flags.SetSkipReferences(value); } + + uint32_t + GetOptions () + { + return m_flags.GetValue(); + } + + void + SetOptions (uint32_t value) + { + m_flags.SetValue(value); + } + + uint32_t& + GetRevision () + { + return m_my_revision; + } + + enum class Type + { + eTypeUnknown, + eTypeFormat, + eTypeEnum + }; + + virtual Type + GetType () + { + return Type::eTypeUnknown; + } + + // we are using a ValueObject* instead of a ValueObjectSP because we do not need to hold on to this for + // extended periods of time and we trust the ValueObject to stay around for as long as it is required + // for us to generate its value + virtual bool + FormatObject (ValueObject *valobj, + std::string& dest) const = 0; + + virtual std::string + GetDescription() = 0; + + protected: + Flags m_flags; + uint32_t m_my_revision; + + private: + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl); + }; + + class TypeFormatImpl_Format : public TypeFormatImpl + { + public: + TypeFormatImpl_Format (lldb::Format f = lldb::eFormatInvalid, + const TypeFormatImpl::Flags& flags = Flags()); + + typedef std::shared_ptr<TypeFormatImpl_Format> SharedPointer; + typedef bool(*ValueCallback)(void*, ConstString, const TypeFormatImpl_Format::SharedPointer&); + + virtual ~TypeFormatImpl_Format () = default; lldb::Format GetFormat () const @@ -186,35 +243,69 @@ namespace lldb_private { m_format = fmt; } - uint32_t - GetOptions () + virtual TypeFormatImpl::Type + GetType () { - return m_flags.GetValue(); + return TypeFormatImpl::Type::eTypeFormat; + } + + virtual bool + FormatObject (ValueObject *valobj, + std::string& dest) const; + + virtual std::string + GetDescription(); + + protected: + lldb::Format m_format; + + private: + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl_Format); + }; + + class TypeFormatImpl_EnumType : public TypeFormatImpl + { + public: + TypeFormatImpl_EnumType (ConstString type_name = ConstString(""), + const TypeFormatImpl::Flags& flags = Flags()); + + typedef std::shared_ptr<TypeFormatImpl_EnumType> SharedPointer; + typedef bool(*ValueCallback)(void*, ConstString, const TypeFormatImpl_EnumType::SharedPointer&); + + ~TypeFormatImpl_EnumType () = default; + + ConstString + GetTypeName () + { + return m_enum_type; } void - SetOptions (uint32_t value) + SetTypeName (ConstString enum_type) { - m_flags.SetValue(value); + m_enum_type = enum_type; } - uint32_t& - GetRevision () + virtual TypeFormatImpl::Type + GetType () { - return m_my_revision; + return TypeFormatImpl::Type::eTypeEnum; } - std::string + virtual bool + FormatObject (ValueObject *valobj, + std::string& dest) const; + + virtual std::string GetDescription(); protected: - Flags m_flags; - lldb::Format m_format; - uint32_t m_my_revision; + ConstString m_enum_type; + mutable std::map<void*,ClangASTType> m_types; private: - DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl); - }; + DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl_EnumType); + }; } // namespace lldb_private #endif // lldb_TypeFormat_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h index 18b9d01..a25f11d 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -32,10 +32,24 @@ namespace lldb_private { { protected: ValueObject &m_backend; + + void + SetValid (bool valid) + { + m_valid = valid; + } + + bool + IsValid () + { + return m_valid; + } + public: SyntheticChildrenFrontEnd (ValueObject &backend) : - m_backend(backend) + m_backend(backend), + m_valid(true) {} virtual @@ -71,6 +85,7 @@ namespace lldb_private { typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer; private: + bool m_valid; DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd); }; diff --git a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h index 4e23cee..375bb50 100644 --- a/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h +++ b/contrib/llvm/tools/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -265,9 +265,6 @@ public: bool PrintValueObject (); - bool - PrintChildrenOneLiner (bool hide_names); - protected: // only this class (and subclasses, if any) should ever be concerned with @@ -366,6 +363,9 @@ protected: PrintChildrenIfNeeded (bool value_printed, bool summary_printed); + bool + PrintChildrenOneLiner (bool hide_names); + private: ValueObject *m_orig_valobj; @@ -386,6 +386,8 @@ private: std::string m_summary; std::string m_error; + friend class StringSummaryFormat; + DISALLOW_COPY_AND_ASSIGN(ValueObjectPrinter); }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/ClangFunction.h b/contrib/llvm/tools/lldb/include/lldb/Expression/ClangFunction.h index 9c14ddb..e150d38 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Expression/ClangFunction.h +++ b/contrib/llvm/tools/lldb/include/lldb/Expression/ClangFunction.h @@ -300,7 +300,7 @@ public: /// @param[in] args_addr /// The address of the argument struct. /// - /// @param[in] ret_value + /// @param[out] ret_value /// The value returned by the function. /// /// @return diff --git a/contrib/llvm/tools/lldb/include/lldb/Expression/IRForTarget.h b/contrib/llvm/tools/lldb/include/lldb/Expression/IRForTarget.h index 5663287..502f796 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Expression/IRForTarget.h +++ b/contrib/llvm/tools/lldb/include/lldb/Expression/IRForTarget.h @@ -30,6 +30,7 @@ namespace llvm { class GlobalValue; class GlobalVariable; class Instruction; + class IntegerType; class Module; class StoreInst; class DataLayout; @@ -650,6 +651,7 @@ private: StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type + llvm::IntegerType *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL. diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h b/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h new file mode 100644 index 0000000..b92de10 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Host/Editline.h @@ -0,0 +1,209 @@ +//===-- Editline.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_Editline_h_ +#define liblldb_Editline_h_ +#if defined(__cplusplus) + +#include "lldb/lldb-private.h" + +#include <stdio.h> +#ifdef _WIN32 +#include "lldb/Host/windows/editlinewin.h" +#else +#include <histedit.h> +#endif + +#include <string> +#include <vector> + +#include "lldb/Host/Condition.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Mutex.h" + +namespace lldb_private { + +//---------------------------------------------------------------------- +/// @class Editline Editline.h "lldb/Host/Editline.h" +/// @brief A class that encapsulates editline functionality. +//---------------------------------------------------------------------- +class Editline +{ +public: + typedef LineStatus (*LineCompletedCallbackType) ( + Editline *editline, + StringList &lines, + uint32_t line_idx, + Error &error, + void *baton); + + typedef int (*CompleteCallbackType) ( + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches, + void *baton); + + typedef int (*GetCharCallbackType) ( + ::EditLine *, + char *c); + + Editline(const char *prog, // Used for the history file and for editrc program name + const char *prompt, + FILE *fin, + FILE *fout, + FILE *ferr); + + ~Editline(); + + Error + GetLine (std::string &line); + + Error + GetLines (const std::string &end_line, StringList &lines); + + bool + LoadHistory (); + + bool + SaveHistory (); + + FILE * + GetInputFile (); + + FILE * + GetOutputFile (); + + FILE * + GetErrorFile (); + + bool + GettingLine () const + { + return m_getting_line; + } + + void + Hide (); + + void + Refresh(); + + void + Interrupt (); + + void + SetAutoCompleteCallback (CompleteCallbackType callback, + void *baton) + { + m_completion_callback = callback; + m_completion_callback_baton = baton; + } + + void + SetLineCompleteCallback (LineCompletedCallbackType callback, + void *baton) + { + m_line_complete_callback = callback; + m_line_complete_callback_baton = baton; + } + + size_t + Push (const char *bytes, size_t len); + + // Cache bytes and use them for input without using a FILE. Calling this function + // will set the getc callback in the editline + size_t + SetInputBuffer (const char *c, size_t len); + + static int + GetCharFromInputFileCallback (::EditLine *e, char *c); + + void + SetGetCharCallback (GetCharCallbackType callback); + + const char * + GetPrompt(); + + void + SetPrompt (const char *p); + +private: + + Error + PrivateGetLine(std::string &line); + + FileSpec + GetHistoryFile(); + + unsigned char + HandleCompletion (int ch); + + int + GetChar (char *c); + + + static unsigned char + CallbackEditPrevLine (::EditLine *e, int ch); + + static unsigned char + CallbackEditNextLine (::EditLine *e, int ch); + + static unsigned char + CallbackComplete (::EditLine *e, int ch); + + static const char * + GetPromptCallback (::EditLine *e); + + static Editline * + GetClientData (::EditLine *e); + + static FILE * + GetFilePointer (::EditLine *e, int fd); + + static int + GetCharInputBufferCallback (::EditLine *e, char *c); + + enum class Command + { + None = 0, + EditPrevLine, + EditNextLine, + }; + ::EditLine *m_editline; + ::History *m_history; + ::HistEvent m_history_event; + std::string m_program; + std::string m_prompt; + std::string m_lines_prompt; + std::string m_getc_buffer; + Mutex m_getc_mutex; + Condition m_getc_cond; + CompleteCallbackType m_completion_callback; + void *m_completion_callback_baton; +// Mutex m_gets_mutex; // Make sure only one thread + LineCompletedCallbackType m_line_complete_callback; + void *m_line_complete_callback_baton; + Command m_lines_command; + uint32_t m_lines_curr_line; + uint32_t m_lines_max_line; + bool m_prompt_with_line_numbers; + bool m_getting_line; + bool m_got_eof; // Set to true when we detect EOF + bool m_interrupted; + + DISALLOW_COPY_AND_ASSIGN(Editline); +}; + +} // namespace lldb_private + +#endif // #if defined(__cplusplus) +#endif // liblldb_Host_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/File.h b/contrib/llvm/tools/lldb/include/lldb/Host/File.h index 607efa0..814d960 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/File.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/File.h @@ -51,7 +51,10 @@ public: m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), - m_owned (false) + m_own_stream (false), + m_own_descriptor (false), + m_is_interactive (eLazyBoolCalculate), + m_is_real_terminal (eLazyBoolCalculate) { } @@ -59,7 +62,10 @@ public: m_descriptor (kInvalidDescriptor), m_stream (fh), m_options (0), - m_owned (transfer_ownership) + m_own_stream (transfer_ownership), + m_own_descriptor (false), + m_is_interactive (eLazyBoolCalculate), + m_is_real_terminal (eLazyBoolCalculate) { } @@ -111,13 +117,15 @@ public: uint32_t options, uint32_t permissions = lldb::eFilePermissionsFileDefault); - File (int fd, bool tranfer_ownership) : + File (int fd, bool transfer_ownership) : m_descriptor (fd), m_stream (kInvalidStream), m_options (0), - m_owned (tranfer_ownership) + m_own_stream (false), + m_own_descriptor (transfer_ownership) { } + //------------------------------------------------------------------ /// Destructor. /// @@ -458,6 +466,32 @@ public: static uint32_t GetPermissions (const char *path, Error &error); + + //------------------------------------------------------------------ + /// Return true if this file is interactive. + /// + /// @return + /// True if this file is a terminal (tty or pty), false + /// otherwise. + //------------------------------------------------------------------ + bool + GetIsInteractive (); + + //------------------------------------------------------------------ + /// Return true if this file from a real terminal. + /// + /// Just knowing a file is a interactive isn't enough, we also need + /// to know if the terminal has a width and height so we can do + /// cursor movement and other terminal maninpulations by sending + /// escape sequences. + /// + /// @return + /// True if this file is a terminal (tty, not a pty) that has + /// a non-zero width and height, false otherwise. + //------------------------------------------------------------------ + bool + GetIsRealTerminal (); + //------------------------------------------------------------------ /// Output printf formatted output to the stream. /// @@ -476,6 +510,12 @@ public: size_t PrintfVarArg(const char *format, va_list args); + + void + SetOptions (uint32_t options) + { + m_options = options; + } protected: @@ -491,13 +531,19 @@ protected: return m_stream != kInvalidStream; } + void + CalculateInteractiveAndTerminal (); + //------------------------------------------------------------------ // Member variables //------------------------------------------------------------------ int m_descriptor; FILE *m_stream; uint32_t m_options; - bool m_owned; + bool m_own_stream; + bool m_own_descriptor; + LazyBool m_is_interactive; + LazyBool m_is_real_terminal; }; } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h b/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h index 086c8f2..dfc4e4a 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/FileSpec.h @@ -534,7 +534,7 @@ public: /// as many bytes as possible. /// /// @return - /// A shared pointer to the memeory mapped data. This shared + /// A shared pointer to the memory mapped data. This shared /// pointer can contain a NULL DataBuffer pointer, so the contained /// pointer must be checked prior to using it. //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h index fe0f6f6..862b1ed 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h @@ -202,6 +202,23 @@ public: GetTargetTriple (); //------------------------------------------------------------------ + /// Gets the name of the distribution (i.e. distributor id). + /// + /// On Linux, this will return the equivalent of lsb_release -i. + /// Android will return 'android'. Other systems may return + /// nothing. + /// + /// @return + /// A ConstString reference containing the OS distribution id. + /// The return string will be all lower case, with whitespace + /// replaced with underscores. The return string will be + /// empty (result.AsCString() will return NULL) if the distribution + /// cannot be obtained. + //------------------------------------------------------------------ + static const ConstString & + GetDistributionId (); + + //------------------------------------------------------------------ /// Get the process ID for the calling process. /// /// @return @@ -459,7 +476,15 @@ public: static bool GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info); - + +#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) + static short + GetPosixspawnFlags (ProcessLaunchInfo &launch_info); + + static Error + LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid); +#endif + static lldb::pid_t LaunchApplication (const FileSpec &app_file_spec); diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/HostGetOpt.h b/contrib/llvm/tools/lldb/include/lldb/Host/HostGetOpt.h new file mode 100644 index 0000000..f4b2c87 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Host/HostGetOpt.h @@ -0,0 +1,20 @@ +//===-- GetOpt.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#pragma once + +#ifndef _MSC_VER + +#include <unistd.h> +#include <getopt.h> + +#else + +#include <lldb/Host/windows/GetOptInc.h> + +#endif diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h b/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h index 5e79e94..4dc6210 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/SocketAddress.h @@ -18,7 +18,6 @@ #include <winsock2.h> #include <WS2tcpip.h> typedef ADDRESS_FAMILY sa_family_t; -typedef USHORT in_port_t; #else #include <sys/socket.h> #include <netdb.h> @@ -103,7 +102,7 @@ public: //------------------------------------------------------------------ // Get the port if the socket address for the family has a port //------------------------------------------------------------------ - in_port_t + uint16_t GetPort () const; //------------------------------------------------------------------ @@ -111,7 +110,7 @@ public: // The family must be set correctly prior to calling this function. //------------------------------------------------------------------ bool - SetPort (in_port_t port); + SetPort (uint16_t port); //------------------------------------------------------------------ // Set the socket address according to the first match from a call @@ -121,10 +120,12 @@ public: // address. //------------------------------------------------------------------ bool - SetAddress (const struct addrinfo *hints_ptr, // Optional hints where the family, protocol and other things can be specified. - const char *host, // Hostname ("foo.bar.com" or "foo" or IP address string ("123.234.12.1" or "2001:0db8:85a3:0000:0000:8a2e:0370:7334") - const char *service, // Protocol name ("tcp", "http", etc) or a raw port number string ("81") - struct addrinfo *addr_info_ptr); // If non-NULL, this will get filled in with the match + getaddrinfo (const char *host, // Hostname ("foo.bar.com" or "foo" or IP address string ("123.234.12.1" or "2001:0db8:85a3:0000:0000:8a2e:0370:7334") + const char *service, // Protocol name ("tcp", "http", etc) or a raw port number string ("81") + int ai_family = PF_UNSPEC, + int ai_socktype = 0, + int ai_protocol = 0, + int ai_flags = 0); //------------------------------------------------------------------ // Quick way to set the SocketAddress to localhost given the family. @@ -133,7 +134,11 @@ public: //------------------------------------------------------------------ bool SetToLocalhost (sa_family_t family, - in_port_t port); + uint16_t port); + + bool + SetToAnyAddress (sa_family_t family, + uint16_t port); //------------------------------------------------------------------ // Returns true if there is a valid socket address in this object. diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h index 31fcc38..bcb9b55 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -17,6 +17,7 @@ #include "lldb/lldb-private.h" #include "lldb/Core/Broadcaster.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Core/Log.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandObject.h" @@ -29,7 +30,8 @@ namespace lldb_private { class CommandInterpreter : public Broadcaster, - public Properties + public Properties, + public IOHandlerDelegate { public: typedef std::map<std::string, OptionArgVectorSP> OptionArgMap; @@ -213,10 +215,10 @@ public: void HandleCommandsFromFile (FileSpec &file, ExecutionContext *context, - bool stop_on_continue, - bool stop_on_error, - bool echo_commands, - bool print_results, + LazyBool stop_on_continue, + LazyBool stop_on_error, + LazyBool echo_commands, + LazyBool print_results, LazyBool add_to_history, CommandReturnObject &result); @@ -305,7 +307,8 @@ public: ExecutionContext GetExecutionContext() { - return m_exe_ctx_ref.Lock(); + const bool thread_and_frame_only_if_stopped = true; + return m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped); } void @@ -317,20 +320,12 @@ public: const char * ProcessEmbeddedScriptCommands (const char *arg); - const char * - GetPrompt (); - void - SetPrompt (const char *); - - bool Confirm (const char *message, bool default_answer); + UpdatePrompt (const char *); - static size_t - GetConfirmationInputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction action, - const char *bytes, - size_t bytes_len); + bool + Confirm (const char *message, + bool default_answer); void LoadCommandDictionary (); @@ -395,8 +390,12 @@ public: bool GetBatchCommandMode () { return m_batch_command_mode; } - void - SetBatchCommandMode (bool value) { m_batch_command_mode = value; } + bool + SetBatchCommandMode (bool value) { + const bool old_value = m_batch_command_mode; + m_batch_command_mode = value; + return old_value; + } void ChildrenTruncated () @@ -435,6 +434,25 @@ public: return m_command_history; } + bool + IsActive (); + + void + RunCommandInterpreter (bool auto_handle_events, + bool spawn_thread); + + void + GetLLDBCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton); + + void + GetPythonCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton); + //------------------------------------------------------------------ // Properties //------------------------------------------------------------------ @@ -450,12 +468,31 @@ public: protected: friend class Debugger; + //------------------------------------------------------------------ + // IOHandlerDelegate functions + //------------------------------------------------------------------ + virtual void + IOHandlerInputComplete (IOHandler &io_handler, + std::string &line); + + virtual ConstString + GetControlSequence (char ch) + { + if (ch == 'd') + return ConstString("quit\n"); + return ConstString(); + } + + size_t + GetProcessOutput (); + void SetSynchronous (bool value); lldb::CommandObjectSP GetCommandSP (const char *cmd, bool include_aliases = true, bool exact = true, StringList *matches = NULL); + private: Error @@ -473,10 +510,12 @@ private: CommandHistory m_command_history; std::string m_repeat_command; // Stores the command that will be executed for an empty command string. std::unique_ptr<ScriptInterpreter> m_script_interpreter_ap; + lldb::IOHandlerSP m_command_io_handler_sp; char m_comment_char; bool m_batch_command_mode; ChildrenTruncatedWarningStatus m_truncation_warning; // Whether we truncated children and whether the user has been told uint32_t m_command_source_depth; + std::vector<uint32_t> m_command_source_flags; }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/PythonDataObjects.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/PythonDataObjects.h index 2762d45..63f1ad5 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/PythonDataObjects.h +++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/PythonDataObjects.h @@ -31,7 +31,7 @@ namespace lldb_private { { } - PythonObject (PyObject* py_obj) : + explicit PythonObject (PyObject* py_obj) : m_py_obj(NULL) { Reset (py_obj); @@ -43,7 +43,7 @@ namespace lldb_private { Reset (rhs.m_py_obj); } - PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp); + explicit PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp); virtual ~PythonObject () @@ -51,18 +51,10 @@ namespace lldb_private { Reset (NULL); } - const PythonObject & - operator = (const PythonObject &rhs) - { - if (this != &rhs) - Reset (rhs.m_py_obj); - return *this; - } - bool Reset (const PythonObject &object) { - return Reset(object.GetPythonObject()); + return Reset(object.get()); } virtual bool @@ -90,11 +82,11 @@ namespace lldb_private { Dump (Stream &strm) const; PyObject* - GetPythonObject () const + get () const { return m_py_obj; } - + PythonString Repr (); @@ -106,6 +98,9 @@ namespace lldb_private { return m_py_obj != NULL; } + bool + IsNULLOrNone () const; + protected: PyObject* m_py_obj; }; @@ -159,7 +154,7 @@ namespace lldb_private { { public: - PythonList (); + PythonList (bool create_empty); PythonList (PyObject* py_obj); PythonList (const PythonObject &object); PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp); @@ -186,7 +181,7 @@ namespace lldb_private { { public: - PythonDictionary (); + explicit PythonDictionary (bool create_empty); PythonDictionary (PyObject* object); PythonDictionary (const PythonObject &object); PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp); @@ -221,6 +216,9 @@ namespace lldb_private { GetValueAtPosition (uint32_t pos) const; void + SetItemForKey (const PythonString &key, PyObject *value); + + void SetItemForKey (const PythonString &key, const PythonObject& value); }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 9f529b8..1d62c9b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -245,11 +245,13 @@ public: return true; } - virtual bool + virtual Error ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options = ExecuteScriptOptions()) { - return true; + Error error; + error.SetErrorString("not implemented"); + return error; } virtual bool diff --git a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index b729cb6..ba53280 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/contrib/llvm/tools/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -19,16 +19,21 @@ #include "lldb/lldb-python.h" #include "lldb/lldb-private.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Core/InputReader.h" +#include "lldb/Interpreter/PythonDataObjects.h" #include "lldb/Host/Terminal.h" namespace lldb_private { -class ScriptInterpreterPython : public ScriptInterpreter +class ScriptInterpreterPython : + public ScriptInterpreter, + public IOHandlerDelegateMultiline { public: + friend class IOHandlerPythonInterpreter; + ScriptInterpreterPython (CommandInterpreter &interpreter); ~ScriptInterpreterPython (); @@ -47,7 +52,7 @@ public: void *ret_value, const ExecuteScriptOptions &options = ExecuteScriptOptions()); - bool + lldb_private::Error ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options = ExecuteScriptOptions()); @@ -134,20 +139,20 @@ public: bool GenerateWatchpointCommandCallbackData (StringList &input, std::string& output); - static size_t - GenerateBreakpointOptionsCommandCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - static size_t - GenerateWatchpointOptionsCommandCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - +// static size_t +// GenerateBreakpointOptionsCommandCallback (void *baton, +// InputReader &reader, +// lldb::InputReaderAction notification, +// const char *bytes, +// size_t bytes_len); +// +// static size_t +// GenerateWatchpointOptionsCommandCallback (void *baton, +// InputReader &reader, +// lldb::InputReaderAction notification, +// const char *bytes, +// size_t bytes_len); + static bool BreakpointCallbackFunction (void *baton, StoppointCallbackContext *context, @@ -238,9 +243,6 @@ public: virtual void ResetOutputFileHandle (FILE *new_fh); - static lldb::thread_result_t - RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton); - static void InitializePrivate (); @@ -266,10 +268,29 @@ public: SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame, SWIGPython_GetDynamicSetting swig_plugin_get); + const char * + GetDictionaryName () + { + return m_dictionary_name.c_str(); + } + + + //---------------------------------------------------------------------- + // IOHandlerDelegate + //---------------------------------------------------------------------- + virtual void + IOHandlerActivated (IOHandler &io_handler); + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data); + protected: bool - EnterSession (bool init_lldb_globals); + EnterSession (uint16_t on_entry_flags, + FILE *in, + FILE *out, + FILE *err); void LeaveSession (); @@ -279,8 +300,6 @@ protected: void RestoreTerminalState (); - -private: class SynchronicityHandler { @@ -322,7 +341,7 @@ private: private: DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterPythonObject); }; - +public: class Locker : public ScriptInterpreterLocker { public: @@ -331,7 +350,8 @@ private: { AcquireLock = 0x0001, InitSession = 0x0002, - InitGlobals = 0x0004 + InitGlobals = 0x0004, + NoSTDIN = 0x0008 }; enum OnLeave @@ -344,7 +364,9 @@ private: Locker (ScriptInterpreterPython *py_interpreter = NULL, uint16_t on_entry = AcquireLock | InitSession, uint16_t on_leave = FreeLock | TearDownSession, - FILE* wait_msg_handle = NULL); + FILE *in = NULL, + FILE *out = NULL, + FILE *err = NULL); ~Locker (); @@ -354,7 +376,7 @@ private: DoAcquireLock (); bool - DoInitSession (bool init_lldb_globals); + DoInitSession (uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err); bool DoFreeLock (); @@ -367,59 +389,40 @@ private: bool m_teardown_session; ScriptInterpreterPython *m_python_interpreter; - FILE* m_tmp_fh; +// FILE* m_tmp_fh; PyGILState_STATE m_GILState; }; - - class PythonInputReaderManager - { - public: - PythonInputReaderManager (ScriptInterpreterPython *interpreter); - - explicit operator bool() - { - return m_error; - } - - ~PythonInputReaderManager(); - - private: - - static size_t - InputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - static lldb::thread_result_t - RunPythonInputReader (lldb::thread_arg_t baton); - - ScriptInterpreterPython *m_interpreter; - lldb::DebuggerSP m_debugger_sp; - lldb::InputReaderSP m_reader_sp; - bool m_error; +private: + + enum ActiveIOHandler { + eIOHandlerNone, + eIOHandlerBreakpoint, + eIOHandlerWatchpoint }; + PythonObject & + GetMainModule (); + + PythonDictionary & + GetSessionDictionary (); + + PythonDictionary & + GetSysModuleDictionary (); - static size_t - InputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - - lldb_utility::PseudoTerminal m_embedded_thread_pty; - lldb_utility::PseudoTerminal m_embedded_python_pty; - lldb::InputReaderSP m_embedded_thread_input_reader_sp; - lldb::InputReaderSP m_embedded_python_input_reader_sp; - FILE *m_dbg_stdout; - PyObject *m_new_sysout; - PyObject *m_old_sysout; - PyObject *m_old_syserr; - PyObject *m_run_one_line; + bool + GetEmbeddedInterpreterModuleObjects (); + + PythonObject m_saved_stdin; + PythonObject m_saved_stdout; + PythonObject m_saved_stderr; + PythonObject m_main_module; + PythonObject m_lldb_module; + PythonDictionary m_session_dict; + PythonDictionary m_sys_module_dict; + PythonObject m_run_one_line_function; + PythonObject m_run_one_line_str_global; std::string m_dictionary_name; TerminalState m_terminal_state; + ActiveIOHandler m_active_io_handler; bool m_session_is_active; bool m_pty_slave_is_open; bool m_valid_session; diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h index fa48dc2..7af0634 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/FuncUnwinders.h @@ -31,7 +31,7 @@ public: // instructions are finished for migrating breakpoints past the // stack frame setup instructions when we don't have line table information. - FuncUnwinders (lldb_private::UnwindTable& unwind_table, lldb_private::UnwindAssembly *assembly_profiler, AddressRange range); + FuncUnwinders (lldb_private::UnwindTable& unwind_table, const lldb::UnwindAssemblySP& assembly_profiler, AddressRange range); ~FuncUnwinders (); @@ -77,7 +77,7 @@ public: private: UnwindTable& m_unwind_table; - UnwindAssembly *m_assembly_profiler; + lldb::UnwindAssemblySP m_assembly_profiler; AddressRange m_range; Mutex m_mutex; diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h index 787f81c..dcea24c 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Function.h @@ -608,6 +608,17 @@ public: size_t MemorySize () const; + lldb::DisassemblerSP + GetInstructions (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache); + + bool + GetDisassembly (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache, + Stream &strm); + protected: enum diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h index ad500f5..afa1f9b 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/ObjectFile.h @@ -451,6 +451,21 @@ public: } //------------------------------------------------------------------ + /// Sets the load address for an entire module, assuming a rigid + /// slide of sections, if possible in the implementation. + /// + /// @return + /// Returns true iff any section's load address changed. + //------------------------------------------------------------------ + virtual bool + SetLoadAddress(Target &target, + lldb::addr_t value, + bool value_is_offset) + { + return false; + } + + //------------------------------------------------------------------ /// Gets whether endian swapping should occur when extracting data /// from this object file. /// diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h index 75e0900..db32ba3 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Symbol.h @@ -291,6 +291,17 @@ public: virtual void DumpSymbolContext (Stream *s); + lldb::DisassemblerSP + GetInstructions (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache); + + bool + GetDisassembly (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache, + Stream &strm); + protected: uint32_t m_uid; // User ID (usually the original symbol table index) diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h index a050144..6fdd828 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/SymbolContext.h @@ -17,6 +17,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Mangled.h" #include "lldb/Symbol/LineEntry.h" +#include "lldb/Utility/Iterable.h" namespace lldb_private { @@ -552,6 +553,14 @@ protected: // Member variables. //------------------------------------------------------------------ collection m_symbol_contexts; ///< The list of symbol contexts. + +public: + typedef AdaptedIterable<collection, SymbolContext, vector_adapter> SymbolContextIterable; + SymbolContextIterable + SymbolContexts() + { + return SymbolContextIterable(m_symbol_contexts); + } }; bool operator== (const SymbolContext& lhs, const SymbolContext& rhs); diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h index 920f571..da32743 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/Type.h @@ -417,7 +417,15 @@ public: return type_sp->GetClangLayoutType().GetLValueReferenceType(); return clang_type.GetLValueReferenceType(); } - + + ClangASTType + GetTypedefedType () const + { + if (type_sp) + return type_sp->GetClangFullType().GetTypedefedType(); + return clang_type.GetTypedefedType(); + } + ClangASTType GetDereferencedType () const { @@ -513,6 +521,9 @@ public: GetReferenceType () const; TypeImpl + GetTypedefedType () const; + + TypeImpl GetDereferencedType () const; TypeImpl diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h index cefb91e..3a99eb4 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/UnwindTable.h @@ -57,7 +57,7 @@ private: bool m_initialized; // delay some initialization until ObjectFile is set up - UnwindAssembly* m_assembly_profiler; + lldb::UnwindAssemblySP m_assembly_profiler; DWARFCallFrameInfo* m_eh_frame; diff --git a/contrib/llvm/tools/lldb/include/lldb/Symbol/VariableList.h b/contrib/llvm/tools/lldb/include/lldb/Symbol/VariableList.h index 2ce6146..08efd3d 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Symbol/VariableList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Symbol/VariableList.h @@ -49,10 +49,16 @@ public: lldb::VariableSP FindVariable (const ConstString& name); + + lldb::VariableSP + FindVariable (const ConstString& name, lldb::ValueType value_type); uint32_t FindVariableIndex (const lldb::VariableSP &var_sp); - + + size_t + AppendVariablesIfUnique(VariableList &var_list); + // Returns the actual number of unique variables that were added to the // list. "total_matches" will get updated with the actualy number of // matches that were found regardless of whether they were unique or not diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h b/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h index 272f64f..6652a5e 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/DynamicLoader.h @@ -246,6 +246,60 @@ public: protected: //------------------------------------------------------------------ + // Utility methods for derived classes + //------------------------------------------------------------------ + + /// Checks to see if the target module has changed, updates the target + /// accordingly and returns the target executable module. + lldb::ModuleSP + GetTargetExecutable(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param link_map_addr The virtual address of the link map for the @p module. + /// + /// @param base_addr The virtual base address @p module is loaded at. + virtual void + UpdateLoadedSections(lldb::ModuleSP module, + lldb::addr_t link_map_addr, + lldb::addr_t base_addr); + + // Utility method so base classes can share implementation of UpdateLoadedSections + void + UpdateLoadedSectionsCommon(lldb::ModuleSP module, + lldb::addr_t base_addr); + + /// Removes the loaded sections from the target in @p module. + /// + /// @param module The module to traverse. + virtual void + UnloadSections(const lldb::ModuleSP module); + + // Utility method so base classes can share implementation of UnloadSections + void + UnloadSectionsCommon(const lldb::ModuleSP module); + + /// Locates or creates a module given by @p file and updates/loads the + /// resulting module at the virtual base address @p base_addr. + lldb::ModuleSP + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr); + + const lldb_private::SectionList * + GetSectionListFromModule(const lldb::ModuleSP module) const; + + // Read an unsigned int of the given size from memory at the given addr. + // Return -1 if the read fails, otherwise return the result as an int64_t. + int64_t + ReadUnsignedIntWithSizeInBytes(lldb::addr_t addr, int size_in_bytes); + + // Read a pointer from memory at the given addr. + // Return LLDB_INVALID_ADDRESS if the read fails. + lldb::addr_t + ReadPointer(lldb::addr_t addr); + + //------------------------------------------------------------------ // Member variables. //------------------------------------------------------------------ Process* m_process; ///< The process that this dynamic loader plug-in is tracking. diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ExecutionContext.h b/contrib/llvm/tools/lldb/include/lldb/Target/ExecutionContext.h index 4038e70..f825c2e 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/ExecutionContext.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/ExecutionContext.h @@ -298,7 +298,7 @@ public: /// any valid weak references in this object. //------------------------------------------------------------------ ExecutionContext - Lock () const; + Lock (bool thread_and_frame_only_if_stopped) const; //------------------------------------------------------------------ /// Returns true if this object has a weak reference to a thread. @@ -402,7 +402,7 @@ public: ExecutionContext (const lldb::ThreadWP &thread_wp); ExecutionContext (const lldb::StackFrameWP &frame_wp); ExecutionContext (const ExecutionContextRef &exe_ctx_ref); - ExecutionContext (const ExecutionContextRef *exe_ctx_ref); + ExecutionContext (const ExecutionContextRef *exe_ctx_ref, bool thread_and_frame_only_if_stopped = false); // These two variants take in a locker, and grab the target, lock the API mutex into locker, then // fill in the rest of the shared pointers. diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h b/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h index 355c052..80011fd 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Platform.h @@ -314,9 +314,9 @@ namespace lldb_private { /// An error object. //------------------------------------------------------------------ virtual Error - GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file); + GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file); //---------------------------------------------------------------------- // Locate the scripting resource given a module specification. @@ -835,6 +835,29 @@ namespace lldb_private { return LLDB_INVALID_QUEUE_ID; } + //------------------------------------------------------------------ + /// Provide a list of trap handler function names for this platform + /// + /// The unwinder needs to treat trap handlers specially -- the stack + /// frame may not be aligned correctly for a trap handler (the kernel + /// often won't perturb the stack pointer, or won't re-align it properly, + /// in the process of calling the handler) and the frame above the handler + /// needs to be treated by the unwinder's "frame 0" rules instead of its + /// "middle of the stack frame" rules. + /// + /// In a user process debugging scenario, the list of trap handlers is + /// typically just "_sigtramp". + /// + /// The Platform base class provides the m_trap_handlers ivar but it does + /// not populate it. Subclasses should add the names of the asynchronous + /// signal handler routines as needed. For most Unix platforms, add _sigtramp. + /// + /// @return + /// A list of symbol names. The list may be empty. + //------------------------------------------------------------------ + virtual const std::vector<ConstString> & + GetTrapHandlerSymbolNames (); + protected: bool m_is_host; // Set to true when we are able to actually set the OS version while @@ -867,6 +890,24 @@ namespace lldb_private { std::string m_ssh_opts; bool m_ignores_remote_hostname; std::string m_local_cache_directory; + std::vector<ConstString> m_trap_handlers; + bool m_calculated_trap_handlers; + + //------------------------------------------------------------------ + /// Ask the Platform subclass to fill in the list of trap handler names + /// + /// For most Unix user process environments, this will be a single + /// function name, _sigtramp. More specialized environments may have + /// additional handler names. The unwinder code needs to know when a + /// trap handler is on the stack because the unwind rules for the frame + /// that caused the trap are different. + /// + /// The base class Platform ivar m_trap_handlers should be updated by + /// the Platform subclass when this method is called. If there are no + /// predefined trap handlers, this method may be a no-op. + //------------------------------------------------------------------ + virtual void + CalculateTrapHandlerSymbolNames () = 0; const char * GetCachedUserName (uint32_t uid) @@ -1115,7 +1156,9 @@ namespace lldb_private { bool m_ssh; std::string m_ssh_opts; + private: + DISALLOW_COPY_AND_ASSIGN(OptionGroupPlatformSSH); }; diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Process.h b/contrib/llvm/tools/lldb/include/lldb/Target/Process.h index cda9b4f..b74347d 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/Process.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Process.h @@ -43,6 +43,7 @@ #include "lldb/Interpreter/Options.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/Memory.h" +#include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/PseudoTerminal.h" @@ -534,7 +535,8 @@ public: m_resume_count (0), m_monitor_callback (NULL), m_monitor_callback_baton (NULL), - m_monitor_signals (false) + m_monitor_signals (false), + m_hijack_listener_sp () { } @@ -553,7 +555,8 @@ public: m_resume_count (0), m_monitor_callback (NULL), m_monitor_callback_baton (NULL), - m_monitor_signals (false) + m_monitor_signals (false), + m_hijack_listener_sp () { if (stdin_path) { @@ -780,6 +783,7 @@ public: m_flags.Clear(); m_file_actions.clear(); m_resume_count = 0; + m_hijack_listener_sp.reset(); } bool @@ -799,9 +803,28 @@ public: m_monitor_signals = monitor_signals; } + Host::MonitorChildProcessCallback + GetMonitorProcessCallback () + { + return m_monitor_callback; + } + + const void* + GetMonitorProcessBaton () const + { + return m_monitor_callback_baton; + } + + // If the LaunchInfo has a monitor callback, then arrange to monitor the process. + // Return true if the LaunchInfo has taken care of monitoring the process, and false if the + // caller might want to monitor the process themselves. + bool MonitorProcess () const { + if (GetFlags().Test(lldb::eLaunchFlagsDontMonitorProcess)) + return true; + if (m_monitor_callback && ProcessIDIsValid()) { Host::StartMonitoringChildProcess (m_monitor_callback, @@ -818,6 +841,19 @@ public: { return m_pty; } + + lldb::ListenerSP + GetHijackListener () const + { + return m_hijack_listener_sp; + } + + void + SetHijackListener (const lldb::ListenerSP &listener_sp) + { + m_hijack_listener_sp = listener_sp; + } + protected: std::string m_working_dir; @@ -830,7 +866,7 @@ protected: Host::MonitorChildProcessCallback m_monitor_callback; void *m_monitor_callback_baton; bool m_monitor_signals; - + lldb::ListenerSP m_hijack_listener_sp; }; //---------------------------------------------------------------------- @@ -863,6 +899,7 @@ public: ProcessInfo::operator= (launch_info); SetProcessPluginName (launch_info.GetProcessPluginName()); SetResumeCount (launch_info.GetResumeCount()); + SetHijackListener(launch_info.GetHijackListener()); } bool @@ -952,7 +989,22 @@ public: return true; return false; } + + lldb::ListenerSP + GetHijackListener () const + { + return m_hijack_listener_sp; + } + + void + SetHijackListener (const lldb::ListenerSP &listener_sp) + { + m_hijack_listener_sp = listener_sp; + } + + protected: + lldb::ListenerSP m_hijack_listener_sp; std::string m_plugin_name; uint32_t m_resume_count; // How many times do we resume after launching bool m_wait_for_launch; @@ -1366,10 +1418,11 @@ class Process : public ExecutionContextScope, public PluginInterface { -friend class ThreadList; -friend class ClangFunction; // For WaitForStateChangeEventsPrivate -friend class ProcessEventData; -friend class StopInfo; + friend class ClangFunction; // For WaitForStateChangeEventsPrivate + friend class ProcessEventData; + friend class StopInfo; + friend class Target; + friend class ThreadList; public: @@ -2112,21 +2165,15 @@ public: /// @param[in] process_name /// The name of the process to attach to. /// - /// @param[in] wait_for_launch - /// If \b true, wait for the process to be launched and attach - /// as soon as possible after it does launch. If \b false, then - /// search for a matching process the currently exists. - /// /// @param[in] attach_info /// Information on how to do the attach. For example, GetUserID() /// will return the uid to attach as. /// /// @return - /// Returns \a pid if attaching was successful, or - /// LLDB_INVALID_PROCESS_ID if attaching fails. + /// Returns an error object. //------------------------------------------------------------------ virtual Error - DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info) + DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) { Error error; error.SetErrorString("attach by name is not supported"); @@ -2225,7 +2272,7 @@ public: //------------------------------------------------------------------ virtual Error DoLaunch (Module *exe_module, - const ProcessLaunchInfo &launch_info) + ProcessLaunchInfo &launch_info) { Error error; error.SetErrorStringWithFormat("error: %s does not support launching processes", GetPluginName().GetCString()); @@ -2991,15 +3038,11 @@ public: //------------------------------------------------------------------ virtual lldb::addr_t - ResolveIndirectFunction(const Address *address, Error &error) - { - error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetPluginName().GetCString()); - return LLDB_INVALID_ADDRESS; - } + ResolveIndirectFunction(const Address *address, Error &error); virtual Error - GetMemoryRegionInfo (lldb::addr_t load_addr, - MemoryRegionInfo &range_info) + GetMemoryRegionInfo (lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { Error error; error.SetErrorString ("Process::GetMemoryRegionInfo() not supported"); @@ -3317,10 +3360,10 @@ public: { return m_thread_list.Threads(); } - + uint32_t GetNextThreadIndexID (uint64_t thread_id); - + lldb::ThreadSP CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context); @@ -3334,6 +3377,27 @@ public: AssignIndexIDToThread(uint64_t thread_id); //------------------------------------------------------------------ + // Queue Queries + //------------------------------------------------------------------ + + void + UpdateQueueListIfNeeded (); + + QueueList & + GetQueueList () + { + UpdateQueueListIfNeeded(); + return m_queue_list; + } + + QueueList::QueueIterable + Queues () + { + UpdateQueueListIfNeeded(); + return m_queue_list.Queues(); + } + + //------------------------------------------------------------------ // Event Handling //------------------------------------------------------------------ lldb::StateType @@ -3343,10 +3407,15 @@ public: // is set to the event which triggered the stop. If wait_always = false, // and the process is already stopped, this function returns immediately. lldb::StateType - WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr = NULL, bool wait_always = true); + WaitForProcessToStop (const TimeValue *timeout, + lldb::EventSP *event_sp_ptr = NULL, + bool wait_always = true, + Listener *hijack_listener = NULL); lldb::StateType - WaitForStateChangedEvents (const TimeValue *timeout, lldb::EventSP &event_sp); + WaitForStateChangedEvents (const TimeValue *timeout, + lldb::EventSP &event_sp, + Listener *hijack_listener); // Pass NULL to use builtin listener Event * PeekAtStateChangedEvents (); @@ -3513,6 +3582,12 @@ public: void SetSTDIOFileDescriptor (int file_descriptor); + void + WatchForSTDIN (IOHandler &io_handler); + + void + CancelWatchForSTDIN (bool exited); + //------------------------------------------------------------------ // Add a permanent region of memory that should never be read or // written to. This can be used to ensure that memory reads or writes @@ -3645,6 +3720,12 @@ protected: { return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread); } + + void + ForceNextEventDelivery() + { + m_force_next_event_delivery = true; + } //------------------------------------------------------------------ // Type definitions @@ -3685,6 +3766,8 @@ protected: ///< m_thread_list_real, but might be different if there is an OS plug-in creating memory threads ThreadList m_extended_thread_list; ///< Owner for extended threads that may be generated, cleared on natural stops uint32_t m_extended_thread_stop_id; ///< The natural stop id when extended_thread_list was last updated + QueueList m_queue_list; ///< The list of libdispatch queues at a given stop point + uint32_t m_queue_list_stop_id; ///< The natural stop id when queue list was last fetched std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver. std::vector<lldb::addr_t> m_image_tokens; Listener &m_listener; @@ -3695,7 +3778,7 @@ protected: std::unique_ptr<SystemRuntime> m_system_runtime_ap; UnixSignals m_unix_signals; /// This is the current signal set for this process. lldb::ABISP m_abi_sp; - lldb::InputReaderSP m_process_input_reader; + lldb::IOHandlerSP m_process_input_reader; Communication m_stdio_communication; Mutex m_stdio_communication_mutex; std::string m_stdout_data; @@ -3715,7 +3798,9 @@ protected: bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check. bool m_finalize_called; bool m_clear_thread_plans_on_stop; + bool m_force_next_event_delivery; lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent. + std::map<lldb::addr_t,lldb::addr_t> m_resolved_indirect_addresses; bool m_destroy_in_process; enum { @@ -3790,21 +3875,14 @@ protected: STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len); void - PushProcessInputReader (); + PushProcessIOHandler (); void - PopProcessInputReader (); + PopProcessIOHandler (); void - ResetProcessInputReader (); - - static size_t - ProcessInputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - + ResetProcessIOHandler (); + Error HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp); diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Queue.h b/contrib/llvm/tools/lldb/include/lldb/Target/Queue.h new file mode 100644 index 0000000..32ee24a --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Queue.h @@ -0,0 +1,189 @@ +//===-- Queue.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_Queue_h_ +#define liblldb_Queue_h_ + +#include <vector> +#include <string> + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private.h" +#include "lldb/Target/QueueItem.h" + + +namespace lldb_private { + +//------------------------------------------------------------------ +// Queue: +// This class represents a libdispatch aka Grand Central Dispatch +// queue in the process. +// +// A program using libdispatch will create queues, put work items +// (functions, blocks) on the queues. The system will create / +// reassign pthreads to execute the work items for the queues. A +// serial queue will be associated with a single thread (or possibly +// no thread, if it is not doing any work). A concurrent queue may +// be associated with multiple threads. +//------------------------------------------------------------------ + + +class Queue : + public std::enable_shared_from_this<Queue> +{ +public: + + Queue (lldb::ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue_name); + + ~Queue (); + + //------------------------------------------------------------------ + /// Get the QueueID for this Queue + /// + /// A 64-bit ID number that uniquely identifies a queue at this particular + /// stop_id. Currently the libdispatch serialnum is used for the QueueID; + /// it is a number that starts at 1 for each process and increments with + /// each queue. A serialnum is not reused for a different queue in the + /// lifetime of that process execution. + /// + /// @return + /// The QueueID for this Queue. + //------------------------------------------------------------------ + lldb::queue_id_t + GetID (); + + //------------------------------------------------------------------ + /// Get the name of this Queue + /// + /// @return + /// The name of the queue, if one is available. + /// A NULL pointer is returned if none is available. + //------------------------------------------------------------------ + const char * + GetName (); + + //------------------------------------------------------------------ + /// Get the IndexID for this Queue + /// + /// This is currently the same as GetID(). If it changes in the future, + /// it will be a small integer value (starting with 1) assigned to + /// each queue that is seen during a Process lifetime. + /// + /// Both the GetID and GetIndexID are being retained for Queues to + /// maintain similar API to the Thread class, and allow for the + /// possibility of GetID changing to a different source in the future. + /// + /// @return + /// The IndexID for this queue. + //------------------------------------------------------------------ + uint32_t + GetIndexID (); + + //------------------------------------------------------------------ + /// Return the threads currently associated with this queue + /// + /// Zero, one, or many threads may be executing code for a queue at + /// a given point in time. This call returns the list of threads + /// that are currently executing work for this queue. + /// + /// @return + /// The threads currently performing work for this queue + //------------------------------------------------------------------ + std::vector<lldb::ThreadSP> + GetThreads (); + + //------------------------------------------------------------------ + /// Return the items that are currently enqueued + /// + /// "Enqueued" means that the item has been added to the queue to + /// be done, but has not yet been done. When the item is going to + /// be processed it is "dequeued". + /// + /// @return + /// The vector of enqueued items for this queue + //------------------------------------------------------------------ + const std::vector<lldb::QueueItemSP> & + GetPendingItems(); + + lldb::ProcessSP + GetProcess() const + { + return m_process_wp.lock(); + } + + //------------------------------------------------------------------ + /// Get the number of work items that this queue is currently running + /// + /// @return + /// The number of work items currently executing. For a serial + /// queue, this will be 0 or 1. For a concurrent queue, this + /// may be any number. + //------------------------------------------------------------------ + uint32_t + GetNumRunningWorkItems () const; + + //------------------------------------------------------------------ + /// Get the number of work items enqueued on this queue + /// + /// @return + /// The number of work items currently enqueued, waiting to + /// execute. + //------------------------------------------------------------------ + uint32_t + GetNumPendingWorkItems () const; + + //------------------------------------------------------------------ + /// Get the dispatch_queue_t structure address for this Queue + /// + /// Get the address in the inferior process' memory of this Queue's + /// dispatch_queue_t structure. + /// + /// @return + /// The address of the dispatch_queue_t structure, if known. + /// LLDB_INVALID_ADDRESS will be returned if it is unavailable. + //------------------------------------------------------------------ + lldb::addr_t + GetLibdispatchQueueAddress () const; + + + void + SetNumRunningWorkItems (uint32_t count); + + void + SetNumPendingWorkItems (uint32_t count); + + void + SetLibdispatchQueueAddress (lldb::addr_t dispatch_queue_t_addr); + + void + PushPendingQueueItem (lldb::QueueItemSP item) + { + m_pending_items.push_back (item); + } + +private: + //------------------------------------------------------------------ + // For Queue only + //------------------------------------------------------------------ + + lldb::ProcessWP m_process_wp; + lldb::queue_id_t m_queue_id; + std::string m_queue_name; + uint32_t m_running_work_items_count; + uint32_t m_pending_work_items_count; + std::vector<lldb::QueueItemSP> m_pending_items; + lldb::addr_t m_dispatch_queue_t_addr; // address of libdispatch dispatch_queue_t for this Queue + + DISALLOW_COPY_AND_ASSIGN (Queue); +}; + +} // namespace lldb_private + +#endif // liblldb_Queue_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h b/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h new file mode 100644 index 0000000..76270da --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Target/QueueItem.h @@ -0,0 +1,244 @@ +//===-- QueueItem.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_QueueItem_h_ +#define liblldb_QueueItem_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/lldb-enumerations.h" + +#include "lldb/Core/Address.h" +#include "lldb/Core/ConstString.h" + + +namespace lldb_private { + +//------------------------------------------------------------------ +// QueueItem: +// This class represents a work item enqueued on a libdispatch aka +// Grand Central Dispatch (GCD) queue. Most often, this will be a +// function or block. +// "enqueued" here means that the work item has been added to a queue +// but it has not yet started executing. When it is "dequeued", +// execution of the item begins. +//------------------------------------------------------------------ + + +class QueueItem : + public std::enable_shared_from_this<QueueItem> +{ +public: + + QueueItem (lldb::QueueSP queue_sp); + + ~QueueItem (); + + //------------------------------------------------------------------ + /// Get the kind of work item this is + /// + /// @return + /// The type of work item that this QueueItem object + /// represents. eQueueItemKindUnknown may be returned. + //------------------------------------------------------------------ + lldb::QueueItemKind + GetKind () const; + + //------------------------------------------------------------------ + /// Set the type of work item this is + /// + /// @param [in] item_kind + /// Set the kind of this work item object. + //------------------------------------------------------------------ + void + SetKind (lldb::QueueItemKind item_kind); + + //------------------------------------------------------------------ + /// Get the code address that will be executed when this work item + /// is executed. + /// + /// @return + /// The address that will be invoked when this work item is + /// executed. Not all types of QueueItems will have an + /// address associated with them; check that the returned + /// Address is valid, or check that the WorkItemKind is a + /// kind that involves an address, such as eQueueItemKindFunction + /// or eQueueItemKindBlock. + //------------------------------------------------------------------ + lldb_private::Address & + GetAddress (); + + //------------------------------------------------------------------ + /// Set the work item address for this object + /// + /// @param [in] addr + /// The address that will be invoked when this work item + /// is executed. + //------------------------------------------------------------------ + void + SetAddress (lldb_private::Address addr); + + //------------------------------------------------------------------ + /// Check if this QueueItem object is valid + /// + /// If the weak pointer to the parent Queue cannot be revivified, + /// it is invalid. + /// + /// @return + /// True if this object is valid. + //------------------------------------------------------------------ + bool + IsValid () + { + return m_queue_wp.lock() != NULL; + } + + //------------------------------------------------------------------ + /// Get an extended backtrace thread for this queue item, if available + /// + /// If the backtrace/thread information was collected when this item + /// was enqueued, this call will provide it. + /// + /// @param [in] type + /// The type of extended backtrace being requested, e.g. "libdispatch" + /// or "pthread". + /// + /// @return + /// A thread shared pointer which will have a reference to an extended + /// thread if one was available. + //------------------------------------------------------------------ + lldb::ThreadSP + GetExtendedBacktraceThread (ConstString type); + + void + SetItemThatEnqueuedThis (lldb::addr_t address_of_item) + { + m_item_that_enqueued_this_ref = address_of_item; + } + + lldb::addr_t + GetItemThatEnqueuedThis () + { + return m_item_that_enqueued_this_ref; + } + + void + SetEnqueueingThreadID (lldb::tid_t tid) + { + m_enqueueing_thread_id = tid; + } + + lldb::tid_t + GetEnqueueingThreadID () + { + return m_enqueueing_thread_id; + } + + void + SetEnqueueingQueueID (lldb::queue_id_t qid) + { + m_enqueueing_queue_id = qid; + } + + lldb::queue_id_t + GetEnqueueingQueueID () + { + return m_enqueueing_queue_id; + } + + void + SetTargetQueueID (lldb::queue_id_t qid) + { + m_target_queue_id = qid; + } + + void + SetStopID (uint32_t stop_id) + { + m_stop_id = stop_id; + } + + uint32_t + GetStopID () + { + return m_stop_id; + } + + void + SetEnqueueingBacktrace (std::vector<lldb::addr_t> backtrace) + { + m_backtrace = backtrace; + } + + std::vector<lldb::addr_t> & + GetEnqueueingBacktrace () + { + return m_backtrace; + } + + void + SetThreadLabel (std::string thread_name) + { + m_thread_label = thread_name; + } + + std::string + GetThreadLabel () + { + return m_thread_label; + } + + void + SetQueueLabel (std::string queue_name) + { + m_queue_label = queue_name; + } + + std::string + GetQueueLabel () + { + return m_queue_label; + } + + void + SetTargetQueueLabel (std::string queue_name) + { + m_target_queue_label = queue_name; + } + +protected: + lldb::QueueWP m_queue_wp; + lldb::QueueItemKind m_kind; + lldb_private::Address m_address; + + lldb::addr_t m_item_that_enqueued_this_ref; // a handle that we can pass into libBacktraceRecording + // to get the QueueItem that enqueued this item + lldb::tid_t m_enqueueing_thread_id; // thread that enqueued this item + lldb::queue_id_t m_enqueueing_queue_id; // Queue that enqueued this item, if it was a queue + lldb::queue_id_t m_target_queue_id; + uint32_t m_stop_id; // indicates when this backtrace was recorded in time + std::vector<lldb::addr_t> m_backtrace; + std::string m_thread_label; + std::string m_queue_label; + std::string m_target_queue_label; + + +private: + //------------------------------------------------------------------ + // For QueueItem only + //------------------------------------------------------------------ + + DISALLOW_COPY_AND_ASSIGN (QueueItem); + +}; + +} // namespace lldb_private + +#endif // liblldb_QueueItem_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h b/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h new file mode 100644 index 0000000..964c1099 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Target/QueueList.h @@ -0,0 +1,141 @@ +//===-- QueueList.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_QueueList_h_ +#define liblldb_QueueList_h_ + +#include <vector> + +#include "lldb/lldb-private.h" +#include "lldb/Core/UserID.h" +#include "lldb/Utility/Iterable.h" + + +namespace lldb_private { + +//------------------------------------------------------------------ +// QueueList: +// This is the container for libdispatch aka Grand Central Dispatch +// Queue objects. +// +// Each Process will have a QueueList. When the process execution is +// paused, the QueueList may be populated with Queues by the +// SystemRuntime. +//------------------------------------------------------------------ + +class QueueList +{ +friend class Process; + +public: + + QueueList (Process *process); + + ~QueueList (); + + //------------------------------------------------------------------ + /// Get the number of libdispatch queues that are available + /// + /// @return + /// The number of queues that are stored in the QueueList. + //------------------------------------------------------------------ + uint32_t + GetSize(); + + //------------------------------------------------------------------ + /// Get the Queue at a given index number + /// + /// @param [in] idx + /// The index number (0-based) of the queue. + /// @return + /// The Queue at that index number. + //------------------------------------------------------------------ + lldb::QueueSP + GetQueueAtIndex (uint32_t idx); + + typedef std::vector<lldb::QueueSP> collection; + typedef LockingAdaptedIterable<collection, lldb::QueueSP, vector_adapter> QueueIterable; + + //------------------------------------------------------------------ + /// Iterate over the list of queues + /// + /// @return + /// An Iterable object which can be used to loop over the queues + /// that exist. + //------------------------------------------------------------------ + QueueIterable + Queues () + { + return QueueIterable(m_queues, m_mutex); + } + + //------------------------------------------------------------------ + /// Clear out the list of queues from the QueueList + //------------------------------------------------------------------ + void + Clear(); + + //------------------------------------------------------------------ + /// Add a Queue to the QueueList + /// + /// @param [in] queue + /// Used by the SystemRuntime to populate the QueueList + //------------------------------------------------------------------ + void + AddQueue (lldb::QueueSP queue); + + //------------------------------------------------------------------ + /// Find a queue in the QueueList by QueueID + /// + /// @param [in] qid + /// The QueueID (same as returned by Thread::GetQueueID()) to find. + /// + /// @return + /// A QueueSP to the queue requested, if it is present in the QueueList. + /// An empty QueueSP willbe returned if this queue was not found. + //------------------------------------------------------------------ + lldb::QueueSP + FindQueueByID (lldb::queue_id_t qid); + + //------------------------------------------------------------------ + /// Find a queue in the QueueList by IndexID + /// + /// @param [in] index_id + /// Find a queue by IndexID. This is an integer associated with each + /// unique queue seen during a debug session and will not be reused + /// for a different queue. Unlike the QueueID, a 64-bit value, this + /// will tend to be an integral value like 1 or 7. + /// + /// @return + /// A QueueSP to the queue requested, if it is present in the QueueList. + /// An empty QueueSP willbe returned if this queue was not found. + //------------------------------------------------------------------ + lldb::QueueSP + FindQueueByIndexID (uint32_t index_id); + + lldb_private::Mutex & + GetMutex (); + +protected: + + //------------------------------------------------------------------ + // Classes that inherit from Process can see and modify these + //------------------------------------------------------------------ + Process *m_process; ///< The process that manages this queue list. + uint32_t m_stop_id; ///< The process stop ID that this queue list is valid for. + collection m_queues; ///< The queues for this process. + Mutex m_mutex; + +private: + QueueList (); +}; + +} // namespace lldb_private + +#endif // liblldb_QueueList_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadHistory.h b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadHistory.h new file mode 100644 index 0000000..50dcfd3 --- /dev/null +++ b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadHistory.h @@ -0,0 +1,109 @@ +//===-- SectionLoadHistory.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_SectionLoadHistory_h_ +#define liblldb_SectionLoadHistory_h_ + +// C Includes +// C++ Includes +#include <map> + +// Project includes +#include "lldb/lldb-public.h" +#include "lldb/Host/Mutex.h" + +namespace lldb_private { + +class SectionLoadHistory +{ +public: + enum { + // Pass eStopIDNow to any function that takes a stop ID to get + // the current value. + eStopIDNow = UINT32_MAX + }; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + SectionLoadHistory () : + m_stop_id_to_section_load_list(), + m_mutex (Mutex::eMutexTypeRecursive) + { + } + + ~SectionLoadHistory() + { + // Call clear since this takes a lock and clears the section load list + // in case another thread is currently using this section load list + Clear(); + } + + SectionLoadList & + GetCurrentSectionLoadList (); + + bool + IsEmpty() const; + + void + Clear (); + + uint32_t + GetLastStopID() const; + + // Get the section load address given a process stop ID + lldb::addr_t + GetSectionLoadAddress (uint32_t stop_id, + const lldb::SectionSP §ion_sp); + + bool + ResolveLoadAddress (uint32_t stop_id, + lldb::addr_t load_addr, + Address &so_addr); + + bool + SetSectionLoadAddress (uint32_t stop_id, + const lldb::SectionSP §ion_sp, + lldb::addr_t load_addr, + bool warn_multiple = false); + + // The old load address should be specified when unloading to ensure we get + // the correct instance of the section as a shared library could be loaded + // at more than one location. + bool + SetSectionUnloaded (uint32_t stop_id, + const lldb::SectionSP §ion_sp, + lldb::addr_t load_addr); + + // Unload all instances of a section. This function can be used on systems + // that don't support multiple copies of the same shared library to be + // loaded at the same time. + size_t + SetSectionUnloaded (uint32_t stop_id, + const lldb::SectionSP §ion_sp); + + void + Dump (Stream &s, + Target *target); + +protected: + + SectionLoadList * + GetSectionLoadListForStopID (uint32_t stop_id, bool read_only); + + typedef std::map<uint32_t, lldb::SectionLoadListSP> StopIDToSectionLoadList; + StopIDToSectionLoadList m_stop_id_to_section_load_list; + mutable Mutex m_mutex; + +private: + DISALLOW_COPY_AND_ASSIGN (SectionLoadHistory); +}; + +} // namespace lldb_private + +#endif // liblldb_SectionLoadHistory_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h index ac05bf7..6a9bbab 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/SectionLoadList.h @@ -36,6 +36,8 @@ public: { } + SectionLoadList (const SectionLoadList& rhs); + ~SectionLoadList() { // Call clear since this takes a lock and clears the section load list @@ -43,6 +45,9 @@ public: Clear(); } + void + operator=(const SectionLoadList &rhs); + bool IsEmpty() const; @@ -79,9 +84,6 @@ protected: addr_to_sect_collection m_addr_to_sect; sect_to_addr_collection m_sect_to_addr; mutable Mutex m_mutex; - -private: - DISALLOW_COPY_AND_ASSIGN (SectionLoadList); }; } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h b/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h index 7a0703e..363ce12 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/SystemRuntime.h @@ -20,9 +20,10 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Target/QueueList.h" +#include "lldb/Target/QueueItem.h" #include "lldb/lldb-private.h" - namespace lldb_private { //---------------------------------------------------------------------- @@ -103,6 +104,14 @@ public: virtual void ModulesDidLoad(lldb_private::ModuleList &module_list); + //------------------------------------------------------------------ + /// Called before detaching from a process. + /// + /// This will give a SystemRuntime plugin a chance to free any resources + /// in the inferior process before we detach. + //------------------------------------------------------------------ + virtual void + Detach (); //------------------------------------------------------------------ /// Return a list of thread origin extended backtraces that may @@ -160,6 +169,107 @@ public: virtual lldb::ThreadSP GetExtendedBacktraceThread (lldb::ThreadSP thread, ConstString type); + //------------------------------------------------------------------ + /// Get the extended backtrace thread for a QueueItem + /// + /// A QueueItem represents a function/block that will be executed on + /// a libdispatch queue in the future, or it represents a function/block + /// that is currently executing on a thread. + /// + /// This method will report a thread backtrace of the function that + /// enqueued it originally, if possible. + /// + /// @param [in] queue_item_sp + /// The QueueItem that we are getting an extended backtrace for. + /// + /// @param [in] type + /// The type of extended backtrace to fetch. The types supported + /// are returned from SystemRuntime::GetExtendedBacktraceTypes. + /// + /// @return + /// If an extended backtrace is available, it is returned. Else + /// an empty ThreadSP is returned. + //------------------------------------------------------------------ + virtual lldb::ThreadSP + GetExtendedBacktraceForQueueItem (lldb::QueueItemSP queue_item_sp, ConstString type) + { + return lldb::ThreadSP(); + } + + //------------------------------------------------------------------ + /// Populate the Process' QueueList with libdispatch / GCD queues that exist. + /// + /// When process execution is paused, the SystemRuntime may be called to fill + /// in the list of Queues that currently exist. + /// + /// @param [out] queue_list + /// This QueueList will be cleared, and any queues that currently exist + /// will be added. An empty QueueList will be returned if no queues + /// exist or if this Systemruntime does not support libdispatch queues. + //------------------------------------------------------------------ + virtual void + PopulateQueueList (lldb_private::QueueList &queue_list) + { + } + + //------------------------------------------------------------------ + /// Get the queue name for a thread given a thread's dispatch_qaddr. + /// + /// On systems using libdispatch queues, a thread may be associated with a queue. + /// There will be a call to get the thread's dispatch_qaddr. At the dispatch_qaddr + /// we will find the address of this thread's dispatch_queue_t structure. + /// Given the address of the dispatch_queue_t structure for a thread, + /// get the queue name and return it. + /// + /// @param [in] dispatch_qaddr + /// The address of the dispatch_queue_t structure for this thread. + /// + /// @return + /// The string of this queue's name. An empty string is returned if the + /// name could not be found. + //------------------------------------------------------------------ + virtual std::string + GetQueueNameFromThreadQAddress (lldb::addr_t dispatch_qaddr) + { + return ""; + } + + //------------------------------------------------------------------ + /// Get the QueueID for the libdispatch queue given the thread's dispatch_qaddr. + /// + /// On systems using libdispatch queues, a thread may be associated with a queue. + /// There will be a call to get the thread's dispatch_qaddr. At the dispatch_qaddr + /// we will find the address of this thread's dispatch_queue_t structure. + /// Given the address of the dispatch_queue_t structure for a thread, + /// get the queue ID and return it. + /// + /// @param [in] dispatch_qaddr + /// The address of the dispatch_queue_t structure for this thread. + /// + /// @return + /// The queue ID, or if it could not be retrieved, LLDB_INVALID_QUEUE_ID. + //------------------------------------------------------------------ + virtual lldb::queue_id_t + GetQueueIDFromThreadQAddress (lldb::addr_t dispatch_qaddr) + { + return LLDB_INVALID_QUEUE_ID; + } + + //------------------------------------------------------------------ + /// Get the pending work items for a libdispatch Queue + /// + /// If this system/process is using libdispatch and the runtime can do so, + /// retrieve the list of pending work items for the specified Queue and + /// add it to the Queue. + /// + /// @param [in] queue + /// The queue of interest. + //------------------------------------------------------------------ + virtual void + PopulatePendingItemsForQueue (lldb_private::Queue *queue) + { + } + protected: //------------------------------------------------------------------ // Member variables. diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h index d874891..e65a511 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/Target.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Target.h @@ -35,7 +35,7 @@ #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" -#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/SectionLoadHistory.h" namespace lldb_private { @@ -164,6 +164,9 @@ public: bool GetUseFastStepping() const; + + bool + GetDisplayExpressionsInCrashlogs () const; LoadScriptFromSymFile GetLoadScriptFromSymbolFile() const; @@ -174,6 +177,11 @@ public: MemoryModuleLoadLevel GetMemoryModuleLoadLevel() const; + bool + GetUserSpecifiedTrapHandlerNames (Args &args) const; + + void + SetUserSpecifiedTrapHandlerNames (const Args &args); }; typedef std::shared_ptr<TargetProperties> TargetPropertiesSP; @@ -526,6 +534,10 @@ public: void Destroy(); + + Error + Launch (Listener &listener, + ProcessLaunchInfo &launch_info); //------------------------------------------------------------------ // This part handles the breakpoints. @@ -630,7 +642,8 @@ public: CreateBreakpoint (lldb::SearchFilterSP &filter_sp, lldb::BreakpointResolverSP &resolver_sp, bool internal, - bool request_hardware); + bool request_hardware, + bool resolve_indirect_symbols); // Use this to create a watchpoint: lldb::WatchpointSP @@ -1001,14 +1014,14 @@ public: SectionLoadList& GetSectionLoadList() { - return m_section_load_list; + return m_section_load_history.GetCurrentSectionLoadList(); } - const SectionLoadList& - GetSectionLoadList() const - { - return m_section_load_list; - } +// const SectionLoadList& +// GetSectionLoadList() const +// { +// return const_cast<SectionLoadHistory *>(&m_section_load_history)->GetCurrentSectionLoadList(); +// } static Target * GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, @@ -1048,6 +1061,26 @@ public: Error Install(ProcessLaunchInfo *launch_info); + + bool + ResolveLoadAddress (lldb::addr_t load_addr, + Address &so_addr, + uint32_t stop_id = SectionLoadHistory::eStopIDNow); + + bool + SetSectionLoadAddress (const lldb::SectionSP §ion, + lldb::addr_t load_addr, + bool warn_multiple = false); + + bool + SetSectionUnloaded (const lldb::SectionSP §ion_sp); + + bool + SetSectionUnloaded (const lldb::SectionSP §ion_sp, lldb::addr_t load_addr); + + void + ClearAllLoadedSections (); + // Since expressions results can persist beyond the lifetime of a process, // and the const expression results are available after a process is gone, // we provide a way for expressions to be evaluated from the Target itself. @@ -1144,7 +1177,7 @@ public: std::unique_ptr<ThreadSpec> m_thread_spec_ap; bool m_active; - // Use AddStopHook to make a new empty stop hook. The GetCommandPointer and fill it with commands, + // Use CreateStopHook to make a new empty stop hook. The GetCommandPointer and fill it with commands, // and SetSpecifier to set the specifier shared pointer (can be null, that will match anything.) StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid); friend class Target; @@ -1153,8 +1186,8 @@ public: // Add an empty stop hook to the Target's stop hook list, and returns a shared pointer to it in new_hook. // Returns the id of the new hook. - lldb::user_id_t - AddStopHook (StopHookSP &new_hook); + StopHookSP + CreateStopHook (); void RunStopHooks (); @@ -1250,7 +1283,7 @@ protected: Mutex m_mutex; ///< An API mutex that is used by the lldb::SB* classes make the SB interface thread safe ArchSpec m_arch; ModuleList m_images; ///< The list of images for this process (shared libraries and anything dynamically loaded). - SectionLoadList m_section_load_list; + SectionLoadHistory m_section_load_history; BreakpointList m_breakpoint_list; BreakpointList m_internal_breakpoint_list; lldb::BreakpointSP m_last_created_breakpoint; @@ -1260,7 +1293,6 @@ protected: // we can correctly tear down everything that we need to, so the only // class that knows about the process lifespan is this target class. lldb::ProcessSP m_process_sp; - bool m_valid; lldb::SearchFilterSP m_search_filter_sp; PathMappingList m_image_search_paths; std::unique_ptr<ClangASTContext> m_scratch_ast_context_ap; @@ -1273,8 +1305,8 @@ protected: typedef std::map<lldb::user_id_t, StopHookSP> StopHookCollection; StopHookCollection m_stop_hooks; lldb::user_id_t m_stop_hook_next_id; + bool m_valid; bool m_suppress_stop_hooks; - bool m_suppress_synthetic_value; static void ImageSearchPathsChanged (const PathMappingList &path_list, diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h b/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h index 4f78b0f..20687e9 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/Thread.h @@ -44,6 +44,9 @@ public: const RegularExpression * GetSymbolsToAvoidRegexp(); + FileSpecList & + GetLibrariesToAvoid() const; + bool GetTraceEnabledState() const; }; @@ -410,6 +413,55 @@ public: DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx); //------------------------------------------------------------------ + /// Default implementation for stepping into. + /// + /// This function is designed to be used by commands where the + /// process is publicly stopped. + /// + /// @param[in] source_step + /// If true and the frame has debug info, then do a source level + /// step in, else do a single instruction step in. + /// + /// @param[in] avoid_code_without_debug_info + /// If \a true, then avoid stepping into code that doesn't have + /// debug info, else step into any code regardless of wether it + /// has debug info. + /// + /// @return + /// An error that describes anything that went wrong + //------------------------------------------------------------------ + virtual Error + StepIn (bool source_step, + bool avoid_code_without_debug_info); + + //------------------------------------------------------------------ + /// Default implementation for stepping over. + /// + /// This function is designed to be used by commands where the + /// process is publicly stopped. + /// + /// @param[in] source_step + /// If true and the frame has debug info, then do a source level + /// step over, else do a single instruction step over. + /// + /// @return + /// An error that describes anything that went wrong + //------------------------------------------------------------------ + virtual Error + StepOver (bool source_step); + + //------------------------------------------------------------------ + /// Default implementation for stepping out. + /// + /// This function is designed to be used by commands where the + /// process is publicly stopped. + /// + /// @return + /// An error that describes anything that went wrong + //------------------------------------------------------------------ + virtual Error + StepOut (); + //------------------------------------------------------------------ /// Retrieves the per-thread data area. /// Most OSs maintain a per-thread pointer (e.g. the FS register on /// x64), which we return the value of here. diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h index f4dfdb2..65d9b74 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadList.h @@ -45,6 +45,8 @@ public: void AddThread (const lldb::ThreadSP &thread_sp); + void + InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx); // Return the selected thread if there is one. Otherwise, return the thread // selected at index 0. lldb::ThreadSP diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanStepInRange.h index dbc8446..2f741f1 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanStepInRange.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/ThreadPlanStepInRange.h @@ -73,7 +73,7 @@ protected: SetFlagsToDefault (); bool - FrameMatchesAvoidRegexp (); + FrameMatchesAvoidCriteria (); private: diff --git a/contrib/llvm/tools/lldb/include/lldb/Target/UnwindAssembly.h b/contrib/llvm/tools/lldb/include/lldb/Target/UnwindAssembly.h index 6a4ae0c..254382a 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Target/UnwindAssembly.h +++ b/contrib/llvm/tools/lldb/include/lldb/Target/UnwindAssembly.h @@ -17,10 +17,11 @@ namespace lldb_private { class UnwindAssembly : + public std::enable_shared_from_this<UnwindAssembly>, public PluginInterface { public: - static UnwindAssembly* + static lldb::UnwindAssemblySP FindPlugin (const ArchSpec &arch); virtual diff --git a/contrib/llvm/tools/lldb/include/lldb/Utility/Iterable.h b/contrib/llvm/tools/lldb/include/lldb/Utility/Iterable.h index 9b91cae..1733537 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Utility/Iterable.h +++ b/contrib/llvm/tools/lldb/include/lldb/Utility/Iterable.h @@ -147,9 +147,14 @@ public: return m_iter >= rhs.m_iter; } - friend AdaptedConstIterator operator+(typename BackingIterator::difference_type, AdaptedConstIterator &); - friend typename BackingIterator::difference_type operator-(AdaptedConstIterator &, AdaptedConstIterator &); - friend void swap(AdaptedConstIterator &, AdaptedConstIterator &); + template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)> + friend AdaptedConstIterator<C1, E1, A1> operator+(typename C1::const_iterator::difference_type, AdaptedConstIterator<C1, E1, A1> &); + + template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)> + friend typename C1::const_iterator::difference_type operator-(AdaptedConstIterator<C1, E1, A1> &, AdaptedConstIterator<C1, E1, A1> &); + + template <typename C1, typename E1, E1 (*A1)(typename C1::const_iterator &)> + friend void swap(AdaptedConstIterator<C1, E1, A1> &, AdaptedConstIterator<C1, E1, A1> &); }; template <typename C, typename E, E (*A)(typename C::const_iterator &)> diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h index 0b34157..347e20f 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h @@ -46,7 +46,9 @@ namespace lldb { eLaunchFlagDisableSTDIO = (1u << 4), ///< Disable stdio for inferior process (e.g. for a GUI app) eLaunchFlagLaunchInTTY = (1u << 5), ///< Launch the process in a new TTY if supported by the host eLaunchFlagLaunchInShell= (1u << 6), ///< Launch the process inside a shell to get shell expansion - eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7) ///< Launch the process in a separate process group + eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7), ///< Launch the process in a separate process group + eLaunchFlagsDontMonitorProcess = (1u << 8) ///< If you are going to hand the process off (e.g. to debugserver) + ///< set this flag so lldb & the handee don't race to reap it. } LaunchFlags; //---------------------------------------------------------------------- @@ -726,6 +728,19 @@ namespace lldb { eFilePermissionsDirectoryDefault = eFilePermissionsUserRWX, } FilePermissions; + //---------------------------------------------------------------------- + // Queue work item types + // + // The different types of work that can be enqueued on a libdispatch + // aka Grand Central Dispatch (GCD) queue. + //---------------------------------------------------------------------- + typedef enum QueueItemKind + { + eQueueItemKindUnknown = 0, + eQueueItemKindFunction, + eQueueItemKindBlock + } QueueItemKind; + } // namespace lldb diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h b/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h index 68d85f0..43e589e 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-forward.h @@ -82,6 +82,7 @@ class Disassembler; struct DumpValueObjectOptions; class DynamicLibrary; class DynamicLoader; +class Editline; class EmulateInstruction; class Error; class EvaluateExpressionOptions; @@ -102,9 +103,9 @@ class FuncUnwinders; class Function; class FunctionInfo; class InlineFunctionInfo; -class InputReader; class Instruction; class InstructionList; +class IOHandler; class IRExecutionUnit; class LanguageRuntime; class SystemRuntime; @@ -181,6 +182,8 @@ class SearchFilter; class Section; class SectionImpl; class SectionList; +class SectionLoadHistory; +class SectionLoadList; class Settings; class SourceManager; class SourceManagerImpl; @@ -214,6 +217,9 @@ class TypeFilterImpl; #ifndef LLDB_DISABLE_PYTHON class ScriptedSyntheticChildren; #endif +class Queue; +class QueueItem; +class QueueImpl; class Target; class TargetList; class Thread; @@ -297,8 +303,8 @@ namespace lldb { typedef std::shared_ptr<lldb_private::Function> FunctionSP; typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP; typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP; - typedef std::shared_ptr<lldb_private::InputReader> InputReaderSP; typedef std::shared_ptr<lldb_private::Instruction> InstructionSP; + typedef std::shared_ptr<lldb_private::IOHandler> IOHandlerSP; typedef std::shared_ptr<lldb_private::LanguageRuntime> LanguageRuntimeSP; typedef std::shared_ptr<lldb_private::SystemRuntime> SystemRuntimeSP; typedef std::shared_ptr<lldb_private::LineTable> LineTableSP; @@ -334,12 +340,16 @@ namespace lldb { typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP; typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP; typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP; + typedef std::shared_ptr<lldb_private::Queue> QueueSP; + typedef std::weak_ptr<lldb_private::Queue> QueueWP; + typedef std::shared_ptr<lldb_private::QueueItem> QueueItemSP; typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP; #ifndef LLDB_DISABLE_PYTHON typedef std::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP; #endif // #ifndef LLDB_DISABLE_PYTHON typedef std::shared_ptr<lldb_private::Section> SectionSP; typedef std::weak_ptr<lldb_private::Section> SectionWP; + typedef std::shared_ptr<lldb_private::SectionLoadList> SectionLoadListSP; typedef std::shared_ptr<lldb_private::SearchFilter> SearchFilterSP; typedef std::shared_ptr<lldb_private::Settings> SettingsSP; typedef std::shared_ptr<lldb_private::StackFrame> StackFrameSP; @@ -349,6 +359,7 @@ namespace lldb { typedef std::shared_ptr<lldb_private::StoppointLocation> StoppointLocationSP; typedef std::shared_ptr<lldb_private::Stream> StreamSP; typedef std::weak_ptr<lldb_private::Stream> StreamWP; + typedef std::shared_ptr<lldb_private::StreamFile> StreamFileSP; typedef std::shared_ptr<lldb_private::StringSummaryFormat> StringTypeSummaryImplSP; typedef std::shared_ptr<lldb_private::SymbolFile> SymbolFileSP; typedef std::shared_ptr<lldb_private::SymbolFileType> SymbolFileTypeSP; @@ -373,6 +384,7 @@ namespace lldb { #ifndef LLDB_DISABLE_PYTHON typedef std::shared_ptr<lldb_private::ScriptedSyntheticChildren> ScriptedSyntheticChildrenSP; #endif + typedef std::shared_ptr<lldb_private::UnwindAssembly> UnwindAssemblySP; typedef std::shared_ptr<lldb_private::UnwindPlan> UnwindPlanSP; typedef lldb_private::SharingPtr<lldb_private::ValueObject> ValueObjectSP; typedef std::shared_ptr<lldb_private::Value> ValueSP; diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h index 9891942..c2273f5 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h @@ -117,7 +117,9 @@ typedef enum PathType ePathTypeHeaderDir, // Find LLDB header file directory ePathTypePythonDir, // Find Python modules (PYTHONPATH) directory ePathTypeLLDBSystemPlugins, // System plug-ins directory - ePathTypeLLDBUserPlugins // User plug-ins directory + ePathTypeLLDBUserPlugins, // User plug-ins directory + ePathTypeLLDBTempSystemDir // The LLDB temp directory for this system + } PathType; @@ -251,6 +253,15 @@ typedef enum MemoryModuleLoadLevel { } MemoryModuleLoadLevel; +//---------------------------------------------------------------------- +// Result enums for when reading multiple lines from IOHandlers +//---------------------------------------------------------------------- +enum class LineStatus { + Success, // The line that was just edited if good and should be added to the lines + Error, // There is an error with the current line and it needs to be re-edited before it can be accepted + Done // Lines are complete +}; + } // namespace lldb_private diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-log.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-log.h index 48cce69..9d8d735 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-log.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-log.h @@ -45,6 +45,7 @@ #define LIBLLDB_LOG_MMAP (1u << 23) #define LIBLLDB_LOG_OS (1u << 24) #define LIBLLDB_LOG_PLATFORM (1u << 25) +#define LIBLLDB_LOG_SYSTEM_RUNTIME (1u << 26) #define LIBLLDB_LOG_ALL (UINT32_MAX) #define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\ LIBLLDB_LOG_THREAD |\ diff --git a/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp b/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp index 11ad149..fbdc0e3 100644 --- a/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBBreakpoint.cpp @@ -23,6 +23,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" diff --git a/contrib/llvm/tools/lldb/source/API/SBCommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/API/SBCommandInterpreter.cpp index ac77e2e..f1faa13 100644 --- a/contrib/llvm/tools/lldb/source/API/SBCommandInterpreter.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBCommandInterpreter.cpp @@ -107,6 +107,22 @@ SBCommandInterpreter::AliasExists (const char *cmd) return false; } +bool +SBCommandInterpreter::IsActive () +{ + if (m_opaque_ptr) + return m_opaque_ptr->IsActive (); + return false; +} + +const char * +SBCommandInterpreter::GetIOHandlerControlSequence(char ch) +{ + if (m_opaque_ptr) + return m_opaque_ptr->GetDebugger().GetTopIOHandlerControlSequence (ch).GetCString(); + return NULL; +} + lldb::ReturnStatus SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history) { diff --git a/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp b/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp index 10c0b7d..8d6887a 100644 --- a/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBDebugger.cpp @@ -20,7 +20,6 @@ #include "lldb/API/SBError.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBFrame.h" -#include "lldb/API/SBInputReader.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBSourceManager.h" #include "lldb/API/SBStream.h" @@ -37,6 +36,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamFile.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/DynamicLibrary.h" #include "lldb/Interpreter/Args.h" @@ -49,6 +49,29 @@ using namespace lldb; using namespace lldb_private; +SBInputReader::SBInputReader() +{ +} +SBInputReader::~SBInputReader() +{ +} + +SBError +SBInputReader::Initialize(lldb::SBDebugger& sb_debugger, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool) +{ + return SBError(); +} + +void +SBInputReader::SetIsDone(bool) +{ +} +bool +SBInputReader::IsActive() const +{ + return false; +} + static lldb::DynamicLibrarySP LoadPlugin (const lldb::DebuggerSP &debugger_sp, const FileSpec& spec, Error& error) { @@ -111,7 +134,7 @@ SBDebugger::Clear () log->Printf ("SBDebugger(%p)::Clear ()", m_opaque_sp.get()); if (m_opaque_sp) - m_opaque_sp->CleanUpInputReaders (); + m_opaque_sp->ClearIOHandlers (); m_opaque_sp.reset(); } @@ -309,7 +332,11 @@ FILE * SBDebugger::GetInputFileHandle () { if (m_opaque_sp) - return m_opaque_sp->GetInputFile().GetStream(); + { + StreamFileSP stream_file_sp (m_opaque_sp->GetInputFile()); + if (stream_file_sp) + return stream_file_sp->GetFile().GetStream(); + } return NULL; } @@ -317,7 +344,11 @@ FILE * SBDebugger::GetOutputFileHandle () { if (m_opaque_sp) - return m_opaque_sp->GetOutputFile().GetStream(); + { + StreamFileSP stream_file_sp (m_opaque_sp->GetOutputFile()); + if (stream_file_sp) + return stream_file_sp->GetFile().GetStream(); + } return NULL; } @@ -325,7 +356,12 @@ FILE * SBDebugger::GetErrorFileHandle () { if (m_opaque_sp) - return m_opaque_sp->GetErrorFile().GetStream(); + if (m_opaque_sp) + { + StreamFileSP stream_file_sp (m_opaque_sp->GetErrorFile()); + if (stream_file_sp) + return stream_file_sp->GetFile().GetStream(); + } return NULL; } @@ -885,17 +921,17 @@ SBDebugger::DispatchInput (void* baton, const void *data, size_t data_len) void SBDebugger::DispatchInput (const void *data, size_t data_len) { - Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf ("SBDebugger(%p)::DispatchInput (data=\"%.*s\", size_t=%" PRIu64 ")", - m_opaque_sp.get(), - (int) data_len, - (const char *) data, - (uint64_t)data_len); - - if (m_opaque_sp) - m_opaque_sp->DispatchInput ((const char *) data, data_len); +// Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); +// +// if (log) +// log->Printf ("SBDebugger(%p)::DispatchInput (data=\"%.*s\", size_t=%" PRIu64 ")", +// m_opaque_sp.get(), +// (int) data_len, +// (const char *) data, +// (uint64_t)data_len); +// +// if (m_opaque_sp) +// m_opaque_sp->DispatchInput ((const char *) data, data_len); } void @@ -911,54 +947,18 @@ SBDebugger::DispatchInputEndOfFile () if (m_opaque_sp) m_opaque_sp->DispatchInputEndOfFile (); } - -bool -SBDebugger::InputReaderIsTopReader (const lldb::SBInputReader &reader) -{ - Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf ("SBDebugger(%p)::InputReaderIsTopReader (SBInputReader(%p))", m_opaque_sp.get(), &reader); - - if (m_opaque_sp && reader.IsValid()) - { - InputReaderSP reader_sp (*reader); - return m_opaque_sp->InputReaderIsTopReader (reader_sp); - } - - return false; -} - void SBDebugger::PushInputReader (SBInputReader &reader) { - Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf ("SBDebugger(%p)::PushInputReader (SBInputReader(%p))", m_opaque_sp.get(), &reader); - - if (m_opaque_sp && reader.IsValid()) - { - TargetSP target_sp (m_opaque_sp->GetSelectedTarget()); - Mutex::Locker api_locker; - if (target_sp) - api_locker.Lock(target_sp->GetAPIMutex()); - InputReaderSP reader_sp(*reader); - m_opaque_sp->PushInputReader (reader_sp); - } } void -SBDebugger::NotifyTopInputReader (InputReaderAction notification) +SBDebugger::RunCommandInterpreter (bool auto_handle_events, + bool spawn_thread) { - Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf ("SBDebugger(%p)::NotifyTopInputReader (%d)", m_opaque_sp.get(), notification); - if (m_opaque_sp) - m_opaque_sp->NotifyTopInputReader (notification); + m_opaque_sp->GetCommandInterpreter().RunCommandInterpreter(auto_handle_events, spawn_thread); } void @@ -1050,7 +1050,7 @@ SBDebugger::GetInternalVariableValue (const char *var_name, const char *debugger if (!value_str.empty()) { StringList string_list; - string_list.SplitIntoLines(value_str.c_str(), value_str.size()); + string_list.SplitIntoLines(value_str); return SBStringList(&string_list); } } diff --git a/contrib/llvm/tools/lldb/source/API/SBFrame.cpp b/contrib/llvm/tools/lldb/source/API/SBFrame.cpp index 1a1a63b..44fc654 100644 --- a/contrib/llvm/tools/lldb/source/API/SBFrame.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBFrame.cpp @@ -845,6 +845,8 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy frame = exe_ctx.GetFramePtr(); if (frame) { + VariableList variable_list; + switch (value_type) { case eValueTypeVariableGlobal: // global variable @@ -852,8 +854,7 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy case eValueTypeVariableArgument: // function argument variables case eValueTypeVariableLocal: // function local variables { - VariableList *variable_list = frame->GetVariableList(true); - + SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock)); const bool can_create = true; @@ -863,21 +864,22 @@ SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueTy if (sc.block && sc.block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, - variable_list)) + &variable_list)) { + if (value_type == eValueTypeVariableGlobal) + { + const bool get_file_globals = true; + VariableList* frame_vars = frame->GetVariableList(get_file_globals); + if (frame_vars) + frame_vars->AppendVariablesIfUnique(variable_list); + } ConstString const_name(name); - const uint32_t num_variables = variable_list->GetSize(); - for (uint32_t i = 0; i < num_variables; ++i) + VariableSP variable_sp(variable_list.FindVariable(const_name,value_type)); + if (variable_sp) { - VariableSP variable_sp (variable_list->GetVariableAtIndex(i)); - if (variable_sp && - variable_sp->GetScope() == value_type && - variable_sp->GetName() == const_name) - { - value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues); - sb_value.SetSP (value_sp, use_dynamic); - break; - } + value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues); + sb_value.SetSP (value_sp, use_dynamic); + break; } } } @@ -1386,20 +1388,22 @@ SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &option frame = exe_ctx.GetFramePtr(); if (frame) { -#ifdef LLDB_CONFIGURATION_DEBUG - StreamString frame_description; - frame->DumpUsingSettingsFormat (&frame_description); - Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s", - expr, options.GetFetchDynamicValue(), frame_description.GetString().c_str()); -#endif - exe_results = target->EvaluateExpression (expr, + if (target->GetDisplayExpressionsInCrashlogs()) + { + StreamString frame_description; + frame->DumpUsingSettingsFormat (&frame_description); + Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s", + expr, options.GetFetchDynamicValue(), frame_description.GetString().c_str()); + } + + exe_results = target->EvaluateExpression (expr, frame, expr_value_sp, options.ref()); expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue()); -#ifdef LLDB_CONFIGURATION_DEBUG - Host::SetCrashDescription (NULL); -#endif + + if (target->GetDisplayExpressionsInCrashlogs()) + Host::SetCrashDescription (NULL); } else { diff --git a/contrib/llvm/tools/lldb/source/API/SBInputReader.cpp b/contrib/llvm/tools/lldb/source/API/SBInputReader.cpp deleted file mode 100644 index 82b75c8..0000000 --- a/contrib/llvm/tools/lldb/source/API/SBInputReader.cpp +++ /dev/null @@ -1,216 +0,0 @@ -//===-- SBInputReader.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-enumerations.h" - -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBInputReader.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBStringList.h" -#include "lldb/Core/InputReader.h" -#include "lldb/Core/Log.h" - - -using namespace lldb; -using namespace lldb_private; - -SBInputReader::SBInputReader () : - m_opaque_sp (), - m_callback_function (NULL), - m_callback_baton (NULL) - -{ -} - -SBInputReader::SBInputReader (const lldb::InputReaderSP &reader_sp) : - m_opaque_sp (reader_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf ("SBInputReader::SBInputReader (reader_sp=%p) => SBInputReader(%p)", reader_sp.get(), - m_opaque_sp.get()); -} - -SBInputReader::SBInputReader (const SBInputReader &rhs) : - m_opaque_sp (rhs.m_opaque_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf("SBInputReader::SBInputReader (rhs.sp=%p) => SBInputReader(%p)", - rhs.m_opaque_sp.get(), m_opaque_sp.get()); -} - -SBInputReader::~SBInputReader () -{ -} - -size_t -SBInputReader::PrivateCallback -( - void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - SBInputReader *sb_reader = (SBInputReader *)baton; - return sb_reader->m_callback_function (sb_reader->m_callback_baton, - sb_reader, - notification, - bytes, - bytes_len); -} - -SBError -SBInputReader::Initialize -( - SBDebugger &debugger, - Callback callback_function, - void *callback_baton, - lldb::InputReaderGranularity granularity, - const char *end_token, - const char *prompt, - bool echo -) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - if (log) - log->Printf("SBInputReader(%p)::Initialize (SBDebugger(%p), callback_function=%p, callback_baton=%p, " - "granularity=%s, end_token=\"%s\", prompt=\"%s\", echo=%i)", - m_opaque_sp.get(), - debugger.get(), - callback_function, - callback_baton, - InputReader::GranularityAsCString (granularity), end_token, prompt, - echo); - - SBError sb_error; - m_opaque_sp.reset (new InputReader (debugger.ref())); - - m_callback_function = callback_function; - m_callback_baton = callback_baton; - - if (m_opaque_sp) - { - sb_error.SetError (m_opaque_sp->Initialize (SBInputReader::PrivateCallback, - this, - granularity, - end_token, - prompt, - echo)); - } - - if (sb_error.Fail()) - { - m_opaque_sp.reset (); - m_callback_function = NULL; - m_callback_baton = NULL; - } - - if (log) - { - SBStream sstr; - sb_error.GetDescription (sstr); - log->Printf ("SBInputReader(%p)::Initialize (...) => SBError(%p): %s", m_opaque_sp.get(), - sb_error.get(), sstr.GetData()); - } - - return sb_error; -} - -bool -SBInputReader::IsValid () const -{ - return (m_opaque_sp.get() != NULL); -} - -const SBInputReader & -SBInputReader::operator = (const SBInputReader &rhs) -{ - if (this != &rhs) - m_opaque_sp = rhs.m_opaque_sp; - return *this; -} - -InputReader * -SBInputReader::operator->() const -{ - return m_opaque_sp.get(); -} - -lldb::InputReaderSP & -SBInputReader::operator *() -{ - return m_opaque_sp; -} - -const lldb::InputReaderSP & -SBInputReader::operator *() const -{ - return m_opaque_sp; -} - -InputReader * -SBInputReader::get() const -{ - return m_opaque_sp.get(); -} - -InputReader & -SBInputReader::ref() const -{ - assert (m_opaque_sp.get()); - return *m_opaque_sp; -} - -bool -SBInputReader::IsDone () const -{ - if (m_opaque_sp) - return m_opaque_sp->IsDone(); - else - return true; -} - -void -SBInputReader::SetIsDone (bool value) -{ - if (m_opaque_sp) - m_opaque_sp->SetIsDone (value); -} - -bool -SBInputReader::IsActive () const -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); - - bool ret_value = false; - if (m_opaque_sp) - ret_value = m_opaque_sp->IsActive(); - - if (log) - log->Printf ("SBInputReader(%p)::IsActive () => %i", m_opaque_sp.get(), ret_value); - - return ret_value; -} - -InputReaderGranularity -SBInputReader::GetGranularity () -{ - if (m_opaque_sp) - return m_opaque_sp->GetGranularity(); - else - return eInputReaderGranularityInvalid; -} diff --git a/contrib/llvm/tools/lldb/source/API/SBModule.cpp b/contrib/llvm/tools/lldb/source/API/SBModule.cpp index 0285cf3..c8543d4 100644 --- a/contrib/llvm/tools/lldb/source/API/SBModule.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBModule.cpp @@ -69,7 +69,7 @@ SBModule::SBModule (lldb::SBProcess &process, lldb::addr_t header_addr) : { Target &target = process_sp->GetTarget(); bool changed = false; - m_opaque_sp->SetLoadAddress(target, 0, changed); + m_opaque_sp->SetLoadAddress(target, 0, true, changed); target.GetImages().Append(m_opaque_sp); } } @@ -579,6 +579,23 @@ SBModule::FindTypes (const char *type) return retval; } +lldb::SBType +SBModule::GetTypeByID (lldb::user_id_t uid) +{ + ModuleSP module_sp (GetSP ()); + if (module_sp) + { + SymbolVendor* vendor = module_sp->GetSymbolVendor(); + if (vendor) + { + Type *type_ptr = vendor->ResolveTypeUID(uid); + if (type_ptr) + return SBType(type_ptr->shared_from_this()); + } + } + return SBType(); +} + lldb::SBTypeList SBModule::GetTypes (uint32_t type_mask) { diff --git a/contrib/llvm/tools/lldb/source/API/SBProcess.cpp b/contrib/llvm/tools/lldb/source/API/SBProcess.cpp index 557006f..235388b 100644 --- a/contrib/llvm/tools/lldb/source/API/SBProcess.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBProcess.cpp @@ -535,6 +535,53 @@ SBProcess::GetThreadAtIndex (size_t index) } uint32_t +SBProcess::GetNumQueues () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + uint32_t num_queues = 0; + ProcessSP process_sp(GetSP()); + if (process_sp) + { + Process::StopLocker stop_locker; + + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); + num_queues = process_sp->GetQueueList().GetSize(); + } + + if (log) + log->Printf ("SBProcess(%p)::GetNumQueues () => %d", process_sp.get(), num_queues); + + return num_queues; +} + +SBQueue +SBProcess::GetQueueAtIndex (size_t index) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + SBQueue sb_queue; + QueueSP queue_sp; + ProcessSP process_sp(GetSP()); + if (process_sp) + { + Process::StopLocker stop_locker; + Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex()); + queue_sp = process_sp->GetQueueList().GetQueueAtIndex(index); + sb_queue.SetQueue (queue_sp); + } + + if (log) + { + log->Printf ("SBProcess(%p)::GetQueueAtIndex (index=%d) => SBQueue(%p)", + process_sp.get(), (uint32_t) index, queue_sp.get()); + } + + return sb_queue; +} + + +uint32_t SBProcess::GetStopID(bool include_expression_stops) { ProcessSP process_sp(GetSP()); diff --git a/contrib/llvm/tools/lldb/source/API/SBQueue.cpp b/contrib/llvm/tools/lldb/source/API/SBQueue.cpp new file mode 100644 index 0000000..8d67a48 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/API/SBQueue.cpp @@ -0,0 +1,368 @@ +//===-- SBQueue.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/SBQueue.h" + +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBThread.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Queue.h" +#include "lldb/Target/QueueItem.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +namespace lldb_private +{ + + class QueueImpl + { + public: + QueueImpl () : + m_queue_wp(), + m_threads(), + m_thread_list_fetched(false), + m_pending_items(), + m_pending_items_fetched(false) + { + } + + QueueImpl (const lldb::QueueSP &queue_sp) : + m_queue_wp(), + m_threads(), + m_thread_list_fetched(false), + m_pending_items(), + m_pending_items_fetched(false) + { + m_queue_wp = queue_sp; + } + + QueueImpl (const QueueImpl &rhs) + { + if (&rhs == this) + return; + m_queue_wp = rhs.m_queue_wp; + m_threads = rhs.m_threads; + m_thread_list_fetched = rhs.m_thread_list_fetched; + m_pending_items = rhs.m_pending_items; + m_pending_items_fetched = rhs.m_pending_items_fetched; + } + + ~QueueImpl () + { + } + + bool + IsValid () + { + return m_queue_wp.lock() != NULL; + } + + void + Clear () + { + m_queue_wp.reset(); + m_thread_list_fetched = false; + m_threads.clear(); + m_pending_items_fetched = false; + m_pending_items.clear(); + } + + void + SetQueue (const lldb::QueueSP &queue_sp) + { + Clear(); + m_queue_wp = queue_sp; + } + + lldb::queue_id_t + GetQueueID () const + { + lldb::queue_id_t result = LLDB_INVALID_QUEUE_ID; + lldb::QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + result = queue_sp->GetID(); + } + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBQueue(%p)::GetQueueID () => 0x%" PRIx64, this, result); + return result; + } + + uint32_t + GetIndexID () const + { + uint32_t result = LLDB_INVALID_INDEX32; + lldb::QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + result = queue_sp->GetIndexID(); + } + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBQueueImpl(%p)::GetIndexID () => %d", this, result); + return result; + } + + const char * + GetName () const + { + const char *name = NULL; + lldb::QueueSP queue_sp = m_queue_wp.lock (); + if (queue_sp.get()) + { + name = queue_sp->GetName(); + } + + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + if (log) + log->Printf ("SBQueueImpl(%p)::GetName () => %s", this, name ? name : "NULL"); + + return name; + } + + void + FetchThreads () + { + if (m_thread_list_fetched == false) + { + lldb::QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + Process::StopLocker stop_locker; + if (stop_locker.TryLock (&queue_sp->GetProcess()->GetRunLock())) + { + const std::vector<ThreadSP> thread_list(queue_sp->GetThreads()); + m_thread_list_fetched = true; + const uint32_t num_threads = thread_list.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + { + ThreadSP thread_sp = thread_list[idx]; + if (thread_sp && thread_sp->IsValid()) + { + m_threads.push_back (thread_sp); + } + } + } + } + } + } + + void + FetchItems () + { + if (m_pending_items_fetched == false) + { + QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + Process::StopLocker stop_locker; + if (stop_locker.TryLock (&queue_sp->GetProcess()->GetRunLock())) + { + const std::vector<QueueItemSP> queue_items(queue_sp->GetPendingItems()); + m_pending_items_fetched = true; + const uint32_t num_pending_items = queue_items.size(); + for (uint32_t idx = 0; idx < num_pending_items; ++idx) + { + QueueItemSP item = queue_items[idx]; + if (item && item->IsValid()) + { + m_pending_items.push_back (item); + } + } + } + } + } + } + + uint32_t + GetNumThreads () + { + uint32_t result = 0; + + FetchThreads(); + if (m_thread_list_fetched) + { + result = m_threads.size(); + } + return result; + } + + lldb::SBThread + GetThreadAtIndex (uint32_t idx) + { + FetchThreads(); + + SBThread sb_thread; + QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp && idx < m_threads.size()) + { + ProcessSP process_sp = queue_sp->GetProcess(); + if (process_sp) + { + ThreadSP thread_sp = m_threads[idx].lock(); + if (thread_sp) + { + sb_thread.SetThread (thread_sp); + } + } + } + return sb_thread; + } + + + uint32_t + GetNumPendingItems () + { + uint32_t result = 0; + FetchItems(); + + if (m_pending_items_fetched) + { + result = m_pending_items.size(); + } + return result; + } + + lldb::SBQueueItem + GetPendingItemAtIndex (uint32_t idx) + { + SBQueueItem result; + FetchItems(); + if (m_pending_items_fetched && idx < m_pending_items.size()) + { + result.SetQueueItem (m_pending_items[idx]); + } + return result; + } + + lldb::SBProcess + GetProcess () + { + SBProcess result; + QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + result.SetSP (queue_sp->GetProcess()); + } + return result; + } + + private: + lldb::QueueWP m_queue_wp; + std::vector<lldb::ThreadWP> m_threads; // threads currently executing this queue's items + bool m_thread_list_fetched; // have we tried to fetch the threads list already? + std::vector<lldb::QueueItemSP> m_pending_items; // items currently enqueued + bool m_pending_items_fetched; // have we tried to fetch the item list already? + }; + +} + +SBQueue::SBQueue () : + m_opaque_sp (new QueueImpl()) +{ +} + +SBQueue::SBQueue (const QueueSP& queue_sp) : + m_opaque_sp (new QueueImpl (queue_sp)) +{ +} + +SBQueue::SBQueue (const SBQueue &rhs) +{ + if (&rhs == this) + return; + + m_opaque_sp = rhs.m_opaque_sp; +} + +const lldb::SBQueue & +SBQueue::operator = (const lldb::SBQueue &rhs) +{ + m_opaque_sp = rhs.m_opaque_sp; + return *this; +} + +SBQueue::~SBQueue() +{ +} + +bool +SBQueue::IsValid() const +{ + return m_opaque_sp->IsValid(); +} + + +void +SBQueue::Clear () +{ + m_opaque_sp->Clear(); +} + + +void +SBQueue::SetQueue (const QueueSP& queue_sp) +{ + m_opaque_sp->SetQueue (queue_sp); +} + +lldb::queue_id_t +SBQueue::GetQueueID () const +{ + return m_opaque_sp->GetQueueID (); +} + +uint32_t +SBQueue::GetIndexID () const +{ + return m_opaque_sp->GetIndexID (); +} + +const char * +SBQueue::GetName () const +{ + return m_opaque_sp->GetName (); +} + +uint32_t +SBQueue::GetNumThreads () +{ + return m_opaque_sp->GetNumThreads (); +} + +SBThread +SBQueue::GetThreadAtIndex (uint32_t idx) +{ + return m_opaque_sp->GetThreadAtIndex (idx); +} + + +uint32_t +SBQueue::GetNumPendingItems () +{ + return m_opaque_sp->GetNumPendingItems (); +} + +SBQueueItem +SBQueue::GetPendingItemAtIndex (uint32_t idx) +{ + return m_opaque_sp->GetPendingItemAtIndex (idx); +} + +SBProcess +SBQueue::GetProcess () +{ + return m_opaque_sp->GetProcess(); +} diff --git a/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp b/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp new file mode 100644 index 0000000..481d51e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/API/SBQueueItem.cpp @@ -0,0 +1,120 @@ +//===-- SBQueueItem.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/lldb-forward.h" + +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBQueueItem.h" +#include "lldb/API/SBThread.h" +#include "lldb/Core/Address.h" +#include "lldb/Target/QueueItem.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Constructors +//---------------------------------------------------------------------- +SBQueueItem::SBQueueItem () : + m_queue_item_sp() +{ +} + +SBQueueItem::SBQueueItem (const QueueItemSP& queue_item_sp) : + m_queue_item_sp (queue_item_sp) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +SBQueueItem::~SBQueueItem() +{ + m_queue_item_sp.reset(); +} + +bool +SBQueueItem::IsValid() const +{ + return m_queue_item_sp.get() != NULL; +} + + +void +SBQueueItem::Clear () +{ + m_queue_item_sp.reset(); +} + + +void +SBQueueItem::SetQueueItem (const QueueItemSP& queue_item_sp) +{ + m_queue_item_sp = queue_item_sp; +} + + +lldb::QueueItemKind +SBQueueItem::GetKind () const +{ + QueueItemKind result = eQueueItemKindUnknown; + if (m_queue_item_sp) + { + result = m_queue_item_sp->GetKind (); + } + return result; +} + +void +SBQueueItem::SetKind (lldb::QueueItemKind kind) +{ + if (m_queue_item_sp) + { + m_queue_item_sp->SetKind (kind); + } +} + +SBAddress +SBQueueItem::GetAddress () const +{ + SBAddress result; + if (m_queue_item_sp) + { + result.SetAddress (&m_queue_item_sp->GetAddress()); + } + return result; +} + +void +SBQueueItem::SetAddress (SBAddress addr) +{ + if (m_queue_item_sp) + { + m_queue_item_sp->SetAddress (addr.ref()); + } +} + +SBThread +SBQueueItem::GetExtendedBacktraceThread (const char *type) +{ + SBThread result; + if (m_queue_item_sp) + { + ThreadSP thread_sp; + ConstString type_const (type); + thread_sp = m_queue_item_sp->GetExtendedBacktraceThread (type_const); + if (thread_sp) + { + result.SetThread (thread_sp); + } + } + return result; +} diff --git a/contrib/llvm/tools/lldb/source/API/SBTarget.cpp b/contrib/llvm/tools/lldb/source/API/SBTarget.cpp index c8bc217..224349c 100644 --- a/contrib/llvm/tools/lldb/source/API/SBTarget.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBTarget.cpp @@ -52,6 +52,7 @@ #include "lldb/Symbol/VariableList.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" + #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" @@ -688,57 +689,26 @@ SBTarget::Launch return sb_process; } } - else - { - if (listener.IsValid()) - process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL); - else - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - } - if (process_sp) - { - sb_process.SetSP (process_sp); - if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO")) - launch_flags |= eLaunchFlagDisableSTDIO; + if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO")) + launch_flags |= eLaunchFlagDisableSTDIO; - ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags); - - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) - launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); - if (argv) - launch_info.GetArguments().AppendArguments (argv); - if (envp) - launch_info.GetEnvironmentEntries ().SetArguments (envp); - - error.SetError (process_sp->Launch (launch_info)); - if (error.Success()) - { - // We we are stopping at the entry point, we can return now! - if (stop_at_entry) - return sb_process; - - // Make sure we are stopped at the entry - StateType state = process_sp->WaitForProcessToStop (NULL); - if (state == eStateStopped) - { - // resume the process to skip the entry point - error.SetError (process_sp->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (target_sp->GetDebugger().GetAsyncExecution () == false) - process_sp->WaitForProcessToStop (NULL); - } - } - } - } + ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags); + + Module *exe_module = target_sp->GetExecutableModulePointer(); + if (exe_module) + launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); + if (argv) + launch_info.GetArguments().AppendArguments (argv); + if (envp) + launch_info.GetEnvironmentEntries ().SetArguments (envp); + + if (listener.IsValid()) + error.SetError (target_sp->Launch(listener.ref(), launch_info)); else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } + error.SetError (target_sp->Launch(target_sp->GetDebugger().GetListener(), launch_info)); + + sb_process.SetSP(target_sp->GetProcessSP()); } else { @@ -749,7 +719,7 @@ SBTarget::Launch if (log) { log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)", - target_sp.get(), process_sp.get()); + target_sp.get(), sb_process.GetSP().get()); } return sb_process; @@ -761,7 +731,6 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error) Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); SBProcess sb_process; - ProcessSP process_sp; TargetSP target_sp(GetSP()); if (log) @@ -773,7 +742,8 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error) { Mutex::Locker api_locker (target_sp->GetAPIMutex()); StateType state = eStateInvalid; - process_sp = target_sp->GetProcessSP(); + { + ProcessSP process_sp = target_sp->GetProcessSP(); if (process_sp) { state = process_sp->GetState(); @@ -787,58 +757,20 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error) return sb_process; } } - - if (state != eStateConnected) - process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL); - - if (process_sp) - { - sb_process.SetSP (process_sp); - lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref(); + } - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) - launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); + lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref(); - const ArchSpec &arch_spec = target_sp->GetArchitecture(); - if (arch_spec.IsValid()) - launch_info.GetArchitecture () = arch_spec; - - error.SetError (process_sp->Launch (launch_info)); - const bool synchronous_execution = target_sp->GetDebugger().GetAsyncExecution () == false; - if (error.Success()) - { - if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - { - // If we are doing synchronous mode, then wait for the initial - // stop to happen, else, return and let the caller watch for - // the stop - if (synchronous_execution) - process_sp->WaitForProcessToStop (NULL); - // We we are stopping at the entry point, we can return now! - return sb_process; - } - - // Make sure we are stopped at the entry - StateType state = process_sp->WaitForProcessToStop (NULL); - if (state == eStateStopped) - { - // resume the process to skip the entry point - error.SetError (process_sp->Resume()); - if (error.Success()) - { - // If we are doing synchronous mode, then wait for the - // process to stop yet again! - if (synchronous_execution) - process_sp->WaitForProcessToStop (NULL); - } - } - } - } - else - { - error.SetErrorString ("unable to create lldb_private::Process"); - } + Module *exe_module = target_sp->GetExecutableModulePointer(); + if (exe_module) + launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); + + const ArchSpec &arch_spec = target_sp->GetArchitecture(); + if (arch_spec.IsValid()) + launch_info.GetArchitecture () = arch_spec; + + error.SetError (target_sp->Launch (target_sp->GetDebugger().GetListener(), launch_info)); + sb_process.SetSP(target_sp->GetProcessSP()); } else { @@ -848,8 +780,8 @@ SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error) log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API); if (log) { - log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)", - target_sp.get(), process_sp.get()); + log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)", + target_sp.get(), sb_process.GetSP().get()); } return sb_process; @@ -1263,7 +1195,7 @@ SBTarget::ResolveLoadAddress (lldb::addr_t vm_addr) if (target_sp) { Mutex::Locker api_locker (target_sp->GetAPIMutex()); - if (target_sp->GetSectionLoadList().ResolveLoadAddress (vm_addr, addr)) + if (target_sp->ResolveLoadAddress (vm_addr, addr)) return sb_addr; } @@ -1273,6 +1205,26 @@ SBTarget::ResolveLoadAddress (lldb::addr_t vm_addr) return sb_addr; } + +lldb::SBAddress +SBTarget::ResolvePastLoadAddress (uint32_t stop_id, lldb::addr_t vm_addr) +{ + lldb::SBAddress sb_addr; + Address &addr = sb_addr.ref(); + TargetSP target_sp(GetSP()); + if (target_sp) + { + Mutex::Locker api_locker (target_sp->GetAPIMutex()); + if (target_sp->ResolveLoadAddress (vm_addr, addr)) + return sb_addr; + } + + // We have a load address that isn't in a section, just return an address + // with the offset filled in (the address) and the section set to NULL + addr.SetRawAddress(vm_addr); + return sb_addr; +} + SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const SBAddress& addr, uint32_t resolve_scope) @@ -2479,10 +2431,14 @@ SBTarget::SetSectionLoadAddress (lldb::SBSection section, } else { - if (target_sp->GetSectionLoadList().SetSectionLoadAddress (section_sp, section_base_addr)) + ProcessSP process_sp (target_sp->GetProcessSP()); + uint32_t stop_id = 0; + if (process_sp) + stop_id = process_sp->GetStopID(); + + if (target_sp->SetSectionLoadAddress (section_sp, section_base_addr)) { // Flush info in the process (stack frames, etc) - ProcessSP process_sp (target_sp->GetProcessSP()); if (process_sp) process_sp->Flush(); } @@ -2511,10 +2467,14 @@ SBTarget::ClearSectionLoadAddress (lldb::SBSection section) } else { - if (target_sp->GetSectionLoadList().SetSectionUnloaded (section.GetSP())) + ProcessSP process_sp (target_sp->GetProcessSP()); + uint32_t stop_id = 0; + if (process_sp) + stop_id = process_sp->GetStopID(); + + if (target_sp->SetSectionUnloaded (section.GetSP())) { // Flush info in the process (stack frames, etc) - ProcessSP process_sp (target_sp->GetProcessSP()); if (process_sp) process_sp->Flush(); } @@ -2539,7 +2499,7 @@ SBTarget::SetModuleLoadAddress (lldb::SBModule module, int64_t slide_offset) if (module_sp) { bool changed = false; - if (module_sp->SetLoadAddress (*target_sp, slide_offset, changed)) + if (module_sp->SetLoadAddress (*target_sp, slide_offset, true, changed)) { // The load was successful, make sure that at least some sections // changed before we notify that our module was loaded. @@ -2586,13 +2546,18 @@ SBTarget::ClearModuleLoadAddress (lldb::SBModule module) SectionList *section_list = objfile->GetSectionList(); if (section_list) { + ProcessSP process_sp (target_sp->GetProcessSP()); + uint32_t stop_id = 0; + if (process_sp) + stop_id = process_sp->GetStopID(); + bool changed = false; const size_t num_sections = section_list->GetSize(); for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { SectionSP section_sp (section_list->GetSectionAtIndex(sect_idx)); if (section_sp) - changed |= target_sp->GetSectionLoadList().SetSectionUnloaded (section_sp) > 0; + changed |= target_sp->SetSectionUnloaded (section_sp) > 0; } if (changed) { diff --git a/contrib/llvm/tools/lldb/source/API/SBType.cpp b/contrib/llvm/tools/lldb/source/API/SBType.cpp index 3055c27..5ca7ddf 100644 --- a/contrib/llvm/tools/lldb/source/API/SBType.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBType.cpp @@ -186,6 +186,14 @@ SBType::GetReferenceType() } SBType +SBType::GetTypedefedType() +{ + if (!IsValid()) + return SBType(); + return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetTypedefedType()))); +} + +SBType SBType::GetDereferencedType() { if (!IsValid()) diff --git a/contrib/llvm/tools/lldb/source/API/SBTypeCategory.cpp b/contrib/llvm/tools/lldb/source/API/SBTypeCategory.cpp index 08fdefa..9fe4dad 100644 --- a/contrib/llvm/tools/lldb/source/API/SBTypeCategory.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBTypeCategory.cpp @@ -87,7 +87,7 @@ SBTypeCategory::GetNumFormats () if (!IsValid()) return 0; - return m_opaque_sp->GetValueNavigator()->GetCount() + m_opaque_sp->GetRegexValueNavigator()->GetCount(); + return m_opaque_sp->GetTypeFormatsContainer()->GetCount() + m_opaque_sp->GetRegexTypeFormatsContainer()->GetCount(); } uint32_t @@ -95,7 +95,7 @@ SBTypeCategory::GetNumSummaries () { if (!IsValid()) return 0; - return m_opaque_sp->GetSummaryNavigator()->GetCount() + m_opaque_sp->GetRegexSummaryNavigator()->GetCount(); + return m_opaque_sp->GetTypeSummariesContainer()->GetCount() + m_opaque_sp->GetRegexTypeSummariesContainer()->GetCount(); } uint32_t @@ -103,7 +103,7 @@ SBTypeCategory::GetNumFilters () { if (!IsValid()) return 0; - return m_opaque_sp->GetFilterNavigator()->GetCount() + m_opaque_sp->GetRegexFilterNavigator()->GetCount(); + return m_opaque_sp->GetTypeFiltersContainer()->GetCount() + m_opaque_sp->GetRegexTypeFiltersContainer()->GetCount(); } #ifndef LLDB_DISABLE_PYTHON @@ -112,7 +112,7 @@ SBTypeCategory::GetNumSynthetics () { if (!IsValid()) return 0; - return m_opaque_sp->GetSyntheticNavigator()->GetCount() + m_opaque_sp->GetRegexSyntheticNavigator()->GetCount(); + return m_opaque_sp->GetTypeSyntheticsContainer()->GetCount() + m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetCount(); } #endif @@ -162,9 +162,9 @@ SBTypeCategory::GetFilterForType (SBTypeNameSpecifier spec) lldb::SyntheticChildrenSP children_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexFilterNavigator()->GetExact(ConstString(spec.GetName()), children_sp); + m_opaque_sp->GetRegexTypeFiltersContainer()->GetExact(ConstString(spec.GetName()), children_sp); else - m_opaque_sp->GetFilterNavigator()->GetExact(ConstString(spec.GetName()), children_sp); + m_opaque_sp->GetTypeFiltersContainer()->GetExact(ConstString(spec.GetName()), children_sp); if (!children_sp) return lldb::SBTypeFilter(); @@ -186,9 +186,9 @@ SBTypeCategory::GetFormatForType (SBTypeNameSpecifier spec) lldb::TypeFormatImplSP format_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexValueNavigator()->GetExact(ConstString(spec.GetName()), format_sp); + m_opaque_sp->GetRegexTypeFormatsContainer()->GetExact(ConstString(spec.GetName()), format_sp); else - m_opaque_sp->GetValueNavigator()->GetExact(ConstString(spec.GetName()), format_sp); + m_opaque_sp->GetTypeFormatsContainer()->GetExact(ConstString(spec.GetName()), format_sp); if (!format_sp) return lldb::SBTypeFormat(); @@ -209,9 +209,9 @@ SBTypeCategory::GetSummaryForType (SBTypeNameSpecifier spec) lldb::TypeSummaryImplSP summary_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexSummaryNavigator()->GetExact(ConstString(spec.GetName()), summary_sp); + m_opaque_sp->GetRegexTypeSummariesContainer()->GetExact(ConstString(spec.GetName()), summary_sp); else - m_opaque_sp->GetSummaryNavigator()->GetExact(ConstString(spec.GetName()), summary_sp); + m_opaque_sp->GetTypeSummariesContainer()->GetExact(ConstString(spec.GetName()), summary_sp); if (!summary_sp) return lldb::SBTypeSummary(); @@ -233,9 +233,9 @@ SBTypeCategory::GetSyntheticForType (SBTypeNameSpecifier spec) lldb::SyntheticChildrenSP children_sp; if (spec.IsRegex()) - m_opaque_sp->GetRegexSyntheticNavigator()->GetExact(ConstString(spec.GetName()), children_sp); + m_opaque_sp->GetRegexTypeSyntheticsContainer()->GetExact(ConstString(spec.GetName()), children_sp); else - m_opaque_sp->GetSyntheticNavigator()->GetExact(ConstString(spec.GetName()), children_sp); + m_opaque_sp->GetTypeSyntheticsContainer()->GetExact(ConstString(spec.GetName()), children_sp); if (!children_sp) return lldb::SBTypeSynthetic(); @@ -312,9 +312,9 @@ SBTypeCategory::AddTypeFormat (SBTypeNameSpecifier type_name, return false; if (type_name.IsRegex()) - m_opaque_sp->GetRegexValueNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), format.GetSP()); + m_opaque_sp->GetRegexTypeFormatsContainer()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), format.GetSP()); else - m_opaque_sp->GetValueNavigator()->Add(ConstString(type_name.GetName()), format.GetSP()); + m_opaque_sp->GetTypeFormatsContainer()->Add(ConstString(type_name.GetName()), format.GetSP()); return true; } @@ -329,9 +329,9 @@ SBTypeCategory::DeleteTypeFormat (SBTypeNameSpecifier type_name) return false; if (type_name.IsRegex()) - return m_opaque_sp->GetRegexValueNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetRegexTypeFormatsContainer()->Delete(ConstString(type_name.GetName())); else - return m_opaque_sp->GetValueNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetTypeFormatsContainer()->Delete(ConstString(type_name.GetName())); } #ifndef LLDB_DISABLE_PYTHON @@ -383,9 +383,9 @@ SBTypeCategory::AddTypeSummary (SBTypeNameSpecifier type_name, } if (type_name.IsRegex()) - m_opaque_sp->GetRegexSummaryNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), summary.GetSP()); + m_opaque_sp->GetRegexTypeSummariesContainer()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), summary.GetSP()); else - m_opaque_sp->GetSummaryNavigator()->Add(ConstString(type_name.GetName()), summary.GetSP()); + m_opaque_sp->GetTypeSummariesContainer()->Add(ConstString(type_name.GetName()), summary.GetSP()); return true; } @@ -401,9 +401,9 @@ SBTypeCategory::DeleteTypeSummary (SBTypeNameSpecifier type_name) return false; if (type_name.IsRegex()) - return m_opaque_sp->GetRegexSummaryNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetRegexTypeSummariesContainer()->Delete(ConstString(type_name.GetName())); else - return m_opaque_sp->GetSummaryNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetTypeSummariesContainer()->Delete(ConstString(type_name.GetName())); } bool @@ -420,9 +420,9 @@ SBTypeCategory::AddTypeFilter (SBTypeNameSpecifier type_name, return false; if (type_name.IsRegex()) - m_opaque_sp->GetRegexFilterNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), filter.GetSP()); + m_opaque_sp->GetRegexTypeFiltersContainer()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), filter.GetSP()); else - m_opaque_sp->GetFilterNavigator()->Add(ConstString(type_name.GetName()), filter.GetSP()); + m_opaque_sp->GetTypeFiltersContainer()->Add(ConstString(type_name.GetName()), filter.GetSP()); return true; } @@ -437,9 +437,9 @@ SBTypeCategory::DeleteTypeFilter (SBTypeNameSpecifier type_name) return false; if (type_name.IsRegex()) - return m_opaque_sp->GetRegexFilterNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetRegexTypeFiltersContainer()->Delete(ConstString(type_name.GetName())); else - return m_opaque_sp->GetFilterNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetTypeFiltersContainer()->Delete(ConstString(type_name.GetName())); } #ifndef LLDB_DISABLE_PYTHON @@ -491,9 +491,9 @@ SBTypeCategory::AddTypeSynthetic (SBTypeNameSpecifier type_name, } if (type_name.IsRegex()) - m_opaque_sp->GetRegexSyntheticNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), synth.GetSP()); + m_opaque_sp->GetRegexTypeSyntheticsContainer()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), synth.GetSP()); else - m_opaque_sp->GetSyntheticNavigator()->Add(ConstString(type_name.GetName()), synth.GetSP()); + m_opaque_sp->GetTypeSyntheticsContainer()->Add(ConstString(type_name.GetName()), synth.GetSP()); return true; } @@ -508,9 +508,9 @@ SBTypeCategory::DeleteTypeSynthetic (SBTypeNameSpecifier type_name) return false; if (type_name.IsRegex()) - return m_opaque_sp->GetRegexSyntheticNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetRegexTypeSyntheticsContainer()->Delete(ConstString(type_name.GetName())); else - return m_opaque_sp->GetSyntheticNavigator()->Delete(ConstString(type_name.GetName())); + return m_opaque_sp->GetTypeSyntheticsContainer()->Delete(ConstString(type_name.GetName())); } #endif // LLDB_DISABLE_PYTHON diff --git a/contrib/llvm/tools/lldb/source/API/SBTypeFormat.cpp b/contrib/llvm/tools/lldb/source/API/SBTypeFormat.cpp index 34ab404..d3ec9bc 100644 --- a/contrib/llvm/tools/lldb/source/API/SBTypeFormat.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBTypeFormat.cpp @@ -25,7 +25,13 @@ m_opaque_sp() SBTypeFormat::SBTypeFormat (lldb::Format format, uint32_t options) -: m_opaque_sp(TypeFormatImplSP(new TypeFormatImpl(format,options))) +: m_opaque_sp(TypeFormatImplSP(new TypeFormatImpl_Format(format,options))) +{ +} + +SBTypeFormat::SBTypeFormat (const char* type, + uint32_t options) +: m_opaque_sp(TypeFormatImplSP(new TypeFormatImpl_EnumType(ConstString(type ? type : ""),options))) { } @@ -47,11 +53,19 @@ SBTypeFormat::IsValid() const lldb::Format SBTypeFormat::GetFormat () { - if (IsValid()) - return m_opaque_sp->GetFormat(); + if (IsValid() && m_opaque_sp->GetType() == TypeFormatImpl::Type::eTypeFormat) + return ((TypeFormatImpl_Format*)m_opaque_sp.get())->GetFormat(); return lldb::eFormatInvalid; } +const char* +SBTypeFormat::GetTypeName () +{ + if (IsValid() && m_opaque_sp->GetType() == TypeFormatImpl::Type::eTypeEnum) + return ((TypeFormatImpl_EnumType*)m_opaque_sp.get())->GetTypeName().AsCString(""); + return ""; +} + uint32_t SBTypeFormat::GetOptions() { @@ -63,14 +77,21 @@ SBTypeFormat::GetOptions() void SBTypeFormat::SetFormat (lldb::Format fmt) { - if (CopyOnWrite_Impl()) - m_opaque_sp->SetFormat(fmt); + if (CopyOnWrite_Impl(Type::eTypeFormat)) + ((TypeFormatImpl_Format*)m_opaque_sp.get())->SetFormat(fmt); +} + +void +SBTypeFormat::SetTypeName (const char* type) +{ + if (CopyOnWrite_Impl(Type::eTypeEnum)) + ((TypeFormatImpl_EnumType*)m_opaque_sp.get())->SetTypeName(ConstString(type ? type : "")); } void SBTypeFormat::SetOptions (uint32_t value) { - if (CopyOnWrite_Impl()) + if (CopyOnWrite_Impl(Type::eTypeKeepSame)) m_opaque_sp->SetOptions(value); } @@ -143,13 +164,30 @@ SBTypeFormat::SBTypeFormat (const lldb::TypeFormatImplSP &typeformat_impl_sp) : } bool -SBTypeFormat::CopyOnWrite_Impl() +SBTypeFormat::CopyOnWrite_Impl(Type type) { if (!IsValid()) return false; - if (m_opaque_sp.unique()) + + if (m_opaque_sp.unique() && + ((type == Type::eTypeKeepSame) || + (type == Type::eTypeFormat && m_opaque_sp->GetType() == TypeFormatImpl::Type::eTypeFormat) || + (type == Type::eTypeEnum && m_opaque_sp->GetType() == TypeFormatImpl::Type::eTypeEnum)) + ) return true; - SetSP(TypeFormatImplSP(new TypeFormatImpl(GetFormat(),GetOptions()))); + if (type == Type::eTypeKeepSame) + { + if (m_opaque_sp->GetType() == TypeFormatImpl::Type::eTypeFormat) + type = Type::eTypeFormat; + else + type = Type::eTypeEnum; + } + + if (type == Type::eTypeFormat) + SetSP(TypeFormatImplSP(new TypeFormatImpl_Format(GetFormat(),GetOptions()))); + else + SetSP(TypeFormatImplSP(new TypeFormatImpl_EnumType(ConstString(GetTypeName()),GetOptions()))); + return true; } diff --git a/contrib/llvm/tools/lldb/source/API/SBValue.cpp b/contrib/llvm/tools/lldb/source/API/SBValue.cpp index 51b6790..4bd0183 100644 --- a/contrib/llvm/tools/lldb/source/API/SBValue.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBValue.cpp @@ -96,7 +96,24 @@ public: bool IsValid () { - return m_valobj_sp.get() != NULL; + if (m_valobj_sp.get() == NULL) + return false; + else + { + // FIXME: This check is necessary but not sufficient. We for sure don't want to touch SBValues whose owning + // targets have gone away. This check is a little weak in that it enforces that restriction when you call + // IsValid, but since IsValid doesn't lock the target, you have no guarantee that the SBValue won't go + // invalid after you call this... + // Also, an SBValue could depend on data from one of the modules in the target, and those could go away + // independently of the target, for instance if a module is unloaded. But right now, neither SBValues + // nor ValueObjects know which modules they depend on. So I have no good way to make that check without + // tracking that in all the ValueObject subclasses. + TargetSP target_sp = m_valobj_sp->GetTargetSP(); + if (target_sp && target_sp->IsValid()) + return true; + else + return false; + } } lldb::ValueObjectSP @@ -120,6 +137,8 @@ public: Target *target = value_sp->GetTargetSP().get(); if (target) api_locker.Lock(target->GetAPIMutex()); + else + return ValueObjectSP(); ProcessSP process_sp(value_sp->GetProcessSP()); if (process_sp && !stop_locker.TryLock (&process_sp->GetRunLock())) @@ -276,7 +295,7 @@ SBValue::IsValid () // If this function ever changes to anything that does more than just // check if the opaque shared pointer is non NULL, then we need to update // all "if (m_opaque_sp)" code in this file. - return m_opaque_sp.get() != NULL && m_opaque_sp->GetRootSP().get() != NULL; + return m_opaque_sp.get() != NULL && m_opaque_sp->IsValid() && m_opaque_sp->GetRootSP().get() != NULL; } void diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp index 32c0b10..5ce064f 100644 --- a/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp +++ b/contrib/llvm/tools/lldb/source/Breakpoint/Breakpoint.cpp @@ -45,14 +45,19 @@ Breakpoint::GetEventIdentifier () //---------------------------------------------------------------------- // Breakpoint constructor //---------------------------------------------------------------------- -Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware) : +Breakpoint::Breakpoint(Target &target, + SearchFilterSP &filter_sp, + BreakpointResolverSP &resolver_sp, + bool hardware, + bool resolve_indirect_symbols) : m_being_created(true), m_hardware(hardware), m_target (target), m_filter_sp (filter_sp), m_resolver_sp (resolver_sp), m_options (), - m_locations (*this) + m_locations (*this), + m_resolve_indirect_symbols(resolve_indirect_symbols) { m_being_created = false; } @@ -87,7 +92,7 @@ Breakpoint::GetTarget () const BreakpointLocationSP Breakpoint::AddLocation (const Address &addr, bool *new_location) { - return m_locations.AddLocation (addr, new_location); + return m_locations.AddLocation (addr, m_resolve_indirect_symbols, new_location); } BreakpointLocationSP diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp index 5009e86..2c75a11 100644 --- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -39,16 +39,29 @@ BreakpointLocation::BreakpointLocation Breakpoint &owner, const Address &addr, lldb::tid_t tid, - bool hardware + bool hardware, + bool check_for_resolver ) : StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware), m_being_created(true), + m_should_resolve_indirect_functions (false), + m_is_reexported (false), + m_is_indirect (false), m_address (addr), m_owner (owner), m_options_ap (), m_bp_site_sp (), m_condition_mutex () { + if (check_for_resolver) + { + Symbol *symbol = m_address.CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) + { + SetShouldResolveIndirectFunctions (true); + } + } + SetThreadID (tid); m_being_created = false; } @@ -545,7 +558,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial) { - s->PutCString("where = "); + if (IsReExported()) + s->PutCString ("re-exported target = "); + else + s->PutCString("where = "); sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false); } else @@ -584,7 +600,10 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) if (sc.symbol) { s->EOL(); - s->Indent("symbol = "); + if (IsReExported()) + s->Indent ("re-exported target = "); + else + s->Indent("symbol = "); s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>")); } } @@ -612,6 +631,24 @@ BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); else m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); + + if (IsIndirect() && m_bp_site_sp) + { + Address resolved_address; + resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target); + Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol(); + if (resolved_symbol) + { + if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial) + s->Printf (", "); + else if (level == lldb::eDescriptionLevelVerbose) + { + s->EOL(); + s->Indent(); + } + s->Printf ("indirect target = %s", resolved_symbol->GetName().GetCString()); + } + } if (level == lldb::eDescriptionLevelVerbose) { diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocationList.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocationList.cpp index 18147de..917c776 100644 --- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocationList.cpp +++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointLocationList.cpp @@ -19,8 +19,10 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" + using namespace lldb; using namespace lldb_private; @@ -39,12 +41,12 @@ BreakpointLocationList::~BreakpointLocationList() } BreakpointLocationSP -BreakpointLocationList::Create (const Address &addr) +BreakpointLocationList::Create (const Address &addr, bool resolve_indirect_symbols) { Mutex::Locker locker (m_mutex); // The location ID is just the size of the location list + 1 lldb::break_id_t bp_loc_id = ++m_next_id; - BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware())); + BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware(), resolve_indirect_symbols)); m_locations.push_back (bp_loc_sp); m_address_to_location[addr] = bp_loc_sp; return bp_loc_sp; @@ -245,7 +247,7 @@ BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level) } BreakpointLocationSP -BreakpointLocationList::AddLocation (const Address &addr, bool *new_location) +BreakpointLocationList::AddLocation (const Address &addr, bool resolve_indirect_symbols, bool *new_location) { Mutex::Locker locker (m_mutex); @@ -254,7 +256,7 @@ BreakpointLocationList::AddLocation (const Address &addr, bool *new_location) BreakpointLocationSP bp_loc_sp (FindByAddress(addr)); if (!bp_loc_sp) { - bp_loc_sp = Create (addr); + bp_loc_sp = Create (addr, resolve_indirect_symbols); if (bp_loc_sp) { bp_loc_sp->ResolveBreakpointSite(); diff --git a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp index c82dd5e..cf5d89c 100644 --- a/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -272,6 +272,8 @@ BreakpointResolverName::SearchCallback { if (func_list.GetContextAtIndex(i, sc)) { + bool is_reexported = false; + if (sc.block && sc.block->GetInlinedFunctionInfo()) { if (!sc.block->GetStartAddress(break_addr)) @@ -293,7 +295,10 @@ BreakpointResolverName::SearchCallback { const Symbol *actual_symbol = sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget()); if (actual_symbol) + { + is_reexported = true; break_addr = actual_symbol->GetAddress(); + } } else { @@ -313,6 +318,7 @@ BreakpointResolverName::SearchCallback if (filter.AddressPasses(break_addr)) { BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location)); + bp_loc_sp->SetIsReExported(is_reexported); if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) { if (log) diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index e540461..532d6ce 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -16,6 +16,7 @@ #include "CommandObjectBreakpointCommand.h" #include "CommandObjectBreakpoint.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Target.h" @@ -34,7 +35,9 @@ using namespace lldb_private; //------------------------------------------------------------------------- -class CommandObjectBreakpointCommandAdd : public CommandObjectParsed +class CommandObjectBreakpointCommandAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: @@ -43,6 +46,7 @@ public: "add", "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.", NULL), + IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { SetHelpLong ( @@ -207,42 +211,47 @@ one command per line.\n" ); return &m_options; } - void - CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, - CommandReturnObject &result) + virtual void + IOHandlerActivated (IOHandler &io_handler) { - InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); - std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - if (reader_sp && data_ap.get()) + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); - - Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, - bp_options, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - "DONE", // end token - "> ", // prompt - true)); // echo input - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } + output_sp->PutCString(g_reader_instructions); + output_sp->Flush(); } - else + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &line) + { + io_handler.SetIsDone(true); + + BreakpointOptions *bp_options = (BreakpointOptions *) io_handler.GetUserData(); + if (bp_options) { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines (line.c_str(), line.size()); + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); + } } } + void + CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CommandReturnObject &result) + { + m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + bp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + } + /// Set a one-liner as the callback for the breakpoint. void SetBreakpointCommandCallback (BreakpointOptions *bp_options, @@ -262,93 +271,6 @@ one command per line.\n" ); return; } - - static size_t - GenerateBreakpointCommandCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - switch (notification) - { - case eInputReaderActivate: - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - if (bytes && bytes_len && baton) - { - BreakpointOptions *bp_options = (BreakpointOptions *) baton; - if (bp_options) - { - Baton *bp_options_baton = bp_options->GetBaton(); - if (bp_options_baton) - ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); - } - } - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderInterrupt: - { - // Finish, and cancel the breakpoint command. - reader.SetIsDone (true); - BreakpointOptions *bp_options = (BreakpointOptions *) baton; - if (bp_options) - { - Baton *bp_options_baton = bp_options->GetBaton (); - if (bp_options_baton) - { - ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); - ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear(); - } - } - if (!batch_mode) - { - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone (true); - break; - - case eInputReaderDone: - break; - } - - return bytes_len; - } static bool BreakpointOptionsCallbackFunction (void *baton, @@ -623,7 +545,7 @@ private: }; const char * -CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; +CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.\n"; // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h index afedb76..e917907 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectBreakpointCommand.h @@ -19,7 +19,6 @@ #include "lldb/lldb-types.h" #include "lldb/Interpreter/Options.h" -#include "lldb/Core/InputReader.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp index 6824ead..7bfdec0 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectCommands.cpp @@ -18,8 +18,7 @@ // Project includes #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReader.h" -#include "lldb/Core/InputReaderEZ.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Core/StringList.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandHistory.h" @@ -309,7 +308,9 @@ protected: CommandOptions (CommandInterpreter &interpreter) : Options (interpreter), - m_stop_on_error (true) + m_stop_on_error (true), + m_silent_run (false), + m_stop_on_continue (true) { } @@ -321,23 +322,21 @@ protected: { Error error; const int short_option = m_getopt_table[option_idx].val; - bool success; switch (short_option) { case 'e': error = m_stop_on_error.SetValueFromCString(option_arg); break; + case 'c': - m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success); - if (!success) - error.SetErrorStringWithFormat("invalid value for stop-on-continue: %s", option_arg); + error = m_stop_on_continue.SetValueFromCString(option_arg); break; + case 's': - m_silent_run = Args::StringToBoolean(option_arg, true, &success); - if (!success) - error.SetErrorStringWithFormat("invalid value for silent-run: %s", option_arg); + error = m_silent_run.SetValueFromCString(option_arg); break; + default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -350,8 +349,8 @@ protected: OptionParsingStarting () { m_stop_on_error.Clear(); - m_silent_run = false; - m_stop_on_continue = true; + m_silent_run.Clear(); + m_stop_on_continue.Clear(); } const OptionDefinition* @@ -367,8 +366,8 @@ protected: // Instance variables to hold the values for command options. OptionValueBoolean m_stop_on_error; - bool m_silent_run; - bool m_stop_on_continue; + OptionValueBoolean m_silent_run; + OptionValueBoolean m_stop_on_continue; }; bool @@ -379,22 +378,40 @@ protected: { const char *filename = command.GetArgumentAtIndex(0); - result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename); - FileSpec cmd_file (filename, true); ExecutionContext *exe_ctx = NULL; // Just use the default context. - bool echo_commands = !m_options.m_silent_run; - bool print_results = true; - bool stop_on_error = m_options.m_stop_on_error.OptionWasSet() ? (bool)m_options.m_stop_on_error : m_interpreter.GetStopCmdSourceOnError(); - - m_interpreter.HandleCommandsFromFile (cmd_file, - exe_ctx, - m_options.m_stop_on_continue, - stop_on_error, - echo_commands, - print_results, - eLazyBoolCalculate, - result); + + // If any options were set, then use them + if (m_options.m_stop_on_error.OptionWasSet() || + m_options.m_silent_run.OptionWasSet() || + m_options.m_stop_on_continue.OptionWasSet()) + { + // Use user set settings + LazyBool print_command = m_options.m_silent_run.GetCurrentValue() ? eLazyBoolNo : eLazyBoolYes; + m_interpreter.HandleCommandsFromFile (cmd_file, + exe_ctx, + m_options.m_stop_on_continue.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on continue + m_options.m_stop_on_error.GetCurrentValue() ? eLazyBoolYes : eLazyBoolNo, // Stop on error + print_command, // Echo command + print_command, // Print command output + eLazyBoolCalculate, // Add to history + result); + + } + else + { + // No options were set, inherit any settings from nested "command source" commands, + // or set to sane default settings... + m_interpreter.HandleCommandsFromFile (cmd_file, + exe_ctx, + eLazyBoolCalculate, // Stop on continue + eLazyBoolCalculate, // Stop on error + eLazyBoolCalculate, // Echo command + eLazyBoolCalculate, // Print command output + eLazyBoolCalculate, // Add to history + result); + + } } else { @@ -423,7 +440,7 @@ CommandObjectCommandsSource::CommandOptions::g_option_table[] = static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" "You must define a Python function with this signature:\n" - "def my_command_impl(debugger, args, result, internal_dict):"; + "def my_command_impl(debugger, args, result, internal_dict):\n"; class CommandObjectCommandsAlias : public CommandObjectRaw @@ -856,7 +873,9 @@ protected: //------------------------------------------------------------------------- #pragma mark CommandObjectCommandsAddRegex -class CommandObjectCommandsAddRegex : public CommandObjectParsed +class CommandObjectCommandsAddRegex : + public CommandObjectParsed, + public IOHandlerDelegate { public: CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) : @@ -864,6 +883,7 @@ public: "command regex", "Allow the user to create a regular expression command.", "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), + IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { SetHelpLong( @@ -899,6 +919,97 @@ public: protected: + + virtual void + IOHandlerActivated (IOHandler &io_handler) + { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString("Enter one of more sed substitution commands in the form: 's/<regex>/<subst>/'.\nTerminate the substitution list with an empty line.\n"); + output_sp->Flush(); + } + } + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) + { + io_handler.SetIsDone(true); + if (m_regex_cmd_ap.get()) + { + StringList lines; + if (lines.SplitIntoLines (data)) + { + const size_t num_lines = lines.GetSize(); + bool check_only = false; + for (size_t i=0; i<num_lines; ++i) + { + printf ("regex[%zu] = %s\n", i, lines[i].c_str()); + llvm::StringRef bytes_strref (lines[i]); + Error error = AppendRegexSubstitution (bytes_strref, check_only); + if (error.Fail()) + { + if (!m_interpreter.GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) + { + StreamSP out_stream = m_interpreter.GetDebugger().GetAsyncOutputStream(); + out_stream->Printf("error: %s\n", error.AsCString()); + } + } + } + } + if (m_regex_cmd_ap->HasRegexEntries()) + { + CommandObjectSP cmd_sp (m_regex_cmd_ap.release()); + m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); + } + } + } + + virtual LineStatus + IOHandlerLinesUpdated (IOHandler &io_handler, + StringList &lines, + uint32_t line_idx, + Error &error) + { + if (line_idx == UINT32_MAX) + { + // Return true to indicate we are done getting lines (this + // is a "fake" line - the real terminating blank line was + // removed during a previous call with the code below) + error.Clear(); + return LineStatus::Done; + } + else + { + const size_t num_lines = lines.GetSize(); + if (line_idx + 1 == num_lines) + { + // The last line was edited, if this line is empty, then we are done + // getting our multiple lines. + if (lines[line_idx].empty()) + { + // Remove the last empty line from "lines" so it doesn't appear + // in our final expression and return true to indicate we are done + // getting lines + lines.PopBack(); + return LineStatus::Done; + } + } + // Check the current line to make sure it is formatted correctly + bool check_only = true; + llvm::StringRef regex_sed(lines[line_idx]); + error = AppendRegexSubstitution (regex_sed, check_only); + if (error.Fail()) + { + return LineStatus::Error; + } + else + { + return LineStatus::Success; + } + } + } + bool DoExecute (Args& command, CommandReturnObject &result) { @@ -920,21 +1031,18 @@ protected: if (argc == 1) { - InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); - if (reader_sp) + Debugger &debugger = m_interpreter.GetDebugger(); + const bool multiple_lines = true; // Get multiple lines + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb", // Name of input reader for history + "\033[K> ", // Prompt and clear line + multiple_lines, + *this)); + + if (io_handler_sp) { - error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback, - this, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - "> ", // prompt - true); // echo input - if (error.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - return true; - } + debugger.PushIOHandler(io_handler_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); } } else @@ -942,7 +1050,8 @@ protected: for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx) { llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx)); - error = AppendRegexSubstitution (arg_strref); + bool check_only = false; + error = AppendRegexSubstitution (arg_strref, check_only); if (error.Fail()) break; } @@ -963,7 +1072,7 @@ protected: } Error - AppendRegexSubstitution (const llvm::StringRef ®ex_sed) + AppendRegexSubstitution (const llvm::StringRef ®ex_sed, bool check_only) { Error error; @@ -1053,10 +1162,14 @@ protected: regex_sed.data()); return error; } - std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); - std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); - m_regex_cmd_ap->AddRegexCommand (regex.c_str(), - subst.c_str()); + + if (check_only == false) + { + std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1)); + std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1)); + m_regex_cmd_ap->AddRegexCommand (regex.c_str(), + subst.c_str()); + } return error; } @@ -1073,89 +1186,6 @@ protected: } } - void - InputReaderDidCancel() - { - m_regex_cmd_ap.reset(); - } - - static size_t - InputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) - { - CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton; - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - switch (notification) - { - case eInputReaderActivate: - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream (); - out_stream->Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:"); - out_stream->Flush(); - } - break; - case eInputReaderReactivate: - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n')) - --bytes_len; - if (bytes_len == 0) - reader.SetIsDone(true); - else if (bytes) - { - llvm::StringRef bytes_strref (bytes, bytes_len); - Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref)); - if (error.Fail()) - { - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf("error: %s\n", error.AsCString()); - out_stream->Flush(); - } - add_regex_cmd->InputReaderDidCancel (); - reader.SetIsDone (true); - } - } - break; - - case eInputReaderInterrupt: - { - reader.SetIsDone (true); - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->PutCString("Regular expression command creations was cancelled.\n"); - out_stream->Flush(); - } - add_regex_cmd->InputReaderDidCancel (); - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone (true); - break; - - case eInputReaderDone: - add_regex_cmd->AddRegexCommandToInterpreter(); - break; - } - - return bytes_len; - } - private: std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap; @@ -1526,7 +1556,9 @@ CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] = // CommandObjectCommandsScriptAdd //------------------------------------------------------------------------- -class CommandObjectCommandsScriptAdd : public CommandObjectParsed +class CommandObjectCommandsScriptAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) : @@ -1534,6 +1566,7 @@ public: "command script add", "Add a scripted function as an LLDB command.", NULL), + IOHandlerDelegateMultiline ("DONE"), m_options (interpreter) { CommandArgumentEntry arg1; @@ -1567,7 +1600,7 @@ protected: public: CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) + Options (interpreter) { } @@ -1586,7 +1619,7 @@ protected: m_funct_name = std::string(option_arg); break; case 's': - m_synchronous = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); + m_synchronicity = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error); if (!error.Success()) error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg); break; @@ -1602,7 +1635,7 @@ protected: OptionParsingStarting () { m_funct_name = ""; - m_synchronous = eScriptedCommandSynchronicitySynchronous; + m_synchronicity = eScriptedCommandSynchronicitySynchronous; } const OptionDefinition* @@ -1618,128 +1651,81 @@ protected: // Instance variables to hold the values for command options. std::string m_funct_name; - ScriptedCommandSynchronicity m_synchronous; + ScriptedCommandSynchronicity m_synchronicity; }; -private: - class PythonAliasReader : public InputReaderEZ + virtual void + IOHandlerActivated (IOHandler &io_handler) { - private: - CommandInterpreter& m_interpreter; - std::string m_cmd_name; - ScriptedCommandSynchronicity m_synchronous; - StringList m_user_input; - DISALLOW_COPY_AND_ASSIGN (PythonAliasReader); - public: - PythonAliasReader(Debugger& debugger, - CommandInterpreter& interpreter, - std::string cmd_name, - ScriptedCommandSynchronicity synch) : - InputReaderEZ(debugger), - m_interpreter(interpreter), - m_cmd_name(cmd_name), - m_synchronous(synch), - m_user_input() - {} - - virtual - ~PythonAliasReader() + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { + output_sp->PutCString(g_python_command_instructions); + output_sp->Flush(); } + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); - virtual void ActivateHandler(HandlerData& data) + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_python_command_instructions); - if (data.reader.GetPrompt()) - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void ReactivateHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (data.reader.GetPrompt() && !batch_mode) + StringList lines; + lines.SplitIntoLines(data); + if (lines.GetSize() > 0) { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void GotTokenHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (data.bytes && data.bytes_len) - { - m_user_input.AppendString(data.bytes, data.bytes_len); - } - if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); + std::string funct_name_str; + if (interpreter->GenerateScriptAliasFunction (lines, funct_name_str)) + { + if (funct_name_str.empty()) + { + error_sp->Printf ("error: unable to obtain a function name, didn't add python command.\n"); + error_sp->Flush(); + } + else + { + // everything should be fine now, let's add this alias + + CommandObjectSP command_obj_sp(new CommandObjectPythonFunction (m_interpreter, + m_cmd_name, + funct_name_str.c_str(), + m_synchronicity)); + + if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true)) + { + error_sp->Printf ("error: unable to add selected command, didn't add python command.\n"); + error_sp->Flush(); + } + } + } + else + { + error_sp->Printf ("error: unable to create function, didn't add python command.\n"); + error_sp->Flush(); + } } - } - virtual void InterruptHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - data.reader.SetIsDone (true); - if (!batch_mode) + else { - out_stream->Printf ("Warning: No script attached.\n"); - out_stream->Flush(); + error_sp->Printf ("error: empty function, didn't add python command.\n"); + error_sp->Flush(); } } - virtual void EOFHandler(HandlerData& data) + else { - data.reader.SetIsDone (true); + error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); + error_sp->Flush(); } - virtual void DoneHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - - ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (!interpreter) - { - out_stream->Printf ("Script interpreter missing: no script attached.\n"); - out_stream->Flush(); - return; - } - std::string funct_name_str; - if (!interpreter->GenerateScriptAliasFunction (m_user_input, - funct_name_str)) - { - out_stream->Printf ("Unable to create function: no script attached.\n"); - out_stream->Flush(); - return; - } - if (funct_name_str.empty()) - { - out_stream->Printf ("Unable to obtain a function name: no script attached.\n"); - out_stream->Flush(); - return; - } - // everything should be fine now, let's add this alias - - CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(m_interpreter, - m_cmd_name, - funct_name_str.c_str(), - m_synchronous)); - - if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true)) - { - out_stream->Printf ("Unable to add selected command: no script attached.\n"); - out_stream->Flush(); - return; - } - } - }; - + + io_handler.SetIsDone(true); + + + } + protected: bool DoExecute (Args& command, CommandReturnObject &result) @@ -1761,45 +1747,24 @@ protected: return false; } - std::string cmd_name = command.GetArgumentAtIndex(0); + // Store the command name and synchronicity in case we get multi-line input + m_cmd_name = command.GetArgumentAtIndex(0); + m_synchronicity = m_options.m_synchronicity; if (m_options.m_funct_name.empty()) { - InputReaderSP reader_sp (new PythonAliasReader (m_interpreter.GetDebugger(), - m_interpreter, - cmd_name, - m_options.m_synchronous)); - - if (reader_sp) - { - - InputReaderEZ::InitializationParameters ipr; - - Error err (reader_sp->Initialize (ipr.SetBaton(NULL).SetPrompt(" "))); - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } + m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions } else { CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter, - cmd_name, + m_cmd_name, m_options.m_funct_name, - m_options.m_synchronous)); - if (m_interpreter.AddUserCommand(cmd_name, new_cmd, true)) + m_synchronicity)); + if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { result.SetStatus (eReturnStatusSuccessFinishNoResult); } @@ -1815,6 +1780,8 @@ protected: } CommandOptions m_options; + std::string m_cmd_name; + ScriptedCommandSynchronicity m_synchronicity; }; static OptionEnumValueElement g_script_synchro_type[] = diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp index fc148b1..f9c683b 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -27,6 +27,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp index 5ca44ff..c772a2e 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.cpp @@ -17,7 +17,6 @@ // Project includes #include "lldb/Interpreter/Args.h" #include "lldb/Core/Value.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Expression/ClangExpressionVariable.h" @@ -197,6 +196,7 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.", NULL, eFlagProcessMustBePaused | eFlagTryTargetAPILock), + IOHandlerDelegate (IOHandlerDelegate::Completion::Expression), m_option_group (interpreter), m_format_options (eFormatDefault), m_command_options (), @@ -254,87 +254,6 @@ CommandObjectExpression::GetOptions () return &m_option_group; } -size_t -CommandObjectExpression::MultiLineExpressionCallback -( - void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton; - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - switch (notification) - { - case eInputReaderActivate: - if (!batch_mode) - { - StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream()); - if (async_strm_sp) - { - async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n"); - async_strm_sp->Flush(); - } - } - // Fall through - case eInputReaderReactivate: - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - ++cmd_object_expr->m_expr_line_count; - if (bytes && bytes_len) - { - cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1); - } - - if (bytes_len == 0) - reader.SetIsDone(true); - break; - - case eInputReaderInterrupt: - cmd_object_expr->m_expr_lines.clear(); - reader.SetIsDone (true); - if (!batch_mode) - { - StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream()); - if (async_strm_sp) - { - async_strm_sp->PutCString("Expression evaluation cancelled.\n"); - async_strm_sp->Flush(); - } - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone (true); - break; - - case eInputReaderDone: - if (cmd_object_expr->m_expr_lines.size() > 0) - { - StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream(); - StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream(); - cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(), - output_stream.get(), - error_stream.get()); - output_stream->Flush(); - error_stream->Flush(); - } - break; - } - - return bytes_len; -} - bool CommandObjectExpression::EvaluateExpression ( @@ -373,6 +292,8 @@ CommandObjectExpression::EvaluateExpression if (m_command_options.timeout > 0) options.SetTimeoutUsec(m_command_options.timeout); + else + options.SetTimeoutUsec(0); exe_results = target->EvaluateExpression (expr, exe_ctx.GetFramePtr(), @@ -443,6 +364,48 @@ CommandObjectExpression::EvaluateExpression return true; } +void +CommandObjectExpression::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) +{ + io_handler.SetIsDone(true); +// StreamSP output_stream = io_handler.GetDebugger().GetAsyncOutputStream(); +// StreamSP error_stream = io_handler.GetDebugger().GetAsyncErrorStream(); + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + + EvaluateExpression (line.c_str(), + output_sp.get(), + error_sp.get()); + if (output_sp) + output_sp->Flush(); + if (error_sp) + error_sp->Flush(); +} + +LineStatus +CommandObjectExpression::IOHandlerLinesUpdated (IOHandler &io_handler, + StringList &lines, + uint32_t line_idx, + Error &error) +{ + if (line_idx == UINT32_MAX) + { + // Remove the last line from "lines" so it doesn't appear + // in our final expression + lines.PopBack(); + error.Clear(); + return LineStatus::Done; + } + else if (line_idx + 1 == lines.GetSize()) + { + // The last line was edited, if this line is empty, then we are done + // getting our multiple lines. + if (lines[line_idx].empty()) + return LineStatus::Done; + } + return LineStatus::Success; +} + bool CommandObjectExpression::DoExecute ( @@ -459,31 +422,21 @@ CommandObjectExpression::DoExecute m_expr_lines.clear(); m_expr_line_count = 0; - InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); - if (reader_sp) - { - Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback, - this, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - NULL, // prompt - true)); // echo input - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + const bool multiple_lines = true; // Get multiple lines + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb-expr", // Name of input reader for history + NULL, // No prompt + multiple_lines, + *this)); + + StreamFileSP output_sp(io_handler_sp->GetOutputStreamFile()); + if (output_sp) { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); + output_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n"); + output_sp->Flush(); } + debugger.PushIOHandler(io_handler_sp); return result.Succeeded(); } diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h index e0703a2..c943f0e 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectExpression.h @@ -14,6 +14,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" @@ -21,7 +22,9 @@ namespace lldb_private { -class CommandObjectExpression : public CommandObjectRaw +class CommandObjectExpression : + public CommandObjectRaw, + public IOHandlerDelegate { public: @@ -71,17 +74,23 @@ public: GetOptions (); protected: + + //------------------------------------------------------------------ + // IOHandler::Delegate functions + //------------------------------------------------------------------ + virtual void + IOHandlerInputComplete (IOHandler &io_handler, + std::string &line); + + virtual LineStatus + IOHandlerLinesUpdated (IOHandler &io_handler, + StringList &lines, + uint32_t line_idx, + Error &error); virtual bool DoExecute (const char *command, CommandReturnObject &result); - static size_t - MultiLineExpressionCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - bool EvaluateExpression (const char *expr, Stream *output_stream, diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.cpp new file mode 100644 index 0000000..3d05335 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.cpp @@ -0,0 +1,61 @@ +//===-- CommandObjectGUI.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 "CommandObjectGUI.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectGUI +//------------------------------------------------------------------------- + +CommandObjectGUI::CommandObjectGUI (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, "gui", "Switch into the curses based GUI mode.", "gui") +{ +} + +CommandObjectGUI::~CommandObjectGUI () +{ +} + +bool +CommandObjectGUI::DoExecute (Args& args, CommandReturnObject &result) +{ +#ifndef LLDB_DISABLE_CURSES + 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); + } + else + { + result.AppendError("the gui command takes no arguments."); + result.SetStatus (eReturnStatusFailed); + } + return true; +#else + result.AppendError("lldb was not build with gui support"); + return false; +#endif +} + diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.h new file mode 100644 index 0000000..72ddb96 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectGUI.h @@ -0,0 +1,43 @@ +//===-- CommandObjectGUI.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_CommandObjectGUI_h_ +#define liblldb_CommandObjectGUI_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectGUI +//------------------------------------------------------------------------- + +class CommandObjectGUI : public CommandObjectParsed +{ +public: + + CommandObjectGUI (CommandInterpreter &interpreter); + + virtual + ~CommandObjectGUI (); + +protected: + virtual bool + DoExecute (Args& args, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectGUI_h_ diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp index f84b401..69b178d 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectMultiword.cpp @@ -235,18 +235,19 @@ CommandObjectMultiword::HandleCompletion // completers will override this. word_complete = true; + const char *arg0 = input.GetArgumentAtIndex(0); if (cursor_index == 0) { CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, - input.GetArgumentAtIndex(0), + arg0, matches); if (matches.GetSize() == 1 && matches.GetStringAtIndex(0) != NULL - && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) + && strcmp (arg0, matches.GetStringAtIndex(0)) == 0) { StringList temp_matches; - CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0), + CommandObject *cmd_obj = GetSubcommandObject (arg0, &temp_matches); if (cmd_obj != NULL) { @@ -270,7 +271,7 @@ CommandObjectMultiword::HandleCompletion } else { - CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0), + CommandObject *sub_command_object = GetSubcommandObject (arg0, &matches); if (sub_command_object == NULL) { diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp index 2933c78..49a3922 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectProcess.cpp @@ -49,7 +49,7 @@ public: virtual ~CommandObjectProcessLaunchOrAttach () {} protected: bool - StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result) + StopProcessIfNecessary (Process *process, StateType &state, CommandReturnObject &result) { state = eStateInvalid; if (process) @@ -187,12 +187,10 @@ protected: { Debugger &debugger = m_interpreter.GetDebugger(); Target *target = debugger.GetSelectedTarget().get(); - Error error; // If our listener is NULL, users aren't allows to launch - char filename[PATH_MAX]; - const Module *exe_module = target->GetExecutableModulePointer(); + ModuleSP exe_module_sp = target->GetExecutableModule(); - if (exe_module == NULL) + if (exe_module_sp == NULL) { result.AppendError ("no file in target, create a debug target using the 'target create' command"); result.SetStatus (eReturnStatusFailed); @@ -200,23 +198,31 @@ protected: } StateType state = eStateInvalid; - Process *process = m_exe_ctx.GetProcessPtr(); - if (!StopProcessIfNecessary(process, state, result)) + if (!StopProcessIfNecessary(m_exe_ctx.GetProcessPtr(), state, result)) return false; const char *target_settings_argv0 = target->GetArg0(); - exe_module->GetFileSpec().GetPath (filename, sizeof(filename)); + if (target->GetDisableASLR()) + m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR); + + if (target->GetDisableSTDIO()) + m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO); + Args environment; + target->GetEnvironmentAsArgs (environment); + if (environment.GetArgumentCount() > 0) + m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment); + if (target_settings_argv0) { m_options.launch_info.GetArguments().AppendArgument (target_settings_argv0); - m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), false); + m_options.launch_info.SetExecutableFile(exe_module_sp->GetPlatformFileSpec(), false); } else { - m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); + m_options.launch_info.SetExecutableFile(exe_module_sp->GetPlatformFileSpec(), true); } if (launch_args.GetArgumentCount() == 0) @@ -228,122 +234,33 @@ protected: else { m_options.launch_info.GetArguments().AppendArguments (launch_args); - // Save the arguments for subsequent runs in the current target. target->SetRunArguments (launch_args); } - if (target->GetDisableASLR()) - m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR); - - if (target->GetDisableSTDIO()) - m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO); - - m_options.launch_info.GetFlags().Set (eLaunchFlagDebug); - - Args environment; - target->GetEnvironmentAsArgs (environment); - if (environment.GetArgumentCount() > 0) - m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment); - - // Get the value of synchronous execution here. If you wait till after you have started to - // run, then you could have hit a breakpoint, whose command might switch the value, and - // then you'll pick up that incorrect value. - bool synchronous_execution = m_interpreter.GetSynchronous (); - - PlatformSP platform_sp (target->GetPlatform()); - - // Finalize the file actions, and if none were given, default to opening - // up a pseudo terminal - const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; - m_options.launch_info.FinalizeFileActions (target, default_to_use_pty); - - if (state == eStateConnected) - { - if (m_options.launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)) - { - result.AppendWarning("can't launch in tty when launching through a remote connection"); - m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY); - } - } - - if (!m_options.launch_info.GetArchitecture().IsValid()) - m_options.launch_info.GetArchitecture() = target->GetArchitecture(); + Error error = target->Launch(debugger.GetListener(), m_options.launch_info); - if (platform_sp && platform_sp->CanDebugProcess ()) - { - process = target->GetPlatform()->DebugProcess (m_options.launch_info, - debugger, - target, - debugger.GetListener(), - error).get(); - } - else - { - const char *plugin_name = m_options.launch_info.GetProcessPluginName(); - process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get(); - if (process) - error = process->Launch (m_options.launch_info); - } - - if (process == NULL) - { - result.SetError (error, "failed to launch or debug process"); - return false; - } - - if (error.Success()) { - const char *archname = exe_module->GetArchitecture().GetArchitectureName(); - - result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process->GetID(), filename, archname); - result.SetDidChangeProcessState (true); - if (m_options.launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false) + const char *archname = exe_module_sp->GetArchitecture().GetArchitectureName(); + ProcessSP process_sp (target->GetProcessSP()); + if (process_sp) { - result.SetStatus (eReturnStatusSuccessContinuingNoResult); - StateType state = process->WaitForProcessToStop (NULL, NULL, false); - - if (state == eStateStopped) - { - error = process->Resume(); - if (error.Success()) - { - if (synchronous_execution) - { - state = process->WaitForProcessToStop (NULL); - const bool must_be_alive = true; - if (!StateIsStoppedState(state, must_be_alive)) - { - result.AppendErrorWithFormat ("process isn't stopped: %s", StateAsCString(state)); - } - result.SetDidChangeProcessState (true); - result.SetStatus (eReturnStatusSuccessFinishResult); - } - else - { - result.SetStatus (eReturnStatusSuccessContinuingNoResult); - } - } - else - { - result.AppendErrorWithFormat ("process resume at entry point failed: %s", error.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendErrorWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state)); - result.SetStatus (eReturnStatusFailed); - } + result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(), exe_module_sp->GetFileSpec().GetPath().c_str(), archname); + result.SetStatus (eReturnStatusSuccessFinishResult); + result.SetDidChangeProcessState (true); + } + else + { + result.AppendError("no error returned from Target::Launch, and target has no process"); + result.SetStatus (eReturnStatusFailed); } } else { - result.AppendErrorWithFormat ("process launch failed: %s", error.AsCString()); + result.AppendError(error.AsCString()); result.SetStatus (eReturnStatusFailed); } - return result.Succeeded(); } @@ -615,37 +532,36 @@ protected: if (error.Success()) { + 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); - } - else - { - result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString()); - result.SetStatus (eReturnStatusFailed); - return false; - } - // If we're synchronous, wait for the stopped event and report that. - // Otherwise just return. - // FIXME: in the async case it will now be possible to get to the command - // interpreter with a state eStateAttaching. Make sure we handle that correctly. - StateType state = process->WaitForProcessToStop (NULL); - - result.SetDidChangeProcessState (true); + StateType state = process->WaitForProcessToStop (NULL, NULL, false, listener_sp.get()); - if (state == eStateStopped) - { - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); - result.SetStatus (eReturnStatusSuccessFinishNoResult); + process->RestoreProcessEvents(); + + result.SetDidChangeProcessState (true); + + if (state == eStateStopped) + { + result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); + process->Destroy(); + result.SetStatus (eReturnStatusFailed); + } } else { - result.AppendError ("attach failed: process did not stop (no such process or permission problem?)"); - process->Destroy(); + result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString()); result.SetStatus (eReturnStatusFailed); - return false; } } } @@ -1170,7 +1086,7 @@ protected: if (process) { - error = process->ConnectRemote (&process->GetTarget().GetDebugger().GetOutputStream(), remote_url); + error = process->ConnectRemote (process->GetTarget().GetDebugger().GetOutputFile().get(), remote_url); if (error.Fail()) { diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp index d04ecdd..ffe2a92 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectQuit.cpp @@ -92,7 +92,8 @@ CommandObjectQuit::DoExecute (Args& command, CommandReturnObject &result) return false; } } - m_interpreter.BroadcastEvent (CommandInterpreter::eBroadcastBitQuitCommandReceived); + const uint32_t event_type = CommandInterpreter::eBroadcastBitQuitCommandReceived; + m_interpreter.BroadcastEvent (event_type); result.SetStatus (eReturnStatusQuit); return true; } diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp index 7cbfaa5..deaf2ab 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectRegister.cpp @@ -29,6 +29,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Thread.h" using namespace lldb; diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp index 1f68736..bf2a42e 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectSource.cpp @@ -28,6 +28,7 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/TargetList.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/Options.h" diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp index 8e7e68a..308b72f 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectTarget.cpp @@ -19,7 +19,7 @@ // Project includes #include "lldb/Interpreter/Args.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReader.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/Section.h" @@ -49,6 +49,7 @@ #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" @@ -2893,7 +2894,8 @@ protected: if (m_slide_option.GetOptionValue().OptionWasSet()) { const addr_t slide = m_slide_option.GetOptionValue().GetCurrentValue(); - module->SetLoadAddress (*target, slide, changed); + const bool slide_is_offset = true; + module->SetLoadAddress (*target, slide, slide_is_offset, changed); } else { @@ -4758,7 +4760,9 @@ private: // CommandObjectTargetStopHookAdd //------------------------------------------------------------------------- -class CommandObjectTargetStopHookAdd : public CommandObjectParsed +class CommandObjectTargetStopHookAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: @@ -4925,9 +4929,10 @@ public: CommandObjectTargetStopHookAdd (CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, - "target stop-hook add ", + "target stop-hook add", "Add a hook to be executed when the target stops.", "target stop-hook add"), + IOHandlerDelegateMultiline ("DONE", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { } @@ -4936,102 +4941,61 @@ public: { } - static size_t - ReadCommandsCallbackFunction (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) +protected: + + virtual void + IOHandlerActivated (IOHandler &io_handler) { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - Target::StopHook *new_stop_hook = ((Target::StopHook *) baton); - static bool got_interrupted; - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - switch (notification) + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { - case eInputReaderActivate: - if (!batch_mode) - { - out_stream->Printf ("%s\n", "Enter your stop hook command(s). Type 'DONE' to end."); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - got_interrupted = false; - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - got_interrupted = false; - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - if (bytes && bytes_len && baton) + output_sp->PutCString("Enter your stop hook command(s). Type 'DONE' to end.\n"); + output_sp->Flush(); + } + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &line) + { + if (m_stop_hook_sp) + { + if (line.empty()) { - StringList *commands = new_stop_hook->GetCommandPointer(); - if (commands) + StreamFileSP error_sp(io_handler.GetErrorStreamFile()); + if (error_sp) { - commands->AppendString (bytes, bytes_len); + error_sp->Printf("error: stop hook #%" PRIu64 " aborted, no commands.\n", m_stop_hook_sp->GetID()); + error_sp->Flush(); } + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + if (target) + target->RemoveStopHookByID(m_stop_hook_sp->GetID()); } - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderInterrupt: + else { - // Finish, and cancel the stop hook. - new_stop_hook->GetTarget()->RemoveStopHookByID(new_stop_hook->GetID()); - if (!batch_mode) + m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { - out_stream->Printf ("Stop hook cancelled.\n"); - out_stream->Flush(); + output_sp->Printf("Stop hook #%" PRIu64 " added.\n", m_stop_hook_sp->GetID()); + output_sp->Flush(); } - - reader.SetIsDone (true); } - got_interrupted = true; - break; - - case eInputReaderEndOfFile: - reader.SetIsDone (true); - break; - - case eInputReaderDone: - if (!got_interrupted && !batch_mode) - { - out_stream->Printf ("Stop hook #%" PRIu64 " added.\n", new_stop_hook->GetID()); - out_stream->Flush(); - } - break; + m_stop_hook_sp.reset(); } - - return bytes_len; + io_handler.SetIsDone(true); } - -protected: + bool DoExecute (Args& command, CommandReturnObject &result) { + m_stop_hook_sp.reset(); + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); if (target) { - Target::StopHookSP new_hook_sp; - target->AddStopHook (new_hook_sp); + Target::StopHookSP new_hook_sp = target->CreateStopHook(); // First step, make the specifier. std::unique_ptr<SymbolContextSpecifier> specifier_ap; @@ -5104,31 +5068,12 @@ protected: } else { - // Otherwise gather up the command list, we'll push an input reader and suck the data from that directly into - // the new stop hook's command string. - InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); - if (!reader_sp) - { - result.AppendError("out of memory\n"); - result.SetStatus (eReturnStatusFailed); - target->RemoveStopHookByID (new_hook_sp->GetID()); - return false; - } - - Error err (reader_sp->Initialize (CommandObjectTargetStopHookAdd::ReadCommandsCallbackFunction, - new_hook_sp.get(), // baton - eInputReaderGranularityLine, // token size, to pass to callback function - "DONE", // end token - "> ", // prompt - true)); // echo input - if (!err.Success()) - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - target->RemoveStopHookByID (new_hook_sp->GetID()); - return false; - } - m_interpreter.GetDebugger().PushInputReader (reader_sp); + m_stop_hook_sp = new_hook_sp; + m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + NULL); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + } result.SetStatus (eReturnStatusSuccessFinishNoResult); } @@ -5142,6 +5087,7 @@ protected: } private: CommandOptions m_options; + Target::StopHookSP m_stop_hook_sp; }; OptionDefinition diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp index 1c695b3..f1b1d2c 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectType.cpp @@ -19,7 +19,7 @@ #include "lldb/Core/ConstString.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReaderEZ.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/State.h" #include "lldb/Core/StringList.h" @@ -42,7 +42,6 @@ public: TypeSummaryImpl::Flags m_flags; StringList m_target_types; - StringList m_user_source; bool m_regex; @@ -74,7 +73,6 @@ public: bool m_skip_references; bool m_cascade; bool m_regex; - StringList m_user_source; StringList m_target_types; std::string m_category; @@ -88,7 +86,6 @@ public: m_skip_references(sref), m_cascade(casc), m_regex(regx), - m_user_source(), m_target_types(), m_category(catg) { @@ -98,9 +95,36 @@ public: }; +static bool +WarnOnPotentialUnquotedUnsignedType (Args& command, CommandReturnObject &result) +{ + for (int idx = 0; idx < command.GetArgumentCount(); idx++) + { + const char* arg = command.GetArgumentAtIndex(idx); + if (idx+1 < command.GetArgumentCount()) + { + if (arg && 0 == strcmp(arg,"unsigned")) + { + const char* next = command.GetArgumentAtIndex(idx+1); + if (next && + (0 == strcmp(next, "int") || + 0 == strcmp(next, "short") || + 0 == strcmp(next, "char") || + 0 == strcmp(next, "long"))) + { + result.AppendWarningWithFormat("%s %s being treated as two types. if you meant the combined type name use quotes, as in \"%s %s\"\n", + arg,next,arg,next); + return true; + } + } + } + } + return false; +} - -class CommandObjectTypeSummaryAdd : public CommandObjectParsed +class CommandObjectTypeSummaryAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { private: @@ -153,10 +177,6 @@ private: return &m_options; } - void - CollectPythonScript(ScriptAddOptions *options, - CommandReturnObject &result); - bool Execute_ScriptSummary (Args& command, CommandReturnObject &result); @@ -178,6 +198,147 @@ public: { } + virtual void + IOHandlerActivated (IOHandler &io_handler) + { + static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" + "def function (valobj,internal_dict):\n" + " \"\"\"valobj: an SBValue which you want to provide a summary for\n" + " internal_dict: an LLDB support object not to be used\"\"\""; + + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(g_summary_addreader_instructions); + output_sp->Flush(); + } + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) + { + StringList lines; + lines.SplitIntoLines(data); + if (lines.GetSize() > 0) + { + ScriptAddOptions *options_ptr = ((ScriptAddOptions*)io_handler.GetUserData()); + if (options_ptr) + { + ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope + + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) + { + std::string funct_name_str; + if (interpreter->GenerateTypeScriptFunction (lines, funct_name_str)) + { + if (funct_name_str.empty()) + { + error_sp->Printf ("unable to obtain a valid function name from the script interpreter.\n"); + error_sp->Flush(); + } + else + { + // now I have a valid function name, let's add this as script for every type in the list + + TypeSummaryImplSP script_format; + script_format.reset(new ScriptSummaryFormat(options->m_flags, + funct_name_str.c_str(), + lines.CopyList(" ").c_str())); + + Error error; + + for (size_t i = 0; i < options->m_target_types.GetSize(); i++) + { + const char *type_name = options->m_target_types.GetStringAtIndex(i); + CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), + script_format, + (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary), + options->m_category, + &error); + if (error.Fail()) + { + error_sp->Printf ("error: %s", error.AsCString()); + error_sp->Flush(); + } + } + + if (options->m_name) + { + CommandObjectTypeSummaryAdd::AddSummary (options->m_name, + script_format, + CommandObjectTypeSummaryAdd::eNamedSummary, + options->m_category, + &error); + if (error.Fail()) + { + CommandObjectTypeSummaryAdd::AddSummary (options->m_name, + script_format, + CommandObjectTypeSummaryAdd::eNamedSummary, + options->m_category, + &error); + if (error.Fail()) + { + error_sp->Printf ("error: %s", error.AsCString()); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: %s", error.AsCString()); + error_sp->Flush(); + } + } + else + { + if (error.AsCString()) + { + error_sp->Printf ("error: %s", error.AsCString()); + error_sp->Flush(); + } + } + } + } + else + { + error_sp->Printf ("error: unable to generate a function.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: no script interpreter.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: internal synchronization information missing or invalid.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: empty function, didn't add python command.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); + error_sp->Flush(); + } +#endif // #ifndef LLDB_DISABLE_PYTHON + io_handler.SetIsDone(true); + } + static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry, @@ -190,7 +351,19 @@ protected: }; -class CommandObjectTypeSynthAdd : public CommandObjectParsed +static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" +"You must define a Python class with these methods:\n" +" def __init__(self, valobj, dict):\n" +" def num_children(self):\n" +" def get_child_at_index(self, index):\n" +" def get_child_index(self, name):\n" +" def update(self):\n" +" '''Optional'''\n" +"class synthProvider:\n"; + +class CommandObjectTypeSynthAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { private: @@ -200,7 +373,7 @@ private: public: CommandOptions (CommandInterpreter &interpreter) : - Options (interpreter) + Options (interpreter) { } @@ -296,9 +469,6 @@ private: return &m_options; } - void - CollectPythonScript (SynthAddOptions *options, - CommandReturnObject &result); bool Execute_HandwritePython (Args& command, CommandReturnObject &result); @@ -307,8 +477,139 @@ private: protected: bool - DoExecute (Args& command, CommandReturnObject &result); + DoExecute (Args& command, CommandReturnObject &result) + { + WarnOnPotentialUnquotedUnsignedType(command, result); + + if (m_options.handwrite_python) + return Execute_HandwritePython(command, result); + else if (m_options.is_class_based) + return Execute_PythonClass(command, result); + else + { + result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line"); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + + virtual void + IOHandlerActivated (IOHandler &io_handler) + { + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(g_synth_addreader_instructions); + output_sp->Flush(); + } + } + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &data) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + +#ifndef LLDB_DISABLE_PYTHON + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) + { + StringList lines; + lines.SplitIntoLines(data); + if (lines.GetSize() > 0) + { + SynthAddOptions *options_ptr = ((SynthAddOptions*)io_handler.GetUserData()); + if (options_ptr) + { + SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope + + ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); + if (interpreter) + { + std::string class_name_str; + if (interpreter->GenerateTypeSynthClass (lines, class_name_str)) + { + if (class_name_str.empty()) + { + error_sp->Printf ("error: unable to obtain a proper name for the class.\n"); + error_sp->Flush(); + } + else + { + // everything should be fine now, let's add the synth provider class + + SyntheticChildrenSP synth_provider; + synth_provider.reset(new ScriptedSyntheticChildren(SyntheticChildren::Flags().SetCascades(options->m_cascade). + SetSkipPointers(options->m_skip_pointers). + SetSkipReferences(options->m_skip_references), + class_name_str.c_str())); + + + lldb::TypeCategoryImplSP category; + DataVisualization::Categories::GetCategory(ConstString(options->m_category.c_str()), category); + + Error error; + + for (size_t i = 0; i < options->m_target_types.GetSize(); i++) + { + const char *type_name = options->m_target_types.GetStringAtIndex(i); + ConstString const_type_name(type_name); + if (const_type_name) + { + if (!CommandObjectTypeSynthAdd::AddSynth(const_type_name, + synth_provider, + options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth, + options->m_category, + &error)) + { + error_sp->Printf("error: %s\n", error.AsCString()); + error_sp->Flush(); + break; + } + } + else + { + error_sp->Printf ("error: invalid type name.\n"); + error_sp->Flush(); + break; + } + } + } + } + else + { + error_sp->Printf ("error: unable to generate a class.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: no script interpreter.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: internal synchronization data missing.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: empty function, didn't add python command.\n"); + error_sp->Flush(); + } + } + else + { + error_sp->Printf ("error: script interpreter missing, didn't add python command.\n"); + error_sp->Flush(); + } + +#endif // #ifndef LLDB_DISABLE_PYTHON + io_handler.SetIsDone(true); + } + public: enum SynthFormatType @@ -371,6 +672,7 @@ private: m_skip_references = false; m_regex = false; m_category.assign("default"); + m_custom_type_name.clear(); } virtual Error SetOptionValue (CommandInterpreter &interpreter, @@ -400,6 +702,9 @@ private: case 'x': m_regex = true; break; + case 't': + m_custom_type_name.assign(option_value); + break; default: error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); break; @@ -419,6 +724,7 @@ private: bool m_skip_pointers; bool m_regex; std::string m_category; + std::string m_custom_type_name; }; OptionGroupOptions m_option_group; @@ -480,7 +786,7 @@ public: ); // Add the "--format" to all options groups - m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_ALL); + m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1); m_option_group.Append (&m_command_options); m_option_group.Finalize(); @@ -504,7 +810,7 @@ protected: } const Format format = m_format_options.GetFormat(); - if (format == eFormatInvalid) + if (format == eFormatInvalid && m_command_options.m_custom_type_name.empty()) { result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); @@ -513,10 +819,16 @@ protected: TypeFormatImplSP entry; - entry.reset(new TypeFormatImpl(format, - TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade). - SetSkipPointers(m_command_options.m_skip_pointers). - SetSkipReferences(m_command_options.m_skip_references))); + if (m_command_options.m_custom_type_name.empty()) + entry.reset(new TypeFormatImpl_Format(format, + TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade). + SetSkipPointers(m_command_options.m_skip_pointers). + SetSkipReferences(m_command_options.m_skip_references))); + else + entry.reset(new TypeFormatImpl_EnumType(ConstString(m_command_options.m_custom_type_name.c_str()), + TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade). + SetSkipPointers(m_command_options.m_skip_pointers). + SetSkipReferences(m_command_options.m_skip_references))); // now I have a valid format, let's add it to every type @@ -525,6 +837,8 @@ protected: if (!category_sp) return false; + WarnOnPotentialUnquotedUnsignedType(command, result); + for (size_t i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); @@ -540,11 +854,11 @@ protected: result.SetStatus(eReturnStatusFailed); return false; } - category_sp->GetRegexSummaryNavigator()->Delete(typeCS); - category_sp->GetRegexValueNavigator()->Add(typeRX, entry); + category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS); + category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry); } else - category_sp->GetValueNavigator()->Add(typeCS, entry); + category_sp->GetTypeFormatsContainer()->Add(typeCS, entry); } else { @@ -562,11 +876,12 @@ protected: OptionDefinition CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] = { - { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, - { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, - { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, - { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."}, + { LLDB_OPT_SET_ALL, false, "category", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."}, + { LLDB_OPT_SET_ALL, false, "cascade", 'C', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."}, + { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."}, + { LLDB_OPT_SET_ALL, false, "skip-references", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."}, { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."}, + { LLDB_OPT_SET_2, false, "type", 't', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Format variables as if they were of this type."}, { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } }; @@ -817,8 +1132,8 @@ private: PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { - cate->GetValueNavigator()->Clear(); - cate->GetRegexValueNavigator()->Clear(); + cate->GetTypeFormatsContainer()->Clear(); + cate->GetRegexTypeFormatsContainer()->Clear(); return true; } @@ -996,6 +1311,7 @@ protected: param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); + delete param; if (cate_regex) delete cate_regex; @@ -1029,12 +1345,12 @@ private: cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); - cate->GetValueNavigator()->LoopThrough(CommandObjectTypeFormatList_LoopCallback, param_vp); + cate->GetTypeFormatsContainer()->LoopThrough(CommandObjectTypeFormatList_LoopCallback, param_vp); - if (cate->GetRegexSummaryNavigator()->GetCount() > 0) + if (cate->GetRegexTypeSummariesContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based summaries (slower):\n"); - cate->GetRegexValueNavigator()->LoopThrough(CommandObjectTypeRXFormatList_LoopCallback, param_vp); + cate->GetRegexTypeFormatsContainer()->LoopThrough(CommandObjectTypeRXFormatList_LoopCallback, param_vp); } return true; } @@ -1089,176 +1405,6 @@ CommandObjectTypeFormatList::CommandOptions::g_option_table[] = // CommandObjectTypeSummaryAdd //------------------------------------------------------------------------- -static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" - "def function (valobj,internal_dict):\n" - " \"\"\"valobj: an SBValue which you want to provide a summary for\n" - " internal_dict: an LLDB support object not to be used\"\"\""; - -class TypeScriptAddInputReader : public InputReaderEZ -{ -private: - DISALLOW_COPY_AND_ASSIGN (TypeScriptAddInputReader); -public: - TypeScriptAddInputReader(Debugger& debugger) : - InputReaderEZ(debugger) - {} - - virtual - ~TypeScriptAddInputReader() - { - } - - virtual void ActivateHandler(HandlerData& data) - { - StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_summary_addreader_instructions); - if (data.reader.GetPrompt()) - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - - virtual void ReactivateHandler(HandlerData& data) - { - StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (data.reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void GotTokenHandler(HandlerData& data) - { - StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (data.bytes && data.bytes_len && data.baton) - { - ((ScriptAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len); - } - if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void InterruptHandler(HandlerData& data) - { - StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - data.reader.SetIsDone (true); - if (!batch_mode) - { - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - virtual void EOFHandler(HandlerData& data) - { - data.reader.SetIsDone (true); - } - virtual void DoneHandler(HandlerData& data) - { - StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream(); - ScriptAddOptions *options_ptr = ((ScriptAddOptions*)data.baton); - if (!options_ptr) - { - out_stream->Printf ("internal synchronization information missing or invalid.\n"); - out_stream->Flush(); - return; - } - - ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope - - ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (!interpreter) - { - out_stream->Printf ("no script interpreter.\n"); - out_stream->Flush(); - return; - } - std::string funct_name_str; - if (!interpreter->GenerateTypeScriptFunction (options->m_user_source, - funct_name_str)) - { - out_stream->Printf ("unable to generate a function.\n"); - out_stream->Flush(); - return; - } - if (funct_name_str.empty()) - { - out_stream->Printf ("unable to obtain a valid function name from the script interpreter.\n"); - out_stream->Flush(); - return; - } - // now I have a valid function name, let's add this as script for every type in the list - - TypeSummaryImplSP script_format; - script_format.reset(new ScriptSummaryFormat(options->m_flags, - funct_name_str.c_str(), - options->m_user_source.CopyList(" ").c_str())); - - Error error; - - for (size_t i = 0; i < options->m_target_types.GetSize(); i++) - { - const char *type_name = options->m_target_types.GetStringAtIndex(i); - CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name), - script_format, - (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary), - options->m_category, - &error); - if (error.Fail()) - { - out_stream->Printf ("%s", error.AsCString()); - out_stream->Flush(); - return; - } - } - - if (options->m_name) - { - CommandObjectTypeSummaryAdd::AddSummary (options->m_name, - script_format, - CommandObjectTypeSummaryAdd::eNamedSummary, - options->m_category, - &error); - if (error.Fail()) - { - CommandObjectTypeSummaryAdd::AddSummary (options->m_name, - script_format, - CommandObjectTypeSummaryAdd::eNamedSummary, - options->m_category, - &error); - if (error.Fail()) - { - out_stream->Printf ("%s", error.AsCString()); - out_stream->Flush(); - return; - } - } - else - { - out_stream->Printf ("%s", error.AsCString()); - out_stream->Flush(); - return; - } - } - else - { - if (error.AsCString()) - { - out_stream->PutCString (error.AsCString()); - out_stream->Flush(); - } - return; - } - } -}; - #endif // #ifndef LLDB_DISABLE_PYTHON Error @@ -1339,35 +1485,9 @@ CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting () m_category = "default"; } + + #ifndef LLDB_DISABLE_PYTHON -void -CommandObjectTypeSummaryAdd::CollectPythonScript (ScriptAddOptions *options, - CommandReturnObject &result) -{ - InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger())); - if (reader_sp && options) - { - - InputReaderEZ::InitializationParameters ipr; - - Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" "))); - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } -} bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturnObject &result) @@ -1393,7 +1513,7 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn return false; } - std::string code = (" " + m_options.m_python_function + "(valobj,internal_dict)"); + std::string code = (" " + m_options.m_python_function + "(valobj,internal_dict)"); script_format.reset(new ScriptSummaryFormat(m_options.m_flags, funct_name, @@ -1432,14 +1552,15 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn return false; } - std::string code = " " + m_options.m_python_script; + std::string code = " " + m_options.m_python_script; script_format.reset(new ScriptSummaryFormat(m_options.m_flags, funct_name_str.c_str(), code.c_str())); } - else // use an InputReader to grab Python code from the user - { + else + { + // Use an IOHandler to grab Python code from the user ScriptAddOptions *options = new ScriptAddOptions(m_options.m_flags, m_options.m_regex, m_options.m_name, @@ -1458,7 +1579,12 @@ CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturn } } - CollectPythonScript(options,result); + m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); } @@ -1590,6 +1716,7 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &in "type summary add", "Add a new summary style for a type.", NULL), + IOHandlerDelegateMultiline ("DONE"), m_options (interpreter) { CommandArgumentEntry type_arg; @@ -1671,6 +1798,8 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &in bool CommandObjectTypeSummaryAdd::DoExecute (Args& command, CommandReturnObject &result) { + WarnOnPotentialUnquotedUnsignedType(command, result); + if (m_options.m_is_add_script) { #ifndef LLDB_DISABLE_PYTHON @@ -1720,8 +1849,8 @@ CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, return false; } - category->GetRegexSummaryNavigator()->Delete(type_name); - category->GetRegexSummaryNavigator()->Add(typeRX, entry); + category->GetRegexTypeSummariesContainer()->Delete(type_name); + category->GetRegexTypeSummariesContainer()->Add(typeRX, entry); return true; } @@ -1733,7 +1862,7 @@ CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name, } else { - category->GetSummaryNavigator()->Add(type_name, entry); + category->GetTypeSummariesContainer()->Add(type_name, entry); return true; } } @@ -1994,8 +2123,8 @@ private: PerCategoryCallback(void* param, const lldb::TypeCategoryImplSP& cate) { - cate->GetSummaryNavigator()->Clear(); - cate->GetRegexSummaryNavigator()->Clear(); + cate->GetTypeSummariesContainer()->Clear(); + cate->GetRegexTypeSummariesContainer()->Clear(); return true; } @@ -2178,7 +2307,8 @@ protected: param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); - + delete param; + if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); @@ -2226,12 +2356,12 @@ private: cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); - cate->GetSummaryNavigator()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param_vp); + cate->GetTypeSummariesContainer()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param_vp); - if (cate->GetRegexSummaryNavigator()->GetCount() > 0) + if (cate->GetRegexTypeSummariesContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based summaries (slower):\n"); - cate->GetRegexSummaryNavigator()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param_vp); + cate->GetRegexTypeSummariesContainer()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param_vp); } return true; } @@ -2741,6 +2871,7 @@ protected: param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); + delete param; if (cate_regex) delete cate_regex; @@ -2774,12 +2905,12 @@ private: cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); - cate->GetFilterNavigator()->LoopThrough(CommandObjectTypeFilterList_LoopCallback, param_vp); + cate->GetTypeFiltersContainer()->LoopThrough(CommandObjectTypeFilterList_LoopCallback, param_vp); - if (cate->GetRegexFilterNavigator()->GetCount() > 0) + if (cate->GetRegexTypeFiltersContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based filters (slower):\n"); - cate->GetRegexFilterNavigator()->LoopThrough(CommandObjectTypeFilterRXList_LoopCallback, param_vp); + cate->GetRegexTypeFiltersContainer()->LoopThrough(CommandObjectTypeFilterRXList_LoopCallback, param_vp); } return true; @@ -2955,7 +3086,8 @@ protected: param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex); DataVisualization::Categories::LoopThrough(PerCategoryCallback,param); - + delete param; + if (cate_regex) delete cate_regex; @@ -2988,12 +3120,12 @@ private: cate_name, (cate->IsEnabled() ? "enabled" : "disabled")); - cate->GetSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp); + cate->GetTypeSyntheticsContainer()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp); - if (cate->GetRegexSyntheticNavigator()->GetCount() > 0) + if (cate->GetRegexTypeSyntheticsContainer()->GetCount() > 0) { result->GetOutputStream().Printf("Regex-based synthetic providers (slower):\n"); - cate->GetRegexSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp); + cate->GetRegexTypeSyntheticsContainer()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp); } return true; @@ -3179,8 +3311,8 @@ protected: lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); - bool delete_category = category->GetFilterNavigator()->Delete(typeCS); - delete_category = category->GetRegexFilterNavigator()->Delete(typeCS) || delete_category; + bool delete_category = category->GetTypeFiltersContainer()->Delete(typeCS); + delete_category = category->GetRegexTypeFiltersContainer()->Delete(typeCS) || delete_category; if (delete_category) { @@ -3345,8 +3477,8 @@ protected: lldb::TypeCategoryImplSP category; DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category); - bool delete_category = category->GetSyntheticNavigator()->Delete(typeCS); - delete_category = category->GetRegexSyntheticNavigator()->Delete(typeCS) || delete_category; + bool delete_category = category->GetTypeSyntheticsContainer()->Delete(typeCS); + delete_category = category->GetRegexTypeSyntheticsContainer()->Delete(typeCS) || delete_category; if (delete_category) { @@ -3484,8 +3616,8 @@ protected: } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); - category->GetFilterNavigator()->Clear(); - category->GetRegexFilterNavigator()->Clear(); + category->GetTypeFiltersContainer()->Clear(); + category->GetRegexTypeFiltersContainer()->Clear(); } result.SetStatus(eReturnStatusSuccessFinishResult); @@ -3613,8 +3745,8 @@ protected: } else DataVisualization::Categories::GetCategory(ConstString(NULL), category); - category->GetSyntheticNavigator()->Clear(); - category->GetRegexSyntheticNavigator()->Clear(); + category->GetTypeSyntheticsContainer()->Clear(); + category->GetRegexTypeSyntheticsContainer()->Clear(); } result.SetStatus(eReturnStatusSuccessFinishResult); @@ -3631,193 +3763,6 @@ CommandObjectTypeSynthClear::CommandOptions::g_option_table[] = }; -//------------------------------------------------------------------------- -// TypeSynthAddInputReader -//------------------------------------------------------------------------- - -static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" - "You must define a Python class with these methods:\n" - " def __init__(self, valobj, dict):\n" - " def num_children(self):\n" - " def get_child_at_index(self, index):\n" - " def get_child_index(self, name):\n" - "Optionally, you can also define a method:\n" - " def update(self):\n" - "if your synthetic provider is holding on to any per-object state variables (currently, this is not implemented because of the way LLDB handles instances of SBValue and you should not rely on object persistence and per-object state)\n" - "class synthProvider:"; - -class TypeSynthAddInputReader : public InputReaderEZ -{ -public: - TypeSynthAddInputReader(Debugger& debugger) : - InputReaderEZ(debugger) - {} - - virtual - ~TypeSynthAddInputReader() - { - } - - virtual void ActivateHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_synth_addreader_instructions); - if (data.reader.GetPrompt()) - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - - virtual void ReactivateHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (data.reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void GotTokenHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - if (data.bytes && data.bytes_len && data.baton) - { - ((SynthAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len); - } - if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", data.reader.GetPrompt()); - out_stream->Flush(); - } - } - virtual void InterruptHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - bool batch_mode = data.GetBatchMode(); - data.reader.SetIsDone (true); - if (!batch_mode) - { - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - virtual void EOFHandler(HandlerData& data) - { - data.reader.SetIsDone (true); - } - virtual void DoneHandler(HandlerData& data) - { - StreamSP out_stream = data.GetOutStream(); - SynthAddOptions *options_ptr = ((SynthAddOptions*)data.baton); - if (!options_ptr) - { - out_stream->Printf ("internal synchronization data missing.\n"); - out_stream->Flush(); - return; - } - - SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope - - ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (!interpreter) - { - out_stream->Printf ("no script interpreter.\n"); - out_stream->Flush(); - return; - } - std::string class_name_str; - if (!interpreter->GenerateTypeSynthClass (options->m_user_source, - class_name_str)) - { - out_stream->Printf ("unable to generate a class.\n"); - out_stream->Flush(); - return; - } - if (class_name_str.empty()) - { - out_stream->Printf ("unable to obtain a proper name for the class.\n"); - out_stream->Flush(); - return; - } - - // everything should be fine now, let's add the synth provider class - - SyntheticChildrenSP synth_provider; - synth_provider.reset(new ScriptedSyntheticChildren(SyntheticChildren::Flags().SetCascades(options->m_cascade). - SetSkipPointers(options->m_skip_pointers). - SetSkipReferences(options->m_skip_references), - class_name_str.c_str())); - - - lldb::TypeCategoryImplSP category; - DataVisualization::Categories::GetCategory(ConstString(options->m_category.c_str()), category); - - Error error; - - for (size_t i = 0; i < options->m_target_types.GetSize(); i++) - { - const char *type_name = options->m_target_types.GetStringAtIndex(i); - ConstString typeCS(type_name); - if (typeCS) - { - if (!CommandObjectTypeSynthAdd::AddSynth(typeCS, - synth_provider, - options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth, - options->m_category, - &error)) - { - out_stream->Printf("%s\n", error.AsCString()); - out_stream->Flush(); - return; - } - } - else - { - out_stream->Printf ("invalid type name.\n"); - out_stream->Flush(); - return; - } - } - } - -private: - DISALLOW_COPY_AND_ASSIGN (TypeSynthAddInputReader); -}; - -void -CommandObjectTypeSynthAdd::CollectPythonScript (SynthAddOptions *options, - CommandReturnObject &result) -{ - InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger())); - if (reader_sp && options) - { - - InputReaderEZ::InitializationParameters ipr; - - Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" "))); - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } -} - bool CommandObjectTypeSynthAdd::Execute_HandwritePython (Args& command, CommandReturnObject &result) { @@ -3842,7 +3787,11 @@ CommandObjectTypeSynthAdd::Execute_HandwritePython (Args& command, CommandReturn } } - CollectPythonScript(options,result); + m_interpreter.GetPythonCommandsFromIOHandler (" ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions + result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } @@ -3921,6 +3870,7 @@ CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd (CommandInterpreter &interp "type synthetic add", "Add a new synthetic provider for a type.", NULL), + IOHandlerDelegateMultiline ("DONE"), m_options (interpreter) { CommandArgumentEntry type_arg; @@ -3979,32 +3929,17 @@ CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, return false; } - category->GetRegexSyntheticNavigator()->Delete(type_name); - category->GetRegexSyntheticNavigator()->Add(typeRX, entry); + category->GetRegexTypeSyntheticsContainer()->Delete(type_name); + category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry); return true; } else { - category->GetSyntheticNavigator()->Add(type_name, entry); + category->GetTypeSyntheticsContainer()->Add(type_name, entry); return true; } } - -bool -CommandObjectTypeSynthAdd::DoExecute (Args& command, CommandReturnObject &result) -{ - if (m_options.handwrite_python) - return Execute_HandwritePython(command, result); - else if (m_options.is_class_based) - return Execute_PythonClass(command, result); - else - { - result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line"); - result.SetStatus(eReturnStatusFailed); - return false; - } -} OptionDefinition CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] = @@ -4173,14 +4108,14 @@ private: return false; } - category->GetRegexFilterNavigator()->Delete(type_name); - category->GetRegexFilterNavigator()->Add(typeRX, entry); + category->GetRegexTypeFiltersContainer()->Delete(type_name); + category->GetRegexTypeFiltersContainer()->Add(typeRX, entry); return true; } else { - category->GetFilterNavigator()->Add(type_name, entry); + category->GetTypeFiltersContainer()->Add(type_name, entry); return true; } } @@ -4279,6 +4214,8 @@ protected: Error error; + WarnOnPotentialUnquotedUnsignedType(command, result); + for (size_t i = 0; i < argc; i++) { const char* typeA = command.GetArgumentAtIndex(i); diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp index e19216d..0083ff1 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp @@ -16,6 +16,7 @@ #include "CommandObjectWatchpointCommand.h" #include "CommandObjectWatchpoint.h" +#include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Target.h" @@ -34,7 +35,9 @@ using namespace lldb_private; //------------------------------------------------------------------------- -class CommandObjectWatchpointCommandAdd : public CommandObjectParsed +class CommandObjectWatchpointCommandAdd : + public CommandObjectParsed, + public IOHandlerDelegateMultiline { public: @@ -43,6 +46,7 @@ public: "add", "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.", NULL), + IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), m_options (interpreter) { SetHelpLong ( @@ -185,40 +189,45 @@ but do NOT enter more than one command per line. \n" ); return &m_options; } - void - CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, - CommandReturnObject &result) + virtual void + IOHandlerActivated (IOHandler &io_handler) { - InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); - std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); - if (reader_sp && data_ap.get()) + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) { - BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); - wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); - - Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback, - wp_options, // callback_data - eInputReaderGranularityLine, // token size, to pass to callback function - "DONE", // end token - "> ", // prompt - true)); // echo input - if (err.Success()) - { - m_interpreter.GetDebugger().PushInputReader (reader_sp); - result.SetStatus (eReturnStatusSuccessFinishNoResult); - } - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } + output_sp->PutCString("Enter your debugger command(s). Type 'DONE' to end.\n"); + output_sp->Flush(); } - else + } + + + virtual void + IOHandlerInputComplete (IOHandler &io_handler, std::string &line) + { + io_handler.SetIsDone(true); + + // The WatchpointOptions object is owned by the watchpoint or watchpoint location + WatchpointOptions *wp_options = (WatchpointOptions *) io_handler.GetUserData(); + if (wp_options) { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); + std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(line); + BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); + wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp); + } } + } + void + CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, + CommandReturnObject &result) + { + m_interpreter.GetLLDBCommandsFromIOHandler ("> ", // Prompt + *this, // IOHandlerDelegate + true, // Run IOHandler in async mode + wp_options); // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions } /// Set a one-liner as the callback for the watchpoint. @@ -240,93 +249,6 @@ but do NOT enter more than one command per line. \n" ); return; } - - static size_t - GenerateWatchpointCommandCallback (void *callback_data, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - switch (notification) - { - case eInputReaderActivate: - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - if (bytes && bytes_len && callback_data) - { - WatchpointOptions *wp_options = (WatchpointOptions *) callback_data; - if (wp_options) - { - Baton *wp_options_baton = wp_options->GetBaton(); - if (wp_options_baton) - ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); - } - } - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush(); - } - break; - - case eInputReaderInterrupt: - { - // Finish, and cancel the watchpoint command. - reader.SetIsDone (true); - WatchpointOptions *wp_options = (WatchpointOptions *) callback_data; - if (wp_options) - { - Baton *wp_options_baton = wp_options->GetBaton (); - if (wp_options_baton) - { - ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear(); - ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear(); - } - } - if (!batch_mode) - { - out_stream->Printf ("Warning: No command attached to watchpoint.\n"); - out_stream->Flush(); - } - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone (true); - break; - - case eInputReaderDone: - break; - } - - return bytes_len; - } static bool WatchpointOptionsCallbackFunction (void *baton, @@ -579,12 +501,8 @@ protected: private: CommandOptions m_options; - static const char *g_reader_instructions; - }; -const char * -CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h index c2faf71..3bc9b35 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.h @@ -19,9 +19,6 @@ #include "lldb/lldb-types.h" #include "lldb/Interpreter/Options.h" -#include "lldb/Core/InputReader.h" -#include "lldb/Interpreter/CommandObject.h" -#include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" diff --git a/contrib/llvm/tools/lldb/source/Core/Address.cpp b/contrib/llvm/tools/lldb/source/Core/Address.cpp index de2165c..5ac2bcc 100644 --- a/contrib/llvm/tools/lldb/source/Core/Address.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Address.cpp @@ -16,6 +16,7 @@ #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Symbol/SymbolVendor.h" @@ -327,15 +328,27 @@ Address::GetLoadAddress (Target *target) const addr_t Address::GetCallableLoadAddress (Target *target, bool is_indirect) const { - if (is_indirect && target) { + addr_t code_addr = LLDB_INVALID_ADDRESS; + + if (is_indirect && target) + { ProcessSP processSP = target->GetProcessSP(); Error error; if (processSP.get()) - return processSP->ResolveIndirectFunction(this, error); + { + code_addr = processSP->ResolveIndirectFunction(this, error); + if (!error.Success()) + code_addr = LLDB_INVALID_ADDRESS; + } } - - addr_t code_addr = GetLoadAddress (target); - + else + { + code_addr = GetLoadAddress (target); + } + + if (code_addr == LLDB_INVALID_ADDRESS) + return code_addr; + if (target) return target->GetCallableLoadAddress (code_addr, GetAddressClass()); return code_addr; diff --git a/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp b/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp index f2eb375..a93f4bd 100644 --- a/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp +++ b/contrib/llvm/tools/lldb/source/Core/ArchSpec.cpp @@ -104,6 +104,11 @@ static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] = { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" }, { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64 , "x86_64" }, + { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64h , "x86_64h" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon , ArchSpec::eCore_hexagon_generic, "hexagon" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon , ArchSpec::eCore_hexagon_hexagonv4, "hexagonv4" }, + { eByteOrderLittle, 4, 4, 4, llvm::Triple::hexagon , ArchSpec::eCore_hexagon_hexagonv5, "hexagonv5" }, + { eByteOrderLittle, 4, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach32 , "unknown-mach-32" }, { eByteOrderLittle, 8, 4, 4 , llvm::Triple::UnknownArch , ArchSpec::eCore_uknownMach64 , "unknown-mach-64" } }; @@ -205,10 +210,11 @@ static const ArchDefinitionEntry g_macho_arch_entries[] = { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPU_TYPE_I386 , 3 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_x86_32_i486 , llvm::MachO::CPU_TYPE_I386 , 4 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_x86_32_i486sx , llvm::MachO::CPU_TYPE_I386 , 0x84 , UINT32_MAX , SUBTYPE_MASK }, - { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPU_TYPE_I386 , CPU_ANY, UINT32_MAX , UINT32_MAX }, + { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPU_TYPE_I386 , CPU_ANY, UINT32_MAX , UINT32_MAX }, { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPU_TYPE_X86_64 , 3 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPU_TYPE_X86_64 , 4 , UINT32_MAX , SUBTYPE_MASK }, - { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPU_TYPE_X86_64 , CPU_ANY, UINT32_MAX , UINT32_MAX }, + { ArchSpec::eCore_x86_64_x86_64h , llvm::MachO::CPU_TYPE_X86_64 , 8 , UINT32_MAX , SUBTYPE_MASK }, + { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPU_TYPE_X86_64 , CPU_ANY, UINT32_MAX , UINT32_MAX }, // Catch any unknown mach architectures so we can always use the object and symbol mach-o files { ArchSpec::eCore_uknownMach32 , 0 , 0 , 0xFF000000u, 0x00000000u }, { ArchSpec::eCore_uknownMach64 , llvm::MachO::CPU_ARCH_ABI64 , 0 , 0xFF000000u, 0x00000000u } @@ -235,7 +241,8 @@ static const ArchDefinitionEntry g_elf_arch_entries[] = { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9 { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // AMD64 - { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // MIPS + { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // MIPS + { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // HEXAGON }; static const ArchDefinition g_elf_arch_def = { @@ -349,14 +356,16 @@ FindArchDefinitionEntry (const ArchDefinition *def, ArchSpec::Core core) ArchSpec::ArchSpec() : m_triple (), m_core (kCore_invalid), - m_byte_order (eByteOrderInvalid) + m_byte_order (eByteOrderInvalid), + m_distribution_id () { } ArchSpec::ArchSpec (const char *triple_cstr, Platform *platform) : m_triple (), m_core (kCore_invalid), - m_byte_order (eByteOrderInvalid) + m_byte_order (eByteOrderInvalid), + m_distribution_id () { if (triple_cstr) SetTriple(triple_cstr, platform); @@ -366,7 +375,8 @@ ArchSpec::ArchSpec (const char *triple_cstr, Platform *platform) : ArchSpec::ArchSpec (const char *triple_cstr) : m_triple (), m_core (kCore_invalid), - m_byte_order (eByteOrderInvalid) + m_byte_order (eByteOrderInvalid), + m_distribution_id () { if (triple_cstr) SetTriple(triple_cstr); @@ -375,7 +385,8 @@ ArchSpec::ArchSpec (const char *triple_cstr) : ArchSpec::ArchSpec(const llvm::Triple &triple) : m_triple (), m_core (kCore_invalid), - m_byte_order (eByteOrderInvalid) + m_byte_order (eByteOrderInvalid), + m_distribution_id () { SetTriple(triple); } @@ -383,7 +394,8 @@ ArchSpec::ArchSpec(const llvm::Triple &triple) : ArchSpec::ArchSpec (ArchitectureType arch_type, uint32_t cpu, uint32_t subtype) : m_triple (), m_core (kCore_invalid), - m_byte_order (eByteOrderInvalid) + m_byte_order (eByteOrderInvalid), + m_distribution_id () { SetArchitecture (arch_type, cpu, subtype); } @@ -403,6 +415,7 @@ ArchSpec::operator= (const ArchSpec& rhs) m_triple = rhs.m_triple; m_core = rhs.m_core; m_byte_order = rhs.m_byte_order; + m_distribution_id = rhs.m_distribution_id; } return *this; } @@ -413,6 +426,7 @@ ArchSpec::Clear() m_triple = llvm::Triple(); m_core = kCore_invalid; m_byte_order = eByteOrderInvalid; + m_distribution_id.Clear (); } //===----------------------------------------------------------------------===// @@ -468,6 +482,18 @@ ArchSpec::GetMachine () const return llvm::Triple::UnknownArch; } +const ConstString& +ArchSpec::GetDistributionId () const +{ + return m_distribution_id; +} + +void +ArchSpec::SetDistributionId (const char* distribution_id) +{ + m_distribution_id.SetCString (distribution_id); +} + uint32_t ArchSpec::GetAddressByteSize() const { @@ -763,6 +789,8 @@ ArchSpec::IsCompatibleMatch (const ArchSpec& rhs) const bool ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const { + // explicitly ignoring m_distribution_id in this method. + if (GetByteOrder() != rhs.GetByteOrder()) return false; @@ -873,7 +901,7 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in if (core2 == ArchSpec::kCore_arm_any) return true; break; - + case ArchSpec::kCore_x86_32_any: if ((core2 >= ArchSpec::kCore_x86_32_first && core2 <= ArchSpec::kCore_x86_32_last) || (core2 == ArchSpec::kCore_x86_32_any)) return true; @@ -896,6 +924,10 @@ cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_in if (core2 == ArchSpec::eCore_arm_armv7) return true; } + + case ArchSpec::kCore_hexagon_any: + if ((core2 >= ArchSpec::kCore_hexagon_first && core2 <= ArchSpec::kCore_hexagon_last) || (core2 == ArchSpec::kCore_hexagon_any)) + return true; break; case ArchSpec::eCore_arm_armv7m: diff --git a/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp b/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp index 5af7497..88f3996 100644 --- a/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Broadcaster.cpp @@ -313,18 +313,22 @@ Broadcaster::RestoreBroadcaster () { Mutex::Locker event_types_locker(m_listeners_mutex); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS)); - if (log) + if (!m_hijacking_listeners.empty()) { - Listener *listener = m_hijacking_listeners.back(); - log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)", - this, - m_broadcaster_name.AsCString(""), - listener->m_name.c_str(), - listener); + Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS)); + if (log) + { + Listener *listener = m_hijacking_listeners.back(); + log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)", + this, + m_broadcaster_name.AsCString(""), + listener->m_name.c_str(), + listener); + } + m_hijacking_listeners.pop_back(); } - m_hijacking_listeners.pop_back(); - m_hijacking_masks.pop_back(); + if (!m_hijacking_masks.empty()) + m_hijacking_masks.pop_back(); } ConstString & diff --git a/contrib/llvm/tools/lldb/source/Core/Communication.cpp b/contrib/llvm/tools/lldb/source/Core/Communication.cpp index 6ea7a11..f05ce32 100644 --- a/contrib/llvm/tools/lldb/source/Core/Communication.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Communication.cpp @@ -269,6 +269,16 @@ Communication::StopReadThread (Error *error_ptr) return status; } +bool +Communication::JoinReadThread (Error *error_ptr) +{ + if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) + return true; + + bool success = Host::ThreadJoin (m_read_thread, NULL, error_ptr); + m_read_thread = LLDB_INVALID_HOST_THREAD; + return success; +} size_t Communication::GetCachedBytes (void *dst, size_t dst_len) diff --git a/contrib/llvm/tools/lldb/source/Core/ConnectionFileDescriptor.cpp b/contrib/llvm/tools/lldb/source/Core/ConnectionFileDescriptor.cpp index 5764a212..ed876e5 100644 --- a/contrib/llvm/tools/lldb/source/Core/ConnectionFileDescriptor.cpp +++ b/contrib/llvm/tools/lldb/source/Core/ConnectionFileDescriptor.cpp @@ -97,11 +97,11 @@ ConnectionFileDescriptor::ConnectionFileDescriptor () : m_fd_send_type (eFDTypeFile), m_fd_recv_type (eFDTypeFile), m_udp_send_sockaddr (new SocketAddress()), - m_should_close_fd (false), m_socket_timeout_usec(0), m_pipe_read(-1), m_pipe_write(-1), m_mutex (Mutex::eMutexTypeRecursive), + m_should_close_fd (false), m_shutting_down (false) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); @@ -116,11 +116,11 @@ ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) : m_fd_send_type (eFDTypeFile), m_fd_recv_type (eFDTypeFile), m_udp_send_sockaddr (new SocketAddress()), - m_should_close_fd (owns_fd), m_socket_timeout_usec(0), m_pipe_read(-1), m_pipe_write(-1), m_mutex (Mutex::eMutexTypeRecursive), + m_should_close_fd (owns_fd), m_shutting_down (false) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); @@ -218,12 +218,15 @@ ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr) if (s && s[0]) { - char *end = NULL; if (strstr(s, "listen://")) { // listen://HOST:PORT - unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0); - return SocketListen (listen_port, error_ptr); + return SocketListen (s + strlen("listen://"), error_ptr); + } + else if (strstr(s, "accept://")) + { + // unix://SOCKNAME + return NamedSocketAccept (s + strlen("accept://"), error_ptr); } else if (strstr(s, "unix-accept://")) { @@ -363,6 +366,9 @@ ConnectionFileDescriptor::Disconnect (Error *error_ptr) if (log) log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this); + // Reset the port predicate when disconnecting and don't broadcast + m_port_predicate.SetValue(0, eBroadcastNever); + ConnectionStatus status = eConnectionStatusSuccess; if (m_fd_send < 0 && m_fd_recv < 0) @@ -1281,16 +1287,31 @@ ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *er } ConnectionStatus -ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr) +ConnectionFileDescriptor::SocketListen (const char *host_and_port, Error *error_ptr) { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION)); if (log) - log->Printf ("%p ConnectionFileDescriptor::SocketListen (port = %i)", this, listen_port_num); + log->Printf ("%p ConnectionFileDescriptor::SocketListen (%s)", this, host_and_port); Disconnect (NULL); m_fd_send_type = m_fd_recv_type = eFDTypeSocket; - int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listen_port == -1) + std::string host_str; + std::string port_str; + int32_t port = INT32_MIN; + if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr)) + { + // Might be just a port number + port = Args::StringToSInt32(host_and_port, -1); + if (port == -1) + return eConnectionStatusError; + else + host_str.clear(); + } + const sa_family_t family = AF_INET; + const int socktype = SOCK_STREAM; + const int protocol = IPPROTO_TCP; + int listen_fd = ::socket (family, socktype, protocol); + if (listen_fd == -1) { if (error_ptr) error_ptr->SetErrorToErrno(); @@ -1298,41 +1319,119 @@ ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_p } // enable local address reuse - SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1); + SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); - SocketAddress localhost; - if (localhost.SetToLocalhost (AF_INET, listen_port_num)) + SocketAddress listen_addr; + if (host_str.empty()) + listen_addr.SetToLocalhost(family, port); + else if (host_str.compare("*") == 0) + listen_addr.SetToAnyAddress(family, port); + else { - int err = ::bind (listen_port, localhost, localhost.GetLength()); + if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str()); + Close (listen_fd, eFDTypeSocket, NULL); + return eConnectionStatusError; + } + } + + SocketAddress anyaddr; + if (anyaddr.SetToAnyAddress (family, port)) + { + int err = ::bind (listen_fd, anyaddr, anyaddr.GetLength()); if (err == -1) { if (error_ptr) error_ptr->SetErrorToErrno(); - Close (listen_port, eFDTypeSocket, NULL); + Close (listen_fd, eFDTypeSocket, NULL); return eConnectionStatusError; } - err = ::listen (listen_port, 1); + err = ::listen (listen_fd, 1); if (err == -1) { if (error_ptr) error_ptr->SetErrorToErrno(); - Close (listen_port, eFDTypeSocket, NULL); + Close (listen_fd, eFDTypeSocket, NULL); return eConnectionStatusError; } - m_fd_send = m_fd_recv = ::accept (listen_port, NULL, 0); + // We were asked to listen on port zero which means we + // must now read the actual port that was given to us + // as port zero is a special code for "find an open port + // for me". + if (port == 0) + port = GetSocketPort(listen_fd); + + // Set the port predicate since when doing a listen://<host>:<port> + // it often needs to accept the incoming connection which is a blocking + // system call. Allowing access to the bound port using a predicate allows + // us to wait for the port predicate to be set to a non-zero value from + // another thread in an efficient manor. + m_port_predicate.SetValue(port, eBroadcastAlways); + + + bool accept_connection = false; + + // Loop until we are happy with our connection + while (!accept_connection) + { + struct sockaddr_in accept_addr; + ::memset (&accept_addr, 0, sizeof accept_addr); +#if !(defined (__linux__) || defined(_MSC_VER)) + accept_addr.sin_len = sizeof accept_addr; +#endif + socklen_t accept_addr_len = sizeof accept_addr; + + int fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len); + + if (fd == -1) + { + if (error_ptr) + error_ptr->SetErrorToErrno(); + break; + } + + if (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY) + { + accept_connection = true; + m_fd_send = m_fd_recv = fd; + } + else + { + if ( +#if !(defined(__linux__) || (defined(_MSC_VER))) + accept_addr_len == listen_addr.sockaddr_in().sin_len && +#endif + accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr) + { + accept_connection = true; + m_fd_send = m_fd_recv = fd; + } + else + { + ::close (fd); + m_fd_send = m_fd_recv = -1; + const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; + const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr; + ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n", + accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], + listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + } + } + } + if (m_fd_send == -1) { - if (error_ptr) - error_ptr->SetErrorToErrno(); - Close (listen_port, eFDTypeSocket, NULL); + Close (listen_fd, eFDTypeSocket, NULL); return eConnectionStatusError; } } // We are done with the listen port - Close (listen_port, eFDTypeSocket, NULL); + Close (listen_fd, eFDTypeSocket, NULL); m_should_close_fd = true; @@ -1446,7 +1545,7 @@ ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_pt { // Socket was created, now lets bind to the requested port SocketAddress addr; - addr.SetToLocalhost (AF_INET, 0); + addr.SetToAnyAddress (AF_INET, 0); if (::bind (m_fd_recv, addr, addr.GetLength()) == -1) { @@ -1581,21 +1680,23 @@ ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec) return false; } -in_port_t +uint16_t ConnectionFileDescriptor::GetSocketPort (int fd) { // We bound to port zero, so we need to figure out which port we actually bound to - SocketAddress sock_addr; - socklen_t sock_addr_len = sock_addr.GetMaxLength (); - if (::getsockname (fd, sock_addr, &sock_addr_len) == 0) - return sock_addr.GetPort (); - + if (fd >= 0) + { + SocketAddress sock_addr; + socklen_t sock_addr_len = sock_addr.GetMaxLength (); + if (::getsockname (fd, sock_addr, &sock_addr_len) == 0) + return sock_addr.GetPort (); + } return 0; } // If the read file descriptor is a socket, then return // the port number that is being used by the socket. -in_port_t +uint16_t ConnectionFileDescriptor::GetReadPort () const { return ConnectionFileDescriptor::GetSocketPort (m_fd_recv); @@ -1603,10 +1704,23 @@ ConnectionFileDescriptor::GetReadPort () const // If the write file descriptor is a socket, then return // the port number that is being used by the socket. -in_port_t +uint16_t ConnectionFileDescriptor::GetWritePort () const { return ConnectionFileDescriptor::GetSocketPort (m_fd_send); } - +uint16_t +ConnectionFileDescriptor::GetBoundPort (uint32_t timeout_sec) +{ + uint16_t bound_port = 0; + if (timeout_sec == UINT32_MAX) + m_port_predicate.WaitForValueNotEqualTo (0, bound_port); + else + { + TimeValue timeout = TimeValue::Now(); + timeout.OffsetWithSeconds(timeout_sec); + m_port_predicate.WaitForValueNotEqualTo (0, bound_port, &timeout); + } + return bound_port; +} diff --git a/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp b/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp index d1f3c09..b42c6ff 100644 --- a/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp +++ b/contrib/llvm/tools/lldb/source/Core/DataExtractor.cpp @@ -37,6 +37,7 @@ #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" using namespace lldb; @@ -45,69 +46,97 @@ using namespace lldb_private; static inline uint16_t ReadInt16(const unsigned char* ptr, offset_t offset) { - return *(uint16_t *)(ptr + offset); + uint16_t value; + memcpy (&value, ptr + offset, 2); + return value; } + static inline uint32_t ReadInt32 (const unsigned char* ptr, offset_t offset) { - return *(uint32_t *)(ptr + offset); + uint32_t value; + memcpy (&value, ptr + offset, 4); + return value; } static inline uint64_t ReadInt64(const unsigned char* ptr, offset_t offset) { - return *(uint64_t *)(ptr + offset); + uint64_t value; + memcpy (&value, ptr + offset, 8); + return value; } static inline uint16_t ReadInt16(const void* ptr) { - return *(uint16_t *)(ptr); + uint16_t value; + memcpy (&value, ptr, 2); + return value; } + static inline uint32_t ReadInt32 (const void* ptr) { - return *(uint32_t *)(ptr); + uint32_t value; + memcpy (&value, ptr, 4); + return value; } static inline uint64_t ReadInt64(const void* ptr) { - return *(uint64_t *)(ptr); + uint64_t value; + memcpy (&value, ptr, 8); + return value; } static inline uint16_t ReadSwapInt16(const unsigned char* ptr, offset_t offset) { - return llvm::ByteSwap_16(*(uint16_t *)(ptr + offset)); + uint16_t value; + memcpy (&value, ptr + offset, 2); + return llvm::ByteSwap_16(value); } static inline uint32_t ReadSwapInt32 (const unsigned char* ptr, offset_t offset) { - return llvm::ByteSwap_32(*(uint32_t *)(ptr + offset)); + uint32_t value; + memcpy (&value, ptr + offset, 4); + return llvm::ByteSwap_32(value); } + static inline uint64_t ReadSwapInt64(const unsigned char* ptr, offset_t offset) { - return llvm::ByteSwap_64(*(uint64_t *)(ptr + offset)); + uint64_t value; + memcpy (&value, ptr + offset, 8); + return llvm::ByteSwap_64(value); } static inline uint16_t ReadSwapInt16(const void* ptr) { - return llvm::ByteSwap_16(*(uint16_t *)(ptr)); + uint16_t value; + memcpy (&value, ptr, 2); + return llvm::ByteSwap_16(value); } static inline uint32_t ReadSwapInt32 (const void* ptr) { - return llvm::ByteSwap_32(*(uint32_t *)(ptr)); + uint32_t value; + memcpy (&value, ptr, 4); + return llvm::ByteSwap_32(value); } + static inline uint64_t ReadSwapInt64(const void* ptr) { - return llvm::ByteSwap_64(*(uint64_t *)(ptr)); + uint64_t value; + memcpy (&value, ptr, 8); + return llvm::ByteSwap_64(value); } #define NON_PRINTABLE_CHAR '.' @@ -502,13 +531,17 @@ uint32_t DataExtractor::GetU32 (offset_t *offset_ptr) const { uint32_t val = 0; - const uint32_t *data = (const uint32_t *)GetData (offset_ptr, sizeof(val)); + const uint8_t *data = (const uint8_t *)GetData (offset_ptr, sizeof(val)); if (data) { if (m_byte_order != lldb::endian::InlHostByteOrder()) + { val = ReadSwapInt32 (data); + } else - val = *data; + { + memcpy (&val, data, 4); + } } return val; } @@ -561,13 +594,17 @@ uint64_t DataExtractor::GetU64 (offset_t *offset_ptr) const { uint64_t val = 0; - const uint64_t *data = (const uint64_t *)GetData (offset_ptr, sizeof(val)); + const uint8_t *data = (const uint8_t *)GetData (offset_ptr, sizeof(val)); if (data) { if (m_byte_order != lldb::endian::InlHostByteOrder()) + { val = ReadSwapInt64 (data); + } else - val = *data; + { + memcpy (&val, data, 8); + } } return val; } @@ -1808,6 +1845,7 @@ DataExtractor::Dump (Stream *s, case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: + case ArchSpec::eCore_x86_64_x86_64h: // clang will assert when contructing the apfloat if we use a 16 byte integer value if (GetAPInt (*this, &offset, 10, apint)) { diff --git a/contrib/llvm/tools/lldb/source/Core/Debugger.cpp b/contrib/llvm/tools/lldb/source/Core/Debugger.cpp index b57c605..34e0e32 100644 --- a/contrib/llvm/tools/lldb/source/Core/Debugger.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Debugger.cpp @@ -18,13 +18,13 @@ #include "lldb/lldb-private.h" #include "lldb/Core/ConnectionFileDescriptor.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamAsynchronousIO.h" #include "lldb/Core/StreamCallback.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObject.h" @@ -180,6 +180,7 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); if (str.length()) new_prompt = str.c_str(); + GetCommandInterpreter().UpdatePrompt(new_prompt); EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt))); GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp); } @@ -196,12 +197,16 @@ Debugger::SetPropertyValue (const ExecutionContext *exe_ctx, StreamString feedback_stream; if (!target_sp->LoadScriptingResources(errors,&feedback_stream)) { - for (auto error : errors) + StreamFileSP stream_sp (GetErrorFile()); + if (stream_sp) { - GetErrorStream().Printf("%s\n",error.AsCString()); + for (auto error : errors) + { + stream_sp->Printf("%s\n",error.AsCString()); + } + if (feedback_stream.GetSize()) + stream_sp->Printf("%s",feedback_stream.GetData()); } - if (feedback_stream.GetSize()) - GetErrorStream().Printf("%s",feedback_stream.GetData()); } } } @@ -246,8 +251,7 @@ Debugger::SetPrompt(const char *p) std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor()); if (str.length()) new_prompt = str.c_str(); - EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));; - GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp); + GetCommandInterpreter().UpdatePrompt(new_prompt); } const char * @@ -611,10 +615,9 @@ Debugger::FindTargetWithProcess (Process *process) Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) : UserID (g_unique_id++), Properties(OptionValuePropertiesSP(new OptionValueProperties())), - m_input_comm("debugger.input"), - m_input_file (), - m_output_file (), - m_error_file (), + m_input_file_sp (new StreamFile (stdin, false)), + m_output_file_sp (new StreamFile (stdout, false)), + m_error_file_sp (new StreamFile (stderr, false)), m_terminal_state (), m_target_list (*this), m_platform_list (), @@ -623,8 +626,11 @@ Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) : m_source_file_cache(), m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)), m_input_reader_stack (), - m_input_reader_data (), - m_instance_name() + m_instance_name (), + m_loaded_plugins (), + m_event_handler_thread (LLDB_INVALID_HOST_THREAD), + m_io_handler_thread (LLDB_INVALID_HOST_THREAD), + m_event_handler_thread_alive(false) { char instance_cstr[256]; snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); @@ -667,7 +673,9 @@ Debugger::~Debugger () void Debugger::Clear() { - CleanUpInputReaders(); + ClearIOHandlers(); + StopIOHandlerThread(); + StopEventHandlerThread(); m_listener.Clear(); int num_targets = m_target_list.GetNumTargets(); for (int i = 0; i < num_targets; i++) @@ -686,23 +694,21 @@ Debugger::Clear() // Close the input file _before_ we close the input read communications class // as it does NOT own the input file, our m_input_file does. m_terminal_state.Clear(); - GetInputFile().Close (); - // Now that we have closed m_input_file, we can now tell our input communication - // class to close down. Its read thread should quickly exit after we close - // the input file handle above. - m_input_comm.Clear (); + if (m_input_file_sp) + m_input_file_sp->GetFile().Close (); } bool Debugger::GetCloseInputOnEOF () const { - return m_input_comm.GetCloseOnEOF(); +// return m_input_comm.GetCloseOnEOF(); + return false; } void Debugger::SetCloseInputOnEOF (bool b) { - m_input_comm.SetCloseOnEOF(b); +// m_input_comm.SetCloseOnEOF(b); } bool @@ -721,37 +727,28 @@ Debugger::SetAsyncExecution (bool async_execution) void Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership) { - File &in_file = GetInputFile(); - in_file.SetStream (fh, tranfer_ownership); + if (m_input_file_sp) + m_input_file_sp->GetFile().SetStream (fh, tranfer_ownership); + else + m_input_file_sp.reset (new StreamFile (fh, tranfer_ownership)); + + File &in_file = m_input_file_sp->GetFile(); if (in_file.IsValid() == false) in_file.SetStream (stdin, true); - // Disconnect from any old connection if we had one - m_input_comm.Disconnect (); - // Pass false as the second argument to ConnectionFileDescriptor below because - // our "in_file" above will already take ownership if requested and we don't - // want to objects trying to own and close a file descriptor. - m_input_comm.SetConnection (new ConnectionFileDescriptor (in_file.GetDescriptor(), false)); - m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this); - // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState. SaveInputTerminalState (); - - Error error; - if (m_input_comm.StartReadThread (&error) == false) - { - File &err_file = GetErrorFile(); - - err_file.Printf ("error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error"); - exit(1); - } } void Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership) { - File &out_file = GetOutputFile(); - out_file.SetStream (fh, tranfer_ownership); + if (m_output_file_sp) + m_output_file_sp->GetFile().SetStream (fh, tranfer_ownership); + else + m_output_file_sp.reset (new StreamFile (fh, tranfer_ownership)); + + File &out_file = m_output_file_sp->GetFile(); if (out_file.IsValid() == false) out_file.SetStream (stdout, false); @@ -766,8 +763,12 @@ Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership) void Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership) { - File &err_file = GetErrorFile(); - err_file.SetStream (fh, tranfer_ownership); + if (m_error_file_sp) + m_error_file_sp->GetFile().SetStream (fh, tranfer_ownership); + else + m_error_file_sp.reset (new StreamFile (fh, tranfer_ownership)); + + File &err_file = m_error_file_sp->GetFile(); if (err_file.IsValid() == false) err_file.SetStream (stderr, false); } @@ -775,9 +776,12 @@ Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership) void Debugger::SaveInputTerminalState () { - File &in_file = GetInputFile(); - if (in_file.GetDescriptor() != File::kInvalidDescriptor) - m_terminal_state.Save(in_file.GetDescriptor(), true); + if (m_input_file_sp) + { + File &in_file = m_input_file_sp->GetFile(); + if (in_file.GetDescriptor() != File::kInvalidDescriptor) + m_terminal_state.Save(in_file.GetDescriptor(), true); + } } void @@ -812,245 +816,211 @@ Debugger::GetSelectedExecutionContext () return exe_ctx; } -InputReaderSP -Debugger::GetCurrentInputReader () -{ - InputReaderSP reader_sp; - - if (!m_input_reader_stack.IsEmpty()) - { - // Clear any finished readers from the stack - while (CheckIfTopInputReaderIsDone()) ; - - if (!m_input_reader_stack.IsEmpty()) - reader_sp = m_input_reader_stack.Top(); - } - - return reader_sp; -} - -void -Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len) -{ - if (bytes_len > 0) - ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len); - else - ((Debugger *)baton)->DispatchInputEndOfFile (); -} - - -void -Debugger::DispatchInput (const char *bytes, size_t bytes_len) -{ - if (bytes == NULL || bytes_len == 0) - return; - - WriteToDefaultReader (bytes, bytes_len); -} - void Debugger::DispatchInputInterrupt () { - m_input_reader_data.clear(); - - InputReaderSP reader_sp (GetCurrentInputReader ()); + Mutex::Locker locker (m_input_reader_stack.GetMutex()); + IOHandlerSP reader_sp (m_input_reader_stack.Top()); if (reader_sp) - { - reader_sp->Notify (eInputReaderInterrupt); - - // If notifying the reader of the interrupt finished the reader, we should pop it off the stack. - while (CheckIfTopInputReaderIsDone ()) ; - } + reader_sp->Interrupt(); } void Debugger::DispatchInputEndOfFile () { - m_input_reader_data.clear(); - - InputReaderSP reader_sp (GetCurrentInputReader ()); + Mutex::Locker locker (m_input_reader_stack.GetMutex()); + IOHandlerSP reader_sp (m_input_reader_stack.Top()); if (reader_sp) - { - reader_sp->Notify (eInputReaderEndOfFile); - - // If notifying the reader of the end-of-file finished the reader, we should pop it off the stack. - while (CheckIfTopInputReaderIsDone ()) ; - } + reader_sp->GotEOF(); } void -Debugger::CleanUpInputReaders () +Debugger::ClearIOHandlers () { - m_input_reader_data.clear(); - // The bottom input reader should be the main debugger input reader. We do not want to close that one here. + Mutex::Locker locker (m_input_reader_stack.GetMutex()); while (m_input_reader_stack.GetSize() > 1) { - InputReaderSP reader_sp (GetCurrentInputReader ()); + IOHandlerSP reader_sp (m_input_reader_stack.Top()); if (reader_sp) { - reader_sp->Notify (eInputReaderEndOfFile); - reader_sp->SetIsDone (true); + m_input_reader_stack.Pop(); + reader_sp->SetIsDone(true); + reader_sp->Cancel(); } } } void -Debugger::NotifyTopInputReader (InputReaderAction notification) +Debugger::ExecuteIOHanders() { - InputReaderSP reader_sp (GetCurrentInputReader()); - if (reader_sp) - { - reader_sp->Notify (notification); + + while (1) + { + IOHandlerSP reader_sp(m_input_reader_stack.Top()); + if (!reader_sp) + break; - // Flush out any input readers that are done. - while (CheckIfTopInputReaderIsDone ()) - /* Do nothing. */; + reader_sp->Activate(); + reader_sp->Run(); + reader_sp->Deactivate(); + + // Remove all input readers that are done from the top of the stack + while (1) + { + IOHandlerSP top_reader_sp = m_input_reader_stack.Top(); + if (top_reader_sp && top_reader_sp->GetIsDone()) + m_input_reader_stack.Pop(); + else + break; + } } + ClearIOHandlers(); } bool -Debugger::InputReaderIsTopReader (const InputReaderSP& reader_sp) +Debugger::IsTopIOHandler (const lldb::IOHandlerSP& reader_sp) { - InputReaderSP top_reader_sp (GetCurrentInputReader()); + return m_input_reader_stack.IsTop (reader_sp); +} + - return (reader_sp.get() == top_reader_sp.get()); +ConstString +Debugger::GetTopIOHandlerControlSequence(char ch) +{ + return m_input_reader_stack.GetTopIOHandlerControlSequence (ch); } - void -Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len) +Debugger::RunIOHandler (const IOHandlerSP& reader_sp) { - if (bytes && bytes_len) - m_input_reader_data.append (bytes, bytes_len); - - if (m_input_reader_data.empty()) - return; + Mutex::Locker locker (m_input_reader_stack.GetMutex()); + PushIOHandler (reader_sp); + reader_sp->Activate(); + reader_sp->Run(); + PopIOHandler (reader_sp); +} - while (!m_input_reader_stack.IsEmpty() && !m_input_reader_data.empty()) +void +Debugger::AdoptTopIOHandlerFilesIfInvalid (StreamFileSP &in, StreamFileSP &out, StreamFileSP &err) +{ + // Before an IOHandler runs, it must have in/out/err streams. + // This function is called when one ore more of the streams + // are NULL. We use the top input reader's in/out/err streams, + // or fall back to the debugger file handles, or we fall back + // onto stdin/stdout/stderr as a last resort. + + Mutex::Locker locker (m_input_reader_stack.GetMutex()); + IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); + // If no STDIN has been set, then set it appropriately + if (!in) { - // Get the input reader from the top of the stack - InputReaderSP reader_sp (GetCurrentInputReader ()); - if (!reader_sp) - break; - - size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.c_str(), - m_input_reader_data.size()); - if (bytes_handled) - { - m_input_reader_data.erase (0, bytes_handled); - } + if (top_reader_sp) + in = top_reader_sp->GetInputStreamFile(); else - { - // No bytes were handled, we might not have reached our - // granularity, just return and wait for more data - break; - } + in = GetInputFile(); + + // If there is nothing, use stdin + if (!in) + in = StreamFileSP(new StreamFile(stdin, false)); + } + // If no STDOUT has been set, then set it appropriately + if (!out) + { + if (top_reader_sp) + out = top_reader_sp->GetOutputStreamFile(); + else + out = GetOutputFile(); + + // If there is nothing, use stdout + if (!out) + out = StreamFileSP(new StreamFile(stdout, false)); + } + // If no STDERR has been set, then set it appropriately + if (!err) + { + if (top_reader_sp) + err = top_reader_sp->GetErrorStreamFile(); + else + err = GetErrorFile(); + + // If there is nothing, use stderr + if (!err) + err = StreamFileSP(new StreamFile(stdout, false)); + } - - // Flush out any input readers that are done. - while (CheckIfTopInputReaderIsDone ()) - /* Do nothing. */; - } void -Debugger::PushInputReader (const InputReaderSP& reader_sp) +Debugger::PushIOHandler (const IOHandlerSP& reader_sp) { if (!reader_sp) return; - // Deactivate the old top reader - InputReaderSP top_reader_sp (GetCurrentInputReader ()); + // Got the current top input reader... + IOHandlerSP top_reader_sp (m_input_reader_stack.Top()); - if (top_reader_sp) - top_reader_sp->Notify (eInputReaderDeactivate); - + // Push our new input reader m_input_reader_stack.Push (reader_sp); - reader_sp->Notify (eInputReaderActivate); - ActivateInputReader (reader_sp); + + // Interrupt the top input reader to it will exit its Run() function + // and let this new input reader take over + if (top_reader_sp) + top_reader_sp->Deactivate(); } bool -Debugger::PopInputReader (const InputReaderSP& pop_reader_sp) +Debugger::PopIOHandler (const IOHandlerSP& pop_reader_sp) { bool result = false; + + Mutex::Locker locker (m_input_reader_stack.GetMutex()); // The reader on the stop of the stack is done, so let the next // read on the stack referesh its prompt and if there is one... if (!m_input_reader_stack.IsEmpty()) { - // Cannot call GetCurrentInputReader here, as that would cause an infinite loop. - InputReaderSP reader_sp(m_input_reader_stack.Top()); + IOHandlerSP reader_sp(m_input_reader_stack.Top()); if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get()) { + reader_sp->Deactivate(); m_input_reader_stack.Pop (); - reader_sp->Notify (eInputReaderDeactivate); - reader_sp->Notify (eInputReaderDone); - result = true; + + reader_sp = m_input_reader_stack.Top(); + if (reader_sp) + reader_sp->Activate(); - if (!m_input_reader_stack.IsEmpty()) - { - reader_sp = m_input_reader_stack.Top(); - if (reader_sp) - { - ActivateInputReader (reader_sp); - reader_sp->Notify (eInputReaderReactivate); - } - } + result = true; } } return result; } bool -Debugger::CheckIfTopInputReaderIsDone () +Debugger::HideTopIOHandler() { - bool result = false; - if (!m_input_reader_stack.IsEmpty()) + Mutex::Locker locker; + + if (locker.TryLock(m_input_reader_stack.GetMutex())) { - // Cannot call GetCurrentInputReader here, as that would cause an infinite loop. - InputReaderSP reader_sp(m_input_reader_stack.Top()); - - if (reader_sp && reader_sp->IsDone()) - { - result = true; - PopInputReader (reader_sp); - } + IOHandlerSP reader_sp(m_input_reader_stack.Top()); + if (reader_sp) + reader_sp->Hide(); + return true; } - return result; + return false; } void -Debugger::ActivateInputReader (const InputReaderSP &reader_sp) +Debugger::RefreshTopIOHandler() { - int input_fd = m_input_file.GetFile().GetDescriptor(); - - if (input_fd >= 0) - { - Terminal tty(input_fd); - - tty.SetEcho(reader_sp->GetEcho()); - - switch (reader_sp->GetGranularity()) - { - case eInputReaderGranularityByte: - case eInputReaderGranularityWord: - tty.SetCanonical (false); - break; - - case eInputReaderGranularityLine: - case eInputReaderGranularityAll: - tty.SetCanonical (true); - break; - - default: - break; - } - } + IOHandlerSP reader_sp(m_input_reader_stack.Top()); + if (reader_sp) + reader_sp->Refresh(); } + StreamSP Debugger::GetAsyncOutputStream () { @@ -2624,7 +2594,7 @@ Debugger::EnableLog (const char *channel, const char **categories, const char *l } else if (log_file == NULL || *log_file == '\0') { - log_stream_sp.reset(new StreamFile(GetOutputFile().GetDescriptor(), false)); + log_stream_sp = GetOutputFile(); } else { @@ -2680,3 +2650,514 @@ Debugger::GetSourceManager () } + +// This function handles events that were broadcast by the process. +void +Debugger::HandleBreakpointEvent (const EventSP &event_sp) +{ + using namespace lldb; + const uint32_t event_type = Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (event_sp); + +// if (event_type & eBreakpointEventTypeAdded +// || event_type & eBreakpointEventTypeRemoved +// || event_type & eBreakpointEventTypeEnabled +// || event_type & eBreakpointEventTypeDisabled +// || event_type & eBreakpointEventTypeCommandChanged +// || event_type & eBreakpointEventTypeConditionChanged +// || event_type & eBreakpointEventTypeIgnoreChanged +// || event_type & eBreakpointEventTypeLocationsResolved) +// { +// // Don't do anything about these events, since the breakpoint commands already echo these actions. +// } +// + if (event_type & eBreakpointEventTypeLocationsAdded) + { + uint32_t num_new_locations = Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(event_sp); + if (num_new_locations > 0) + { + BreakpointSP breakpoint = Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); + StreamFileSP output_sp (GetOutputFile()); + if (output_sp) + { + output_sp->Printf("%d location%s added to breakpoint %d\n", + num_new_locations, + num_new_locations == 1 ? "" : "s", + breakpoint->GetID()); + RefreshTopIOHandler(); + } + } + } +// else if (event_type & eBreakpointEventTypeLocationsRemoved) +// { +// // These locations just get disabled, not sure it is worth spamming folks about this on the command line. +// } +// else if (event_type & eBreakpointEventTypeLocationsResolved) +// { +// // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy. +// } +} + +size_t +Debugger::GetProcessSTDOUT (Process *process, Stream *stream) +{ + size_t total_bytes = 0; + if (stream == NULL) + stream = GetOutputFile().get(); + + if (stream) + { + // The process has stuff waiting for stdout; get it and write it out to the appropriate place. + if (process == NULL) + { + TargetSP target_sp = GetTargetList().GetSelectedTarget(); + if (target_sp) + process = target_sp->GetProcessSP().get(); + } + if (process) + { + Error error; + size_t len; + char stdio_buffer[1024]; + while ((len = process->GetSTDOUT (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + stream->Write(stdio_buffer, len); + total_bytes += len; + } + } + stream->Flush(); + } + return total_bytes; +} + +size_t +Debugger::GetProcessSTDERR (Process *process, Stream *stream) +{ + size_t total_bytes = 0; + if (stream == NULL) + stream = GetOutputFile().get(); + + if (stream) + { + // The process has stuff waiting for stderr; get it and write it out to the appropriate place. + if (process == NULL) + { + TargetSP target_sp = GetTargetList().GetSelectedTarget(); + if (target_sp) + process = target_sp->GetProcessSP().get(); + } + if (process) + { + Error error; + size_t len; + char stdio_buffer[1024]; + while ((len = process->GetSTDERR (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + stream->Write(stdio_buffer, len); + total_bytes += len; + } + } + stream->Flush(); + } + return total_bytes; +} + +// This function handles events that were broadcast by the process. +void +Debugger::HandleProcessEvent (const EventSP &event_sp) +{ + using namespace lldb; + const uint32_t event_type = event_sp->GetType(); + ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); + + const bool gui_enabled = IsForwardingEvents(); + bool top_io_handler_hid = false; + if (gui_enabled == false) + top_io_handler_hid = HideTopIOHandler(); + + assert (process_sp); + + if (event_type & Process::eBroadcastBitSTDOUT) + { + // The process has stdout available, get it and write it out to the + // appropriate place. + if (top_io_handler_hid) + GetProcessSTDOUT (process_sp.get(), NULL); + } + else if (event_type & Process::eBroadcastBitSTDERR) + { + // The process has stderr available, get it and write it out to the + // appropriate place. + if (top_io_handler_hid) + GetProcessSTDERR (process_sp.get(), NULL); + } + else if (event_type & Process::eBroadcastBitStateChanged) + { + // Drain all stout and stderr so we don't see any output come after + // we print our prompts + if (top_io_handler_hid) + { + StreamFileSP stream_sp (GetOutputFile()); + GetProcessSTDOUT (process_sp.get(), stream_sp.get()); + GetProcessSTDERR (process_sp.get(), NULL); + // Something changed in the process; get the event and report the process's current status and location to + // the user. + StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); + if (event_state == eStateInvalid) + return; + + switch (event_state) + { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateStepping: + case eStateDetached: + { + stream_sp->Printf("Process %" PRIu64 " %s\n", + process_sp->GetID(), + StateAsCString (event_state)); + } + break; + + case eStateRunning: + // Don't be chatty when we run... + break; + + case eStateExited: + process_sp->GetStatus(*stream_sp); + break; + + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + // Make sure the program hasn't been auto-restarted: + if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get())) + { + size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get()); + if (num_reasons > 0) + { + // FIXME: Do we want to report this, or would that just be annoyingly chatty? + if (num_reasons == 1) + { + const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0); + stream_sp->Printf("Process %" PRIu64 " stopped and restarted: %s\n", + process_sp->GetID(), + reason ? reason : "<UNKNOWN REASON>"); + } + else + { + stream_sp->Printf("Process %" PRIu64 " stopped and restarted, reasons:\n", + process_sp->GetID()); + + + for (size_t i = 0; i < num_reasons; i++) + { + const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i); + stream_sp->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>"); + } + } + } + } + else + { + // Lock the thread list so it doesn't change on us + ThreadList &thread_list = process_sp->GetThreadList(); + Mutex::Locker locker (thread_list.GetMutex()); + + ThreadSP curr_thread (thread_list.GetSelectedThread()); + ThreadSP thread; + StopReason curr_thread_stop_reason = eStopReasonInvalid; + if (curr_thread) + curr_thread_stop_reason = curr_thread->GetStopReason(); + if (!curr_thread || + !curr_thread->IsValid() || + curr_thread_stop_reason == eStopReasonInvalid || + curr_thread_stop_reason == eStopReasonNone) + { + // Prefer a thread that has just completed its plan over another thread as current thread. + ThreadSP plan_thread; + ThreadSP other_thread; + const size_t num_threads = thread_list.GetSize(); + size_t i; + for (i = 0; i < num_threads; ++i) + { + thread = thread_list.GetThreadAtIndex(i); + StopReason thread_stop_reason = thread->GetStopReason(); + switch (thread_stop_reason) + { + case eStopReasonInvalid: + case eStopReasonNone: + break; + + case eStopReasonTrace: + case eStopReasonBreakpoint: + case eStopReasonWatchpoint: + case eStopReasonSignal: + case eStopReasonException: + case eStopReasonExec: + case eStopReasonThreadExiting: + if (!other_thread) + other_thread = thread; + break; + case eStopReasonPlanComplete: + if (!plan_thread) + plan_thread = thread; + break; + } + } + if (plan_thread) + thread_list.SetSelectedThreadByID (plan_thread->GetID()); + else if (other_thread) + thread_list.SetSelectedThreadByID (other_thread->GetID()); + else + { + if (curr_thread && curr_thread->IsValid()) + thread = curr_thread; + else + thread = thread_list.GetThreadAtIndex(0); + + if (thread) + thread_list.SetSelectedThreadByID (thread->GetID()); + } + } + + if (GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget()) + { + const bool only_threads_with_stop_reason = true; + const uint32_t start_frame = 0; + const uint32_t num_frames = 1; + const uint32_t num_frames_with_source = 1; + process_sp->GetStatus(*stream_sp); + process_sp->GetThreadStatus (*stream_sp, + only_threads_with_stop_reason, + start_frame, + num_frames, + num_frames_with_source); + } + else + { + uint32_t target_idx = GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this()); + if (target_idx != UINT32_MAX) + stream_sp->Printf ("Target %d: (", target_idx); + else + stream_sp->Printf ("Target <unknown index>: ("); + process_sp->GetTarget().Dump (stream_sp.get(), eDescriptionLevelBrief); + stream_sp->Printf (") stopped.\n"); + } + } + break; + } + } + } + + if (top_io_handler_hid) + RefreshTopIOHandler(); +} + +void +Debugger::HandleThreadEvent (const EventSP &event_sp) +{ + // At present the only thread event we handle is the Frame Changed event, + // and all we do for that is just reprint the thread status for that thread. + using namespace lldb; + const uint32_t event_type = event_sp->GetType(); + if (event_type == Thread::eBroadcastBitStackChanged || + event_type == Thread::eBroadcastBitThreadSelected ) + { + ThreadSP thread_sp (Thread::ThreadEventData::GetThreadFromEvent (event_sp.get())); + if (thread_sp) + { + HideTopIOHandler(); + StreamFileSP stream_sp (GetOutputFile()); + thread_sp->GetStatus(*stream_sp, 0, 1, 1); + RefreshTopIOHandler(); + } + } +} + +bool +Debugger::IsForwardingEvents () +{ + return (bool)m_forward_listener_sp; +} + +void +Debugger::EnableForwardEvents (const ListenerSP &listener_sp) +{ + m_forward_listener_sp = listener_sp; +} + +void +Debugger::CancelForwardEvents (const ListenerSP &listener_sp) +{ + m_forward_listener_sp.reset(); +} + + +void +Debugger::DefaultEventHandler() +{ + Listener& listener(GetListener()); + ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); + ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); + ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); + BroadcastEventSpec target_event_spec (broadcaster_class_target, + Target::eBroadcastBitBreakpointChanged); + + BroadcastEventSpec process_event_spec (broadcaster_class_process, + Process::eBroadcastBitStateChanged | + Process::eBroadcastBitSTDOUT | + Process::eBroadcastBitSTDERR); + + BroadcastEventSpec thread_event_spec (broadcaster_class_thread, + Thread::eBroadcastBitStackChanged | + Thread::eBroadcastBitThreadSelected ); + + listener.StartListeningForEventSpec (*this, target_event_spec); + listener.StartListeningForEventSpec (*this, process_event_spec); + listener.StartListeningForEventSpec (*this, thread_event_spec); + listener.StartListeningForEvents (m_command_interpreter_ap.get(), + CommandInterpreter::eBroadcastBitQuitCommandReceived | + CommandInterpreter::eBroadcastBitAsynchronousOutputData | + CommandInterpreter::eBroadcastBitAsynchronousErrorData ); + + bool done = false; + while (!done) + { +// Mutex::Locker locker; +// if (locker.TryLock(m_input_reader_stack.GetMutex())) +// { +// if (m_input_reader_stack.IsEmpty()) +// break; +// } +// + EventSP event_sp; + if (listener.WaitForEvent(NULL, event_sp)) + { + if (event_sp) + { + Broadcaster *broadcaster = event_sp->GetBroadcaster(); + if (broadcaster) + { + uint32_t event_type = event_sp->GetType(); + ConstString broadcaster_class (broadcaster->GetBroadcasterClass()); + if (broadcaster_class == broadcaster_class_process) + { + HandleProcessEvent (event_sp); + } + else if (broadcaster_class == broadcaster_class_target) + { + if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(event_sp.get())) + { + HandleBreakpointEvent (event_sp); + } + } + else if (broadcaster_class == broadcaster_class_thread) + { + HandleThreadEvent (event_sp); + } + else if (broadcaster == m_command_interpreter_ap.get()) + { + if (event_type & CommandInterpreter::eBroadcastBitQuitCommandReceived) + { + done = true; + } + else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousErrorData) + { + const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); + if (data && data[0]) + { + StreamFileSP error_sp (GetErrorFile()); + if (error_sp) + { + HideTopIOHandler(); + error_sp->PutCString(data); + error_sp->Flush(); + RefreshTopIOHandler(); + } + } + } + else if (event_type & CommandInterpreter::eBroadcastBitAsynchronousOutputData) + { + const char *data = reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event_sp.get())); + if (data && data[0]) + { + StreamFileSP output_sp (GetOutputFile()); + if (output_sp) + { + HideTopIOHandler(); + output_sp->PutCString(data); + output_sp->Flush(); + RefreshTopIOHandler(); + } + } + } + } + } + + if (m_forward_listener_sp) + m_forward_listener_sp->AddEvent(event_sp); + } + } + } +} + +lldb::thread_result_t +Debugger::EventHandlerThread (lldb::thread_arg_t arg) +{ + ((Debugger *)arg)->DefaultEventHandler(); + return NULL; +} + +bool +Debugger::StartEventHandlerThread() +{ + if (!IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread)) + m_event_handler_thread = Host::ThreadCreate("lldb.debugger.event-handler", EventHandlerThread, this, NULL); + return IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread); +} + +void +Debugger::StopEventHandlerThread() +{ + if (IS_VALID_LLDB_HOST_THREAD(m_event_handler_thread)) + { + GetCommandInterpreter().BroadcastEvent(CommandInterpreter::eBroadcastBitQuitCommandReceived); + Host::ThreadJoin(m_event_handler_thread, NULL, NULL); + m_event_handler_thread = LLDB_INVALID_HOST_THREAD; + } +} + + +lldb::thread_result_t +Debugger::IOHandlerThread (lldb::thread_arg_t arg) +{ + Debugger *debugger = (Debugger *)arg; + debugger->ExecuteIOHanders(); + debugger->StopEventHandlerThread(); + return NULL; +} + +bool +Debugger::StartIOHandlerThread() +{ + if (!IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread)) + m_io_handler_thread = Host::ThreadCreate("lldb.debugger.io-handler", IOHandlerThread, this, NULL); + return IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread); +} + +void +Debugger::StopIOHandlerThread() +{ + if (IS_VALID_LLDB_HOST_THREAD(m_io_handler_thread)) + { + if (m_input_file_sp) + m_input_file_sp->GetFile().Close(); + Host::ThreadJoin(m_io_handler_thread, NULL, NULL); + m_io_handler_thread = LLDB_INVALID_HOST_THREAD; + } +} + + diff --git a/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp b/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp index 7f830ac..1d2b8cf 100644 --- a/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Disassembler.cpp @@ -35,6 +35,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" @@ -1044,10 +1045,8 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const } uint32_t -InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target) +InstructionList::GetIndexOfInstructionAtAddress (const Address &address) { - Address address; - address.SetLoadAddress(load_addr, &target); size_t num_instructions = m_instructions.size(); uint32_t index = UINT32_MAX; for (size_t i = 0; i < num_instructions; i++) @@ -1061,6 +1060,15 @@ InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Tar return index; } + +uint32_t +InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target) +{ + Address address; + address.SetLoadAddress(load_addr, &target); + return GetIndexOfInstructionAtAddress(address); +} + size_t Disassembler::ParseInstructions (const ExecutionContext *exe_ctx, const AddressRange &range, @@ -1235,25 +1243,25 @@ PseudoInstruction::SetOpcode (size_t opcode_size, void *opcode_data) case 8: { uint8_t value8 = *((uint8_t *) opcode_data); - m_opcode.SetOpcode8 (value8); + m_opcode.SetOpcode8 (value8, eByteOrderInvalid); break; } case 16: { uint16_t value16 = *((uint16_t *) opcode_data); - m_opcode.SetOpcode16 (value16); + m_opcode.SetOpcode16 (value16, eByteOrderInvalid); break; } case 32: { uint32_t value32 = *((uint32_t *) opcode_data); - m_opcode.SetOpcode32 (value32); + m_opcode.SetOpcode32 (value32, eByteOrderInvalid); break; } case 64: { uint64_t value64 = *((uint64_t *) opcode_data); - m_opcode.SetOpcode64 (value64); + m_opcode.SetOpcode64 (value64, eByteOrderInvalid); break; } default: diff --git a/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp b/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp index 82f8404..1f545b7 100644 --- a/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp +++ b/contrib/llvm/tools/lldb/source/Core/DynamicLoader.cpp @@ -10,7 +10,11 @@ #include "lldb/lldb-private.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" using namespace lldb; using namespace lldb_private; @@ -74,3 +78,137 @@ DynamicLoader::SetStopWhenImagesChange (bool stop) m_process->SetStopOnSharedLibraryEvents (stop); } +ModuleSP +DynamicLoader::GetTargetExecutable() +{ + Target &target = m_process->GetTarget(); + ModuleSP executable = target.GetExecutableModule(); + + if (executable.get()) + { + if (executable->GetFileSpec().Exists()) + { + ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture()); + ModuleSP module_sp (new Module (module_spec)); + + // Check if the executable has changed and set it to the target executable if they differ. + if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) + { + if (module_sp->GetUUID() != executable->GetUUID()) + executable.reset(); + } + else if (executable->FileHasChanged()) + { + executable.reset(); + } + + if (!executable.get()) + { + executable = target.GetSharedModule(module_spec); + if (executable.get() != target.GetExecutableModulePointer()) + { + // Don't load dependent images since we are in dyld where we will know + // and find out about all images that are loaded + const bool get_dependent_images = false; + target.SetExecutableModule(executable, get_dependent_images); + } + } + } + } + return executable; +} + +void +DynamicLoader::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr) +{ + UpdateLoadedSectionsCommon(module, base_addr); +} + +void +DynamicLoader::UpdateLoadedSectionsCommon(ModuleSP module, addr_t base_addr) +{ + bool changed; + const bool base_addr_is_offset = true; + module->SetLoadAddress(m_process->GetTarget(), base_addr, base_addr_is_offset, changed); +} + +void +DynamicLoader::UnloadSections(const ModuleSP module) +{ + UnloadSectionsCommon(module); +} + +void +DynamicLoader::UnloadSectionsCommon(const ModuleSP module) +{ + Target &target = m_process->GetTarget(); + const SectionList *sections = GetSectionListFromModule(module); + + assert(sections && "SectionList missing from unloaded module."); + + const size_t num_sections = sections->GetSize(); + for (size_t i = 0; i < num_sections; ++i) + { + SectionSP section_sp (sections->GetSectionAtIndex(i)); + target.SetSectionUnloaded(section_sp); + } +} + + +const SectionList * +DynamicLoader::GetSectionListFromModule(const ModuleSP module) const +{ + SectionList *sections = nullptr; + if (module.get()) + { + ObjectFile *obj_file = module->GetObjectFile(); + if (obj_file) + { + sections = obj_file->GetSectionList(); + } + } + return sections; +} + +ModuleSP +DynamicLoader::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + ModuleList &modules = target.GetImages(); + ModuleSP module_sp; + + ModuleSpec module_spec (file, target.GetArchitecture()); + if ((module_sp = modules.FindFirstModule (module_spec))) + { + UpdateLoadedSections(module_sp, link_map_addr, base_addr); + } + else if ((module_sp = target.GetSharedModule(module_spec))) + { + UpdateLoadedSections(module_sp, link_map_addr, base_addr); + } + + return module_sp; +} + +int64_t +DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr, int size_in_bytes) +{ + Error error; + + uint64_t value = m_process->ReadUnsignedIntegerFromMemory(addr, size_in_bytes, 0, error); + if (error.Fail()) + return -1; + else + return (int64_t)value; +} + +addr_t +DynamicLoader::ReadPointer(addr_t addr) +{ + Error error; + addr_t value = m_process->ReadPointerFromMemory(addr, error); + if (error.Fail()) + return LLDB_INVALID_ADDRESS; + else + return value; +} diff --git a/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp new file mode 100644 index 0000000..168a8f6 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp @@ -0,0 +1,5305 @@ +//===-- IOHandler.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 <string> + +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/State.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Host/Editline.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/ThreadPlan.h" + +#ifndef LLDB_DISABLE_CURSES +#include <ncurses.h> +#include <panel.h> +#endif + +using namespace lldb; +using namespace lldb_private; + +IOHandler::IOHandler (Debugger &debugger) : + IOHandler (debugger, + StreamFileSP(), // Adopt STDIN from top input reader + StreamFileSP(), // Adopt STDOUT from top input reader + StreamFileSP(), // Adopt STDERR from top input reader + 0) // Flags +{ +} + + +IOHandler::IOHandler (Debugger &debugger, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, + uint32_t flags) : + m_debugger (debugger), + m_input_sp (input_sp), + m_output_sp (output_sp), + m_error_sp (error_sp), + m_flags (flags), + m_user_data (NULL), + m_done (false), + m_active (false) +{ + // If any files are not specified, then adopt them from the top input reader. + if (!m_input_sp || !m_output_sp || !m_error_sp) + debugger.AdoptTopIOHandlerFilesIfInvalid (m_input_sp, + m_output_sp, + m_error_sp); +} + +IOHandler::~IOHandler() +{ +} + + +int +IOHandler::GetInputFD() +{ + if (m_input_sp) + return m_input_sp->GetFile().GetDescriptor(); + return -1; +} + +int +IOHandler::GetOutputFD() +{ + if (m_output_sp) + return m_output_sp->GetFile().GetDescriptor(); + return -1; +} + +int +IOHandler::GetErrorFD() +{ + if (m_error_sp) + return m_error_sp->GetFile().GetDescriptor(); + return -1; +} + +FILE * +IOHandler::GetInputFILE() +{ + if (m_input_sp) + return m_input_sp->GetFile().GetStream(); + return NULL; +} + +FILE * +IOHandler::GetOutputFILE() +{ + if (m_output_sp) + return m_output_sp->GetFile().GetStream(); + return NULL; +} + +FILE * +IOHandler::GetErrorFILE() +{ + if (m_error_sp) + return m_error_sp->GetFile().GetStream(); + return NULL; +} + +StreamFileSP & +IOHandler::GetInputStreamFile() +{ + return m_input_sp; +} + +StreamFileSP & +IOHandler::GetOutputStreamFile() +{ + return m_output_sp; +} + + +StreamFileSP & +IOHandler::GetErrorStreamFile() +{ + return m_error_sp; +} + +bool +IOHandler::GetIsInteractive () +{ + return GetInputStreamFile()->GetFile().GetIsInteractive (); +} + +bool +IOHandler::GetIsRealTerminal () +{ + return GetInputStreamFile()->GetFile().GetIsRealTerminal(); +} + +IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger, + const char *prompt, + bool default_response) : + IOHandlerEditline(debugger, + NULL, // NULL editline_name means no history loaded/saved + NULL, + false, // Multi-line + *this), + m_default_response (default_response), + m_user_response (default_response) +{ + StreamString prompt_stream; + prompt_stream.PutCString(prompt); + if (m_default_response) + prompt_stream.Printf(": [Y/n] "); + else + prompt_stream.Printf(": [y/N] "); + + SetPrompt (prompt_stream.GetString().c_str()); + +} + + +IOHandlerConfirm::~IOHandlerConfirm () +{ +} + +int +IOHandlerConfirm::IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches) +{ + if (current_line == cursor) + { + if (m_default_response) + { + matches.AppendString("y"); + } + else + { + matches.AppendString("n"); + } + } + return matches.GetSize(); +} + +void +IOHandlerConfirm::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) +{ + if (line.empty()) + { + // User just hit enter, set the response to the default + m_user_response = m_default_response; + io_handler.SetIsDone(true); + return; + } + + if (line.size() == 1) + { + switch (line[0]) + { + case 'y': + case 'Y': + m_user_response = true; + io_handler.SetIsDone(true); + return; + case 'n': + case 'N': + m_user_response = false; + io_handler.SetIsDone(true); + return; + default: + break; + } + } + + if (line == "yes" || line == "YES" || line == "Yes") + { + m_user_response = true; + io_handler.SetIsDone(true); + } + else if (line == "no" || line == "NO" || line == "No") + { + m_user_response = false; + io_handler.SetIsDone(true); + } +} + +int +IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler, + const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches) +{ + switch (m_completion) + { + case Completion::None: + break; + + case Completion::LLDBCommand: + return io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion (current_line, + cursor, + last_char, + skip_first_n_matches, + max_matches, + matches); + + case Completion::Expression: + { + bool word_complete = false; + const char *word_start = cursor; + if (cursor > current_line) + --word_start; + while (word_start > current_line && !isspace(*word_start)) + --word_start; + CommandCompletions::InvokeCommonCompletionCallbacks (io_handler.GetDebugger().GetCommandInterpreter(), + CommandCompletions::eVariablePathCompletion, + word_start, + skip_first_n_matches, + max_matches, + NULL, + word_complete, + matches); + + size_t num_matches = matches.GetSize(); + if (num_matches > 0) + { + std::string common_prefix; + matches.LongestCommonPrefix (common_prefix); + const size_t partial_name_len = strlen(word_start); + + // If we matched a unique single command, add a space... + // Only do this if the completer told us this was a complete word, however... + if (num_matches == 1 && word_complete) + { + common_prefix.push_back(' '); + } + common_prefix.erase (0, partial_name_len); + matches.InsertStringAtIndex(0, std::move(common_prefix)); + } + return num_matches; + } + break; + } + + + return 0; +} + + +IOHandlerEditline::IOHandlerEditline (Debugger &debugger, + const char *editline_name, // Used for saving history files + const char *prompt, + bool multi_line, + IOHandlerDelegate &delegate) : + IOHandlerEditline(debugger, + StreamFileSP(), // Inherit input from top input reader + StreamFileSP(), // Inherit output from top input reader + StreamFileSP(), // Inherit error from top input reader + 0, // Flags + editline_name, // Used for saving history files + prompt, + multi_line, + delegate) +{ +} + +IOHandlerEditline::IOHandlerEditline (Debugger &debugger, + const lldb::StreamFileSP &input_sp, + const lldb::StreamFileSP &output_sp, + const lldb::StreamFileSP &error_sp, + uint32_t flags, + const char *editline_name, // Used for saving history files + const char *prompt, + bool multi_line, + IOHandlerDelegate &delegate) : + IOHandler (debugger, input_sp, output_sp, error_sp, flags), + m_editline_ap (), + m_delegate (delegate), + m_prompt (), + m_multi_line (multi_line) +{ + SetPrompt(prompt); + + bool use_editline = false; + +#ifndef _MSC_VER + use_editline = m_input_sp->GetFile().GetIsRealTerminal(); +#else + use_editline = true; +#endif + + if (use_editline) + { + m_editline_ap.reset(new Editline (editline_name, + prompt ? prompt : "", + GetInputFILE (), + GetOutputFILE (), + GetErrorFILE ())); + m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this); + m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this); + } + +} + +IOHandlerEditline::~IOHandlerEditline () +{ + m_editline_ap.reset(); +} + + +bool +IOHandlerEditline::GetLine (std::string &line) +{ + if (m_editline_ap) + { + return m_editline_ap->GetLine(line).Success(); + } + else + { + line.clear(); + + FILE *in = GetInputFILE(); + if (in) + { + if (GetIsInteractive()) + { + const char *prompt = GetPrompt(); + if (prompt && prompt[0]) + { + FILE *out = GetOutputFILE(); + if (out) + { + ::fprintf(out, "%s", prompt); + ::fflush(out); + } + } + } + char buffer[256]; + bool done = false; + bool got_line = false; + while (!done) + { + if (fgets(buffer, sizeof(buffer), in) == NULL) + done = true; + else + { + got_line = true; + size_t buffer_len = strlen(buffer); + assert (buffer[buffer_len] == '\0'); + char last_char = buffer[buffer_len-1]; + if (last_char == '\r' || last_char == '\n') + { + done = true; + // Strip trailing newlines + while (last_char == '\r' || last_char == '\n') + { + --buffer_len; + if (buffer_len == 0) + break; + last_char = buffer[buffer_len-1]; + } + } + line.append(buffer, buffer_len); + } + } + // We might have gotten a newline on a line by itself + // make sure to return true in this case. + return got_line; + } + else + { + // No more input file, we are done... + SetIsDone(true); + } + return false; + } +} + + +LineStatus +IOHandlerEditline::LineCompletedCallback (Editline *editline, + StringList &lines, + uint32_t line_idx, + Error &error, + void *baton) +{ + IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton; + return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error); +} + +int +IOHandlerEditline::AutoCompleteCallback (const char *current_line, + const char *cursor, + const char *last_char, + int skip_first_n_matches, + int max_matches, + StringList &matches, + void *baton) +{ + IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton; + if (editline_reader) + return editline_reader->m_delegate.IOHandlerComplete (*editline_reader, + current_line, + cursor, + last_char, + skip_first_n_matches, + max_matches, + matches); + return 0; +} + +const char * +IOHandlerEditline::GetPrompt () +{ + if (m_editline_ap) + return m_editline_ap->GetPrompt (); + else if (m_prompt.empty()) + return NULL; + return m_prompt.c_str(); +} + +bool +IOHandlerEditline::SetPrompt (const char *p) +{ + if (p && p[0]) + m_prompt = p; + else + m_prompt.clear(); + if (m_editline_ap) + m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str()); + return true; +} + +bool +IOHandlerEditline::GetLines (StringList &lines) +{ + bool success = false; + if (m_editline_ap) + { + std::string end_token; + success = m_editline_ap->GetLines(end_token, lines).Success(); + } + else + { + LineStatus lines_status = LineStatus::Success; + + while (lines_status == LineStatus::Success) + { + std::string line; + if (GetLine(line)) + { + lines.AppendString(line); + Error error; + lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error); + } + else + { + lines_status = LineStatus::Done; + } + } + success = lines.GetSize() > 0; + } + return success; +} + +// Each IOHandler gets to run until it is done. It should read data +// from the "in" and place output into "out" and "err and return +// when done. +void +IOHandlerEditline::Run () +{ + std::string line; + while (IsActive()) + { + if (m_multi_line) + { + StringList lines; + if (GetLines (lines)) + { + line = lines.CopyList(); + m_delegate.IOHandlerInputComplete(*this, line); + } + else + { + m_done = true; + } + } + else + { + if (GetLine(line)) + { + m_delegate.IOHandlerInputComplete(*this, line); + } + else + { + m_done = true; + } + } + } +} + +void +IOHandlerEditline::Hide () +{ + if (m_editline_ap && m_editline_ap->GettingLine()) + m_editline_ap->Hide(); +} + + +void +IOHandlerEditline::Refresh () +{ + if (m_editline_ap && m_editline_ap->GettingLine()) + m_editline_ap->Refresh(); + else + { + const char *prompt = GetPrompt(); + if (prompt && prompt[0]) + { + FILE *out = GetOutputFILE(); + if (out) + { + ::fprintf(out, "%s", prompt); + ::fflush(out); + } + } + } +} + +void +IOHandlerEditline::Cancel () +{ + if (m_editline_ap) + m_editline_ap->Interrupt (); +} + +void +IOHandlerEditline::Interrupt () +{ + if (m_editline_ap) + m_editline_ap->Interrupt(); +} + +void +IOHandlerEditline::GotEOF() +{ + if (m_editline_ap) + m_editline_ap->Interrupt(); +} + +// we may want curses to be disabled for some builds +// for instance, windows +#ifndef LLDB_DISABLE_CURSES + +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/StackFrame.h" + +#define KEY_RETURN 10 +#define KEY_ESCAPE 27 + +namespace curses +{ + class Menu; + class MenuDelegate; + class Window; + class WindowDelegate; + typedef std::shared_ptr<Menu> MenuSP; + typedef std::shared_ptr<MenuDelegate> MenuDelegateSP; + typedef std::shared_ptr<Window> WindowSP; + typedef std::shared_ptr<WindowDelegate> WindowDelegateSP; + typedef std::vector<MenuSP> Menus; + typedef std::vector<WindowSP> Windows; + typedef std::vector<WindowDelegateSP> WindowDelegates; + +#if 0 +type summary add -s "x=${var.x}, y=${var.y}" curses::Point +type summary add -s "w=${var.width}, h=${var.height}" curses::Size +type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect +#endif + struct Point + { + int x; + int y; + + Point (int _x = 0, int _y = 0) : + x(_x), + y(_y) + { + } + + void + Clear () + { + x = 0; + y = 0; + } + + Point & + operator += (const Point &rhs) + { + x += rhs.x; + y += rhs.y; + return *this; + } + + void + Dump () + { + printf ("(x=%i, y=%i)\n", x, y); + } + + }; + + bool operator == (const Point &lhs, const Point &rhs) + { + return lhs.x == rhs.x && lhs.y == rhs.y; + } + bool operator != (const Point &lhs, const Point &rhs) + { + return lhs.x != rhs.x || lhs.y != rhs.y; + } + + struct Size + { + int width; + int height; + Size (int w = 0, int h = 0) : + width (w), + height (h) + { + } + + void + Clear () + { + width = 0; + height = 0; + } + + void + Dump () + { + printf ("(w=%i, h=%i)\n", width, height); + } + + }; + + bool operator == (const Size &lhs, const Size &rhs) + { + return lhs.width == rhs.width && lhs.height == rhs.height; + } + bool operator != (const Size &lhs, const Size &rhs) + { + return lhs.width != rhs.width || lhs.height != rhs.height; + } + + struct Rect + { + Point origin; + Size size; + + Rect () : + origin(), + size() + { + } + + Rect (const Point &p, const Size &s) : + origin (p), + size (s) + { + } + + void + Clear () + { + origin.Clear(); + size.Clear(); + } + + void + Dump () + { + printf ("(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width, size.height); + } + + void + Inset (int w, int h) + { + if (size.width > w*2) + size.width -= w*2; + origin.x += w; + + if (size.height > h*2) + size.height -= h*2; + origin.y += h; + } + // Return a status bar rectangle which is the last line of + // this rectangle. This rectangle will be modified to not + // include the status bar area. + Rect + MakeStatusBar () + { + Rect status_bar; + if (size.height > 1) + { + status_bar.origin.x = origin.x; + status_bar.origin.y = size.height; + status_bar.size.width = size.width; + status_bar.size.height = 1; + --size.height; + } + return status_bar; + } + + // Return a menubar rectangle which is the first line of + // this rectangle. This rectangle will be modified to not + // include the menubar area. + Rect + MakeMenuBar () + { + Rect menubar; + if (size.height > 1) + { + menubar.origin.x = origin.x; + menubar.origin.y = origin.y; + menubar.size.width = size.width; + menubar.size.height = 1; + ++origin.y; + --size.height; + } + return menubar; + } + + void + HorizontalSplitPercentage (float top_percentage, Rect &top, Rect &bottom) const + { + float top_height = top_percentage * size.height; + HorizontalSplit (top_height, top, bottom); + } + + void + HorizontalSplit (int top_height, Rect &top, Rect &bottom) const + { + top = *this; + if (top_height < size.height) + { + top.size.height = top_height; + bottom.origin.x = origin.x; + bottom.origin.y = origin.y + top.size.height; + bottom.size.width = size.width; + bottom.size.height = size.height - top.size.height; + } + else + { + bottom.Clear(); + } + } + + void + VerticalSplitPercentage (float left_percentage, Rect &left, Rect &right) const + { + float left_width = left_percentage * size.width; + VerticalSplit (left_width, left, right); + } + + + void + VerticalSplit (int left_width, Rect &left, Rect &right) const + { + left = *this; + if (left_width < size.width) + { + left.size.width = left_width; + right.origin.x = origin.x + left.size.width; + right.origin.y = origin.y; + right.size.width = size.width - left.size.width; + right.size.height = size.height; + } + else + { + right.Clear(); + } + } + }; + + bool operator == (const Rect &lhs, const Rect &rhs) + { + return lhs.origin == rhs.origin && lhs.size == rhs.size; + } + bool operator != (const Rect &lhs, const Rect &rhs) + { + return lhs.origin != rhs.origin || lhs.size != rhs.size; + } + + enum HandleCharResult + { + eKeyNotHandled = 0, + eKeyHandled = 1, + eQuitApplication = 2 + }; + + enum class MenuActionResult + { + Handled, + NotHandled, + Quit // Exit all menus and quit + }; + + struct KeyHelp + { + int ch; + const char *description; + }; + + class WindowDelegate + { + public: + virtual + ~WindowDelegate() + { + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + return false; // Drawing not handled + } + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int key) + { + return eKeyNotHandled; + } + + virtual const char * + WindowDelegateGetHelpText () + { + return NULL; + } + + virtual KeyHelp * + WindowDelegateGetKeyHelp () + { + return NULL; + } + }; + + class HelpDialogDelegate : + public WindowDelegate + { + public: + HelpDialogDelegate (const char *text, KeyHelp *key_help_array); + + virtual + ~HelpDialogDelegate(); + + virtual bool + WindowDelegateDraw (Window &window, bool force); + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int key); + + size_t + GetNumLines() const + { + return m_text.GetSize(); + } + + size_t + GetMaxLineLength () const + { + return m_text.GetMaxStringLength(); + } + + protected: + StringList m_text; + int m_first_visible_line; + }; + + + class Window + { + public: + + Window (const char *name) : + m_name (name), + m_window (NULL), + m_panel (NULL), + m_parent (NULL), + m_subwindows (), + m_delegate_sp (), + m_curr_active_window_idx (UINT32_MAX), + m_prev_active_window_idx (UINT32_MAX), + m_delete (false), + m_needs_update (true), + m_can_activate (true), + m_is_subwin (false) + { + } + + Window (const char *name, WINDOW *w, bool del = true) : + m_name (name), + m_window (NULL), + m_panel (NULL), + m_parent (NULL), + m_subwindows (), + m_delegate_sp (), + m_curr_active_window_idx (UINT32_MAX), + m_prev_active_window_idx (UINT32_MAX), + m_delete (del), + m_needs_update (true), + m_can_activate (true), + m_is_subwin (false) + { + if (w) + Reset(w); + } + + Window (const char *name, const Rect &bounds) : + m_name (name), + m_window (NULL), + m_parent (NULL), + m_subwindows (), + m_delegate_sp (), + m_curr_active_window_idx (UINT32_MAX), + m_prev_active_window_idx (UINT32_MAX), + m_delete (true), + m_needs_update (true), + m_can_activate (true), + m_is_subwin (false) + { + Reset (::newwin (bounds.size.height, bounds.size.width, bounds.origin.y, bounds.origin.y)); + } + + virtual + ~Window () + { + RemoveSubWindows (); + Reset (); + } + + void + Reset (WINDOW *w = NULL, bool del = true) + { + if (m_window == w) + return; + + if (m_panel) + { + ::del_panel (m_panel); + m_panel = NULL; + } + if (m_window && m_delete) + { + ::delwin (m_window); + m_window = NULL; + m_delete = false; + } + if (w) + { + m_window = w; + m_panel = ::new_panel (m_window); + m_delete = del; + } + } + + void AttributeOn (attr_t attr) { ::wattron (m_window, attr); } + void AttributeOff (attr_t attr) { ::wattroff (m_window, attr); } + void Box (chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { ::box(m_window, v_char, h_char); } + void Clear () { ::wclear (m_window); } + void Erase () { ::werase (m_window); } + Rect GetBounds () { return Rect (GetParentOrigin(), GetSize()); } // Get the rectangle in our parent window + int GetChar () { return ::wgetch (m_window); } + int GetCursorX () { return getcurx (m_window); } + int GetCursorY () { return getcury (m_window); } + Rect GetFrame () { return Rect (Point(), GetSize()); } // Get our rectangle in our own coordinate system + Point GetParentOrigin() { return Point (GetParentX(), GetParentY()); } + Size GetSize() { return Size (GetWidth(), GetHeight()); } + int GetParentX () { return getparx (m_window); } + int GetParentY () { return getpary (m_window); } + int GetMaxX() { return getmaxx (m_window); } + int GetMaxY() { return getmaxy (m_window); } + int GetWidth() { return GetMaxX(); } + int GetHeight() { return GetMaxY(); } + void MoveCursor (int x, int y) { ::wmove (m_window, y, x); } + void MoveWindow (int x, int y) { MoveWindow(Point(x,y)); } + void Resize (int w, int h) { ::wresize(m_window, h, w); } + void Resize (const Size &size) { ::wresize(m_window, size.height, size.width); } + void PutChar (int ch) { ::waddch (m_window, ch); } + void PutCString (const char *s, int len = -1) { ::waddnstr (m_window, s, len); } + void Refresh () { ::wrefresh (m_window); } + void DeferredRefresh () + { + // We are using panels, so we don't need to call this... + //::wnoutrefresh(m_window); + } + void SetBackground (int color_pair_idx) { ::wbkgd (m_window,COLOR_PAIR(color_pair_idx)); } + void UnderlineOn () { AttributeOn(A_UNDERLINE); } + void UnderlineOff () { AttributeOff(A_UNDERLINE); } + + void PutCStringTruncated (const char *s, int right_pad) + { + int bytes_left = GetWidth() - GetCursorX(); + if (bytes_left > right_pad) + { + bytes_left -= right_pad; + ::waddnstr (m_window, s, bytes_left); + } + } + + void + MoveWindow (const Point &origin) + { + const bool moving_window = origin != GetParentOrigin(); + if (m_is_subwin && moving_window) + { + // Can't move subwindows, must delete and re-create + Size size = GetSize(); + Reset (::subwin (m_parent->m_window, + size.height, + size.width, + origin.y, + origin.x), true); + } + else + { + ::mvwin (m_window, origin.y, origin.x); + } + } + + void + SetBounds (const Rect &bounds) + { + const bool moving_window = bounds.origin != GetParentOrigin(); + if (m_is_subwin && moving_window) + { + // Can't move subwindows, must delete and re-create + Reset (::subwin (m_parent->m_window, + bounds.size.height, + bounds.size.width, + bounds.origin.y, + bounds.origin.x), true); + } + else + { + if (moving_window) + MoveWindow(bounds.origin); + Resize (bounds.size); + } + } + + void + Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3))) + { + va_list args; + va_start (args, format); + vwprintw(m_window, format, args); + va_end (args); + } + + void + Touch () + { + ::touchwin (m_window); + if (m_parent) + m_parent->Touch(); + } + + WindowSP + CreateSubWindow (const char *name, const Rect &bounds, bool make_active) + { + WindowSP subwindow_sp; + if (m_window) + { + subwindow_sp.reset(new Window(name, ::subwin (m_window, + bounds.size.height, + bounds.size.width, + bounds.origin.y, + bounds.origin.x), true)); + subwindow_sp->m_is_subwin = true; + } + else + { + subwindow_sp.reset(new Window(name, ::newwin (bounds.size.height, + bounds.size.width, + bounds.origin.y, + bounds.origin.x), true)); + subwindow_sp->m_is_subwin = false; + } + subwindow_sp->m_parent = this; + if (make_active) + { + m_prev_active_window_idx = m_curr_active_window_idx; + m_curr_active_window_idx = m_subwindows.size(); + } + m_subwindows.push_back(subwindow_sp); + ::top_panel (subwindow_sp->m_panel); + m_needs_update = true; + return subwindow_sp; + } + + bool + RemoveSubWindow (Window *window) + { + Windows::iterator pos, end = m_subwindows.end(); + size_t i = 0; + for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) + { + if ((*pos).get() == window) + { + if (m_prev_active_window_idx == i) + m_prev_active_window_idx = UINT32_MAX; + else if (m_prev_active_window_idx != UINT32_MAX && m_prev_active_window_idx > i) + --m_prev_active_window_idx; + + if (m_curr_active_window_idx == i) + m_curr_active_window_idx = UINT32_MAX; + else if (m_curr_active_window_idx != UINT32_MAX && m_curr_active_window_idx > i) + --m_curr_active_window_idx; + window->Erase(); + m_subwindows.erase(pos); + m_needs_update = true; + if (m_parent) + m_parent->Touch(); + else + ::touchwin (stdscr); + return true; + } + } + return false; + } + + WindowSP + FindSubWindow (const char *name) + { + Windows::iterator pos, end = m_subwindows.end(); + size_t i = 0; + for (pos = m_subwindows.begin(); pos != end; ++pos, ++i) + { + if ((*pos)->m_name.compare(name) == 0) + return *pos; + } + return WindowSP(); + } + + void + RemoveSubWindows () + { + m_curr_active_window_idx = UINT32_MAX; + m_prev_active_window_idx = UINT32_MAX; + for (Windows::iterator pos = m_subwindows.begin(); + pos != m_subwindows.end(); + pos = m_subwindows.erase(pos)) + { + (*pos)->Erase(); + } + if (m_parent) + m_parent->Touch(); + else + ::touchwin (stdscr); + } + + WINDOW * + get() + { + return m_window; + } + + operator WINDOW *() + { + return m_window; + } + + //---------------------------------------------------------------------- + // Window drawing utilities + //---------------------------------------------------------------------- + void + DrawTitleBox (const char *title, const char *bottom_message = NULL) + { + attr_t attr = 0; + if (IsActive()) + attr = A_BOLD | COLOR_PAIR(2); + else + attr = 0; + if (attr) + AttributeOn(attr); + + Box(); + MoveCursor(3, 0); + + if (title && title[0]) + { + PutChar ('<'); + PutCString (title); + PutChar ('>'); + } + + if (bottom_message && bottom_message[0]) + { + int bottom_message_length = strlen(bottom_message); + int x = GetWidth() - 3 - (bottom_message_length + 2); + + if (x > 0) + { + MoveCursor (x, GetHeight() - 1); + PutChar ('['); + PutCString(bottom_message); + PutChar (']'); + } + else + { + MoveCursor (1, GetHeight() - 1); + PutChar ('['); + PutCStringTruncated (bottom_message, 1); + } + } + if (attr) + AttributeOff(attr); + + } + + virtual void + Draw (bool force) + { + if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw (*this, force)) + return; + + for (auto &subwindow_sp : m_subwindows) + subwindow_sp->Draw(force); + } + + bool + CreateHelpSubwindow () + { + if (m_delegate_sp) + { + const char *text = m_delegate_sp->WindowDelegateGetHelpText (); + KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp (); + if ((text && text[0]) || key_help) + { + std::auto_ptr<HelpDialogDelegate> help_delegate_ap(new HelpDialogDelegate(text, key_help)); + const size_t num_lines = help_delegate_ap->GetNumLines(); + const size_t max_length = help_delegate_ap->GetMaxLineLength(); + Rect bounds = GetBounds(); + bounds.Inset(1, 1); + if (max_length + 4 < bounds.size.width) + { + bounds.origin.x += (bounds.size.width - max_length + 4)/2; + bounds.size.width = max_length + 4; + } + else + { + if (bounds.size.width > 100) + { + const int inset_w = bounds.size.width / 4; + bounds.origin.x += inset_w; + bounds.size.width -= 2*inset_w; + } + } + + if (num_lines + 2 < bounds.size.height) + { + bounds.origin.y += (bounds.size.height - num_lines + 2)/2; + bounds.size.height = num_lines + 2; + } + else + { + if (bounds.size.height > 100) + { + const int inset_h = bounds.size.height / 4; + bounds.origin.y += inset_h; + bounds.size.height -= 2*inset_h; + } + } + WindowSP help_window_sp; + Window *parent_window = GetParent(); + if (parent_window) + help_window_sp = parent_window->CreateSubWindow("Help", bounds, true); + else + help_window_sp = CreateSubWindow("Help", bounds, true); + help_window_sp->SetDelegate(WindowDelegateSP(help_delegate_ap.release())); + return true; + } + } + return false; + } + + virtual HandleCharResult + HandleChar (int key) + { + // Always check the active window first + HandleCharResult result = eKeyNotHandled; + WindowSP active_window_sp = GetActiveWindow (); + if (active_window_sp) + { + result = active_window_sp->HandleChar (key); + if (result != eKeyNotHandled) + return result; + } + + if (m_delegate_sp) + { + result = m_delegate_sp->WindowDelegateHandleChar (*this, key); + if (result != eKeyNotHandled) + return result; + } + + // Then check for any windows that want any keys + // that weren't handled. This is typically only + // for a menubar. + // Make a copy of the subwindows in case any HandleChar() + // functions muck with the subwindows. If we don't do this, + // we can crash when iterating over the subwindows. + Windows subwindows (m_subwindows); + for (auto subwindow_sp : subwindows) + { + if (subwindow_sp->m_can_activate == false) + { + HandleCharResult result = subwindow_sp->HandleChar(key); + if (result != eKeyNotHandled) + return result; + } + } + + return eKeyNotHandled; + } + + bool + SetActiveWindow (Window *window) + { + const size_t num_subwindows = m_subwindows.size(); + for (size_t i=0; i<num_subwindows; ++i) + { + if (m_subwindows[i].get() == window) + { + m_prev_active_window_idx = m_curr_active_window_idx; + ::top_panel (window->m_panel); + m_curr_active_window_idx = i; + return true; + } + } + return false; + } + + WindowSP + GetActiveWindow () + { + if (!m_subwindows.empty()) + { + if (m_curr_active_window_idx >= m_subwindows.size()) + { + if (m_prev_active_window_idx < m_subwindows.size()) + { + m_curr_active_window_idx = m_prev_active_window_idx; + m_prev_active_window_idx = UINT32_MAX; + } + else if (IsActive()) + { + m_prev_active_window_idx = UINT32_MAX; + m_curr_active_window_idx = UINT32_MAX; + + // Find first window that wants to be active if this window is active + const size_t num_subwindows = m_subwindows.size(); + for (size_t i=0; i<num_subwindows; ++i) + { + if (m_subwindows[i]->GetCanBeActive()) + { + m_curr_active_window_idx = i; + break; + } + } + } + } + + if (m_curr_active_window_idx < m_subwindows.size()) + return m_subwindows[m_curr_active_window_idx]; + } + return WindowSP(); + } + + bool + GetCanBeActive () const + { + return m_can_activate; + } + + void + SetCanBeActive (bool b) + { + m_can_activate = b; + } + + const WindowDelegateSP & + GetDelegate () const + { + return m_delegate_sp; + } + + void + SetDelegate (const WindowDelegateSP &delegate_sp) + { + m_delegate_sp = delegate_sp; + } + + Window * + GetParent () const + { + return m_parent; + } + + bool + IsActive () const + { + if (m_parent) + return m_parent->GetActiveWindow().get() == this; + else + return true; // Top level window is always active + } + + void + SelectNextWindowAsActive () + { + // Move active focus to next window + const size_t num_subwindows = m_subwindows.size(); + if (m_curr_active_window_idx == UINT32_MAX) + { + uint32_t idx = 0; + for (auto subwindow_sp : m_subwindows) + { + if (subwindow_sp->GetCanBeActive()) + { + m_curr_active_window_idx = idx; + break; + } + ++idx; + } + } + else if (m_curr_active_window_idx + 1 < num_subwindows) + { + bool handled = false; + m_prev_active_window_idx = m_curr_active_window_idx; + for (size_t idx=m_curr_active_window_idx + 1; idx<num_subwindows; ++idx) + { + if (m_subwindows[idx]->GetCanBeActive()) + { + m_curr_active_window_idx = idx; + handled = true; + break; + } + } + if (!handled) + { + for (size_t idx=0; idx<=m_prev_active_window_idx; ++idx) + { + if (m_subwindows[idx]->GetCanBeActive()) + { + m_curr_active_window_idx = idx; + break; + } + } + } + } + else + { + m_prev_active_window_idx = m_curr_active_window_idx; + for (size_t idx=0; idx<num_subwindows; ++idx) + { + if (m_subwindows[idx]->GetCanBeActive()) + { + m_curr_active_window_idx = idx; + break; + } + } + } + } + + const char * + GetName () const + { + return m_name.c_str(); + } + protected: + std::string m_name; + WINDOW *m_window; + PANEL *m_panel; + Window *m_parent; + Windows m_subwindows; + WindowDelegateSP m_delegate_sp; + uint32_t m_curr_active_window_idx; + uint32_t m_prev_active_window_idx; + bool m_delete; + bool m_needs_update; + bool m_can_activate; + bool m_is_subwin; + + private: + DISALLOW_COPY_AND_ASSIGN(Window); + }; + + class MenuDelegate + { + public: + virtual ~MenuDelegate() {} + + virtual MenuActionResult + MenuDelegateAction (Menu &menu) = 0; + }; + + class Menu : public WindowDelegate + { + public: + enum class Type + { + Invalid, + Bar, + Item, + Separator + }; + + // Menubar or separator constructor + Menu (Type type); + + // Menuitem constructor + Menu (const char *name, + const char *key_name, + int key_value, + uint64_t identifier); + + virtual ~ + Menu () + { + } + + const MenuDelegateSP & + GetDelegate () const + { + return m_delegate_sp; + } + + void + SetDelegate (const MenuDelegateSP &delegate_sp) + { + m_delegate_sp = delegate_sp; + } + + void + RecalculateNameLengths(); + + void + AddSubmenu (const MenuSP &menu_sp); + + int + DrawAndRunMenu (Window &window); + + void + DrawMenuTitle (Window &window, bool highlight); + + virtual bool + WindowDelegateDraw (Window &window, bool force); + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int key); + + MenuActionResult + ActionPrivate (Menu &menu) + { + MenuActionResult result = MenuActionResult::NotHandled; + if (m_delegate_sp) + { + result = m_delegate_sp->MenuDelegateAction (menu); + if (result != MenuActionResult::NotHandled) + return result; + } + else if (m_parent) + { + result = m_parent->ActionPrivate(menu); + if (result != MenuActionResult::NotHandled) + return result; + } + return m_canned_result; + } + + MenuActionResult + Action () + { + // Call the recursive action so it can try to handle it + // with the menu delegate, and if not, try our parent menu + return ActionPrivate (*this); + } + + void + SetCannedResult (MenuActionResult result) + { + m_canned_result = result; + } + + Menus & + GetSubmenus() + { + return m_submenus; + } + + const Menus & + GetSubmenus() const + { + return m_submenus; + } + + int + GetSelectedSubmenuIndex () const + { + return m_selected; + } + + void + SetSelectedSubmenuIndex (int idx) + { + m_selected = idx; + } + + Type + GetType () const + { + return m_type; + } + + int + GetStartingColumn() const + { + return m_start_col; + } + + void + SetStartingColumn(int col) + { + m_start_col = col; + } + + int + GetKeyValue() const + { + return m_key_value; + } + + void + SetKeyValue(int key_value) + { + m_key_value = key_value; + } + + std::string & + GetName() + { + return m_name; + } + + std::string & + GetKeyName() + { + return m_key_name; + } + + int + GetDrawWidth () const + { + return m_max_submenu_name_length + m_max_submenu_key_name_length + 8; + } + + + uint64_t + GetIdentifier() const + { + return m_identifier; + } + + void + SetIdentifier (uint64_t identifier) + { + m_identifier = identifier; + } + + protected: + std::string m_name; + std::string m_key_name; + uint64_t m_identifier; + Type m_type; + int m_key_value; + int m_start_col; + int m_max_submenu_name_length; + int m_max_submenu_key_name_length; + int m_selected; + Menu *m_parent; + Menus m_submenus; + WindowSP m_menu_window_sp; + MenuActionResult m_canned_result; + MenuDelegateSP m_delegate_sp; + }; + + // Menubar or separator constructor + Menu::Menu (Type type) : + m_name (), + m_key_name (), + m_identifier (0), + m_type (type), + m_key_value (0), + m_start_col (0), + m_max_submenu_name_length (0), + m_max_submenu_key_name_length (0), + m_selected (0), + m_parent (NULL), + m_submenus (), + m_canned_result (MenuActionResult::NotHandled), + m_delegate_sp() + { + } + + // Menuitem constructor + Menu::Menu (const char *name, + const char *key_name, + int key_value, + uint64_t identifier) : + m_name (), + m_key_name (), + m_identifier (identifier), + m_type (Type::Invalid), + m_key_value (key_value), + m_start_col (0), + m_max_submenu_name_length (0), + m_max_submenu_key_name_length (0), + m_selected (0), + m_parent (NULL), + m_submenus (), + m_canned_result (MenuActionResult::NotHandled), + m_delegate_sp() + { + if (name && name[0]) + { + m_name = name; + m_type = Type::Item; + if (key_name && key_name[0]) + m_key_name = key_name; + } + else + { + m_type = Type::Separator; + } + } + + void + Menu::RecalculateNameLengths() + { + m_max_submenu_name_length = 0; + m_max_submenu_key_name_length = 0; + Menus &submenus = GetSubmenus(); + const size_t num_submenus = submenus.size(); + for (size_t i=0; i<num_submenus; ++i) + { + Menu *submenu = submenus[i].get(); + if (m_max_submenu_name_length < submenu->m_name.size()) + m_max_submenu_name_length = submenu->m_name.size(); + if (m_max_submenu_key_name_length < submenu->m_key_name.size()) + m_max_submenu_key_name_length = submenu->m_key_name.size(); + } + } + + void + Menu::AddSubmenu (const MenuSP &menu_sp) + { + menu_sp->m_parent = this; + if (m_max_submenu_name_length < menu_sp->m_name.size()) + m_max_submenu_name_length = menu_sp->m_name.size(); + if (m_max_submenu_key_name_length < menu_sp->m_key_name.size()) + m_max_submenu_key_name_length = menu_sp->m_key_name.size(); + m_submenus.push_back(menu_sp); + } + + void + Menu::DrawMenuTitle (Window &window, bool highlight) + { + if (m_type == Type::Separator) + { + window.MoveCursor(0, window.GetCursorY()); + window.PutChar(ACS_LTEE); + int width = window.GetWidth(); + if (width > 2) + { + width -= 2; + for (size_t i=0; i< width; ++i) + window.PutChar(ACS_HLINE); + } + window.PutChar(ACS_RTEE); + } + else + { + const int shortcut_key = m_key_value; + bool underlined_shortcut = false; + const attr_t hilgight_attr = A_REVERSE; + if (highlight) + window.AttributeOn(hilgight_attr); + if (isprint(shortcut_key)) + { + size_t lower_pos = m_name.find(tolower(shortcut_key)); + size_t upper_pos = m_name.find(toupper(shortcut_key)); + const char *name = m_name.c_str(); + size_t pos = std::min<size_t>(lower_pos, upper_pos); + if (pos != std::string::npos) + { + underlined_shortcut = true; + if (pos > 0) + { + window.PutCString(name, pos); + name += pos; + } + const attr_t shortcut_attr = A_UNDERLINE|A_BOLD; + window.AttributeOn (shortcut_attr); + window.PutChar(name[0]); + window.AttributeOff(shortcut_attr); + name++; + if (name[0]) + window.PutCString(name); + } + } + + if (!underlined_shortcut) + { + window.PutCString(m_name.c_str()); + } + + if (highlight) + window.AttributeOff(hilgight_attr); + + if (m_key_name.empty()) + { + if (!underlined_shortcut && isprint(m_key_value)) + { + window.AttributeOn (COLOR_PAIR(3)); + window.Printf (" (%c)", m_key_value); + window.AttributeOff (COLOR_PAIR(3)); + } + } + else + { + window.AttributeOn (COLOR_PAIR(3)); + window.Printf (" (%s)", m_key_name.c_str()); + window.AttributeOff (COLOR_PAIR(3)); + } + } + } + + bool + Menu::WindowDelegateDraw (Window &window, bool force) + { + Menus &submenus = GetSubmenus(); + const size_t num_submenus = submenus.size(); + const int selected_idx = GetSelectedSubmenuIndex(); + Menu::Type menu_type = GetType (); + switch (menu_type) + { + case Menu::Type::Bar: + { + window.SetBackground(2); + window.MoveCursor(0, 0); + for (size_t i=0; i<num_submenus; ++i) + { + Menu *menu = submenus[i].get(); + if (i > 0) + window.PutChar(' '); + menu->SetStartingColumn (window.GetCursorX()); + window.PutCString("| "); + menu->DrawMenuTitle (window, false); + } + window.PutCString(" |"); + window.DeferredRefresh(); + } + break; + + case Menu::Type::Item: + { + int y = 1; + int x = 3; + // Draw the menu + int cursor_x = 0; + int cursor_y = 0; + window.Erase(); + window.SetBackground(2); + window.Box(); + for (size_t i=0; i<num_submenus; ++i) + { + const bool is_selected = i == selected_idx; + window.MoveCursor(x, y + i); + if (is_selected) + { + // Remember where we want the cursor to be + cursor_x = x-1; + cursor_y = y+i; + } + submenus[i]->DrawMenuTitle (window, is_selected); + } + window.MoveCursor(cursor_x, cursor_y); + window.DeferredRefresh(); + } + break; + + default: + case Menu::Type::Separator: + break; + } + return true; // Drawing handled... + } + + HandleCharResult + Menu::WindowDelegateHandleChar (Window &window, int key) + { + HandleCharResult result = eKeyNotHandled; + + Menus &submenus = GetSubmenus(); + const size_t num_submenus = submenus.size(); + const int selected_idx = GetSelectedSubmenuIndex(); + Menu::Type menu_type = GetType (); + if (menu_type == Menu::Type::Bar) + { + MenuSP run_menu_sp; + switch (key) + { + case KEY_DOWN: + case KEY_UP: + // Show last menu or first menu + if (selected_idx < num_submenus) + run_menu_sp = submenus[selected_idx]; + else if (!submenus.empty()) + run_menu_sp = submenus.front(); + result = eKeyHandled; + break; + + case KEY_RIGHT: + { + ++m_selected; + if (m_selected >= num_submenus) + m_selected = 0; + if (m_selected < num_submenus) + run_menu_sp = submenus[m_selected]; + else if (!submenus.empty()) + run_menu_sp = submenus.front(); + result = eKeyHandled; + } + break; + + case KEY_LEFT: + { + --m_selected; + if (m_selected < 0) + m_selected = num_submenus - 1; + if (m_selected < num_submenus) + run_menu_sp = submenus[m_selected]; + else if (!submenus.empty()) + run_menu_sp = submenus.front(); + result = eKeyHandled; + } + break; + + default: + for (size_t i=0; i<num_submenus; ++i) + { + if (submenus[i]->GetKeyValue() == key) + { + SetSelectedSubmenuIndex(i); + run_menu_sp = submenus[i]; + result = eKeyHandled; + break; + } + } + break; + } + + if (run_menu_sp) + { + // Run the action on this menu in case we need to populate the + // menu with dynamic content and also in case check marks, and + // any other menu decorations need to be caclulated + if (run_menu_sp->Action() == MenuActionResult::Quit) + return eQuitApplication; + + Rect menu_bounds; + menu_bounds.origin.x = run_menu_sp->GetStartingColumn(); + menu_bounds.origin.y = 1; + menu_bounds.size.width = run_menu_sp->GetDrawWidth(); + menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2; + if (m_menu_window_sp) + window.GetParent()->RemoveSubWindow(m_menu_window_sp.get()); + + m_menu_window_sp = window.GetParent()->CreateSubWindow (run_menu_sp->GetName().c_str(), + menu_bounds, + true); + m_menu_window_sp->SetDelegate (run_menu_sp); + } + } + else if (menu_type == Menu::Type::Item) + { + switch (key) + { + case KEY_DOWN: + if (m_submenus.size() > 1) + { + const int start_select = m_selected; + while (++m_selected != start_select) + { + if (m_selected >= num_submenus) + m_selected = 0; + if (m_submenus[m_selected]->GetType() == Type::Separator) + continue; + else + break; + } + return eKeyHandled; + } + break; + + case KEY_UP: + if (m_submenus.size() > 1) + { + const int start_select = m_selected; + while (--m_selected != start_select) + { + if (m_selected < 0) + m_selected = num_submenus - 1; + if (m_submenus[m_selected]->GetType() == Type::Separator) + continue; + else + break; + } + return eKeyHandled; + } + break; + + case KEY_RETURN: + if (selected_idx < num_submenus) + { + if (submenus[selected_idx]->Action() == MenuActionResult::Quit) + return eQuitApplication; + window.GetParent()->RemoveSubWindow(&window); + return eKeyHandled; + } + break; + + case KEY_ESCAPE: // Beware: pressing escape key has 1 to 2 second delay in case other chars are entered for escaped sequences + window.GetParent()->RemoveSubWindow(&window); + return eKeyHandled; + + default: + { + bool handled = false; + for (size_t i=0; i<num_submenus; ++i) + { + Menu *menu = submenus[i].get(); + if (menu->GetKeyValue() == key) + { + handled = true; + SetSelectedSubmenuIndex(i); + window.GetParent()->RemoveSubWindow(&window); + if (menu->Action() == MenuActionResult::Quit) + return eQuitApplication; + return eKeyHandled; + } + } + } + break; + + } + } + else if (menu_type == Menu::Type::Separator) + { + + } + return result; + } + + + class Application + { + public: + Application (FILE *in, FILE *out) : + m_window_sp(), + m_screen (NULL), + m_in (in), + m_out (out) + { + + } + + ~Application () + { + m_window_delegates.clear(); + m_window_sp.reset(); + if (m_screen) + { + ::delscreen(m_screen); + m_screen = NULL; + } + } + + void + Initialize () + { + ::setlocale(LC_ALL, ""); + ::setlocale(LC_CTYPE, ""); +#if 0 + ::initscr(); +#else + m_screen = ::newterm(NULL, m_out, m_in); +#endif + ::start_color(); + ::curs_set(0); + ::noecho(); + ::keypad(stdscr,TRUE); + } + + void + Terminate () + { + ::endwin(); + } + + void + Run (Debugger &debugger) + { + bool done = false; + int delay_in_tenths_of_a_second = 1; + + // Alas the threading model in curses is a bit lame so we need to + // resort to polling every 0.5 seconds. We could poll for stdin + // ourselves and then pass the keys down but then we need to + // translate all of the escape sequences ourselves. So we resort to + // polling for input because we need to receive async process events + // while in this loop. + + halfdelay(delay_in_tenths_of_a_second); // Poll using some number of tenths of seconds seconds when calling Window::GetChar() + + ListenerSP listener_sp (new Listener ("lldb.IOHandler.curses.Application")); + ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); + ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); + ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); + debugger.EnableForwardEvents (listener_sp); + + bool update = true; +#if defined(__APPLE__) + std::deque<int> escape_chars; +#endif + + while (!done) + { + if (update) + { + m_window_sp->Draw(false); + // All windows should be calling Window::DeferredRefresh() instead + // of Window::Refresh() so we can do a single update and avoid + // any screen blinking + update_panels(); + + // Cursor hiding isn't working on MacOSX, so hide it in the top left corner + m_window_sp->MoveCursor(0, 0); + + doupdate(); + update = false; + } + +#if defined(__APPLE__) + // Terminal.app doesn't map its function keys correctly, F1-F4 default to: + // \033OP, \033OQ, \033OR, \033OS, so lets take care of this here if possible + int ch; + if (escape_chars.empty()) + ch = m_window_sp->GetChar(); + else + { + ch = escape_chars.front(); + escape_chars.pop_front(); + } + if (ch == KEY_ESCAPE) + { + int ch2 = m_window_sp->GetChar(); + if (ch2 == 'O') + { + int ch3 = m_window_sp->GetChar(); + switch (ch3) + { + case 'P': ch = KEY_F(1); break; + case 'Q': ch = KEY_F(2); break; + case 'R': ch = KEY_F(3); break; + case 'S': ch = KEY_F(4); break; + default: + escape_chars.push_back(ch2); + if (ch3 != -1) + escape_chars.push_back(ch3); + break; + } + } + else if (ch2 != -1) + escape_chars.push_back(ch2); + } +#else + int ch = m_window_sp->GetChar(); + +#endif + if (ch == -1) + { + if (feof(m_in) || ferror(m_in)) + { + done = true; + } + else + { + // Just a timeout from using halfdelay(), check for events + EventSP event_sp; + while (listener_sp->PeekAtNextEvent()) + { + listener_sp->GetNextEvent(event_sp); + + if (event_sp) + { + Broadcaster *broadcaster = event_sp->GetBroadcaster(); + if (broadcaster) + { + //uint32_t event_type = event_sp->GetType(); + ConstString broadcaster_class (broadcaster->GetBroadcasterClass()); + if (broadcaster_class == broadcaster_class_process) + { + update = true; + continue; // Don't get any key, just update our view + } + } + } + } + } + } + else + { + HandleCharResult key_result = m_window_sp->HandleChar(ch); + switch (key_result) + { + case eKeyHandled: + update = true; + break; + case eKeyNotHandled: + break; + case eQuitApplication: + done = true; + break; + } + } + } + + debugger.CancelForwardEvents (listener_sp); + + } + + WindowSP & + GetMainWindow () + { + if (!m_window_sp) + m_window_sp.reset (new Window ("main", stdscr, false)); + return m_window_sp; + } + + WindowDelegates & + GetWindowDelegates () + { + return m_window_delegates; + } + + protected: + WindowSP m_window_sp; + WindowDelegates m_window_delegates; + SCREEN *m_screen; + FILE *m_in; + FILE *m_out; + }; + + +} // namespace curses + + +using namespace curses; + +struct Row +{ + ValueObjectSP valobj; + Row *parent; + int row_idx; + int x; + int y; + bool might_have_children; + bool expanded; + bool calculated_children; + std::vector<Row> children; + + Row (const ValueObjectSP &v, Row *p) : + valobj (v), + parent (p), + row_idx(0), + x(1), + y(1), + might_have_children (v ? v->MightHaveChildren() : false), + expanded (false), + calculated_children (false), + children() + { + } + + size_t + GetDepth () const + { + if (parent) + return 1 + parent->GetDepth(); + return 0; + } + + void + Expand() + { + expanded = true; + if (!calculated_children) + { + calculated_children = true; + if (valobj) + { + const size_t num_children = valobj->GetNumChildren(); + for (size_t i=0; i<num_children; ++i) + { + children.push_back(Row (valobj->GetChildAtIndex(i, true), this)); + } + } + } + } + + void + Unexpand () + { + expanded = false; + } + + void + DrawTree (Window &window) + { + if (parent) + parent->DrawTreeForChild (window, this, 0); + + if (might_have_children) + { + // It we can get UTF8 characters to work we should try to use the "symbol" + // UTF8 string below +// const char *symbol = ""; +// if (row.expanded) +// symbol = "\xe2\x96\xbd "; +// else +// symbol = "\xe2\x96\xb7 "; +// window.PutCString (symbol); + + // The ACS_DARROW and ACS_RARROW don't look very nice they are just a + // 'v' or '>' character... +// if (expanded) +// window.PutChar (ACS_DARROW); +// else +// window.PutChar (ACS_RARROW); + // Since we can't find any good looking right arrow/down arrow + // symbols, just use a diamond... + window.PutChar (ACS_DIAMOND); + window.PutChar (ACS_HLINE); + } + } + + void + DrawTreeForChild (Window &window, Row *child, uint32_t reverse_depth) + { + if (parent) + parent->DrawTreeForChild (window, this, reverse_depth + 1); + + if (&children.back() == child) + { + // Last child + if (reverse_depth == 0) + { + window.PutChar (ACS_LLCORNER); + window.PutChar (ACS_HLINE); + } + else + { + window.PutChar (' '); + window.PutChar (' '); + } + } + else + { + if (reverse_depth == 0) + { + window.PutChar (ACS_LTEE); + window.PutChar (ACS_HLINE); + } + else + { + window.PutChar (ACS_VLINE); + window.PutChar (' '); + } + } + } +}; + +struct DisplayOptions +{ + bool show_types; +}; + +class TreeItem; + +class TreeDelegate +{ +public: + TreeDelegate() {} + virtual ~TreeDelegate() {} + virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) = 0; + virtual void TreeDelegateGenerateChildren (TreeItem &item) = 0; + virtual bool TreeDelegateItemSelected (TreeItem &item) = 0; // Return true if we need to update views +}; +typedef std::shared_ptr<TreeDelegate> TreeDelegateSP; + +class TreeItem +{ +public: + + TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) : + m_parent (parent), + m_delegate (delegate), + m_identifier (0), + m_row_idx (-1), + m_children (), + m_might_have_children (might_have_children), + m_is_expanded (false) + { + } + + TreeItem & + operator=(const TreeItem &rhs) + { + if (this != &rhs) + { + m_parent = rhs.m_parent; + m_delegate = rhs.m_delegate; + m_identifier = rhs.m_identifier; + m_row_idx = rhs.m_row_idx; + m_children = rhs.m_children; + m_might_have_children = rhs.m_might_have_children; + m_is_expanded = rhs.m_is_expanded; + } + return *this; + } + + size_t + GetDepth () const + { + if (m_parent) + return 1 + m_parent->GetDepth(); + return 0; + } + + int + GetRowIndex () const + { + return m_row_idx; + } + + void + ClearChildren () + { + m_children.clear(); + } + + void + Resize (size_t n, const TreeItem &t) + { + m_children.resize(n, t); + } + + TreeItem & + operator [](size_t i) + { + return m_children[i]; + } + + void + SetRowIndex (int row_idx) + { + m_row_idx = row_idx; + } + + size_t + GetNumChildren () + { + m_delegate.TreeDelegateGenerateChildren (*this); + return m_children.size(); + } + + void + ItemWasSelected () + { + m_delegate.TreeDelegateItemSelected(*this); + } + void + CalculateRowIndexes (int &row_idx) + { + SetRowIndex(row_idx); + ++row_idx; + + // The root item must calculate its children + if (m_parent == NULL) + GetNumChildren(); + + const bool expanded = IsExpanded(); + for (auto &item : m_children) + { + if (expanded) + item.CalculateRowIndexes(row_idx); + else + item.SetRowIndex(-1); + } + } + + TreeItem * + GetParent () + { + return m_parent; + } + + bool + IsExpanded () const + { + return m_is_expanded; + } + + void + Expand() + { + m_is_expanded = true; + } + + void + Unexpand () + { + m_is_expanded = false; + } + + bool + Draw (Window &window, + const int first_visible_row, + const uint32_t selected_row_idx, + int &row_idx, + int &num_rows_left) + { + if (num_rows_left <= 0) + return false; + + if (m_row_idx >= first_visible_row) + { + window.MoveCursor(2, row_idx + 1); + + if (m_parent) + m_parent->DrawTreeForChild (window, this, 0); + + if (m_might_have_children) + { + // It we can get UTF8 characters to work we should try to use the "symbol" + // UTF8 string below + // const char *symbol = ""; + // if (row.expanded) + // symbol = "\xe2\x96\xbd "; + // else + // symbol = "\xe2\x96\xb7 "; + // window.PutCString (symbol); + + // The ACS_DARROW and ACS_RARROW don't look very nice they are just a + // 'v' or '>' character... + // if (expanded) + // window.PutChar (ACS_DARROW); + // else + // window.PutChar (ACS_RARROW); + // Since we can't find any good looking right arrow/down arrow + // symbols, just use a diamond... + window.PutChar (ACS_DIAMOND); + window.PutChar (ACS_HLINE); + } + bool highlight = (selected_row_idx == m_row_idx) && window.IsActive(); + + if (highlight) + window.AttributeOn(A_REVERSE); + + m_delegate.TreeDelegateDrawTreeItem(*this, window); + + if (highlight) + window.AttributeOff(A_REVERSE); + ++row_idx; + --num_rows_left; + } + + if (num_rows_left <= 0) + return false; // We are done drawing... + + if (IsExpanded()) + { + for (auto &item : m_children) + { + // If we displayed all the rows and item.Draw() returns + // false we are done drawing and can exit this for loop + if (item.Draw(window, first_visible_row, selected_row_idx, row_idx, num_rows_left) == false) + break; + } + } + return num_rows_left >= 0; // Return true if not done drawing yet + } + + void + DrawTreeForChild (Window &window, TreeItem *child, uint32_t reverse_depth) + { + if (m_parent) + m_parent->DrawTreeForChild (window, this, reverse_depth + 1); + + if (&m_children.back() == child) + { + // Last child + if (reverse_depth == 0) + { + window.PutChar (ACS_LLCORNER); + window.PutChar (ACS_HLINE); + } + else + { + window.PutChar (' '); + window.PutChar (' '); + } + } + else + { + if (reverse_depth == 0) + { + window.PutChar (ACS_LTEE); + window.PutChar (ACS_HLINE); + } + else + { + window.PutChar (ACS_VLINE); + window.PutChar (' '); + } + } + } + + TreeItem * + GetItemForRowIndex (uint32_t row_idx) + { + if (m_row_idx == row_idx) + return this; + if (m_children.empty()) + return NULL; + if (m_children.back().m_row_idx < row_idx) + return NULL; + if (IsExpanded()) + { + for (auto &item : m_children) + { + TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx); + if (selected_item_ptr) + return selected_item_ptr; + } + } + return NULL; + } + +// void * +// GetUserData() const +// { +// return m_user_data; +// } +// +// void +// SetUserData (void *user_data) +// { +// m_user_data = user_data; +// } + uint64_t + GetIdentifier() const + { + return m_identifier; + } + + void + SetIdentifier (uint64_t identifier) + { + m_identifier = identifier; + } + + +protected: + TreeItem *m_parent; + TreeDelegate &m_delegate; + //void *m_user_data; + uint64_t m_identifier; + int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item + std::vector<TreeItem> m_children; + bool m_might_have_children; + bool m_is_expanded; + +}; + +class TreeWindowDelegate : public WindowDelegate +{ +public: + TreeWindowDelegate (Debugger &debugger, const TreeDelegateSP &delegate_sp) : + m_debugger (debugger), + m_delegate_sp (delegate_sp), + m_root (NULL, *delegate_sp, true), + m_selected_item (NULL), + m_num_rows (0), + m_selected_row_idx (0), + m_first_visible_row (0), + m_min_x (0), + m_min_y (0), + m_max_x (0), + m_max_y (0) + { + } + + int + NumVisibleRows () const + { + return m_max_y - m_min_y; + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext()); + Process *process = exe_ctx.GetProcessPtr(); + + bool display_content = false; + if (process) + { + StateType state = process->GetState(); + if (StateIsStoppedState(state, true)) + { + // We are stopped, so it is ok to + display_content = true; + } + else if (StateIsRunningState(state)) + { + return true; // Don't do any updating when we are running + } + } + + m_min_x = 2; + m_min_y = 1; + m_max_x = window.GetWidth() - 1; + m_max_y = window.GetHeight() - 1; + + window.Erase(); + window.DrawTitleBox (window.GetName()); + + if (display_content) + { + const int num_visible_rows = NumVisibleRows(); + m_num_rows = 0; + m_root.CalculateRowIndexes(m_num_rows); + + // If we unexpanded while having something selected our + // total number of rows is less than the num visible rows, + // then make sure we show all the rows by setting the first + // visible row accordingly. + if (m_first_visible_row > 0 && m_num_rows < num_visible_rows) + m_first_visible_row = 0; + + // Make sure the selected row is always visible + if (m_selected_row_idx < m_first_visible_row) + m_first_visible_row = m_selected_row_idx; + else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx) + m_first_visible_row = m_selected_row_idx - num_visible_rows + 1; + + int row_idx = 0; + int num_rows_left = num_visible_rows; + m_root.Draw (window, m_first_visible_row, m_selected_row_idx, row_idx, num_rows_left); + // Get the selected row + m_selected_item = m_root.GetItemForRowIndex (m_selected_row_idx); + } + else + { + m_selected_item = NULL; + } + + window.DeferredRefresh(); + + + return true; // Drawing handled + } + + + virtual const char * + WindowDelegateGetHelpText () + { + return "Thread window keyboard shortcuts:"; + } + + virtual KeyHelp * + WindowDelegateGetKeyHelp () + { + static curses::KeyHelp g_source_view_key_help[] = { + { KEY_UP, "Select previous item" }, + { KEY_DOWN, "Select next item" }, + { KEY_RIGHT, "Expand the selected item" }, + { KEY_LEFT, "Unexpand the selected item or select parent if not expanded" }, + { KEY_PPAGE, "Page up" }, + { KEY_NPAGE, "Page down" }, + { 'h', "Show help dialog" }, + { ' ', "Toggle item expansion" }, + { ',', "Page up" }, + { '.', "Page down" }, + { '\0', NULL } + }; + return g_source_view_key_help; + } + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int c) + { + switch(c) + { + case ',': + case KEY_PPAGE: + // Page up key + if (m_first_visible_row > 0) + { + if (m_first_visible_row > m_max_y) + m_first_visible_row -= m_max_y; + else + m_first_visible_row = 0; + m_selected_row_idx = m_first_visible_row; + m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx); + if (m_selected_item) + m_selected_item->ItemWasSelected (); + } + return eKeyHandled; + + case '.': + case KEY_NPAGE: + // Page down key + if (m_num_rows > m_max_y) + { + if (m_first_visible_row + m_max_y < m_num_rows) + { + m_first_visible_row += m_max_y; + m_selected_row_idx = m_first_visible_row; + m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx); + if (m_selected_item) + m_selected_item->ItemWasSelected (); + } + } + return eKeyHandled; + + case KEY_UP: + if (m_selected_row_idx > 0) + { + --m_selected_row_idx; + m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx); + if (m_selected_item) + m_selected_item->ItemWasSelected (); + } + return eKeyHandled; + case KEY_DOWN: + if (m_selected_row_idx + 1 < m_num_rows) + { + ++m_selected_row_idx; + m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx); + if (m_selected_item) + m_selected_item->ItemWasSelected (); + } + return eKeyHandled; + + case KEY_RIGHT: + if (m_selected_item) + { + if (!m_selected_item->IsExpanded()) + m_selected_item->Expand(); + } + return eKeyHandled; + + case KEY_LEFT: + if (m_selected_item) + { + if (m_selected_item->IsExpanded()) + m_selected_item->Unexpand(); + else if (m_selected_item->GetParent()) + { + m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex(); + m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx); + if (m_selected_item) + m_selected_item->ItemWasSelected (); + } + } + return eKeyHandled; + + case ' ': + // Toggle expansion state when SPACE is pressed + if (m_selected_item) + { + if (m_selected_item->IsExpanded()) + m_selected_item->Unexpand(); + else + m_selected_item->Expand(); + } + return eKeyHandled; + + case 'h': + window.CreateHelpSubwindow (); + return eKeyHandled; + + default: + break; + } + return eKeyNotHandled; + } + +protected: + Debugger &m_debugger; + TreeDelegateSP m_delegate_sp; + TreeItem m_root; + TreeItem *m_selected_item; + int m_num_rows; + int m_selected_row_idx; + int m_first_visible_row; + int m_min_x; + int m_min_y; + int m_max_x; + int m_max_y; + +}; + +class FrameTreeDelegate : public TreeDelegate +{ +public: + FrameTreeDelegate (const ThreadSP &thread_sp) : + TreeDelegate(), + m_thread_wp() + { + if (thread_sp) + m_thread_wp = thread_sp; + } + + virtual ~FrameTreeDelegate() + { + } + + virtual void + TreeDelegateDrawTreeItem (TreeItem &item, Window &window) + { + ThreadSP thread_sp = m_thread_wp.lock(); + if (thread_sp) + { + const uint64_t frame_idx = item.GetIdentifier(); + StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx); + if (frame_sp) + { + 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)) + { + int right_pad = 1; + window.PutCStringTruncated(strm.GetString().c_str(), right_pad); + } + } + } + } + virtual void + TreeDelegateGenerateChildren (TreeItem &item) + { + // No children for frames yet... + } + + virtual bool + TreeDelegateItemSelected (TreeItem &item) + { + ThreadSP thread_sp = m_thread_wp.lock(); + if (thread_sp) + { + const uint64_t frame_idx = item.GetIdentifier(); + thread_sp->SetSelectedFrameByIndex(frame_idx); + return true; + } + return false; + } + void + SetThread (ThreadSP thread_sp) + { + m_thread_wp = thread_sp; + } + +protected: + ThreadWP m_thread_wp; +}; + +class ThreadTreeDelegate : public TreeDelegate +{ +public: + ThreadTreeDelegate (Debugger &debugger) : + TreeDelegate(), + m_debugger (debugger), + m_thread_wp (), + m_tid (LLDB_INVALID_THREAD_ID), + m_stop_id (UINT32_MAX) + { + } + + virtual + ~ThreadTreeDelegate() + { + } + + virtual void + TreeDelegateDrawTreeItem (TreeItem &item, Window &window) + { + ThreadSP thread_sp = m_thread_wp.lock(); + if (thread_sp) + { + 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)) + { + int right_pad = 1; + window.PutCStringTruncated(strm.GetString().c_str(), right_pad); + } + } + } + virtual void + TreeDelegateGenerateChildren (TreeItem &item) + { + TargetSP target_sp (m_debugger.GetSelectedTarget()); + if (target_sp) + { + ProcessSP process_sp = target_sp->GetProcessSP(); + if (process_sp && process_sp->IsAlive()) + { + StateType state = process_sp->GetState(); + if (StateIsStoppedState(state, true)) + { + ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); + if (thread_sp) + { + if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid) + return; // Children are already up to date + if (m_frame_delegate_sp) + m_frame_delegate_sp->SetThread(thread_sp); + else + { + // Always expand the thread item the first time we show it + item.Expand(); + m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp)); + } + + m_stop_id = process_sp->GetStopID(); + m_thread_wp = thread_sp; + m_tid = thread_sp->GetID(); + + TreeItem t (&item, *m_frame_delegate_sp, false); + size_t num_frames = thread_sp->GetStackFrameCount(); + item.Resize (num_frames, t); + for (size_t i=0; i<num_frames; ++i) + { + item[i].SetIdentifier(i); + } + } + return; + } + } + } + item.ClearChildren(); + } + + virtual bool + TreeDelegateItemSelected (TreeItem &item) + { + ThreadSP thread_sp = m_thread_wp.lock(); + if (thread_sp) + { + ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList(); + Mutex::Locker locker (thread_list.GetMutex()); + ThreadSP selected_thread_sp = thread_list.GetSelectedThread(); + if (selected_thread_sp->GetID() != thread_sp->GetID()) + { + thread_list.SetSelectedThreadByID(thread_sp->GetID()); + return true; + } + } + return false; + } + +protected: + Debugger &m_debugger; + ThreadWP m_thread_wp; + std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp; + lldb::user_id_t m_tid; + uint32_t m_stop_id; +}; + +class ValueObjectListDelegate : public WindowDelegate +{ +public: + ValueObjectListDelegate () : + m_valobj_list (), + m_rows (), + m_selected_row (NULL), + m_selected_row_idx (0), + m_first_visible_row (0), + m_num_rows (0), + m_max_x (0), + m_max_y (0) + { + } + + ValueObjectListDelegate (ValueObjectList &valobj_list) : + m_valobj_list (valobj_list), + m_rows (), + m_selected_row (NULL), + m_selected_row_idx (0), + m_first_visible_row (0), + m_num_rows (0), + m_max_x (0), + m_max_y (0) + { + SetValues (valobj_list); + } + + virtual + ~ValueObjectListDelegate() + { + } + + void + SetValues (ValueObjectList &valobj_list) + { + m_selected_row = NULL; + m_selected_row_idx = 0; + m_first_visible_row = 0; + m_num_rows = 0; + m_rows.clear(); + m_valobj_list = valobj_list; + const size_t num_values = m_valobj_list.GetSize(); + for (size_t i=0; i<num_values; ++i) + m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL)); + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + m_num_rows = 0; + m_min_x = 2; + m_min_y = 1; + m_max_x = window.GetWidth() - 1; + m_max_y = window.GetHeight() - 1; + + window.Erase(); + window.DrawTitleBox (window.GetName()); + + const int num_visible_rows = NumVisibleRows(); + const int num_rows = CalculateTotalNumberRows (m_rows); + + // If we unexpanded while having something selected our + // total number of rows is less than the num visible rows, + // then make sure we show all the rows by setting the first + // visible row accordingly. + if (m_first_visible_row > 0 && num_rows < num_visible_rows) + m_first_visible_row = 0; + + // Make sure the selected row is always visible + if (m_selected_row_idx < m_first_visible_row) + m_first_visible_row = m_selected_row_idx; + else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx) + m_first_visible_row = m_selected_row_idx - num_visible_rows + 1; + + DisplayRows (window, m_rows, g_options); + + window.DeferredRefresh(); + + // Get the selected row + m_selected_row = GetRowForRowIndex (m_selected_row_idx); + // Keep the cursor on the selected row so the highlight and the cursor + // are always on the same line + if (m_selected_row) + window.MoveCursor (m_selected_row->x, + m_selected_row->y); + + return true; // Drawing handled + } + + virtual KeyHelp * + WindowDelegateGetKeyHelp () + { + static curses::KeyHelp g_source_view_key_help[] = { + { KEY_UP, "Select previous item" }, + { KEY_DOWN, "Select next item" }, + { KEY_RIGHT, "Expand selected item" }, + { KEY_LEFT, "Unexpand selected item or select parent if not expanded" }, + { KEY_PPAGE, "Page up" }, + { KEY_NPAGE, "Page down" }, + { 'A', "Format as annotated address" }, + { 'b', "Format as binary" }, + { 'B', "Format as hex bytes with ASCII" }, + { 'c', "Format as character" }, + { 'd', "Format as a signed integer" }, + { 'D', "Format selected value using the default format for the type" }, + { 'f', "Format as float" }, + { 'h', "Show help dialog" }, + { 'i', "Format as instructions" }, + { 'o', "Format as octal" }, + { 'p', "Format as pointer" }, + { 's', "Format as C string" }, + { 't', "Toggle showing/hiding type names" }, + { 'u', "Format as an unsigned integer" }, + { 'x', "Format as hex" }, + { 'X', "Format as uppercase hex" }, + { ' ', "Toggle item expansion" }, + { ',', "Page up" }, + { '.', "Page down" }, + { '\0', NULL } + }; + return g_source_view_key_help; + } + + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int c) + { + switch(c) + { + case 'x': + case 'X': + case 'o': + case 's': + case 'u': + case 'd': + case 'D': + case 'i': + case 'A': + case 'p': + case 'c': + case 'b': + case 'B': + case 'f': + // Change the format for the currently selected item + if (m_selected_row) + m_selected_row->valobj->SetFormat (FormatForChar (c)); + return eKeyHandled; + + case 't': + // Toggle showing type names + g_options.show_types = !g_options.show_types; + return eKeyHandled; + + case ',': + case KEY_PPAGE: + // Page up key + if (m_first_visible_row > 0) + { + if (m_first_visible_row > m_max_y) + m_first_visible_row -= m_max_y; + else + m_first_visible_row = 0; + m_selected_row_idx = m_first_visible_row; + } + return eKeyHandled; + + case '.': + case KEY_NPAGE: + // Page down key + if (m_num_rows > m_max_y) + { + if (m_first_visible_row + m_max_y < m_num_rows) + { + m_first_visible_row += m_max_y; + m_selected_row_idx = m_first_visible_row; + } + } + return eKeyHandled; + + case KEY_UP: + if (m_selected_row_idx > 0) + --m_selected_row_idx; + return eKeyHandled; + case KEY_DOWN: + if (m_selected_row_idx + 1 < m_num_rows) + ++m_selected_row_idx; + return eKeyHandled; + + case KEY_RIGHT: + if (m_selected_row) + { + if (!m_selected_row->expanded) + m_selected_row->Expand(); + } + return eKeyHandled; + + case KEY_LEFT: + if (m_selected_row) + { + if (m_selected_row->expanded) + m_selected_row->Unexpand(); + else if (m_selected_row->parent) + m_selected_row_idx = m_selected_row->parent->row_idx; + } + return eKeyHandled; + + case ' ': + // Toggle expansion state when SPACE is pressed + if (m_selected_row) + { + if (m_selected_row->expanded) + m_selected_row->Unexpand(); + else + m_selected_row->Expand(); + } + return eKeyHandled; + + case 'h': + window.CreateHelpSubwindow (); + return eKeyHandled; + + default: + break; + } + return eKeyNotHandled; + } + +protected: + ValueObjectList m_valobj_list; + std::vector<Row> m_rows; + Row *m_selected_row; + uint32_t m_selected_row_idx; + uint32_t m_first_visible_row; + uint32_t m_num_rows; + int m_min_x; + int m_min_y; + int m_max_x; + int m_max_y; + + static Format + FormatForChar (int c) + { + switch (c) + { + case 'x': return eFormatHex; + case 'X': return eFormatHexUppercase; + case 'o': return eFormatOctal; + case 's': return eFormatCString; + case 'u': return eFormatUnsigned; + case 'd': return eFormatDecimal; + case 'D': return eFormatDefault; + case 'i': return eFormatInstruction; + case 'A': return eFormatAddressInfo; + case 'p': return eFormatPointer; + case 'c': return eFormatChar; + case 'b': return eFormatBinary; + case 'B': return eFormatBytesWithASCII; + case 'f': return eFormatFloat; + } + return eFormatDefault; + } + + bool + DisplayRowObject (Window &window, + Row &row, + DisplayOptions &options, + bool highlight, + bool last_child) + { + ValueObject *valobj = row.valobj.get(); + + if (valobj == NULL) + return false; + + const char *type_name = options.show_types ? valobj->GetTypeName().GetCString() : NULL; + const char *name = valobj->GetName().GetCString(); + const char *value = valobj->GetValueAsCString (); + const char *summary = valobj->GetSummaryAsCString (); + + window.MoveCursor (row.x, row.y); + + row.DrawTree (window); + + if (highlight) + window.AttributeOn(A_REVERSE); + + if (type_name && type_name[0]) + window.Printf ("(%s) ", type_name); + + if (name && name[0]) + window.PutCString(name); + + attr_t changd_attr = 0; + if (valobj->GetValueDidChange()) + changd_attr = COLOR_PAIR(5) | A_BOLD; + + if (value && value[0]) + { + window.PutCString(" = "); + if (changd_attr) + window.AttributeOn(changd_attr); + window.PutCString (value); + if (changd_attr) + window.AttributeOff(changd_attr); + } + + if (summary && summary[0]) + { + window.PutChar(' '); + if (changd_attr) + window.AttributeOn(changd_attr); + window.PutCString(summary); + if (changd_attr) + window.AttributeOff(changd_attr); + } + + if (highlight) + window.AttributeOff (A_REVERSE); + + return true; + } + void + DisplayRows (Window &window, + std::vector<Row> &rows, + DisplayOptions &options) + { + // > 0x25B7 + // \/ 0x25BD + + bool window_is_active = window.IsActive(); + for (auto &row : rows) + { + const bool last_child = row.parent && &rows[rows.size()-1] == &row; + // Save the row index in each Row structure + row.row_idx = m_num_rows; + if ((m_num_rows >= m_first_visible_row) && + ((m_num_rows - m_first_visible_row) < NumVisibleRows())) + { + row.x = m_min_x; + row.y = m_num_rows - m_first_visible_row + 1; + if (DisplayRowObject (window, + row, + options, + window_is_active && m_num_rows == m_selected_row_idx, + last_child)) + { + ++m_num_rows; + } + else + { + row.x = 0; + row.y = 0; + } + } + else + { + row.x = 0; + row.y = 0; + ++m_num_rows; + } + + if (row.expanded && !row.children.empty()) + { + DisplayRows (window, + row.children, + options); + } + } + } + + int + CalculateTotalNumberRows (const std::vector<Row> &rows) + { + int row_count = 0; + for (const auto &row : rows) + { + ++row_count; + if (row.expanded) + row_count += CalculateTotalNumberRows(row.children); + } + return row_count; + } + static Row * + GetRowForRowIndexImpl (std::vector<Row> &rows, size_t &row_index) + { + for (auto &row : rows) + { + if (row_index == 0) + return &row; + else + { + --row_index; + if (row.expanded && !row.children.empty()) + { + Row *result = GetRowForRowIndexImpl (row.children, row_index); + if (result) + return result; + } + } + } + return NULL; + } + + Row * + GetRowForRowIndex (size_t row_index) + { + return GetRowForRowIndexImpl (m_rows, row_index); + } + + int + NumVisibleRows () const + { + return m_max_y - m_min_y; + } + + static DisplayOptions g_options; +}; + +class FrameVariablesWindowDelegate : public ValueObjectListDelegate +{ +public: + FrameVariablesWindowDelegate (Debugger &debugger) : + ValueObjectListDelegate (), + m_debugger (debugger), + m_frame_block (NULL) + { + } + + virtual + ~FrameVariablesWindowDelegate() + { + } + + virtual const char * + WindowDelegateGetHelpText () + { + return "Frame variable window keyboard shortcuts:"; + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext()); + Process *process = exe_ctx.GetProcessPtr(); + Block *frame_block = NULL; + StackFrame *frame = NULL; + + if (process) + { + StateType state = process->GetState(); + if (StateIsStoppedState(state, true)) + { + frame = exe_ctx.GetFramePtr(); + if (frame) + frame_block = frame->GetFrameBlock (); + } + else if (StateIsRunningState(state)) + { + return true; // Don't do any updating when we are running + } + } + + ValueObjectList local_values; + if (frame_block) + { + // Only update the variables if they have changed + if (m_frame_block != frame_block) + { + m_frame_block = frame_block; + + VariableList *locals = frame->GetVariableList(true); + if (locals) + { + const DynamicValueType use_dynamic = eDynamicDontRunTarget; + const size_t num_locals = locals->GetSize(); + for (size_t i=0; i<num_locals; ++i) + local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic)); + // Update the values + SetValues(local_values); + } + } + } + else + { + m_frame_block = NULL; + // Update the values with an empty list if there is no frame + SetValues(local_values); + } + + return ValueObjectListDelegate::WindowDelegateDraw (window, force); + + } + +protected: + Debugger &m_debugger; + Block *m_frame_block; +}; + + +class RegistersWindowDelegate : public ValueObjectListDelegate +{ +public: + RegistersWindowDelegate (Debugger &debugger) : + ValueObjectListDelegate (), + m_debugger (debugger) + { + } + + virtual + ~RegistersWindowDelegate() + { + } + + virtual const char * + WindowDelegateGetHelpText () + { + return "Register window keyboard shortcuts:"; + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext()); + StackFrame *frame = exe_ctx.GetFramePtr(); + + ValueObjectList value_list; + if (frame) + { + if (frame->GetStackID() != m_stack_id) + { + m_stack_id = frame->GetStackID(); + RegisterContextSP reg_ctx (frame->GetRegisterContext()); + if (reg_ctx) + { + const uint32_t num_sets = reg_ctx->GetRegisterSetCount(); + for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx) + { + value_list.Append(ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx)); + } + } + SetValues(value_list); + } + } + else + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) + return true; // Don't do any updating if we are running + else + { + // Update the values with an empty list if there + // is no process or the process isn't alive anymore + SetValues(value_list); + } + } + return ValueObjectListDelegate::WindowDelegateDraw (window, force); + } + +protected: + Debugger &m_debugger; + StackID m_stack_id; +}; + +static const char * +CursesKeyToCString (int ch) +{ + static char g_desc[32]; + if (ch >= KEY_F0 && ch < KEY_F0 + 64) + { + snprintf(g_desc, sizeof(g_desc), "F%u", ch - KEY_F0); + return g_desc; + } + switch (ch) + { + case KEY_DOWN: return "down"; + case KEY_UP: return "up"; + case KEY_LEFT: return "left"; + case KEY_RIGHT: return "right"; + case KEY_HOME: return "home"; + case KEY_BACKSPACE: return "backspace"; + case KEY_DL: return "delete-line"; + case KEY_IL: return "insert-line"; + case KEY_DC: return "delete-char"; + case KEY_IC: return "insert-char"; + case KEY_CLEAR: return "clear"; + case KEY_EOS: return "clear-to-eos"; + case KEY_EOL: return "clear-to-eol"; + case KEY_SF: return "scroll-forward"; + case KEY_SR: return "scroll-backward"; + case KEY_NPAGE: return "page-down"; + case KEY_PPAGE: return "page-up"; + case KEY_STAB: return "set-tab"; + case KEY_CTAB: return "clear-tab"; + case KEY_CATAB: return "clear-all-tabs"; + case KEY_ENTER: return "enter"; + case KEY_PRINT: return "print"; + case KEY_LL: return "lower-left key"; + case KEY_A1: return "upper left of keypad"; + case KEY_A3: return "upper right of keypad"; + case KEY_B2: return "center of keypad"; + case KEY_C1: return "lower left of keypad"; + case KEY_C3: return "lower right of keypad"; + case KEY_BTAB: return "back-tab key"; + case KEY_BEG: return "begin key"; + case KEY_CANCEL: return "cancel key"; + case KEY_CLOSE: return "close key"; + case KEY_COMMAND: return "command key"; + case KEY_COPY: return "copy key"; + case KEY_CREATE: return "create key"; + case KEY_END: return "end key"; + case KEY_EXIT: return "exit key"; + case KEY_FIND: return "find key"; + case KEY_HELP: return "help key"; + case KEY_MARK: return "mark key"; + case KEY_MESSAGE: return "message key"; + case KEY_MOVE: return "move key"; + case KEY_NEXT: return "next key"; + case KEY_OPEN: return "open key"; + case KEY_OPTIONS: return "options key"; + case KEY_PREVIOUS: return "previous key"; + case KEY_REDO: return "redo key"; + case KEY_REFERENCE: return "reference key"; + case KEY_REFRESH: return "refresh key"; + case KEY_REPLACE: return "replace key"; + case KEY_RESTART: return "restart key"; + case KEY_RESUME: return "resume key"; + case KEY_SAVE: return "save key"; + case KEY_SBEG: return "shifted begin key"; + case KEY_SCANCEL: return "shifted cancel key"; + case KEY_SCOMMAND: return "shifted command key"; + case KEY_SCOPY: return "shifted copy key"; + case KEY_SCREATE: return "shifted create key"; + case KEY_SDC: return "shifted delete-character key"; + case KEY_SDL: return "shifted delete-line key"; + case KEY_SELECT: return "select key"; + case KEY_SEND: return "shifted end key"; + case KEY_SEOL: return "shifted clear-to-end-of-line key"; + case KEY_SEXIT: return "shifted exit key"; + case KEY_SFIND: return "shifted find key"; + case KEY_SHELP: return "shifted help key"; + case KEY_SHOME: return "shifted home key"; + case KEY_SIC: return "shifted insert-character key"; + case KEY_SLEFT: return "shifted left-arrow key"; + case KEY_SMESSAGE: return "shifted message key"; + case KEY_SMOVE: return "shifted move key"; + case KEY_SNEXT: return "shifted next key"; + case KEY_SOPTIONS: return "shifted options key"; + case KEY_SPREVIOUS: return "shifted previous key"; + case KEY_SPRINT: return "shifted print key"; + case KEY_SREDO: return "shifted redo key"; + case KEY_SREPLACE: return "shifted replace key"; + case KEY_SRIGHT: return "shifted right-arrow key"; + case KEY_SRSUME: return "shifted resume key"; + case KEY_SSAVE: return "shifted save key"; + case KEY_SSUSPEND: return "shifted suspend key"; + case KEY_SUNDO: return "shifted undo key"; + case KEY_SUSPEND: return "suspend key"; + case KEY_UNDO: return "undo key"; + case KEY_MOUSE: return "Mouse event has occurred"; + case KEY_RESIZE: return "Terminal resize event"; + case KEY_EVENT: return "We were interrupted by an event"; + case KEY_RETURN: return "return"; + case ' ': return "space"; + case '\t': return "tab"; + case KEY_ESCAPE: return "escape"; + default: + if (isprint(ch)) + snprintf(g_desc, sizeof(g_desc), "%c", ch); + else + snprintf(g_desc, sizeof(g_desc), "\\x%2.2x", ch); + return g_desc; + } + return NULL; +} + +HelpDialogDelegate::HelpDialogDelegate (const char *text, KeyHelp *key_help_array) : + m_text (), + m_first_visible_line (0) +{ + if (text && text[0]) + { + m_text.SplitIntoLines(text); + m_text.AppendString(""); + } + if (key_help_array) + { + for (KeyHelp *key = key_help_array; key->ch; ++key) + { + StreamString key_description; + key_description.Printf("%10s - %s", CursesKeyToCString(key->ch), key->description); + m_text.AppendString(std::move(key_description.GetString())); + } + } +} + +HelpDialogDelegate::~HelpDialogDelegate() +{ +} + +bool +HelpDialogDelegate::WindowDelegateDraw (Window &window, bool force) +{ + window.Erase(); + const int window_height = window.GetHeight(); + int x = 2; + int y = 1; + const int min_y = y; + const int max_y = window_height - 1 - y; + const int num_visible_lines = max_y - min_y + 1; + const size_t num_lines = m_text.GetSize(); + const char *bottom_message; + if (num_lines <= num_visible_lines) + bottom_message = "Press any key to exit"; + else + bottom_message = "Use arrows to scroll, any other key to exit"; + window.DrawTitleBox(window.GetName(), bottom_message); + while (y <= max_y) + { + window.MoveCursor(x, y); + window.PutCStringTruncated(m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1); + ++y; + } + return true; +} + +HandleCharResult +HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key) +{ + bool done = false; + const size_t num_lines = m_text.GetSize(); + const size_t num_visible_lines = window.GetHeight() - 2; + + if (num_lines <= num_visible_lines) + { + done = true; + // If we have all lines visible and don't need scrolling, then any + // key press will cause us to exit + } + else + { + switch (key) + { + case KEY_UP: + if (m_first_visible_line > 0) + --m_first_visible_line; + break; + + case KEY_DOWN: + if (m_first_visible_line + num_visible_lines < num_lines) + ++m_first_visible_line; + break; + + case KEY_PPAGE: + case ',': + if (m_first_visible_line > 0) + { + if (m_first_visible_line >= num_visible_lines) + m_first_visible_line -= num_visible_lines; + else + m_first_visible_line = 0; + } + break; + case KEY_NPAGE: + case '.': + if (m_first_visible_line + num_visible_lines < num_lines) + { + m_first_visible_line += num_visible_lines; + if (m_first_visible_line > num_lines) + m_first_visible_line = num_lines - num_visible_lines; + } + break; + default: + done = true; + break; + } + } + if (done) + window.GetParent()->RemoveSubWindow(&window); + return eKeyHandled; +} + +class ApplicationDelegate : + public WindowDelegate, + public MenuDelegate +{ +public: + enum { + eMenuID_LLDB = 1, + eMenuID_LLDBAbout, + eMenuID_LLDBExit, + + eMenuID_Target, + eMenuID_TargetCreate, + eMenuID_TargetDelete, + + eMenuID_Process, + eMenuID_ProcessAttach, + eMenuID_ProcessDetach, + eMenuID_ProcessLaunch, + eMenuID_ProcessContinue, + eMenuID_ProcessHalt, + eMenuID_ProcessKill, + + eMenuID_Thread, + eMenuID_ThreadStepIn, + eMenuID_ThreadStepOver, + eMenuID_ThreadStepOut, + + eMenuID_View, + eMenuID_ViewBacktrace, + eMenuID_ViewRegisters, + eMenuID_ViewSource, + eMenuID_ViewVariables, + + eMenuID_Help, + eMenuID_HelpGUIHelp + }; + + ApplicationDelegate (Application &app, Debugger &debugger) : + WindowDelegate (), + MenuDelegate (), + m_app (app), + m_debugger (debugger) + { + } + + virtual + ~ApplicationDelegate () + { + } + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + return false; // Drawing not handled, let standard window drawing happen + } + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int key) + { + switch (key) + { + case '\t': + window.SelectNextWindowAsActive(); + return eKeyHandled; + + case 'h': + window.CreateHelpSubwindow(); + return eKeyHandled; + + case KEY_ESCAPE: + return eQuitApplication; + + default: + break; + } + return eKeyNotHandled; + } + + + virtual const char * + WindowDelegateGetHelpText () + { + return "Welcome to the LLDB curses GUI.\n\n" + "Press the TAB key to change the selected view.\n" + "Each view has its own keyboard shortcuts, press 'h' to open a dialog to display them.\n\n" + "Common key bindings for all views:"; + } + + virtual KeyHelp * + WindowDelegateGetKeyHelp () + { + static curses::KeyHelp g_source_view_key_help[] = { + { '\t', "Select next view" }, + { 'h', "Show help dialog with view specific key bindings" }, + { ',', "Page up" }, + { '.', "Page down" }, + { KEY_UP, "Select previous" }, + { KEY_DOWN, "Select next" }, + { KEY_LEFT, "Unexpand or select parent" }, + { KEY_RIGHT, "Expand" }, + { KEY_PPAGE, "Page up" }, + { KEY_NPAGE, "Page down" }, + { '\0', NULL } + }; + return g_source_view_key_help; + } + + virtual MenuActionResult + MenuDelegateAction (Menu &menu) + { + switch (menu.GetIdentifier()) + { + case eMenuID_ThreadStepIn: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) + exe_ctx.GetThreadRef().StepIn(true, true); + } + } + return MenuActionResult::Handled; + + case eMenuID_ThreadStepOut: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) + exe_ctx.GetThreadRef().StepOut(); + } + } + return MenuActionResult::Handled; + + case eMenuID_ThreadStepOver: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) + exe_ctx.GetThreadRef().StepOver(true); + } + } + return MenuActionResult::Handled; + + case eMenuID_ProcessContinue: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) + process->Resume(); + } + } + return MenuActionResult::Handled; + + case eMenuID_ProcessKill: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) + process->Destroy(); + } + } + return MenuActionResult::Handled; + + case eMenuID_ProcessHalt: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) + process->Halt(); + } + } + return MenuActionResult::Handled; + + case eMenuID_ProcessDetach: + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + { + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) + process->Detach(false); + } + } + return MenuActionResult::Handled; + + case eMenuID_Process: + { + // Populate the menu with all of the threads if the process is stopped when + // the Process menu gets selected and is about to display its submenu. + Menus &submenus = menu.GetSubmenus(); + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + Process *process = exe_ctx.GetProcessPtr(); + if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true)) + { + if (submenus.size() == 7) + menu.AddSubmenu (MenuSP (new Menu(Menu::Type::Separator))); + else if (submenus.size() > 8) + submenus.erase (submenus.begin() + 8, submenus.end()); + + ThreadList &threads = process->GetThreadList(); + Mutex::Locker locker (threads.GetMutex()); + size_t num_threads = threads.GetSize(); + for (size_t i=0; i<num_threads; ++i) + { + ThreadSP thread_sp = threads.GetThreadAtIndex(i); + char menu_char = '\0'; + if (i < 9) + menu_char = '1' + i; + StreamString thread_menu_title; + thread_menu_title.Printf("Thread %u", thread_sp->GetIndexID()); + const char *thread_name = thread_sp->GetName(); + if (thread_name && thread_name[0]) + thread_menu_title.Printf (" %s", thread_name); + else + { + const char *queue_name = thread_sp->GetQueueName(); + if (queue_name && queue_name[0]) + thread_menu_title.Printf (" %s", queue_name); + } + menu.AddSubmenu (MenuSP (new Menu(thread_menu_title.GetString().c_str(), NULL, menu_char, thread_sp->GetID()))); + } + } + else if (submenus.size() > 7) + { + // Remove the separator and any other thread submenu items + // that were previously added + submenus.erase (submenus.begin() + 7, submenus.end()); + } + // Since we are adding and removing items we need to recalculate the name lengths + menu.RecalculateNameLengths(); + } + return MenuActionResult::Handled; + + case eMenuID_ViewVariables: + { + WindowSP main_window_sp = m_app.GetMainWindow(); + WindowSP source_window_sp = main_window_sp->FindSubWindow("Source"); + WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables"); + WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers"); + const Rect source_bounds = source_window_sp->GetBounds(); + + if (variables_window_sp) + { + const Rect variables_bounds = variables_window_sp->GetBounds(); + + main_window_sp->RemoveSubWindow(variables_window_sp.get()); + + if (registers_window_sp) + { + // We have a registers window, so give all the area back to the registers window + Rect registers_bounds = variables_bounds; + registers_bounds.size.width = source_bounds.size.width; + registers_window_sp->SetBounds(registers_bounds); + } + else + { + // We have no registers window showing so give the bottom + // area back to the source view + source_window_sp->Resize (source_bounds.size.width, + source_bounds.size.height + variables_bounds.size.height); + } + } + else + { + Rect new_variables_rect; + if (registers_window_sp) + { + // We have a registers window so split the area of the registers + // window into two columns where the left hand side will be the + // variables and the right hand side will be the registers + const Rect variables_bounds = registers_window_sp->GetBounds(); + Rect new_registers_rect; + variables_bounds.VerticalSplitPercentage (0.50, new_variables_rect, new_registers_rect); + registers_window_sp->SetBounds (new_registers_rect); + } + else + { + // No variables window, grab the bottom part of the source window + Rect new_source_rect; + source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_variables_rect); + source_window_sp->SetBounds (new_source_rect); + } + WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Variables", + new_variables_rect, + false); + new_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger))); + } + touchwin(stdscr); + } + return MenuActionResult::Handled; + + case eMenuID_ViewRegisters: + { + WindowSP main_window_sp = m_app.GetMainWindow(); + WindowSP source_window_sp = main_window_sp->FindSubWindow("Source"); + WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables"); + WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers"); + const Rect source_bounds = source_window_sp->GetBounds(); + + if (registers_window_sp) + { + if (variables_window_sp) + { + const Rect variables_bounds = variables_window_sp->GetBounds(); + + // We have a variables window, so give all the area back to the variables window + variables_window_sp->Resize (variables_bounds.size.width + registers_window_sp->GetWidth(), + variables_bounds.size.height); + } + else + { + // We have no variables window showing so give the bottom + // area back to the source view + source_window_sp->Resize (source_bounds.size.width, + source_bounds.size.height + registers_window_sp->GetHeight()); + } + main_window_sp->RemoveSubWindow(registers_window_sp.get()); + } + else + { + Rect new_regs_rect; + if (variables_window_sp) + { + // We have a variables window, split it into two columns + // where the left hand side will be the variables and the + // right hand side will be the registers + const Rect variables_bounds = variables_window_sp->GetBounds(); + Rect new_vars_rect; + variables_bounds.VerticalSplitPercentage (0.50, new_vars_rect, new_regs_rect); + variables_window_sp->SetBounds (new_vars_rect); + } + else + { + // No registers window, grab the bottom part of the source window + Rect new_source_rect; + source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_regs_rect); + source_window_sp->SetBounds (new_source_rect); + } + WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Registers", + new_regs_rect, + false); + new_window_sp->SetDelegate (WindowDelegateSP(new RegistersWindowDelegate(m_debugger))); + } + touchwin(stdscr); + } + return MenuActionResult::Handled; + + case eMenuID_HelpGUIHelp: + m_app.GetMainWindow ()->CreateHelpSubwindow(); + return MenuActionResult::Handled; + + default: + break; + } + + return MenuActionResult::NotHandled; + } +protected: + Application &m_app; + Debugger &m_debugger; +}; + + +class StatusBarWindowDelegate : public WindowDelegate +{ +public: + StatusBarWindowDelegate (Debugger &debugger) : + m_debugger (debugger) + { + } + + virtual + ~StatusBarWindowDelegate () + { + } + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = exe_ctx.GetThreadPtr(); + StackFrame *frame = exe_ctx.GetFramePtr(); + window.Erase(); + window.SetBackground(2); + window.MoveCursor (0, 0); + if (process) + { + const StateType state = process->GetState(); + window.Printf ("Process: %5" PRIu64 " %10s", process->GetID(), StateAsCString(state)); + + if (StateIsStoppedState(state, true)) + { + window.MoveCursor (40, 0); + if (thread) + window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID()); + + window.MoveCursor (60, 0); + if (frame) + window.Printf ("Frame: %3u PC = 0x%16.16" PRIx64, frame->GetFrameIndex(), frame->GetFrameCodeAddress().GetOpcodeLoadAddress (exe_ctx.GetTargetPtr())); + } + else if (state == eStateExited) + { + const char *exit_desc = process->GetExitDescription(); + const int exit_status = process->GetExitStatus(); + if (exit_desc && exit_desc[0]) + window.Printf (" with status = %i (%s)", exit_status, exit_desc); + else + window.Printf (" with status = %i", exit_status); + } + } + window.DeferredRefresh(); + return true; + } + +protected: + Debugger &m_debugger; +}; + +class SourceFileWindowDelegate : public WindowDelegate +{ +public: + SourceFileWindowDelegate (Debugger &debugger) : + WindowDelegate (), + m_debugger (debugger), + m_sc (), + m_file_sp (), + m_disassembly_scope (NULL), + m_disassembly_sp (), + m_disassembly_range (), + m_line_width (4), + m_selected_line (0), + m_pc_line (0), + m_stop_id (0), + m_frame_idx (UINT32_MAX), + m_first_visible_line (0), + m_min_x (0), + m_min_y (0), + m_max_x (0), + m_max_y (0) + { + } + + + virtual + ~SourceFileWindowDelegate() + { + } + + void + Update (const SymbolContext &sc) + { + m_sc = sc; + } + + uint32_t + NumVisibleLines () const + { + return m_max_y - m_min_y; + } + + virtual const char * + WindowDelegateGetHelpText () + { + return "Source/Disassembly window keyboard shortcuts:"; + } + + virtual KeyHelp * + WindowDelegateGetKeyHelp () + { + static curses::KeyHelp g_source_view_key_help[] = { + { KEY_RETURN, "Run to selected line with one shot breakpoint" }, + { KEY_UP, "Select previous source line" }, + { KEY_DOWN, "Select next source line" }, + { KEY_PPAGE, "Page up" }, + { KEY_NPAGE, "Page down" }, + { 'b', "Set breakpoint on selected source/disassembly line" }, + { 'c', "Continue process" }, + { 'd', "Detach and resume process" }, + { 'D', "Detach with process suspended" }, + { 'h', "Show help dialog" }, + { 'k', "Kill process" }, + { 'n', "Step over (source line)" }, + { 'N', "Step over (single instruction)" }, + { 'o', "Step out" }, + { 's', "Step in (source line)" }, + { 'S', "Step in (single instruction)" }, + { ',', "Page up" }, + { '.', "Page down" }, + { '\0', NULL } + }; + return g_source_view_key_help; + } + + virtual bool + WindowDelegateDraw (Window &window, bool force) + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + Process *process = exe_ctx.GetProcessPtr(); + Thread *thread = NULL; + + bool update_location = false; + if (process) + { + StateType state = process->GetState(); + if (StateIsStoppedState(state, true)) + { + // We are stopped, so it is ok to + update_location = true; + } + } + + m_min_x = 1; + m_min_y = 1; + m_max_x = window.GetMaxX()-1; + m_max_y = window.GetMaxY()-1; + + const uint32_t num_visible_lines = NumVisibleLines(); + StackFrameSP frame_sp; + bool set_selected_line_to_pc = false; + + + if (update_location) + { + + const bool process_alive = process ? process->IsAlive() : false; + bool thread_changed = false; + if (process_alive) + { + thread = exe_ctx.GetThreadPtr(); + if (thread) + { + frame_sp = thread->GetSelectedFrame(); + auto tid = thread->GetID(); + thread_changed = tid != m_tid; + m_tid = tid; + } + else + { + if (m_tid != LLDB_INVALID_THREAD_ID) + { + thread_changed = true; + m_tid = LLDB_INVALID_THREAD_ID; + } + } + } + const uint32_t stop_id = process ? process->GetStopID() : 0; + const bool stop_id_changed = stop_id != m_stop_id; + bool frame_changed = false; + m_stop_id = stop_id; + if (frame_sp) + { + m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + const uint32_t frame_idx = frame_sp->GetFrameIndex(); + frame_changed = frame_idx != m_frame_idx; + m_frame_idx = frame_idx; + } + else + { + m_sc.Clear(true); + frame_changed = m_frame_idx != UINT32_MAX; + m_frame_idx = UINT32_MAX; + } + + const bool context_changed = thread_changed || frame_changed || stop_id_changed; + + if (process_alive) + { + if (m_sc.line_entry.IsValid()) + { + m_pc_line = m_sc.line_entry.line; + if (m_pc_line != UINT32_MAX) + --m_pc_line; // Convert to zero based line number... + // Update the selected line if the stop ID changed... + if (context_changed) + m_selected_line = m_pc_line; + + if (m_file_sp && m_file_sp->FileSpecMatches(m_sc.line_entry.file)) + { + // Same file, nothing to do, we should either have the + // lines or not (source file missing) + if (m_selected_line >= m_first_visible_line) + { + if (m_selected_line >= m_first_visible_line + num_visible_lines) + m_first_visible_line = m_selected_line - 10; + } + else + { + if (m_selected_line > 10) + m_first_visible_line = m_selected_line - 10; + else + m_first_visible_line = 0; + } + } + else + { + // File changed, set selected line to the line with the PC + m_selected_line = m_pc_line; + m_file_sp = m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file); + if (m_file_sp) + { + const size_t num_lines = m_file_sp->GetNumLines(); + int m_line_width = 1; + for (size_t n = num_lines; n >= 10; n = n / 10) + ++m_line_width; + + snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width); + if (num_lines < num_visible_lines || m_selected_line < num_visible_lines) + m_first_visible_line = 0; + else + m_first_visible_line = m_selected_line - 10; + } + } + } + else + { + m_file_sp.reset(); + } + + if (!m_file_sp || m_file_sp->GetNumLines() == 0) + { + // Show disassembly + bool prefer_file_cache = false; + if (m_sc.function) + { + if (m_disassembly_scope != m_sc.function) + { + m_disassembly_scope = m_sc.function; + m_disassembly_sp = m_sc.function->GetInstructions (exe_ctx, NULL, prefer_file_cache); + if (m_disassembly_sp) + { + set_selected_line_to_pc = true; + m_disassembly_range = m_sc.function->GetAddressRange(); + } + else + { + m_disassembly_range.Clear(); + } + } + else + { + set_selected_line_to_pc = context_changed; + } + } + else if (m_sc.symbol) + { + if (m_disassembly_scope != m_sc.symbol) + { + m_disassembly_scope = m_sc.symbol; + m_disassembly_sp = m_sc.symbol->GetInstructions (exe_ctx, NULL, prefer_file_cache); + if (m_disassembly_sp) + { + set_selected_line_to_pc = true; + m_disassembly_range.GetBaseAddress() = m_sc.symbol->GetAddress(); + m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize()); + } + else + { + m_disassembly_range.Clear(); + } + } + else + { + set_selected_line_to_pc = context_changed; + } + } + } + } + else + { + m_pc_line = UINT32_MAX; + } + } + + + window.Erase(); + window.DrawTitleBox ("Sources"); + + + Target *target = exe_ctx.GetTargetPtr(); + const size_t num_source_lines = GetNumSourceLines(); + if (num_source_lines > 0) + { + // Display source + BreakpointLines bp_lines; + if (target) + { + BreakpointList &bp_list = target->GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx) + { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx) + { + BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry (bp_loc_line_entry)) + { + if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file) + { + bp_lines.insert(bp_loc_line_entry.line); + } + } + } + } + } + + + const attr_t selected_highlight_attr = A_REVERSE; + const attr_t pc_highlight_attr = COLOR_PAIR(1); + + for (int i=0; i<num_visible_lines; ++i) + { + const uint32_t curr_line = m_first_visible_line + i; + if (curr_line < num_source_lines) + { + const int line_y = 1+i; + window.MoveCursor(1, line_y); + const bool is_pc_line = curr_line == m_pc_line; + const bool line_is_selected = m_selected_line == curr_line; + // Highlight the line as the PC line first, then if the selected line + // isn't the same as the PC line, highlight it differently + attr_t highlight_attr = 0; + attr_t bp_attr = 0; + if (is_pc_line) + highlight_attr = pc_highlight_attr; + else if (line_is_selected) + highlight_attr = selected_highlight_attr; + + if (bp_lines.find(curr_line+1) != bp_lines.end()) + bp_attr = COLOR_PAIR(2); + + if (bp_attr) + window.AttributeOn(bp_attr); + + window.Printf (m_line_format, curr_line + 1); + + if (bp_attr) + window.AttributeOff(bp_attr); + + window.PutChar(ACS_VLINE); + // Mark the line with the PC with a diamond + if (is_pc_line) + window.PutChar(ACS_DIAMOND); + else + window.PutChar(' '); + + if (highlight_attr) + window.AttributeOn(highlight_attr); + const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false); + if (line_len > 0) + window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len); + + if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) + { + StopInfoSP stop_info_sp; + if (thread) + stop_info_sp = thread->GetStopInfo(); + if (stop_info_sp) + { + const char *stop_description = stop_info_sp->GetDescription(); + if (stop_description && stop_description[0]) + { + size_t stop_description_len = strlen(stop_description); + int desc_x = window.GetWidth() - stop_description_len - 16; + window.Printf ("%*s", desc_x - window.GetCursorX(), ""); + //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y); + window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description); + } + } + else + { + window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, ""); + } + } + if (highlight_attr) + window.AttributeOff(highlight_attr); + + } + else + { + break; + } + } + } + else + { + size_t num_disassembly_lines = GetNumDisassemblyLines(); + if (num_disassembly_lines > 0) + { + // Display disassembly + BreakpointAddrs bp_file_addrs; + Target *target = exe_ctx.GetTargetPtr(); + if (target) + { + BreakpointList &bp_list = target->GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx) + { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx) + { + BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + const lldb::addr_t file_addr = bp_loc_sp->GetAddress().GetFileAddress(); + if (file_addr != LLDB_INVALID_ADDRESS) + { + if (m_disassembly_range.ContainsFileAddress(file_addr)) + bp_file_addrs.insert(file_addr); + } + } + } + } + + + const attr_t selected_highlight_attr = A_REVERSE; + const attr_t pc_highlight_attr = COLOR_PAIR(1); + + StreamString strm; + + InstructionList &insts = m_disassembly_sp->GetInstructionList(); + Address pc_address; + + if (frame_sp) + pc_address = frame_sp->GetFrameCodeAddress(); + const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX; + if (set_selected_line_to_pc) + { + m_selected_line = pc_idx; + } + + const uint32_t non_visible_pc_offset = (num_visible_lines / 5); + if (m_first_visible_line >= num_disassembly_lines) + m_first_visible_line = 0; + + if (pc_idx < num_disassembly_lines) + { + if (pc_idx < m_first_visible_line || + pc_idx >= m_first_visible_line + num_visible_lines) + m_first_visible_line = pc_idx - non_visible_pc_offset; + } + + for (size_t i=0; i<num_visible_lines; ++i) + { + const uint32_t inst_idx = m_first_visible_line + i; + Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get(); + if (!inst) + break; + + window.MoveCursor(1, i+1); + const bool is_pc_line = frame_sp && inst_idx == pc_idx; + const bool line_is_selected = m_selected_line == inst_idx; + // Highlight the line as the PC line first, then if the selected line + // isn't the same as the PC line, highlight it differently + attr_t highlight_attr = 0; + attr_t bp_attr = 0; + if (is_pc_line) + highlight_attr = pc_highlight_attr; + else if (line_is_selected) + highlight_attr = selected_highlight_attr; + + if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end()) + bp_attr = COLOR_PAIR(2); + + if (bp_attr) + window.AttributeOn(bp_attr); + + window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target)); + + if (bp_attr) + window.AttributeOff(bp_attr); + + window.PutChar(ACS_VLINE); + // Mark the line with the PC with a diamond + if (is_pc_line) + window.PutChar(ACS_DIAMOND); + else + window.PutChar(' '); + + if (highlight_attr) + window.AttributeOn(highlight_attr); + + const char *mnemonic = inst->GetMnemonic(&exe_ctx); + const char *operands = inst->GetOperands(&exe_ctx); + const char *comment = inst->GetComment(&exe_ctx); + + if (mnemonic && mnemonic[0] == '\0') + mnemonic = NULL; + if (operands && operands[0] == '\0') + operands = NULL; + if (comment && comment[0] == '\0') + comment = NULL; + + strm.Clear(); + + if (mnemonic && operands && comment) + strm.Printf ("%-8s %-25s ; %s", mnemonic, operands, comment); + else if (mnemonic && operands) + strm.Printf ("%-8s %s", mnemonic, operands); + else if (mnemonic) + strm.Printf ("%s", mnemonic); + + int right_pad = 1; + window.PutCStringTruncated(strm.GetString().c_str(), right_pad); + + if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) + { + StopInfoSP stop_info_sp; + if (thread) + stop_info_sp = thread->GetStopInfo(); + if (stop_info_sp) + { + const char *stop_description = stop_info_sp->GetDescription(); + if (stop_description && stop_description[0]) + { + size_t stop_description_len = strlen(stop_description); + int desc_x = window.GetWidth() - stop_description_len - 16; + window.Printf ("%*s", desc_x - window.GetCursorX(), ""); + //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y); + window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description); + } + } + else + { + window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, ""); + } + } + if (highlight_attr) + window.AttributeOff(highlight_attr); + } + } + } + window.DeferredRefresh(); + return true; // Drawing handled + } + + size_t + GetNumLines () + { + size_t num_lines = GetNumSourceLines(); + if (num_lines == 0) + num_lines = GetNumDisassemblyLines(); + return num_lines; + } + + size_t + GetNumSourceLines () const + { + if (m_file_sp) + return m_file_sp->GetNumLines(); + return 0; + } + size_t + GetNumDisassemblyLines () const + { + if (m_disassembly_sp) + return m_disassembly_sp->GetInstructionList().GetSize(); + return 0; + } + + virtual HandleCharResult + WindowDelegateHandleChar (Window &window, int c) + { + const uint32_t num_visible_lines = NumVisibleLines(); + const size_t num_lines = GetNumLines (); + + switch (c) + { + case ',': + case KEY_PPAGE: + // Page up key + if (m_first_visible_line > num_visible_lines) + m_first_visible_line -= num_visible_lines; + else + m_first_visible_line = 0; + m_selected_line = m_first_visible_line; + return eKeyHandled; + + case '.': + case KEY_NPAGE: + // Page down key + { + if (m_first_visible_line + num_visible_lines < num_lines) + m_first_visible_line += num_visible_lines; + else if (num_lines < num_visible_lines) + m_first_visible_line = 0; + else + m_first_visible_line = num_lines - num_visible_lines; + m_selected_line = m_first_visible_line; + } + return eKeyHandled; + + case KEY_UP: + if (m_selected_line > 0) + { + m_selected_line--; + if (m_first_visible_line > m_selected_line) + m_first_visible_line = m_selected_line; + } + return eKeyHandled; + + case KEY_DOWN: + if (m_selected_line + 1 < num_lines) + { + m_selected_line++; + if (m_first_visible_line + num_visible_lines < m_selected_line) + m_first_visible_line++; + } + return eKeyHandled; + + case '\r': + case '\n': + case KEY_ENTER: + // Set a breakpoint and run to the line using a one shot breakpoint + if (GetNumSourceLines() > 0) + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope() && exe_ctx.GetProcessRef().IsAlive()) + { + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL, // Don't limit the breakpoint to certain modules + m_file_sp->GetFileSpec(), // Source file + m_selected_line + 1, // Source line number (m_selected_line is zero based) + eLazyBoolCalculate, // Check inlines using global setting + eLazyBoolCalculate, // Skip prologue using global setting, + false, // internal + false); // request_hardware + // Make breakpoint one shot + bp_sp->GetOptions()->SetOneShot(true); + exe_ctx.GetProcessRef().Resume(); + } + } + else if (m_selected_line < GetNumDisassemblyLines()) + { + const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get(); + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasTargetScope()) + { + Address addr = inst->GetAddress(); + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr, // lldb_private::Address + false, // internal + false); // request_hardware + // Make breakpoint one shot + bp_sp->GetOptions()->SetOneShot(true); + exe_ctx.GetProcessRef().Resume(); + } + } + return eKeyHandled; + + case 'b': // 'b' == toggle breakpoint on currently selected line + if (m_selected_line < GetNumSourceLines()) + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasTargetScope()) + { + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL, // Don't limit the breakpoint to certain modules + m_file_sp->GetFileSpec(), // Source file + m_selected_line + 1, // Source line number (m_selected_line is zero based) + eLazyBoolCalculate, // Check inlines using global setting + eLazyBoolCalculate, // Skip prologue using global setting, + false, // internal + false); // request_hardware + } + } + else if (m_selected_line < GetNumDisassemblyLines()) + { + const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get(); + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasTargetScope()) + { + Address addr = inst->GetAddress(); + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr, // lldb_private::Address + false, // internal + false); // request_hardware + } + } + return eKeyHandled; + + case 'd': // 'd' == detach and let run + case 'D': // 'D' == detach and keep stopped + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + exe_ctx.GetProcessRef().Detach(c == 'D'); + } + return eKeyHandled; + + case 'k': + // 'k' == kill + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + exe_ctx.GetProcessRef().Destroy(); + } + return eKeyHandled; + + case 'c': + // 'c' == continue + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasProcessScope()) + exe_ctx.GetProcessRef().Resume(); + } + return eKeyHandled; + + case 'o': + // 'o' == step out + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true)) + { + exe_ctx.GetThreadRef().StepOut(); + } + } + return eKeyHandled; + case 'n': // 'n' == step over + case 'N': // 'N' == step over instruction + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true)) + { + bool source_step = (c == 'n'); + exe_ctx.GetThreadRef().StepOver(source_step); + } + } + return eKeyHandled; + case 's': // 's' == step into + case 'S': // 'S' == step into instruction + { + ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true)) + { + bool source_step = (c == 's'); + bool avoid_code_without_debug_info = true; + exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info); + } + } + return eKeyHandled; + + case 'h': + window.CreateHelpSubwindow (); + return eKeyHandled; + + default: + break; + } + return eKeyNotHandled; + } + +protected: + typedef std::set<uint32_t> BreakpointLines; + typedef std::set<lldb::addr_t> BreakpointAddrs; + + Debugger &m_debugger; + SymbolContext m_sc; + SourceManager::FileSP m_file_sp; + SymbolContextScope *m_disassembly_scope; + lldb::DisassemblerSP m_disassembly_sp; + AddressRange m_disassembly_range; + lldb::user_id_t m_tid; + char m_line_format[8]; + int m_line_width; + uint32_t m_selected_line; // The selected line + uint32_t m_pc_line; // The line with the PC + uint32_t m_stop_id; + uint32_t m_frame_idx; + int m_first_visible_line; + int m_min_x; + int m_min_y; + int m_max_x; + int m_max_y; + +}; + +DisplayOptions ValueObjectListDelegate::g_options = { true }; + +IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) : + IOHandler (debugger) +{ +} + +void +IOHandlerCursesGUI::Activate () +{ + IOHandler::Activate(); + if (!m_app_ap) + { + m_app_ap.reset (new Application (GetInputFILE(), GetOutputFILE())); + + + // This is both a window and a menu delegate + std::shared_ptr<ApplicationDelegate> app_delegate_sp(new ApplicationDelegate(*m_app_ap, m_debugger)); + + MenuDelegateSP app_menu_delegate_sp = std::static_pointer_cast<MenuDelegate>(app_delegate_sp); + MenuSP lldb_menu_sp(new Menu("LLDB" , "F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB)); + MenuSP exit_menuitem_sp(new Menu("Exit", NULL, 'x', ApplicationDelegate::eMenuID_LLDBExit)); + exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit); + lldb_menu_sp->AddSubmenu (MenuSP (new Menu("About LLDB", NULL, 'a', ApplicationDelegate::eMenuID_LLDBAbout))); + lldb_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator))); + lldb_menu_sp->AddSubmenu (exit_menuitem_sp); + + MenuSP target_menu_sp(new Menu("Target" ,"F2", KEY_F(2), ApplicationDelegate::eMenuID_Target)); + target_menu_sp->AddSubmenu (MenuSP (new Menu("Create", NULL, 'c', ApplicationDelegate::eMenuID_TargetCreate))); + target_menu_sp->AddSubmenu (MenuSP (new Menu("Delete", NULL, 'd', ApplicationDelegate::eMenuID_TargetDelete))); + + MenuSP process_menu_sp(new Menu("Process", "F3", KEY_F(3), ApplicationDelegate::eMenuID_Process)); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Attach" , NULL, 'a', ApplicationDelegate::eMenuID_ProcessAttach))); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Detach" , NULL, 'd', ApplicationDelegate::eMenuID_ProcessDetach))); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Launch" , NULL, 'l', ApplicationDelegate::eMenuID_ProcessLaunch))); + process_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator))); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Continue", NULL, 'c', ApplicationDelegate::eMenuID_ProcessContinue))); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Halt" , NULL, 'h', ApplicationDelegate::eMenuID_ProcessHalt))); + process_menu_sp->AddSubmenu (MenuSP (new Menu("Kill" , NULL, 'k', ApplicationDelegate::eMenuID_ProcessKill))); + + MenuSP thread_menu_sp(new Menu("Thread", "F4", KEY_F(4), ApplicationDelegate::eMenuID_Thread)); + thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step In" , NULL, 'i', ApplicationDelegate::eMenuID_ThreadStepIn))); + thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Over", NULL, 'v', ApplicationDelegate::eMenuID_ThreadStepOver))); + thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Out" , NULL, 'o', ApplicationDelegate::eMenuID_ThreadStepOut))); + + MenuSP view_menu_sp(new Menu("View", "F5", KEY_F(5), ApplicationDelegate::eMenuID_View)); + view_menu_sp->AddSubmenu (MenuSP (new Menu("Backtrace", NULL, 'b', ApplicationDelegate::eMenuID_ViewBacktrace))); + view_menu_sp->AddSubmenu (MenuSP (new Menu("Registers", NULL, 'r', ApplicationDelegate::eMenuID_ViewRegisters))); + view_menu_sp->AddSubmenu (MenuSP (new Menu("Source" , NULL, 's', ApplicationDelegate::eMenuID_ViewSource))); + view_menu_sp->AddSubmenu (MenuSP (new Menu("Variables", NULL, 'v', ApplicationDelegate::eMenuID_ViewVariables))); + + MenuSP help_menu_sp(new Menu("Help", "F6", KEY_F(6), ApplicationDelegate::eMenuID_Help)); + help_menu_sp->AddSubmenu (MenuSP (new Menu("GUI Help", NULL, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp))); + + m_app_ap->Initialize(); + WindowSP &main_window_sp = m_app_ap->GetMainWindow(); + + MenuSP menubar_sp(new Menu(Menu::Type::Bar)); + menubar_sp->AddSubmenu (lldb_menu_sp); + menubar_sp->AddSubmenu (target_menu_sp); + menubar_sp->AddSubmenu (process_menu_sp); + menubar_sp->AddSubmenu (thread_menu_sp); + menubar_sp->AddSubmenu (view_menu_sp); + menubar_sp->AddSubmenu (help_menu_sp); + menubar_sp->SetDelegate(app_menu_delegate_sp); + + Rect content_bounds = main_window_sp->GetFrame(); + Rect menubar_bounds = content_bounds.MakeMenuBar(); + Rect status_bounds = content_bounds.MakeStatusBar(); + Rect source_bounds; + Rect variables_bounds; + Rect threads_bounds; + Rect source_variables_bounds; + content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, threads_bounds); + source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds, variables_bounds); + + WindowSP menubar_window_sp = main_window_sp->CreateSubWindow("Menubar", menubar_bounds, false); + // Let the menubar get keys if the active window doesn't handle the + // keys that are typed so it can respond to menubar key presses. + menubar_window_sp->SetCanBeActive(false); // Don't let the menubar become the active window + menubar_window_sp->SetDelegate(menubar_sp); + + WindowSP source_window_sp (main_window_sp->CreateSubWindow("Source", + source_bounds, + true)); + WindowSP variables_window_sp (main_window_sp->CreateSubWindow("Variables", + variables_bounds, + false)); + WindowSP threads_window_sp (main_window_sp->CreateSubWindow("Threads", + threads_bounds, + false)); + WindowSP status_window_sp (main_window_sp->CreateSubWindow("Status", + status_bounds, + false)); + status_window_sp->SetCanBeActive(false); // Don't let the status bar become the active window + main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp)); + source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger))); + variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger))); + TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger)); + threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp))); + status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger))); + + // Show the main help window once the first time the curses GUI is launched + static bool g_showed_help = false; + if (!g_showed_help) + { + g_showed_help = true; + main_window_sp->CreateHelpSubwindow(); + } + + init_pair (1, COLOR_WHITE , COLOR_BLUE ); + init_pair (2, COLOR_BLACK , COLOR_WHITE ); + init_pair (3, COLOR_MAGENTA , COLOR_WHITE ); + init_pair (4, COLOR_MAGENTA , COLOR_BLACK ); + init_pair (5, COLOR_RED , COLOR_BLACK ); + + } +} + +void +IOHandlerCursesGUI::Deactivate () +{ + m_app_ap->Terminate(); +} + +void +IOHandlerCursesGUI::Run () +{ + m_app_ap->Run(m_debugger); + SetIsDone(true); +} + + +IOHandlerCursesGUI::~IOHandlerCursesGUI () +{ + +} + +void +IOHandlerCursesGUI::Hide () +{ +} + + +void +IOHandlerCursesGUI::Refresh () +{ +} + +void +IOHandlerCursesGUI::Cancel () +{ +} + +void +IOHandlerCursesGUI::Interrupt () +{ +} + + +void +IOHandlerCursesGUI::GotEOF() +{ +} + +#endif // #ifndef LLDB_DISABLE_CURSES
\ No newline at end of file diff --git a/contrib/llvm/tools/lldb/source/Core/InputReader.cpp b/contrib/llvm/tools/lldb/source/Core/InputReader.cpp deleted file mode 100644 index cbaa671..0000000 --- a/contrib/llvm/tools/lldb/source/Core/InputReader.cpp +++ /dev/null @@ -1,387 +0,0 @@ -//===-- InputReader.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 <string> - -#include "lldb/Core/InputReader.h" -#include "lldb/Core/Debugger.h" -#include "lldb/Interpreter/CommandInterpreter.h" - -using namespace lldb; -using namespace lldb_private; - -InputReader::InputReader (Debugger &debugger) : - m_debugger (debugger), - m_callback (NULL), - m_callback_baton (NULL), - m_end_token (), - m_granularity (eInputReaderGranularityInvalid), - m_done (true), - m_echo (true), - m_active (false), - m_reader_done (false), - m_user_input(), - m_save_user_input(false) -{ -} - -InputReader::~InputReader () -{ -} - -Error -InputReader::Initialize -( - Callback callback, - void *baton, - lldb::InputReaderGranularity granularity, - const char *end_token, - const char *prompt, - bool echo -) -{ - Error err; - m_callback = callback; - m_callback_baton = baton, - m_granularity = granularity; - if (end_token != NULL) - m_end_token = end_token; - if (prompt != NULL) - m_prompt = prompt; - m_done = true; - m_echo = echo; - - if (m_granularity == eInputReaderGranularityInvalid) - { - err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'."); - } - else - if (end_token != NULL && granularity != eInputReaderGranularityInvalid) - { - if (granularity == eInputReaderGranularityByte) - { - // Check to see if end_token is longer than one byte. - - if (strlen (end_token) > 1) - { - err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte)."); - } - } - else if (granularity == eInputReaderGranularityWord) - { - // Check to see if m_end_token contains any white space (i.e. is multiple words). - - const char *white_space = " \t\n"; - size_t pos = m_end_token.find_first_of (white_space); - if (pos != std::string::npos) - { - err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word)."); - } - } - else - { - // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens. - - size_t pos = m_end_token.find_first_of ('\n'); - if (pos != std::string::npos) - { - err.SetErrorString ("Invalid end token: End token cannot contain a newline."); - } - } - } - - m_done = err.Fail(); - - return err; -} - -size_t -InputReader::HandleRawBytes (const char *bytes, size_t bytes_len) -{ - const char *end_token = NULL; - - if (m_end_token.empty() == false) - { - end_token = ::strstr (bytes, m_end_token.c_str()); - if (end_token >= bytes + bytes_len) - end_token = NULL; - } - - const char *p = bytes; - const char *end = bytes + bytes_len; - - switch (m_granularity) - { - case eInputReaderGranularityInvalid: - break; - - case eInputReaderGranularityByte: - while (p < end) - { - if (end_token == p) - { - p += m_end_token.size(); - SetIsDone(true); - break; - } - - if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0) - break; - ++p; - if (IsDone()) - break; - } - // Return how many bytes were handled. - return p - bytes; - break; - - - case eInputReaderGranularityWord: - { - char quote = '\0'; - const char *word_start = NULL; - bool send_word = false; - for (; p < end; ++p, send_word = false) - { - if (end_token && end_token == p) - { - m_end_token.size(); - SetIsDone(true); - break; - } - - const char ch = *p; - if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\'))) - { - // We have a space character or the terminating quote - send_word = word_start != NULL; - quote = '\0'; - } - else if (quote) - { - // We are in the middle of a quoted character - continue; - } - else if (ch == '"' || ch == '\'' || ch == '`') - quote = ch; - else if (word_start == NULL) - { - // We have the first character in a word - word_start = p; - } - - if (send_word) - { - const size_t word_len = p - word_start; - size_t bytes_handled = m_callback (m_callback_baton, - *this, - eInputReaderGotToken, - word_start, - word_len); - - if (bytes_handled != word_len) - return word_start - bytes + bytes_handled; - - if (IsDone()) - return p - bytes; - } - } - } - break; - - - case eInputReaderGranularityLine: - { - const char *line_start = bytes; - const char *end_line = NULL; - while (p < end) - { - const char ch = *p; - if (ch == '\n' || ch == '\r') - { - size_t line_length = p - line_start; - // Now skip the newline character - ++p; - // Skip a complete DOS newline if we run into one - if (ch == 0xd && p < end && *p == 0xa) - ++p; - - if (line_start <= end_token && end_token < line_start + line_length) - { - SetIsDone(true); - m_callback (m_callback_baton, - *this, - eInputReaderGotToken, - line_start, - end_token - line_start); - - return p - bytes; - } - - size_t bytes_handled = m_callback (m_callback_baton, - *this, - eInputReaderGotToken, - line_start, - line_length); - - end_line = p; - - if (bytes_handled != line_length) - { - // The input reader wasn't able to handle all the data - return line_start - bytes + bytes_handled; - } - - - if (IsDone()) - return p - bytes; - - line_start = p; - } - else - { - ++p; - } - } - - if (end_line) - return end_line - bytes; - } - break; - - - case eInputReaderGranularityAll: - { - // Nothing should be handle unless we see our end token - if (end_token) - { - size_t length = end_token - bytes; - size_t bytes_handled = m_callback (m_callback_baton, - *this, - eInputReaderGotToken, - bytes, - length); - m_done = true; - - p += bytes_handled + m_end_token.size(); - - // Consume any white space, such as newlines, beyond the end token - - while (p < end && isspace(*p)) - ++p; - - if (bytes_handled != length) - return bytes_handled; - else - { - return p - bytes; - //return bytes_handled + m_end_token.size(); - } - } - return 0; - } - break; - } - return 0; -} - -const char * -InputReader::GetPrompt () const -{ - if (!m_prompt.empty()) - return m_prompt.c_str(); - else - return NULL; -} - -void -InputReader::RefreshPrompt () -{ - if (m_debugger.GetCommandInterpreter().GetBatchCommandMode()) - return; - - if (!m_prompt.empty()) - { - File &out_file = m_debugger.GetOutputFile(); - if (out_file.IsValid()) - { - out_file.Printf ("%s", m_prompt.c_str()); - out_file.Flush(); - } - } -} - -void -InputReader::Notify (InputReaderAction notification) -{ - switch (notification) - { - case eInputReaderActivate: - case eInputReaderReactivate: - m_active = true; - m_reader_done.SetValue(false, eBroadcastAlways); - break; - - case eInputReaderDeactivate: - case eInputReaderDone: - m_active = false; - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderInterrupt: - case eInputReaderEndOfFile: - break; - - case eInputReaderGotToken: - return; // We don't notify the tokens here, it is done in HandleRawBytes - } - if (m_callback) - m_callback (m_callback_baton, *this, notification, NULL, 0); - if (notification == eInputReaderDone) - m_reader_done.SetValue(true, eBroadcastAlways); -} - -void -InputReader::WaitOnReaderIsDone () -{ - m_reader_done.WaitForValueEqualTo (true); -} - -const char * -InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity) -{ - switch (granularity) - { - case eInputReaderGranularityInvalid: return "invalid"; - case eInputReaderGranularityByte: return "byte"; - case eInputReaderGranularityWord: return "word"; - case eInputReaderGranularityLine: return "line"; - case eInputReaderGranularityAll: return "all"; - } - - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity); - return unknown_state_string; -} - -bool -InputReader::HandlerData::GetBatchMode() -{ - return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); -} - -lldb::StreamSP -InputReader::HandlerData::GetOutStream() -{ - return reader.GetDebugger().GetAsyncOutputStream(); -} diff --git a/contrib/llvm/tools/lldb/source/Core/InputReaderEZ.cpp b/contrib/llvm/tools/lldb/source/Core/InputReaderEZ.cpp deleted file mode 100644 index 7a865bd..0000000 --- a/contrib/llvm/tools/lldb/source/Core/InputReaderEZ.cpp +++ /dev/null @@ -1,91 +0,0 @@ -//===-- InputReaderEZ.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/Core/InputReaderEZ.h" - -using namespace lldb; -using namespace lldb_private; - -size_t -InputReaderEZ::Callback_Impl(void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) - -{ - HandlerData hand_data(reader, - bytes, - bytes_len, - baton); - - switch (notification) - { - case eInputReaderActivate: - reader.ActivateHandler(hand_data); - break; - case eInputReaderDeactivate: - reader.DeactivateHandler(hand_data); - break; - case eInputReaderReactivate: - reader.ReactivateHandler(hand_data); - break; - case eInputReaderAsynchronousOutputWritten: - reader.AsynchronousOutputWrittenHandler(hand_data); - break; - case eInputReaderGotToken: - { - if (reader.GetSaveUserInput()) - reader.GetUserInput().AppendString(bytes, bytes_len); - reader.GotTokenHandler(hand_data); - } - break; - case eInputReaderInterrupt: - reader.InterruptHandler(hand_data); - break; - case eInputReaderEndOfFile: - reader.EOFHandler(hand_data); - break; - case eInputReaderDone: - reader.DoneHandler(hand_data); - break; - } - return bytes_len; -} - -Error -InputReaderEZ::Initialize(void* baton, - lldb::InputReaderGranularity token_size, - const char* end_token, - const char *prompt, - bool echo) -{ - return InputReader::Initialize(Callback_Impl, - baton, - token_size, - end_token, - prompt, - echo); -} - -Error -InputReaderEZ::Initialize(InitializationParameters& params) -{ - Error ret = Initialize(params.m_baton, - params.m_token_size, - params.m_end_token, - params.m_prompt, - params.m_echo); - m_save_user_input = params.m_save_user_input; - return ret; -} - -InputReaderEZ::~InputReaderEZ () -{ -} diff --git a/contrib/llvm/tools/lldb/source/Core/InputReaderStack.cpp b/contrib/llvm/tools/lldb/source/Core/InputReaderStack.cpp deleted file mode 100644 index 764ea26..0000000 --- a/contrib/llvm/tools/lldb/source/Core/InputReaderStack.cpp +++ /dev/null @@ -1,80 +0,0 @@ -//===-- InputReaderStack.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/Core/InputReaderStack.h" - -// C Includes -// C++ Includes -// Other libraries and framework includes -// Project includes - - -using namespace lldb; -using namespace lldb_private; - -InputReaderStack::InputReaderStack () : - m_input_readers (), - m_input_readers_mutex (Mutex::eMutexTypeRecursive) -{ -} - -InputReaderStack::~InputReaderStack () -{ -} - -size_t -InputReaderStack::GetSize () const -{ - Mutex::Locker locker (m_input_readers_mutex); - return m_input_readers.size(); -} - -void -InputReaderStack::Push (const lldb::InputReaderSP& reader_sp) -{ - if (reader_sp) - { - Mutex::Locker locker (m_input_readers_mutex); - m_input_readers.push (reader_sp); - } -} - -bool -InputReaderStack::IsEmpty () const -{ - Mutex::Locker locker (m_input_readers_mutex); - return m_input_readers.empty(); -} - -InputReaderSP -InputReaderStack::Top () -{ - InputReaderSP input_reader_sp; - { - Mutex::Locker locker (m_input_readers_mutex); - if (!m_input_readers.empty()) - input_reader_sp = m_input_readers.top(); - } - - return input_reader_sp; -} - -void -InputReaderStack::Pop () -{ - Mutex::Locker locker (m_input_readers_mutex); - if (!m_input_readers.empty()) - m_input_readers.pop(); -} - -Mutex & -InputReaderStack::GetStackMutex () -{ - return m_input_readers_mutex; -} diff --git a/contrib/llvm/tools/lldb/source/Core/Log.cpp b/contrib/llvm/tools/lldb/source/Core/Log.cpp index 8d659cf..b7dc056 100644 --- a/contrib/llvm/tools/lldb/source/Core/Log.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Log.cpp @@ -83,7 +83,10 @@ Log::GetMask() const void Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args) { - if (m_stream_sp) + // Make a copy of our stream shared pointer in case someone disables our + // log while we are logging and releases the stream + StreamSP stream_sp(m_stream_sp); + if (stream_sp) { static uint32_t g_sequence_id = 0; StreamString header; @@ -116,11 +119,11 @@ Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args) } header.PrintfVarArg (format, args); - m_stream_sp->Printf("%s\n", header.GetData()); + stream_sp->Printf("%s\n", header.GetData()); if (m_options.Test (LLDB_LOG_OPTION_BACKTRACE)) - Host::Backtrace (*m_stream_sp, 1024); - m_stream_sp->Flush(); + Host::Backtrace (*stream_sp, 1024); + stream_sp->Flush(); } } @@ -467,8 +470,11 @@ Log::GetVerbose() const if (m_options.Test(LLDB_LOG_OPTION_VERBOSE)) return true; - if (m_stream_sp) - return m_stream_sp->GetVerbose(); + // Make a copy of our stream shared pointer in case someone disables our + // log while we are logging and releases the stream + StreamSP stream_sp(m_stream_sp); + if (stream_sp) + return stream_sp->GetVerbose(); return false; } @@ -478,8 +484,11 @@ Log::GetVerbose() const bool Log::GetDebug() const { - if (m_stream_sp) - return m_stream_sp->GetDebug(); + // Make a copy of our stream shared pointer in case someone disables our + // log while we are logging and releases the stream + StreamSP stream_sp(m_stream_sp); + if (stream_sp) + return stream_sp->GetDebug(); return false; } diff --git a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp index a41986d..55bd3cb 100644 --- a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp @@ -20,17 +20,10 @@ #ifdef LLDB_USE_BUILTIN_DEMANGLER -#include <vector> -#include <algorithm> -#include <string> -#include <numeric> -#include <cstdlib> -#include <cstring> -#include <cctype> //---------------------------------------------------------------------- // Inlined copy of: // http://llvm.org/svn/llvm-project/libcxxabi/trunk/src/cxa_demangle.cpp -// revision 193704. +// revision 199944. // // Changes include: // - remove the "__cxxabiv1" namespace @@ -38,8 +31,32 @@ // - removed extern "C" from the cxa_demangle function // - Changed the scope of the unnamed namespace to include cxa_demangle // function. +// - Added "#undef _LIBCPP_EXTERN_TEMPLATE" to avoid warning //---------------------------------------------------------------------- +#undef _LIBCPP_EXTERN_TEMPLATE // Avoid warning below + +//===-------------------------- cxa_demangle.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define _LIBCPP_EXTERN_TEMPLATE(...) +#define _LIBCPP_NO_EXCEPTIONS + +#include <vector> +#include <algorithm> +#include <string> +#include <numeric> +#include <cstdlib> +#include <cstring> +#include <cctype> + + namespace { @@ -558,6 +575,8 @@ parse_template_param(const char* first, const char* last, C& db) { if (first[1] == '_') { + if (db.template_param.empty()) + return first; if (!db.template_param.back().empty()) { for (auto& t : db.template_param.back().front()) @@ -580,7 +599,7 @@ parse_template_param(const char* first, const char* last, C& db) sub *= 10; sub += static_cast<size_t>(*t - '0'); } - if (t == last || *t != '_') + if (t == last || *t != '_' || db.template_param.empty()) return first; ++sub; if (sub < db.template_param.back().size()) @@ -615,6 +634,8 @@ parse_const_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto expr = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; @@ -639,6 +660,8 @@ parse_dynamic_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto expr = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; @@ -663,6 +686,8 @@ parse_reinterpret_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto expr = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; @@ -687,6 +712,8 @@ parse_static_cast_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto expr = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; @@ -723,6 +750,8 @@ parse_sizeof_type_expr(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; first = t; } @@ -741,6 +770,8 @@ parse_sizeof_expr_expr(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; first = t; } @@ -832,6 +863,8 @@ parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db const char* t = parse_function_param(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; first = t; } @@ -855,6 +888,8 @@ parse_typeid_expr(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back() = "typeid(" + db.names.back().move_full() + ")"; first = t; } @@ -873,6 +908,8 @@ parse_throw_expr(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back() = "throw " + db.names.back().move_full(); first = t; } @@ -894,6 +931,8 @@ parse_dot_star_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto expr = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += ".*" + expr; @@ -918,6 +957,8 @@ parse_simple_id(const char* first, const char* last, C& db) const char* t1 = parse_template_args(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); @@ -964,6 +1005,8 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; } @@ -979,6 +1022,8 @@ parse_unresolved_type(const char* first, const char* last, C& db) t = parse_unqualified_name(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "std::"); db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; @@ -1005,6 +1050,8 @@ parse_destructor_name(const char* first, const char* last, C& db) t = parse_simple_id(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "~"); first = t; } @@ -1036,6 +1083,8 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { + if (db.names.size() < 2) + return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); @@ -1060,6 +1109,8 @@ parse_base_unresolved_name(const char* first, const char* last, C& db) first = parse_template_args(t, last, db); if (first != t) { + if (db.names.size() < 2) + return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); @@ -1109,7 +1160,11 @@ parse_unresolved_name(const char* first, const char* last, C& db) if (t2 != t) { if (global) + { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "::"); + } first = t2; } else if (last - t > 2 && t[0] == 's' && t[1] == 'r') @@ -1124,6 +1179,8 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); @@ -1137,7 +1194,7 @@ parse_unresolved_name(const char* first, const char* last, C& db) while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last) + if (t1 == t || t1 == last || db.names.size() < 2) return first; auto s = db.names.back().move_full(); db.names.pop_back(); @@ -1148,9 +1205,12 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - db.names.pop_back(); + if (!db.names.empty()) + db.names.pop_back(); return first; } + if (db.names.size() < 2) + return first; auto s = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); @@ -1166,6 +1226,8 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_template_args(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += std::move(args); @@ -1174,9 +1236,12 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - db.names.pop_back(); + if (!db.names.empty()) + db.names.pop_back(); return first; } + if (db.names.size() < 2) + return first; auto s = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); @@ -1189,11 +1254,15 @@ parse_unresolved_name(const char* first, const char* last, C& db) return first; t = t1; if (global) + { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "::"); + } while (*t != 'E') { t1 = parse_unresolved_qualifier_level(t, last, db); - if (t1 == t || t1 == last) + if (t1 == t || t1 == last || db.names.size() < 2) return first; auto s = db.names.back().move_full(); db.names.pop_back(); @@ -1204,9 +1273,12 @@ parse_unresolved_name(const char* first, const char* last, C& db) t1 = parse_base_unresolved_name(t, last, db); if (t1 == t) { - db.names.pop_back(); + if (!db.names.empty()) + db.names.pop_back(); return first; } + if (db.names.size() < 2) + return first; auto s = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += "::" + std::move(s); @@ -1232,6 +1304,8 @@ parse_dot_expr(const char* first, const char* last, C& db) const char* t1 = parse_unresolved_name(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto name = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += "." + name; @@ -1255,6 +1329,8 @@ parse_call_expr(const char* first, const char* last, C& db) { if (t == last) return first; + if (db.names.empty()) + return first; db.names.back().first += db.names.back().second; db.names.back().second = typename C::String(); db.names.back().first.append("("); @@ -1264,10 +1340,14 @@ parse_call_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; + if (db.names.empty()) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { + if (db.names.empty()) + return first; if (!first_expr) { db.names.back().first.append(", "); @@ -1278,6 +1358,8 @@ parse_call_expr(const char* first, const char* last, C& db) t = t1; } ++t; + if (db.names.empty()) + return first; db.names.back().first.append(")"); first = t; } @@ -1320,10 +1402,14 @@ parse_new_expr(const char* first, const char* last, C& db) has_expr_list = true; if (!first_expr) { + if (db.names.empty()) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { + if (db.names.empty()) + return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; @@ -1349,10 +1435,14 @@ parse_new_expr(const char* first, const char* last, C& db) return first; if (!first_expr) { + if (db.names.empty()) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { + if (db.names.empty()) + return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; @@ -1366,14 +1456,20 @@ parse_new_expr(const char* first, const char* last, C& db) typename C::String init_list; if (has_init) { + if (db.names.empty()) + return first; init_list = db.names.back().move_full(); db.names.pop_back(); } + if (db.names.empty()) + return first; auto type = db.names.back().move_full(); db.names.pop_back(); typename C::String expr_list; if (has_expr_list) { + if (db.names.empty()) + return first; expr_list = db.names.back().move_full(); db.names.pop_back(); } @@ -1435,10 +1531,14 @@ parse_conversion_expr(const char* first, const char* last, C& db) return first; if (!first_expr) { + if (db.names.empty()) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) { + if (db.names.empty()) + return first; db.names.back().first.append(", "); db.names.back().first.append(tmp); first_expr = false; @@ -1449,6 +1549,8 @@ parse_conversion_expr(const char* first, const char* last, C& db) } ++t; } + if (db.names.size() < 2) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; @@ -1472,6 +1574,8 @@ parse_arrow_expr(const char* first, const char* last, C& db) const char* t1 = parse_expression(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += "->"; @@ -1564,6 +1668,8 @@ parse_function_type(const char* first, const char* last, C& db) sig += " &&"; break; } + if (db.names.empty()) + return first; db.names.back().first += " "; db.names.back().second.insert(0, sig); first = t; @@ -1587,6 +1693,8 @@ parse_pointer_to_member_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { + if (db.names.size() < 2) + return first; auto func = std::move(db.names.back()); db.names.pop_back(); auto class_type = std::move(db.names.back()); @@ -1621,6 +1729,8 @@ parse_array_type(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; if (db.names.back().second.substr(0, 2) == " [") db.names.back().second.erase(0, 1); db.names.back().second.insert(0, " []"); @@ -1635,6 +1745,8 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t+1, last, db); if (t2 != t+1) { + if (db.names.empty()) + return first; if (db.names.back().second.substr(0, 2) == " [") db.names.back().second.erase(0, 1); db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); @@ -1650,6 +1762,8 @@ parse_array_type(const char* first, const char* last, C& db) const char* t2 = parse_type(++t, last, db); if (t2 != t) { + if (db.names.size() < 2) + return first; auto type = std::move(db.names.back()); db.names.pop_back(); auto expr = std::move(db.names.back()); @@ -1682,6 +1796,8 @@ parse_decltype(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2 && t != last && *t == 'E') { + if (db.names.empty()) + return first; db.names.back() = "decltype(" + db.names.back().move_full() + ")"; first = t+1; } @@ -1719,6 +1835,8 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t1 = parse_type(t, last, db); if (t1 != t) { + if (db.names.empty()) + return first; db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; first = t1; } @@ -1740,6 +1858,8 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t = parse_expression(t1, last, db); if (t != t1) { + if (db.names.empty()) + return first; num = db.names.back().move_full(); db.names.pop_back(); t1 = t; @@ -1750,6 +1870,8 @@ parse_vector_type(const char* first, const char* last, C& db) const char* t = parse_type(t1, last, db); if (t != t1) { + if (db.names.empty()) + return first; db.names.back().first += " vector[" + num + "]"; first = t; } @@ -1860,6 +1982,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_array_type(first, last, db); if (t != first) { + if (db.names.empty()) + return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); } @@ -1868,6 +1992,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_type(first+1, last, db); if (t != first+1) { + if (db.names.empty()) + return first; db.names.back().first.append(" complex"); first = t; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); @@ -1877,6 +2003,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_function_type(first, last, db); if (t != first) { + if (db.names.empty()) + return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); } @@ -1885,6 +2013,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_type(first+1, last, db); if (t != first+1) { + if (db.names.empty()) + return first; db.names.back().first.append(" imaginary"); first = t; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); @@ -1894,6 +2024,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_pointer_to_member_type(first, last, db); if (t != first) { + if (db.names.empty()) + return first; first = t; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); } @@ -2021,6 +2153,8 @@ parse_type(const char* first, const char* last, C& db) const char* t2 = parse_type(t, last, db); if (t2 != t) { + if (db.names.size() < 2) + return first; auto type = db.names.back().move_full(); db.names.pop_back(); if (db.names.back().first.substr(0, 9) != "objcproto") @@ -2053,6 +2187,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; } @@ -2068,6 +2204,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_template_args(first, last, db); if (t != first) { + if (db.names.size() < 2) + return first; auto template_args = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += template_args; @@ -2103,6 +2241,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_decltype(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; return first; @@ -2112,6 +2252,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_vector_type(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; return first; @@ -2133,6 +2275,8 @@ parse_type(const char* first, const char* last, C& db) t = parse_name(first, last, db); if (t != first) { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); first = t; } @@ -2169,6 +2313,7 @@ parse_type(const char* first, const char* last, C& db) // ::= gt # > // ::= ix # [] // ::= le # <= +// ::= li <source-name> # operator "" // ::= ls # << // ::= lS # <<= // ::= lt # < @@ -2251,6 +2396,8 @@ parse_operator_name(const char* first, const char* last, C& db) db.try_to_parse_template_args = try_to_parse_template_args; if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "operator "); db.parsed_ctor_dtor_cv = true; first = t; @@ -2328,6 +2475,18 @@ parse_operator_name(const char* first, const char* last, C& db) db.names.push_back("operator<="); first += 2; break; + case 'i': + { + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator\"\" "); + first = t; + } + } + break; case 's': db.names.push_back("operator<<"); first += 2; @@ -2472,6 +2631,8 @@ parse_operator_name(const char* first, const char* last, C& db) const char* t = parse_source_name(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "operator "); first = t; } @@ -2681,6 +2842,8 @@ parse_expr_primary(const char* first, const char* last, C& db) ; if (n != t && n != last && *n == 'E') { + if (db.names.empty()) + return first; db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); first = n+1; break; @@ -2781,6 +2944,8 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '2': case '3': case '5': + if (db.names.empty()) + return first; db.names.push_back(base_name(db.names.back().first)); first += 2; db.parsed_ctor_dtor_cv = true; @@ -2794,6 +2959,8 @@ parse_ctor_dtor_name(const char* first, const char* last, C& db) case '1': case '2': case '5': + if (db.names.empty()) + return first; db.names.push_back("~" + base_name(db.names.back().first)); first += 2; db.parsed_ctor_dtor_cv = true; @@ -2864,6 +3031,8 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) db.names.pop_back(); return first; } + if (db.names.size() < 2) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back().first.append(tmp); @@ -2873,6 +3042,8 @@ parse_unnamed_type_name(const char* first, const char* last, C& db) t1 = parse_type(t0, last, db); if (t1 == t0) break; + if (db.names.size() < 2) + return first; tmp = db.names.back().move_full(); db.names.pop_back(); if (!tmp.empty()) @@ -2987,7 +3158,11 @@ parse_unscoped_name(const char* first, const char* last, C& db) if (t1 != t0) { if (St) + { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "std::"); + } first = t1; } } @@ -3005,6 +3180,8 @@ parse_alignof_type(const char* first, const char* last, C& db) const char* t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; first = t; } @@ -3023,6 +3200,8 @@ parse_alignof_expr(const char* first, const char* last, C& db) const char* t = parse_expression(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; first = t; } @@ -3037,6 +3216,8 @@ parse_noexcept_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first, last, db); if (t1 != first) { + if (db.names.empty()) + return first; db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; first = t1; } @@ -3050,6 +3231,8 @@ parse_prefix_expression(const char* first, const char* last, const typename C::S const char* t1 = parse_expression(first, last, db); if (t1 != first) { + if (db.names.empty()) + return first; db.names.back().first = op + "(" + db.names.back().move_full() + ")"; first = t1; } @@ -3066,6 +3249,8 @@ parse_binary_expression(const char* first, const char* last, const typename C::S const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { + if (db.names.size() < 2) + return first; auto op2 = db.names.back().move_full(); db.names.pop_back(); auto op1 = db.names.back().move_full(); @@ -3216,6 +3401,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { + if (db.names.empty()) + return first; db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + "delete[] " + db.names.back().move_full(); first = t1; @@ -3235,6 +3422,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(t+2, last, db); if (t1 != t+2) { + if (db.names.empty()) + return first; db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + "delete " + db.names.back().move_full(); first = t1; @@ -3305,6 +3494,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t2 = parse_expression(t1, last, db); if (t2 != t1) { + if (db.names.size() < 2) + return first; auto op2 = db.names.back().move_full(); db.names.pop_back(); auto op1 = db.names.back().move_full(); @@ -3376,6 +3567,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { + if (db.names.empty()) + return first; db.names.back() = "(" + db.names.back().move_full() + ")--"; first = t1; } @@ -3464,6 +3657,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t1 = parse_expression(first+2, last, db); if (t1 != first+2) { + if (db.names.empty()) + return first; db.names.back() = "(" + db.names.back().move_full() + ")++"; first = t1; } @@ -3491,6 +3686,8 @@ parse_expression(const char* first, const char* last, C& db) const char* t3 = parse_expression(t2, last, db); if (t3 != t2) { + if (db.names.size() < 3) + return first; auto op3 = db.names.back().move_full(); db.names.pop_back(); auto op2 = db.names.back().move_full(); @@ -3918,6 +4115,8 @@ parse_local_name(const char* first, const char* last, C& db) { case 's': first = parse_discriminator(t+1, last); + if (db.names.empty()) + return first; db.names.back().first.append("::string literal"); break; case 'd': @@ -3930,6 +4129,8 @@ parse_local_name(const char* first, const char* last, C& db) t1 = parse_name(t, last, db); if (t1 != t) { + if (db.names.size() < 2) + return first; auto name = db.names.back().move_full(); db.names.pop_back(); db.names.back().first.append("::"); @@ -3948,6 +4149,8 @@ parse_local_name(const char* first, const char* last, C& db) { // parse but ignore discriminator first = parse_discriminator(t1, last); + if (db.names.size() < 2) + return first; auto name = db.names.back().move_full(); db.names.pop_back(); db.names.back().first.append("::"); @@ -4004,11 +4207,15 @@ parse_name(const char* first, const char* last, C& db) { if (t1 != last && *t1 == 'I') // <unscoped-template-name> <template-args> { + if (db.names.empty()) + return first; db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); t0 = t1; t1 = parse_template_args(t0, last, db); if (t1 != t0) { + if (db.names.size() < 2) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += tmp; @@ -4027,6 +4234,8 @@ parse_name(const char* first, const char* last, C& db) t1 = parse_template_args(t0, last, db); if (t1 != t0) { + if (db.names.size() < 2) + return first; auto tmp = db.names.back().move_full(); db.names.pop_back(); db.names.back().first += tmp; @@ -4112,6 +4321,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "vtable for "); first = t; } @@ -4121,6 +4332,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "VTT for "); first = t; } @@ -4130,6 +4343,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "typeinfo for "); first = t; } @@ -4139,6 +4354,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_type(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "typeinfo name for "); first = t; } @@ -4155,6 +4372,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t1, last, db); if (t != t1) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "covariant return thunk to "); first = t; } @@ -4171,6 +4390,8 @@ parse_special_name(const char* first, const char* last, C& db) const char* t1 = parse_type(++t0, last, db); if (t1 != t0) { + if (db.names.size() < 2) + return first; auto left = db.names.back().move_full(); db.names.pop_back(); db.names.back().first = "construction vtable for " + @@ -4190,6 +4411,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_encoding(t0, last, db); if (t != t0) { + if (db.names.empty()) + return first; if (first[2] == 'v') { db.names.back().first.insert(0, "virtual thunk to "); @@ -4213,6 +4436,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "guard variable for "); first = t; } @@ -4222,6 +4447,8 @@ parse_special_name(const char* first, const char* last, C& db) t = parse_name(first+2, last, db); if (t != first+2) { + if (db.names.empty()) + return first; db.names.back().first.insert(0, "reference temporary for "); first = t; } @@ -4233,6 +4460,26 @@ parse_special_name(const char* first, const char* last, C& db) return first; } +template <class T> +class save_value +{ + T& restore_; + T original_value_; +public: + save_value(T& restore) + : restore_(restore), + original_value_(restore) + {} + + ~save_value() + { + restore_ = std::move(original_value_); + } + + save_value(const save_value&) = delete; + save_value& operator=(const save_value&) = delete; +}; + // <encoding> ::= <function name> <bare-function-type> // ::= <data name> // ::= <special-name> @@ -4243,6 +4490,11 @@ parse_encoding(const char* first, const char* last, C& db) { if (first != last) { + save_value<decltype(db.encoding_depth)> su(db.encoding_depth); + ++db.encoding_depth; + save_value<decltype(db.tag_templates)> sb(db.tag_templates); + if (db.encoding_depth > 1) + db.tag_templates = true; switch (*first) { case 'G': @@ -4258,17 +4510,23 @@ parse_encoding(const char* first, const char* last, C& db) { if (t != last && *t != 'E' && *t != '.') { - bool tag_templates = db.tag_templates; + save_value<bool> sb2(db.tag_templates); db.tag_templates = false; const char* t2; typename C::String ret2; + if (db.names.empty()) + return first; const typename C::String& nm = db.names.back().first; + if (nm.empty()) + return first; if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-' && nm[nm.size()-2] != '>') { t2 = parse_type(t, last, db); if (t2 == t) return first; + if (db.names.size() < 2) + return first; auto ret1 = std::move(db.names.back().first); ret2 = std::move(db.names.back().second); if (ret2.empty()) @@ -4305,6 +4563,8 @@ parse_encoding(const char* first, const char* last, C& db) db.names.pop_back(); if (!tmp.empty()) { + if (db.names.empty()) + return first; if (!first_arg) db.names.back().first += ", "; else @@ -4315,6 +4575,8 @@ parse_encoding(const char* first, const char* last, C& db) t = t2; } } + if (db.names.empty()) + return first; db.names.back().first += ')'; if (cv & 1) db.names.back().first.append(" const"); @@ -4328,7 +4590,6 @@ parse_encoding(const char* first, const char* last, C& db) db.names.back().first.append(" &&"); db.names.back().first += ret2; first = t; - db.tag_templates = tag_templates; } else first = t; @@ -4370,6 +4631,8 @@ parse_block_invoke(const char* first, const char* last, C& db) while (t != last && isdigit(*t)) ++t; } + if (db.names.empty()) + return first; db.names.back().first.insert(0, "invocation function for block in "); first = t; } @@ -4385,6 +4648,8 @@ parse_dot_suffix(const char* first, const char* last, C& db) { if (first != last && *first == '.') { + if (db.names.empty()) + return first; db.names.back().first += " (" + typename C::String(first, last) + ")"; first = last; } @@ -4620,6 +4885,7 @@ struct Db Vector<template_param_type> template_param; unsigned cv; unsigned ref; + unsigned encoding_depth; bool parsed_ctor_dtor_cv; bool tag_templates; bool fix_forward_references; @@ -4647,6 +4913,7 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status) Db db(a); db.cv = 0; db.ref = 0; + db.encoding_depth = 0; db.parsed_ctor_dtor_cv = false; db.tag_templates = true; db.template_param.emplace_back(a); @@ -4699,8 +4966,7 @@ __cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status) return buf; } -} // unnamed namespace - +} #endif diff --git a/contrib/llvm/tools/lldb/source/Core/Module.cpp b/contrib/llvm/tools/lldb/source/Core/Module.cpp index f90a097..d5758c0 100644 --- a/contrib/llvm/tools/lldb/source/Core/Module.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Module.cpp @@ -33,6 +33,7 @@ #include "lldb/Target/CPPLanguageRuntime.h" #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Symbol/SymbolFile.h" @@ -1499,30 +1500,19 @@ Module::SetArchitecture (const ArchSpec &new_arch) } bool -Module::SetLoadAddress (Target &target, lldb::addr_t offset, bool &changed) +Module::SetLoadAddress (Target &target, lldb::addr_t value, bool value_is_offset, bool &changed) { - size_t num_loaded_sections = 0; - SectionList *section_list = GetSectionList (); - if (section_list) + ObjectFile *object_file = GetObjectFile(); + if (object_file) { - const size_t num_sections = section_list->GetSize(); - size_t sect_idx = 0; - for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) - { - // Iterate through the object file sections to find the - // first section that starts of file offset zero and that - // has bytes in the file... - SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); - // Only load non-thread specific sections when given a slide - if (section_sp && !section_sp->IsThreadSpecific()) - { - if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + offset)) - ++num_loaded_sections; - } - } + changed = object_file->SetLoadAddress(target, value, value_is_offset); + return true; } - changed = num_loaded_sections > 0; - return num_loaded_sections > 0; + else + { + changed = false; + } + return false; } diff --git a/contrib/llvm/tools/lldb/source/Core/Opcode.cpp b/contrib/llvm/tools/lldb/source/Core/Opcode.cpp index 978a110..2bf7f5e 100644 --- a/contrib/llvm/tools/lldb/source/Core/Opcode.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Opcode.cpp @@ -71,6 +71,10 @@ Opcode::Dump (Stream *s, uint32_t min_byte_width) lldb::ByteOrder Opcode::GetDataByteOrder () const { + if (m_byte_order != eByteOrderInvalid) + { + return m_byte_order; + } switch (m_type) { case Opcode::eTypeInvalid: break; @@ -89,39 +93,66 @@ uint32_t Opcode::GetData (DataExtractor &data) const { uint32_t byte_size = GetByteSize (); + uint8_t swap_buf[8]; + const void *buf = NULL; - DataBufferSP buffer_sp; if (byte_size > 0) { - switch (m_type) + if (!GetEndianSwap()) + { + if (m_type == Opcode::eType16_2) + { + // 32 bit thumb instruction, we need to sizzle this a bit + swap_buf[0] = m_data.inst.bytes[2]; + swap_buf[1] = m_data.inst.bytes[3]; + swap_buf[2] = m_data.inst.bytes[0]; + swap_buf[3] = m_data.inst.bytes[1]; + buf = swap_buf; + } + else + { + buf = GetOpcodeDataBytes(); + } + } + else { - case Opcode::eTypeInvalid: - break; - - case Opcode::eType8: buffer_sp.reset (new DataBufferHeap (&m_data.inst8, byte_size)); break; - case Opcode::eType16: buffer_sp.reset (new DataBufferHeap (&m_data.inst16, byte_size)); break; - case Opcode::eType16_2: - { - // 32 bit thumb instruction, we need to sizzle this a bit - uint8_t buf[4]; - buf[0] = m_data.inst.bytes[2]; - buf[1] = m_data.inst.bytes[3]; - buf[2] = m_data.inst.bytes[0]; - buf[3] = m_data.inst.bytes[1]; - buffer_sp.reset (new DataBufferHeap (buf, byte_size)); - } - break; - case Opcode::eType32: - buffer_sp.reset (new DataBufferHeap (&m_data.inst32, byte_size)); - break; - case Opcode::eType64: buffer_sp.reset (new DataBufferHeap (&m_data.inst64, byte_size)); break; - case Opcode::eTypeBytes:buffer_sp.reset (new DataBufferHeap (GetOpcodeBytes(), byte_size)); break; - break; + switch (m_type) + { + case Opcode::eTypeInvalid: + break; + case Opcode::eType8: + buf = GetOpcodeDataBytes(); + break; + case Opcode::eType16: + *(uint16_t *)swap_buf = llvm::ByteSwap_16(m_data.inst16); + buf = swap_buf; + break; + case Opcode::eType16_2: + swap_buf[0] = m_data.inst.bytes[1]; + swap_buf[1] = m_data.inst.bytes[0]; + swap_buf[2] = m_data.inst.bytes[3]; + swap_buf[3] = m_data.inst.bytes[2]; + buf = swap_buf; + break; + case Opcode::eType32: + *(uint32_t *)swap_buf = llvm::ByteSwap_32(m_data.inst32); + buf = swap_buf; + break; + case Opcode::eType64: + *(uint32_t *)swap_buf = llvm::ByteSwap_64(m_data.inst64); + buf = swap_buf; + break; + case Opcode::eTypeBytes: + buf = GetOpcodeDataBytes(); + break; + } } } - - if (buffer_sp) + if (buf) { + DataBufferSP buffer_sp; + + buffer_sp.reset (new DataBufferHeap (buf, byte_size)); data.SetByteOrder(GetDataByteOrder()); data.SetData (buffer_sp); return byte_size; diff --git a/contrib/llvm/tools/lldb/source/Core/Section.cpp b/contrib/llvm/tools/lldb/source/Core/Section.cpp index e2a084c..28d7d93 100644 --- a/contrib/llvm/tools/lldb/source/Core/Section.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Section.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/Section.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp b/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp index 9400346..0a6a804 100644 --- a/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp +++ b/contrib/llvm/tools/lldb/source/Core/SourceManager.cpp @@ -432,6 +432,56 @@ SourceManager::File::GetLineOffset (uint32_t line) return UINT32_MAX; } +uint32_t +SourceManager::File::GetNumLines () +{ + CalculateLineOffsets(); + return m_offsets.size(); +} + +const char * +SourceManager::File::PeekLineData (uint32_t line) +{ + if (!LineIsValid(line)) + return NULL; + + size_t line_offset = GetLineOffset (line); + if (line_offset < m_data_sp->GetByteSize()) + return (const char *)m_data_sp->GetBytes() + line_offset; + return NULL; +} + +uint32_t +SourceManager::File::GetLineLength (uint32_t line, bool include_newline_chars) +{ + if (!LineIsValid(line)) + return false; + + size_t start_offset = GetLineOffset (line); + size_t end_offset = GetLineOffset (line + 1); + if (end_offset == UINT32_MAX) + end_offset = m_data_sp->GetByteSize(); + + if (end_offset > start_offset) + { + uint32_t length = end_offset - start_offset; + if (include_newline_chars == false) + { + const char *line_start = (const char *)m_data_sp->GetBytes() + start_offset; + while (length > 0) + { + const char last_char = line_start[length-1]; + if ((last_char == '\r') || (last_char == '\n')) + --length; + else + break; + } + } + return length; + } + return 0; +} + bool SourceManager::File::LineIsValid (uint32_t line) { diff --git a/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp b/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp index b9e5cdf..257982a 100644 --- a/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp +++ b/contrib/llvm/tools/lldb/source/Core/StreamAsynchronousIO.cpp @@ -28,25 +28,26 @@ StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t b StreamAsynchronousIO::~StreamAsynchronousIO () { + // Flush when we destroy to make sure we display the data + Flush(); } void StreamAsynchronousIO::Flush () { - if (m_accumulated_data.GetSize() > 0) + if (!m_accumulated_data.empty()) { std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes); // Let's swap the bytes to avoid LARGE string copies. - data_bytes_ap->SwapBytes (m_accumulated_data.GetString()); + data_bytes_ap->SwapBytes (m_accumulated_data); EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release())); m_broadcaster.BroadcastEvent (new_event_sp); - m_accumulated_data.Clear(); } } size_t StreamAsynchronousIO::Write (const void *s, size_t length) { - m_accumulated_data.Write (s, length); + m_accumulated_data.append ((const char *)s, length); return length; } diff --git a/contrib/llvm/tools/lldb/source/Core/StringList.cpp b/contrib/llvm/tools/lldb/source/Core/StringList.cpp index 9949751..d2fa8cf 100644 --- a/contrib/llvm/tools/lldb/source/Core/StringList.cpp +++ b/contrib/llvm/tools/lldb/source/Core/StringList.cpp @@ -56,6 +56,12 @@ StringList::AppendString (const std::string &s) } void +StringList::AppendString (std::string &&s) +{ + m_strings.push_back (s); +} + +void StringList::AppendString (const char *str, size_t str_len) { if (str) @@ -93,6 +99,20 @@ StringList::GetSize () const return m_strings.size(); } +size_t +StringList::GetMaxStringLength () const +{ + size_t max_length = 0; + for (const auto &s : m_strings) + { + const size_t len = s.size(); + if (max_length < len) + max_length = len; + } + return max_length; +} + + const char * StringList::GetStringAtIndex (size_t idx) const { @@ -126,37 +146,39 @@ StringList::Clear () void StringList::LongestCommonPrefix (std::string &common_prefix) { - //arg_sstr_collection::iterator pos, end = m_args.end(); - size_t pos = 0; - size_t end = m_strings.size(); + const size_t num_strings = m_strings.size(); - if (pos == end) + if (num_strings == 0) + { common_prefix.clear(); + } else - common_prefix = m_strings[pos]; - - for (++pos; pos != end; ++pos) { - size_t new_size = strlen (m_strings[pos].c_str()); + common_prefix = m_strings.front(); - // First trim common_prefix if it is longer than the current element: - if (common_prefix.size() > new_size) - common_prefix.erase (new_size); + for (size_t idx = 1; idx < num_strings; ++idx) + { + std::string &curr_string = m_strings[idx]; + size_t new_size = curr_string.size(); - // Then trim it at the first disparity: + // First trim common_prefix if it is longer than the current element: + if (common_prefix.size() > new_size) + common_prefix.erase (new_size); - for (size_t i = 0; i < common_prefix.size(); i++) - { - if (m_strings[pos][i] != common_prefix[i]) + // Then trim it at the first disparity: + for (size_t i = 0; i < common_prefix.size(); i++) { - common_prefix.erase(i); - break; + if (curr_string[i] != common_prefix[i]) + { + common_prefix.erase(i); + break; + } } - } - // If we've emptied the common prefix, we're done. - if (common_prefix.empty()) - break; + // If we've emptied the common prefix, we're done. + if (common_prefix.empty()) + break; + } } } @@ -173,6 +195,24 @@ StringList::InsertStringAtIndex (size_t idx, const char *str) } void +StringList::InsertStringAtIndex (size_t idx, const std::string &str) +{ + if (idx < m_strings.size()) + m_strings.insert (m_strings.begin() + idx, str); + else + m_strings.push_back (str); +} + +void +StringList::InsertStringAtIndex (size_t idx, std::string &&str) +{ + if (idx < m_strings.size()) + m_strings.insert (m_strings.begin() + idx, str); + else + m_strings.push_back (str); +} + +void StringList::DeleteStringAtIndex (size_t idx) { if (idx < m_strings.size()) @@ -180,6 +220,12 @@ StringList::DeleteStringAtIndex (size_t idx) } size_t +StringList::SplitIntoLines (const std::string &lines) +{ + return SplitIntoLines (lines.c_str(), lines.size()); +} + +size_t StringList::SplitIntoLines (const char *lines, size_t len) { const size_t orig_size = m_strings.size(); @@ -231,8 +277,7 @@ StringList::RemoveBlankLines () } std::string -StringList::CopyList(const char* item_preamble, - const char* items_sep) +StringList::CopyList(const char* item_preamble, const char* items_sep) const { StreamString strm; for (size_t i = 0; i < GetSize(); i++) diff --git a/contrib/llvm/tools/lldb/source/Core/Value.cpp b/contrib/llvm/tools/lldb/source/Core/Value.cpp index 9dd72c7..9d42a37 100644 --- a/contrib/llvm/tools/lldb/source/Core/Value.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Value.cpp @@ -26,6 +26,7 @@ #include "lldb/Symbol/Variable.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp index d39d21a..10e5ab4 100644 --- a/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp +++ b/contrib/llvm/tools/lldb/source/Core/ValueObject.cpp @@ -50,6 +50,7 @@ #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -977,14 +978,14 @@ ValueObject::GetPointeeData (DataExtractor& data, ValueObjectSP pointee_sp = Dereference(error); if (error.Fail() || pointee_sp.get() == NULL) return 0; - return pointee_sp->GetDataExtractor().Copy(data); + return pointee_sp->GetData(data); } else { ValueObjectSP child_sp = GetChildAtIndex(0, true); if (child_sp.get() == NULL) return 0; - return child_sp->GetDataExtractor().Copy(data); + return child_sp->GetData(data); } return true; } @@ -1388,99 +1389,33 @@ ValueObject::GetObjectDescription () } bool -ValueObject::GetValueAsCString (lldb::Format format, +ValueObject::GetValueAsCString (const lldb_private::TypeFormatImpl& format, std::string& destination) { - if (GetClangType().IsAggregateType () == false && UpdateValueIfNeeded(false)) - { - const Value::ContextType context_type = m_value.GetContextType(); - - if (context_type == Value::eContextTypeRegisterInfo) - { - const RegisterInfo *reg_info = m_value.GetRegisterInfo(); - if (reg_info) - { - ExecutionContext exe_ctx (GetExecutionContextRef()); - - StreamString reg_sstr; - m_data.Dump (®_sstr, - 0, - format, - reg_info->byte_size, - 1, - UINT32_MAX, - LLDB_INVALID_ADDRESS, - 0, - 0, - exe_ctx.GetBestExecutionContextScope()); - destination.swap(reg_sstr.GetString()); - } - } - else - { - ClangASTType clang_type = GetClangType (); - if (clang_type) - { - // put custom bytes to display in this DataExtractor to override the default value logic - lldb_private::DataExtractor special_format_data; - if (format == eFormatCString) - { - Flags type_flags(clang_type.GetTypeInfo(NULL)); - if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC)) - { - // if we are dumping a pointer as a c-string, get the pointee data as a string - TargetSP target_sp(GetTargetSP()); - if (target_sp) - { - size_t max_len = target_sp->GetMaximumSizeOfStringSummary(); - Error error; - DataBufferSP buffer_sp(new DataBufferHeap(max_len+1,0)); - Address address(GetPointerValue()); - if (target_sp->ReadCStringFromMemory(address, (char*)buffer_sp->GetBytes(), max_len, error) && error.Success()) - special_format_data.SetData(buffer_sp); - } - } - } - - StreamString sstr; - ExecutionContext exe_ctx (GetExecutionContextRef()); - clang_type.DumpTypeValue (&sstr, // The stream to use for display - format, // Format to display this type with - special_format_data.GetByteSize() ? - special_format_data: m_data, // Data to extract from - 0, // Byte offset into "m_data" - GetByteSize(), // Byte size of item in "m_data" - GetBitfieldBitSize(), // Bitfield bit size - GetBitfieldBitOffset(), // Bitfield bit offset - exe_ctx.GetBestExecutionContextScope()); - // Don't set the m_error to anything here otherwise - // we won't be able to re-format as anything else. The - // code for ClangASTType::DumpTypeValue() should always - // return something, even if that something contains - // an error messsage. "m_error" is used to detect errors - // when reading the valid object, not for formatting errors. - if (sstr.GetString().empty()) - destination.clear(); - else - destination.swap(sstr.GetString()); - } - } - return !destination.empty(); - } + if (UpdateValueIfNeeded(false)) + return format.FormatObject(this,destination); else return false; } +bool +ValueObject::GetValueAsCString (lldb::Format format, + std::string& destination) +{ + return GetValueAsCString(TypeFormatImpl_Format(format),destination); +} + const char * ValueObject::GetValueAsCString () { if (UpdateValueIfNeeded(true)) { + lldb::TypeFormatImplSP format_sp; lldb::Format my_format = GetFormat(); if (my_format == lldb::eFormatDefault) { if (m_type_format_sp) - my_format = m_type_format_sp->GetFormat(); + format_sp = m_type_format_sp; else { if (m_is_bitfield_for_scalar) @@ -1503,7 +1438,9 @@ ValueObject::GetValueAsCString () if (my_format != m_last_format || m_value_str.empty()) { m_last_format = my_format; - if (GetValueAsCString(my_format, m_value_str)) + if (!format_sp) + format_sp.reset(new TypeFormatImpl_Format(my_format)); + if (GetValueAsCString(*format_sp.get(), m_value_str)) { if (!m_value_did_change && m_old_value_valid) { @@ -1609,7 +1546,8 @@ bool ValueObject::DumpPrintableRepresentation(Stream& s, ValueObjectRepresentationStyle val_obj_display, Format custom_format, - PrintableRepresentationSpecialCases special) + PrintableRepresentationSpecialCases special, + bool do_dump_error) { Flags flags(GetTypeInfo()); @@ -1808,7 +1746,12 @@ ValueObject::DumpPrintableRepresentation(Stream& s, else { if (m_error.Fail()) - s.Printf("<%s>", m_error.AsCString()); + { + if (do_dump_error) + s.Printf("<%s>", m_error.AsCString()); + else + return false; + } else if (val_obj_display == eValueObjectRepresentationStyleSummary) s.PutCString("<no summary available>"); else if (val_obj_display == eValueObjectRepresentationStyleValue) @@ -3515,7 +3458,8 @@ ValueObject::CreateConstantValue (const ConstString &name) if (!valobj_sp) { - valobj_sp = ValueObjectConstResult::Create (NULL, m_error); + ExecutionContext exe_ctx (GetExecutionContextRef()); + valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), m_error); } return valobj_sp; } @@ -3769,7 +3713,8 @@ ValueObject::EvaluationPoint::SyncWithProcessState() { // Start with the target, if it is NULL, then we're obviously not going to get any further: - ExecutionContext exe_ctx(m_exe_ctx_ref.Lock()); + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx(m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped)); if (exe_ctx.GetTargetPtr() == NULL) return false; diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp index 23add1c..ccf87cd 100644 --- a/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp +++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectChild.cpp @@ -206,8 +206,12 @@ ValueObjectChild::UpdateValue () if (m_error.Success()) { - ExecutionContext exe_ctx (GetExecutionContextRef().Lock()); - m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx (GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); + if (GetClangType().GetTypeInfo() & ClangASTType::eTypeHasValue) + m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); + else + m_error.Clear(); // No value so nothing to read... } } else diff --git a/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp b/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp index 3d8b07a..2e5bb22 100644 --- a/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp +++ b/contrib/llvm/tools/lldb/source/Core/ValueObjectVariable.cpp @@ -328,6 +328,12 @@ ValueObjectVariable::GetLocationAsCString () bool ValueObjectVariable::SetValueFromCString (const char *value_str, Error& error) { + if (!UpdateValueIfNeeded()) + { + error.SetErrorString("unable to update value before writing"); + return false; + } + if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo) { RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo(); @@ -360,6 +366,12 @@ ValueObjectVariable::SetValueFromCString (const char *value_str, Error& error) bool ValueObjectVariable::SetData (DataExtractor &data, Error &error) { + if (!UpdateValueIfNeeded()) + { + error.SetErrorString("unable to update value before writing"); + return false; + } + if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo) { RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo(); @@ -371,7 +383,7 @@ ValueObjectVariable::SetData (DataExtractor &data, Error &error) error.SetErrorString("unable to retrieve register info"); return false; } - error = reg_value.SetValueFromData(reg_info, data, 0, false); + error = reg_value.SetValueFromData(reg_info, data, 0, true); if (error.Fail()) return false; if (reg_ctx->WriteRegister (reg_info, reg_value)) diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/DataVisualization.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/DataVisualization.cpp index 48d3517..c2c2206 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/DataVisualization.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/DataVisualization.cpp @@ -204,35 +204,35 @@ DataVisualization::Categories::GetCategoryAtIndex (size_t index) bool DataVisualization::NamedSummaryFormats::GetSummaryFormat (const ConstString &type, lldb::TypeSummaryImplSP &entry) { - return GetFormatManager().GetNamedSummaryNavigator().Get(type,entry); + return GetFormatManager().GetNamedSummaryContainer().Get(type,entry); } void DataVisualization::NamedSummaryFormats::Add (const ConstString &type, const lldb::TypeSummaryImplSP &entry) { - GetFormatManager().GetNamedSummaryNavigator().Add(FormatManager::GetValidTypeName(type),entry); + GetFormatManager().GetNamedSummaryContainer().Add(FormatManager::GetValidTypeName(type),entry); } bool DataVisualization::NamedSummaryFormats::Delete (const ConstString &type) { - return GetFormatManager().GetNamedSummaryNavigator().Delete(type); + return GetFormatManager().GetNamedSummaryContainer().Delete(type); } void DataVisualization::NamedSummaryFormats::Clear () { - GetFormatManager().GetNamedSummaryNavigator().Clear(); + GetFormatManager().GetNamedSummaryContainer().Clear(); } void DataVisualization::NamedSummaryFormats::LoopThrough (TypeSummaryImpl::SummaryCallback callback, void* callback_baton) { - GetFormatManager().GetNamedSummaryNavigator().LoopThrough(callback, callback_baton); + GetFormatManager().GetNamedSummaryContainer().LoopThrough(callback, callback_baton); } uint32_t DataVisualization::NamedSummaryFormats::GetCount () { - return GetFormatManager().GetNamedSummaryNavigator().GetCount(); + return GetFormatManager().GetNamedSummaryContainer().GetCount(); } diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp index bec2edf..751e612 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/FormatManager.cpp @@ -741,12 +741,12 @@ AddFormat (TypeCategoryImpl::SharedPointer category_sp, TypeFormatImpl::Flags flags, bool regex = false) { - lldb::TypeFormatImplSP format_sp(new TypeFormatImpl(format, flags)); + lldb::TypeFormatImplSP format_sp(new TypeFormatImpl_Format(format, flags)); if (regex) - category_sp->GetRegexValueNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),format_sp); + category_sp->GetRegexTypeFormatsContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),format_sp); else - category_sp->GetValueNavigator()->Add(type_name, format_sp); + category_sp->GetTypeFormatsContainer()->Add(type_name, format_sp); } @@ -761,9 +761,9 @@ AddStringSummary(TypeCategoryImpl::SharedPointer category_sp, string)); if (regex) - category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); + category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); else - category_sp->GetSummaryNavigator()->Add(type_name, summary_sp); + category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp); } #ifndef LLDB_DISABLE_PYTHON @@ -782,9 +782,9 @@ AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp, funct_name, code.c_str())); if (regex) - category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); + category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); else - category_sp->GetSummaryNavigator()->Add(type_name, summary_sp); + category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp); } #endif @@ -799,9 +799,9 @@ AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp, { lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description)); if (regex) - category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); + category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp); else - category_sp->GetSummaryNavigator()->Add(type_name, summary_sp); + category_sp->GetTypeSummariesContainer()->Add(type_name, summary_sp); } #endif @@ -815,9 +815,27 @@ static void AddCXXSynthetic (TypeCategoryImpl::SharedPointer category_sp, { lldb::SyntheticChildrenSP synth_sp(new CXXSyntheticChildren(flags,description,generator)); if (regex) - category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), synth_sp); + category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), synth_sp); else - category_sp->GetSyntheticNavigator()->Add(type_name,synth_sp); + category_sp->GetTypeSyntheticsContainer()->Add(type_name,synth_sp); +} +#endif + +#ifndef LLDB_DISABLE_PYTHON +static void AddFilter (TypeCategoryImpl::SharedPointer category_sp, + std::vector<std::string> children, + const char* description, + ConstString type_name, + ScriptedSyntheticChildren::Flags flags, + bool regex = false) +{ + TypeFilterImplSP filter_sp(new TypeFilterImpl(flags)); + for (auto child : children) + filter_sp->AddExpressionPath(child); + if (regex) + category_sp->GetRegexTypeFiltersContainer()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), filter_sp); + else + category_sp->GetTypeFiltersContainer()->Add(type_name,filter_sp); } #endif @@ -838,26 +856,26 @@ FormatManager::LoadLibStdcppFormatters() TypeCategoryImpl::SharedPointer gnu_category_sp = GetCategory(m_gnu_cpp_category_name); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::string"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"), std_string_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char>"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char>"), std_string_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"), std_string_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"), std_string_summary_sp); // making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*) lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}")); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::wstring"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"), std_wstring_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t>"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"), std_wstring_summary_sp); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"), std_wstring_summary_sp); @@ -866,24 +884,24 @@ FormatManager::LoadLibStdcppFormatters() SyntheticChildren::Flags stl_synth_flags; stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), + gnu_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), + gnu_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); - gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), + gnu_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true); - gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), + gnu_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), + gnu_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), + gnu_category_sp->GetRegexTypeSummariesContainer()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); @@ -891,10 +909,10 @@ FormatManager::LoadLibStdcppFormatters() AddCXXSynthetic(gnu_category_sp, lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true); - gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::vector<std::allocator<bool> >"), + gnu_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::vector<std::allocator<bool> >"), TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); - gnu_category_sp->GetSyntheticNavigator()->Add(ConstString("std::vector<std::allocator<bool> >"), + gnu_category_sp->GetTypeSyntheticsContainer()->Add(ConstString("std::vector<std::allocator<bool> >"), SyntheticChildrenSP(new CXXSyntheticChildren(stl_synth_flags,"libc++ std::vector<bool> synthetic children",lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator))); #endif @@ -921,14 +939,14 @@ FormatManager::LoadLibcxxFormatters() TypeCategoryImpl::SharedPointer libcxx_category_sp = GetCategory(m_libcxx_category_name); - libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::string"), + libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::string"), std_string_summary_sp); - libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"), + libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"), std_string_summary_sp); - libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::wstring"), + libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::wstring"), std_wstring_summary_sp); - libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"), + libcxx_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"), std_wstring_summary_sp); SyntheticChildren::Flags stl_synth_flags; @@ -943,7 +961,7 @@ FormatManager::LoadLibcxxFormatters() AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_synth_flags, true); - libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")), + libcxx_category_sp->GetRegexTypeSyntheticsContainer()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")), SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags, "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); @@ -963,13 +981,15 @@ FormatManager::LoadLibcxxFormatters() AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::unordered containers summary provider", ConstString("^(std::__1::)unordered_(multi)?(map|set)<.+> >$"), stl_summary_flags, true); stl_summary_flags.SetSkipPointers(true); - AddStringSummary(libcxx_category_sp, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true); - AddStringSummary(libcxx_category_sp, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}", ConstString("^std::__1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + + AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::weak_ptr summary provider", ConstString("^std::__1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true); AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true); + AddFilter(libcxx_category_sp, {"__a_"}, "libc++ std::atomic filter", ConstString("^std::__1::atomic<.*>$"), stl_synth_flags, true); #endif } @@ -1002,9 +1022,9 @@ FormatManager::LoadSystemFormatters() TypeCategoryImpl::SharedPointer sys_category_sp = GetCategory(m_system_category_name); - sys_category_sp->GetSummaryNavigator()->Add(ConstString("char *"), string_format); - sys_category_sp->GetSummaryNavigator()->Add(ConstString("unsigned char *"), string_format); - sys_category_sp->GetRegexSummaryNavigator()->Add(any_size_char_arr, string_array_format); + sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("char *"), string_format); + sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("unsigned char *"), string_format); + sys_category_sp->GetRegexTypeSummariesContainer()->Add(any_size_char_arr, string_array_format); lldb::TypeSummaryImplSP ostype_summary(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false) .SetSkipPointers(true) @@ -1015,10 +1035,10 @@ FormatManager::LoadSystemFormatters() .SetHideItemNames(false), "${var%O}")); - sys_category_sp->GetSummaryNavigator()->Add(ConstString("OSType"), ostype_summary); + sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("OSType"), ostype_summary); #ifndef LLDB_DISABLE_PYTHON - // FIXME because of a bug in the FormatNavigator we need to add a summary for both X* and const X* (<rdar://problem/12717717>) + // FIXME because of a bug in the FormattersContainer we need to add a summary for both X* and const X* (<rdar://problem/12717717>) AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "char16_t * summary provider", ConstString("char16_t *"), string_flags); AddCXXSummary(sys_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags); @@ -1065,11 +1085,11 @@ FormatManager::LoadObjCFormatters() TypeCategoryImpl::SharedPointer objc_category_sp = GetCategory(m_objc_category_name); lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider,"")); - objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL"), + objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL"), ObjC_BOOL_summary); - objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL &"), + objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL &"), ObjC_BOOL_summary); - objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL *"), + objc_category_sp->GetTypeSummariesContainer()->Add(ConstString("BOOL *"), ObjC_BOOL_summary); #ifndef LLDB_DISABLE_PYTHON @@ -1256,6 +1276,7 @@ FormatManager::LoadObjCFormatters() AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSString"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("CFStringRef"), appkit_flags); + AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("__CFString"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("CFMutableStringRef"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSMutableString"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("__NSCFConstantString"), appkit_flags); @@ -1286,7 +1307,7 @@ FormatManager::LoadObjCFormatters() AddStringSummary(appkit_category_sp,"name:${var.name%S} reason:${var.reason%S}",ConstString("NSException"),appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSNumber"), appkit_flags); - AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "CFNumberRef summary provider", ConstString("CFNumberRef"), appkit_flags); + AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "CFNumberRef summary provider", ConstString("CFNumberRef"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("__NSCFBoolean"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("__NSCFNumber"), appkit_flags); AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSCFBoolean"), appkit_flags); @@ -1306,7 +1327,7 @@ FormatManager::LoadObjCFormatters() AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("NSCalendarDate"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("NSTimeZone"), appkit_flags); - AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("CFTimeZoneRef"), appkit_flags); + AddCXXSummary(corefoundation_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("CFTimeZoneRef"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("__NSTimeZone"), appkit_flags); // CFAbsoluteTime is actually a double rather than a pointer to an object @@ -1318,7 +1339,7 @@ FormatManager::LoadObjCFormatters() AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", ConstString("NSIndexSet"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", ConstString("NSMutableIndexSet"), appkit_flags); - AddStringSummary(appkit_category_sp, + AddStringSummary(corefoundation_category_sp, "@\"${var.month%d}/${var.day%d}/${var.year%d} ${var.hour%d}:${var.minute%d}:${var.second}\"", ConstString("CFGregorianDate"), appkit_flags); diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/LibCxx.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/LibCxx.cpp index 21e1046..6380d97 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/LibCxx.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/LibCxx.cpp @@ -26,19 +26,64 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +bool +lldb_private::formatters::LibcxxSmartPointerSummaryProvider (ValueObject& valobj, Stream& stream) +{ + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath( {ConstString("__cntrl_"),ConstString("__shared_owners_")} )); + ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath( {ConstString("__cntrl_"),ConstString("__shared_weak_owners_")} )); + + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) + { + stream.Printf("nullptr"); + return true; + } + else + { + bool print_pointee = false; + Error error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) + { + if (pointee_sp->DumpPrintableRepresentation(stream, + ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::ePrintableRepresentationSpecialCasesDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + if (count_sp) + stream.Printf(" strong=%" PRIu64, 1+count_sp->GetValueAsUnsigned(0)); + + if (weakcount_sp) + stream.Printf(" weak=%" PRIu64, 1+weakcount_sp->GetValueAsUnsigned(0)); + + return true; +} + lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp.get()), +m_bool_type(), m_exe_ctx_ref(), m_count(0), m_base_data_address(0), -m_options() +m_children() { if (valobj_sp) + { Update(); - m_options.SetCoerceToId(false); - m_options.SetUnwindOnError(true); - m_options.SetKeepInMemory(true); - m_options.SetUseDynamic(lldb::eDynamicCanRunTarget); + m_bool_type = valobj_sp->GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeBool); + } } size_t @@ -50,10 +95,16 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildre lldb::ValueObjectSP lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx) { + auto iter = m_children.find(idx), + end = m_children.end(); + if (iter != end) + return iter->second; if (idx >= m_count) return ValueObjectSP(); if (m_base_data_address == 0 || m_count == 0) return ValueObjectSP(); + if (!m_bool_type) + return ValueObjectSP(); size_t byte_idx = (idx >> 3); // divide by 8 to get byte index size_t bit_index = (idx & 7); // efficient idx % 8 for bit index lldb::addr_t byte_location = m_base_data_address + byte_idx; @@ -88,15 +139,15 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si return ValueObjectSP(); } bool bit_set = ((byte & mask) != 0); - Target& target(process_sp->GetTarget()); ValueObjectSP retval_sp; - if (bit_set) - target.EvaluateExpression("(bool)true", NULL, retval_sp); - else - target.EvaluateExpression("(bool)false", NULL, retval_sp); + DataBufferSP buffer_sp(new DataBufferHeap(m_bool_type.GetByteSize(),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("[%zu]",idx); + DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); + retval_sp = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_exe_ctx_ref, m_bool_type); if (retval_sp) - retval_sp->SetName(ConstString(name.GetData())); + m_children[idx] = retval_sp; return retval_sp; } @@ -113,6 +164,7 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (si bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { + m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) return false; diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp index b73d3bf..05b41d0 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/LibCxxUnorderedMap.cpp @@ -84,7 +84,8 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtInde stream.Printf("[%zu]",idx); DataExtractor data; val_hash.first->GetData(data); - ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(); + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped); return val_hash.first->CreateValueObjectFromData(stream.GetData(), data, exe_ctx, diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp index a02560e..322d1cf 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeCategory.cpp @@ -21,15 +21,11 @@ using namespace lldb_private; TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener* clist, ConstString name) : -m_value_nav(new ValueNavigator("format",clist)), -m_regex_value_nav(new RegexValueNavigator("regex-format",clist)), -m_summary_nav(new SummaryNavigator("summary",clist)), -m_regex_summary_nav(new RegexSummaryNavigator("regex-summary",clist)), -m_filter_nav(new FilterNavigator("filter",clist)), -m_regex_filter_nav(new RegexFilterNavigator("regex-filter",clist)), +m_format_cont("format","regex-format",clist), +m_summary_cont("summary","regex-summary",clist), +m_filter_cont("filter","regex-filter",clist), #ifndef LLDB_DISABLE_PYTHON -m_synth_nav(new SynthNavigator("synth",clist)), -m_regex_synth_nav(new RegexSynthNavigator("regex-synth",clist)), +m_synth_cont("synth","regex-synth",clist), #endif m_enabled(false), m_change_listener(clist), @@ -45,9 +41,9 @@ TypeCategoryImpl::Get (ValueObject& valobj, { if (!IsEnabled()) return false; - if (GetValueNavigator()->Get(candidates, entry, reason)) + if (GetTypeFormatsContainer()->Get(candidates, entry, reason)) return true; - bool regex = GetRegexValueNavigator()->Get(candidates, entry, reason); + bool regex = GetRegexTypeFormatsContainer()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; @@ -61,9 +57,9 @@ TypeCategoryImpl::Get (ValueObject& valobj, { if (!IsEnabled()) return false; - if (GetSummaryNavigator()->Get(candidates, entry, reason)) + if (GetTypeSummariesContainer()->Get(candidates, entry, reason)) return true; - bool regex = GetRegexSummaryNavigator()->Get(candidates, entry, reason); + bool regex = GetRegexTypeSummariesContainer()->Get(candidates, entry, reason); if (regex && reason) *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary; return regex; @@ -82,16 +78,16 @@ TypeCategoryImpl::Get (ValueObject& valobj, bool regex_filter = false; // first find both Filter and Synth, and then check which is most recent - if (!GetFilterNavigator()->Get(candidates, filter_sp, &reason_filter)) - regex_filter = GetRegexFilterNavigator()->Get (candidates, filter_sp, &reason_filter); + if (!GetTypeFiltersContainer()->Get(candidates, filter_sp, &reason_filter)) + regex_filter = GetRegexTypeFiltersContainer()->Get (candidates, filter_sp, &reason_filter); #ifndef LLDB_DISABLE_PYTHON bool regex_synth = false; uint32_t reason_synth = 0; bool pick_synth = false; ScriptedSyntheticChildren::SharedPointer synth; - if (!GetSyntheticNavigator()->Get(candidates, synth, &reason_synth)) - regex_synth = GetRegexSyntheticNavigator()->Get (candidates, synth, &reason_synth); + if (!GetTypeSyntheticsContainer()->Get(candidates, synth, &reason_synth)) + regex_synth = GetRegexTypeSyntheticsContainer()->Get (candidates, synth, &reason_synth); if (!filter_sp.get() && !synth.get()) return false; else if (!filter_sp.get() && synth.get()) @@ -137,25 +133,25 @@ void TypeCategoryImpl::Clear (FormatCategoryItems items) { if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue ) - m_value_nav->Clear(); + GetTypeFormatsContainer()->Clear(); if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue ) - m_regex_value_nav->Clear(); + GetRegexTypeFormatsContainer()->Clear(); if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary ) - m_summary_nav->Clear(); + GetTypeSummariesContainer()->Clear(); if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary ) - m_regex_summary_nav->Clear(); + GetRegexTypeSummariesContainer()->Clear(); if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter ) - m_filter_nav->Clear(); + GetTypeFiltersContainer()->Clear(); if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter ) - m_regex_filter_nav->Clear(); + GetRegexTypeFiltersContainer()->Clear(); #ifndef LLDB_DISABLE_PYTHON if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth ) - m_synth_nav->Clear(); + GetTypeSyntheticsContainer()->Clear(); if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) - m_regex_synth_nav->Clear(); + GetRegexTypeSyntheticsContainer()->Clear(); #endif } @@ -166,25 +162,25 @@ TypeCategoryImpl::Delete (ConstString name, bool success = false; if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue ) - success = m_value_nav->Delete(name) || success; + success = GetTypeFormatsContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue ) - success = m_regex_value_nav->Delete(name) || success; + success = GetRegexTypeFormatsContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary ) - success = m_summary_nav->Delete(name) || success; + success = GetTypeSummariesContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary ) - success = m_regex_summary_nav->Delete(name) || success; + success = GetRegexTypeSummariesContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter ) - success = m_filter_nav->Delete(name) || success; + success = GetTypeFiltersContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter ) - success = m_regex_filter_nav->Delete(name) || success; + success = GetRegexTypeFiltersContainer()->Delete(name) || success; #ifndef LLDB_DISABLE_PYTHON if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth ) - success = m_synth_nav->Delete(name) || success; + success = GetTypeSyntheticsContainer()->Delete(name) || success; if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) - success = m_regex_synth_nav->Delete(name) || success; + success = GetRegexTypeSyntheticsContainer()->Delete(name) || success; #endif return success; } @@ -195,25 +191,25 @@ TypeCategoryImpl::GetCount (FormatCategoryItems items) uint32_t count = 0; if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue ) - count += m_value_nav->GetCount(); + count += GetTypeFormatsContainer()->GetCount(); if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue ) - count += m_regex_value_nav->GetCount(); + count += GetRegexTypeFormatsContainer()->GetCount(); if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary ) - count += m_summary_nav->GetCount(); + count += GetTypeSummariesContainer()->GetCount(); if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary ) - count += m_regex_summary_nav->GetCount(); + count += GetRegexTypeSummariesContainer()->GetCount(); if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter ) - count += m_filter_nav->GetCount(); + count += GetTypeFiltersContainer()->GetCount(); if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter ) - count += m_regex_filter_nav->GetCount(); + count += GetRegexTypeFiltersContainer()->GetCount(); #ifndef LLDB_DISABLE_PYTHON if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth ) - count += m_synth_nav->GetCount(); + count += GetTypeSyntheticsContainer()->GetCount(); if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) - count += m_regex_synth_nav->GetCount(); + count += GetRegexTypeSyntheticsContainer()->GetCount(); #endif return count; } @@ -237,7 +233,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, if ( (items & eFormatCategoryItemValue) == eFormatCategoryItemValue ) { - if (m_value_nav->Get(type_name, format_sp)) + if (GetTypeFormatsContainer()->Get(type_name, format_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -248,7 +244,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, } if ( (items & eFormatCategoryItemRegexValue) == eFormatCategoryItemRegexValue ) { - if (m_regex_value_nav->Get(type_name, format_sp)) + if (GetRegexTypeFormatsContainer()->Get(type_name, format_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -260,7 +256,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary ) { - if (m_summary_nav->Get(type_name, summary_sp)) + if (GetTypeSummariesContainer()->Get(type_name, summary_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -271,7 +267,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, } if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary ) { - if (m_regex_summary_nav->Get(type_name, summary_sp)) + if (GetRegexTypeSummariesContainer()->Get(type_name, summary_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -283,7 +279,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter ) { - if (m_filter_nav->Get(type_name, filter_sp)) + if (GetTypeFiltersContainer()->Get(type_name, filter_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -294,7 +290,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, } if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter ) { - if (m_regex_filter_nav->Get(type_name, filter_sp)) + if (GetRegexTypeFiltersContainer()->Get(type_name, filter_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -307,7 +303,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, #ifndef LLDB_DISABLE_PYTHON if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth ) { - if (m_synth_nav->Get(type_name, synth_sp)) + if (GetTypeSyntheticsContainer()->Get(type_name, synth_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -318,7 +314,7 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, } if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth ) { - if (m_regex_synth_nav->Get(type_name, synth_sp)) + if (GetRegexTypeSyntheticsContainer()->Get(type_name, synth_sp)) { if (matching_category) *matching_category = m_name.GetCString(); @@ -331,66 +327,66 @@ TypeCategoryImpl::AnyMatches(ConstString type_name, return false; } -TypeCategoryImpl::ValueNavigator::MapValueType +TypeCategoryImpl::FormatContainer::MapValueType TypeCategoryImpl::GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp) { - ValueNavigator::MapValueType retval; + FormatContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) - m_regex_value_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetRegexTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),retval); else - m_value_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetTypeFormatsContainer()->GetExact(ConstString(type_sp->GetName()),retval); } return retval; } -TypeCategoryImpl::SummaryNavigator::MapValueType +TypeCategoryImpl::SummaryContainer::MapValueType TypeCategoryImpl::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp) { - SummaryNavigator::MapValueType retval; + SummaryContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) - m_regex_summary_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetRegexTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()),retval); else - m_summary_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetTypeSummariesContainer()->GetExact(ConstString(type_sp->GetName()),retval); } return retval; } -TypeCategoryImpl::FilterNavigator::MapValueType +TypeCategoryImpl::FilterContainer::MapValueType TypeCategoryImpl::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp) { - FilterNavigator::MapValueType retval; + FilterContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) - m_regex_filter_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetRegexTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),retval); else - m_filter_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetTypeFiltersContainer()->GetExact(ConstString(type_sp->GetName()),retval); } return retval; } #ifndef LLDB_DISABLE_PYTHON -TypeCategoryImpl::SynthNavigator::MapValueType +TypeCategoryImpl::SynthContainer::MapValueType TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp) { - SynthNavigator::MapValueType retval; + SynthContainer::MapValueType retval; if (type_sp) { if (type_sp->IsRegex()) - m_regex_synth_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetRegexTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()),retval); else - m_synth_nav->GetExact(ConstString(type_sp->GetName()),retval); + GetTypeSyntheticsContainer()->GetExact(ConstString(type_sp->GetName()),retval); } return retval; @@ -400,74 +396,74 @@ TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp) lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex (size_t index) { - if (index < m_summary_nav->GetCount()) - return m_summary_nav->GetTypeNameSpecifierAtIndex(index); + if (index < GetTypeSummariesContainer()->GetCount()) + return GetTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index); else - return m_regex_summary_nav->GetTypeNameSpecifierAtIndex(index-m_summary_nav->GetCount()); + return GetRegexTypeSummariesContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeSummariesContainer()->GetCount()); } -TypeCategoryImpl::ValueNavigator::MapValueType +TypeCategoryImpl::FormatContainer::MapValueType TypeCategoryImpl::GetFormatAtIndex (size_t index) { - if (index < m_value_nav->GetCount()) - return m_value_nav->GetAtIndex(index); + if (index < GetTypeFormatsContainer()->GetCount()) + return GetTypeFormatsContainer()->GetAtIndex(index); else - return m_regex_value_nav->GetAtIndex(index-m_value_nav->GetCount()); + return GetRegexTypeFormatsContainer()->GetAtIndex(index-GetTypeFormatsContainer()->GetCount()); } -TypeCategoryImpl::SummaryNavigator::MapValueType +TypeCategoryImpl::SummaryContainer::MapValueType TypeCategoryImpl::GetSummaryAtIndex (size_t index) { - if (index < m_summary_nav->GetCount()) - return m_summary_nav->GetAtIndex(index); + if (index < GetTypeSummariesContainer()->GetCount()) + return GetTypeSummariesContainer()->GetAtIndex(index); else - return m_regex_summary_nav->GetAtIndex(index-m_summary_nav->GetCount()); + return GetRegexTypeSummariesContainer()->GetAtIndex(index-GetTypeSummariesContainer()->GetCount()); } -TypeCategoryImpl::FilterNavigator::MapValueType +TypeCategoryImpl::FilterContainer::MapValueType TypeCategoryImpl::GetFilterAtIndex (size_t index) { - if (index < m_filter_nav->GetCount()) - return m_filter_nav->GetAtIndex(index); + if (index < GetTypeFiltersContainer()->GetCount()) + return GetTypeFiltersContainer()->GetAtIndex(index); else - return m_regex_filter_nav->GetAtIndex(index-m_filter_nav->GetCount()); + return GetRegexTypeFiltersContainer()->GetAtIndex(index-GetTypeFiltersContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForFormatAtIndex (size_t index) { - if (index < m_value_nav->GetCount()) - return m_value_nav->GetTypeNameSpecifierAtIndex(index); + if (index < GetTypeFormatsContainer()->GetCount()) + return GetTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index); else - return m_regex_value_nav->GetTypeNameSpecifierAtIndex(index-m_value_nav->GetCount()); + return GetRegexTypeFormatsContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeFormatsContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex (size_t index) { - if (index < m_filter_nav->GetCount()) - return m_filter_nav->GetTypeNameSpecifierAtIndex(index); + if (index < GetTypeFiltersContainer()->GetCount()) + return GetTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index); else - return m_regex_filter_nav->GetTypeNameSpecifierAtIndex(index-m_filter_nav->GetCount()); + return GetRegexTypeFiltersContainer()->GetTypeNameSpecifierAtIndex(index-GetTypeFiltersContainer()->GetCount()); } #ifndef LLDB_DISABLE_PYTHON -TypeCategoryImpl::SynthNavigator::MapValueType +TypeCategoryImpl::SynthContainer::MapValueType TypeCategoryImpl::GetSyntheticAtIndex (size_t index) { - if (index < m_synth_nav->GetCount()) - return m_synth_nav->GetAtIndex(index); + if (index < GetTypeSyntheticsContainer()->GetCount()) + return GetTypeSyntheticsContainer()->GetAtIndex(index); else - return m_regex_synth_nav->GetAtIndex(index-m_synth_nav->GetCount()); + return GetRegexTypeSyntheticsContainer()->GetAtIndex(index-GetTypeSyntheticsContainer()->GetCount()); } lldb::TypeNameSpecifierImplSP TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex (size_t index) { - if (index < m_synth_nav->GetCount()) - return m_synth_nav->GetTypeNameSpecifierAtIndex(index); + if (index < GetTypeSyntheticsContainer()->GetCount()) + return GetTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index); else - return m_regex_synth_nav->GetTypeNameSpecifierAtIndex(index - m_synth_nav->GetCount()); + return GetRegexTypeSyntheticsContainer()->GetTypeNameSpecifierAtIndex(index - GetTypeSyntheticsContainer()->GetCount()); } #endif diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp index 7f18dde..a72f551 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/TypeFormat.cpp @@ -25,21 +25,117 @@ #include "lldb/DataFormatters/TypeFormat.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Symbol/ClangASTType.h" +#include "lldb/Symbol/TypeList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; -TypeFormatImpl::TypeFormatImpl (lldb::Format f, - const Flags& flags) : +TypeFormatImpl::TypeFormatImpl (const Flags& flags) : m_flags(flags), +m_my_revision(0) +{ +} + + +TypeFormatImpl_Format::TypeFormatImpl_Format (lldb::Format f, + const TypeFormatImpl::Flags& flags) : +TypeFormatImpl(flags), m_format (f) { } +bool +TypeFormatImpl_Format::FormatObject (ValueObject *valobj, + std::string& dest) const +{ + if (!valobj) + return false; + if (valobj->GetClangType().IsAggregateType () == false) + { + const Value& value(valobj->GetValue()); + const Value::ContextType context_type = value.GetContextType(); + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + DataExtractor data; + + if (context_type == Value::eContextTypeRegisterInfo) + { + const RegisterInfo *reg_info = value.GetRegisterInfo(); + if (reg_info) + { + valobj->GetData(data); + + StreamString reg_sstr; + data.Dump (®_sstr, + 0, + GetFormat(), + reg_info->byte_size, + 1, + UINT32_MAX, + LLDB_INVALID_ADDRESS, + 0, + 0, + exe_ctx.GetBestExecutionContextScope()); + dest.swap(reg_sstr.GetString()); + } + } + else + { + ClangASTType clang_type = valobj->GetClangType (); + if (clang_type) + { + // put custom bytes to display in the DataExtractor to override the default value logic + if (GetFormat() == eFormatCString) + { + lldb_private::Flags type_flags(clang_type.GetTypeInfo(NULL)); // disambiguate w.r.t. TypeFormatImpl::Flags + if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC)) + { + // if we are dumping a pointer as a c-string, get the pointee data as a string + TargetSP target_sp(valobj->GetTargetSP()); + if (target_sp) + { + size_t max_len = target_sp->GetMaximumSizeOfStringSummary(); + Error error; + DataBufferSP buffer_sp(new DataBufferHeap(max_len+1,0)); + Address address(valobj->GetPointerValue()); + if (target_sp->ReadCStringFromMemory(address, (char*)buffer_sp->GetBytes(), max_len, error) && error.Success()) + data.SetData(buffer_sp); + } + } + } + else + valobj->GetData(data); + + StreamString sstr; + clang_type.DumpTypeValue (&sstr, // The stream to use for display + GetFormat(), // Format to display this type with + data, // Data to extract from + 0, // Byte offset into "m_data" + valobj->GetByteSize(), // Byte size of item in "m_data" + valobj->GetBitfieldBitSize(), // Bitfield bit size + valobj->GetBitfieldBitOffset(), // Bitfield bit offset + exe_ctx.GetBestExecutionContextScope()); + // Given that we do not want to set the ValueObject's m_error + // for a formatting error (or else we wouldn't be able to reformat + // until a next update), an empty string is treated as a "false" + // return from here, but that's about as severe as we get + // ClangASTType::DumpTypeValue() should always return + // something, even if that something is an error message + if (sstr.GetString().empty()) + dest.clear(); + else + dest.swap(sstr.GetString()); + } + } + return !dest.empty(); + } + else + return false; +} + std::string -TypeFormatImpl::GetDescription() +TypeFormatImpl_Format::GetDescription() { StreamString sstr; sstr.Printf ("%s%s%s%s", @@ -50,3 +146,87 @@ TypeFormatImpl::GetDescription() return sstr.GetString(); } +TypeFormatImpl_EnumType::TypeFormatImpl_EnumType (ConstString type_name, + const TypeFormatImpl::Flags& flags) : +TypeFormatImpl(flags), +m_enum_type(type_name), +m_types() +{ +} + +bool +TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj, + std::string& dest) const +{ + dest.clear(); + if (!valobj) + return false; + if (valobj->GetClangType().IsAggregateType ()) + return false; + ProcessSP process_sp; + TargetSP target_sp; + void* valobj_key = (process_sp = valobj->GetProcessSP()).get(); + if (!valobj_key) + valobj_key = (target_sp = valobj->GetTargetSP()).get(); + else + target_sp = process_sp->GetTarget().shared_from_this(); + if (!valobj_key) + return false; + auto iter = m_types.find(valobj_key), + end = m_types.end(); + ClangASTType valobj_enum_type; + if (iter == end) + { + // probably a redundant check + if (!target_sp) + return false; + const ModuleList& images(target_sp->GetImages()); + SymbolContext sc; + TypeList types; + images.FindTypes(sc, m_enum_type, false, UINT32_MAX, types); + if (types.GetSize() == 0) + return false; + for (lldb::TypeSP type_sp : types.Types()) + { + if (!type_sp) + continue; + if ( (type_sp->GetClangForwardType().GetTypeInfo() & ClangASTType::eTypeIsEnumeration) == ClangASTType::eTypeIsEnumeration) + { + valobj_enum_type = type_sp->GetClangFullType(); + m_types.emplace(valobj_key,valobj_enum_type); + break; + } + } + } + else + valobj_enum_type = iter->second; + if (valobj_enum_type.IsValid() == false) + return false; + DataExtractor data; + valobj->GetData(data); + ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); + StreamString sstr; + valobj_enum_type.DumpTypeValue(&sstr, + lldb::eFormatEnum, + data, + 0, + data.GetByteSize(), + 0, + 0, + exe_ctx.GetBestExecutionContextScope()); + if (!sstr.GetString().empty()) + dest.swap(sstr.GetString()); + return !dest.empty(); +} + +std::string +TypeFormatImpl_EnumType::GetDescription() +{ + StreamString sstr; + sstr.Printf ("as type %s%s%s%s", + m_enum_type.AsCString("<invalid type>"), + Cascades() ? "" : " (not cascading)", + SkipsPointers() ? " (skip pointers)" : "", + SkipsReferences() ? " (skip references)" : ""); + return sstr.GetString(); +} diff --git a/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 5c7f48b..944d6d2 100644 --- a/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/contrib/llvm/tools/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -403,7 +403,6 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, // Use a new temporary pointer depth in case we override the // current pointer depth below... - uint32_t curr_ptr_depth = m_ptr_depth; if (is_ptr || is_ref) { @@ -413,7 +412,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, if (m_valobj->GetPointerValue (&ptr_address_type) == 0) return false; - else if (is_ref && m_curr_depth == 0) + else if (is_ref && m_curr_depth == 0 && curr_ptr_depth == 0) { // If this is the root object (depth is zero) that we are showing // and it is a reference, and no pointer depth has been supplied @@ -468,7 +467,7 @@ ValueObjectPrinter::PrintChild (ValueObjectSP child_sp, ValueObjectPrinter child_printer(child_sp.get(), m_stream, child_options, - (IsPtr() || IsRef()) ? curr_ptr_depth - 1 : curr_ptr_depth, + (IsPtr() || IsRef()) && curr_ptr_depth >= 1 ? curr_ptr_depth - 1 : curr_ptr_depth, m_curr_depth + 1); child_printer.PrintValueObject(); } diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp index 316efdf9..23bca54 100644 --- a/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/ClangASTSource.cpp @@ -318,6 +318,10 @@ ClangASTSource::CompleteType (clang::ObjCInterfaceDecl *interface_decl) m_ast_importer->CompleteObjCInterfaceDecl (interface_decl); + if (interface_decl->getSuperClass() && + interface_decl->getSuperClass() != interface_decl) + CompleteType(interface_decl->getSuperClass()); + if (log) { log->Printf(" [COID] After:"); @@ -970,6 +974,9 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context) } ss.Flush(); + if (strstr(ss.GetData(), "$__lldb")) + return; // we don't need any results + ConstString selector_name(ss.GetData()); if (log) diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp index 87c984d..198fde9 100644 --- a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -1428,6 +1428,10 @@ ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context, if (data_symbol) { + std::string warning("got name from symbols: "); + warning.append(name.AsCString()); + const unsigned diag_id = m_ast_context->getDiagnostics().getCustomDiagID(clang::DiagnosticsEngine::Level::Warning, "%0"); + m_ast_context->getDiagnostics().Report(diag_id) << warning.c_str(); AddOneGenericVariable(context, *data_symbol, current_id); context.m_found.variable = true; } @@ -1605,6 +1609,8 @@ ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP v { if (const TagType *tag_type = dyn_cast<TagType>(parser_type)) CompleteType(tag_type->getDecl()); + if (const ObjCObjectPointerType *objc_object_ptr_type = dyn_cast<ObjCObjectPointerType>(parser_type)) + CompleteType(objc_object_ptr_type->getInterfaceDecl()); } diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp index f0de1ed..615f29f 100644 --- a/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/ClangExpressionParser.cpp @@ -16,6 +16,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Expression/ClangASTSource.h" #include "lldb/Expression/ClangExpression.h" @@ -35,7 +36,6 @@ #include "clang/Basic/Version.h" #include "clang/CodeGen/CodeGenAction.h" #include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Driver/CC1Options.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" @@ -506,7 +506,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr, Stream *error_stream = NULL; Target *target = exe_ctx.GetTargetPtr(); if (target) - error_stream = &target->GetDebugger().GetErrorStream(); + error_stream = target->GetDebugger().GetErrorFile().get(); IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), diff --git a/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp index d9ecd41..6b0eee8 100644 --- a/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/ClangUserExpression.cpp @@ -1024,7 +1024,9 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, } if (result_valobj_sp.get() == NULL) - result_valobj_sp = ValueObjectConstResult::Create (NULL, error); + { + result_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(), error); + } return execution_results; } diff --git a/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp index b36be8e..28aa6d0 100644 --- a/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/DWARFExpression.cpp @@ -1429,6 +1429,12 @@ DWARFExpression::Evaluate //---------------------------------------------------------------------- case DW_OP_deref: { + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack empty for DW_OP_deref."); + return false; + } Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) { @@ -1504,6 +1510,12 @@ DWARFExpression::Evaluate //---------------------------------------------------------------------- case DW_OP_deref_size: { + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack empty for DW_OP_deref_size."); + return false; + } uint8_t size = opcodes.GetU8(&offset); Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) @@ -2562,9 +2574,90 @@ DWARFExpression::Evaluate // variable a particular DWARF expression refers to. //---------------------------------------------------------------------- case DW_OP_piece: - if (error_ptr) - error_ptr->SetErrorString ("Unimplemented opcode DW_OP_piece."); - return false; + if (stack.size() < 1) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_piece."); + return false; + } + else + { + const uint64_t piece_byte_size = opcodes.GetULEB128(&offset); + switch (stack.back().GetValueType()) + { + case Value::eValueTypeScalar: + case Value::eValueTypeFileAddress: + case Value::eValueTypeLoadAddress: + case Value::eValueTypeHostAddress: + { + uint32_t bit_size = piece_byte_size * 8; + uint32_t bit_offset = 0; + if (!stack.back().GetScalar().ExtractBitfield (bit_size, bit_offset)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte scalar value.", piece_byte_size, (uint64_t)stack.back().GetScalar().GetByteSize()); + return false; + } + } + break; + + case Value::eValueTypeVector: + { + if (stack.back().GetVector().length >= piece_byte_size) + stack.back().GetVector().length = piece_byte_size; + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte vector value.", piece_byte_size, (uint64_t)stack.back().GetVector().length); + return false; + } + } + break; + } + } + break; + + case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3); + if (stack.size() < 1) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_bit_piece."); + return false; + } + else + { + const uint64_t piece_bit_size = opcodes.GetULEB128(&offset); + const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset); + switch (stack.back().GetValueType()) + { + case Value::eValueTypeScalar: + case Value::eValueTypeFileAddress: + case Value::eValueTypeLoadAddress: + case Value::eValueTypeHostAddress: + { + if (!stack.back().GetScalar().ExtractBitfield (piece_bit_size, piece_bit_offset)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bit value with %" PRIu64 " bit offset from a %" PRIu64 " bit scalar value.", + piece_bit_size, + piece_bit_offset, + (uint64_t)(stack.back().GetScalar().GetByteSize()*8)); + return false; + } + } + break; + + case Value::eValueTypeVector: + if (error_ptr) + { + error_ptr->SetErrorStringWithFormat ("unable to extract %" PRIu64 " bit value with %" PRIu64 " bit offset from a vector value.", + piece_bit_size, + piece_bit_offset); + } + return false; + } + } + break; //---------------------------------------------------------------------- // OPCODE: DW_OP_push_object_address diff --git a/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp index 4030f14..a75a0fc 100644 --- a/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/IRDynamicChecks.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" @@ -145,7 +146,8 @@ public: DynamicCheckerFunctions &checker_functions) : m_module(module), m_checker_functions(checker_functions), - m_i8ptr_ty(NULL) + m_i8ptr_ty(NULL), + m_intptr_ty(NULL) { } @@ -279,9 +281,6 @@ protected: //------------------------------------------------------------------ llvm::Value *BuildPointerValidatorFunc(lldb::addr_t start_address) { - IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(), - (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32); - llvm::Type *param_array[1]; param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy()); @@ -290,7 +289,7 @@ protected: FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true); PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty); - Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false); + Constant *fun_addr_int = ConstantInt::get(GetIntptrTy(), start_address, false); return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty); } @@ -306,9 +305,6 @@ protected: //------------------------------------------------------------------ llvm::Value *BuildObjectCheckerFunc(lldb::addr_t start_address) { - IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(), - (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32); - llvm::Type *param_array[2]; param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy()); @@ -318,7 +314,7 @@ protected: FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true); PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty); - Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false); + Constant *fun_addr_int = ConstantInt::get(GetIntptrTy(), start_address, false); return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty); } @@ -330,6 +326,18 @@ protected: return m_i8ptr_ty; } + IntegerType *GetIntptrTy() + { + if (!m_intptr_ty) + { + llvm::DataLayout data_layout(&m_module); + + m_intptr_ty = llvm::Type::getIntNTy(m_module.getContext(), data_layout.getPointerSizeInBits()); + } + + return m_intptr_ty; + } + typedef std::vector <llvm::Instruction *> InstVector; typedef InstVector::iterator InstIterator; @@ -338,6 +346,7 @@ protected: DynamicCheckerFunctions &m_checker_functions; ///< The dynamic checker functions for the process private: PointerType *m_i8ptr_ty; + IntegerType *m_intptr_ty; }; class ValidPointerChecker : public Instrumenter diff --git a/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp index 104732a..17bd03a 100644 --- a/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/IRExecutionUnit.cpp @@ -75,12 +75,7 @@ IRExecutionUnit::WriteNow (const uint8_t *bytes, if (err.Success()) { DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8); - - StreamString ss; - - my_extractor.Dump(&ss, 0, lldb::eFormatBytesWithASCII, 1, my_buffer.GetByteSize(), 32, allocation_process_addr, 0, 0); - - log->PutCString(ss.GetData()); + my_extractor.PutToLog(log, 0, my_buffer.GetByteSize(), allocation_process_addr, 16, DataExtractor::TypeUInt8); } } @@ -243,6 +238,8 @@ IRExecutionUnit::GetRunnableInfo(Error &error, { lldb::ProcessSP process_sp(GetProcessWP().lock()); + static Mutex s_runnable_info_mutex(Mutex::Type::eMutexTypeRecursive); + func_addr = LLDB_INVALID_ADDRESS; func_end = LLDB_INVALID_ADDRESS; @@ -261,6 +258,8 @@ IRExecutionUnit::GetRunnableInfo(Error &error, return; }; + Mutex::Locker runnable_info_mutex_locker(s_runnable_info_mutex); + m_did_jit = true; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -394,6 +393,25 @@ IRExecutionUnit::GetRunnableInfo(Error &error, { log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); } + + log->Printf("Sections: "); + for (AllocationRecord &record : m_records) + { + if (record.m_process_address != LLDB_INVALID_ADDRESS) + { + record.dump(log); + + DataBufferHeap my_buffer(record.m_size, 0); + Error err; + ReadMemory(my_buffer.GetBytes(), record.m_process_address, record.m_size, err); + + if (err.Success()) + { + DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8); + my_extractor.PutToLog(log, 0, my_buffer.GetByteSize(), record.m_process_address, 16, DataExtractor::TypeUInt8); + } + } + } } func_addr = m_function_load_addr; diff --git a/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp b/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp index d68dc00..a998896 100644 --- a/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/IRForTarget.cpp @@ -105,6 +105,7 @@ IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map, m_data_allocator(execution_unit), m_CFStringCreateWithBytes(NULL), m_sel_registerName(NULL), + m_intptr_ty(NULL), m_error_stream(error_stream), m_result_store(NULL), m_result_is_pointer(false), @@ -285,10 +286,8 @@ llvm::Constant * IRForTarget::BuildFunctionPointer (llvm::Type *type, uint64_t ptr) { - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32); PointerType *fun_ptr_ty = PointerType::getUnqual(type); - Constant *fun_addr_int = ConstantInt::get(intptr_ty, ptr, false); + Constant *fun_addr_int = ConstantInt::get(m_intptr_ty, ptr, false); return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty); } @@ -726,9 +725,6 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, Type *ns_str_ty = ns_str->getType(); Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext()); - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() - == Module::Pointer64) ? 64 : 32); Type *i32_ty = Type::getInt32Ty(m_module->getContext()); Type *i8_ty = Type::getInt8Ty(m_module->getContext()); @@ -775,7 +771,7 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, arg_type_array[0] = i8_ptr_ty; arg_type_array[1] = i8_ptr_ty; - arg_type_array[2] = intptr_ty; + arg_type_array[2] = m_intptr_ty; arg_type_array[3] = i32_ty; arg_type_array[4] = i8_ty; @@ -785,7 +781,7 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, // Build the constant containing the pointer to the function PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty); - Constant *CFSCWB_addr_int = ConstantInt::get(intptr_ty, CFStringCreateWithBytes_addr, false); + Constant *CFSCWB_addr_int = ConstantInt::get(m_intptr_ty, CFStringCreateWithBytes_addr, false); m_CFStringCreateWithBytes = ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty); } @@ -796,7 +792,7 @@ IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str, Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty); Constant *bytes_arg = cstr ? ConstantExpr::getBitCast(cstr, i8_ptr_ty) : Constant::getNullValue(i8_ptr_ty); - Constant *numBytes_arg = ConstantInt::get(intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false); + Constant *numBytes_arg = ConstantInt::get(m_intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false); Constant *encoding_arg = ConstantInt::get(i32_ty, 0x0600, false); /* 0x0600 is kCFStringEncodingASCII */ Constant *isExternal_arg = ConstantInt::get(i8_ty, 0x0, false); /* 0x0 is false */ @@ -1149,10 +1145,8 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load) llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false); // Build the constant containing the pointer to the function - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32); PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type); - Constant *srN_addr_int = ConstantInt::get(intptr_ty, sel_registerName_addr, false); + Constant *srN_addr_int = ConstantInt::get(m_intptr_ty, sel_registerName_addr, false); m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty); } @@ -1599,10 +1593,8 @@ IRForTarget::HandleSymbol (Value *symbol) log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), symbol_addr); Type *symbol_type = symbol->getType(); - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32); - Constant *symbol_addr_int = ConstantInt::get(intptr_ty, symbol_addr, false); + Constant *symbol_addr_int = ConstantInt::get(m_intptr_ty, symbol_addr, false); Value *symbol_addr_ptr = ConstantExpr::getIntToPtr(symbol_addr_int, symbol_type); @@ -1680,11 +1672,7 @@ IRForTarget::HandleObjCClass(Value *classlist_reference) if (load_instructions.empty()) return false; - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() - == Module::Pointer64) ? 64 : 32); - - Constant *class_addr = ConstantInt::get(intptr_ty, (uint64_t)class_ptr); + Constant *class_addr = ConstantInt::get(m_intptr_ty, (uint64_t)class_ptr); for (LoadInst *load_instruction : load_instructions) { @@ -2499,10 +2487,7 @@ IRForTarget::ReplaceVariables (Function &llvm_function) llvm::Constant * IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset) { - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32); - - llvm::Constant *offset_int = ConstantInt::get(intptr_ty, offset); + llvm::Constant *offset_int = ConstantInt::get(m_intptr_ty, offset); llvm::Constant *offset_array[1]; @@ -2537,10 +2522,7 @@ IRForTarget::CompleteDataAllocation () if (!allocation || allocation == LLDB_INVALID_ADDRESS) return false; - IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(), - (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32); - - Constant *relocated_addr = ConstantInt::get(intptr_ty, (uint64_t)allocation); + Constant *relocated_addr = ConstantInt::get(m_intptr_ty, (uint64_t)allocation); Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext())); m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast); @@ -2607,6 +2589,7 @@ IRForTarget::runOnModule (Module &llvm_module) m_module = &llvm_module; m_target_data.reset(new DataLayout(m_module)); + m_intptr_ty = llvm::Type::getIntNTy(m_module->getContext(), m_target_data->getPointerSizeInBits()); if (log) { @@ -2641,13 +2624,13 @@ IRForTarget::runOnModule (Module &llvm_module) return false; } - llvm::Type *intptr_ty = Type::getInt8Ty(m_module->getContext()); + llvm::Type *int8_ty = Type::getInt8Ty(m_module->getContext()); m_reloc_placeholder = new llvm::GlobalVariable((*m_module), - intptr_ty, + int8_ty, false /* IsConstant */, GlobalVariable::InternalLinkage, - Constant::getNullValue(intptr_ty), + Constant::getNullValue(int8_ty), "reloc_placeholder", NULL /* InsertBefore */, GlobalVariable::NotThreadLocal /* ThreadLocal */, diff --git a/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp index 8731fbe..90687c0 100644 --- a/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp +++ b/contrib/llvm/tools/lldb/source/Expression/Materializer.cpp @@ -461,7 +461,9 @@ public: } else { - lldb::addr_t addr_of_valobj = valobj_sp->GetAddressOf(); + AddressType address_type = eAddressTypeInvalid; + const bool scalar_is_load_address = false; + lldb::addr_t addr_of_valobj = valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); if (addr_of_valobj != LLDB_INVALID_ADDRESS) { Error write_error; @@ -503,6 +505,9 @@ public: size_t bit_align = m_variable_sp->GetType()->GetClangLayoutType().GetTypeBitAlign(); size_t byte_align = (bit_align + 7) / 8; + if (!byte_align) + byte_align = 1; + Error alloc_error; m_temporary_allocation = map.Malloc(data.GetByteSize(), byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error); @@ -739,6 +744,9 @@ public: size_t bit_align = m_type.GetTypeBitAlign(); size_t byte_align = (bit_align + 7) / 8; + if (!byte_align) + byte_align = 1; + Error alloc_error; m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error); diff --git a/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp new file mode 100644 index 0000000..679aadd --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Host/common/Editline.cpp @@ -0,0 +1,696 @@ +//===-- Editline.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/Editline.h" + +#include "lldb/Core/Error.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/StringList.h" +#include "lldb/Host/Host.h" + +#include <limits.h> + +using namespace lldb; +using namespace lldb_private; + +static const char k_prompt_escape_char = '\1'; + +Editline::Editline (const char *prog, // prog can't be NULL + const char *prompt, // can be NULL for no prompt + FILE *fin, + FILE *fout, + FILE *ferr) : + m_editline (NULL), + m_history (NULL), + m_history_event (), + m_program (), + m_prompt (), + m_lines_prompt (), + m_getc_buffer (), + m_getc_mutex (Mutex::eMutexTypeNormal), + m_getc_cond (), +// m_gets_mutex (Mutex::eMutexTypeNormal), + m_completion_callback (NULL), + m_completion_callback_baton (NULL), + m_line_complete_callback (NULL), + m_line_complete_callback_baton (NULL), + m_lines_command (Command::None), + m_lines_curr_line (0), + m_lines_max_line (0), + m_prompt_with_line_numbers (false), + m_getting_line (false), + m_got_eof (false), + m_interrupted (false) +{ + if (prog && prog[0]) + { + m_program = prog; + m_editline = ::el_init(prog, fin, fout, ferr); + m_history = ::history_init(); + } + else + { + m_editline = ::el_init("lldb-tmp", fin, fout, ferr); + } + if (prompt && prompt[0]) + SetPrompt (prompt); + + //::el_set (m_editline, EL_BIND, "^[[A", NULL); // Print binding for up arrow key + //::el_set (m_editline, EL_BIND, "^[[B", NULL); // Print binding for up down key + + assert (m_editline); + ::el_set (m_editline, EL_CLIENTDATA, this); + + // only defined for newer versions of editline +#ifdef EL_PROMPT_ESC + ::el_set (m_editline, EL_PROMPT_ESC, GetPromptCallback, k_prompt_escape_char); +#else + // fall back on old prompt setting code + ::el_set (m_editline, EL_PROMPT, GetPromptCallback); +#endif + ::el_set (m_editline, EL_EDITOR, "emacs"); + if (m_history) + { + ::el_set (m_editline, EL_HIST, history, m_history); + } + ::el_set (m_editline, EL_ADDFN, "lldb-complete", "Editline completion function", Editline::CallbackComplete); + ::el_set (m_editline, EL_ADDFN, "lldb-edit-prev-line", "Editline edit prev line", Editline::CallbackEditPrevLine); + ::el_set (m_editline, EL_ADDFN, "lldb-edit-next-line", "Editline edit next line", Editline::CallbackEditNextLine); + + ::el_set (m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string + ::el_set (m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. + ::el_set (m_editline, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. + ::el_set (m_editline, EL_BIND, "\t", "lldb-complete", NULL); // Bind TAB to be autocompelte + + // Source $PWD/.editrc then $HOME/.editrc + ::el_source (m_editline, NULL); + + if (m_history) + { + ::history (m_history, &m_history_event, H_SETSIZE, 800); + ::history (m_history, &m_history_event, H_SETUNIQUE, 1); + } + + // Always read through our callback function so we don't read + // stuff we aren't supposed to. This also stops the extra echoing + // that can happen when you have more input than editline can handle + // at once. + SetGetCharCallback(GetCharFromInputFileCallback); + + LoadHistory(); +} + +Editline::~Editline() +{ + SaveHistory(); + + if (m_history) + { + ::history_end (m_history); + m_history = NULL; + } + + // Disable edit mode to stop the terminal from flushing all input + // during the call to el_end() since we expect to have multiple editline + // instances in this program. + ::el_set (m_editline, EL_EDITMODE, 0); + + ::el_end(m_editline); + m_editline = NULL; +} + +void +Editline::SetGetCharCallback (GetCharCallbackType callback) +{ + ::el_set (m_editline, EL_GETCFN, callback); +} + +FileSpec +Editline::GetHistoryFile() +{ + char history_path[PATH_MAX]; + ::snprintf (history_path, sizeof(history_path), "~/.%s-history", m_program.c_str()); + return FileSpec(history_path, true); +} + +bool +Editline::LoadHistory () +{ + if (m_history) + { + FileSpec history_file(GetHistoryFile()); + if (history_file.Exists()) + ::history (m_history, &m_history_event, H_LOAD, history_file.GetPath().c_str()); + return true; + } + return false; +} + +bool +Editline::SaveHistory () +{ + if (m_history) + { + std::string history_path = GetHistoryFile().GetPath(); + ::history (m_history, &m_history_event, H_SAVE, history_path.c_str()); + return true; + } + return false; +} + + +Error +Editline::PrivateGetLine(std::string &line) +{ + Error error; + if (m_interrupted) + { + error.SetErrorString("interrupted"); + return error; + } + + line.clear(); + if (m_editline != NULL) + { + int line_len = 0; + const char *line_cstr = NULL; + // Call el_gets to prompt the user and read the user's input. +// { +// // Make sure we know when we are in el_gets() by using a mutex +// Mutex::Locker locker (m_gets_mutex); + line_cstr = ::el_gets (m_editline, &line_len); +// } + + static int save_errno = (line_len < 0) ? errno : 0; + + if (save_errno != 0) + { + error.SetError(save_errno, eErrorTypePOSIX); + } + else if (line_cstr) + { + // Decrement the length so we don't have newline characters in "line" for when + // we assign the cstr into the std::string + while (line_len > 0 && + (line_cstr[line_len - 1] == '\n' || + line_cstr[line_len - 1] == '\r')) + --line_len; + + if (line_len > 0) + { + // We didn't strip the newlines, we just adjusted the length, and + // we want to add the history item with the newlines + if (m_history) + ::history (m_history, &m_history_event, H_ENTER, line_cstr); + + // Copy the part of the c string that we want (removing the newline chars) + line.assign(line_cstr, line_len); + } + } + } + else + { + error.SetErrorString("the EditLine instance has been deleted"); + } + return error; +} + + +Error +Editline::GetLine(std::string &line) +{ + Error error; + line.clear(); + + // Set arrow key bindings for up and down arrows for single line + // mode where up and down arrows do prev/next history + ::el_set (m_editline, EL_BIND, "^[[A", "ed-prev-history", NULL); // Map up arrow + ::el_set (m_editline, EL_BIND, "^[[B", "ed-next-history", NULL); // Map down arrow + m_interrupted = false; + + if (!m_got_eof) + { + if (m_getting_line) + { + error.SetErrorString("already getting a line"); + return error; + } + if (m_lines_curr_line > 0) + { + error.SetErrorString("already getting lines"); + return error; + } + m_getting_line = true; + error = PrivateGetLine(line); + m_getting_line = false; + } + + if (m_got_eof && line.empty()) + { + // Only set the error if we didn't get an error back from PrivateGetLine() + if (error.Success()) + error.SetErrorString("end of file"); + } + + return error; +} + +size_t +Editline::Push (const char *bytes, size_t len) +{ + if (m_editline) + { + // Must NULL terminate the string for el_push() so we stick it + // into a std::string first + ::el_push(m_editline, + const_cast<char*>(std::string (bytes, len).c_str())); + return len; + } + return 0; +} + + +Error +Editline::GetLines(const std::string &end_line, StringList &lines) +{ + Error error; + if (m_getting_line) + { + error.SetErrorString("already getting a line"); + return error; + } + if (m_lines_curr_line > 0) + { + error.SetErrorString("already getting lines"); + return error; + } + + // Set arrow key bindings for up and down arrows for multiple line + // mode where up and down arrows do edit prev/next line + ::el_set (m_editline, EL_BIND, "^[[A", "lldb-edit-prev-line", NULL); // Map up arrow + ::el_set (m_editline, EL_BIND, "^[[B", "lldb-edit-next-line", NULL); // Map down arrow + ::el_set (m_editline, EL_BIND, "^b", "ed-prev-history", NULL); + ::el_set (m_editline, EL_BIND, "^n", "ed-next-history", NULL); + m_interrupted = false; + + LineStatus line_status = LineStatus::Success; + + lines.Clear(); + + FILE *out_file = GetOutputFile(); + FILE *err_file = GetErrorFile(); + m_lines_curr_line = 1; + while (line_status != LineStatus::Done) + { + const uint32_t line_idx = m_lines_curr_line-1; + if (line_idx >= lines.GetSize()) + lines.SetSize(m_lines_curr_line); + m_lines_max_line = lines.GetSize(); + m_lines_command = Command::None; + assert(line_idx < m_lines_max_line); + std::string &line = lines[line_idx]; + error = PrivateGetLine(line); + if (error.Fail()) + { + line_status = LineStatus::Error; + } + else + { + switch (m_lines_command) + { + case Command::None: + if (m_line_complete_callback) + { + line_status = m_line_complete_callback (this, + lines, + line_idx, + error, + m_line_complete_callback_baton); + } + else if (line == end_line) + { + line_status = LineStatus::Done; + } + + if (line_status == LineStatus::Success) + { + ++m_lines_curr_line; + // If we already have content for the next line because + // we were editing previous lines, then populate the line + // with the appropriate contents + if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) + ::el_push (m_editline, + const_cast<char*>(lines[line_idx+1].c_str())); + } + else if (line_status == LineStatus::Error) + { + // Clear to end of line ("ESC[K"), then print the error, + // then go to the next line ("\n") and then move cursor up + // two lines ("ESC[2A"). + fprintf (err_file, "\033[Kerror: %s\n\033[2A", error.AsCString()); + } + break; + case Command::EditPrevLine: + if (m_lines_curr_line > 1) + { + //::fprintf (out_file, "\033[1A\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); // Make cursor go up a line and clear that line + ::fprintf (out_file, "\033[1A\033[1000D\033[2K"); + if (!lines[line_idx-1].empty()) + ::el_push (m_editline, + const_cast<char*>(lines[line_idx-1].c_str())); + --m_lines_curr_line; + } + break; + case Command::EditNextLine: + // Allow the down arrow to create a new line + ++m_lines_curr_line; + //::fprintf (out_file, "\033[1B\033[%uD\033[2K", (uint32_t)(m_lines_prompt.size() + lines[line_idx].size())); + ::fprintf (out_file, "\033[1B\033[1000D\033[2K"); + if (line_idx+1 < lines.GetSize() && !lines[line_idx+1].empty()) + ::el_push (m_editline, + const_cast<char*>(lines[line_idx+1].c_str())); + break; + } + } + } + m_lines_curr_line = 0; + m_lines_command = Command::None; + + // If we have a callback, call it one more time to let the + // user know the lines are complete + if (m_line_complete_callback) + m_line_complete_callback (this, + lines, + UINT32_MAX, + error, + m_line_complete_callback_baton); + + return error; +} + +unsigned char +Editline::HandleCompletion (int ch) +{ + if (m_completion_callback == NULL) + return CC_ERROR; + + const LineInfo *line_info = ::el_line(m_editline); + StringList completions; + int page_size = 40; + + const int num_completions = m_completion_callback (line_info->buffer, + line_info->cursor, + line_info->lastchar, + 0, // Don't skip any matches (start at match zero) + -1, // Get all the matches + completions, + m_completion_callback_baton); + + FILE *out_file = GetOutputFile(); + +// if (num_completions == -1) +// { +// ::el_insertstr (m_editline, m_completion_key); +// return CC_REDISPLAY; +// } +// else + if (num_completions == -2) + { + // Replace the entire line with the first string... + ::el_deletestr (m_editline, line_info->cursor - line_info->buffer); + ::el_insertstr (m_editline, completions.GetStringAtIndex(0)); + return CC_REDISPLAY; + } + + // If we get a longer match display that first. + const char *completion_str = completions.GetStringAtIndex(0); + if (completion_str != NULL && *completion_str != '\0') + { + el_insertstr (m_editline, completion_str); + return CC_REDISPLAY; + } + + if (num_completions > 1) + { + int num_elements = num_completions + 1; + ::fprintf (out_file, "\nAvailable completions:"); + if (num_completions < page_size) + { + for (int i = 1; i < num_elements; i++) + { + completion_str = completions.GetStringAtIndex(i); + ::fprintf (out_file, "\n\t%s", completion_str); + } + ::fprintf (out_file, "\n"); + } + else + { + int cur_pos = 1; + char reply; + int got_char; + while (cur_pos < num_elements) + { + int endpoint = cur_pos + page_size; + if (endpoint > num_elements) + endpoint = num_elements; + for (; cur_pos < endpoint; cur_pos++) + { + completion_str = completions.GetStringAtIndex(cur_pos); + ::fprintf (out_file, "\n\t%s", completion_str); + } + + if (cur_pos >= num_elements) + { + ::fprintf (out_file, "\n"); + break; + } + + ::fprintf (out_file, "\nMore (Y/n/a): "); + reply = 'n'; + got_char = el_getc(m_editline, &reply); + if (got_char == -1 || reply == 'n') + break; + if (reply == 'a') + page_size = num_elements - cur_pos; + } + } + + } + + if (num_completions == 0) + return CC_REFRESH_BEEP; + else + return CC_REDISPLAY; +} + +Editline * +Editline::GetClientData (::EditLine *e) +{ + Editline *editline = NULL; + if (e && ::el_get(e, EL_CLIENTDATA, &editline) == 0) + return editline; + return NULL; +} + +FILE * +Editline::GetInputFile () +{ + return GetFilePointer (m_editline, 0); +} + +FILE * +Editline::GetOutputFile () +{ + return GetFilePointer (m_editline, 1); +} + +FILE * +Editline::GetErrorFile () +{ + return GetFilePointer (m_editline, 2); +} + +const char * +Editline::GetPrompt() +{ + if (m_prompt_with_line_numbers && m_lines_curr_line > 0) + { + StreamString strm; + strm.Printf("%3u: ", m_lines_curr_line); + m_lines_prompt = std::move(strm.GetString()); + return m_lines_prompt.c_str(); + } + else + { + return m_prompt.c_str(); + } +} + +void +Editline::SetPrompt (const char *p) +{ + if (p && p[0]) + m_prompt = p; + else + m_prompt.clear(); + size_t start_pos = 0; + size_t escape_pos; + while ((escape_pos = m_prompt.find('\033', start_pos)) != std::string::npos) + { + m_prompt.insert(escape_pos, 1, k_prompt_escape_char); + start_pos += 2; + } +} + +FILE * +Editline::GetFilePointer (::EditLine *e, int fd) +{ + FILE *file_ptr = NULL; + if (e && ::el_get(e, EL_GETFP, fd, &file_ptr) == 0) + return file_ptr; + return NULL; +} + +unsigned char +Editline::CallbackEditPrevLine (::EditLine *e, int ch) +{ + Editline *editline = GetClientData (e); + if (editline->m_lines_curr_line > 1) + { + editline->m_lines_command = Command::EditPrevLine; + return CC_NEWLINE; + } + return CC_ERROR; +} +unsigned char +Editline::CallbackEditNextLine (::EditLine *e, int ch) +{ + Editline *editline = GetClientData (e); + if (editline->m_lines_curr_line < editline->m_lines_max_line) + { + editline->m_lines_command = Command::EditNextLine; + return CC_NEWLINE; + } + return CC_ERROR; +} + +unsigned char +Editline::CallbackComplete (::EditLine *e, int ch) +{ + Editline *editline = GetClientData (e); + if (editline) + return editline->HandleCompletion (ch); + return CC_ERROR; +} + +const char * +Editline::GetPromptCallback (::EditLine *e) +{ + Editline *editline = GetClientData (e); + if (editline) + return editline->GetPrompt(); + return ""; +} + +size_t +Editline::SetInputBuffer (const char *c, size_t len) +{ + if (c && len > 0) + { + Mutex::Locker locker(m_getc_mutex); + SetGetCharCallback(GetCharInputBufferCallback); + m_getc_buffer.append(c, len); + m_getc_cond.Broadcast(); + } + return len; +} + +int +Editline::GetChar (char *c) +{ + Mutex::Locker locker(m_getc_mutex); + if (m_getc_buffer.empty()) + m_getc_cond.Wait(m_getc_mutex); + if (m_getc_buffer.empty()) + return 0; + *c = m_getc_buffer[0]; + m_getc_buffer.erase(0,1); + return 1; +} + +int +Editline::GetCharInputBufferCallback (EditLine *e, char *c) +{ + Editline *editline = GetClientData (e); + if (editline) + return editline->GetChar(c); + return 0; +} + +int +Editline::GetCharFromInputFileCallback (EditLine *e, char *c) +{ + Editline *editline = GetClientData (e); + if (editline && editline->m_got_eof == false) + { + char ch = ::fgetc(editline->GetInputFile()); + if (ch == '\x04') + { + // Only turn a CTRL+D into a EOF if we receive the + // CTRL+D an empty line, otherwise it will forward + // delete the character at the cursor + const LineInfo *line_info = ::el_line(e); + if (line_info != NULL && + line_info->buffer == line_info->cursor && + line_info->cursor == line_info->lastchar) + { + ch = EOF; + } + } + + if (ch == EOF) + { + editline->m_got_eof = true; + } + else + { + *c = ch; + return 1; + } + } + return 0; +} + +void +Editline::Hide () +{ + FILE *out_file = GetOutputFile(); + if (out_file) + { + const LineInfo *line_info = ::el_line(m_editline); + if (line_info) + ::fprintf (out_file, "\033[%uD\033[K", (uint32_t)(strlen(GetPrompt()) + line_info->cursor - line_info->buffer)); + } +} + + +void +Editline::Refresh() +{ + ::el_set (m_editline, EL_REFRESH); +} + +void +Editline::Interrupt () +{ + m_interrupted = true; + if (m_getting_line || m_lines_curr_line > 0) + el_insertstr(m_editline, "\n"); // True to force the line to complete itself so we get exit from el_gets() +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/File.cpp b/contrib/llvm/tools/lldb/source/Host/common/File.cpp index bbd1185..bb0ee39 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/File.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/File.cpp @@ -13,10 +13,13 @@ #include <fcntl.h> #include <limits.h> #include <stdarg.h> +#include <stdio.h> #include <sys/stat.h> #ifdef _WIN32 #include "lldb/Host/windows/windows.h" +#else +#include <sys/ioctl.h> #endif #include "lldb/Core/DataBufferHeap.h" @@ -76,8 +79,11 @@ FILE * File::kInvalidStream = NULL; File::File(const char *path, uint32_t options, uint32_t permissions) : m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), - m_options (0), - m_owned (false) + m_options (), + m_own_stream (false), + m_own_descriptor (false), + m_is_interactive (eLazyBoolCalculate), + m_is_real_terminal (eLazyBoolCalculate) { Open (path, options, permissions); } @@ -88,7 +94,11 @@ File::File (const FileSpec& filespec, m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), - m_owned (false) + m_own_stream (false), + m_own_descriptor (false), + m_is_interactive (eLazyBoolCalculate), + m_is_real_terminal (eLazyBoolCalculate) + { if (filespec) { @@ -100,7 +110,10 @@ File::File (const File &rhs) : m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), - m_owned (false) + m_own_stream (false), + m_own_descriptor (false), + m_is_interactive (eLazyBoolCalculate), + m_is_real_terminal (eLazyBoolCalculate) { Duplicate (rhs); } @@ -141,7 +154,7 @@ File::SetDescriptor (int fd, bool transfer_ownership) if (IsValid()) Close(); m_descriptor = fd; - m_owned = transfer_ownership; + m_own_descriptor = transfer_ownership; } @@ -155,10 +168,31 @@ File::GetStream () const char *mode = GetStreamOpenModeFromOptions (m_options); if (mode) { + if (!m_own_descriptor) + { + // We must duplicate the file descriptor if we don't own it because + // when you call fdopen, the stream will own the fd +#ifdef _WIN32 + m_descriptor = ::_dup(GetDescriptor()); +#else + m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD); +#endif + m_own_descriptor = true; + } + do { m_stream = ::fdopen (m_descriptor, mode); } while (m_stream == NULL && errno == EINTR); + + // If we got a stream, then we own the stream and should no + // longer own the descriptor because fclose() will close it for us + + if (m_stream) + { + m_own_stream = true; + m_own_descriptor = false; + } } } } @@ -172,7 +206,7 @@ File::SetStream (FILE *fh, bool transfer_ownership) if (IsValid()) Close(); m_stream = fh; - m_owned = transfer_ownership; + m_own_stream = transfer_ownership; } Error @@ -194,7 +228,7 @@ File::Duplicate (const File &rhs) else { m_options = rhs.m_options; - m_owned = true; + m_own_descriptor = true; } } else @@ -272,7 +306,10 @@ File::Open (const char *path, uint32_t options, uint32_t permissions) if (!DescriptorIsValid()) error.SetErrorToErrno(); else - m_owned = true; + { + m_own_descriptor = true; + m_options = options; + } return error; } @@ -328,27 +365,24 @@ Error File::Close () { Error error; - if (IsValid ()) + if (StreamIsValid() && m_own_stream) { - if (m_owned) - { - if (StreamIsValid()) - { - if (::fclose (m_stream) == EOF) - error.SetErrorToErrno(); - } - - if (DescriptorIsValid()) - { - if (::close (m_descriptor) != 0) - error.SetErrorToErrno(); - } - } - m_descriptor = kInvalidDescriptor; - m_stream = kInvalidStream; - m_options = 0; - m_owned = false; + if (::fclose (m_stream) == EOF) + error.SetErrorToErrno(); } + + if (DescriptorIsValid() && m_own_descriptor) + { + if (::close (m_descriptor) != 0) + error.SetErrorToErrno(); + } + m_descriptor = kInvalidDescriptor; + m_stream = kInvalidStream; + m_options = 0; + m_own_stream = false; + m_own_descriptor = false; + m_is_interactive = eLazyBoolCalculate; + m_is_real_terminal = eLazyBoolCalculate; return error; } @@ -844,3 +878,43 @@ File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options) return mode; } + +void +File::CalculateInteractiveAndTerminal () +{ + const int fd = GetDescriptor(); + if (fd >= 0) + { + m_is_interactive = eLazyBoolNo; + m_is_real_terminal = eLazyBoolNo; +#ifndef _MSC_VER + if (isatty(fd)) + { + m_is_interactive = eLazyBoolYes; + struct winsize window_size; + if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) + { + if (window_size.ws_col > 0) + m_is_real_terminal = eLazyBoolYes; + } + } +#endif + } +} + +bool +File::GetIsInteractive () +{ + if (m_is_interactive == eLazyBoolCalculate) + CalculateInteractiveAndTerminal (); + return m_is_interactive == eLazyBoolYes; +} + +bool +File::GetIsRealTerminal () +{ + if (m_is_real_terminal == eLazyBoolCalculate) + CalculateInteractiveAndTerminal(); + return m_is_real_terminal == eLazyBoolYes; +} + diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp index 262776f..d43221c 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp @@ -18,6 +18,7 @@ #include <winsock2.h> #include <WS2tcpip.h> #else +#include <unistd.h> #include <dlfcn.h> #include <grp.h> #include <netdb.h> @@ -37,7 +38,7 @@ #include <AvailabilityMacros.h> #endif -#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) +#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) #include <spawn.h> #include <sys/wait.h> #include <sys/syscall.h> @@ -68,6 +69,18 @@ #include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" +#if defined (__APPLE__) +#ifndef _POSIX_SPAWN_DISABLE_ASLR +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#endif + +extern "C" +{ + int __pthread_chdir(const char *path); + int __pthread_fchdir (int fildes); +} + +#endif using namespace lldb; using namespace lldb_private; @@ -367,25 +380,31 @@ Host::GetArchitecture (SystemDefaultArchitecture arch_kind) // If the OS is Linux, "unknown" in the vendor slot isn't what we want // for the default triple. It's probably an artifact of config.guess. if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor) - triple.setVendorName(""); + triple.setVendorName (""); + + const char* distribution_id = GetDistributionId ().AsCString(); switch (triple.getArch()) { default: g_host_arch_32.SetTriple(triple); + g_host_arch_32.SetDistributionId (distribution_id); g_supports_32 = true; break; case llvm::Triple::x86_64: g_host_arch_64.SetTriple(triple); + g_host_arch_64.SetDistributionId (distribution_id); g_supports_64 = true; g_host_arch_32.SetTriple(triple.get32BitArchVariant()); + g_host_arch_32.SetDistributionId (distribution_id); g_supports_32 = true; break; case llvm::Triple::sparcv9: case llvm::Triple::ppc64: g_host_arch_64.SetTriple(triple); + g_host_arch_64.SetDistributionId (distribution_id); g_supports_64 = true; break; } @@ -445,6 +464,19 @@ Host::GetTargetTriple() return g_host_triple; } +// See linux/Host.cpp for Linux-based implementations of this. +// Add your platform-specific implementation to the appropriate host file. +#if !defined(__linux__) + +const ConstString & + Host::GetDistributionId () +{ + static ConstString s_distribution_id; + return s_distribution_id; +} + +#endif // #if !defined(__linux__) + lldb::pid_t Host::GetCurrentProcessID() { @@ -457,7 +489,7 @@ lldb::tid_t Host::GetCurrentThreadID() { #if defined (__APPLE__) - // Calling "mach_port_deallocate()" bumps the reference count on the thread + // Calling "mach_thread_self()" bumps the reference count on the thread // port, so we need to deallocate it. mach_task_self() doesn't bump the ref // count. thread_port_t thread_self = mach_thread_self(); @@ -489,10 +521,14 @@ Host::GetSignalAsCString (int signo) case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught) case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught) case SIGABRT: return "SIGABRT"; // 6 abort() -#if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE)) +#if defined(SIGPOLL) +#if !defined(SIGIO) || (SIGPOLL != SIGIO) +// Under some GNU/Linux, SIGPOLL and SIGIO are the same. Causing the build to +// fail with 'multiple define cases with same value' case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) #endif -#if !defined(_POSIX_C_SOURCE) +#endif +#if defined(SIGEMT) case SIGEMT: return "SIGEMT"; // 7 EMT instruction #endif case SIGFPE: return "SIGFPE"; // 8 floating point exception @@ -510,15 +546,17 @@ Host::GetSignalAsCString (int signo) case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) -#if !defined(_POSIX_C_SOURCE) +#if defined(SIGIO) case SIGIO: return "SIGIO"; // 23 input/output possible signal #endif case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm case SIGPROF: return "SIGPROF"; // 27 profiling time alarm -#if !defined(_POSIX_C_SOURCE) +#if defined(SIGWINCH) case SIGWINCH: return "SIGWINCH"; // 28 window size changes +#endif +#if defined(SIGINFO) case SIGINFO: return "SIGINFO"; // 29 information request #endif case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1 @@ -739,8 +777,8 @@ bool Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *thread_name, size_t len) { - char *namebuf = (char *)::malloc (len + 1); - + std::unique_ptr<char[]> namebuf(new char[len+1]); + // Thread names are coming in like '<lldb.comm.debugger.edit>' and // '<lldb.comm.debugger.editline>'. So just chopping the end of the string // off leads to a lot of similar named threads. Go through the thread name @@ -749,10 +787,10 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, if (lastdot && lastdot != thread_name) thread_name = lastdot + 1; - ::strncpy (namebuf, thread_name, len); + ::strncpy (namebuf.get(), thread_name, len); namebuf[len] = 0; - int namebuflen = strlen(namebuf); + int namebuflen = strlen(namebuf.get()); if (namebuflen > 0) { if (namebuf[namebuflen - 1] == '(' || namebuf[namebuflen - 1] == '>') @@ -761,10 +799,8 @@ Host::SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, namebuflen--; namebuf[namebuflen] = 0; } - return Host::SetThreadName (pid, tid, namebuf); + return Host::SetThreadName (pid, tid, namebuf.get()); } - - ::free(namebuf); return false; } @@ -1092,19 +1128,23 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) { framework_pos += strlen("LLDB.framework"); ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path)); - } -#else - llvm::SmallString<256> python_version_dir; - llvm::raw_svector_ostream os(python_version_dir); - os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages"; - os.flush(); + } + else + { +#endif + llvm::SmallString<256> python_version_dir; + llvm::raw_svector_ostream os(python_version_dir); + os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages"; + os.flush(); - // We may get our string truncated. Should we protect - // this with an assert? + // We may get our string truncated. Should we protect + // this with an assert? - ::strncat(raw_path, python_version_dir.c_str(), - sizeof(raw_path) - strlen(raw_path) - 1); + ::strncat(raw_path, python_version_dir.c_str(), + sizeof(raw_path) - strlen(raw_path) - 1); +#if defined (__APPLE__) + } #endif FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path)); g_lldb_python_dir.SetCString(resolved_path); @@ -1224,6 +1264,29 @@ Host::GetLLDBPath (PathType path_type, FileSpec &file_spec) // TODO: where would user LLDB plug-ins be located on other systems? return false; } + + case ePathTypeLLDBTempSystemDir: + { + static ConstString g_lldb_tmp_dir; + if (!g_lldb_tmp_dir) + { + const char *tmpdir_cstr = getenv("TMPDIR"); + if (tmpdir_cstr == NULL) + { + tmpdir_cstr = getenv("TMP"); + if (tmpdir_cstr == NULL) + tmpdir_cstr = getenv("TEMP"); + } + if (tmpdir_cstr) + { + g_lldb_tmp_dir.SetCString(tmpdir_cstr); + if (log) + log->Printf("Host::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_lldb_tmp_dir.GetCString()); + } + } + file_spec.GetDirectory() = g_lldb_tmp_dir; + return (bool)file_spec.GetDirectory(); + } } return false; @@ -1473,21 +1536,36 @@ Host::RunShellCommand (const char *command, if (working_dir) launch_info.SetWorkingDirectory(working_dir); - char output_file_path_buffer[L_tmpnam]; + char output_file_path_buffer[PATH_MAX]; const char *output_file_path = NULL; + if (command_output_ptr) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" - output_file_path = ::tmpnam(output_file_path_buffer); - launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); + FileSpec tmpdir_file_spec; + if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.GetFilename().SetCString("lldb-shell-output.XXXXXX"); + strncpy(output_file_path_buffer, tmpdir_file_spec.GetPath().c_str(), sizeof(output_file_path_buffer)); + } + else + { + strncpy(output_file_path_buffer, "/tmp/lldb-shell-output.XXXXXX", sizeof(output_file_path_buffer)); + } + + output_file_path = ::mktemp(output_file_path_buffer); + } + + launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); + if (output_file_path) + { launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path, false, true); launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO); } else { - launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); } @@ -1569,24 +1647,73 @@ Host::RunShellCommand (const char *command, return error; } -#if defined(__linux__) || defined(__FreeBSD__) -// The functions below implement process launching via posix_spawn() for Linux -// and FreeBSD. -// The posix_spawn() and posix_spawnp() functions first appeared in FreeBSD 8.0, -static Error -LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid) +// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD and other GLIBC +// systems + +#if defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || defined (__GLIBC__) + +// this method needs to be visible to macosx/Host.cpp and +// common/Host.cpp. + +short +Host::GetPosixspawnFlags (ProcessLaunchInfo &launch_info) +{ + short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; + +#if defined (__APPLE__) + if (launch_info.GetFlags().Test (eLaunchFlagExec)) + flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test (eLaunchFlagDebug)) + flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag + + if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR)) + flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag + + if (launch_info.GetLaunchInSeparateProcessGroup()) + flags |= POSIX_SPAWN_SETPGROUP; + +#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT +#if defined (__APPLE__) && (defined (__x86_64__) || defined (__i386__)) + static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; + if (g_use_close_on_exec_flag == eLazyBoolCalculate) + { + g_use_close_on_exec_flag = eLazyBoolNo; + + uint32_t major, minor, update; + if (Host::GetOSVersion(major, minor, update)) + { + // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or earlier + if (major > 10 || (major == 10 && minor > 7)) + { + // Only enable for 10.8 and later OS versions + g_use_close_on_exec_flag = eLazyBoolYes; + } + } + } +#else + static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; +#endif + // Close all files exception those with file actions if this is supported. + if (g_use_close_on_exec_flag == eLazyBoolYes) + flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; +#endif +#endif // #if defined (__APPLE__) + return flags; +} + +Error +Host::LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, ::pid_t &pid) { Error error; Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS)); - assert(exe_path); - assert(!launch_info.GetFlags().Test (eLaunchFlagDebug)); - posix_spawnattr_t attr; - error.SetError( ::posix_spawnattr_init (&attr), eErrorTypePOSIX); - error.LogIfError(log, "::posix_spawnattr_init ( &attr )"); + + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_init ( &attr )"); if (error.Fail()) return error; @@ -1598,52 +1725,89 @@ LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, : sigset_t all_signals; sigemptyset (&no_signals); sigfillset (&all_signals); - ::posix_spawnattr_setsigmask(&attr, &all_signals); + ::posix_spawnattr_setsigmask(&attr, &no_signals); +#if defined (__linux__) || defined (__FreeBSD__) ::posix_spawnattr_setsigdefault(&attr, &no_signals); +#else + ::posix_spawnattr_setsigdefault(&attr, &all_signals); +#endif - short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; + short flags = GetPosixspawnFlags(launch_info); error.SetError( ::posix_spawnattr_setflags (&attr, flags), eErrorTypePOSIX); - error.LogIfError(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_setflags ( &attr, flags=0x%8.8x )", flags); if (error.Fail()) return error; - const size_t num_file_actions = launch_info.GetNumFileActions (); - posix_spawn_file_actions_t file_actions, *file_action_ptr = NULL; - // Make a quick class that will cleanup the posix spawn attributes in case - // we return in the middle of this function. - lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> - posix_spawn_file_actions_cleanup (file_action_ptr, NULL, posix_spawn_file_actions_destroy); - - if (num_file_actions > 0) + // posix_spawnattr_setbinpref_np appears to be an Apple extension per: + // http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ +#if defined (__APPLE__) && !defined (__arm__) + + // Don't set the binpref if a shell was provided. After all, that's only going to affect what version of the shell + // is launched, not what fork of the binary is launched. We insert "arch --arch <ARCH> as part of the shell invocation + // to do that job on OSX. + + if (launch_info.GetShell() == nullptr) { - error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); - error.LogIfError(log, "::posix_spawn_file_actions_init ( &file_actions )"); - if (error.Fail()) - return error; - - file_action_ptr = &file_actions; - posix_spawn_file_actions_cleanup.set(file_action_ptr); - - for (size_t i = 0; i < num_file_actions; ++i) + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + const ArchSpec &arch_spec = launch_info.GetArchitecture(); + cpu_type_t cpu = arch_spec.GetMachOCPUType(); + cpu_type_t sub = arch_spec.GetMachOCPUSubType(); + if (cpu != 0 && + cpu != UINT32_MAX && + cpu != LLDB_INVALID_CPUTYPE && + !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try to set the CPU type or we will fail { - const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); - if (launch_file_action && - !ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions, - launch_file_action, - log, - error)) + size_t ocount = 0; + error.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu, &ocount), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu, (uint64_t)ocount); + + if (error.Fail() || ocount != 1) return error; } } - // Change working directory if neccessary. +#endif + + const char *tmp_argv[2]; + char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector(); + char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector(); + if (argv == NULL) + { + // posix_spawn gets very unhappy if it doesn't have at least the program + // name in argv[0]. One of the side affects I have noticed is the environment + // variables don't make it into the child process if "argv == NULL"!!! + tmp_argv[0] = exe_path; + tmp_argv[1] = NULL; + argv = (char * const*)tmp_argv; + } + +#if !defined (__APPLE__) + // manage the working directory char current_dir[PATH_MAX]; current_dir[0] = '\0'; +#endif const char *working_dir = launch_info.GetWorkingDirectory(); - if (working_dir != NULL) + if (working_dir) { +#if defined (__APPLE__) + // Set the working directory on this thread only + if (__pthread_chdir (working_dir) < 0) { + if (errno == ENOENT) { + error.SetErrorStringWithFormat("No such file or directory: %s", working_dir); + } else if (errno == ENOTDIR) { + error.SetErrorStringWithFormat("Path doesn't name a directory: %s", working_dir); + } else { + error.SetErrorStringWithFormat("An unknown error occurred when changing directory for process execution."); + } + return error; + } +#else if (::getcwd(current_dir, sizeof(current_dir)) == NULL) { error.SetError(errno, eErrorTypePOSIX); @@ -1657,45 +1821,111 @@ LaunchProcessPosixSpawn (const char *exe_path, ProcessLaunchInfo &launch_info, : error.LogIfError(log, "unable to change working directory to %s", working_dir); return error; } +#endif } - const char *tmp_argv[2]; - char * const *argv = (char * const*)launch_info.GetArguments().GetConstArgumentVector(); - char * const *envp = (char * const*)launch_info.GetEnvironmentEntries().GetConstArgumentVector(); - - // Prepare minimal argument list if we didn't get it from the launch_info structure. - // We must pass argv into posix_spawnp and it must contain at least two items - - // pointer to an executable and NULL. - if (argv == NULL) + const size_t num_file_actions = launch_info.GetNumFileActions (); + if (num_file_actions > 0) { - tmp_argv[0] = exe_path; - tmp_argv[1] = NULL; - argv = (char * const*)tmp_argv; - } + posix_spawn_file_actions_t file_actions; + error.SetError( ::posix_spawn_file_actions_init (&file_actions), eErrorTypePOSIX); + if (error.Fail() || log) + error.PutToLog(log, "::posix_spawn_file_actions_init ( &file_actions )"); + if (error.Fail()) + return error; + + // Make a quick class that will cleanup the posix spawn attributes in case + // we return in the middle of this function. + lldb_utility::CleanUp <posix_spawn_file_actions_t *, int> posix_spawn_file_actions_cleanup (&file_actions, posix_spawn_file_actions_destroy); + + for (size_t i=0; i<num_file_actions; ++i) + { + const ProcessLaunchInfo::FileAction *launch_file_action = launch_info.GetFileActionAtIndex(i); + if (launch_file_action) + { + if (!ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (&file_actions, + launch_file_action, + log, + error)) + return error; + } + } + + error.SetError (::posix_spawnp (&pid, + exe_path, + &file_actions, + &attr, + argv, + envp), + eErrorTypePOSIX); - error.SetError (::posix_spawnp (&pid, - exe_path, - (num_file_actions > 0) ? &file_actions : NULL, - &attr, - argv, - envp), - eErrorTypePOSIX); + if (error.Fail() || log) + { + error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", + pid, + exe_path, + &file_actions, + &attr, + argv, + envp); + if (log) + { + for (int ii=0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } + } - error.LogIfError(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", - pid, exe_path, file_action_ptr, &attr, argv, envp); + } + else + { + error.SetError (::posix_spawnp (&pid, + exe_path, + NULL, + &attr, + argv, + envp), + eErrorTypePOSIX); + + if (error.Fail() || log) + { + error.PutToLog(log, "::posix_spawnp ( pid => %i, path = '%s', file_actions = NULL, attr = %p, argv = %p, envp = %p )", + pid, + exe_path, + &attr, + argv, + envp); + if (log) + { + for (int ii=0; argv[ii]; ++ii) + log->Printf("argv[%i] = '%s'", ii, argv[ii]); + } + } + } - // Change back the current directory. - // NOTE: do not override previously established error from posix_spawnp. - if (working_dir != NULL && ::chdir(current_dir) == -1 && error.Success()) + if (working_dir) { - error.SetError(errno, eErrorTypePOSIX); - error.LogIfError(log, "unable to change current directory back to %s", - current_dir); +#if defined (__APPLE__) + // No more thread specific current working directory + __pthread_fchdir (-1); +#else + if (::chdir(current_dir) == -1 && error.Success()) + { + error.SetError(errno, eErrorTypePOSIX); + error.LogIfError(log, "unable to change current directory back to %s", + current_dir); + } +#endif } return error; } +#endif // LaunchProcedssPosixSpawn: Apple, Linux, FreeBSD and other GLIBC systems + + +#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) +// The functions below implement process launching via posix_spawn() for Linux +// and FreeBSD. Error Host::LaunchProcess (ProcessLaunchInfo &launch_info) @@ -1747,6 +1977,8 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) // If all went well, then set the process ID into the launch info launch_info.SetProcessID(pid); + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + // Make sure we reap any processes we spawn or we will have zombies. if (!launch_info.MonitorProcess()) { @@ -1755,6 +1987,13 @@ Host::LaunchProcess (ProcessLaunchInfo &launch_info) NULL, pid, monitor_signals); + if (log) + log->PutCString ("monitored child process with default Process::SetProcessExitStatus."); + } + else + { + if (log) + log->PutCString ("monitored child process with user-specified process monitor."); } } else diff --git a/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp index ead044f..cf13359 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/OptionParser.cpp @@ -9,14 +9,10 @@ #include "lldb/Host/OptionParser.h" -#ifdef _MSC_VER -#include "../windows/msvc/getopt.inc" -#else -#ifdef _WIN32 +#if (!defined( _MSC_VER ) && defined( _WIN32 )) #define _BSD_SOURCE // Required so that getopt.h defines optreset #endif -#include <getopt.h> -#endif +#include "lldb/Host/HostGetOpt.h" using namespace lldb_private; diff --git a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp index 1fa7531..75f3cd1 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/SocketAddress.cpp @@ -95,7 +95,7 @@ GetFamilyLength (sa_family_t family) socklen_t SocketAddress::GetLength () const { -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) return m_socket_addr.sa.sa_len; #else return GetFamilyLength (GetFamily()); @@ -118,24 +118,24 @@ void SocketAddress::SetFamily (sa_family_t family) { m_socket_addr.sa.sa_family = family; -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) m_socket_addr.sa.sa_len = GetFamilyLength (family); #endif } -in_port_t +uint16_t SocketAddress::GetPort () const { switch (GetFamily()) { - case AF_INET: return m_socket_addr.sa_ipv4.sin_port; - case AF_INET6: return m_socket_addr.sa_ipv6.sin6_port; + case AF_INET: return ntohs(m_socket_addr.sa_ipv4.sin_port); + case AF_INET6: return ntohs(m_socket_addr.sa_ipv6.sin6_port); } return 0; } bool -SocketAddress::SetPort (in_port_t port) +SocketAddress::SetPort (uint16_t port) { switch (GetFamily()) { @@ -206,36 +206,34 @@ SocketAddress::operator=(const struct sockaddr_storage &s) } bool -SocketAddress::SetAddress (const struct addrinfo *hints_ptr, - const char *host, - const char *service, - struct addrinfo *addr_info_ptr) +SocketAddress::getaddrinfo (const char *host, + const char *service, + int ai_family, + int ai_socktype, + int ai_protocol, + int ai_flags) { + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai_family; + hints.ai_socktype = ai_socktype; + hints.ai_protocol = ai_protocol; + hints.ai_flags = ai_flags; + struct addrinfo *service_info_list = NULL; - int err = ::getaddrinfo (host, service, hints_ptr, &service_info_list); + int err = ::getaddrinfo (host, service, &hints, &service_info_list); if (err == 0 && service_info_list) - { - if (addr_info_ptr) - *addr_info_ptr = *service_info_list; *this = service_info_list; - } else Clear(); :: freeaddrinfo (service_info_list); - - const bool is_valid = IsValid(); - if (!is_valid) - { - if (addr_info_ptr) - ::memset (addr_info_ptr, 0, sizeof(struct addrinfo)); - } - return is_valid; + return IsValid(); } bool -SocketAddress::SetToLocalhost (sa_family_t family, in_port_t port) +SocketAddress::SetToLocalhost (sa_family_t family, uint16_t port) { switch (family) { @@ -243,7 +241,7 @@ SocketAddress::SetToLocalhost (sa_family_t family, in_port_t port) SetFamily (AF_INET); if (SetPort (port)) { - m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY); + m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); return true; } break; @@ -252,7 +250,7 @@ SocketAddress::SetToLocalhost (sa_family_t family, in_port_t port) SetFamily (AF_INET6); if (SetPort (port)) { - m_socket_addr.sa_ipv6.sin6_addr = in6addr_any; + m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback; return true; } break; @@ -261,3 +259,31 @@ SocketAddress::SetToLocalhost (sa_family_t family, in_port_t port) Clear(); return false; } + +bool +SocketAddress::SetToAnyAddress (sa_family_t family, uint16_t port) +{ + switch (family) + { + case AF_INET: + SetFamily (AF_INET); + if (SetPort (port)) + { + m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY); + return true; + } + break; + + case AF_INET6: + SetFamily (AF_INET6); + if (SetPort (port)) + { + m_socket_addr.sa_ipv6.sin6_addr = in6addr_any; + return true; + } + break; + + } + Clear(); + return false; +} diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp index a7c892d..fb0fc7f 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandInterpreter.cpp @@ -22,6 +22,7 @@ #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" #include "../Commands/CommandObjectFrame.h" +#include "../Commands/CommandObjectGUI.h" #include "../Commands/CommandObjectHelp.h" #include "../Commands/CommandObjectLog.h" #include "../Commands/CommandObjectMemory.h" @@ -42,11 +43,12 @@ #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/Timer.h" +#include "lldb/Host/Editline.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" @@ -99,11 +101,13 @@ CommandInterpreter::CommandInterpreter ) : Broadcaster (&debugger, "lldb.command-interpreter"), Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))), + IOHandlerDelegate (IOHandlerDelegate::Completion::LLDBCommand), m_debugger (debugger), m_synchronous_execution (synchronous_execution), m_skip_lldbinit_files (false), m_skip_app_init_files (false), m_script_interpreter_ap (), + m_command_io_handler_sp (), m_comment_char ('#'), m_batch_command_mode (false), m_truncation_warning(eNoTruncation), @@ -376,6 +380,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this)); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this)); m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (*this)); + m_command_dict["gui"] = CommandObjectSP (new CommandObjectGUI (*this)); m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp (*this)); m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (*this)); m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (*this)); @@ -1929,12 +1934,19 @@ CommandInterpreter::HandleCompletionMatches (Args &parsed_line, && matches.GetStringAtIndex(0) != NULL && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0) { - look_for_subcommand = true; - num_command_matches = 0; - matches.DeleteStringAtIndex(0); - parsed_line.AppendArgument (""); - cursor_index++; - cursor_char_position = 0; + if (parsed_line.GetArgumentCount() == 1) + { + word_complete = true; + } + else + { + look_for_subcommand = true; + num_command_matches = 0; + matches.DeleteStringAtIndex(0); + parsed_line.AppendArgument (""); + cursor_index++; + cursor_char_position = 0; + } } } @@ -2023,7 +2035,7 @@ CommandInterpreter::HandleCompletion (const char *current_line, const char *current_elem = partial_parsed_line.GetArgumentAtIndex(cursor_index); if (cursor_char_position == 0 || current_elem[cursor_char_position - 1] != ' ') { - parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '"'); + parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '\0'); cursor_index++; cursor_char_position = 0; } @@ -2086,96 +2098,15 @@ CommandInterpreter::~CommandInterpreter () { } -const char * -CommandInterpreter::GetPrompt () -{ - return m_debugger.GetPrompt(); -} - void -CommandInterpreter::SetPrompt (const char *new_prompt) +CommandInterpreter::UpdatePrompt (const char *new_prompt) { - m_debugger.SetPrompt (new_prompt); + EventSP prompt_change_event_sp (new Event(eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));; + BroadcastEvent (prompt_change_event_sp); + if (m_command_io_handler_sp) + m_command_io_handler_sp->SetPrompt(new_prompt); } -size_t -CommandInterpreter::GetConfirmationInputReaderCallback -( - void *baton, - InputReader &reader, - lldb::InputReaderAction action, - const char *bytes, - size_t bytes_len -) -{ - File &out_file = reader.GetDebugger().GetOutputFile(); - bool *response_ptr = (bool *) baton; - - switch (action) - { - case eInputReaderActivate: - if (out_file.IsValid()) - { - if (reader.GetPrompt()) - { - out_file.Printf ("%s", reader.GetPrompt()); - out_file.Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - if (out_file.IsValid() && reader.GetPrompt()) - { - out_file.Printf ("%s", reader.GetPrompt()); - out_file.Flush (); - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - if (bytes_len == 0) - { - reader.SetIsDone(true); - } - else if (bytes[0] == 'y' || bytes[0] == 'Y') - { - *response_ptr = true; - reader.SetIsDone(true); - } - else if (bytes[0] == 'n' || bytes[0] == 'N') - { - *response_ptr = false; - reader.SetIsDone(true); - } - else - { - if (out_file.IsValid() && !reader.IsDone() && reader.GetPrompt()) - { - out_file.Printf ("Please answer \"y\" or \"n\".\n%s", reader.GetPrompt()); - out_file.Flush (); - } - } - break; - - case eInputReaderInterrupt: - case eInputReaderEndOfFile: - *response_ptr = false; // Assume ^C or ^D means cancel the proposed action - reader.SetIsDone (true); - break; - - case eInputReaderDone: - break; - } - - return bytes_len; - -} bool CommandInterpreter::Confirm (const char *message, bool default_answer) @@ -2183,31 +2114,13 @@ CommandInterpreter::Confirm (const char *message, bool default_answer) // Check AutoConfirm first: if (m_debugger.GetAutoConfirm()) return default_answer; - - InputReaderSP reader_sp (new InputReader(GetDebugger())); - bool response = default_answer; - if (reader_sp) - { - std::string prompt(message); - prompt.append(": ["); - if (default_answer) - prompt.append ("Y/n] "); - else - prompt.append ("y/N] "); - - Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback, - &response, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - prompt.c_str(), // prompt - true)); // echo input - if (err.Success()) - { - GetDebugger().PushInputReader (reader_sp); - } - reader_sp->WaitOnReaderIsDone(); - } - return response; + + IOHandlerConfirm *confirm = new IOHandlerConfirm(m_debugger, + message, + default_answer); + IOHandlerSP io_handler_sp (confirm); + m_debugger.RunIOHandler (io_handler_sp); + return confirm->GetResponse(); } OptionArgVectorSP @@ -2477,13 +2390,16 @@ CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result) if (init_file.Exists()) { - ExecutionContext *exe_ctx = NULL; // We don't have any context yet. - bool stop_on_continue = true; - bool stop_on_error = false; - bool echo_commands = false; - bool print_results = false; - - HandleCommandsFromFile (init_file, exe_ctx, stop_on_continue, stop_on_error, echo_commands, print_results, eLazyBoolNo, result); + const bool saved_batch = SetBatchCommandMode (true); + HandleCommandsFromFile (init_file, + NULL, // Execution context + eLazyBoolYes, // Stop on continue + eLazyBoolNo, // Stop on error + eLazyBoolNo, // Don't echo commands + eLazyBoolNo, // Don't print command output + eLazyBoolNo, // Don't add the commands that are sourced into the history buffer + result); + SetBatchCommandMode (saved_batch); } else { @@ -2546,8 +2462,8 @@ CommandInterpreter::HandleCommands (const StringList &commands, if (echo_commands) { result.AppendMessageWithFormat ("%s %s\n", - GetPrompt(), - cmd); + m_debugger.GetPrompt(), + cmd); } CommandReturnObject tmp_result; @@ -2631,30 +2547,145 @@ CommandInterpreter::HandleCommands (const StringList &commands, return; } +// Make flags that we can pass into the IOHandler so our delegates can do the right thing +enum { + eHandleCommandFlagStopOnContinue = (1u << 0), + eHandleCommandFlagStopOnError = (1u << 1), + eHandleCommandFlagEchoCommand = (1u << 2), + eHandleCommandFlagPrintResult = (1u << 3) +}; + void CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file, ExecutionContext *context, - bool stop_on_continue, - bool stop_on_error, - bool echo_command, - bool print_result, + LazyBool stop_on_continue, + LazyBool stop_on_error, + LazyBool echo_command, + LazyBool print_result, LazyBool add_to_history, CommandReturnObject &result) { if (cmd_file.Exists()) { - bool success; - StringList commands; - success = commands.ReadFileLines(cmd_file); - if (!success) + StreamFileSP input_file_sp (new StreamFile()); + + std::string cmd_file_path = cmd_file.GetPath(); + Error error = input_file_sp->GetFile().Open(cmd_file_path.c_str(), File::eOpenOptionRead); + + if (error.Success()) { - result.AppendErrorWithFormat ("Error reading commands from file: %s.\n", cmd_file.GetFilename().AsCString()); + Debugger &debugger = GetDebugger(); + + uint32_t flags = 0; + + if (stop_on_continue == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Stop on continue by default + flags |= eHandleCommandFlagStopOnContinue; + } + else if (m_command_source_flags.back() & eHandleCommandFlagStopOnContinue) + { + flags |= eHandleCommandFlagStopOnContinue; + } + } + else if (stop_on_continue == eLazyBoolYes) + { + flags |= eHandleCommandFlagStopOnContinue; + } + + if (stop_on_error == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + if (GetStopCmdSourceOnError()) + flags |= eHandleCommandFlagStopOnError; + } + else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) + { + flags |= eHandleCommandFlagStopOnError; + } + } + else if (stop_on_error == eLazyBoolYes) + { + flags |= eHandleCommandFlagStopOnError; + } + + if (echo_command == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Echo command by default + flags |= eHandleCommandFlagEchoCommand; + } + else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) + { + flags |= eHandleCommandFlagEchoCommand; + } + } + else if (echo_command == eLazyBoolYes) + { + flags |= eHandleCommandFlagEchoCommand; + } + + if (print_result == eLazyBoolCalculate) + { + if (m_command_source_flags.empty()) + { + // Print output by default + flags |= eHandleCommandFlagPrintResult; + } + else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) + { + flags |= eHandleCommandFlagPrintResult; + } + } + else if (print_result == eLazyBoolYes) + { + flags |= eHandleCommandFlagPrintResult; + } + + if (flags & eHandleCommandFlagPrintResult) + { + debugger.GetOutputFile()->Printf("Executing commands in '%s'.\n", cmd_file_path.c_str()); + } + + // Used for inheriting the right settings when "command source" might have + // nested "command source" commands + lldb::StreamFileSP empty_stream_sp; + m_command_source_flags.push_back(flags); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + input_file_sp, + empty_stream_sp, // Pass in an empty stream so we inherit the top input reader output stream + empty_stream_sp, // Pass in an empty stream so we inherit the top input reader error stream + flags, + NULL, // Pass in NULL for "editline_name" so no history is saved, or written + debugger.GetPrompt(), + false, // Not multi-line + *this)); + const bool old_async_execution = debugger.GetAsyncExecution(); + + // Set synchronous execution if we not stopping when we continue + if ((flags & eHandleCommandFlagStopOnContinue) == 0) + debugger.SetAsyncExecution (false); + + m_command_source_depth++; + + debugger.RunIOHandler(io_handler_sp); + if (!m_command_source_flags.empty()) + m_command_source_flags.pop_back(); + m_command_source_depth--; + result.SetStatus (eReturnStatusSuccessFinishNoResult); + debugger.SetAsyncExecution (old_async_execution); + } + else + { + result.AppendErrorWithFormat ("error: an error occurred read file '%s': %s\n", cmd_file_path.c_str(), error.AsCString()); result.SetStatus (eReturnStatusFailed); - return; } - m_command_source_depth++; - HandleCommands (commands, context, stop_on_continue, stop_on_error, echo_command, print_result, add_to_history, result); - m_command_source_depth--; + + } else { @@ -2894,7 +2925,6 @@ CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList } } - void CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) { @@ -2908,3 +2938,195 @@ CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context) m_exe_ctx_ref.SetTargetPtr (m_debugger.GetSelectedTarget().get(), adopt_selected); } } + + +size_t +CommandInterpreter::GetProcessOutput () +{ + // The process has stuff waiting for stderr; get it and write it out to the appropriate place. + char stdio_buffer[1024]; + size_t len; + size_t total_bytes = 0; + Error error; + TargetSP target_sp (m_debugger.GetTargetList().GetSelectedTarget()); + if (target_sp) + { + ProcessSP process_sp (target_sp->GetProcessSP()); + if (process_sp) + { + while ((len = process_sp->GetSTDOUT (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + size_t bytes_written = len; + m_debugger.GetOutputFile()->Write (stdio_buffer, bytes_written); + total_bytes += len; + } + while ((len = process_sp->GetSTDERR (stdio_buffer, sizeof (stdio_buffer), error)) > 0) + { + size_t bytes_written = len; + m_debugger.GetErrorFile()->Write (stdio_buffer, bytes_written); + total_bytes += len; + } + } + } + return total_bytes; +} + +void +CommandInterpreter::IOHandlerInputComplete (IOHandler &io_handler, std::string &line) +{ + const bool is_interactive = io_handler.GetIsInteractive(); + if (is_interactive == false) + { + // When we are not interactive, don't execute blank lines. This will happen + // sourcing a commands file. We don't want blank lines to repeat the previous + // command and cause any errors to occur (like redefining an alias, get an error + // and stop parsing the commands file). + if (line.empty()) + return; + + // When using a non-interactive file handle (like when sourcing commands from a file) + // we need to echo the command out so we don't just see the command output and no + // command... + if (io_handler.GetFlags().Test(eHandleCommandFlagEchoCommand)) + io_handler.GetOutputStreamFile()->Printf("%s%s\n", io_handler.GetPrompt(), line.c_str()); + } + + lldb_private::CommandReturnObject result; + HandleCommand(line.c_str(), eLazyBoolCalculate, result); + + // Now emit the command output text from the command we just executed + if (io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) + { + // Display any STDOUT/STDERR _prior_ to emitting the command result text + GetProcessOutput (); + + if (!result.GetImmediateOutputStream()) + { + const char *output = result.GetOutputData(); + if (output && output[0]) + io_handler.GetOutputStreamFile()->PutCString(output); + } + + // Now emit the command error text from the command we just executed + if (!result.GetImmediateErrorStream()) + { + const char *error = result.GetErrorData(); + if (error && error[0]) + io_handler.GetErrorStreamFile()->PutCString(error); + } + } + + switch (result.GetStatus()) + { + case eReturnStatusInvalid: + case eReturnStatusSuccessFinishNoResult: + case eReturnStatusSuccessFinishResult: + case eReturnStatusStarted: + break; + + case eReturnStatusSuccessContinuingNoResult: + case eReturnStatusSuccessContinuingResult: + if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue)) + io_handler.SetIsDone(true); + break; + + case eReturnStatusFailed: + if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) + io_handler.SetIsDone(true); + break; + + case eReturnStatusQuit: + io_handler.SetIsDone(true); + break; + } +} + +void +CommandInterpreter::GetLLDBCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton) +{ + Debugger &debugger = GetDebugger(); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb", // Name of input reader for history + prompt, // Prompt + true, // Get multiple lines + delegate)); // IOHandlerDelegate + + if (io_handler_sp) + { + io_handler_sp->SetUserData (baton); + if (asynchronously) + debugger.PushIOHandler(io_handler_sp); + else + debugger.RunIOHandler(io_handler_sp); + } + +} + + +void +CommandInterpreter::GetPythonCommandsFromIOHandler (const char *prompt, + IOHandlerDelegate &delegate, + bool asynchronously, + void *baton) +{ + Debugger &debugger = GetDebugger(); + IOHandlerSP io_handler_sp (new IOHandlerEditline (debugger, + "lldb-python", // Name of input reader for history + prompt, // Prompt + true, // Get multiple lines + delegate)); // IOHandlerDelegate + + if (io_handler_sp) + { + io_handler_sp->SetUserData (baton); + if (asynchronously) + debugger.PushIOHandler(io_handler_sp); + else + debugger.RunIOHandler(io_handler_sp); + } + +} + +bool +CommandInterpreter::IsActive () +{ + return m_debugger.IsTopIOHandler (m_command_io_handler_sp); +} + +void +CommandInterpreter::RunCommandInterpreter(bool auto_handle_events, + bool spawn_thread) +{ + const bool multiple_lines = false; // Only get one line at a time + if (!m_command_io_handler_sp) + m_command_io_handler_sp.reset(new IOHandlerEditline (m_debugger, + m_debugger.GetInputFile(), + m_debugger.GetOutputFile(), + m_debugger.GetErrorFile(), + eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult, + "lldb", + m_debugger.GetPrompt(), + multiple_lines, + *this)); + m_debugger.PushIOHandler(m_command_io_handler_sp); + + if (auto_handle_events) + m_debugger.StartEventHandlerThread(); + + if (spawn_thread) + { + m_debugger.StartIOHandlerThread(); + } + else + { + m_debugger.ExecuteIOHanders(); + + if (auto_handle_events) + m_debugger.StopEventHandlerThread(); + } + +} + diff --git a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp index c71ca28..c699536 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/CommandObject.cpp @@ -261,13 +261,7 @@ CommandObject::CheckRequirements (CommandReturnObject &result) { Target *target = m_exe_ctx.GetTargetPtr(); if (target) - { - if (m_api_locker.TryLock (target->GetAPIMutex(), NULL) == false) - { - result.AppendError ("failed to get API lock"); - return false; - } - } + m_api_locker.Lock (target->GetAPIMutex()); } } diff --git a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp index 8d245cc..c6c66d8 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/Options.cpp @@ -952,7 +952,7 @@ Options::HandleOptionArgumentCompletion // If this is the "shlib" option and there was an argument provided, // restrict it to that shared library. - if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1) + if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1) { const char *module_name = input.GetArgumentAtIndex(cur_arg_pos); if (module_name) diff --git a/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp index 1e2bd23..053ff34 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/PythonDataObjects.cpp @@ -84,6 +84,12 @@ PythonObject::Str () return PythonString(str); } +bool +PythonObject::IsNULLOrNone () const +{ + return ((m_py_obj == nullptr) || (m_py_obj == Py_None)); +} + //---------------------------------------------------------------------- // PythonString //---------------------------------------------------------------------- @@ -97,7 +103,7 @@ PythonString::PythonString (PyObject *py_obj) : PythonString::PythonString (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a string + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a string } PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -166,7 +172,7 @@ PythonInteger::PythonInteger (PyObject *py_obj) : PythonInteger::PythonInteger (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a integer type + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a integer type } PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -223,8 +229,8 @@ PythonInteger::SetInteger (int64_t value) // PythonList //---------------------------------------------------------------------- -PythonList::PythonList () : - PythonObject(PyList_New(0)) +PythonList::PythonList (bool create_empty) : + PythonObject(create_empty ? PyList_New(0) : NULL) { } @@ -243,7 +249,7 @@ PythonList::PythonList (PyObject *py_obj) : PythonList::PythonList (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a list + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a list } PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -280,29 +286,29 @@ PythonList::GetItemAtIndex (uint32_t index) { if (m_py_obj) return PythonObject(PyList_GetItem(m_py_obj, index)); - return NULL; + return PythonObject(); } void PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object) { if (m_py_obj && object) - PyList_SetItem(m_py_obj, index, object.GetPythonObject()); + PyList_SetItem(m_py_obj, index, object.get()); } void PythonList::AppendItem (const PythonObject &object) { if (m_py_obj && object) - PyList_Append(m_py_obj, object.GetPythonObject()); + PyList_Append(m_py_obj, object.get()); } //---------------------------------------------------------------------- // PythonDictionary //---------------------------------------------------------------------- -PythonDictionary::PythonDictionary () : - PythonObject(PyDict_New()) +PythonDictionary::PythonDictionary (bool create_empty) : +PythonObject(create_empty ? PyDict_New() : NULL) { } @@ -316,7 +322,7 @@ PythonDictionary::PythonDictionary (PyObject *py_obj) : PythonDictionary::PythonDictionary (const PythonObject &object) : PythonObject() { - Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a dictionary + Reset(object.get()); // Use "Reset()" to ensure that py_obj is a dictionary } PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) : @@ -356,7 +362,7 @@ PythonDictionary::GetItemForKey (const char *key) const PythonString python_key(key); return GetItemForKey(python_key); } - return NULL; + return PythonObject(); } @@ -364,7 +370,7 @@ PythonObject PythonDictionary::GetItemForKey (const PythonString &key) const { if (m_py_obj && key) - return PythonObject(PyDict_GetItem(m_py_obj, key.GetPythonObject())); + return PythonObject(PyDict_GetItem(m_py_obj, key.get())); return PythonObject(); } @@ -374,7 +380,7 @@ PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fa { if (m_py_obj && key) { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); if (py_obj && PyString_Check(py_obj)) return PyString_AsString(py_obj); } @@ -386,7 +392,7 @@ PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_ { if (m_py_obj && key) { - PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject()); + PyObject *py_obj = PyDict_GetItem(m_py_obj, key.get()); if (py_obj) { if (PyInt_Check(py_obj)) @@ -404,7 +410,7 @@ PythonDictionary::GetKeys () const { if (m_py_obj) return PythonList(PyDict_Keys(m_py_obj)); - return PythonList(); + return PythonList(true); } PythonString @@ -431,7 +437,7 @@ PythonDictionary::GetValueAtPosition (uint32_t pos) const Py_ssize_t pos_iter = 0; if (!m_py_obj) - return NULL; + return PythonObject(); while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) { if (pos-- == 0) @@ -441,10 +447,17 @@ PythonDictionary::GetValueAtPosition (uint32_t pos) const } void +PythonDictionary::SetItemForKey (const PythonString &key, PyObject *value) +{ + if (m_py_obj && key && value) + PyDict_SetItem(m_py_obj, key.get(), value); +} + +void PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value) { if (m_py_obj && key && value) - PyDict_SetItem(m_py_obj, key.GetPythonObject(), value.GetPythonObject()); + PyDict_SetItem(m_py_obj, key.get(), value.get()); } #endif diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp index 6a44114..e33480d 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterNone.cpp @@ -11,6 +11,7 @@ #include "lldb/Interpreter/ScriptInterpreterNone.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StringList.h" #include "lldb/Core/Debugger.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -30,14 +31,14 @@ ScriptInterpreterNone::~ScriptInterpreterNone () bool ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, const ExecuteScriptOptions&) { - m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); + m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); return false; } void ScriptInterpreterNone::ExecuteInterpreterLoop () { - m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n"); + m_interpreter.GetDebugger().GetErrorFile()->PutCString ("error: there is no embedded script interpreter in this mode.\n"); } diff --git a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp index fb60fed..c1d28e8 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/contrib/llvm/tools/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -27,11 +27,14 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Core/Communication.h" +#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/PythonDataObjects.h" #include "lldb/Target/Thread.h" using namespace lldb; @@ -66,22 +69,23 @@ _check_and_flush (FILE *stream) return fflush (stream) || prev_fail ? EOF : 0; } +static std::string +ReadPythonBacktrace (PyObject* py_backtrace); + ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter, uint16_t on_entry, uint16_t on_leave, - FILE* wait_msg_handle) : + FILE *in, + FILE *out, + FILE *err) : ScriptInterpreterLocker (), m_teardown_session( (on_leave & TearDownSession) == TearDownSession ), - m_python_interpreter(py_interpreter), - m_tmp_fh(wait_msg_handle) + m_python_interpreter(py_interpreter) { - if (m_python_interpreter && !m_tmp_fh) - m_tmp_fh = (m_python_interpreter->m_dbg_stdout ? m_python_interpreter->m_dbg_stdout : stdout); - DoAcquireLock(); if ((on_entry & InitSession) == InitSession) { - if (DoInitSession((on_entry & InitGlobals) == InitGlobals) == false) + if (DoInitSession(on_entry, in, out, err) == false) { // Don't teardown the session if we didn't init it. m_teardown_session = false; @@ -100,11 +104,11 @@ ScriptInterpreterPython::Locker::DoAcquireLock() } bool -ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals) +ScriptInterpreterPython::Locker::DoInitSession(uint16_t on_entry_flags, FILE *in, FILE *out, FILE *err) { if (!m_python_interpreter) return false; - return m_python_interpreter->EnterSession (init_lldb_globals); + return m_python_interpreter->EnterSession (on_entry_flags, in, out, err); } bool @@ -133,268 +137,29 @@ ScriptInterpreterPython::Locker::~Locker() DoFreeLock(); } -ScriptInterpreterPython::PythonInputReaderManager::PythonInputReaderManager (ScriptInterpreterPython *interpreter) : -m_interpreter(interpreter), -m_debugger_sp(), -m_reader_sp(), -m_error(false) -{ - if (m_interpreter == NULL) - { - m_error = true; - return; - } - - m_debugger_sp = m_interpreter->GetCommandInterpreter().GetDebugger().shared_from_this(); - - if (!m_debugger_sp) - { - m_error = true; - return; - } - - m_reader_sp = InputReaderSP(new InputReader(*m_debugger_sp.get())); - - if (!m_reader_sp) - { - m_error = true; - return; - } - - Error error (m_reader_sp->Initialize (ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback, - m_interpreter, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - NULL, // prompt - true)); // echo input - if (error.Fail()) - m_error = true; - else - { - m_debugger_sp->PushInputReader (m_reader_sp); - m_interpreter->m_embedded_thread_input_reader_sp = m_reader_sp; - } -} - -ScriptInterpreterPython::PythonInputReaderManager::~PythonInputReaderManager() -{ - // Nothing to do if either m_interpreter or m_reader_sp is invalid. - if (!m_interpreter || !m_reader_sp) - return; - - m_reader_sp->SetIsDone (true); - if (m_debugger_sp) - m_debugger_sp->PopInputReader(m_reader_sp); - - // Only mess with m_interpreter's counterpart if, indeed, they are the same object. - if (m_reader_sp.get() == m_interpreter->m_embedded_thread_input_reader_sp.get()) - { - m_interpreter->m_embedded_thread_pty.CloseSlaveFileDescriptor(); - m_interpreter->m_embedded_thread_input_reader_sp.reset(); - } -} - -size_t -ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback (void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len) -{ - lldb::thread_t embedded_interpreter_thread; - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - if (baton == NULL) - return 0; - - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - if (script_interpreter->m_script_lang != eScriptLanguagePython) - return 0; - - switch (notification) - { - case eInputReaderActivate: - { - // Save terminal settings if we can - int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); - if (input_fd == File::kInvalidDescriptor) - input_fd = STDIN_FILENO; - - script_interpreter->SaveTerminalState(input_fd); - - char error_str[1024]; - if (script_interpreter->m_embedded_thread_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, - sizeof(error_str))) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", - script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor()); - { - StreamString run_string; - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); - if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), - pty_slave_name); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - } - } - embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.noninteractive-python>", - ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader, - script_interpreter, NULL); - if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); - Error detach_error; - Host::ThreadDetach (embedded_interpreter_thread, &detach_error); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed in creating thread"); - reader.SetIsDone (true); - } - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed to open master pty "); - reader.SetIsDone (true); - } - } - break; - - case eInputReaderDeactivate: - // When another input reader is pushed, don't leave the session... - //script_interpreter->LeaveSession (); - break; - - case eInputReaderReactivate: -// { -// ScriptInterpreterPython::Locker locker(script_interpreter, -// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, -// ScriptInterpreterPython::Locker::FreeAcquiredLock); -// } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderInterrupt: - { - PyThreadState* state = _PyThreadState_Current; - if (!state) - state = script_interpreter->m_command_thread_state; - if (state) - { - long tid = state->thread_id; - _PyThreadState_Current = state; - int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt); - if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p", - tid,num_threads,state); - } - else if (log) - log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL"); - } - break; - - case eInputReaderEndOfFile: - reader.SetIsDone(true); - break; - - case eInputReaderGotToken: - if (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor() != -1) - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu", bytes, - bytes_len); - if (bytes && bytes_len) - ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), bytes, bytes_len); - ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), "\n", 1); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad.", - bytes, - bytes_len); - reader.SetIsDone (true); - } - break; - - case eInputReaderDone: - { - StreamString run_string; - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str)); - if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL) - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin; sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - } - // Restore terminal settings if they were validly saved - if (log) - log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader."); - - script_interpreter->RestoreTerminalState (); - - script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor(); - } - break; - } - - return bytes_len; -} ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) : ScriptInterpreter (interpreter, eScriptLanguagePython), - m_embedded_thread_pty (), - m_embedded_python_pty (), - m_embedded_thread_input_reader_sp (), - m_embedded_python_input_reader_sp (), - m_dbg_stdout (interpreter.GetDebugger().GetOutputFile().GetStream()), - m_new_sysout (NULL), - m_old_sysout (NULL), - m_old_syserr (NULL), - m_run_one_line (NULL), + IOHandlerDelegateMultiline("DONE"), + m_saved_stdin (), + m_saved_stdout (), + m_saved_stderr (), + m_main_module (), + m_lldb_module (), + m_session_dict (false), // Don't create an empty dictionary, leave it invalid + m_sys_module_dict (false), // Don't create an empty dictionary, leave it invalid + m_run_one_line_function (), + m_run_one_line_str_global (), m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()), m_terminal_state (), + m_active_io_handler (eIOHandlerNone), m_session_is_active (false), + m_pty_slave_is_open (false), m_valid_session (true), m_command_thread_state (NULL) { - static int g_initialized = false; - - if (!g_initialized) - { - g_initialized = true; - ScriptInterpreterPython::InitializePrivate (); - } + ScriptInterpreterPython::InitializePrivate (); m_dictionary_name.append("_dict"); StreamString run_string; @@ -425,72 +190,130 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete run_string.Clear(); run_string.Printf ("run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str()); PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); int new_count = Debugger::TestDebuggerRefCount(); if (new_count > old_count) Debugger::Terminate(); + run_string.Printf ("run_one_line (%s, 'import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 "; pydoc.pager = pydoc.plainpager')", m_dictionary_name.c_str(), interpreter.GetDebugger().GetID()); PyRun_SimpleString (run_string.GetData()); - - if (m_dbg_stdout != NULL) - { - m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); - } - - // get the output file handle from the debugger (if any) - File& out_file = interpreter.GetDebugger().GetOutputFile(); - if (out_file.IsValid()) - ResetOutputFileHandle(out_file.GetStream()); } ScriptInterpreterPython::~ScriptInterpreterPython () { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); +} - if (m_embedded_thread_input_reader_sp.get() != NULL) - { - m_embedded_thread_input_reader_sp->SetIsDone (true); - m_embedded_thread_pty.CloseSlaveFileDescriptor(); - const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp; - debugger.PopInputReader (reader_sp); - m_embedded_thread_input_reader_sp.reset(); - } +void +ScriptInterpreterPython::IOHandlerActivated (IOHandler &io_handler) +{ + const char *instructions = NULL; - if (m_embedded_python_input_reader_sp.get() != NULL) + switch (m_active_io_handler) { - m_embedded_python_input_reader_sp->SetIsDone (true); - m_embedded_python_pty.CloseSlaveFileDescriptor(); - const InputReaderSP reader_sp = m_embedded_python_input_reader_sp; - debugger.PopInputReader (reader_sp); - m_embedded_python_input_reader_sp.reset(); + case eIOHandlerNone: + break; + case eIOHandlerBreakpoint: + instructions = R"(Enter your Python command(s). Type 'DONE' to end. +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" +)"; + break; + case eIOHandlerWatchpoint: + instructions = "Enter your Python command(s). Type 'DONE' to end.\n"; + break; } - if (m_new_sysout) + if (instructions) { - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeLock); - Py_XDECREF ((PyObject*)m_new_sysout); + StreamFileSP output_sp(io_handler.GetOutputStreamFile()); + if (output_sp) + { + output_sp->PutCString(instructions); + output_sp->Flush(); + } } } void -ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::string &data) { - if (fh == NULL) - return; - - m_dbg_stdout = fh; + io_handler.SetIsDone(true); + bool batch_mode = m_interpreter.GetBatchCommandMode(); + + switch (m_active_io_handler) + { + case eIOHandlerNone: + break; + case eIOHandlerBreakpoint: + { + BreakpointOptions *bp_options = (BreakpointOptions *)io_handler.GetUserData(); + std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(data); + + if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + if (error_sp) + { + error_sp->Printf ("Warning: No command attached to breakpoint.\n"); + error_sp->Flush(); + } + } + } + m_active_io_handler = eIOHandlerNone; + } + break; + case eIOHandlerWatchpoint: + { + WatchpointOptions *wp_options = (WatchpointOptions *)io_handler.GetUserData(); + std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); + if (data_ap.get()) + { + data_ap->user_source.SplitIntoLines(data); + + if (GenerateWatchpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + { + BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); + wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); + } + else if (!batch_mode) + { + StreamFileSP error_sp = io_handler.GetErrorStreamFile(); + if (error_sp) + { + error_sp->Printf ("Warning: No command attached to breakpoint.\n"); + error_sp->Flush(); + } + } + } + m_active_io_handler = eIOHandlerNone; + } + break; + } - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); +} + + +void +ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +{ } void @@ -529,15 +352,24 @@ ScriptInterpreterPython::LeaveSession () // When the current thread state is NULL, PyThreadState_Get() issues a fatal error. if (PyThreadState_GetDict()) { - PyObject *sysmod = PyImport_AddModule ("sys"); - PyObject *sysdict = PyModule_GetDict (sysmod); - - if (m_new_sysout && sysmod && sysdict) + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) { - if (m_old_sysout) - PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_old_sysout); - if (m_old_syserr) - PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_old_syserr); + if (m_saved_stdin) + { + sys_module_dict.SetItemForKey("stdin", m_saved_stdin); + m_saved_stdin.Reset (); + } + if (m_saved_stdout) + { + sys_module_dict.SetItemForKey("stdout", m_saved_stdout); + m_saved_stdout.Reset (); + } + if (m_saved_stderr) + { + sys_module_dict.SetItemForKey("stderr", m_saved_stderr); + m_saved_stderr.Reset (); + } } } @@ -545,7 +377,10 @@ ScriptInterpreterPython::LeaveSession () } bool -ScriptInterpreterPython::EnterSession (bool init_lldb_globals) +ScriptInterpreterPython::EnterSession (uint16_t on_entry_flags, + FILE *in, + FILE *out, + FILE *err) { // If we have already entered the session, without having officially 'left' it, then there is no need to // 'enter' it again. @@ -553,19 +388,19 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) if (m_session_is_active) { if (log) - log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i) session is already active, returning without doing anything", init_lldb_globals); + log->Printf("ScriptInterpreterPython::EnterSession(on_entry_flags=0x%" PRIx16 ") session is already active, returning without doing anything", on_entry_flags); return false; } if (log) - log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i)", init_lldb_globals); + log->Printf("ScriptInterpreterPython::EnterSession(on_entry_flags=0x%" PRIx16 ")", on_entry_flags); m_session_is_active = true; StreamString run_string; - if (init_lldb_globals) + if (on_entry_flags & Locker::InitGlobals) { run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); @@ -578,26 +413,61 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) else { // If we aren't initing the globals, we should still always set the debugger (since that is always unique.) - run_string.Printf ( "run_one_line (%s, \"lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); + run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID()); run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID()); - run_string.PutCString ("\")"); + run_string.PutCString ("')"); } PyRun_SimpleString (run_string.GetData()); run_string.Clear(); - PyObject *sysmod = PyImport_AddModule ("sys"); - PyObject *sysdict = PyModule_GetDict (sysmod); - - if (m_new_sysout && sysmod && sysdict) + PythonDictionary &sys_module_dict = GetSysModuleDictionary (); + if (sys_module_dict) { - m_old_sysout = PyDict_GetItemString(sysdict, "stdout"); - m_old_syserr = PyDict_GetItemString(sysdict, "stderr"); - if (m_new_sysout) + lldb::StreamFileSP in_sp; + lldb::StreamFileSP out_sp; + lldb::StreamFileSP err_sp; + if (in == NULL || out == NULL || err == NULL) + m_interpreter.GetDebugger().AdoptTopIOHandlerFilesIfInvalid (in_sp, out_sp, err_sp); + + if (in == NULL && in_sp && (on_entry_flags & Locker::NoSTDIN) == 0) + in = in_sp->GetFile().GetStream(); + if (in) { - PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_new_sysout); - PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_new_sysout); + m_saved_stdin.Reset(sys_module_dict.GetItemForKey("stdin")); + + PyObject *new_file = PyFile_FromFile (in, (char *) "", (char *) "r", 0); + sys_module_dict.SetItemForKey ("stdin", new_file); + Py_DECREF (new_file); } + else + m_saved_stdin.Reset(); + + if (out == NULL && out_sp) + out = out_sp->GetFile().GetStream(); + if (out) + { + m_saved_stdout.Reset(sys_module_dict.GetItemForKey("stdout")); + + PyObject *new_file = PyFile_FromFile (out, (char *) "", (char *) "w", 0); + sys_module_dict.SetItemForKey ("stdout", new_file); + Py_DECREF (new_file); + } + else + m_saved_stdout.Reset(); + + if (err == NULL && err_sp) + err = err_sp->GetFile().GetStream(); + if (err) + { + m_saved_stderr.Reset(sys_module_dict.GetItemForKey("stderr")); + + PyObject *new_file = PyFile_FromFile (err, (char *) "", (char *) "w", 0); + sys_module_dict.SetItemForKey ("stderr", new_file); + Py_DECREF (new_file); + } + else + m_saved_stderr.Reset(); } if (PyErr_Occurred()) @@ -606,44 +476,42 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals) return true; } -static PyObject* -FindSessionDictionary (const char* dict_name) +PythonObject & +ScriptInterpreterPython::GetMainModule () { - static std::map<ConstString,PyObject*> g_dict_map; - - ConstString dict(dict_name); - - std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict); - - if (iter != g_dict_map.end()) - return iter->second; - - PyObject *main_mod = PyImport_AddModule ("__main__"); - if (main_mod != NULL) + if (!m_main_module) + m_main_module.Reset(PyImport_AddModule ("__main__")); + return m_main_module; +} + +PythonDictionary & +ScriptInterpreterPython::GetSessionDictionary () +{ + if (!m_session_dict) { - PyObject *main_dict = PyModule_GetDict (main_mod); - if ((main_dict != NULL) - && PyDict_Check (main_dict)) + PythonObject &main_module = GetMainModule (); + if (main_module) { - // Go through the main dictionary looking for the correct python script interpreter dictionary - PyObject *key, *value; - Py_ssize_t pos = 0; - - while (PyDict_Next (main_dict, &pos, &key, &value)) + PythonDictionary main_dict(PyModule_GetDict (main_module.get())); + if (main_dict) { - // We have stolen references to the key and value objects in the dictionary; we need to increment - // them now so that Python's garbage collector doesn't collect them out from under us. - Py_INCREF (key); - Py_INCREF (value); - if (strcmp (PyString_AsString (key), dict_name) == 0) - { - g_dict_map[dict] = value; - return value; - } + m_session_dict = main_dict.GetItemForKey(m_dictionary_name.c_str()); } } } - return NULL; + return m_session_dict; +} + +PythonDictionary & +ScriptInterpreterPython::GetSysModuleDictionary () +{ + if (!m_sys_module_dict) + { + PyObject *sys_module = PyImport_AddModule ("sys"); + if (sys_module) + m_sys_module_dict.Reset(PyModule_GetDict (sys_module)); + } + return m_sys_module_dict; } static std::string @@ -665,82 +533,154 @@ GenerateUniqueName (const char* base_name_wanted, } bool +ScriptInterpreterPython::GetEmbeddedInterpreterModuleObjects () +{ + if (!m_run_one_line_function) + { + PyObject *module = PyImport_AddModule ("lldb.embedded_interpreter"); + if (module != NULL) + { + PythonDictionary module_dict (PyModule_GetDict (module)); + if (module_dict) + { + m_run_one_line_function = module_dict.GetItemForKey("run_one_line"); + m_run_one_line_str_global = module_dict.GetItemForKey("g_run_one_line_str"); + } + } + } + return (bool)m_run_one_line_function; +} + +static void +ReadThreadBytesReceived(void *baton, const void *src, size_t src_len) +{ + if (src && src_len) + { + Stream *strm = (Stream *)baton; + strm->Write(src, src_len); + strm->Flush(); + } +} + +bool ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options) { if (!m_valid_session) return false; - - // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through - // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside - // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated - // method to pass the command string directly down to Python. - - Locker locker(this, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - bool success = false; - - if (command) + + if (command && command[0]) { - // Find the correct script interpreter dictionary in the main module. - PyObject *script_interpreter_dict = FindSessionDictionary(m_dictionary_name.c_str()); - if (script_interpreter_dict != NULL) + // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through + // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside + // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated + // method to pass the command string directly down to Python. + Debugger &debugger = m_interpreter.GetDebugger(); + + StreamFileSP input_file_sp; + StreamFileSP output_file_sp; + StreamFileSP error_file_sp; + Communication output_comm ("lldb.ScriptInterpreterPython.ExecuteOneLine.comm"); + int pipe_fds[2] = { -1, -1 }; + + if (options.GetEnableIO()) { - PyObject *pfunc = (PyObject*)m_run_one_line; - PyObject *pmod = PyImport_AddModule ("lldb.embedded_interpreter"); - if (pmod != NULL) + if (result) { - PyObject *pmod_dict = PyModule_GetDict (pmod); - if ((pmod_dict != NULL) - && PyDict_Check (pmod_dict)) + input_file_sp = debugger.GetInputFile(); + // Set output to a temporary file so we can forward the results on to the result object + + int err = pipe(pipe_fds); + if (err == 0) { - if (!pfunc) + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor(pipe_fds[0], true)); + if (conn_ap->IsConnected()) { - PyObject *key, *value; - Py_ssize_t pos = 0; + output_comm.SetConnection(conn_ap.release()); + output_comm.SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived, &result->GetOutputStream()); + output_comm.StartReadThread(); + FILE *outfile_handle = fdopen (pipe_fds[1], "w"); + output_file_sp.reset(new StreamFile(outfile_handle, true)); + error_file_sp = output_file_sp; + if (outfile_handle) + ::setbuf (outfile_handle, NULL); - while (PyDict_Next (pmod_dict, &pos, &key, &value)) - { - Py_INCREF (key); - Py_INCREF (value); - if (strcmp (PyString_AsString (key), "run_one_line") == 0) - { - pfunc = value; - break; - } - } - m_run_one_line = pfunc; + result->SetImmediateOutputFile(debugger.GetOutputFile()->GetFile().GetStream()); + result->SetImmediateErrorFile(debugger.GetErrorFile()->GetFile().GetStream()); } - - if (pfunc && PyCallable_Check (pfunc)) + } + } + if (!input_file_sp || !output_file_sp || !error_file_sp) + debugger.AdoptTopIOHandlerFilesIfInvalid(input_file_sp, output_file_sp, error_file_sp); + } + else + { + input_file_sp.reset (new StreamFile ()); + input_file_sp->GetFile().Open("/dev/null", File::eOpenOptionRead); + output_file_sp.reset (new StreamFile ()); + output_file_sp->GetFile().Open("/dev/null", File::eOpenOptionWrite); + error_file_sp = output_file_sp; + } + + FILE *in_file = input_file_sp->GetFile().GetStream(); + FILE *out_file = output_file_sp->GetFile().GetStream(); + FILE *err_file = error_file_sp->GetFile().GetStream(); + Locker locker(this, + ScriptInterpreterPython::Locker::AcquireLock | + ScriptInterpreterPython::Locker::InitSession | + (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), + ScriptInterpreterPython::Locker::FreeAcquiredLock | + ScriptInterpreterPython::Locker::TearDownSession, + in_file, + out_file, + err_file); + + bool success = false; + + // Find the correct script interpreter dictionary in the main module. + PythonDictionary &session_dict = GetSessionDictionary (); + if (session_dict) + { + if (GetEmbeddedInterpreterModuleObjects ()) + { + PyObject *pfunc = m_run_one_line_function.get(); + + if (pfunc && PyCallable_Check (pfunc)) + { + PythonObject pargs (Py_BuildValue("(Os)", session_dict.get(), command)); + if (pargs) { - PyObject *pargs = Py_BuildValue("(Os)",script_interpreter_dict,command); - if (pargs != NULL) + PythonObject return_value(PyObject_CallObject (pfunc, pargs.get())); + if (return_value) + success = true; + else if (options.GetMaskoutErrors() && PyErr_Occurred ()) { - PyObject *pvalue = NULL; - { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - pvalue = PyObject_CallObject (pfunc, pargs); - } - Py_XDECREF (pargs); - if (pvalue != NULL) - { - Py_XDECREF (pvalue); - success = true; - } - else if (options.GetMaskoutErrors() && PyErr_Occurred ()) - { - PyErr_Print(); - PyErr_Clear(); - } + PyErr_Print(); + PyErr_Clear(); } } } } - Py_INCREF (script_interpreter_dict); } + // Flush our output and error file handles + ::fflush (out_file); + if (out_file != err_file) + ::fflush (err_file); + + if (pipe_fds[0] != -1) + { + // Close the write end of the pipe since we are done with our + // one line script. This should cause the read thread that + // output_comm is using to exit + output_file_sp->GetFile().Close(); + // The close above should cause this thread to exit when it gets + // to the end of file, so let it get all its data + output_comm.JoinReadThread(); + // Now we can close the read end of the pipe + output_comm.Disconnect(); + } + + if (success) return true; @@ -755,155 +695,113 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec return false; } -size_t -ScriptInterpreterPython::InputReaderCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - lldb::thread_t embedded_interpreter_thread; - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - if (baton == NULL) - return 0; +class IOHandlerPythonInterpreter : + public IOHandler +{ +public: + + IOHandlerPythonInterpreter (Debugger &debugger, + ScriptInterpreterPython *python) : + IOHandler (debugger), + m_python(python) + { - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + } - if (script_interpreter->m_script_lang != eScriptLanguagePython) - return 0; + virtual + ~IOHandlerPythonInterpreter() + { + + } - switch (notification) + virtual ConstString + GetControlSequence (char ch) { - case eInputReaderActivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (!batch_mode) - { - out_stream->Printf ("Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n"); - out_stream->Flush(); - } - - // Save terminal settings if we can - int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor(); - if (input_fd == File::kInvalidDescriptor) - input_fd = STDIN_FILENO; - - script_interpreter->SaveTerminalState(input_fd); - - { - ScriptInterpreterPython::Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - } + if (ch == 'd') + return ConstString("quit()\n"); + return ConstString(); + } - char error_str[1024]; - if (script_interpreter->m_embedded_python_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, - sizeof(error_str))) + virtual void + Run () + { + if (m_python) + { + int stdin_fd = GetInputFD(); + if (stdin_fd >= 0) { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in opening master pty (fd = %d).", - script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor()); - embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.embedded-python-loop>", - ScriptInterpreterPython::RunEmbeddedPythonInterpreter, - script_interpreter, NULL); - if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread)) - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread); - Error detach_error; - Host::ThreadDetach (embedded_interpreter_thread, &detach_error); - } - else + Terminal terminal(stdin_fd); + TerminalState terminal_state; + const bool is_a_tty = terminal.IsATerminal(); + + if (is_a_tty) { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed in creating thread"); - reader.SetIsDone (true); + terminal_state.Save (stdin_fd, false); + terminal.SetCanonical(false); + terminal.SetEcho(true); } - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty "); - reader.SetIsDone (true); + + ScriptInterpreterPython::Locker locker (m_python, + ScriptInterpreterPython::Locker::AcquireLock | + ScriptInterpreterPython::Locker::InitSession | + ScriptInterpreterPython::Locker::InitGlobals, + ScriptInterpreterPython::Locker::FreeAcquiredLock | + ScriptInterpreterPython::Locker::TearDownSession); + + // The following call drops into the embedded interpreter loop and stays there until the + // user chooses to exit from the Python interpreter. + // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before + // a system call that can hang, and lock it when the syscall has returned. + + // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and + // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want + // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off, + // and things could hang (it's happened before). + + StreamString run_string; + run_string.Printf ("run_python_interpreter (%s)", m_python->GetDictionaryName ()); + PyRun_SimpleString (run_string.GetData()); + + if (is_a_tty) + terminal_state.Restore(); } } - break; - - case eInputReaderDeactivate: - // When another input reader is pushed, don't leave the session... - //script_interpreter->LeaveSession (); - break; + SetIsDone(true); + } - case eInputReaderReactivate: - { - ScriptInterpreterPython::Locker locker (script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; + virtual void + Hide () + { - case eInputReaderInterrupt: - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24); - break; + } + + virtual void + Refresh () + { - case eInputReaderEndOfFile: - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()\n", 7); - break; - - case eInputReaderGotToken: - if (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor() != -1) - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu", bytes, - bytes_len); - if (bytes && bytes_len) - { - if ((int) bytes[0] == 4) - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()", 6); - else - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), bytes, bytes_len); - } - ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "\n", 1); - } - else - { - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad.", - bytes, - bytes_len); - reader.SetIsDone (true); - } + } - break; + virtual void + Cancel () + { - case eInputReaderDone: - { - Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock, - ScriptInterpreterPython::Locker::FreeAcquiredLock); - script_interpreter->LeaveSession (); - } - - // Restore terminal settings if they were validly saved - if (log) - log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader."); - - script_interpreter->RestoreTerminalState (); - - script_interpreter->m_embedded_python_pty.CloseMasterFileDescriptor(); - break; } - return bytes_len; -} + virtual void + Interrupt () + { + + } + + virtual void + GotEOF() + { + + } +protected: + ScriptInterpreterPython *m_python; +}; void @@ -918,24 +816,13 @@ ScriptInterpreterPython::ExecuteInterpreterLoop () // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't // do it. - if (!debugger.GetInputFile().IsValid()) + if (!debugger.GetInputFile()->GetFile().IsValid()) return; - InputReaderSP reader_sp (new InputReader(debugger)); - if (reader_sp) - { - Error error (reader_sp->Initialize (ScriptInterpreterPython::InputReaderCallback, - this, // baton - eInputReaderGranularityLine, // token size, to pass to callback function - NULL, // end token - NULL, // prompt - true)); // echo input - - if (error.Success()) - { - debugger.PushInputReader (reader_sp); - m_embedded_python_input_reader_sp = reader_sp; - } + IOHandlerSP io_handler_sp (new IOHandlerPythonInterpreter (debugger, this)); + if (io_handler_sp) + { + debugger.PushIOHandler(io_handler_sp); } } @@ -951,27 +838,21 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); PyObject *py_return = NULL; - PyObject *mainmod = PyImport_AddModule ("__main__"); - PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = NULL; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); PyObject *py_error = NULL; bool ret_success = false; - bool should_decrement_locals = false; int success; - locals = FindSessionDictionary(m_dictionary_name.c_str()); + PythonDictionary locals = GetSessionDictionary (); - if (locals == NULL) + if (!locals) { - locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); - should_decrement_locals = true; + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); } - if (locals == NULL) - { + if (!locals) locals = globals; - should_decrement_locals = false; - } py_error = PyErr_Occurred(); if (py_error != NULL) @@ -980,22 +861,18 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, if (in_string != NULL) { { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return = PyRun_String (in_string, Py_eval_input, globals, locals); + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + py_return = PyRun_String (in_string, Py_eval_input, globals.get(), locals.get()); if (py_return == NULL) { py_error = PyErr_Occurred (); if (py_error != NULL) PyErr_Clear (); - py_return = PyRun_String (in_string, Py_single_input, globals, locals); + py_return = PyRun_String (in_string, Py_single_input, globals.get(), locals.get()); } } - if (locals != NULL - && should_decrement_locals) - Py_XDECREF (locals); - if (py_return != NULL) { switch (return_type) @@ -1115,35 +992,31 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string, return ret_success; } -bool +Error ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options) { - + Error error; Locker locker(this, ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0), ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); bool success = false; - PyObject *py_return = NULL; - PyObject *mainmod = PyImport_AddModule ("__main__"); - PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = NULL; + PythonObject return_value; + PythonObject &main_module = GetMainModule (); + PythonDictionary globals (PyModule_GetDict(main_module.get())); PyObject *py_error = NULL; - bool should_decrement_locals = false; - locals = FindSessionDictionary(m_dictionary_name.c_str()); + PythonDictionary locals = GetSessionDictionary (); - if (locals == NULL) + if (!locals) { - locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); - should_decrement_locals = true; + locals = PyObject_GetAttrString (globals.get(), m_dictionary_name.c_str()); } - if (locals == NULL) + if (!locals) { locals = globals; - should_decrement_locals = false; } py_error = PyErr_Occurred(); @@ -1159,16 +1032,11 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec if (compiled_code) { { // scope for PythonInputReaderManager - PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); - py_return = PyEval_EvalCode (compiled_code, globals, locals); + //PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL); + return_value.Reset(PyEval_EvalCode (compiled_code, globals.get(), locals.get())); } - if (py_return != NULL) - { + if (return_value) success = true; - Py_XDECREF (py_return); - } - if (locals && should_decrement_locals) - Py_XDECREF (locals); } } } @@ -1176,324 +1044,50 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec py_error = PyErr_Occurred (); if (py_error != NULL) { - success = false; - if (options.GetMaskoutErrors()) - { - if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError)) - PyErr_Print (); - PyErr_Clear(); - } - } - - return success; -} - -static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end."; - -static const char *g_bkpt_command_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" - "def function(frame,bp_loc,internal_dict):\n" - " \"\"\"frame: the SBFrame for the location at which you stopped\n" - " bp_loc: an SBBreakpointLocation for the breakpoint location information\n" - " internal_dict: an LLDB support object not to be used\"\"\""; - -size_t -ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - static StringList commands_in_progress; - - switch (notification) - { - case eInputReaderActivate: - { - - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - commands_in_progress.Clear(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_bkpt_command_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; +// puts(in_string); +// _PyObject_Dump (py_error); +// PyErr_Print(); +// success = false; - case eInputReaderGotToken: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - std::string temp_string (bytes, bytes_len); - commands_in_progress.AppendString (temp_string.c_str()); - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderEndOfFile: - case eInputReaderInterrupt: - // Control-c (SIGINT) & control-d both mean finish & exit. - reader.SetIsDone(true); + PyObject *type = NULL; + PyObject *value = NULL; + PyObject *traceback = NULL; + PyErr_Fetch (&type,&value,&traceback); - // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. - if (notification == eInputReaderInterrupt) - commands_in_progress.Clear(); + // get the backtrace + std::string bt = ReadPythonBacktrace(traceback); - // Fall through here... - - case eInputReaderDone: + if (value && value != Py_None) + error.SetErrorStringWithFormat("%s\n%s", PyString_AsString(PyObject_Str(value)),bt.c_str()); + else + error.SetErrorStringWithFormat("%s",bt.c_str()); + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + if (options.GetMaskoutErrors()) { - bool batch_mode = notification == eInputReaderDone ? - reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : - true; - BreakpointOptions *bp_options = (BreakpointOptions *)baton; - std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - data_ap->user_source.AppendList (commands_in_progress); - if (data_ap.get()) - { - ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (interpreter) - { - if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source, - data_ap->script_source)) - { - BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); - bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); - } - else if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - else - { - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - } + PyErr_Clear(); } - break; - } - return bytes_len; + return error; } -size_t -ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback -( - void *baton, - InputReader &reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - static StringList commands_in_progress; - - switch (notification) - { - case eInputReaderActivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - - commands_in_progress.Clear(); - if (!batch_mode) - { - out_stream->Printf ("%s\n", g_reader_instructions); - if (reader.GetPrompt()) - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - if (reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderAsynchronousOutputWritten: - break; - - case eInputReaderGotToken: - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); - std::string temp_string (bytes, bytes_len); - commands_in_progress.AppendString (temp_string.c_str()); - if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) - { - out_stream->Printf ("%s", reader.GetPrompt()); - out_stream->Flush (); - } - } - break; - - case eInputReaderEndOfFile: - case eInputReaderInterrupt: - // Control-c (SIGINT) & control-d both mean finish & exit. - reader.SetIsDone(true); - - // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command. - if (notification == eInputReaderInterrupt) - commands_in_progress.Clear(); - - // Fall through here... - - case eInputReaderDone: - { - bool batch_mode = notification == eInputReaderDone ? - reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() : - true; - WatchpointOptions *wp_options = (WatchpointOptions *)baton; - std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData()); - data_ap->user_source.AppendList (commands_in_progress); - if (data_ap.get()) - { - ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (interpreter) - { - if (interpreter->GenerateWatchpointCommandCallbackData (data_ap->user_source, - data_ap->script_source)) - { - BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release())); - wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp); - } - else if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: No command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - else - { - if (!batch_mode) - { - StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); - out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n"); - out_stream->Flush(); - } - } - } - } - break; - - } - - return bytes_len; -} void ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, CommandReturnObject &result) { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); - - InputReaderSP reader_sp (new InputReader (debugger)); - - if (reader_sp) - { - Error err = reader_sp->Initialize ( - ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback, - bp_options, // baton - eInputReaderGranularityLine, // token size, for feeding data to callback function - "DONE", // end token - " ", // prompt - true); // echo input - - if (err.Success()) - debugger.PushInputReader (reader_sp); - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } + m_active_io_handler = eIOHandlerBreakpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, bp_options); } void ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, CommandReturnObject &result) { - Debugger &debugger = GetCommandInterpreter().GetDebugger(); - - InputReaderSP reader_sp (new InputReader (debugger)); - - if (reader_sp) - { - Error err = reader_sp->Initialize ( - ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback, - wp_options, // baton - eInputReaderGranularityLine, // token size, for feeding data to callback function - "DONE", // end token - "> ", // prompt - true); // echo input - - if (err.Success()) - debugger.PushInputReader (reader_sp); - else - { - result.AppendError (err.AsCString()); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError("out of memory"); - result.SetStatus (eReturnStatusFailed); - } + m_active_io_handler = eIOHandlerWatchpoint; + m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options); } // Set a Python one-liner as the callback for the breakpoint. @@ -1548,7 +1142,7 @@ ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &func // Convert StringList to one long, newline delimited, const char *. std::string function_def_string(function_def.CopyList()); - return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); + return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)).Success(); } bool @@ -1700,7 +1294,9 @@ ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, ll void* ret_val; { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); ret_val = g_swig_create_os_plugin (class_name, m_dictionary_name.c_str(), process_sp); @@ -1712,7 +1308,9 @@ ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, ll lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock(this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_register_info"; @@ -1771,7 +1369,9 @@ ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_thread_info"; @@ -1857,7 +1457,9 @@ lldb::ScriptInterpreterObjectSP ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp, lldb::tid_t tid) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock (this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "get_register_data"; static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid)); @@ -1919,7 +1521,9 @@ ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP lldb::tid_t tid, lldb::addr_t context) { - Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock); + Locker py_lock(this, + Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); static char callee_name[] = "create_thread"; std::string param_format; @@ -2011,7 +1615,7 @@ ScriptInterpreterPython::GetDynamicSettings (lldb::ScriptInterpreterObjectSP plu PyObject *reply_pyobj = nullptr; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); TargetSP target_sp(target->shared_from_this()); reply_pyobj = (PyObject*)g_swig_plugin_get(plugin_module_sp->GetObject(),setting_name,target_sp); } @@ -2045,7 +1649,7 @@ ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name void* ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_synthetic_script (class_name, python_interpreter->m_dictionary_name.c_str(), valobj); @@ -2136,14 +1740,14 @@ ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name, && *python_function_name) { { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); { - Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback"); - ret_val = g_swig_typescript_callback (python_function_name, - FindSessionDictionary(m_dictionary_name.c_str()), - valobj, - &new_callee, - retval); + Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback"); + ret_val = g_swig_typescript_callback (python_function_name, + GetSessionDictionary().get(), + valobj, + &new_callee, + retval); } } } @@ -2188,8 +1792,7 @@ ScriptInterpreterPython::BreakpointCallbackFunction if (!script_interpreter) return true; - if (python_function_name != NULL - && python_function_name[0] != '\0') + if (python_function_name && python_function_name[0]) { const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id); @@ -2201,8 +1804,8 @@ ScriptInterpreterPython::BreakpointCallbackFunction { bool ret_val = true; { - Locker py_lock(python_interpreter); - ret_val = g_swig_breakpoint_callback (python_function_name, + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_breakpoint_callback (python_function_name, python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, bp_loc_sp); @@ -2243,8 +1846,7 @@ ScriptInterpreterPython::WatchpointCallbackFunction if (!script_interpreter) return true; - if (python_function_name != NULL - && python_function_name[0] != '\0') + if (python_function_name && python_function_name[0]) { const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP()); WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id); @@ -2254,8 +1856,8 @@ ScriptInterpreterPython::WatchpointCallbackFunction { bool ret_val = true; { - Locker py_lock(python_interpreter); - ret_val = g_swig_watchpoint_callback (python_function_name, + Locker py_lock(python_interpreter, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + ret_val = g_swig_watchpoint_callback (python_function_name, python_interpreter->m_dictionary_name.c_str(), stop_frame_sp, wp_sp); @@ -2269,106 +1871,6 @@ ScriptInterpreterPython::WatchpointCallbackFunction return true; } -lldb::thread_result_t -ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton) -{ - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); - - if (log) - log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread starting...", baton); - - char error_str[1024]; - const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str)); - - if (pty_slave_name != NULL) - { - StreamString run_string; - - // Ensure we have the GIL before running any Python code. - // Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed), - // we can just release the GIL after finishing our work. - // If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function. - Locker locker(script_interpreter, - ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals, - ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession); - - run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), - pty_slave_name); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - // The following call drops into the embedded interpreter loop and stays there until the - // user chooses to exit from the Python interpreter. - // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before - // a system call that can hang, and lock it when the syscall has returned. - - // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and - // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want - // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off, - // and things could hang (it's happened before). - - run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear (); - - run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - - run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); - PyRun_SimpleString (run_string.GetData()); - run_string.Clear(); - } - - if (script_interpreter->m_embedded_python_input_reader_sp) - script_interpreter->m_embedded_python_input_reader_sp->SetIsDone (true); - - script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor(); - - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT); - if (log) - log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton); - - - // Clean up the input reader and make the debugger pop it off the stack. - Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger(); - const InputReaderSP reader_sp = script_interpreter->m_embedded_python_input_reader_sp; - if (reader_sp) - { - debugger.PopInputReader (reader_sp); - script_interpreter->m_embedded_python_input_reader_sp.reset(); - } - - return NULL; -} - -lldb::thread_result_t -ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader (lldb::thread_arg_t baton) -{ - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; - - const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp; - - if (reader_sp) - reader_sp->WaitOnReaderIsDone(); - - return NULL; -} - size_t ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp) { @@ -2386,7 +1888,7 @@ ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObje uint32_t ret_val = 0; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_calc_children (implementor); } @@ -2410,7 +1912,7 @@ ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& lldb::ValueObjectSP ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); void* child_ptr = g_swig_get_child_index (implementor,idx); if (child_ptr != NULL && child_ptr != Py_None) { @@ -2446,7 +1948,7 @@ ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterO int ret_val = UINT32_MAX; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_get_index_child (implementor, child_name); } @@ -2470,7 +1972,7 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre return ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_update_provider (implementor); } @@ -2494,7 +1996,7 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr return ret_val; { - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_mighthavechildren_provider (implementor); } @@ -2582,7 +2084,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { ProcessSP process_sp(process->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_process (impl_function, m_dictionary_name.c_str(), process_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2614,7 +2116,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { ThreadSP thread_sp(thread->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_thread (impl_function, m_dictionary_name.c_str(), thread_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2646,7 +2148,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { TargetSP target_sp(target->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_target (impl_function, m_dictionary_name.c_str(), target_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2678,7 +2180,7 @@ ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function, } { StackFrameSP frame_sp(frame->shared_from_this()); - Locker py_lock(this); + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); ret_val = g_swig_run_script_keyword_frame (impl_function, m_dictionary_name.c_str(), frame_sp, output); if (!ret_val) error.SetErrorString("python script evaluation failed"); @@ -2728,7 +2230,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // Before executing Pyton code, lock the GIL. Locker py_lock (this, - Locker::AcquireLock | (init_session ? Locker::InitSession : 0), + Locker::AcquireLock | (init_session ? Locker::InitSession : 0) | Locker::NoSTDIN, Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0)); if (target_file.GetFileType() == FileSpec::eFileTypeInvalid || @@ -2755,7 +2257,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.insert(1,'%s');\n\n", directory.c_str(), directory.c_str()); - bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); + bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)).Success(); if (!syspath_retval) { error.SetErrorString("Python sys.path handling failed"); @@ -2782,7 +2284,6 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, command_stream.Clear(); command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str()); bool does_contain = false; - int refcount = 0; // this call will succeed if the module was ever imported in any Debugger in the lifetime of the process // in which this LLDB framework is living bool was_imported_globally = (ExecuteOneLineWithReturn(command_stream.GetData(), @@ -2792,10 +2293,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, // this call will fail if the module was not imported in this Debugger before command_stream.Clear(); command_stream.Printf("sys.getrefcount(%s)",basename.c_str()); - bool was_imported_locally = (ExecuteOneLineWithReturn(command_stream.GetData(), - ScriptInterpreterPython::eScriptReturnTypeInt, - &refcount, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0); + bool was_imported_locally = !(GetSessionDictionary().GetItemForKey(basename.c_str()).IsNULLOrNone()); bool was_imported = (was_imported_globally || was_imported_locally); @@ -2818,47 +2316,9 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname, else command_stream.Printf("import %s",basename.c_str()); - bool import_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false).SetMaskoutErrors(false)); - PyObject* py_error = PyErr_Occurred(); // per Python docs: "you do not need to Py_DECREF()" the return of this function - - if (py_error || !import_retval) // check for failure of the import - { - if (py_error) // if we have a Python error.. - { - PyObject *type = NULL,*value = NULL,*traceback = NULL; - PyErr_Fetch (&type,&value,&traceback); - - if (PyErr_GivenExceptionMatches (py_error, PyExc_ImportError)) // and it is an ImportError - { - if (value && value != Py_None) - error.SetErrorString(PyString_AsString(PyObject_Str(value))); - else - error.SetErrorString("ImportError raised by imported module"); - } - else // any other error - { - // get the backtrace - std::string bt = ReadPythonBacktrace(traceback); - - if (value && value != Py_None) - error.SetErrorStringWithFormat("Python error raised while importing module: %s - traceback: %s", PyString_AsString(PyObject_Str(value)),bt.c_str()); - else - error.SetErrorStringWithFormat("Python raised an error while importing module - traceback: %s",bt.c_str()); - } - - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - } - else // we failed but have no error to explain why - { - error.SetErrorString("unknown error while importing module"); - } - - // anyway, clear the error indicator and return false - PyErr_Clear(); + error = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)); + if (error.Fail()) return false; - } // if we are here, everything worked // call __lldb_init_module(debugger,dict) @@ -2954,7 +2414,7 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function, // to set the asynchronous exception - not a desirable situation m_command_thread_state = _PyThreadState_Current; - PythonInputReaderManager py_input(this); + //PythonInputReaderManager py_input(this); ret_val = g_swig_call_command (impl_function, m_dictionary_name.c_str(), @@ -3007,8 +2467,8 @@ std::unique_ptr<ScriptInterpreterLocker> ScriptInterpreterPython::AcquireInterpreterLock () { std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker(this, - Locker::AcquireLock | Locker::InitSession, - Locker::FreeLock | Locker::TearDownSession)); + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN, + Locker::FreeLock | Locker::TearDownSession)); return py_lock; } @@ -3059,6 +2519,13 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb void ScriptInterpreterPython::InitializePrivate () { + static int g_initialized = false; + + if (g_initialized) + return; + + g_initialized = true; + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); // Python will muck with STDIN terminal state, so save off any current TTY @@ -3081,8 +2548,8 @@ ScriptInterpreterPython::InitializePrivate () Py_InitializeEx (0); // Initialize SWIG after setting up python - assert (g_swig_init_callback != NULL); - g_swig_init_callback (); + if (g_swig_init_callback) + g_swig_init_callback (); // Update the path python uses to search for modules to include the current directory. diff --git a/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py index 0e57c1e..bc0dd6d 100644 --- a/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py +++ b/contrib/llvm/tools/lldb/source/Interpreter/embedded_interpreter.py @@ -1,103 +1,108 @@ -import readline +import __builtin__ import code +import lldb import sys import traceback -class SimpleREPL(code.InteractiveConsole): - def __init__(self, prompt, dict): - code.InteractiveConsole.__init__(self,dict) - self.prompt = prompt - self.loop_exit = False - self.dict = dict +try: + import readline + import rlcompleter +except ImportError: + have_readline = False +else: + have_readline = True + if 'libedit' in readline.__doc__: + readline.parse_and_bind('bind ^I rl_complete') + else: + readline.parse_and_bind('tab: complete') - def interact(self): - try: - sys.ps1 - except AttributeError: - sys.ps1 = ">>> " - try: - sys.ps2 - except AttributeError: - sys.ps2 = "... " +g_builtin_override_called = False - while not self.loop_exit: - try: - self.read_py_command() - except (SystemExit, EOFError): - # EOF while in Python just breaks out to top level. - self.write('\n') - self.loop_exit = True - break - except KeyboardInterrupt: - self.write("\nKeyboardInterrupt\n") - self.resetbuffer() - more = 0 - except: - traceback.print_exc() +class LLDBQuitter(object): + def __init__(self, name): + self.name = name + def __repr__(self): + self() + def __call__(self, code=None): + global g_builtin_override_called + g_builtin_override_called = True + raise SystemExit(-1) - def process_input (self, in_str): - # Canonicalize the format of the input string - temp_str = in_str - temp_str.strip(' \t') - words = temp_str.split() - temp_str = ('').join(words) +def setquit(): + '''Redefine builtin functions 'quit()' and 'exit()' to print a message and raise an EOFError exception.''' + # This function will be called prior to each interactive + # interpreter loop or each single line, so we set the global + # g_builtin_override_called to False so we know if a SystemExit + # is thrown, we can catch it and tell the difference between + # a call to "quit()" or "exit()" and something like + # "sys.exit(123)" + global g_builtin_override_called + g_builtin_override_called = False + __builtin__.quit = LLDBQuitter('quit') + __builtin__.exit = LLDBQuitter('exit') - # Check the input string to see if it was the quit - # command. If so, intercept it, so that it doesn't - # close stdin on us! - if (temp_str.lower() == "quit()" or temp_str.lower() == "exit()"): - self.loop_exit = True - in_str = "raise SystemExit " - return in_str +# When running one line, we might place the string to run in this string +# in case it would be hard to correctly escape a string's contents - def my_raw_input (self, prompt): - stream = sys.stdout - stream.write (prompt) - stream.flush () - try: - line = sys.stdin.readline() - except KeyboardInterrupt: - line = " \n" - except (SystemExit, EOFError): - line = "quit()\n" - if not line: - raise EOFError - if line[-1] == '\n': - line = line[:-1] - return line +g_run_one_line_str = None - def read_py_command(self): - # Read off a complete Python command. - more = 0 - while 1: - if more: - prompt = sys.ps2 - else: - prompt = sys.ps1 - line = self.my_raw_input(prompt) - # Can be None if sys.stdin was redefined - encoding = getattr(sys.stdin, "encoding", None) - if encoding and not isinstance(line, unicode): - line = line.decode(encoding) - line = self.process_input (line) - more = self.push(line) - if not more: - break - def one_line (self, input): - line = self.process_input (input) - more = self.push(line) - if more: - self.write ("Input not a complete line.") - self.resetbuffer() - more = 0 +def get_terminal_size(fd): + try: + import fcntl, termios, struct + hw = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) + except: + hw = (0,0) + return hw -def run_python_interpreter (dict): - # Pass in the dictionary, for continuity from one session to the next. - repl = SimpleREPL('>>> ', dict) - repl.interact() +def readfunc_stdio(prompt): + sys.stdout.write(prompt) + return sys.stdin.readline() -def run_one_line (dict, input_string): - repl = SimpleREPL ('', dict) - repl.one_line (input_string) +def run_python_interpreter (local_dict): + # Pass in the dictionary, for continuity from one session to the next. + setquit() + try: + fd = sys.stdin.fileno(); + interacted = False + if get_terminal_size(fd)[1] == 0: + try: + import termios + old = termios.tcgetattr(fd) + if old[3] & termios.ECHO: + # Need to turn off echoing and restore + new = termios.tcgetattr(fd) + new[3] = new[3] & ~termios.ECHO + try: + termios.tcsetattr(fd, termios.TCSADRAIN, new) + interacted = True + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()'.", readfunc=readfunc_stdio, local=local_dict) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old) + except: + pass + # Don't need to turn off echoing + if not interacted: + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", readfunc=readfunc_stdio, local=local_dict) + else: + # We have a real interactive terminal + code.interact(banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", local=local_dict) + except SystemExit as e: + global g_builtin_override_called + if not g_builtin_override_called: + print 'Script exited with %s' %(e) +def run_one_line (local_dict, input_string): + global g_run_one_line_str + setquit() + try: + repl = code.InteractiveConsole(local_dict); + if input_string: + repl.runsource (input_string) + elif g_run_one_line_str: + repl.runsource (g_run_one_line_str) + + except SystemExit as e: + global g_builtin_override_called + if not g_builtin_override_called: + print 'Script exited with %s' %(e) diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp index f360a18..8596381 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp @@ -235,22 +235,12 @@ ABIMacOSX_i386::GetRedZoneSize () const ABISP ABIMacOSX_i386::CreateInstance (const ArchSpec &arch) { - static ABISP g_abi_mac_sp; - static ABISP g_abi_other_sp; - if (arch.GetTriple().getArch() == llvm::Triple::x86) - { - if (arch.GetTriple().isOSDarwin()) - { - if (!g_abi_mac_sp) - g_abi_mac_sp.reset (new ABIMacOSX_i386(true)); - return g_abi_mac_sp; - } - else - { - if (!g_abi_other_sp) - g_abi_other_sp.reset (new ABIMacOSX_i386(false)); - return g_abi_other_sp; - } + static ABISP g_abi_sp; + if (arch.GetTriple().getArch() == llvm::Triple::x86) + { + if (!g_abi_sp) + g_abi_sp.reset (new ABIMacOSX_i386); + return g_abi_sp; } return ABISP(); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h index a2eee28..43784a5 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h @@ -71,24 +71,25 @@ public: return true; } + // The Darwin i386 ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (4-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. + // + // If we were to enforce 16-byte alignment, we also need to relax to 4-byte + // alignment for non-darwin i386 targets. virtual bool CallFrameAddressIsValid (lldb::addr_t cfa) { - // Darwin call frame addresses must be 16-byte aligned, but other OS's - // only need 4-byte alignment. Otherwise the ABI matches, so we have - // this one minor override here. - if (target_is_darwin) - { - // Make sure the stack call frame addresses are are 16 byte aligned - if (cfa & (16ull - 1ull)) - return false; // Not 16 byte aligned - } - else - { - // Make sure the stack call frame addresses are are 4 byte aligned - if (cfa & (4ull - 1ull)) - return false; // Not 4 byte aligned - } + // Make sure the stack call frame addresses are are 4 byte aligned + if (cfa & (4ull - 1ull)) + return false; // Not 4 byte aligned if (cfa == 0) return false; // Zero is not a valid stack address return true; @@ -139,11 +140,7 @@ protected: RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); private: - ABIMacOSX_i386(bool is_darwin) : lldb_private::ABI(), - target_is_darwin(is_darwin) - { } // Call CreateInstance instead. - - bool target_is_darwin; + ABIMacOSX_i386() : lldb_private::ABI() { } // Call CreateInstance instead. }; diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h index 5ccb6e5f..7fd1b6c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h @@ -68,12 +68,22 @@ public: return true; } + // The SysV x86_64 ABI requires that stack frames be 16 byte aligned. + // When there is a trap handler on the stack, e.g. _sigtramp in userland + // code, we've seen that the stack pointer is often not aligned properly + // before the handler is invoked. This means that lldb will stop the unwind + // early -- before the function which caused the trap. + // + // To work around this, we relax that alignment to be just word-size (8-bytes). + // Whitelisting the trap handlers for user space would be easy (_sigtramp) but + // in other environments there can be a large number of different functions + // involved in async traps. virtual bool CallFrameAddressIsValid (lldb::addr_t cfa) { - // Make sure the stack call frame addresses are 16 byte aligned - if (cfa & (16ull - 1ull)) - return false; // Not 16 byte aligned + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & (8ull - 1ull)) + return false; // Not 8 byte aligned if (cfa == 0) return false; // Zero is not a valid stack address return true; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp index 61c3c64..e9b8a9f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp @@ -35,6 +35,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/StackFrame.h" @@ -127,6 +128,7 @@ public: bool got_op = false; DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC(); const ArchSpec &arch = llvm_disasm.GetArchitecture(); + const lldb::ByteOrder byte_order = data.GetByteOrder(); const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize(); const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize(); @@ -135,26 +137,26 @@ public: // Fixed size instructions, just read that amount of data. if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size)) return false; - + switch (min_op_byte_size) { case 1: - m_opcode.SetOpcode8 (data.GetU8 (&data_offset)); + m_opcode.SetOpcode8 (data.GetU8 (&data_offset), byte_order); got_op = true; break; case 2: - m_opcode.SetOpcode16 (data.GetU16 (&data_offset)); + m_opcode.SetOpcode16 (data.GetU16 (&data_offset), byte_order); got_op = true; break; case 4: - m_opcode.SetOpcode32 (data.GetU32 (&data_offset)); + m_opcode.SetOpcode32 (data.GetU32 (&data_offset), byte_order); got_op = true; break; case 8: - m_opcode.SetOpcode64 (data.GetU64 (&data_offset)); + m_opcode.SetOpcode64 (data.GetU64 (&data_offset), byte_order); got_op = true; break; @@ -177,20 +179,20 @@ public: uint32_t thumb_opcode = data.GetU16(&data_offset); if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0)) { - m_opcode.SetOpcode16 (thumb_opcode); + m_opcode.SetOpcode16 (thumb_opcode, byte_order); m_is_valid = true; } else { thumb_opcode <<= 16; thumb_opcode |= data.GetU16(&data_offset); - m_opcode.SetOpcode16_2 (thumb_opcode); + m_opcode.SetOpcode16_2 (thumb_opcode, byte_order); m_is_valid = true; } } else { - m_opcode.SetOpcode32 (data.GetU32(&data_offset)); + m_opcode.SetOpcode32 (data.GetU32(&data_offset), byte_order); m_is_valid = true; } } @@ -303,12 +305,13 @@ public: inst_size = m_opcode.GetByteSize(); StreamString mnemonic_strm; lldb::offset_t offset = 0; + lldb::ByteOrder byte_order = data.GetByteOrder(); switch (inst_size) { case 1: { const uint8_t uval8 = data.GetU8 (&offset); - m_opcode.SetOpcode8 (uval8); + m_opcode.SetOpcode8 (uval8, byte_order); m_opcode_name.assign (".byte"); mnemonic_strm.Printf("0x%2.2x", uval8); } @@ -316,7 +319,7 @@ public: case 2: { const uint16_t uval16 = data.GetU16(&offset); - m_opcode.SetOpcode16(uval16); + m_opcode.SetOpcode16(uval16, byte_order); m_opcode_name.assign (".short"); mnemonic_strm.Printf("0x%4.4x", uval16); } @@ -324,7 +327,7 @@ public: case 4: { const uint32_t uval32 = data.GetU32(&offset); - m_opcode.SetOpcode32(uval32); + m_opcode.SetOpcode32(uval32, byte_order); m_opcode_name.assign (".long"); mnemonic_strm.Printf("0x%8.8x", uval32); } @@ -332,7 +335,7 @@ public: case 8: { const uint64_t uval64 = data.GetU64(&offset); - m_opcode.SetOpcode64(uval64); + m_opcode.SetOpcode64(uval64, byte_order); m_opcode_name.assign (".quad"); mnemonic_strm.Printf("0x%16.16" PRIx64, uval64); } @@ -432,7 +435,8 @@ DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, uns m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "", features_str)); - m_asm_info_ap.reset(curr_target->createMCAsmInfo(*curr_target->createMCRegInfo(triple), triple)); + std::unique_ptr<llvm::MCRegisterInfo> reg_info(curr_target->createMCRegInfo(triple)); + m_asm_info_ap.reset(curr_target->createMCAsmInfo(*reg_info, triple)); if (m_instr_info_ap.get() == NULL || m_reg_info_ap.get() == NULL || m_subtarget_info_ap.get() == NULL || m_asm_info_ap.get() == NULL) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 284890f..11c92a0 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -150,46 +150,6 @@ DynamicLoaderPOSIXDYLD::DidLaunch() } } -ModuleSP -DynamicLoaderPOSIXDYLD::GetTargetExecutable() -{ - Target &target = m_process->GetTarget(); - ModuleSP executable = target.GetExecutableModule(); - - if (executable.get()) - { - if (executable->GetFileSpec().Exists()) - { - ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture()); - ModuleSP module_sp (new Module (module_spec)); - - // Check if the executable has changed and set it to the target executable if they differ. - if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid()) - { - if (module_sp->GetUUID() != executable->GetUUID()) - executable.reset(); - } - else if (executable->FileHasChanged()) - { - executable.reset(); - } - - if (!executable.get()) - { - executable = target.GetSharedModule(module_spec); - if (executable.get() != target.GetExecutableModulePointer()) - { - // Don't load dependent images since we are in dyld where we will know - // and find out about all images that are loaded - const bool get_dependent_images = false; - target.SetExecutableModule(executable, get_dependent_images); - } - } - } - } - return executable; -} - Error DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm) { @@ -211,48 +171,17 @@ DynamicLoaderPOSIXDYLD::CanLoadImage() void DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t link_map_addr, addr_t base_addr) { - SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); - const SectionList *sections = GetSectionListFromModule(module); - - assert(sections && "SectionList missing from loaded module."); - m_loaded_modules[module] = link_map_addr; - const size_t num_sections = sections->GetSize(); - - for (unsigned i = 0; i < num_sections; ++i) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr; - lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp); - - // If the file address of the section is zero then this is not an - // allocatable/loadable section (property of ELF sh_addr). Skip it. - if (new_load_addr == base_addr) - continue; - - if (old_load_addr == LLDB_INVALID_ADDRESS || - old_load_addr != new_load_addr) - load_list.SetSectionLoadAddress(section_sp, new_load_addr); - } + UpdateLoadedSectionsCommon(module, base_addr); } void DynamicLoaderPOSIXDYLD::UnloadSections(const ModuleSP module) { - SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); - const SectionList *sections = GetSectionListFromModule(module); - - assert(sections && "SectionList missing from unloaded module."); - m_loaded_modules.erase(module); - const size_t num_sections = sections->GetSize(); - for (size_t i = 0; i < num_sections; ++i) - { - SectionSP section_sp (sections->GetSectionAtIndex(i)); - load_list.SetSectionUnloaded(section_sp); - } + UnloadSectionsCommon(module); } void @@ -481,26 +410,6 @@ DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() m_process->GetTarget().ModulesDidLoad(module_list); } -ModuleSP -DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t link_map_addr, addr_t base_addr) -{ - Target &target = m_process->GetTarget(); - ModuleList &modules = target.GetImages(); - ModuleSP module_sp; - - ModuleSpec module_spec (file, target.GetArchitecture()); - if ((module_sp = modules.FindFirstModule (module_spec))) - { - UpdateLoadedSections(module_sp, link_map_addr, base_addr); - } - else if ((module_sp = target.GetSharedModule(module_spec))) - { - UpdateLoadedSections(module_sp, link_map_addr, base_addr); - } - - return module_sp; -} - addr_t DynamicLoaderPOSIXDYLD::ComputeLoadOffset() { @@ -544,41 +453,6 @@ DynamicLoaderPOSIXDYLD::GetEntryPoint() return m_entry_point; } -const SectionList * -DynamicLoaderPOSIXDYLD::GetSectionListFromModule(const ModuleSP module) const -{ - SectionList *sections = nullptr; - if (module.get()) - { - ObjectFile *obj_file = module->GetObjectFile(); - if (obj_file) - { - sections = obj_file->GetSectionList(); - } - } - return sections; -} - -static int ReadInt(Process *process, addr_t addr) -{ - Error error; - int value = (int)process->ReadUnsignedIntegerFromMemory(addr, sizeof(uint32_t), 0, error); - if (error.Fail()) - return -1; - else - return value; -} - -static addr_t ReadPointer(Process *process, addr_t addr) -{ - Error error; - addr_t value = process->ReadPointerFromMemory(addr, error); - if (error.Fail()) - return LLDB_INVALID_ADDRESS; - else - return value; -} - lldb::addr_t DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const lldb::ThreadSP thread) { @@ -600,26 +474,27 @@ DynamicLoaderPOSIXDYLD::GetThreadLocalData (const lldb::ModuleSP module, const l return LLDB_INVALID_ADDRESS; // Find the module's modid. - int modid = ReadInt (m_process, link_map + metadata.modid_offset); + int modid_size = 4; // FIXME(spucci): This isn't right for big-endian 64-bit + int64_t modid = ReadUnsignedIntWithSizeInBytes (link_map + metadata.modid_offset, modid_size); if (modid == -1) return LLDB_INVALID_ADDRESS; // Lookup the DTV stucture for this thread. addr_t dtv_ptr = tp + metadata.dtv_offset; - addr_t dtv = ReadPointer (m_process, dtv_ptr); + addr_t dtv = ReadPointer (dtv_ptr); if (dtv == LLDB_INVALID_ADDRESS) return LLDB_INVALID_ADDRESS; // Find the TLS block for this module. addr_t dtv_slot = dtv + metadata.dtv_slot_size*modid; - addr_t tls_block = ReadPointer (m_process, dtv_slot + metadata.tls_offset); + addr_t tls_block = ReadPointer (dtv_slot + metadata.tls_offset); Module *mod = module.get(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (log) log->Printf("DynamicLoaderPOSIXDYLD::Performed TLS lookup: " - "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%i, tls_block=0x%" PRIx64 "\n", - mod->GetObjectName().AsCString(""), link_map, tp, modid, tls_block); + "module=%s, link_map=0x%" PRIx64 ", tp=0x%" PRIx64 ", modid=%" PRId64 ", tls_block=0x%" PRIx64 "\n", + mod->GetObjectName().AsCString(""), link_map, tp, (int64_t)modid, tls_block); return tls_block; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 7997b34..9ced5da 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -126,7 +126,7 @@ protected: /// @param link_map_addr The virtual address of the link map for the @p module. /// /// @param base_addr The virtual base address @p module is loaded at. - void + virtual void UpdateLoadedSections(lldb::ModuleSP module, lldb::addr_t link_map_addr, lldb::addr_t base_addr); @@ -134,14 +134,9 @@ protected: /// Removes the loaded sections from the target in @p module. /// /// @param module The module to traverse. - void + virtual void UnloadSections(const lldb::ModuleSP module); - /// Locates or creates a module given by @p file and updates/loads the - /// resulting module at the virtual base address @p base_addr. - lldb::ModuleSP - LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t link_map_addr, lldb::addr_t base_addr); - /// Resolves the entry point for the current inferior process and sets a /// breakpoint at that address. void @@ -173,16 +168,8 @@ protected: lldb::addr_t GetEntryPoint(); - /// Checks to see if the target module has changed, updates the target - /// accordingly and returns the target executable module. - lldb::ModuleSP - GetTargetExecutable(); - private: DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD); - - const lldb_private::SectionList * - GetSectionListFromModule(const lldb::ModuleSP module) const; }; #endif // liblldb_DynamicLoaderPOSIXDYLD_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 274ba32..86cf450 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -134,7 +134,7 @@ DynamicLoaderStatic::LoadAllImagesAtFileAddresses () SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); if (section_sp) { - if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress())) + if (m_process->GetTarget().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress())) changed = true; } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index db03f45..f1cb41d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -289,37 +289,65 @@ EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, Reg uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber () const { - if (m_opcode_mode == eModeThumb) + bool is_apple = false; + if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) + is_apple = true; + switch (m_arch.GetTriple().getOS()) { - switch (m_arch.GetTriple().getOS()) - { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: - return 7; + is_apple = true; + break; default: break; - } } - return 11; + + /* On Apple iOS et al, the frame pointer register is always r7. + * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + */ + + uint32_t fp_regnum = 11; + + if (is_apple) + fp_regnum = 7; + + if (m_opcode_mode == eModeThumb) + fp_regnum = 7; + + return fp_regnum; } uint32_t EmulateInstructionARM::GetFramePointerDWARFRegisterNumber () const { - if (m_opcode_mode == eModeThumb) + bool is_apple = false; + if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple) + is_apple = true; + switch (m_arch.GetTriple().getOS()) { - switch (m_arch.GetTriple().getOS()) - { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: case llvm::Triple::IOS: - return dwarf_r7; + is_apple = true; + break; default: break; - } } - return dwarf_r11; + + /* On Apple iOS et al, the frame pointer register is always r7. + * Typically on other ARM systems, thumb code uses r7; arm code uses r11. + */ + + uint32_t fp_regnum = dwarf_r11; + + if (is_apple) + fp_regnum = dwarf_r7; + + if (m_opcode_mode == eModeThumb) + fp_regnum = dwarf_r7; + + return fp_regnum; } // Push Multiple Registers stores multiple registers to the stack, storing to @@ -12889,18 +12917,18 @@ EmulateInstructionARM::ReadInstruction () { if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0)) { - m_opcode.SetOpcode16 (thumb_opcode); + m_opcode.SetOpcode16 (thumb_opcode, GetByteOrder()); } else { - m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success)); + m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success), GetByteOrder()); } } } else { m_opcode_mode = eModeARM; - m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success)); + m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success), GetByteOrder()); } } } @@ -13510,15 +13538,15 @@ EmulateInstructionARM::TestEmulation (Stream *out_stream, ArchSpec &arch, Option if (arch.GetTriple().getArch() == llvm::Triple::arm) { m_opcode_mode = eModeARM; - m_opcode.SetOpcode32 (test_opcode); + m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); } else if (arch.GetTriple().getArch() == llvm::Triple::thumb) { m_opcode_mode = eModeThumb; if (test_opcode < 0x10000) - m_opcode.SetOpcode16 (test_opcode); + m_opcode.SetOpcode16 (test_opcode, GetByteOrder()); else - m_opcode.SetOpcode32 (test_opcode); + m_opcode.SetOpcode32 (test_opcode, GetByteOrder()); } else diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index f3c2d63..9781dcb 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -23,6 +23,7 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -402,7 +403,9 @@ ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp, FileSpecList filter_modules; BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); - return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, false); + const bool hardware = false; + const bool resolve_indirect_functions = false; + return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, hardware, resolve_indirect_functions); } void diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 7bdacfe..335090c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -24,6 +24,7 @@ #include "lldb/Core/Stream.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Host/Host.h" @@ -462,6 +463,47 @@ ObjectFileELF::IsExecutable() const return m_header.e_entry != 0; } +bool +ObjectFileELF::SetLoadAddress (Target &target, + lldb::addr_t value, + bool value_is_offset) +{ + ModuleSP module_sp = GetModule(); + if (module_sp) + { + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList (); + if (section_list) + { + if (value_is_offset) + { + const size_t num_sections = section_list->GetSize(); + size_t sect_idx = 0; + + for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) + { + // Iterate through the object file sections to find all + // of the sections that have SHF_ALLOC in their flag bits. + SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx)); + // if (section_sp && !section_sp->IsThreadSpecific()) + if (section_sp && section_sp->Test(SHF_ALLOC)) + { + if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value)) + ++num_loaded_sections; + } + } + return num_loaded_sections > 0; + } + else + { + // Not sure how to slide an ELF file given the base address + // of the ELF file in memory + } + } + } + return false; // If it changed +} + ByteOrder ObjectFileELF::GetByteOrder() const { diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index a2ab9b8..9b7c073 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -118,6 +118,11 @@ public: virtual bool ParseHeader(); + virtual bool + SetLoadAddress (lldb_private::Target &target, + lldb::addr_t value, + bool value_is_offset); + virtual lldb::ByteOrder GetByteOrder() const; diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 37b3241..7ca337e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -190,6 +190,13 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list, auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure threads_list stays alive PythonList threads_list(m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp)); + + const uint32_t num_cores = core_thread_list.GetSize(false); + + // Make a map so we can keep track of which cores were used from the + // core_thread list. Any real threads/cores that weren't used should + // later be put back into the "new_thread_list". + std::vector<bool> core_used_map(num_cores, false); if (threads_list) { if (log) @@ -207,18 +214,26 @@ OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list, PythonDictionary thread_dict(threads_list.GetItemAtIndex(i)); if (thread_dict) { - ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, NULL)); + ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, core_used_map, NULL)); if (thread_sp) new_thread_list.AddThread(thread_sp); } } } } - - // No new threads added from the thread info array gotten from python, just - // display the core threads. - if (new_thread_list.GetSize(false) == 0) - new_thread_list = core_thread_list; + + // Any real core threads that didn't end up backing a memory thread should + // still be in the main thread list, and they should be inserted at the beginning + // of the list + uint32_t insert_idx = 0; + for (uint32_t core_idx = 0; core_idx < num_cores; ++core_idx) + { + if (core_used_map[core_idx] == false) + { + new_thread_list.InsertThread (core_thread_list.GetThreadAtIndex(core_idx, false), insert_idx); + ++insert_idx; + } + } return new_thread_list.GetSize(false) > 0; } @@ -227,6 +242,7 @@ ThreadSP OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict, ThreadList &core_thread_list, ThreadList &old_thread_list, + std::vector<bool> &core_used_map, bool *did_create_ptr) { ThreadSP thread_sp; @@ -282,6 +298,10 @@ OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict ThreadSP core_thread_sp (core_thread_list.GetThreadAtIndex(core_number, false)); if (core_thread_sp) { + // Keep track of which cores were set as the backing thread for memory threads... + if (core_number < core_used_map.size()) + core_used_map[core_number] = true; + ThreadSP backing_core_thread_sp (core_thread_sp->GetBackingThread()); if (backing_core_thread_sp) { @@ -398,12 +418,13 @@ OperatingSystemPython::CreateThread (lldb::tid_t tid, addr_t context) auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure thread_info_dict stays alive PythonDictionary thread_info_dict (m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context)); + std::vector<bool> core_used_map; if (thread_info_dict) { ThreadList core_threads(m_process); ThreadList &thread_list = m_process->GetThreadList(); bool did_create = false; - ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, &did_create)); + ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, core_used_map, &did_create)); if (did_create) thread_list.AddThread(thread_sp); return thread_sp; diff --git a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h index 077039e..3b7dd26 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h +++ b/contrib/llvm/tools/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h @@ -93,6 +93,7 @@ protected: CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict, lldb_private::ThreadList &core_thread_list, lldb_private::ThreadList &old_thread_list, + std::vector<bool> &core_used_map, bool *did_create_ptr); DynamicRegisterInfo * diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index da29c16..7eca67a 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -142,7 +142,8 @@ PlatformFreeBSD::Terminate () /// Default Constructor //------------------------------------------------------------------ PlatformFreeBSD::PlatformFreeBSD (bool is_host) : -Platform(is_host) +Platform(is_host), +m_remote_platform_sp() { } @@ -312,6 +313,7 @@ PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_64_x86_64: + case ArchSpec::eCore_x86_64_x86_64h: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; @@ -571,14 +573,14 @@ PlatformFreeBSD::GetGroupName (uint32_t gid) // From PlatformMacOSX only Error -PlatformFreeBSD::GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) +PlatformFreeBSD::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { if (IsRemote()) { if (m_remote_platform_sp) - return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file); + return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); } // Default to the local case @@ -673,3 +675,9 @@ PlatformFreeBSD::GetStatus (Stream &strm) Platform::GetStatus(strm); } + +void +PlatformFreeBSD::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 11d1cd6..0682eac 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -144,8 +144,8 @@ public: // Only on PlatformMacOSX: virtual lldb_private::Error - GetFile (const lldb_private::FileSpec &platform_file, - const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file); + GetFileWithUUID (const lldb_private::FileSpec &platform_file, + const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file); lldb_private::Error GetSharedModule (const lldb_private::ModuleSpec &module_spec, @@ -160,6 +160,9 @@ public: virtual void GetStatus (lldb_private::Stream &strm); + virtual void + CalculateTrapHandlerSymbolNames (); + protected: lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b5f92dc..bb07d99 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -589,3 +589,8 @@ PlatformPOSIX::SetRemoteWorkingDirectory(const lldb_private::ConstString &path) return Platform::SetRemoteWorkingDirectory(path); } +void +PlatformPOSIX::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 336e0f9..130c84b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -111,8 +111,11 @@ public: uint64_t &low, uint64_t &high); + virtual void + CalculateTrapHandlerSymbolNames (); + protected: - std::auto_ptr<lldb_private::OptionGroupOptions> m_options; + std::unique_ptr<lldb_private::OptionGroupOptions> m_options; lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 248abaf..3832265 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -119,9 +119,9 @@ PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file, } Error -PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) +PlatformRemoteGDBServer::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { // Default to the local case local_file = platform_file; @@ -265,9 +265,6 @@ PlatformRemoteGDBServer::ConnectRemote (Args& args) // If a working directory was set prior to connecting, send it down now if (m_working_dir) m_gdb_client.SetWorkingDir(m_working_dir.GetCString()); -#if 0 - m_gdb_client.TestPacketSpeed(10000); -#endif } else { @@ -418,7 +415,21 @@ PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_i if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + ArchSpec remote_arch = GetRemoteSystemArchitecture(); + llvm::Triple &remote_triple = remote_arch.GetTriple(); + uint16_t port = 0; + if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) + { + // When remote debugging to iOS, we use a USB mux that always talks + // to localhost, so we will need the remote debugserver to accept connections + // only from localhost, no matter what our current hostname is + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + } + else + { + // All other hosts should use their actual hostname + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); + } if (port == 0) { @@ -492,7 +503,21 @@ PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info, if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid); + ArchSpec remote_arch = GetRemoteSystemArchitecture(); + llvm::Triple &remote_triple = remote_arch.GetTriple(); + uint16_t port = 0; + if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) + { + // When remote debugging to iOS, we use a USB mux that always talks + // to localhost, so we will need the remote debugserver to accept connections + // only from localhost, no matter what our current hostname is + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "localhost"); + } + else + { + // All other hosts should use their actual hostname + port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); + } if (port == 0) { @@ -673,3 +698,9 @@ PlatformRemoteGDBServer::RunShellCommand (const char *command, // Shou { return m_gdb_client.RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); } + +void +PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 808fb5e..e236e97 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -73,9 +73,9 @@ public: GetDescription (); virtual lldb_private::Error - GetFile (const lldb_private::FileSpec &platform_file, - const lldb_private::UUID *uuid_ptr, - lldb_private::FileSpec &local_file); + GetFileWithUUID (const lldb_private::FileSpec &platform_file, + const lldb_private::UUID *uuid_ptr, + lldb_private::FileSpec &local_file); virtual bool GetProcessInfo (lldb::pid_t pid, @@ -209,6 +209,9 @@ public: std::string *command_output, // Pass NULL if you don't want the command output uint32_t timeout_sec); // Timeout in seconds to wait for shell program to finish + virtual void + CalculateTrapHandlerSymbolNames (); + protected: GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp index 083f08e..d13b9a4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp @@ -132,6 +132,8 @@ ProcessFreeBSD::DoDetach(bool keep_stopped) return error; } + DisableAllBreakpointSites(); + error = m_monitor->Detach(GetID()); if (error.Success()) diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h index ccae5cb..d6ae346 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h @@ -101,4 +101,4 @@ protected: }; -#endif // liblldb_MacOSXProcess_H_ +#endif // liblldb_ProcessFreeBSD_H_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index d517996..3d793d0 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -101,8 +101,8 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, log->Printf("ptrace() failed; errno=%d (%s)", errno, str); } -#ifdef __amd64__ if (log) { +#ifdef __amd64__ if (req == PT_GETREGS) { struct reg *r = (struct reg *) addr; @@ -111,8 +111,15 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data, log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp); log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax); } - } #endif + if (req == PT_GETDBREGS || req == PT_SETDBREGS) { + struct dbreg *r = (struct dbreg *) addr; + char setget = (req == PT_GETDBREGS) ? 'G' : 'S'; + + for (int i = 0; i <= 7; i++) + log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]); + } + } return result; } @@ -348,6 +355,82 @@ WriteRegOperation::Execute(ProcessMonitor *monitor) } //------------------------------------------------------------------------------ +/// @class ReadDebugRegOperation +/// @brief Implements ProcessMonitor::ReadDebugRegisterValue. +class ReadDebugRegOperation : public Operation +{ +public: + ReadDebugRegOperation(lldb::tid_t tid, unsigned offset, unsigned size, + RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), m_size(size), + m_value(value), m_result(result) + { } + + void Execute(ProcessMonitor *monitor); + +private: + lldb::tid_t m_tid; + unsigned m_offset; + unsigned m_size; + RegisterValue &m_value; + bool &m_result; +}; + +void +ReadDebugRegOperation::Execute(ProcessMonitor *monitor) +{ + struct dbreg regs; + int rc; + + if ((rc = PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0)) < 0) { + m_result = false; + } else { + if (m_size == sizeof(uintptr_t)) + m_value = *(uintptr_t *)(((caddr_t)®s) + m_offset); + else + memcpy(&m_value, (((caddr_t)®s) + m_offset), m_size); + m_result = true; + } +} + +//------------------------------------------------------------------------------ +/// @class WriteDebugRegOperation +/// @brief Implements ProcessMonitor::WriteDebugRegisterValue. +class WriteDebugRegOperation : public Operation +{ +public: + WriteDebugRegOperation(lldb::tid_t tid, unsigned offset, + const RegisterValue &value, bool &result) + : m_tid(tid), m_offset(offset), + m_value(value), m_result(result) + { } + + void Execute(ProcessMonitor *monitor); + +private: + lldb::tid_t m_tid; + unsigned m_offset; + const RegisterValue &m_value; + bool &m_result; +}; + +void +WriteDebugRegOperation::Execute(ProcessMonitor *monitor) +{ + struct dbreg regs; + + if (PTRACE(PT_GETDBREGS, m_tid, (caddr_t)®s, 0) < 0) { + m_result = false; + return; + } + *(uintptr_t *)(((caddr_t)®s) + m_offset) = (uintptr_t)m_value.GetAsUInt64(); + if (PTRACE(PT_SETDBREGS, m_tid, (caddr_t)®s, 0) < 0) + m_result = false; + else + m_result = true; +} + +//------------------------------------------------------------------------------ /// @class ReadGPROperation /// @brief Implements ProcessMonitor::ReadGPR. class ReadGPROperation : public Operation @@ -896,7 +979,8 @@ ProcessMonitor::Launch(LaunchArgs *args) eDupStdoutFailed, eDupStderrFailed, eChdirFailed, - eExecFailed + eExecFailed, + eSetGidFailed }; // Child process. @@ -907,7 +991,8 @@ ProcessMonitor::Launch(LaunchArgs *args) exit(ePtraceFailed); // Do not inherit setgid powers. - setgid(getgid()); + if (setgid(getgid()) != 0) + exit(eSetGidFailed); // Let us have our own process group. setpgid(0, 0); @@ -972,6 +1057,9 @@ ProcessMonitor::Launch(LaunchArgs *args) case eExecFailed: args->m_error.SetErrorString("Child exec failed."); break; + case eSetGidFailed: + args->m_error.SetErrorString("Child setgid failed."); + break; default: args->m_error.SetErrorString("Child returned unknown exit status."); break; @@ -1170,7 +1258,7 @@ ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor, case 0: case TRAP_TRACE: if (log) - log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64, __FUNCTION__, tid); + log->Printf ("ProcessMonitor::%s() received trace event, tid = %" PRIu64 " : si_code = %d", __FUNCTION__, tid, info->si_code); message = ProcessMessage::Trace(tid); break; @@ -1459,6 +1547,28 @@ ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset, } bool +ProcessMonitor::ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, unsigned size, + lldb_private::RegisterValue &value) +{ + bool result; + ReadDebugRegOperation op(tid, offset, size, value, result); + DoOperation(&op); + return result; +} + +bool +ProcessMonitor::WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, + const lldb_private::RegisterValue &value) +{ + bool result; + WriteDebugRegOperation op(tid, offset, value, result); + DoOperation(&op); + return result; +} + +bool ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size) { bool result; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h index 36b2fe0..4c8198f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -104,8 +104,6 @@ public: /// dependent) offset. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, unsigned size, lldb_private::RegisterValue &value); @@ -114,49 +112,52 @@ public: /// (architecture dependent) offset. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name, const lldb_private::RegisterValue &value); + /// Reads the contents from the debug register identified by the given + /// (architecture dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool + ReadDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, unsigned size, + lldb_private::RegisterValue &value); + + /// Writes the given value to the debug register identified by the given + /// (architecture dependent) offset. + /// + /// This method is provided for use by RegisterContextFreeBSD derivatives. + bool + WriteDebugRegisterValue(lldb::tid_t tid, unsigned offset, + const char *reg_name, + const lldb_private::RegisterValue &value); /// Reads all general purpose registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Reads all floating point registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Reads the specified register set into the specified buffer. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); /// Writes all general purpose registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Writes all floating point registers into the specified buffer. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size); /// Writes the specified register set into the specified buffer. /// /// This method is provided for use by RegisterContextFreeBSD derivatives. - /// FIXME: The FreeBSD implementation of this function should use tid in order - /// to enable support for debugging threaded programs. bool WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp index e1dda42..cc759ea 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.cpp @@ -65,7 +65,16 @@ POSIXThread::POSIXThread(Process &process, lldb::tid_t tid) lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx); if (wp.get() && wp->IsEnabled()) { - assert(EnableHardwareWatchpoint(wp.get())); + // This watchpoint as been enabled; obviously this "new" thread + // has been created since that watchpoint was enabled. Since + // the POSIXBreakpointProtocol has yet to be initialized, its + // m_watchpoints_initialized member will be FALSE. Attempting to + // read the debug status register to determine if a watchpoint + // has been hit would result in the zeroing of that register. + // Since the active debug registers would have been cloned when + // this thread was created, simply force the m_watchpoints_initized + // member to TRUE and avoid resetting dr6 and dr7. + GetPOSIXBreakpointProtocol()->ForceWatchpointsInitialized(); } } } @@ -151,8 +160,6 @@ POSIXThread::GetRegisterContext() { case ArchSpec::eCore_mips64: { - RegisterInfoInterface *reg_interface = NULL; - switch (target_arch.GetTriple().getOS()) { case llvm::Triple::FreeBSD: @@ -276,6 +283,43 @@ POSIXThread::DidStop() // Don't set the thread state to stopped unless we really stopped. } +bool +POSIXThread::Resume() +{ + lldb::StateType resume_state = GetResumeState(); + ProcessMonitor &monitor = GetMonitor(); + bool status; + + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD)); + if (log) + log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__, + StateAsCString(resume_state)); + + switch (resume_state) + { + default: + assert(false && "Unexpected state for resume!"); + status = false; + break; + + case lldb::eStateRunning: + SetState(resume_state); + status = monitor.Resume(GetID(), GetResumeSignal()); + break; + + case lldb::eStateStepping: + SetState(resume_state); + status = monitor.SingleStep(GetID(), GetResumeSignal()); + break; + case lldb::eStateStopped: + case lldb::eStateSuspended: + status = true; + break; + } + + return status; +} + void POSIXThread::Notify(const ProcessMessage &message) { @@ -474,6 +518,21 @@ POSIXThread::WatchNotify(const ProcessMessage &message) void POSIXThread::TraceNotify(const ProcessMessage &message) { + POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); + if (reg_ctx) + { + uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints(); + uint32_t wp_idx; + for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++) + { + if (reg_ctx->IsWatchpointHit(wp_idx)) + { + WatchNotify(message); + return; + } + } + } + SetStopInfo (StopInfo::CreateStopReasonToTrace(*this)); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.h index a59a3a7..51d6645 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/POSIXThread.h @@ -79,6 +79,8 @@ public: //-------------------------------------------------------------------------- // These methods form a specialized interface to POSIX threads. // + bool Resume(); + void Notify(const ProcessMessage &message); //-------------------------------------------------------------------------- diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 8cfd9d6..6239462 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -200,7 +200,7 @@ ProcessPOSIX::GetFilePath( Error ProcessPOSIX::DoLaunch (Module *module, - const ProcessLaunchInfo &launch_info) + ProcessLaunchInfo &launch_info) { Error error; assert(m_monitor == NULL); @@ -259,6 +259,31 @@ ProcessPOSIX::DidLaunch() { } +Error +ProcessPOSIX::DoResume() +{ + StateType state = GetPrivateState(); + + assert(state == eStateStopped); + + SetPrivateState(eStateRunning); + + bool did_resume = false; + + Mutex::Locker lock(m_thread_list.GetMutex()); + + uint32_t thread_count = m_thread_list.GetSize(false); + for (uint32_t i = 0; i < thread_count; ++i) + { + POSIXThread *thread = static_cast<POSIXThread*>( + m_thread_list.GetThreadAtIndex(i, false).get()); + did_resume = thread->Resume() || did_resume; + } + assert(did_resume && "Process resume failed!"); + + return Error(); +} + addr_t ProcessPOSIX::GetImageInfoAddress() { @@ -351,6 +376,107 @@ ProcessPOSIX::DoDidExec() } } +void +ProcessPOSIX::SendMessage(const ProcessMessage &message) +{ + Mutex::Locker lock(m_message_mutex); + + Mutex::Locker thread_lock(m_thread_list.GetMutex()); + + POSIXThread *thread = static_cast<POSIXThread*>( + m_thread_list.FindThreadByID(message.GetTID(), false).get()); + + switch (message.GetKind()) + { + case ProcessMessage::eInvalidMessage: + return; + + case ProcessMessage::eAttachMessage: + SetPrivateState(eStateStopped); + return; + + case ProcessMessage::eLimboMessage: + assert(thread); + thread->SetState(eStateStopped); + if (message.GetTID() == GetID()) + { + m_exit_status = message.GetExitStatus(); + if (m_exit_now) + { + SetPrivateState(eStateExited); + m_monitor->Detach(GetID()); + } + else + { + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + } + } + else + { + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + } + break; + + case ProcessMessage::eExitMessage: + assert(thread); + thread->SetState(eStateExited); + // FIXME: I'm not sure we need to do this. + if (message.GetTID() == GetID()) + { + m_exit_status = message.GetExitStatus(); + SetExitStatus(m_exit_status, NULL); + } + else if (!IsAThreadRunning()) + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eSignalMessage: + case ProcessMessage::eSignalDeliveredMessage: + if (message.GetSignal() == SIGSTOP && + AddThreadForInitialStopIfNeeded(message.GetTID())) + return; + // Intentional fall-through + + case ProcessMessage::eBreakpointMessage: + case ProcessMessage::eTraceMessage: + case ProcessMessage::eWatchpointMessage: + case ProcessMessage::eCrashMessage: + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + + case ProcessMessage::eNewThreadMessage: + { + lldb::tid_t new_tid = message.GetChildTID(); + if (WaitingForInitialStop(new_tid)) + { + m_monitor->WaitForInitialTIDStop(new_tid); + } + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } + + case ProcessMessage::eExecMessage: + { + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } + } + + + m_message_queue.push(message); +} + void ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid) { @@ -506,20 +632,6 @@ ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr) return error; } -addr_t -ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error) -{ - addr_t function_addr = LLDB_INVALID_ADDRESS; - if (address == NULL) { - error.SetErrorStringWithFormat("unable to determine direct function call for NULL address"); - } else if (!InferiorCall(this, address, function_addr)) { - function_addr = LLDB_INVALID_ADDRESS; - error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s", - address->CalculateSymbolContextSymbol()->GetName().AsCString()); - } - return function_addr; -} - size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h index 8b30498..7f705d3 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -58,13 +58,13 @@ public: virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - const lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info); virtual void DidLaunch(); virtual lldb_private::Error - DoResume() = 0; + DoResume(); virtual lldb_private::Error DoHalt(bool &caused_stop); @@ -104,9 +104,6 @@ public: virtual lldb_private::Error DoDeallocateMemory(lldb::addr_t ptr); - virtual lldb::addr_t - ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error); - virtual size_t GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site); @@ -149,7 +146,7 @@ public: /// Registers the given message with this process. virtual void - SendMessage(const ProcessMessage &message) = 0; + SendMessage(const ProcessMessage &message); ProcessMonitor & GetMonitor() { assert(m_monitor); return *m_monitor; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp index 50ec8d4..01c9bb4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_i386.cpp @@ -37,8 +37,18 @@ struct GPR uint32_t gs; }; -#define DR_SIZE 0 -#define DR_OFFSET(reg_index) 0 +struct dbreg { + uint32_t dr[8]; /* debug registers */ + /* Index 0-3: debug address registers */ + /* Index 4-5: reserved */ + /* Index 6: debug status */ + /* Index 7: debug control */ +}; + + +#define DR_SIZE sizeof(uint32_t) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(dbreg, dr[reg_index])) //--------------------------------------------------------------------------- // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp index 4717345..2162aaf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp @@ -46,8 +46,19 @@ typedef struct _GPR uint64_t ss; } GPR; -#define DR_SIZE 0 -#define DR_OFFSET(reg_index) 0 +struct dbreg { + uint64_t dr[16]; /* debug registers */ + /* Index 0-3: debug address registers */ + /* Index 4-5: reserved */ + /* Index 6: debug status */ + /* Index 7: debug control */ + /* Index 8-15: reserved */ +}; + +#define DR_SIZE sizeof(uint64_t) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(dbreg, dr[reg_index])) + //--------------------------------------------------------------------------- // Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 structure. diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h index e48c528..600dae7 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIX.h @@ -66,6 +66,10 @@ public: virtual uint32_t NumSupportedHardwareWatchpoints () = 0; + // Force m_watchpoints_initialized to TRUE + void + ForceWatchpointsInitialized () {m_watchpoints_initialized = true;} + protected: bool m_watchpoints_initialized; }; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp index f833c9b..c446bbf 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/POSIX/RegisterContextPOSIXProcessMonitor_x86.cpp @@ -109,6 +109,15 @@ RegisterContextPOSIXProcessMonitor_x86_64::ReadRegister(const unsigned reg, RegisterValue &value) { ProcessMonitor &monitor = GetMonitor(); + +#if defined(__FreeBSD__) + if (reg >= m_reg_info.first_dr) + return monitor.ReadDebugRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg), + GetRegisterName(reg), + GetRegisterSize(reg), + value); +#endif return monitor.ReadRegisterValue(m_thread.GetID(), GetRegisterOffset(reg), GetRegisterName(reg), @@ -164,6 +173,13 @@ RegisterContextPOSIXProcessMonitor_x86_64::WriteRegister(const unsigned reg, } ProcessMonitor &monitor = GetMonitor(); +#if defined(__FreeBSD__) + if (reg >= m_reg_info.first_dr) + return monitor.WriteDebugRegisterValue(m_thread.GetID(), + GetRegisterOffset(reg_to_write), + GetRegisterName(reg_to_write), + value_to_write); +#endif return monitor.WriteRegisterValue(m_thread.GetID(), GetRegisterOffset(reg_to_write), GetRegisterName(reg_to_write), diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp index 5211362..d045bc7 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.cpp @@ -25,7 +25,7 @@ HistoryThread::HistoryThread (lldb_private::Process &process, std::vector<lldb::addr_t> pcs, uint32_t stop_id, bool stop_id_is_valid) : - Thread (process, LLDB_INVALID_THREAD_ID), + Thread (process, tid), m_framelist_mutex(), m_framelist(), m_pcs (pcs), diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h index 01fdd16..f9a431d 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/HistoryThread.h @@ -22,6 +22,16 @@ namespace lldb_private { +//---------------------------------------------------------------------- +/// @class HistoryThread HistoryThread.h "HistoryThread.h" +/// @brief A thread object representing a backtrace from a previous point in the process execution +/// +/// This subclass of Thread is used to provide a backtrace from earlier in +/// process execution. It is given a backtrace list of pc addresses and +/// optionally a stop_id of when those pc addresses were collected, and it will +/// create stack frames for them. +//---------------------------------------------------------------------- + class HistoryThread : public lldb_private::Thread { public: diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 6d1b04f..1d5d19f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -34,9 +34,16 @@ using namespace lldb; using namespace lldb_private; -bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, - addr_t addr, addr_t length, unsigned prot, - unsigned flags, addr_t fd, addr_t offset) { +bool +lldb_private::InferiorCallMmap (Process *process, + addr_t &allocated_addr, + addr_t addr, + addr_t length, + unsigned prot, + unsigned flags, + addr_t fd, + addr_t offset) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -139,8 +146,11 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, return false; } -bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, - addr_t length) { +bool +lldb_private::InferiorCallMunmap (Process *process, + addr_t addr, + addr_t length) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL) return false; @@ -209,7 +219,14 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, return false; } -bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) { +// FIXME: This has nothing to do with Posix, it is just a convenience function that calls a +// function of the form "void * (*)(void)". We should find a better place to put this. + +bool +lldb_private::InferiorCall (Process *process, + const Address *address, + addr_t &returned_func) +{ Thread *thread = process->GetThreadList().GetSelectedThread().get(); if (thread == NULL || address == NULL) return false; @@ -233,7 +250,7 @@ bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan); if (call_plan_sp) { - StreamFile error_strm; + StreamString error_strm; // This plan is a utility plan, so set it to discard itself when done. call_plan_sp->SetIsMasterPlan (true); call_plan_sp->SetOkayToDiscard(true); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp index c19aec3..f209d53 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -21,15 +21,17 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" -#include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "lldb/Target/DynamicLoader.h" #include "RegisterContextLLDB.h" @@ -48,6 +50,7 @@ RegisterContextLLDB::RegisterContextLLDB m_thread(thread), m_fast_unwind_plan_sp (), m_full_unwind_plan_sp (), + m_fallback_unwind_plan_sp (), m_all_registers_available(false), m_frame_type (-1), m_cfa (LLDB_INVALID_ADDRESS), @@ -75,13 +78,44 @@ RegisterContextLLDB::RegisterContextLLDB // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet if (IsFrameZero() - || next_frame->m_frame_type == eSigtrampFrame + || next_frame->m_frame_type == eTrapHandlerFrame || next_frame->m_frame_type == eDebuggerFrame) { m_all_registers_available = true; } } +bool +RegisterContextLLDB::IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset) +{ + if (!unwind_plan_sp) + return false; + + // check if m_current_pc is valid + if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) + { + // yes - current offset can be used as is + valid_pc_offset = m_current_offset; + return true; + } + + // if m_current_offset <= 0, we've got nothing else to try + if (m_current_offset <= 0) + return false; + + // check pc - 1 to see if it's valid + Address pc_minus_one (m_current_pc); + pc_minus_one.SetOffset(m_current_pc.GetOffset() - 1); + if (unwind_plan_sp->PlanValidAtAddress(pc_minus_one)) + { + // *valid_pc_offset = m_current_offset - 1; + valid_pc_offset = m_current_pc.GetOffset() - 1; + return true; + } + + return false; +} + // Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently // executing frame. @@ -95,6 +129,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (reg_ctx_sp.get() == NULL) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a register context"); return; } @@ -103,6 +138,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (current_pc == LLDB_INVALID_ADDRESS) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("frame does not have a pc"); return; } @@ -117,7 +153,7 @@ RegisterContextLLDB::InitializeZerothFrame() current_pc = abi->FixCodeAddress(current_pc); // Initialize m_current_pc, an Address object, based on current_pc, an addr_t. - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc); + m_current_pc.SetLoadAddress (current_pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -137,11 +173,9 @@ RegisterContextLLDB::InitializeZerothFrame() AddressRange addr_range; m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range); - static ConstString g_sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) || - (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -197,6 +231,7 @@ RegisterContextLLDB::InitializeZerothFrame() if (!active_row.get()) { + UnwindLogMsg ("could not find an unwindplan row for this frame's pc"); m_frame_type = eNotAValidFrame; return; } @@ -205,6 +240,7 @@ RegisterContextLLDB::InitializeZerothFrame() addr_t cfa_regval = LLDB_INVALID_ADDRESS; if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval)) { + UnwindLogMsg ("could not read CFA register for this frame."); m_frame_type = eNotAValidFrame; return; } @@ -229,17 +265,20 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (IsFrameZero ()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("non-zeroth frame tests positive for IsFrameZero -- that shouldn't happen."); return; } if (!GetNextFrame().get() || !GetNextFrame()->IsValid()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get next frame, marking this frame as invalid."); return; } if (!m_thread.GetRegisterContext()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("Could not get register context for this thread, marking this frame as invalid."); return; } @@ -265,6 +304,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (pc == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("this frame has a pc of 0x0"); return; } @@ -276,7 +316,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (abi) pc = abi->FixCodeAddress(pc); - process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc); + m_current_pc.SetLoadAddress (pc, &process->GetTarget()); // If we don't have a Module for some reason, we're not going to find symbol/function information - just // stick in some reasonable defaults and hope we can unwind past this frame. @@ -304,6 +344,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() { // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now. m_frame_type = eNotAValidFrame; + UnwindLogMsg ("pc is in a non-executable section of memory and this isn't the 2nd frame in the stack walk."); return; } } @@ -352,6 +393,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() && (permissions & ePermissionsReadable) == 0) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("the CFA points to a region of memory that is not readable"); return; } } @@ -366,10 +408,15 @@ RegisterContextLLDB::InitializeNonZerothFrame() return; } m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find any symbol for this pc, or a default unwind plan, to continue unwind."); return; } bool resolve_tail_call_address = true; // m_current_pc can be one past the address range of the function... + // This will handle the case where the saved pc does not point to + // a function/symbol because it is beyond the bounds of the correct + // function and there's no symbol there. ResolveSymbolContextForAddress + // will fail to find a symbol, back up the pc by 1 and re-search. uint32_t resolved_scope = pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction | eSymbolContextSymbol, m_sym_ctx, resolve_tail_call_address); @@ -392,18 +439,35 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (m_sym_ctx_valid == false) decr_pc_and_recompute_addr_range = true; - // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), and - // our "current" pc is the start of a function or our "current" pc is one past the end of a function... + // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp), + // and our "current" pc is the start of a function... if (m_sym_ctx_valid - && GetNextFrame()->m_frame_type != eSigtrampFrame + && GetNextFrame()->m_frame_type != eTrapHandlerFrame && GetNextFrame()->m_frame_type != eDebuggerFrame && addr_range.GetBaseAddress().IsValid() - && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()) + && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection() + && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset()) { - if (addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset() || - addr_range.GetBaseAddress().GetOffset() + addr_range.GetByteSize() == m_current_pc.GetOffset()) + decr_pc_and_recompute_addr_range = true; + } + + // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc" + // value is pointing to the next function, e.g. if a function ends with a CALL instruction. + // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function + // to the ABI plugin and consult that. + if (decr_pc_and_recompute_addr_range) + { + Address temporary_pc(m_current_pc); + temporary_pc.SetOffset(m_current_pc.GetOffset() - 1); + m_sym_ctx.Clear(false); + m_sym_ctx_valid = false; + if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol) + { + m_sym_ctx_valid = true; + } + if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range)) { - decr_pc_and_recompute_addr_range = true; + m_sym_ctx_valid = false; } } @@ -428,11 +492,9 @@ RegisterContextLLDB::InitializeNonZerothFrame() m_current_offset_backed_up_one = -1; } - static ConstString sigtramp_name ("_sigtramp"); - if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name) - || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name)) + if (IsTrapHandlerSymbol (process, m_sym_ctx)) { - m_frame_type = eSigtrampFrame; + m_frame_type = eTrapHandlerFrame; } else { @@ -467,9 +529,10 @@ RegisterContextLLDB::InitializeNonZerothFrame() else { m_full_unwind_plan_sp = GetFullUnwindPlanForFrame (); - if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(m_full_unwind_plan_sp, valid_offset)) { - active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (valid_offset); row_register_kind = m_full_unwind_plan_sp->GetRegisterKind (); if (active_row.get() && log) { @@ -483,6 +546,7 @@ RegisterContextLLDB::InitializeNonZerothFrame() if (!active_row.get()) { m_frame_type = eNotAValidFrame; + UnwindLogMsg ("could not find unwind row for this pc"); return; } @@ -551,7 +615,7 @@ RegisterContextLLDB::IsFrameZero () const // // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -573,7 +637,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () return unwind_plan_sp; // If we're in _sigtramp(), unwinding past this frame requires special knowledge. - if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame) + if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame) return unwind_plan_sp; unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread); @@ -602,7 +666,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame () // On entry to this method, // -// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct, +// 1. m_frame_type should already be set to eTrapHandlerFrame/eDebuggerFrame if either of those are correct, // 2. m_sym_ctx should already be filled in, and // 3. m_current_pc should have the current pc value for this frame // 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown @@ -627,7 +691,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () bool behaves_like_zeroth_frame = false; if (IsFrameZero () - || GetNextFrame()->m_frame_type == eSigtrampFrame + || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { behaves_like_zeroth_frame = true; @@ -648,7 +712,7 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()); if (current_pc_addr == 0 - || (process->GetLoadAddressPermissions(current_pc_addr, permissions) + || (process->GetLoadAddressPermissions (current_pc_addr, permissions) && (permissions & ePermissionsExecutable) == 0)) { unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); @@ -697,12 +761,14 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // is properly encoded in the eh_frame section, so prefer that if available. // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of // how to unwind out of sigtramp. - if (m_frame_type == eSigtrampFrame) + if (m_frame_type == eTrapHandlerFrame) { m_fast_unwind_plan_sp.reset(); unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc) && unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolYes) + { return unwind_plan_sp; + } } // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero @@ -728,6 +794,15 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) { + if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + { + // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably + // don't have any eh_frame instructions available. + // The assembly profilers work really well with compiler-generated functions but hand-written + // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback + // UnwindPlan in case this doesn't work out when we try to unwind. + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; } @@ -735,7 +810,8 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + int valid_offset = -1; + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -744,7 +820,17 @@ RegisterContextLLDB::GetFullUnwindPlanForFrame () // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible. unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread); - if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc)) + if (unwind_plan_sp->GetSourcedFromCompiler() == eLazyBoolNo) + { + // We probably have an UnwindPlan created by inspecting assembly instructions, and we probably + // don't have any eh_frame instructions available. + // The assembly profilers work really well with compiler-generated functions but hand-written + // assembly can be problematic. We'll set the architecture default UnwindPlan as our fallback + // UnwindPlan in case this doesn't work out when we try to unwind. + m_fallback_unwind_plan_sp = arch_default_unwind_plan_sp; + } + + if (IsUnwindPlanValidForCurrentPC(unwind_plan_sp, valid_offset)) { UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString()); return unwind_plan_sp; @@ -915,6 +1001,12 @@ RegisterContextLLDB::IsValid () const return m_frame_type != eNotAValidFrame; } +bool +RegisterContextLLDB::IsTrapHandlerFrame () const +{ + return m_frame_type == eTrapHandlerFrame; +} + // A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther // up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after // frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the @@ -927,6 +1019,35 @@ RegisterContextLLDB::IsSkipFrame () const return m_frame_type == eSkipFrame; } +bool +RegisterContextLLDB::IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const +{ + PlatformSP platform_sp (process->GetTarget().GetPlatform()); + if (platform_sp) + { + const std::vector<ConstString> trap_handler_names (platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString name : trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + } + const std::vector<ConstString> user_specified_trap_handler_names (m_parent_unwind.GetUserSpecifiedTrapHandlerFunctionNames()); + for (ConstString name : user_specified_trap_handler_names) + { + if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == name) || + (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == name)) + { + return true; + } + } + + return false; +} + // Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value? enum UnwindLLDB::RegisterSearchResult @@ -1077,21 +1198,22 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat m_full_unwind_plan_sp->GetSourceName().GetCString()); // Throw away the full unwindplan; install the arch default unwindplan - InvalidateFullUnwindPlan(); - - // Now re-fetch the pc value we're searching for - uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; - UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) - && arch_default_pc_reg != LLDB_INVALID_REGNUM - && active_row - && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + if (TryFallbackUnwindPlan()) { - have_unwindplan_regloc = true; - } - else - { - have_unwindplan_regloc = false; + // Now re-fetch the pc value we're searching for + uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM; + UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg) + && arch_default_pc_reg != LLDB_INVALID_REGNUM + && active_row + && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc)) + { + have_unwindplan_regloc = true; + } + else + { + have_unwindplan_regloc = false; + } } } } @@ -1161,7 +1283,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1171,7 +1293,7 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation; regloc.location.target_memory_location = m_cfa + offset; m_registers[lldb_regnum] = regloc; - UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum); + UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset %d", lldb_regnum, offset); return UnwindLLDB::RegisterSearchResult::eRegisterFound; } @@ -1234,54 +1356,48 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat } // If the Full unwindplan has been determined to be incorrect, this method will -// replace it with the architecture's default unwindplna, if one is defined. +// replace it with the architecture's default unwindplan, if one is defined. // It will also find the FuncUnwinders object for this function and replace the // Full unwind method for the function there so we don't use the errant Full unwindplan // again in the future of this debug session. // We're most likely doing this because the Full unwindplan was generated by assembly // instruction profiling and the profiler got something wrong. -void -RegisterContextLLDB::InvalidateFullUnwindPlan () +bool +RegisterContextLLDB::TryFallbackUnwindPlan () { UnwindPlan::Row::RegisterLocation unwindplan_regloc; - ExecutionContext exe_ctx (m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - ABI *abi = process ? process->GetABI().get() : NULL; - if (abi) + if (m_fallback_unwind_plan_sp.get() == NULL) + return false; + + UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; + UnwindPlan::RowSP active_row = m_fallback_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); + + if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) { - UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp; - UnwindPlanSP arch_default_unwind_plan_sp; - arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); - abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp); - if (arch_default_unwind_plan_sp) + FuncUnwindersSP func_unwinders_sp; + if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) { - UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset); - - if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM) + func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); + if (func_unwinders_sp) { - FuncUnwindersSP func_unwinders_sp; - if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule()) - { - func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); - if (func_unwinders_sp) - { - func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); - } - } - m_registers.clear(); - m_full_unwind_plan_sp = arch_default_unwind_plan_sp; - addr_t cfa_regval = LLDB_INVALID_ADDRESS; - if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) - { - m_cfa = cfa_regval + active_row->GetCFAOffset (); - } - - UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", - original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString()); + func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread); } } + m_registers.clear(); + m_full_unwind_plan_sp = m_fallback_unwind_plan_sp; + addr_t cfa_regval = LLDB_INVALID_ADDRESS; + if (ReadGPRValue (m_fallback_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval)) + { + m_cfa = cfa_regval + active_row->GetCFAOffset (); + } + + UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.", + original_full_unwind_plan_sp->GetSourceName().GetCString(), m_fallback_unwind_plan_sp->GetSourceName().GetCString()); + m_fallback_unwind_plan_sp.reset(); } + + return true; } // Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that @@ -1550,3 +1666,4 @@ RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...) } } + diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h index dc6d8c6..0a60bfe 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/RegisterContextLLDB.h @@ -73,6 +73,9 @@ public: IsValid () const; bool + IsTrapHandlerFrame () const; + + bool GetCFA (lldb::addr_t& cfa); bool @@ -86,7 +89,7 @@ private: enum FrameType { eNormalFrame, - eSigtrampFrame, + eTrapHandlerFrame, eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack @@ -120,6 +123,19 @@ private: bool IsSkipFrame () const; + + //------------------------------------------------------------------ + /// Determines if a SymbolContext is a trap handler or not + /// + /// Given a SymbolContext, determines if this is a trap handler function + /// aka asynchronous signal handler. + /// + /// @return + /// Returns true if the SymbolContext is a trap handler. + //------------------------------------------------------------------ + bool + IsTrapHandlerSymbol (lldb_private::Process *process, const lldb_private::SymbolContext &m_sym_ctx) const; + // Provide a location for where THIS function saved the CALLER's register value // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this // function didn't modify/use. @@ -144,8 +160,20 @@ private: const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); - void - InvalidateFullUnwindPlan (); + //------------------------------------------------------------------ + /// If the unwind has to the caller frame has failed, try something else + /// + /// If lldb is using an assembly language based UnwindPlan for a frame and + /// the unwind to the caller frame fails, try falling back to a generic + /// UnwindPlan (architecture default unwindplan) to see if that might work + /// better. This is mostly helping to work around problems where the + /// assembly language inspection fails on hand-written assembly code. + /// + /// @return + /// Returns true if a fallback unwindplan was found & was installed. + //------------------------------------------------------------------ + bool + TryFallbackUnwindPlan (); // Get the contents of a general purpose (address-size) register for this frame // (usually retrieved from the next frame) @@ -164,6 +192,10 @@ private: void UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); + bool + IsUnwindPlanValidForCurrentPC(lldb::UnwindPlanSP unwind_plan_sp, int &valid_pc_offset); + + lldb_private::Thread& m_thread; /// @@ -171,8 +203,10 @@ private: // i.e. where THIS frame saved them /// - lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL + lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL lldb::UnwindPlanSP m_full_unwind_plan_sp; + lldb::UnwindPlanSP m_fallback_unwind_plan_sp; // may be NULL + bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs? int m_frame_type; // enum FrameType diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp index 552ae50..5db08e5 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.cpp @@ -26,8 +26,21 @@ using namespace lldb_private; UnwindLLDB::UnwindLLDB (Thread &thread) : Unwind (thread), m_frames(), - m_unwind_complete(false) + m_unwind_complete(false), + m_user_supplied_trap_handler_functions() { + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) + { + Args args; + process_sp->GetTarget().GetUserSpecifiedTrapHandlerNames (args); + size_t count = args.GetArgumentCount(); + for (size_t i = 0; i < count; i++) + { + const char *func_name = args.GetArgumentAtIndex(i); + m_user_supplied_trap_handler_functions.push_back (ConstString (func_name)); + } + } } uint32_t @@ -95,7 +108,13 @@ UnwindLLDB::AddFirstFrame () first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; m_frames.push_back (first_cursor_sp); return true; + unwind_done: + Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); + if (log) + { + log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + } m_unwind_complete = true; return false; } @@ -138,10 +157,27 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (reg_ctx_sp.get() == NULL) + { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } + if (log) + log->Printf ("%*sFrame %d did not get a RegisterContext, stopping.", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); goto unwind_done; + } if (!reg_ctx_sp->IsValid()) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk", @@ -151,6 +187,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (!reg_ctx_sp->GetCFA (cursor_sp->cfa)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk", @@ -160,15 +202,33 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa)) { - if (log) + // On Mac OS X, the _sigtramp asynchronous signal trampoline frame may not have + // its (constructed) CFA aligned correctly -- don't do the abi alignment check for + // these. + if (reg_ctx_sp->IsTrapHandlerFrame() == false) { - log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", - cur_idx < 100 ? cur_idx : 100, "", cur_idx); + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } + if (log) + { + log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk", + cur_idx < 100 ? cur_idx : 100, "", cur_idx); + } + goto unwind_done; } - goto unwind_done; } if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk", @@ -178,6 +238,12 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc)) { + // If the RegisterContextLLDB has a fallback UnwindPlan, it will switch to that and return + // true. Subsequent calls to TryFallbackUnwindPlan() will return false. + if (m_frames[cur_idx - 1]->reg_ctx_lldb_sp->TryFallbackUnwindPlan()) + { + return AddOneMoreFrame (abi); + } if (log) { log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk", @@ -185,12 +251,26 @@ UnwindLLDB::AddOneMoreFrame (ABI *abi) } goto unwind_done; } + if (!m_frames.empty()) + { + // Infinite loop where the current cursor is the same as the previous one... + if (m_frames.back()->start_pc == cursor_sp->start_pc && m_frames.back()->cfa == cursor_sp->cfa) + { + if (log) + log->Printf ("th%d pc of this frame is the same as the previous frame and CFAs for both frames are identical -- stopping unwind", m_thread.GetIndexID()); + goto unwind_done; + } + } cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp; m_frames.push_back (cursor_sp); return true; unwind_done: + if (log) + { + log->Printf ("th%d Unwind of this thread is complete.", m_thread.GetIndexID()); + } m_unwind_complete = true; return false; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h index 5725654..eb54003 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Utility/UnwindLLDB.h @@ -13,6 +13,7 @@ #include <vector> #include "lldb/lldb-public.h" +#include "lldb/Core/ConstString.h" #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/RegisterContext.h" @@ -90,6 +91,24 @@ protected: SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_register); + //------------------------------------------------------------------ + /// Provide the list of user-specified trap handler functions + /// + /// The Platform is one source of trap handler function names; that + /// may be augmented via a setting. The setting needs to be converted + /// into an array of ConstStrings before it can be used - we only want + /// to do that once per thread so it's here in the UnwindLLDB object. + /// + /// @return + /// Vector of ConstStrings of trap handler function names. May be + /// empty. + //------------------------------------------------------------------ + const std::vector<ConstString> & + GetUserSpecifiedTrapHandlerFunctionNames () + { + return m_user_supplied_trap_handler_functions; + } + private: struct Cursor @@ -110,6 +129,7 @@ private: // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size() // is how far we've currently gone. + std::vector<ConstString> m_user_supplied_trap_handler_functions; bool AddOneMoreFrame (ABI *abi); bool AddFirstFrame (); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 93641ed..7ea5c89 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -131,7 +131,8 @@ ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *head VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && - last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) + last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() && + last_entry->GetByteSize() == last_entry->data.GetByteSize()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); @@ -294,9 +295,13 @@ ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error & size_t zero_fill_size = 0; // Padding lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address - if (file_end > offset) - bytes_left = file_end - offset; + // Figure out how many on-disk bytes remain in this segment + // starting at the given offset + if (file_end > file_start + offset) + bytes_left = file_end - (file_start + offset); + // Figure out how many bytes we need to zero-fill if we are + // reading more bytes than available in the on-disk segment if (bytes_to_read > bytes_left) { zero_fill_size = bytes_to_read - bytes_left; @@ -365,12 +370,12 @@ enum { // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void -ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, +ParseFreeBSDPrStatus(ThreadData &thread_data, DataExtractor &data, ArchSpec &arch) { lldb::offset_t offset = 0; - bool have_padding = (arch.GetMachine() == llvm::Triple::mips64 || - arch.GetMachine() == llvm::Triple::x86_64); + bool lp64 = (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); @@ -380,23 +385,26 @@ ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data, log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version); } - if (have_padding) - offset += 4; - offset += 28; // pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate - thread_data->signo = data.GetU32(&offset); // pr_cursig + // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate + if (lp64) + offset += 32; + else + offset += 16; + + thread_data.signo = data.GetU32(&offset); // pr_cursig offset += 4; // pr_pid - if (have_padding) + if (lp64) offset += 4; size_t len = data.GetByteSize() - offset; - thread_data->gpregset = DataExtractor(data, offset, len); + thread_data.gpregset = DataExtractor(data, offset, len); } static void -ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data) +ParseFreeBSDThrMisc(ThreadData &thread_data, DataExtractor &data) { lldb::offset_t offset = 0; - thread_data->name = data.GetCStr(&offset, 20); + thread_data.name = data.GetCStr(&offset, 20); } /// Parse Thread context from PT_NOTE segment and store it in the thread list @@ -418,13 +426,13 @@ ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data) /// For case (b) there may be either one NT_PRPSINFO per thread, or a single /// one that applies to all threads (depending on the platform type). void -ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, +ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header, DataExtractor segment_data) { assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE); lldb::offset_t offset = 0; - ThreadData *thread_data = new ThreadData(); + std::unique_ptr<ThreadData> thread_data(new ThreadData); bool have_prstatus = false; bool have_prpsinfo = false; @@ -447,7 +455,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * assert(thread_data->gpregset.GetByteSize() > 0); // Add the new thread to thread list m_thread_data.push_back(*thread_data); - thread_data = new ThreadData(); + *thread_data = ThreadData(); have_prstatus = false; have_prpsinfo = false; } @@ -464,7 +472,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * { case NT_FREEBSD_PRSTATUS: have_prstatus = true; - ParseFreeBSDPrStatus(thread_data, note_data, arch); + ParseFreeBSDPrStatus(*thread_data, note_data, arch); break; case NT_FREEBSD_FPREGSET: thread_data->fpregset = note_data; @@ -473,7 +481,7 @@ ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader * have_prpsinfo = true; break; case NT_FREEBSD_THRMISC: - ParseFreeBSDThrMisc(thread_data, note_data); + ParseFreeBSDThrMisc(*thread_data, note_data); break; case NT_FREEBSD_PROCSTAT_AUXV: // FIXME: FreeBSD sticks an int at the beginning of the note diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp index 610506c..3e09c7b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.cpp @@ -63,8 +63,16 @@ RegisterContextCorePOSIX_x86_64::WriteFPR() bool RegisterContextCorePOSIX_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); - return true; + switch (reg_info->byte_size) + { + case 4: + value = *(uint32_t *)(m_gpregset + reg_info->byte_offset); + return true; + case 8: + value = *(uint64_t *)(m_gpregset + reg_info->byte_offset); + return true; + } + return false; } bool diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 3bda86d..cadcf53 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -17,6 +17,7 @@ #include "ThreadElfCore.h" #include "ProcessElfCore.h" #include "RegisterContextLinux_x86_64.h" +#include "RegisterContextFreeBSD_i386.h" #include "RegisterContextFreeBSD_mips64.h" #include "RegisterContextFreeBSD_x86_64.h" #include "RegisterContextPOSIXCore_mips64.h" @@ -85,45 +86,66 @@ ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame) ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get()); ArchSpec arch = process->GetArchitecture(); - switch (arch.GetMachine()) + RegisterInfoInterface *reg_interface = NULL; + + switch (arch.GetTriple().getOS()) { - case llvm::Triple::mips64: - switch (arch.GetTriple().getOS()) + case llvm::Triple::FreeBSD: + { + switch (arch.GetMachine()) { - case llvm::Triple::FreeBSD: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, new RegisterContextFreeBSD_mips64(arch), m_gpregset_data, m_fpregset_data)); + case llvm::Triple::mips64: + reg_interface = new RegisterContextFreeBSD_mips64(arch); + break; + case llvm::Triple::x86: + reg_interface = new RegisterContextFreeBSD_i386(arch); + break; + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(arch); break; default: - if (log) - log->Printf ("elf-core::%s:: OS(%d) not supported", - __FUNCTION__, arch.GetTriple().getOS()); - assert (false && "OS not supported"); break; } break; - case llvm::Triple::x86_64: - switch (arch.GetTriple().getOS()) + } + + case llvm::Triple::Linux: + { + switch (arch.GetMachine()) { - case llvm::Triple::FreeBSD: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextFreeBSD_x86_64(arch), m_gpregset_data, m_fpregset_data)); - break; - case llvm::Triple::Linux: - m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, new RegisterContextLinux_x86_64(arch), m_gpregset_data, m_fpregset_data)); + case llvm::Triple::x86_64: + reg_interface = new RegisterContextLinux_x86_64(arch); break; default: - if (log) - log->Printf ("elf-core::%s:: OS(%d) not supported", - __FUNCTION__, arch.GetTriple().getOS()); - assert (false && "OS not supported"); break; } break; + } + + default: + break; + } + + if (!reg_interface) { + if (log) + log->Printf ("elf-core::%s:: Architecture(%d) or OS(%d) not supported", + __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); + assert (false && "Architecture or OS not supported"); + } + + switch (arch.GetMachine()) + { + case llvm::Triple::mips64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_mips64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64 (*this, reg_interface, m_gpregset_data, m_fpregset_data)); + break; default: - if (log) - log->Printf ("elf-core::%s:: Architecture(%d) not supported", - __FUNCTION__, arch.GetMachine()); - assert (false && "Architecture not supported"); + break; } + reg_ctx_sp = m_thread_reg_ctx_sp; } else if (m_unwinder_ap.get()) diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f67e1b5..72600d8 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,9 +13,11 @@ // C Includes #include <limits.h> #include <string.h> +#include <sys/stat.h> // C++ Includes // Other libraries and framework includes +#include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" @@ -143,7 +145,9 @@ GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name, m_private_is_running (false), m_history (512), m_send_acks (true), - m_is_platform (is_platform) + m_is_platform (is_platform), + m_listen_thread (LLDB_INVALID_HOST_THREAD), + m_listen_url () { } @@ -195,14 +199,14 @@ GDBRemoteCommunication::SendNack () return bytes_written; } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length) { Mutex::Locker locker(m_sequence_mutex); return SendPacketNoLock (payload, payload_length); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length) { if (IsConnected()) @@ -235,32 +239,32 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le if (bytes_written == packet.GetSize()) { if (GetSendAcks ()) - { - if (GetAck () != '+') - { - if (log) - log->Printf("get ack failed..."); - return 0; - } - } + return GetAck (); + else + return PacketResult::Success; } else { if (log) log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData()); } - return bytes_written; } - return 0; + return PacketResult::ErrorSendFailed; } -char +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::GetAck () { StringExtractorGDBRemote packet; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1) - return packet.GetChar(); - return 0; + PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()); + if (result == PacketResult::Success) + { + if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck) + return PacketResult::Success; + else + return PacketResult::ErrorSendAck; + } + return result; } bool @@ -280,7 +284,7 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec) { uint8_t buffer[8192]; @@ -290,9 +294,10 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac // Check for a packet from our cache first without trying any reading... if (CheckForPacket (NULL, 0, packet)) - return packet.GetStringRef().size(); + return PacketResult::Success; bool timed_out = false; + bool disconnected = false; while (IsConnected() && !timed_out) { lldb::ConnectionStatus status = eConnectionStatusNoConnection; @@ -309,7 +314,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac if (bytes_read > 0) { if (CheckForPacket (buffer, bytes_read, packet)) - return packet.GetStringRef().size(); + return PacketResult::Success; } else { @@ -326,13 +331,19 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac case eConnectionStatusNoConnection: case eConnectionStatusLostConnection: case eConnectionStatusError: + disconnected = true; Disconnect(); break; } } } - packet.Clear (); - return 0; + packet.Clear (); + if (disconnected) + return PacketResult::ErrorDisconnected; + if (timed_out) + return PacketResult::ErrorReplyTimeout; + else + return PacketResult::ErrorReplyFailed; } bool @@ -486,6 +497,13 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri for (int i = 0; i < repeat_count; ++i) packet_str.push_back(char_to_repeat); } + else if (*c == 0x7d) + { + // 0x7d is the escape character. The next character is to + // be XOR'd with 0x20. + char escapee = *++c ^ 0x20; + packet_str.push_back(escapee); + } else { packet_str.push_back(*c); @@ -538,18 +556,65 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri } Error -GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, - const char *unix_socket_name, // For handshaking - lldb_private::ProcessLaunchInfo &launch_info) +GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) +{ + Error error; + if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) + { + error.SetErrorString("listen thread already running"); + } + else + { + char listen_url[512]; + if (hostname && hostname[0]) + snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); + else + snprintf(listen_url, sizeof(listen_url), "listen://%i", port); + m_listen_url = listen_url; + SetConnection(new ConnectionFileDescriptor()); + m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error); + } + return error; +} + +bool +GDBRemoteCommunication::JoinListenThread () +{ + if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread)) + { + Host::ThreadJoin(m_listen_thread, NULL, NULL); + m_listen_thread = LLDB_INVALID_HOST_THREAD; + } + return true; +} + +lldb::thread_result_t +GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg) +{ + GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg; + Error error; + ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection (); + + if (connection) + { + // Do the listen on another thread so we can continue on... + if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess) + comm->SetConnection(NULL); + } + return NULL; +} + +Error +GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, + uint16_t in_port, + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &out_port) { + out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; - // This function will fill in the launch information for the debugserver - // instance that gets launched. - launch_info.Clear(); - char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); @@ -591,19 +656,88 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); - debugserver_args.AppendArgument(debugserver_url); + + // If a host and port is supplied then use it + char host_and_port[128]; + if (hostname) + { + snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); + debugserver_args.AppendArgument(host_and_port); + } + else + { + host_and_port[0] = '\0'; + } + // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); - - if (unix_socket_name && unix_socket_name[0]) + + char named_pipe_path[PATH_MAX]; + named_pipe_path[0] = '\0'; + + bool listen = false; + if (host_and_port[0]) + { + // Create a temporary file to get the stdout/stderr and redirect the + // output of the command into this file. We will later read this file + // if all goes well and fill the data into "command_output_ptr" + + if (in_port == 0) + { + // Binding to port zero, we need to figure out what port it ends up + // using using a named pipe... + FileSpec tmpdir_file_spec; + if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) + { + tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); + strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); + } + else + { + strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); + } + + if (::mktemp (named_pipe_path)) + { +#if defined(_MSC_VER) + if ( false ) +#else + if (::mkfifo(named_pipe_path, 0600) == 0) +#endif + { + debugserver_args.AppendArgument("--named-pipe"); + debugserver_args.AppendArgument(named_pipe_path); + } + } + } + else + { + listen = true; + } + } + else { - debugserver_args.AppendArgument("--unix-socket"); - debugserver_args.AppendArgument(unix_socket_name); + // No host and port given, so lets listen on our end and make the debugserver + // connect to us.. + error = StartListenThread ("localhost", 0); + if (error.Fail()) + return error; + + ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); + out_port = connection->GetBoundPort(3); + assert (out_port != 0); + char port_cstr[32]; + snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); + // Send the host and port down that debugserver and specify an option + // so that it connects back to the port we are listening to in this process + debugserver_args.AppendArgument("--reverse-connect"); + debugserver_args.AppendArgument(port_cstr); } + const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { @@ -617,46 +751,41 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } - // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); - // debugserver_args.AppendArgument("--log-flags=0x802e0e"); - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) + // Close STDIN, STDOUT and STDERR. We might need to redirect them + // to "/dev/null" if we run into any problems. + launch_info.AppendCloseFileAction (STDIN_FILENO); + launch_info.AppendCloseFileAction (STDOUT_FILENO); + launch_info.AppendCloseFileAction (STDERR_FILENO); + + error = Host::LaunchProcess(launch_info); + + if (named_pipe_path[0]) { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); + File name_pipe_file; + error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + if (error.Success()) + { + char port_cstr[256]; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + error = name_pipe_file.Read(port_cstr, num_bytes); + assert (error.Success()); + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + out_port = Args::StringToUInt32(port_cstr, 0); + name_pipe_file.Close(); + } + Host::Unlink(named_pipe_path); } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) + else if (listen) { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); + } - else if (attach_name && attach_name[0]) + else { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); + // Make sure we actually connect with the debugserver... + JoinListenThread(); } -#endif - - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. -// launch_info.AppendCloseFileAction (STDIN_FILENO); -// launch_info.AppendCloseFileAction (STDOUT_FILENO); -// launch_info.AppendCloseFileAction (STDERR_FILENO); - - error = Host::LaunchProcess(launch_info); } else { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index a107795..d836111 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -35,6 +35,19 @@ public: { eBroadcastBitRunPacketSent = kLoUserBroadcastBit }; + + enum class PacketResult + { + Success = 0, // Success + ErrorSendFailed, // Error sending the packet + ErrorSendAck, // Didn't get an ack back after sending a packet + ErrorReplyFailed, // Error getting the reply + ErrorReplyTimeout, // Timed out waiting for reply + ErrorReplyInvalid, // Got a reply but it wasn't valid for the packet that was sent + ErrorReplyAck, // Sending reply ack failed + ErrorDisconnected, // We were disconnected + ErrorNoSequenceLock // We couldn't get the sequence lock for a multi-packet request + }; //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ @@ -45,7 +58,7 @@ public: virtual ~GDBRemoteCommunication(); - char + PacketResult GetAck (); size_t @@ -109,9 +122,10 @@ public: // supplied connection URL. //------------------------------------------------------------------ lldb_private::Error - StartDebugserverProcess (const char *connect_url, - const char *unix_socket_name, - lldb_private::ProcessLaunchInfo &launch_info); + StartDebugserverProcess (const char *hostname, + uint16_t in_port, // If set to zero, then out_port will contain the bound port on exit + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &out_port); void DumpHistory(lldb_private::Stream &strm); @@ -223,15 +237,15 @@ protected: mutable bool m_dumped_to_log; }; - size_t + PacketResult SendPacket (const char *payload, size_t payload_length); - size_t + PacketResult SendPacketNoLock (const char *payload, size_t payload_length); - size_t + PacketResult WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response, uint32_t timeout_usec); @@ -242,7 +256,7 @@ protected: // Classes that inherit from GDBRemoteCommunication can see and modify these //------------------------------------------------------------------ uint32_t m_packet_timeout; -#ifdef LLDB_CONFIGURATION_DEBUG +#ifdef ENABLE_MUTEX_ERROR_CHECKING lldb_private::TrackingMutex m_sequence_mutex; #else lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time @@ -256,9 +270,22 @@ protected: // a single process + lldb_private::Error + StartListenThread (const char *hostname = "localhost", + uint16_t port = 0); + + bool + JoinListenThread (); + static lldb::thread_result_t + ListenThread (lldb::thread_arg_t arg); private: + + lldb::thread_t m_listen_thread; + std::string m_listen_url; + + //------------------------------------------------------------------ // For GDBRemoteCommunication only //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 2690992..ab3bf7f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -66,6 +66,9 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_prepare_for_reg_writing_reply (eLazyBoolCalculate), m_supports_p (eLazyBoolCalculate), m_supports_QSaveRegisterState (eLazyBoolCalculate), + m_supports_qXfer_libraries_read (eLazyBoolCalculate), + m_supports_qXfer_libraries_svr4_read (eLazyBoolCalculate), + m_supports_augmented_libraries_svr4_read (eLazyBoolCalculate), m_supports_qProcessInfoPID (true), m_supports_qfProcessInfo (true), m_supports_qUserName (true), @@ -84,6 +87,7 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_async_mutex (Mutex::eMutexTypeRecursive), m_async_packet_predicate (false), m_async_packet (), + m_async_result (PacketResult::Success), m_async_response (), m_async_signal (-1), m_thread_id_to_used_usec_map (), @@ -95,7 +99,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) : m_os_build (), m_os_kernel (), m_hostname (), - m_default_packet_timeout (0) + m_default_packet_timeout (0), + m_max_packet_size (0) { } @@ -117,12 +122,25 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) // fail to send the handshake ack, there is no reason to continue... if (SendAck()) { + // Wait for any responses that might have been queued up in the remote + // GDB server and flush them all + StringExtractorGDBRemote response; + PacketResult packet_result = PacketResult::Success; + const uint32_t timeout_usec = 10 * 1000; // Wait for 10 ms for a response + while (packet_result == PacketResult::Success) + packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, timeout_usec); + // The return value from QueryNoAckModeSupported() is true if the packet // was sent and _any_ response (including UNIMPLEMENTED) was received), // or false if no response was received. This quickly tells us if we have // a live connection to a remote GDB server... if (QueryNoAckModeSupported()) { +#if 0 + // Set above line to "#if 1" to test packet speed if remote GDB server + // supports the qSpeedTest packet... + TestPacketSpeed(10000); +#endif return true; } else @@ -140,6 +158,46 @@ GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) } bool +GDBRemoteCommunicationClient::GetAugmentedLibrariesSVR4ReadSupported () +{ + if (m_supports_augmented_libraries_svr4_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_augmented_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesSVR4ReadSupported () +{ + if (m_supports_qXfer_libraries_svr4_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_libraries_svr4_read == eLazyBoolYes); +} + +bool +GDBRemoteCommunicationClient::GetQXferLibrariesReadSupported () +{ + if (m_supports_qXfer_libraries_read == eLazyBoolCalculate) + { + GetRemoteQSupported(); + } + return (m_supports_qXfer_libraries_read == eLazyBoolYes); +} + +uint64_t +GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() +{ + if (m_max_packet_size == 0) + { + GetRemoteQSupported(); + } + return m_max_packet_size; +} + +bool GDBRemoteCommunicationClient::QueryNoAckModeSupported () { if (m_supports_not_sending_acks == eLazyBoolCalculate) @@ -148,7 +206,7 @@ GDBRemoteCommunicationClient::QueryNoAckModeSupported () m_supports_not_sending_acks = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false)) + if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -169,7 +227,7 @@ GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () m_supports_threads_in_stop_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false)) + if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_threads_in_stop_reply = eLazyBoolYes; @@ -185,7 +243,7 @@ GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false)) + if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_attach_or_wait_reply = eLazyBoolYes; @@ -205,7 +263,7 @@ GDBRemoteCommunicationClient::GetSyncThreadStateSupported () m_prepare_for_reg_writing_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false)) + if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_prepare_for_reg_writing_reply = eLazyBoolYes; @@ -236,6 +294,9 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; + m_supports_qXfer_libraries_read = eLazyBoolCalculate; + m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; m_supports_qfProcessInfo = true; @@ -251,8 +312,50 @@ GDBRemoteCommunicationClient::ResetDiscoverableSettings() m_supports_QEnvironmentHexEncoded = true; m_host_arch.Clear(); m_process_arch.Clear(); + + m_max_packet_size = 0; } +void +GDBRemoteCommunicationClient::GetRemoteQSupported () +{ + // Clear out any capabilities we expect to see in the qSupported response + m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; + m_supports_qXfer_libraries_read = eLazyBoolNo; + m_supports_augmented_libraries_svr4_read = eLazyBoolNo; + m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qSupported", + response, + /*send_async=*/false) == PacketResult::Success) + { + const char *response_cstr = response.GetStringRef().c_str(); + if (::strstr (response_cstr, "qXfer:libraries-svr4:read+")) + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; + if (::strstr (response_cstr, "augmented-libraries-svr4-read")) + { + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied + m_supports_augmented_libraries_svr4_read = eLazyBoolYes; + } + if (::strstr (response_cstr, "qXfer:libraries:read+")) + m_supports_qXfer_libraries_read = eLazyBoolYes; + + const char *packet_size_str = ::strstr (response_cstr, "PacketSize="); + if (packet_size_str) + { + StringExtractorGDBRemote packet_response(packet_size_str + strlen("PacketSize=")); + m_max_packet_size = packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); + if (m_max_packet_size == 0) + { + m_max_packet_size = UINT64_MAX; // Must have been a garbled response + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + if (log) + log->Printf ("Garbled PacketSize spec in qSupported response"); + } + } + } +} bool GDBRemoteCommunicationClient::GetThreadSuffixSupported () @@ -261,7 +364,7 @@ GDBRemoteCommunicationClient::GetThreadSuffixSupported () { StringExtractorGDBRemote response; m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false)) + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_thread_suffix = eLazyBoolYes; @@ -281,7 +384,7 @@ GDBRemoteCommunicationClient::GetVContSupported (char flavor) m_supports_vCont_C = eLazyBoolNo; m_supports_vCont_s = eLazyBoolNo; m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false)) + if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); if (::strstr (response_cstr, ";c")) @@ -345,7 +448,7 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) else snprintf(packet, sizeof(packet), "p0"); - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) m_supports_p = eLazyBoolYes; @@ -354,7 +457,63 @@ GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) return m_supports_p; } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses +( + const char *payload_prefix, + std::string &response_string +) +{ + Mutex::Locker locker; + if (!GetSequenceMutex(locker, + "ProcessGDBRemote::SendPacketsAndConcatenateResponses() failed due to not getting the sequence mutex")) + { + Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); + if (log) + log->Printf("error: failed to get packet sequence mutex, not sending packets with prefix '%s'", + payload_prefix); + return PacketResult::ErrorNoSequenceLock; + } + + response_string = ""; + std::string payload_prefix_str(payload_prefix); + unsigned int response_size = 0x1000; + if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet + response_size = GetRemoteMaxPacketSize(); + } + + for (unsigned int offset = 0; true; offset += response_size) + { + StringExtractorGDBRemote this_response; + // Construct payload + char sizeDescriptor[128]; + snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset, response_size); + PacketResult result = SendPacketAndWaitForResponse((payload_prefix_str + sizeDescriptor).c_str(), + this_response, + /*send_async=*/false); + if (result != PacketResult::Success) + return result; + + const std::string &this_string = this_response.GetStringRef(); + + // Check for m or l as first character; l seems to mean this is the last chunk + char first_char = *this_string.c_str(); + if (first_char != 'm' && first_char != 'l') + { + return PacketResult::ErrorReplyInvalid; + } + // Skip past m or l + const char *s = this_string.c_str() + 1; + + // Concatenate the result so far + response_string += s; + if (first_char == 'l') + // We're done + return PacketResult::Success; + } +} + +GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, @@ -368,7 +527,18 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse send_async); } -size_t +GDBRemoteCommunicationClient::PacketResult +GDBRemoteCommunicationClient::SendPacketAndWaitForResponseNoLock (const char *payload, + size_t payload_length, + StringExtractorGDBRemote &response) +{ + PacketResult packet_result = SendPacketNoLock (payload, payload_length); + if (packet_result == PacketResult::Success) + packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); + return packet_result; +} + +GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, @@ -377,18 +547,13 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse bool send_async ) { + PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); size_t response_len = 0; if (GetSequenceMutex (locker)) { - if (SendPacketNoLock (payload, payload_length)) - response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - else - { - if (log) - log->Printf("error: failed to send '%*s'", (int) payload_length, payload); - } + packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } else { @@ -424,6 +589,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse // Swap the response buffer to avoid malloc and string copy response.GetStringRef().swap (m_async_response.GetStringRef()); response_len = response.GetStringRef().size(); + packet_result = m_async_result; } else { @@ -456,13 +622,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse if (log) log->Printf ("async: got lock without sending interrupt"); // Send the packet normally since we got the lock - if (SendPacketNoLock (payload, payload_length)) - response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - else - { - if (log) - log->Printf("error: failed to send '%*s'", (int) payload_length, payload); - } + packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } } else @@ -483,12 +643,7 @@ GDBRemoteCommunicationClient::SendPacketAndWaitForResponse log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); } } - if (response_len == 0) - { - if (log) - log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload); - } - return response_len; + return packet_result; } static const char *end_delimiter = "--end--;"; @@ -615,7 +770,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse { if (log) log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); - if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0) + if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) state = eStateInvalid; m_private_is_running.SetValue (true, eBroadcastAlways); @@ -626,7 +781,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse if (log) log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str()); - if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX)) + if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX) == PacketResult::Success) { if (response.Empty()) state = eStateInvalid; @@ -683,7 +838,7 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse // packet to make sure it doesn't get in the way StringExtractorGDBRemote extra_stop_reply_packet; uint32_t timeout_usec = 1000; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec)) + if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec) == PacketResult::Success) { switch (extra_stop_reply_packet.GetChar()) { @@ -747,11 +902,12 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); // We are supposed to send an asynchronous packet while - // we are running. + // we are running. m_async_response.Clear(); if (m_async_packet.empty()) { - if (packet_log) + m_async_result = PacketResult::ErrorSendFailed; + if (packet_log) packet_log->Printf ("async: error: empty async packet"); } @@ -760,10 +916,10 @@ GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse if (packet_log) packet_log->Printf ("async: sending packet"); - SendPacketAndWaitForResponse (&m_async_packet[0], - m_async_packet.size(), - m_async_response, - false); + m_async_result = SendPacketAndWaitForResponse (&m_async_packet[0], + m_async_packet.size(), + m_async_response, + false); } // Let the other thread that was trying to send the async // packet know that the packet has been sent and response is @@ -973,7 +1129,7 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID () { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false)) + if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) { if (response.GetChar() == 'Q') if (response.GetChar() == 'C') @@ -987,7 +1143,7 @@ GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) { error_str.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false)) + if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -1050,7 +1206,7 @@ GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &laun } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1097,7 +1253,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu { packet.PutCString("QEnvironmentHexEncoded:"); packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1113,7 +1269,7 @@ GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_valu else if (m_supports_QEnvironment) { packet.Printf("QEnvironment:%s", name_equal_value); - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1136,7 +1292,7 @@ GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) StreamString packet; packet.Printf("QLaunchArch:%s", arch); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1236,7 +1392,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qHostInfo", response, false)) + if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -1248,6 +1404,7 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) std::string os_name; std::string vendor_name; std::string triple; + std::string distribution_id; uint32_t pointer_byte_size = 0; StringExtractor extractor; ByteOrder byte_order = eByteOrderInvalid; @@ -1281,6 +1438,13 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) extractor.GetHexByteString (triple); ++num_keys_decoded; } + else if (name.compare ("distribution_id") == 0) + { + extractor.GetStringRef ().swap (value); + extractor.SetFilePos (0); + extractor.GetHexByteString (distribution_id); + ++num_keys_decoded; + } else if (name.compare("os_build") == 0) { extractor.GetStringRef().swap(value); @@ -1455,7 +1619,9 @@ GDBRemoteCommunicationClient::GetHostInfo (bool force) { assert (byte_order == m_host_arch.GetByteOrder()); } - } + } + if (!distribution_id.empty ()) + m_host_arch.SetDistributionId (distribution_id.c_str ()); } } } @@ -1474,7 +1640,7 @@ GDBRemoteCommunicationClient::SendAttach char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid); assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsErrorResponse()) return response.GetError(); @@ -1514,7 +1680,7 @@ GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) permissions & lldb::ePermissionsExecutable ? "x" : ""); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -1537,7 +1703,7 @@ GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -1563,7 +1729,7 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { m_supports_detach_stay_stopped = eLazyBoolYes; } @@ -1580,15 +1746,15 @@ GDBRemoteCommunicationClient::Detach (bool keep_stopped) } else { - size_t num_sent = SendPacket ("D1", 2); - if (num_sent == 0) + PacketResult packet_result = SendPacket ("D1", 2); + if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } } else { - size_t num_sent = SendPacket ("D", 1); - if (num_sent == 0) + PacketResult packet_result = SendPacket ("D", 1); + if (packet_result != PacketResult::Success) error.SetErrorString ("Sending disconnect packet failed."); } return error; @@ -1608,7 +1774,7 @@ GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr, const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; @@ -1711,7 +1877,7 @@ GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; std::string name; @@ -1773,7 +1939,7 @@ GDBRemoteCommunicationClient::SetSTDIN (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1795,7 +1961,7 @@ GDBRemoteCommunicationClient::SetSTDOUT (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1817,7 +1983,7 @@ GDBRemoteCommunicationClient::SetSTDERR (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1833,7 +1999,7 @@ bool GDBRemoteCommunicationClient::GetWorkingDir (std::string &cwd) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false)) + if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) return false; @@ -1855,7 +2021,7 @@ GDBRemoteCommunicationClient::SetWorkingDir (char const *path) packet.PutBytesAsRawHex8(path, strlen(path)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1874,7 +2040,7 @@ GDBRemoteCommunicationClient::SetDisableASLR (bool enable) const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1893,6 +2059,11 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot std::string name; std::string value; StringExtractor extractor; + + uint32_t cpu = LLDB_INVALID_CPUTYPE; + uint32_t sub = 0; + std::string vendor; + std::string os_type; while (response.GetNameColonValue(name, value)) { @@ -1938,6 +2109,32 @@ GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemot extractor.GetHexByteString (value); process_info.GetExecutableFile().SetFile (value.c_str(), false); } + else if (name.compare("cputype") == 0) + { + cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); + } + else if (name.compare("cpusubtype") == 0) + { + sub = Args::StringToUInt32 (value.c_str(), 0, 16); + } + else if (name.compare("vendor") == 0) + { + vendor = value; + } + else if (name.compare("ostype") == 0) + { + os_type = value; + } + } + + if (cpu != LLDB_INVALID_CPUTYPE && !vendor.empty() && !os_type.empty()) + { + if (vendor == "apple") + { + process_info.GetArchitecture().SetArchitecture (eArchTypeMachO, cpu, sub); + process_info.GetArchitecture().GetTriple().setVendorName (llvm::StringRef (vendor)); + process_info.GetArchitecture().GetTriple().setOSName (llvm::StringRef (os_type)); + } } if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) @@ -1957,7 +2154,7 @@ GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceIn const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { return DecodeProcessInfoResponse (response, process_info); } @@ -1981,7 +2178,7 @@ GDBRemoteCommunicationClient::GetCurrentProcessInfo () GetHostInfo (); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse ("qProcessInfo", response, false)) + if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2141,7 +2338,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat } } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false)) + if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { do { @@ -2151,7 +2348,7 @@ GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &mat process_infos.Append(process_info); response.GetStringRef().clear(); response.SetFilePos(0); - } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false)); + } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); } else { @@ -2172,7 +2369,7 @@ GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2202,7 +2399,7 @@ GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse (packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2228,50 +2425,81 @@ GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets) uint32_t i; TimeValue start_time, end_time; uint64_t total_time_nsec; - float packets_per_second; if (SendSpeedTestPacket (0, 0)) { - for (uint32_t send_size = 0; send_size <= 1024; send_size *= 2) + static uint32_t g_send_sizes[] = { 0, 64, 128, 512, 1024 }; + static uint32_t g_recv_sizes[] = { 0, 64, 128, 512, 1024 }; //, 4*1024, 8*1024, 16*1024, 32*1024, 48*1024, 64*1024, 96*1024, 128*1024 }; + const size_t k_num_send_sizes = sizeof(g_send_sizes)/sizeof(uint32_t); + const size_t k_num_recv_sizes = sizeof(g_recv_sizes)/sizeof(uint32_t); + const uint64_t k_recv_amount = 4*1024*1024; // Receive 4MB + for (uint32_t send_idx = 0; send_idx < k_num_send_sizes; ++send_idx) { - for (uint32_t recv_size = 0; recv_size <= 1024; recv_size *= 2) + const uint32_t send_size = g_send_sizes[send_idx]; + for (uint32_t recv_idx = 0; recv_idx < k_num_recv_sizes; ++recv_idx) { + const uint32_t recv_size = g_recv_sizes[recv_idx]; + StreamString packet; + packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size); + uint32_t bytes_left = send_size; + while (bytes_left > 0) + { + if (bytes_left >= 26) + { + packet.PutCString("abcdefghijklmnopqrstuvwxyz"); + bytes_left -= 26; + } + else + { + packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz"); + bytes_left = 0; + } + } + start_time = TimeValue::Now(); - for (i=0; i<num_packets; ++i) + if (recv_size == 0) { - SendSpeedTestPacket (send_size, recv_size); + for (i=0; i<num_packets; ++i) + { + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); + } + } + else + { + uint32_t bytes_read = 0; + while (bytes_read < k_recv_amount) + { + StringExtractorGDBRemote response; + SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); + bytes_read += recv_size; + } } end_time = TimeValue::Now(); total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - printf ("%u qSpeedTest(send=%-5u, recv=%-5u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n", - num_packets, - send_size, - recv_size, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - packets_per_second); if (recv_size == 0) - recv_size = 32; + { + float packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; + printf ("%u qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n", + num_packets, + send_size, + recv_size, + total_time_nsec / TimeValue::NanoSecPerSec, + total_time_nsec % TimeValue::NanoSecPerSec, + packets_per_second); + } + else + { + float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); + printf ("%u qSpeedTest(send=%-7u, recv=%-7u) sent 4MB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec.\n", + num_packets, + send_size, + recv_size, + total_time_nsec / TimeValue::NanoSecPerSec, + total_time_nsec % TimeValue::NanoSecPerSec, + mb_second); + } } - if (send_size == 0) - send_size = 32; - } - } - else - { - start_time = TimeValue::Now(); - for (i=0; i<num_packets; ++i) - { - GetCurrentProcessID (); } - end_time = TimeValue::Now(); - total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); - packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; - printf ("%u 'qC' packets packets in 0x%" PRIu64 "%9.9" PRIu64 " sec for %f packets/sec.\n", - num_packets, - total_time_nsec / TimeValue::NanoSecPerSec, - total_time_nsec % TimeValue::NanoSecPerSec, - packets_per_second); } } @@ -2296,32 +2524,36 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t } StringExtractorGDBRemote response; - return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0; - return false; + return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; } uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname) { pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; StreamString stream; stream.PutCString("qLaunchGDBServer;"); std::string hostname; - if (Host::GetHostname (hostname)) - { - // Make the GDB server we launch only accept connections from this host - stream.Printf("host:%s;", hostname.c_str()); - } + if (remote_accept_hostname && remote_accept_hostname[0]) + hostname = remote_accept_hostname; else { - // Make the GDB server we launch accept connections from any host since we can't figure out the hostname - stream.Printf("host:*;"); + if (Host::GetHostname (hostname)) + { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } + else + { + // Make the GDB server we launch accept connections from any host since we can't figure out the hostname + stream.Printf("host:*;"); + } } const char *packet = stream.GetData(); int packet_len = stream.GetSize(); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; @@ -2347,7 +2579,7 @@ GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -2369,7 +2601,7 @@ GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -2395,7 +2627,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { @@ -2409,7 +2641,7 @@ GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) bool GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) { - if (SendPacketAndWaitForResponse("?", 1, response, false)) + if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success) return response.IsNormalResponse(); return false; } @@ -2422,7 +2654,7 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto char packet[256]; int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); assert (packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_qThreadStopInfo = false; @@ -2443,15 +2675,10 @@ GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtracto uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { - switch (type) - { - case eBreakpointSoftware: if (!m_supports_z0) return UINT8_MAX; break; - case eBreakpointHardware: if (!m_supports_z1) return UINT8_MAX; break; - case eWatchpointWrite: if (!m_supports_z2) return UINT8_MAX; break; - case eWatchpointRead: if (!m_supports_z3) return UINT8_MAX; break; - case eWatchpointReadWrite: if (!m_supports_z4) return UINT8_MAX; break; - } - + // Check if the stub is known not to support this breakpoint type + if (!SupportsGDBStoppointPacket(type)) + return UINT8_MAX; + // Construct the breakpoint packet char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), @@ -2460,28 +2687,35 @@ GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, type, addr, length); - + // Check we havent overwritten the end of the packet buffer assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, true)) + // Try to send the breakpoint packet, and check that it was correctly sent + if (SendPacketAndWaitForResponse(packet, packet_len, response, true) == PacketResult::Success) { + // Receive and OK packet when the breakpoint successfully placed if (response.IsOKResponse()) return 0; - else if (response.IsErrorResponse()) + + // Error while setting breakpoint, send back specific error + if (response.IsErrorResponse()) return response.GetError(); - } - else - { - switch (type) + + // Empty packet informs us that breakpoint is not supported + if (response.IsUnsupportedResponse()) { + // Disable this breakpoint type since it is unsupported + switch (type) + { case eBreakpointSoftware: m_supports_z0 = false; break; case eBreakpointHardware: m_supports_z1 = false; break; case eWatchpointWrite: m_supports_z2 = false; break; case eWatchpointRead: m_supports_z3 = false; break; case eWatchpointReadWrite: m_supports_z4 = false; break; + } } } - + // Signal generic faliure return UINT8_MAX; } @@ -2497,9 +2731,10 @@ GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thr sequence_mutex_unavailable = false; StringExtractorGDBRemote response; - for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()); - response.IsNormalResponse(); - SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ())) + PacketResult packet_result; + for (packet_result = SendPacketAndWaitForResponseNoLock ("qfThreadInfo", strlen("qfThreadInfo"), response); + packet_result == PacketResult::Success && response.IsNormalResponse(); + packet_result = SendPacketAndWaitForResponseNoLock ("qsThreadInfo", strlen("qsThreadInfo"), response)) { char ch = response.GetChar(); if (ch == 'l') @@ -2539,7 +2774,7 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr() if (!IsRunning()) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false)) + if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success) { if (response.IsNormalResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); @@ -2569,7 +2804,7 @@ GDBRemoteCommunicationClient::RunShellCommand (const char *command, // const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return Error("malformed reply"); @@ -2608,7 +2843,7 @@ GDBRemoteCommunicationClient::MakeDirectory (const char *path, const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } @@ -2628,7 +2863,7 @@ GDBRemoteCommunicationClient::SetFilePermissions (const char *path, const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return Error(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX); } @@ -2679,7 +2914,7 @@ GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, UINT64_MAX, error); } @@ -2695,7 +2930,7 @@ GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, -1, error) == 0; } @@ -2713,7 +2948,7 @@ GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_sp const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return UINT64_MAX; @@ -2733,7 +2968,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const char *path, uint32_t &fil const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { @@ -2780,7 +3015,7 @@ GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return 0; @@ -2819,7 +3054,7 @@ GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { @@ -2861,7 +3096,7 @@ GDBRemoteCommunicationClient::CreateSymlink (const char *src, const char *dst) const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { @@ -2902,7 +3137,7 @@ GDBRemoteCommunicationClient::Unlink (const char *path) const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { @@ -2942,7 +3177,7 @@ GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_ const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -2966,7 +3201,7 @@ GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_s const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -2998,7 +3233,7 @@ GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, String else packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false); + return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; @@ -3024,7 +3259,7 @@ GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractor else packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - return SendPacketAndWaitForResponse(packet, response, false); + return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; @@ -3051,7 +3286,7 @@ GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { @@ -3094,7 +3329,7 @@ GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t sa StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false)) + if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 564afbb..a1e982b 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -47,17 +47,38 @@ public: bool HandshakeWithServer (lldb_private::Error *error_ptr); - size_t + PacketResult SendPacketAndWaitForResponse (const char *send_payload, StringExtractorGDBRemote &response, bool send_async); - size_t + PacketResult SendPacketAndWaitForResponse (const char *send_payload, size_t send_length, StringExtractorGDBRemote &response, bool send_async); + // For packets which specify a range of output to be returned, + // return all of the output via a series of request packets of the form + // <prefix>0,<size> + // <prefix><size>,<size> + // <prefix><size>*2,<size> + // <prefix><size>*3,<size> + // ... + // until a "$l..." packet is received, indicating the end. + // (size is in hex; this format is used by a standard gdbserver to + // return the given portion of the output specified by <prefix>; + // for example, "qXfer:libraries-svr4:read::fff,1000" means + // "return a chunk of the xml description file for shared + // library load addresses, where the chunk starts at offset 0xfff + // and continues for 0x1000 bytes"). + // Concatenate the resulting server response packets together and + // return in response_string. If any packet fails, the return value + // indicates that failure and the returned string value is undefined. + PacketResult + SendPacketsAndConcatenateResponses (const char *send_payload_prefix, + std::string &response_string); + lldb::StateType SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process, const char *packet_payload, @@ -94,7 +115,7 @@ public: GetLaunchSuccess (std::string &error_str); uint16_t - LaunchGDBserverAndGetPort (lldb::pid_t &pid); + LaunchGDBserverAndGetPort (lldb::pid_t &pid, const char *remote_accept_hostname); bool KillSpawnedProcess (lldb::pid_t pid); @@ -248,6 +269,9 @@ public: const lldb_private::ArchSpec & GetProcessArchitecture (); + void + GetRemoteQSupported(); + bool GetVContSupported (char flavor); @@ -359,6 +383,18 @@ public: bool SetCurrentThreadForRun (uint64_t tid); + bool + GetQXferLibrariesReadSupported (); + + bool + GetQXferLibrariesSVR4ReadSupported (); + + uint64_t + GetRemoteMaxPacketSize(); + + bool + GetAugmentedLibrariesSVR4ReadSupported (); + lldb_private::LazyBool SupportsAllocDeallocMemory () // const { @@ -458,6 +494,11 @@ public: protected: + PacketResult + SendPacketAndWaitForResponseNoLock (const char *payload, + size_t payload_length, + StringExtractorGDBRemote &response); + bool GetCurrentProcessInfo (); @@ -484,7 +525,10 @@ protected: lldb_private::LazyBool m_prepare_for_reg_writing_reply; lldb_private::LazyBool m_supports_p; lldb_private::LazyBool m_supports_QSaveRegisterState; - + lldb_private::LazyBool m_supports_qXfer_libraries_read; + lldb_private::LazyBool m_supports_qXfer_libraries_svr4_read; + lldb_private::LazyBool m_supports_augmented_libraries_svr4_read; + bool m_supports_qProcessInfoPID:1, m_supports_qfProcessInfo:1, @@ -511,6 +555,7 @@ protected: lldb_private::Mutex m_async_mutex; lldb_private::Predicate<bool> m_async_packet_predicate; std::string m_async_packet; + PacketResult m_async_result; StringExtractorGDBRemote m_async_response; int m_async_signal; // We were asked to deliver a signal to the inferior process. bool m_interrupt_sent; @@ -526,6 +571,7 @@ protected: std::string m_os_kernel; std::string m_hostname; uint32_t m_default_packet_timeout; + uint64_t m_max_packet_size; // as returned by qSupported bool DecodeProcessInfoResponse (StringExtractorGDBRemote &response, diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 7cc3a05..df95542 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -25,6 +25,7 @@ #include "lldb/Host/File.h" #include "lldb/Host/Host.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" // Project includes @@ -40,6 +41,7 @@ using namespace lldb_private; //---------------------------------------------------------------------- GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), + m_platform_sp (Platform::GetDefaultPlatform ()), m_async_thread (LLDB_INVALID_HOST_THREAD), m_process_launch_info (), m_process_launch_error (), @@ -52,6 +54,23 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) : { } +GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform, + const lldb::PlatformSP& platform_sp) : + GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform), + m_platform_sp (platform_sp), + m_async_thread (LLDB_INVALID_HOST_THREAD), + m_process_launch_info (), + m_process_launch_error (), + m_spawned_pids (), + m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), + m_proc_infos (), + m_proc_infos_index (0), + m_port_map (), + m_port_offset(0) +{ + assert(platform_sp); +} + //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -90,154 +109,249 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, bool &quit) { StringExtractorGDBRemote packet; - if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec)) + PacketResult packet_result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); + if (packet_result == PacketResult::Success) { const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType (); switch (packet_type) { - case StringExtractorGDBRemote::eServerPacketType_nack: - case StringExtractorGDBRemote::eServerPacketType_ack: - break; - - case StringExtractorGDBRemote::eServerPacketType_invalid: - error.SetErrorString("invalid packet"); - quit = true; - break; - - case StringExtractorGDBRemote::eServerPacketType_interrupt: - error.SetErrorString("interrupt received"); - interrupt = true; - break; + case StringExtractorGDBRemote::eServerPacketType_nack: + case StringExtractorGDBRemote::eServerPacketType_ack: + break; + + case StringExtractorGDBRemote::eServerPacketType_invalid: + error.SetErrorString("invalid packet"); + quit = true; + break; + + case StringExtractorGDBRemote::eServerPacketType_interrupt: + error.SetErrorString("interrupt received"); + interrupt = true; + break; + + default: + case StringExtractorGDBRemote::eServerPacketType_unimplemented: + packet_result = SendUnimplementedResponse (packet.GetStringRef().c_str()); + break; - case StringExtractorGDBRemote::eServerPacketType_unimplemented: - return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0; + case StringExtractorGDBRemote::eServerPacketType_A: + packet_result = Handle_A (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_A: - return Handle_A (packet); + case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: + packet_result = Handle_qfProcessInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo: - return Handle_qfProcessInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: + packet_result = Handle_qsProcessInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo: - return Handle_qsProcessInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qC: + packet_result = Handle_qC (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qC: - return Handle_qC (packet); + case StringExtractorGDBRemote::eServerPacketType_qHostInfo: + packet_result = Handle_qHostInfo (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qHostInfo: - return Handle_qHostInfo (packet); + case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: + packet_result = Handle_qLaunchGDBServer (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer: - return Handle_qLaunchGDBServer (packet); + case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: + packet_result = Handle_qKillSpawnedProcess (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess: - return Handle_qKillSpawnedProcess (packet); + case StringExtractorGDBRemote::eServerPacketType_k: + packet_result = Handle_k (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: - return Handle_qLaunchSuccess (packet); + case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess: + packet_result = Handle_qLaunchSuccess (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qGroupName: - return Handle_qGroupName (packet); + case StringExtractorGDBRemote::eServerPacketType_qGroupName: + packet_result = Handle_qGroupName (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: + packet_result = Handle_qProcessInfoPID (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: + packet_result = Handle_qSpeedTest (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qUserName: + packet_result = Handle_qUserName (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: + packet_result = Handle_qGetWorkingDir(packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QEnvironment: + packet_result = Handle_QEnvironment (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: + packet_result = Handle_QLaunchArch (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: + packet_result = Handle_QSetDisableASLR (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: + packet_result = Handle_QSetSTDIN (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: + packet_result = Handle_QSetSTDOUT (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: + packet_result = Handle_QSetSTDERR (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: + packet_result = Handle_QSetWorkingDir (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: + packet_result = Handle_QStartNoAckMode (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: + packet_result = Handle_qPlatform_mkdir (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: + packet_result = Handle_qPlatform_chmod (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: + packet_result = Handle_qPlatform_shell (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID: - return Handle_qProcessInfoPID (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_open: + packet_result = Handle_vFile_Open (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qSpeedTest: - return Handle_qSpeedTest (packet); - - case StringExtractorGDBRemote::eServerPacketType_qUserName: - return Handle_qUserName (packet); - - case StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir: - return Handle_qGetWorkingDir(packet); - - case StringExtractorGDBRemote::eServerPacketType_QEnvironment: - return Handle_QEnvironment (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_close: + packet_result = Handle_vFile_Close (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QLaunchArch: - return Handle_QLaunchArch (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_pread: + packet_result = Handle_vFile_pRead (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR: - return Handle_QSetDisableASLR (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: + packet_result = Handle_vFile_pWrite (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN: - return Handle_QSetSTDIN (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_size: + packet_result = Handle_vFile_Size (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT: - return Handle_QSetSTDOUT (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_mode: + packet_result = Handle_vFile_Mode (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR: - return Handle_QSetSTDERR (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_exists: + packet_result = Handle_vFile_Exists (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir: - return Handle_QSetWorkingDir (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_stat: + packet_result = Handle_vFile_Stat (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode: - return Handle_QStartNoAckMode (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_md5: + packet_result = Handle_vFile_MD5 (packet); + break; - case StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir: - return Handle_qPlatform_mkdir (packet); - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod: - return Handle_qPlatform_chmod (packet); - - case StringExtractorGDBRemote::eServerPacketType_qPlatform_shell: - return Handle_qPlatform_shell (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_open: - return Handle_vFile_Open (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_close: - return Handle_vFile_Close (packet); + case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: + packet_result = Handle_vFile_symlink (packet); + break; + + case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: + packet_result = Handle_vFile_unlink (packet); + break; + } + } + else + { + if (!IsConnected()) + { + error.SetErrorString("lost connection"); + quit = true; + } + else + { + error.SetErrorString("timeout"); + } + } + return packet_result == PacketResult::Success; +} - case StringExtractorGDBRemote::eServerPacketType_vFile_pread: - return Handle_vFile_pRead (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchArguments (const char *const args[], int argc) +{ + if ((argc < 1) || !args || !args[0] || !args[0][0]) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - case StringExtractorGDBRemote::eServerPacketType_vFile_pwrite: - return Handle_vFile_pWrite (packet); + m_process_launch_info.SetArguments (const_cast<const char**> (args), true); + return lldb_private::Error (); +} - case StringExtractorGDBRemote::eServerPacketType_vFile_size: - return Handle_vFile_Size (packet); +lldb_private::Error +GDBRemoteCommunicationServer::SetLaunchFlags (unsigned int launch_flags) +{ + m_process_launch_info.GetFlags ().Set (launch_flags); + return lldb_private::Error (); +} - case StringExtractorGDBRemote::eServerPacketType_vFile_mode: - return Handle_vFile_Mode (packet); +lldb_private::Error +GDBRemoteCommunicationServer::LaunchProcess () +{ + if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) + return lldb_private::Error ("%s: no process command line specified to launch", __FUNCTION__); - case StringExtractorGDBRemote::eServerPacketType_vFile_exists: - return Handle_vFile_Exists (packet); + // specify the process monitor if not already set. This should + // generally be what happens since we need to reap started + // processes. + if (!m_process_launch_info.GetMonitorProcessCallback ()) + m_process_launch_info.SetMonitorProcessCallback(ReapDebuggedProcess, this, false); - case StringExtractorGDBRemote::eServerPacketType_vFile_stat: - return Handle_vFile_Stat (packet); + lldb_private::Error error = m_platform_sp->LaunchProcess (m_process_launch_info); + if (!error.Success ()) + { + fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); + return error; + } - case StringExtractorGDBRemote::eServerPacketType_vFile_md5: - return Handle_vFile_MD5 (packet); + printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID()); - case StringExtractorGDBRemote::eServerPacketType_vFile_symlink: - return Handle_vFile_symlink (packet); - - case StringExtractorGDBRemote::eServerPacketType_vFile_unlink: - return Handle_vFile_unlink (packet); - } - return true; - } - else + // add to list of spawned processes. On an lldb-gdbserver, we + // would expect there to be only one. + lldb::pid_t pid; + if ( (pid = m_process_launch_info.GetProcessID()) != LLDB_INVALID_PROCESS_ID ) { - if (!IsConnected()) - error.SetErrorString("lost connection"); - else - error.SetErrorString("timeout"); + Mutex::Locker locker (m_spawned_pids_mutex); + m_spawned_pids.insert(pid); } - return false; + return error; } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *) { // TODO: Log the packet we aren't handling... return SendPacketNoLock ("", 0); } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) { char packet[16]; @@ -247,7 +361,7 @@ GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err) } -size_t +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendOKResponse () { return SendPacketNoLock ("OK", 2); @@ -256,10 +370,10 @@ GDBRemoteCommunicationServer::SendOKResponse () bool GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr) { - return GetAck(); + return GetAck() == PacketResult::Success; } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet) { StreamString response; @@ -272,6 +386,14 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet response.PutCStringAsRawHex8(host_triple.getTriple().c_str()); response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize()); + const char* distribution_id = host_arch.GetDistributionId ().AsCString (); + if (distribution_id) + { + response.PutCString("distribution_id:"); + response.PutCStringAsRawHex8(distribution_id); + response.PutCString(";"); + } + uint32_t cpu = host_arch.GetMachOCPUType(); uint32_t sub = host_arch.GetMachOCPUSubType(); if (cpu != LLDB_INVALID_CPUTYPE) @@ -351,7 +473,7 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet } #endif // #if defined(__APPLE__) - return SendPacketNoLock (response.GetData(), response.GetSize()) > 0; + return SendPacketNoLock (response.GetData(), response.GetSize()); } static void @@ -377,7 +499,7 @@ CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &r } } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { // Packet format: "qProcessInfoPID:%i" where %i is the pid @@ -396,7 +518,7 @@ GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote & return SendErrorResponse (1); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; @@ -497,7 +619,7 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (3); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) { if (m_proc_infos_index < m_proc_infos.GetSize()) @@ -510,7 +632,7 @@ GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &pa return SendErrorResponse (4); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet) { // Packet format: "qUserName:%i" where %i is the uid @@ -530,7 +652,7 @@ GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet) { // Packet format: "qGroupName:%i" where %i is the gid @@ -549,7 +671,7 @@ GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packe return SendErrorResponse (6); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qSpeedTest:")); @@ -641,7 +763,7 @@ AcceptPortFromInferior (void *arg) // return false; //} -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) { // The 'A' packet is the most over designed packet ever here with @@ -708,8 +830,11 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) if (success) { + // FIXME: remove linux restriction once eLaunchFlagDebug is supported +#if !defined (__linux__) m_process_launch_info.GetFlags().Set (eLaunchFlagDebug); - m_process_launch_error = Host::LaunchProcess (m_process_launch_info); +#endif + m_process_launch_error = LaunchProcess (); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); @@ -718,7 +843,7 @@ GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet) return SendErrorResponse (8); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet) { lldb::pid_t pid = m_process_launch_info.GetProcessID(); @@ -762,11 +887,30 @@ GDBRemoteCommunicationServer::ReapDebugserverProcess (void *callback_baton, } bool +GDBRemoteCommunicationServer::DebuggedProcessReaped (lldb::pid_t pid) +{ + // reap a process that we were debugging (but not debugserver) + Mutex::Locker locker (m_spawned_pids_mutex); + return m_spawned_pids.erase(pid) > 0; +} + +bool +GDBRemoteCommunicationServer::ReapDebuggedProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, // Zero for no signal + int status) // Exit value of process if signal is zero +{ + GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer *)callback_baton; + server->DebuggedProcessReaped (pid); + return true; +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) { #ifdef _WIN32 - // No unix sockets on windows - return false; + return SendErrorResponse(9); #else // Spawn a local debugserver as a platform so we can then attach or launch // a process... @@ -775,7 +919,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote { // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; - char connect_url[PATH_MAX]; Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp @@ -796,45 +939,23 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; - const char *unix_socket_name = NULL; - char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; - - if (port == 0) - { - if (::mkstemp (unix_socket_name_buf) == 0) - { - unix_socket_name = unix_socket_name_buf; - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); - accept_thread = Host::ThreadCreate (unix_socket_name, - AcceptPortFromInferior, - connect_url, - &error); - } - else - { - error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); - } - } if (error.Success()) { // Spawn a debugserver and try to get the port it listens to. ProcessLaunchInfo debugserver_launch_info; - StreamString host_and_port; if (hostname.empty()) hostname = "localhost"; - host_and_port.Printf("%s:%u", hostname.c_str(), port); - const char *host_and_port_cstr = host_and_port.GetString().c_str(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) - log->Printf("Launching debugserver with: %s...\n", host_and_port_cstr); + log->Printf("Launching debugserver with: %s:%u...\n", hostname.c_str(), port); debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - error = StartDebugserverProcess (host_and_port_cstr, - unix_socket_name, - debugserver_launch_info); + error = StartDebugserverProcess (hostname.empty() ? NULL : hostname.c_str(), + port, + debugserver_launch_info, + port); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -854,45 +975,17 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote if (error.Success()) { - bool success = false; + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < sizeof(response)); + PacketResult packet_result = SendPacketNoLock (response, response_len); - if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) - { - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) - { - if (accept_thread_result) - { - port = (intptr_t)accept_thread_result; - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - } - } - } - else - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - - } - Host::Unlink (unix_socket_name); - - if (!success) + if (packet_result != PacketResult::Success) { if (debugserver_pid != LLDB_INVALID_PROCESS_ID) ::kill (debugserver_pid, SIGINT); } - return success; - } - else if (accept_thread) - { - Host::Unlink (unix_socket_name); + return packet_result; } } } @@ -901,59 +994,124 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote } bool -GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +GDBRemoteCommunicationServer::KillSpawnedProcess (lldb::pid_t pid) { - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - if (m_is_platform) + // make sure we know about this process { - packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return false; + } - lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); + // first try a SIGTERM (standard kill) + Host::Kill (pid, SIGTERM); - // Scope for locker + // check if that worked + for (size_t i=0; i<10; ++i) + { { Mutex::Locker locker (m_spawned_pids_mutex); if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendErrorResponse (10); + { + // it is now killed + return true; + } } - Host::Kill (pid, SIGTERM); + usleep (10000); + } + + // check one more time after the final usleep + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + + // the launched process still lives. Now try killling it again, + // this time with an unblockable signal. + Host::Kill (pid, SIGKILL); - for (size_t i=0; i<10; ++i) + for (size_t i=0; i<10; ++i) + { { - // Scope for locker + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); + // it is now killed + return true; } - usleep (10000); } + usleep (10000); + } + + // check one more time after the final usleep + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) + return true; + } + + // no luck - the process still lives + return false; +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) +{ + packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); + + lldb::pid_t pid = packet.GetU64(LLDB_INVALID_PROCESS_ID); - // Scope for locker + // verify that we know anything about this pid. + // Scope for locker + { + Mutex::Locker locker (m_spawned_pids_mutex); + if (m_spawned_pids.find(pid) == m_spawned_pids.end()) { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); + // not a pid we know about + return SendErrorResponse (10); } - Host::Kill (pid, SIGKILL); + } + + // go ahead and attempt to kill the spawned process + if (KillSpawnedProcess (pid)) + return SendOKResponse (); + else + return SendErrorResponse (11); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::Handle_k (StringExtractorGDBRemote &packet) +{ + // ignore for now if we're lldb_platform + if (m_is_platform) + return SendUnimplementedResponse (packet.GetStringRef().c_str()); - for (size_t i=0; i<10; ++i) + // shutdown all spawned processes + std::set<lldb::pid_t> spawned_pids_copy; + + // copy pids + { + Mutex::Locker locker (m_spawned_pids_mutex); + spawned_pids_copy.insert (m_spawned_pids.begin (), m_spawned_pids.end ()); + } + + // nuke the spawned processes + for (auto it = spawned_pids_copy.begin (); it != spawned_pids_copy.end (); ++it) + { + lldb::pid_t spawned_pid = *it; + if (!KillSpawnedProcess (spawned_pid)) { - // Scope for locker - { - Mutex::Locker locker (m_spawned_pids_mutex); - if (m_spawned_pids.find(pid) == m_spawned_pids.end()) - return SendOKResponse(); - } - usleep (10000); + fprintf (stderr, "%s: failed to kill spawned pid %" PRIu64 ", ignoring.\n", __FUNCTION__, spawned_pid); } } - return SendErrorResponse (11); + + // TODO figure out how to shut down gracefully at this point + return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) { if (m_process_launch_error.Success()) @@ -964,7 +1122,7 @@ GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &p return SendPacketNoLock (response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QEnvironment:")); @@ -977,7 +1135,7 @@ GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &pa return SendErrorResponse (12); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QLaunchArch:")); @@ -992,7 +1150,7 @@ GDBRemoteCommunicationServer::Handle_QLaunchArch (StringExtractorGDBRemote &pack return SendErrorResponse(13); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetDisableASLR:")); @@ -1003,7 +1161,7 @@ GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote & return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetWorkingDir:")); @@ -1027,7 +1185,7 @@ GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &p return SendOKResponse (); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) { StreamString response; @@ -1043,8 +1201,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p else { response.PutBytesAsRawHex8(cwd, strlen(cwd)); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } } else @@ -1053,8 +1210,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p if (working_dir && working_dir[0]) { response.PutBytesAsRawHex8(working_dir, strlen(working_dir)); - SendPacketNoLock(response.GetData(), response.GetSize()); - return true; + return SendPacketNoLock(response.GetData(), response.GetSize()); } else { @@ -1063,7 +1219,7 @@ GDBRemoteCommunicationServer::Handle_qGetWorkingDir (StringExtractorGDBRemote &p } } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); @@ -1080,7 +1236,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet return SendErrorResponse (15); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDOUT:")); @@ -1097,7 +1253,7 @@ GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packe return SendErrorResponse (16); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDERR:")); @@ -1114,16 +1270,16 @@ GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packe return SendErrorResponse (17); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { // Send response first before changing m_send_acks to we ack this packet - SendOKResponse (); + PacketResult packet_result = SendOKResponse (); m_send_acks = false; - return true; + return packet_result; } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_mkdir:")); @@ -1141,7 +1297,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_mkdir (StringExtractorGDBRemote & return SendErrorResponse(20); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_chmod:")); @@ -1160,7 +1316,7 @@ GDBRemoteCommunicationServer::Handle_qPlatform_chmod (StringExtractorGDBRemote & return SendErrorResponse(19); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:open:")); @@ -1176,7 +1332,6 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe mode_t mode = packet.GetHexMaxU32(false, 0600); Error error; int fd = ::open (path.c_str(), flags, mode); - printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>"); const int save_errno = fd == -1 ? errno : 0; StreamString response; response.PutChar('F'); @@ -1190,7 +1345,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Open (StringExtractorGDBRemote &packe return SendErrorResponse(18); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:close:")); @@ -1215,7 +1370,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Close (StringExtractorGDBRemote &pack return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &packet) { #ifdef _WIN32 @@ -1257,7 +1412,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pRead (StringExtractorGDBRemote &pack #endif } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) { #ifdef _WIN32 @@ -1294,7 +1449,7 @@ GDBRemoteCommunicationServer::Handle_vFile_pWrite (StringExtractorGDBRemote &pac #endif } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:size:")); @@ -1316,7 +1471,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Size (StringExtractorGDBRemote &packe return SendErrorResponse(22); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:mode:")); @@ -1335,7 +1490,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Mode (StringExtractorGDBRemote &packe return SendErrorResponse(23); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:exists:")); @@ -1356,7 +1511,7 @@ GDBRemoteCommunicationServer::Handle_vFile_Exists (StringExtractorGDBRemote &pac return SendErrorResponse(24); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:symlink:")); @@ -1370,7 +1525,7 @@ GDBRemoteCommunicationServer::Handle_vFile_symlink (StringExtractorGDBRemote &pa return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:unlink:")); @@ -1382,7 +1537,7 @@ GDBRemoteCommunicationServer::Handle_vFile_unlink (StringExtractorGDBRemote &pac return SendPacketNoLock(response.GetData(), response.GetSize()); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_shell:")); @@ -1424,13 +1579,13 @@ GDBRemoteCommunicationServer::Handle_qPlatform_shell (StringExtractorGDBRemote & return SendErrorResponse(24); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { return SendUnimplementedResponse("GDBRemoteCommunicationServer::Handle_vFile_Stat() unimplemented"); } -bool +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:MD5:")); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index 721ea50..913c6b6 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -37,6 +37,9 @@ public: //------------------------------------------------------------------ GDBRemoteCommunicationServer(bool is_platform); + GDBRemoteCommunicationServer(bool is_platform, + const lldb::PlatformSP& platform_sp); + virtual ~GDBRemoteCommunicationServer(); @@ -138,7 +141,55 @@ public: m_port_offset = port_offset; } + //------------------------------------------------------------------ + /// Specify the program to launch and its arguments. + /// + /// The LaunchProcess () command can be executed to do the lauching. + /// + /// @param[in] args + /// The command line to launch. + /// + /// @param[in] argc + /// The number of elements in the args array of cstring pointers. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + lldb_private::Error + SetLaunchArguments (const char *const args[], int argc); + + //------------------------------------------------------------------ + /// Specify the launch flags for the process. + /// + /// The LaunchProcess () command can be executed to do the lauching. + /// + /// @param[in] launch_flags + /// The launch flags to use when launching this process. + /// + /// @return + /// An Error object indicating the success or failure of making + /// the setting. + //------------------------------------------------------------------ + lldb_private::Error + SetLaunchFlags (unsigned int launch_flags); + + //------------------------------------------------------------------ + /// Launch a process with the current launch settings. + /// + /// This method supports running an lldb-gdbserver or similar + /// server in a situation where the startup code has been provided + /// with all the information for a child process to be launched. + /// + /// @return + /// An Error object indicating the success or failure of the + /// launch. + //------------------------------------------------------------------ + lldb_private::Error + LaunchProcess (); + protected: + lldb::PlatformSP m_platform_sp; lldb::thread_t m_async_thread; lldb_private::ProcessLaunchInfo m_process_launch_info; lldb_private::Error m_process_launch_error; @@ -148,120 +199,123 @@ protected: uint32_t m_proc_infos_index; PortMap m_port_map; uint16_t m_port_offset; - - size_t + + PacketResult SendUnimplementedResponse (const char *packet); - size_t + PacketResult SendErrorResponse (uint8_t error); - size_t + PacketResult SendOKResponse (); - bool + PacketResult Handle_A (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qLaunchSuccess (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qHostInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); - bool + PacketResult + Handle_k (StringExtractorGDBRemote &packet); + + PacketResult Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qPlatform_chmod (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qProcessInfoPID (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qfProcessInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qsProcessInfo (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qC (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qUserName (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qGroupName (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qSpeedTest (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QEnvironment (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QLaunchArch (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetDisableASLR (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetWorkingDir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qGetWorkingDir (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QStartNoAckMode (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDIN (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDOUT (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_QSetSTDERR (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Open (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Close (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_pRead (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_pWrite (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Size (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Mode (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Exists (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_symlink (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_unlink (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_Stat (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_vFile_MD5 (StringExtractorGDBRemote &packet); - bool + PacketResult Handle_qPlatform_shell (StringExtractorGDBRemote &packet); private: @@ -275,6 +329,19 @@ private: int signal, int status); + bool + DebuggedProcessReaped (lldb::pid_t pid); + + static bool + ReapDebuggedProcess (void *callback_baton, + lldb::pid_t pid, + bool exited, + int signal, + int status); + + bool + KillSpawnedProcess (lldb::pid_t pid); + //------------------------------------------------------------------ // For GDBRemoteCommunicationServer only //------------------------------------------------------------------ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index c291df7..73b9b3e 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -275,7 +275,7 @@ GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -298,7 +298,7 @@ GDBRemoteRegisterContext::SyncThreadState(Process *process) if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) InvalidateAllRegisters(); @@ -363,7 +363,7 @@ GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo * if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { SetAllRegisterValid (false); if (response.IsOKResponse()) @@ -519,7 +519,7 @@ GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); - if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsErrorResponse()) return false; @@ -591,7 +591,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (gdb_comm.SendPacketAndWaitForResponse (G_packet, G_packet_len, response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -660,7 +660,7 @@ GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, - false)) + false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) ++num_restored; diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 3a62aa1..326efd4 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -34,7 +34,6 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" @@ -94,7 +93,7 @@ using namespace lldb_private; namespace { - + static PropertyDefinition g_properties[] = { @@ -186,7 +185,7 @@ get_random_port () if (!rand_initialized) { time_t seed = time(NULL); - + rand_initialized = true; srand(seed); } @@ -385,7 +384,7 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) @@ -536,6 +535,10 @@ ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } + else + { + break; // ensure exit before reg_num is incremented + } } else { @@ -644,13 +647,20 @@ ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) // We have a valid process SetID (pid); GetThreadList(); - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) { - if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture - m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + if (!m_target.GetArchitecture().IsValid()) + { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + { + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + else + { + m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } - const StateType state = SetThreadStopInfo (m_last_stop_packet); if (state == eStateStopped) { @@ -689,7 +699,7 @@ ProcessGDBRemote::WillLaunchOrAttach () // Process Control //---------------------------------------------------------------------- Error -ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_info) +ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) { Error error; @@ -727,23 +737,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - error = StartDebugserverProcess (host_port, launch_info); - if (error.Fail()) - { - if (log) - log->Printf("failed to start debugserver process: %s", error.AsCString()); - return error; - } - - error = ConnectToDebugserver (connect_url); + error = LaunchAndConnectToDebugserver (launch_info); } if (error.Success()) @@ -847,10 +844,18 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ return error; } - if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false)) + if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false) == GDBRemoteCommunication::PacketResult::Success) { - if (!m_target.GetArchitecture().IsValid()) { // Make sure we have an architecture - m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + if (!m_target.GetArchitecture().IsValid()) + { + if (m_gdb_comm.GetProcessArchitecture().IsValid()) + { + m_target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); + } + else + { + m_target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); + } } SetPrivateState (SetThreadStopInfo (m_last_stop_packet)); @@ -885,31 +890,35 @@ Error ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) { Error error; - // Sleep and wait a bit for debugserver to start to listen... - std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) + // Only connect if we have a valid connect URL + + if (connect_url && connect_url[0]) { - const uint32_t max_retry_count = 50; - uint32_t retry_count = 0; - while (!m_gdb_comm.IsConnected()) + std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); + if (conn_ap.get()) { - if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) + const uint32_t max_retry_count = 50; + uint32_t retry_count = 0; + while (!m_gdb_comm.IsConnected()) { - m_gdb_comm.SetConnection (conn_ap.release()); - break; - } - else if (error.WasInterrupted()) - { - // If we were interrupted, don't keep retrying. - break; - } - - retry_count++; - - if (retry_count >= max_retry_count) - break; + if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) + { + m_gdb_comm.SetConnection (conn_ap.release()); + break; + } + else if (error.WasInterrupted()) + { + // If we were interrupted, don't keep retrying. + break; + } + + retry_count++; + + if (retry_count >= max_retry_count) + break; - usleep (100000); + usleep (100000); + } } } @@ -1039,12 +1048,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - - error = StartDebugserverProcess (host_port, attach_info); + error = LaunchAndConnectToDebugserver (attach_info); if (error.Fail()) { @@ -1054,10 +1058,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) @@ -1071,29 +1071,8 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process return error; } -size_t -ProcessGDBRemote::AttachInputReaderCallback -( - void *baton, - InputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - if (notification == eInputReaderGotToken) - { - ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton; - if (gdb_process->m_waiting_for_attach) - gdb_process->m_waiting_for_attach = false; - reader->SetIsDone(true); - return 1; - } - return 0; -} - Error -ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info) +ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) { Error error; // Clear out and clean up from any current state @@ -1104,12 +1083,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); + error = LaunchAndConnectToDebugserver (attach_info); - error = StartDebugserverProcess (host_port, attach_info); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -1118,17 +1093,13 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) { StreamString packet; - if (wait_for_launch) + if (attach_info.GetWaitForLaunch()) { if (!m_gdb_comm.GetVAttachOrWaitSupported()) { @@ -1198,7 +1169,11 @@ ProcessGDBRemote::DoResume () bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport ()) { - if (m_continue_c_tids.size() == num_threads) + if (m_continue_c_tids.size() == num_threads || + (m_continue_c_tids.empty() && + m_continue_C_tids.empty() && + m_continue_s_tids.empty() && + m_continue_S_tids.empty())) { // All threads are continuing, just send a "c" packet continue_packet.PutCString ("c"); @@ -1669,6 +1644,21 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) } } + // If the response is old style 'S' packet which does not provide us with thread information + // then update the thread list and choose the first one. + if (!thread_sp) + { + UpdateThreadIDList (); + + if (!m_thread_ids.empty ()) + { + Mutex::Locker locker (m_thread_list_real.GetMutex ()); + thread_sp = m_thread_list_real.FindThreadByProtocolID (m_thread_ids.front (), false); + if (thread_sp) + gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get ()); + } + } + if (thread_sp) { // Clear the stop info just in case we don't set it to anything @@ -1744,7 +1734,7 @@ ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) } } - if (signo && did_exec == false) + if (!handled && signo && did_exec == false) { if (signo == SIGTRAP) { @@ -2027,12 +2017,30 @@ ProcessGDBRemote::DoDestroy () bool send_async = true; const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3); - if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async)) + if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success) { char packet_cmd = response.GetChar(0); if (packet_cmd == 'W' || packet_cmd == 'X') { +#if defined(__APPLE__) + // For Native processes on Mac OS X, we launch through the Host Platform, then hand the process off + // to debugserver, which becomes the parent process through "PT_ATTACH". Then when we go to kill + // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we call waitpid which returns + // with no error and the correct status. But amusingly enough that doesn't seem to actually reap + // the process, but instead it is left around as a Zombie. Probably the kernel is in the process of + // switching ownership back to lldb which was the original parent, and gets confused in the handoff. + // Anyway, so call waitpid here to finally reap it. + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && platform_sp->IsHost()) + { + int status; + ::pid_t reap_pid; + reap_pid = waitpid (GetID(), &status, WNOHANG); + if (log) + log->Printf ("Reaped pid: %d, status: %d.\n", reap_pid, status); + } +#endif SetLastStopPacket (response); ClearThreadIDList (); exit_status = response.GetHexU8(); @@ -2129,7 +2137,7 @@ ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &erro const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { @@ -2165,7 +2173,7 @@ ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Erro packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder()); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true)) + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { @@ -2303,70 +2311,106 @@ Error ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) { Error error; - assert (bp_site != NULL); + assert(bp_site != NULL); - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); + // Get logging info + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); user_id_t site_id = bp_site->GetID(); + + // Get the breakpoint address const addr_t addr = bp_site->GetLoadAddress(); + + // Log that a breakpoint was requested if (log) - log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr); + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr); + // Breakpoint already exists and is enabled if (bp_site->IsEnabled()) { if (log) - log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr); + log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr); return error; } - else + + // Get the software breakpoint trap opcode size + const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); + + // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type + // is supported by the remote stub. These are set to true by default, and later set to false + // only after we receive an unimplemented response when sending a breakpoint packet. This means + // initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will + // attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which + // indicates if the user specifically asked for hardware breakpoints. If true then we will + // skip over software breakpoints. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired())) { - const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); + // Try to send off a software breakpoint packet ($Z0) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0) + { + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eExternal); + return error; + } - if (bp_site->HardwareRequired()) + // SendGDBStoppointTypePacket() will return an error if it was unable to set this + // breakpoint. We need to differentiate between a error specific to placing this breakpoint + // or if we have learned that this breakpoint type is unsupported. To do this, we + // must test the support boolean for this breakpoint type to see if it now indicates that + // this breakpoint type is unsupported. If they are still supported then we should return + // with the error code. If they are now unsupported, then we would like to fall through + // and try another form of breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) + return error; + + // We reach here when software breakpoints have been found to be unsupported. For future + // calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is + // known not to be supported. + if (log) + log->Printf("Software breakpoints are unsupported"); + + // So we will fall through and try a hardware breakpoint + } + + // The process of setting a hardware breakpoint is much the same as above. We check the + // supported boolean for this breakpoint type, and if it is thought to be supported then we + // will try to set this breakpoint with a hardware breakpoint. + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) + { + // Try to send off a hardware breakpoint packet ($Z1) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0) { - // Try and set hardware breakpoint, and if that fails, fall through - // and set a software breakpoint? - if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware)) - { - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0) - { - bp_site->SetEnabled(true); - bp_site->SetType (BreakpointSite::eHardware); - } - else - { - error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)"); - } - } - else - { - error.SetErrorString("hardware breakpoints are not supported"); - } + // The breakpoint was placed successfully + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eHardware); return error; } - else if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware)) + + // Check if the error was something other then an unsupported breakpoint type + if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0) - { - bp_site->SetEnabled(true); - bp_site->SetType (BreakpointSite::eExternal); - return error; - } + // Unable to set this hardware breakpoint + error.SetErrorString("failed to set hardware breakpoint (hardware breakpoint resources might be exhausted or unavailable)"); + return error; } - return EnableSoftwareBreakpoint (bp_site); + // We will reach here when the stub gives an unsported response to a hardware breakpoint + if (log) + log->Printf("Hardware breakpoints are unsupported"); + + // Finally we will falling through to a #trap style breakpoint } - if (log) + // Don't fall through when hardware breakpoints were specifically requested + if (bp_site->HardwareRequired()) { - const char *err_string = error.AsCString(); - log->Printf ("ProcessGDBRemote::EnableBreakpointSite () error for breakpoint at 0x%8.8" PRIx64 ": %s", - bp_site->GetLoadAddress(), - err_string ? err_string : "NULL"); + error.SetErrorString("hardware breakpoints are not supported"); + return error; } - // We shouldn't reach here on a successful breakpoint enable... - if (error.Success()) - error.SetErrorToGenericError(); - return error; + + // As a last resort we want to place a manual breakpoint. An instruction + // is placed into the process memory using memory write packets. + return EnableSoftwareBreakpoint(bp_site); } Error @@ -2392,7 +2436,7 @@ ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) break; case BreakpointSite::eHardware: - if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size)) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size)) error.SetErrorToGenericError(); break; @@ -2547,14 +2591,7 @@ ProcessGDBRemote::DoSignal (int signo) } Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url) -{ - ProcessLaunchInfo launch_info; - return StartDebugserverProcess(debugserver_url, launch_info); -} - -Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") +ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) { Error error; if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) @@ -2563,141 +2600,55 @@ ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const Pr static FileSpec g_debugserver_file_spec; ProcessLaunchInfo debugserver_launch_info; - char debugserver_path[PATH_MAX]; - FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile(); - - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. - const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); - if (env_debugserver_path) - debugserver_file_spec.SetFile (env_debugserver_path, false); - else - debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); - if (!debugserver_exists) - { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) - { - debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); - if (debugserver_exists) - { - g_debugserver_file_spec = debugserver_file_spec; - } - else - { - g_debugserver_file_spec.Clear(); - debugserver_file_spec.Clear(); - } - } - } + debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); + debugserver_launch_info.SetUserID(process_info.GetUserID()); - if (debugserver_exists) - { - debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); - - m_stdio_communication.Clear(); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - Args &debugserver_args = debugserver_launch_info.GetArguments(); - char arg_cstr[PATH_MAX]; - - // Start args with "debugserver /file/path -r --" - debugserver_args.AppendArgument(debugserver_path); - debugserver_args.AppendArgument(debugserver_url); - // use native registers, not the GDB registers - debugserver_args.AppendArgument("--native-regs"); - // make debugserver run in its own session so signals generated by - // special terminal key sequences (^C) don't affect debugserver - debugserver_args.AppendArgument("--setsid"); - - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); - if (env_debugserver_log_file) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); - debugserver_args.AppendArgument(arg_cstr); - } - - const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); - if (env_debugserver_log_flags) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); - debugserver_args.AppendArgument(arg_cstr); - } -// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); -// debugserver_args.AppendArgument("--log-flags=0x802e0e"); - - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) - { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); - } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); - } - else if (attach_name && attach_name[0]) - { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); - } +#if defined (__APPLE__) && defined (__arm__) + // On iOS, still do a local connection using a random port + const char *hostname = "localhost"; + uint16_t port = get_random_port (); +#else + // Set hostname being NULL to do the reverse connect where debugserver + // will bind to port zero and it will communicate back to us the port + // that we will connect to + const char *hostname = NULL; + uint16_t port = 0; #endif - - ProcessLaunchInfo::FileAction file_action; - - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. - file_action.Close (STDIN_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDOUT_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDERR_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - - if (log) - { - StreamString strm; - debugserver_args.Dump (&strm); - log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); - } - debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); - debugserver_launch_info.SetUserID(process_info.GetUserID()); + error = m_gdb_comm.StartDebugserverProcess (hostname, + port, + debugserver_launch_info, + port); - error = Host::LaunchProcess(debugserver_launch_info); + if (error.Success ()) + m_debugserver_pid = debugserver_launch_info.GetProcessID(); + else + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - if (error.Success ()) - m_debugserver_pid = debugserver_launch_info.GetProcessID(); - else - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; + if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) + StartAsyncThread (); + + if (error.Fail()) + { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - if (error.Fail() || log) - error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path); + if (log) + log->Printf("failed to start debugserver process: %s", error.AsCString()); + return error; + } + + if (m_gdb_comm.IsConnected()) + { + // Finish the connection process by doing the handshake without connecting (send NULL URL) + ConnectToDebugserver (NULL); } else { - error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME); + StreamString connect_url; + connect_url.Printf("connect://%s:%u", hostname, port); + error = ConnectToDebugserver (connect_url.GetString().c_str()); } - if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) - StartAsyncThread (); } return error; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 3524407..9331775 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -21,7 +21,6 @@ #include "lldb/Core/Broadcaster.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/Error.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/StringList.h" #include "lldb/Core/ThreadSafeValue.h" @@ -86,7 +85,7 @@ public: virtual lldb_private::Error DoLaunch (lldb_private::Module *exe_module, - const lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info); virtual void DidLaunch (); @@ -111,7 +110,6 @@ public: virtual lldb_private::Error DoAttachToProcessWithName (const char *process_name, - bool wait_for_launch, const lldb_private::ProcessAttachInfo &attach_info); virtual void @@ -284,10 +282,7 @@ protected: lldb_private::ThreadList &new_thread_list); lldb_private::Error - StartDebugserverProcess (const char *debugserver_url); - - lldb_private::Error - StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info); + LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info); void KillDebugserverProcess (); @@ -382,13 +377,6 @@ protected: GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr, std::string &dispatch_queue_name); - static size_t - AttachInputReaderCallback (void *baton, - lldb_private::InputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - lldb_private::DynamicLoader * GetDynamicLoader (); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 4e475c8..fb524de 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -19,6 +19,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" +#include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" #include "lldb/Target/Unwind.h" @@ -74,10 +75,10 @@ ThreadGDBRemote::GetQueueName () ProcessSP process_sp (GetProcess()); if (process_sp) { - PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); - if (platform_sp) + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) { - m_dispatch_queue_name = platform_sp->GetQueueNameForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + m_dispatch_queue_name = runtime->GetQueueNameFromThreadQAddress (m_thread_dispatch_qaddr); } if (m_dispatch_queue_name.length() > 0) { @@ -96,10 +97,10 @@ ThreadGDBRemote::GetQueueID () ProcessSP process_sp (GetProcess()); if (process_sp) { - PlatformSP platform_sp (process_sp->GetTarget().GetPlatform()); - if (platform_sp) + SystemRuntime *runtime = process_sp->GetSystemRuntime (); + if (runtime) { - return platform_sp->GetQueueIDForThreadQAddress (process_sp.get(), m_thread_dispatch_qaddr); + return runtime->GetQueueIDFromThreadQAddress (m_thread_dispatch_qaddr); } } } diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index fce995e..d6c580c 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -53,7 +53,7 @@ public: bool ExtractValue(const lldb_private::DWARFDataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu); - bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; } + bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (const uint8_t*)m_value.value.cstr; } const uint8_t* BlockData() const; uint64_t Reference(const DWARFCompileUnit* cu) const; uint64_t Reference (dw_offset_t offset) const; diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 09b5053..c1aecfe 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1644,6 +1644,13 @@ struct BitfieldInfo { } + void + Clear() + { + bit_size = LLDB_INVALID_ADDRESS; + bit_offset = LLDB_INVALID_ADDRESS; + } + bool IsValid () { return (bit_size != LLDB_INVALID_ADDRESS) && @@ -1915,12 +1922,14 @@ SymbolFileDWARF::ParseChildMembers accessibility = default_accessibility; member_accessibilities.push_back(accessibility); - BitfieldInfo this_field_info; - - this_field_info.bit_size = bit_size; - - if (member_byte_offset != UINT32_MAX || bit_size != 0) + uint64_t field_bit_offset = (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); + if (bit_size > 0) { + + BitfieldInfo this_field_info; + this_field_info.bit_offset = field_bit_offset; + this_field_info.bit_size = bit_size; + ///////////////////////////////////////////////////////////// // How to locate a field given the DWARF debug information // @@ -1937,10 +1946,9 @@ SymbolFileDWARF::ParseChildMembers // AT_bit_size indicates the size of the field in bits. ///////////////////////////////////////////////////////////// - this_field_info.bit_offset = 0; - - this_field_info.bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); - + if (byte_size == 0) + byte_size = member_type->GetByteSize(); + if (GetObjectFile()->GetByteOrder() == eByteOrderLittle) { this_field_info.bit_offset += byte_size * 8; @@ -1950,30 +1958,30 @@ SymbolFileDWARF::ParseChildMembers { this_field_info.bit_offset += bit_offset; } - } + + // Update the field bit offset we will report for layout + field_bit_offset = this_field_info.bit_offset; - // If the member to be emitted did not start on a character boundary and there is - // empty space between the last field and this one, then we need to emit an - // anonymous member filling up the space up to its start. There are three cases - // here: - // - // 1 If the previous member ended on a character boundary, then we can emit an - // anonymous member starting at the most recent character boundary. - // - // 2 If the previous member did not end on a character boundary and the distance - // from the end of the previous member to the current member is less than a - // word width, then we can emit an anonymous member starting right after the - // previous member and right before this member. - // - // 3 If the previous member did not end on a character boundary and the distance - // from the end of the previous member to the current member is greater than - // or equal a word width, then we act as in Case 1. - - const uint64_t character_width = 8; - const uint64_t word_width = 32; - - if (this_field_info.IsValid()) - { + // If the member to be emitted did not start on a character boundary and there is + // empty space between the last field and this one, then we need to emit an + // anonymous member filling up the space up to its start. There are three cases + // here: + // + // 1 If the previous member ended on a character boundary, then we can emit an + // anonymous member starting at the most recent character boundary. + // + // 2 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is less than a + // word width, then we can emit an anonymous member starting right after the + // previous member and right before this member. + // + // 3 If the previous member did not end on a character boundary and the distance + // from the end of the previous member to the current member is greater than + // or equal a word width, then we act as in Case 1. + + const uint64_t character_width = 8; + const uint64_t word_width = 32; + // Objective-C has invalid DW_AT_bit_offset values in older versions // of clang, so we have to be careful and only insert unnammed bitfields // if we have a new enough clang. @@ -2019,6 +2027,11 @@ SymbolFileDWARF::ParseChildMembers layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset)); } } + last_field_info = this_field_info; + } + else + { + last_field_info.Clear(); } ClangASTType member_clang_type = member_type->GetClangLayoutType(); @@ -2062,11 +2075,8 @@ SymbolFileDWARF::ParseChildMembers GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset())); - if (this_field_info.IsValid()) - { - layout_info.field_offsets.insert(std::make_pair(field_decl, this_field_info.bit_offset)); - last_field_info = this_field_info; - } + layout_info.field_offsets.insert(std::make_pair(field_decl, field_bit_offset)); + } else { @@ -2546,6 +2556,37 @@ SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) if (!base_classes.empty()) { + // Make sure all base classes refer to complete types and not + // forward declarations. If we don't do this, clang will crash + // with an assertion in the call to clang_type.SetBaseClassesForClassType() + bool base_class_error = false; + for (auto &base_class : base_classes) + { + clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); + if (type_source_info) + { + ClangASTType base_class_type (GetClangASTContext().getASTContext(), type_source_info->getType()); + if (base_class_type.GetCompleteType() == false) + { + if (!base_class_error) + { + GetObjectFile()->GetModule()->ReportError ("DWARF DIE at 0x%8.8x for class '%s' has a base class '%s' that is a forward declaration, not a complete definition.\nPlease file a bug against the compiler and include the preprocessed output for %s", + die->GetOffset(), + die->GetName(this, dwarf_cu), + base_class_type.GetTypeName().GetCString(), + sc.comp_unit ? sc.comp_unit->GetPath().c_str() : "the source file"); + } + // We have no choice other than to pretend that the base class + // is complete. If we don't do this, clang will crash when we + // call setBases() inside of "clang_type.SetBaseClassesForClassType()" + // below. Since we provide layout assistance, all ivars in this + // class and other classe will be fine, this is the best we can do + // short of crashing. + base_class_type.StartTagDeclarationDefinition (); + base_class_type.CompleteTagDeclarationDefinition (); + } + } + } clang_type.SetBaseClassesForClassType (&base_classes.front(), base_classes.size()); @@ -4158,6 +4199,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, const DWARFDebugInfoEntry *parent_die, bool skip_artificial, bool &is_static, + bool &is_variadic, TypeList* type_list, std::vector<ClangASTType>& function_param_types, std::vector<clang::ParmVarDecl*>& function_param_decls, @@ -4309,6 +4351,10 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, } break; + case DW_TAG_unspecified_parameters: + is_variadic = true; + break; + case DW_TAG_template_type_parameter: case DW_TAG_template_value_parameter: ParseTemplateDIE (dwarf_cu, die,template_param_infos); @@ -6222,6 +6268,11 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, case DW_TAG_subprogram: case DW_TAG_member: case DW_TAG_APPLE_property: + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_enumeration_type: + case DW_TAG_typedef: + case DW_TAG_union_type: child_die = NULL; is_forward_declaration = false; break; @@ -6543,6 +6594,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, die, skip_artificial, is_static, + is_variadic, type_list, function_param_types, function_param_decls, diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 5588657..8dac209 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -364,6 +364,7 @@ protected: const DWARFDebugInfoEntry *parent_die, bool skip_artificial, bool &is_static, + bool &is_variadic, lldb_private::TypeList* type_list, std::vector<lldb_private::ClangASTType>& function_args, std::vector<clang::ParmVarDecl*>& function_param_decls, diff --git a/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index 6500aab..a9f8f36 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -9,12 +9,8 @@ #include "SymbolVendorELF.h" -//#include <libxml/parser.h> -// #include <libxml/tree.h> #include <string.h> -// #include <AvailabilityMacros.h> - #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp index 5ba9c6a..4f30ccf 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/ClangASTContext.cpp @@ -1152,12 +1152,18 @@ ClangASTContext::CreateRecordType (DeclContext *decl_ctx, // the CXXRecordDecl class since we often don't know from debug information // if something is struct or a class, so we default to always use the more // complete definition just in case. + + bool is_anonymous = (!name) || (!name[0]); + CXXRecordDecl *decl = CXXRecordDecl::Create (*ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast->Idents.get(name) : NULL); + is_anonymous ? NULL : &ast->Idents.get(name)); + + if (is_anonymous) + decl->setAnonymousStructOrUnion(true); if (decl) { diff --git a/contrib/llvm/tools/lldb/source/Symbol/ClangASTType.cpp b/contrib/llvm/tools/lldb/source/Symbol/ClangASTType.cpp index 0dfabcc..a407801 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/ClangASTType.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/ClangASTType.cpp @@ -38,6 +38,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/ClangExternalASTSourceCommon.h" @@ -1134,7 +1135,7 @@ ClangASTType::GetTypeName () const if (typedef_type) { const TypedefNameDecl *typedef_decl = typedef_type->getDecl(); - type_name = typedef_decl->getQualifiedNameAsString(printing_policy); + type_name = typedef_decl->getQualifiedNameAsString(); } else { diff --git a/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp b/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp index 68b05ad..134dbf5 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/FuncUnwinders.cpp @@ -28,7 +28,7 @@ using namespace lldb_private; FuncUnwinders::FuncUnwinders ( UnwindTable& unwind_table, - UnwindAssembly *assembly_profiler, + const lldb::UnwindAssemblySP& assembly_profiler, AddressRange range ) : m_unwind_table(unwind_table), diff --git a/contrib/llvm/tools/lldb/source/Symbol/Function.cpp b/contrib/llvm/tools/lldb/source/Symbol/Function.cpp index 31334a6..e6d6c00 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/Function.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/Function.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Symbol/Function.h" +#include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" @@ -404,6 +405,43 @@ Function::CalculateSymbolContextFunction () return this; } +lldb::DisassemblerSP +Function::GetInstructions (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache) +{ + ModuleSP module_sp (GetAddressRange().GetBaseAddress().GetModule()); + if (module_sp) + { + const bool prefer_file_cache = false; + return Disassembler::DisassembleRange (module_sp->GetArchitecture(), + NULL, + flavor, + exe_ctx, + GetAddressRange(), + prefer_file_cache); + } + return lldb::DisassemblerSP(); +} + +bool +Function::GetDisassembly (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache, + Stream &strm) +{ + lldb::DisassemblerSP disassembler_sp = GetInstructions (exe_ctx, flavor, prefer_file_cache); + if (disassembler_sp) + { + const bool show_address = true; + const bool show_bytes = false; + disassembler_sp->GetInstructionList().Dump (&strm, show_address, show_bytes, &exe_ctx); + return true; + } + return false; +} + + //Symbol * //Function::CalculateSymbolContextSymbol () //{ diff --git a/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp b/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp index a881b6f..6311a32 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/Symbol.cpp @@ -580,3 +580,40 @@ Symbol::ResolveReExportedSymbol (Target &target) } return NULL; } + + +lldb::DisassemblerSP +Symbol::GetInstructions (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache) +{ + ModuleSP module_sp (m_addr_range.GetBaseAddress().GetModule()); + if (module_sp) + { + const bool prefer_file_cache = false; + return Disassembler::DisassembleRange (module_sp->GetArchitecture(), + NULL, + flavor, + exe_ctx, + m_addr_range, + prefer_file_cache); + } + return lldb::DisassemblerSP(); +} + +bool +Symbol::GetDisassembly (const ExecutionContext &exe_ctx, + const char *flavor, + bool prefer_file_cache, + Stream &strm) +{ + lldb::DisassemblerSP disassembler_sp = GetInstructions (exe_ctx, flavor, prefer_file_cache); + if (disassembler_sp) + { + const bool show_address = true; + const bool show_bytes = false; + disassembler_sp->GetInstructionList().Dump (&strm, show_address, show_bytes, &exe_ctx); + return true; + } + return false; +} diff --git a/contrib/llvm/tools/lldb/source/Symbol/Type.cpp b/contrib/llvm/tools/lldb/source/Symbol/Type.cpp index 32a1d47..073940e 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/Type.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/Type.cpp @@ -1084,6 +1084,16 @@ TypeImpl::GetReferenceType () const } TypeImpl +TypeImpl::GetTypedefedType () const +{ + if (m_dynamic_type.IsValid()) + { + return TypeImpl(m_static_type, m_dynamic_type.GetTypedefedType()); + } + return TypeImpl(m_static_type.GetTypedefedType()); +} + +TypeImpl TypeImpl::GetDereferencedType () const { if (m_dynamic_type.IsValid()) diff --git a/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp index 7276e0a..36fe3b1 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/Variable.cpp @@ -832,10 +832,17 @@ PrivateAutoComplete (StackFrame *frame, VariableList *variable_list = frame->GetVariableList(get_file_globals); + if (!variable_list) + break; + const size_t num_variables = variable_list->GetSize(); for (size_t i=0; i<num_variables; ++i) { Variable *variable = variable_list->GetVariableAtIndex(i).get(); + + if (!variable) + continue; + const char *variable_name = variable->GetName().AsCString(); if (strstr(variable_name, token.c_str()) == variable_name) { diff --git a/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp b/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp index 3451166..75eb870 100644 --- a/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp +++ b/contrib/llvm/tools/lldb/source/Symbol/VariableList.cpp @@ -115,6 +115,32 @@ VariableList::FindVariable(const ConstString& name) return var_sp; } +VariableSP +VariableList::FindVariable (const ConstString& name, lldb::ValueType value_type) +{ + VariableSP var_sp; + iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + { + if ((*pos)->NameMatches(name) && (*pos)->GetScope() == value_type) + { + var_sp = (*pos); + break; + } + } + return var_sp; +} + +size_t +VariableList::AppendVariablesIfUnique(VariableList &var_list) +{ + const size_t initial_size = var_list.GetSize(); + iterator pos, end = m_variables.end(); + for (pos = m_variables.begin(); pos != end; ++pos) + var_list.AddVariableIfUnique(*pos); + return var_list.GetSize() - initial_size; +} + size_t VariableList::AppendVariablesIfUnique (const RegularExpression& regex, VariableList &var_list, size_t& total_matches) { diff --git a/contrib/llvm/tools/lldb/source/Target/ExecutionContext.cpp b/contrib/llvm/tools/lldb/source/Target/ExecutionContext.cpp index 7a8b601..db4025f 100644 --- a/contrib/llvm/tools/lldb/source/Target/ExecutionContext.cpp +++ b/contrib/llvm/tools/lldb/source/Target/ExecutionContext.cpp @@ -154,7 +154,7 @@ ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref) : { } -ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr) : +ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr, bool thread_and_frame_only_if_stopped) : m_target_sp (), m_process_sp (), m_thread_sp (), @@ -164,8 +164,11 @@ ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr) { m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); - m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); - m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); + if (!thread_and_frame_only_if_stopped || (m_process_sp && StateIsStoppedState(m_process_sp->GetState(), true))) + { + m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); + m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); + } } } @@ -824,9 +827,9 @@ ExecutionContextRef::GetFrameSP () const } ExecutionContext -ExecutionContextRef::Lock () const +ExecutionContextRef::Lock (bool thread_and_frame_only_if_stopped) const { - return ExecutionContext(this); + return ExecutionContext(this, thread_and_frame_only_if_stopped); } diff --git a/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp index 2fdc253..a2b7f1d 100644 --- a/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp +++ b/contrib/llvm/tools/lldb/source/Target/LanguageRuntime.cpp @@ -269,7 +269,8 @@ LanguageRuntime::CreateExceptionBreakpoint (Target &target, BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language)); bool hardware = false; - BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware)); + bool resolve_indirect_functions = false; + BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions)); if (is_internal) exc_breakpt_sp->SetBreakpointKind("exception"); diff --git a/contrib/llvm/tools/lldb/source/Target/Platform.cpp b/contrib/llvm/tools/lldb/source/Target/Platform.cpp index 66f9c0e..d6010fb 100644 --- a/contrib/llvm/tools/lldb/source/Target/Platform.cpp +++ b/contrib/llvm/tools/lldb/source/Target/Platform.cpp @@ -81,9 +81,9 @@ Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp) } Error -Platform::GetFile (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) +Platform::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { // Default to the local case local_file = platform_file; @@ -255,7 +255,9 @@ Platform::Platform (bool is_host) : m_rsync_prefix (), m_supports_ssh (false), m_ssh_opts (), - m_ignores_remote_hostname (false) + m_ignores_remote_hostname (false), + m_trap_handlers(), + m_calculated_trap_handlers (false) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); if (log) @@ -1039,6 +1041,8 @@ Platform::DebugProcess (ProcessLaunchInfo &launch_info, process_sp = Attach (attach_info, debugger, target, listener, error); if (process_sp) { + launch_info.SetHijackListener(attach_info.GetHijackListener()); + // Since we attached to the process, it will think it needs to detach // if the process object just goes away without an explicit call to // Process::Kill() or Process::Detach(), so let it know to kill the @@ -1388,3 +1392,15 @@ Platform::GetEnvironment (StringList &environment) environment.Clear(); return false; } + +const std::vector<ConstString> & +Platform::GetTrapHandlerSymbolNames () +{ + if (!m_calculated_trap_handlers) + { + CalculateTrapHandlerSymbolNames(); + m_calculated_trap_handlers = true; + } + return m_trap_handlers; +} + diff --git a/contrib/llvm/tools/lldb/source/Target/Process.cpp b/contrib/llvm/tools/lldb/source/Target/Process.cpp index 1de322a..1256ad3 100644 --- a/contrib/llvm/tools/lldb/source/Target/Process.cpp +++ b/contrib/llvm/tools/lldb/source/Target/Process.cpp @@ -18,14 +18,16 @@ #include "lldb/Core/Event.h" #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/InputReader.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Expression/ClangUserExpression.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Host/Host.h" +#include "lldb/Host/Terminal.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/OperatingSystem.h" @@ -41,6 +43,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanBase.h" +#include "Plugins/Process/Utility/InferiorCallPOSIX.h" #ifndef LLDB_DISABLE_POSIX #include <spawn.h> @@ -1025,6 +1028,8 @@ Process::Process(Target &target, Listener &listener) : m_thread_list (this), m_extended_thread_list (this), m_extended_thread_stop_id (0), + m_queue_list (this), + m_queue_list_stop_id (0), m_notifications (), m_image_tokens (), m_listener (listener), @@ -1048,6 +1053,7 @@ Process::Process(Target &target, Listener &listener) : m_currently_handling_event(false), m_finalize_called(false), m_clear_thread_plans_on_stop (false), + m_force_next_event_delivery(false), m_last_broadcast_state (eStateInvalid), m_destroy_in_process (false), m_can_jit(eCanJITDontKnow) @@ -1151,6 +1157,8 @@ Process::Finalize() m_thread_list_real.Destroy(); m_thread_list.Destroy(); m_extended_thread_list.Destroy(); + m_queue_list.Clear(); + m_queue_list_stop_id = 0; std::vector<Notifications> empty_notifications; m_notifications.swap(empty_notifications); m_image_tokens.clear(); @@ -1235,7 +1243,7 @@ Process::GetNextEvent (EventSP &event_sp) StateType -Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always) +Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener) { // We can't just wait for a "stopped" event, because the stopped event may have restarted the target. // We have to actually check each event, and in the case of a stopped event check the restarted flag @@ -1264,7 +1272,7 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp while (state != eStateInvalid) { EventSP event_sp; - state = WaitForStateChangedEvents (timeout, event_sp); + state = WaitForStateChangedEvents (timeout, event_sp, hijack_listener); if (event_sp_ptr && event_sp) *event_sp_ptr = event_sp; @@ -1274,12 +1282,22 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp case eStateDetached: case eStateExited: case eStateUnloaded: + // We need to toggle the run lock as this won't get done in + // SetPublicState() if the process is hijacked. + if (hijack_listener) + m_public_run_lock.SetStopped(); return state; case eStateStopped: if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) continue; else + { + // We need to toggle the run lock as this won't get done in + // SetPublicState() if the process is hijacked. + if (hijack_listener) + m_public_run_lock.SetStopped(); return state; + } default: continue; } @@ -1292,7 +1310,8 @@ StateType Process::WaitForState ( const TimeValue *timeout, - const StateType *match_states, const uint32_t num_match_states + const StateType *match_states, + const uint32_t num_match_states ) { EventSP event_sp; @@ -1305,7 +1324,7 @@ Process::WaitForState if (state == eStateDetached || state == eStateExited) return state; - state = WaitForStateChangedEvents (timeout, event_sp); + state = WaitForStateChangedEvents (timeout, event_sp, NULL); for (i=0; i<num_match_states; ++i) { @@ -1351,18 +1370,22 @@ Process::RestorePrivateProcessEvents () } StateType -Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp) +Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp, Listener *hijack_listener) { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout); + Listener *listener = hijack_listener; + if (listener == NULL) + listener = &m_listener; + StateType state = eStateInvalid; - if (m_listener.WaitForEventForBroadcasterWithType (timeout, - this, - eBroadcastBitStateChanged | eBroadcastBitInterrupt, - event_sp)) + if (listener->WaitForEventForBroadcasterWithType (timeout, + this, + eBroadcastBitStateChanged | eBroadcastBitInterrupt, + event_sp)) { if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); @@ -1500,6 +1523,7 @@ Process::SetExitStatus (int status, const char *cstr) DidExit (); SetPrivateState (eStateExited); + CancelWatchForSTDIN (true); return true; } @@ -1600,12 +1624,32 @@ Process::UpdateThreadListIfNeeded () // Clear any extended threads that we may have accumulated previously m_extended_thread_list.Clear(); m_extended_thread_stop_id = GetLastNaturalStopID (); + + m_queue_list.Clear(); + m_queue_list_stop_id = GetLastNaturalStopID (); } } } } } +void +Process::UpdateQueueListIfNeeded () +{ + if (m_system_runtime_ap.get()) + { + if (m_queue_list.GetSize() == 0 || m_queue_list_stop_id != GetLastNaturalStopID()) + { + const StateType state = GetPrivateState(); + if (StateIsStoppedState (state, true)) + { + m_system_runtime_ap->PopulateQueueList (m_queue_list); + m_queue_list_stop_id = GetLastNaturalStopID(); + } + } + } +} + ThreadSP Process::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context) { @@ -2084,7 +2128,60 @@ Process::EnableBreakpointSiteByID (lldb::user_id_t break_id) lldb::break_id_t Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware) { - const addr_t load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + addr_t load_addr = LLDB_INVALID_ADDRESS; + + bool show_error = true; + switch (GetState()) + { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + show_error = false; + break; + + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + show_error = IsAlive(); + break; + } + + // Reset the IsIndirect flag here, in case the location changes from + // pointing to a indirect symbol to a regular symbol. + owner->SetIsIndirect (false); + + if (owner->ShouldResolveIndirectFunctions()) + { + Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) + { + Error error; + load_addr = ResolveIndirectFunction (&symbol->GetAddress(), error); + if (!error.Success() && show_error) + { + m_target.GetDebugger().GetErrorFile()->Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", + symbol->GetAddress().GetLoadAddress(&m_target), + owner->GetBreakpoint().GetID(), + owner->GetID(), + error.AsCString() ? error.AsCString() : "unkown error"); + return LLDB_INVALID_BREAK_ID; + } + Address resolved_address(load_addr); + load_addr = resolved_address.GetOpcodeLoadAddress (&m_target); + owner->SetIsIndirect(true); + } + else + load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + } + else + load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target); + if (load_addr != LLDB_INVALID_ADDRESS) { BreakpointSiteSP bp_site_sp; @@ -2113,36 +2210,14 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw } else { - bool show_error = true; - switch (GetState()) - { - case eStateInvalid: - case eStateUnloaded: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateDetached: - case eStateExited: - show_error = false; - break; - - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - show_error = IsAlive(); - break; - } - if (show_error) { // Report error for setting breakpoint... - m_target.GetDebugger().GetErrorFile().Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - load_addr, - owner->GetBreakpoint().GetID(), - owner->GetID(), - error.AsCString() ? error.AsCString() : "unkown error"); + m_target.GetDebugger().GetErrorFile()->Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", + load_addr, + owner->GetBreakpoint().GetID(), + owner->GetID(), + error.AsCString() ? error.AsCString() : "unkown error"); } } } @@ -3153,7 +3228,7 @@ Process::Attach (ProcessAttachInfo &attach_info) const bool restarted = false; SetPublicState (eStateAttaching, restarted); // Now attach using these arguments. - error = DoAttachToProcessWithName (process_name, wait_for_launch, attach_info); + error = DoAttachToProcessWithName (process_name, attach_info); } else { @@ -3663,8 +3738,6 @@ Process::Destroy () } m_stdio_communication.StopReadThread(); m_stdio_communication.Disconnect(); - if (m_process_input_reader && m_process_input_reader->IsActive()) - m_target.GetDebugger().PopInputReader (m_process_input_reader); if (m_process_input_reader) m_process_input_reader.reset(); @@ -3745,33 +3818,38 @@ Process::ShouldBroadcastEvent (Event *event_ptr) // stopped -> running: Report except when there is one or more no votes // and no yes votes. SynchronouslyNotifyStateChanged (state); - switch (m_last_broadcast_state) + if (m_force_next_event_delivery) + return_value = true; + else { - case eStateRunning: - case eStateStepping: - // We always suppress multiple runnings with no PUBLIC stop in between. - return_value = false; - break; - default: - // TODO: make this work correctly. For now always report - // run if we aren't running so we don't miss any runnning - // events. If I run the lldb/test/thread/a.out file and - // break at main.cpp:58, run and hit the breakpoints on - // multiple threads, then somehow during the stepping over - // of all breakpoints no run gets reported. - - // This is a transition from stop to run. - switch (m_thread_list.ShouldReportRun (event_ptr)) - { - case eVoteYes: - case eVoteNoOpinion: - return_value = true; - break; - case eVoteNo: - return_value = false; - break; - } - break; + switch (m_last_broadcast_state) + { + case eStateRunning: + case eStateStepping: + // We always suppress multiple runnings with no PUBLIC stop in between. + return_value = false; + break; + default: + // TODO: make this work correctly. For now always report + // run if we aren't running so we don't miss any runnning + // events. If I run the lldb/test/thread/a.out file and + // break at main.cpp:58, run and hit the breakpoints on + // multiple threads, then somehow during the stepping over + // of all breakpoints no run gets reported. + + // This is a transition from stop to run. + switch (m_thread_list.ShouldReportRun (event_ptr)) + { + case eVoteYes: + case eVoteNoOpinion: + return_value = true; + break; + case eVoteNo: + return_value = false; + break; + } + break; + } } break; case eStateStopped: @@ -3844,6 +3922,9 @@ Process::ShouldBroadcastEvent (Event *event_ptr) break; } + // Forcing the next event delivery is a one shot deal. So reset it here. + m_force_next_event_delivery = false; + // We do some coalescing of events (for instance two consecutive running events get coalesced.) // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done, @@ -4046,9 +4127,14 @@ Process::HandlePrivateEvent (EventSP &event_sp) } Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get()); if (StateIsRunningState (new_state)) - PushProcessInputReader (); + { + // Only push the input handler if we aren't fowarding events, + // as this means the curses GUI is in use... + if (!GetTarget().GetDebugger().IsForwardingEvents()) + PushProcessIOHandler (); + } else if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) - PopProcessInputReader (); + PopProcessIOHandler (); BroadcastEvent (event_sp); } @@ -4594,64 +4680,203 @@ Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_ process->AppendSTDOUT (static_cast<const char *>(src), src_len); } -size_t -Process::ProcessInputReaderCallback (void *baton, - InputReader &reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len) +void +Process::ResetProcessIOHandler () +{ + m_process_input_reader.reset(); +} + + +class IOHandlerProcessSTDIO : + public IOHandler { - Process *process = (Process *) baton; - - switch (notification) +public: + IOHandlerProcessSTDIO (Process *process, + int write_fd) : + IOHandler(process->GetTarget().GetDebugger()), + m_process (process), + m_read_file (), + m_write_file (write_fd, false), + m_pipe_read(), + m_pipe_write() + { + m_read_file.SetDescriptor(GetInputFD(), false); + } + + virtual + ~IOHandlerProcessSTDIO () { - case eInputReaderActivate: - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderReactivate: - break; - - case eInputReaderAsynchronousOutputWritten: - break; - case eInputReaderGotToken: + } + + bool + OpenPipes () + { + if (m_pipe_read.IsValid() && m_pipe_write.IsValid()) + return true; + + int fds[2]; +#ifdef _MSC_VER + // pipe is not supported on windows so default to a fail condition + int err = 1; +#else + int err = pipe(fds); +#endif + if (err == 0) { - Error error; - process->PutSTDIN (bytes, bytes_len, error); + m_pipe_read.SetDescriptor(fds[0], true); + m_pipe_write.SetDescriptor(fds[1], true); + return true; } - break; + return false; + } + + void + ClosePipes() + { + m_pipe_read.Close(); + m_pipe_write.Close(); + } + + // Each IOHandler gets to run until it is done. It should read data + // from the "in" and place output into "out" and "err and return + // when done. + virtual void + Run () + { + if (m_read_file.IsValid() && m_write_file.IsValid()) + { + SetIsDone(false); + if (OpenPipes()) + { + const int read_fd = m_read_file.GetDescriptor(); + const int pipe_read_fd = m_pipe_read.GetDescriptor(); + TerminalState terminal_state; + terminal_state.Save (read_fd, false); + Terminal terminal(read_fd); + terminal.SetCanonical(false); + terminal.SetEcho(false); +// FD_ZERO, FD_SET are not supported on windows +#ifndef _MSC_VER + while (!GetIsDone()) + { + fd_set read_fdset; + FD_ZERO (&read_fdset); + FD_SET (read_fd, &read_fdset); + FD_SET (pipe_read_fd, &read_fdset); + const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1; + int num_set_fds = select (nfds, &read_fdset, NULL, NULL, NULL); + if (num_set_fds < 0) + { + const int select_errno = errno; + + if (select_errno != EINTR) + SetIsDone(true); + } + else if (num_set_fds > 0) + { + char ch = 0; + size_t n; + if (FD_ISSET (read_fd, &read_fdset)) + { + n = 1; + if (m_read_file.Read(&ch, n).Success() && n == 1) + { + if (m_write_file.Write(&ch, n).Fail() || n != 1) + SetIsDone(true); + } + else + SetIsDone(true); + } + if (FD_ISSET (pipe_read_fd, &read_fdset)) + { + // Consume the interrupt byte + n = 1; + m_pipe_read.Read (&ch, n); + SetIsDone(true); + } + } + } +#endif + terminal_state.Restore(); + + } + else + SetIsDone(true); + } + else + SetIsDone(true); + } + + // Hide any characters that have been displayed so far so async + // output can be displayed. Refresh() will be called after the + // output has been displayed. + virtual void + Hide () + { - case eInputReaderInterrupt: - process->SendAsyncInterrupt(); - break; - - case eInputReaderEndOfFile: - process->AppendSTDOUT ("^D", 2); - break; + } + // Called when the async output has been received in order to update + // the input reader (refresh the prompt and redisplay any current + // line(s) that are being edited + virtual void + Refresh () + { - case eInputReaderDone: - break; + } + + virtual void + Cancel () + { + size_t n = 1; + char ch = 'q'; + m_pipe_write.Write (&ch, n); + } + + virtual void + Interrupt () + { + if (StateIsRunningState(m_process->GetState())) + m_process->SendAsyncInterrupt(); + } + + virtual void + GotEOF() + { } - return bytes_len; +protected: + Process *m_process; + File m_read_file; // Read from this file (usually actual STDIN for LLDB + File m_write_file; // Write to this file (usually the master pty for getting io to debuggee) + File m_pipe_read; + File m_pipe_write; + +}; + +void +Process::WatchForSTDIN (IOHandler &io_handler) +{ } void -Process::ResetProcessInputReader () -{ - m_process_input_reader.reset(); +Process::CancelWatchForSTDIN (bool exited) +{ + if (m_process_input_reader) + { + if (exited) + m_process_input_reader->SetIsDone(true); + m_process_input_reader->Cancel(); + } } void -Process::SetSTDIOFileDescriptor (int file_descriptor) +Process::SetSTDIOFileDescriptor (int fd) { // First set up the Read Thread for reading/handling process I/O - std::unique_ptr<ConnectionFileDescriptor> conn_ap (new ConnectionFileDescriptor (file_descriptor, true)); + std::unique_ptr<ConnectionFileDescriptor> conn_ap (new ConnectionFileDescriptor (fd, true)); if (conn_ap.get()) { @@ -4664,70 +4889,37 @@ Process::SetSTDIOFileDescriptor (int file_descriptor) // Now read thread is set up, set up input reader. if (!m_process_input_reader.get()) - { - m_process_input_reader.reset (new InputReader(m_target.GetDebugger())); - Error err (m_process_input_reader->Initialize (Process::ProcessInputReaderCallback, - this, - eInputReaderGranularityByte, - NULL, - NULL, - false)); - - if (err.Fail()) - m_process_input_reader.reset(); - } + m_process_input_reader.reset (new IOHandlerProcessSTDIO (this, fd)); } } } void -Process::PushProcessInputReader () +Process::PushProcessIOHandler () { - if (m_process_input_reader && !m_process_input_reader->IsActive()) - m_target.GetDebugger().PushInputReader (m_process_input_reader); + IOHandlerSP io_handler_sp (m_process_input_reader); + if (io_handler_sp) + { + io_handler_sp->SetIsDone(false); + m_target.GetDebugger().PushIOHandler (io_handler_sp); + } } void -Process::PopProcessInputReader () +Process::PopProcessIOHandler () { - if (m_process_input_reader && m_process_input_reader->IsActive()) - m_target.GetDebugger().PopInputReader (m_process_input_reader); + IOHandlerSP io_handler_sp (m_process_input_reader); + if (io_handler_sp) + { + io_handler_sp->Cancel(); + m_target.GetDebugger().PopIOHandler (io_handler_sp); + } } // The process needs to know about installed plug-ins void Process::SettingsInitialize () { -// static std::vector<OptionEnumValueElement> g_plugins; -// -// int i=0; -// const char *name; -// OptionEnumValueElement option_enum; -// while ((name = PluginManager::GetProcessPluginNameAtIndex (i)) != NULL) -// { -// if (name) -// { -// option_enum.value = i; -// option_enum.string_value = name; -// option_enum.usage = PluginManager::GetProcessPluginDescriptionAtIndex (i); -// g_plugins.push_back (option_enum); -// } -// ++i; -// } -// option_enum.value = 0; -// option_enum.string_value = NULL; -// option_enum.usage = NULL; -// g_plugins.push_back (option_enum); -// -// for (i=0; (name = SettingsController::instance_settings_table[i].var_name); ++i) -// { -// if (::strcmp (name, "plugin") == 0) -// { -// SettingsController::instance_settings_table[i].enum_values = &g_plugins[0]; -// break; -// } -// } -// Thread::SettingsInitialize (); } @@ -4925,6 +5117,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, final_timeout.OffsetWithMicroSeconds(timeout_usec); } + // This isn't going to work if there are unfetched events on the queue. + // Are there cases where we might want to run the remaining events here, and then try to + // call the function? That's probably being too tricky for our own good. + + Event *other_events = listener.PeekAtNextEvent(); + if (other_events != NULL) + { + errors.Printf("Calling RunThreadPlan with pending events on the queue."); + return eExecutionSetupError; + } + + // We also need to make sure that the next event is delivered. We might be calling a function as part of + // a thread plan, in which case the last delivered event could be the running event, and we don't want + // event coalescing to cause us to lose OUR running event... + ForceNextEventDelivery(); + // This while loop must exit out the bottom, there's cleanup that we need to do when we are done. // So don't call return anywhere within it. @@ -5680,6 +5888,10 @@ void Process::Flush () { m_thread_list.Flush(); + m_extended_thread_list.Flush(); + m_extended_thread_stop_id = 0; + m_queue_list.Clear(); + m_queue_list_stop_id = 0; } void @@ -5709,3 +5921,37 @@ Process::DidExec () target.DidExec(); } +addr_t +Process::ResolveIndirectFunction(const Address *address, Error &error) +{ + if (address == nullptr) + { + error.SetErrorString("Invalid address argument"); + return LLDB_INVALID_ADDRESS; + } + + addr_t function_addr = LLDB_INVALID_ADDRESS; + + addr_t addr = address->GetLoadAddress(&GetTarget()); + std::map<addr_t,addr_t>::const_iterator iter = m_resolved_indirect_addresses.find(addr); + if (iter != m_resolved_indirect_addresses.end()) + { + function_addr = (*iter).second; + } + else + { + if (!InferiorCall(this, address, function_addr)) + { + Symbol *symbol = address->CalculateSymbolContextSymbol(); + error.SetErrorStringWithFormat ("Unable to call resolver for indirect function %s", + symbol ? symbol->GetName().AsCString() : "<UNKNOWN>"); + function_addr = LLDB_INVALID_ADDRESS; + } + else + { + m_resolved_indirect_addresses.insert(std::pair<addr_t, addr_t>(addr, function_addr)); + } + } + return function_addr; +} + diff --git a/contrib/llvm/tools/lldb/source/Target/Queue.cpp b/contrib/llvm/tools/lldb/source/Target/Queue.cpp new file mode 100644 index 0000000..2b9d2a0 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/Queue.cpp @@ -0,0 +1,127 @@ +//===-- Queue.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/Process.h" +#include "lldb/Target/Queue.h" +#include "lldb/Target/QueueList.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/SystemRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue_name) : + m_process_wp (), + m_queue_id (queue_id), + m_queue_name (), + m_running_work_items_count(0), + m_pending_work_items_count(0), + m_pending_items(), + m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS) +{ + if (queue_name) + m_queue_name = queue_name; + + m_process_wp = process_sp; +} + +Queue::~Queue () +{ +} + +queue_id_t +Queue::GetID () +{ + return m_queue_id; +} + +const char * +Queue::GetName () +{ + const char *result = NULL; + if (m_queue_name.size() > 0) + result = m_queue_name.c_str(); + return result; +} + +uint32_t +Queue::GetIndexID () +{ + return m_queue_id; +} + +std::vector<lldb::ThreadSP> +Queue::GetThreads () +{ + std::vector<ThreadSP> result; + ProcessSP process_sp = m_process_wp.lock(); + if (process_sp.get ()) + { + for (ThreadSP thread_sp : process_sp->Threads()) + { + if (thread_sp->GetQueueID() == m_queue_id) + { + result.push_back (thread_sp); + } + } + } + return result; +} + +void +Queue::SetNumRunningWorkItems (uint32_t count) +{ + m_running_work_items_count = count; +} + +uint32_t +Queue::GetNumRunningWorkItems () const +{ + return m_running_work_items_count; +} + + +void +Queue::SetNumPendingWorkItems (uint32_t count) +{ + m_pending_work_items_count = count; +} + +uint32_t +Queue::GetNumPendingWorkItems () const +{ + return m_pending_work_items_count; +} + +void +Queue::SetLibdispatchQueueAddress (addr_t dispatch_queue_t_addr) +{ + m_dispatch_queue_t_addr = dispatch_queue_t_addr; +} + +addr_t +Queue::GetLibdispatchQueueAddress () const +{ + return m_dispatch_queue_t_addr; +} + + +const std::vector<lldb::QueueItemSP> & +Queue::GetPendingItems () +{ + if (m_pending_items.size() == 0) + { + ProcessSP process_sp = m_process_wp.lock(); + if (process_sp && process_sp->GetSystemRuntime()) + { + process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue (this); + } + } + return m_pending_items; +} diff --git a/contrib/llvm/tools/lldb/source/Target/QueueItem.cpp b/contrib/llvm/tools/lldb/source/Target/QueueItem.cpp new file mode 100644 index 0000000..bb67628 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/QueueItem.cpp @@ -0,0 +1,77 @@ +//===-- QueueItem.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/Queue.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/QueueItem.h" +#include "lldb/Target/SystemRuntime.h" + +using namespace lldb; +using namespace lldb_private; + +QueueItem::QueueItem (QueueSP queue_sp) : + m_queue_wp (), + m_kind (eQueueItemKindUnknown), + m_address (), + m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS), + m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID), + m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID), + m_target_queue_id (LLDB_INVALID_QUEUE_ID), + m_stop_id (0), + m_backtrace(), + m_thread_label(), + m_queue_label(), + m_target_queue_label() +{ + m_queue_wp = queue_sp; +} + +QueueItem::~QueueItem () +{ +} + +QueueItemKind +QueueItem::GetKind() const +{ + return m_kind; +} + +void +QueueItem::SetKind (QueueItemKind item_kind) +{ + m_kind = item_kind; +} + +Address & +QueueItem::GetAddress () +{ + return m_address; +} + +void +QueueItem::SetAddress (Address addr) +{ + m_address = addr; +} + +ThreadSP +QueueItem::GetExtendedBacktraceThread (ConstString type) +{ + ThreadSP return_thread; + QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) + { + ProcessSP process_sp = queue_sp->GetProcess(); + if (process_sp && process_sp->GetSystemRuntime()) + { + return_thread = process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem (this->shared_from_this(), type); + } + } + return return_thread; +} diff --git a/contrib/llvm/tools/lldb/source/Target/QueueList.cpp b/contrib/llvm/tools/lldb/source/Target/QueueList.cpp new file mode 100644 index 0000000..6134f5c --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/QueueList.cpp @@ -0,0 +1,102 @@ +//===-- QueueList.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/Process.h" +#include "lldb/Target/Queue.h" +#include "lldb/Target/QueueList.h" + +using namespace lldb; +using namespace lldb_private; + +QueueList::QueueList (Process *process) : + m_process (process), + m_stop_id (0), + m_queues (), + m_mutex () +{ +} + +QueueList::~QueueList () +{ + Clear(); +} + +uint32_t +QueueList::GetSize () +{ + Mutex::Locker locker (m_mutex); + return m_queues.size(); +} + +lldb::QueueSP +QueueList::GetQueueAtIndex (uint32_t idx) +{ + Mutex::Locker locker (m_mutex); + if (idx < m_queues.size()) + { + return m_queues[idx]; + } + else + { + return QueueSP(); + } +} + +void +QueueList::Clear () +{ + Mutex::Locker locker (m_mutex); + m_queues.clear(); +} + +void +QueueList::AddQueue (QueueSP queue_sp) +{ + Mutex::Locker locker (m_mutex); + if (queue_sp.get ()) + { + m_queues.push_back (queue_sp); + } +} + +lldb::QueueSP +QueueList::FindQueueByID (lldb::queue_id_t qid) +{ + QueueSP ret; + for (QueueSP queue_sp : Queues()) + { + if (queue_sp->GetID() == qid) + { + ret = queue_sp; + break; + } + } + return ret; +} + +lldb::QueueSP +QueueList::FindQueueByIndexID (uint32_t index_id) +{ + QueueSP ret; + for (QueueSP queue_sp : Queues()) + { + if (queue_sp->GetIndexID() == index_id) + { + ret = queue_sp; + break; + } + } + return ret; +} + +lldb_private::Mutex & +QueueList::GetMutex () +{ + return m_mutex; +} diff --git a/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp b/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp new file mode 100644 index 0000000..527168c --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Target/SectionLoadHistory.cpp @@ -0,0 +1,182 @@ +//===-- SectionLoadHistory.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/SectionLoadHistory.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Stream.h" +#include "lldb/Target/SectionLoadList.h" + +using namespace lldb; +using namespace lldb_private; + + +bool +SectionLoadHistory::IsEmpty() const +{ + Mutex::Locker locker(m_mutex); + return m_stop_id_to_section_load_list.empty(); +} + +void +SectionLoadHistory::Clear () +{ + Mutex::Locker locker(m_mutex); + m_stop_id_to_section_load_list.clear(); +} + +uint32_t +SectionLoadHistory::GetLastStopID() const +{ + Mutex::Locker locker(m_mutex); + if (m_stop_id_to_section_load_list.empty()) + return 0; + else + return m_stop_id_to_section_load_list.rbegin()->first; +} + +SectionLoadList * +SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only) +{ + if (m_stop_id_to_section_load_list.empty()) + { + SectionLoadListSP section_load_list_sp(new SectionLoadList()); + if (stop_id == eStopIDNow) + stop_id = 0; + m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; + return section_load_list_sp.get(); + } + else + { + if (read_only) + { + // The section load list is for reading data only so we don't need to create + // a new SectionLoadList for the current stop ID, just return the section + // load list for the stop ID that is equal to or less than the current stop ID + if (stop_id == eStopIDNow) + { + // If we are asking for the latest and greatest value, it is always + // at the end of our list becuase that will be the highest stop ID. + StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin(); + return rpos->second.get(); + } + else + { + StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id); + if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id) + return pos->second.get(); + else if (pos != m_stop_id_to_section_load_list.begin()) + { + --pos; + return pos->second.get(); + } + } + } + else + { + // You can only use "eStopIDNow" when reading from the section load history + assert(stop_id != eStopIDNow); + + // We are updating the section load list (not read only), so if the stop ID + // passed in isn't the same as the last stop ID in our collection, then create + // a new node using the current stop ID + StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id); + if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id) + { + // We already have an entry for this value + return pos->second.get(); + } + + // We must make a new section load list that is based on the last valid + // section load list, so here we copy the last section load list and add + // a new node for the current stop ID. + StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin(); + SectionLoadListSP section_load_list_sp(new SectionLoadList(*rpos->second.get())); + m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; + return section_load_list_sp.get(); + } + } + return NULL; +} + +SectionLoadList & +SectionLoadHistory::GetCurrentSectionLoadList () +{ + const bool read_only = true; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only); + assert(section_load_list != NULL); + return *section_load_list; +} + +addr_t +SectionLoadHistory::GetSectionLoadAddress (uint32_t stop_id, const lldb::SectionSP §ion_sp) +{ + Mutex::Locker locker(m_mutex); + const bool read_only = true; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); + return section_load_list->GetSectionLoadAddress(section_sp); +} + +bool +SectionLoadHistory::ResolveLoadAddress (uint32_t stop_id, addr_t load_addr, Address &so_addr) +{ + // First find the top level section that this load address exists in + Mutex::Locker locker(m_mutex); + const bool read_only = true; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); + return section_load_list->ResolveLoadAddress (load_addr, so_addr); +} + +bool +SectionLoadHistory::SetSectionLoadAddress (uint32_t stop_id, + const lldb::SectionSP §ion_sp, + addr_t load_addr, + bool warn_multiple) +{ + Mutex::Locker locker(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); + return section_load_list->SetSectionLoadAddress(section_sp, load_addr, warn_multiple); +} + +size_t +SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp) +{ + Mutex::Locker locker(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); + return section_load_list->SetSectionUnloaded (section_sp); +} + +bool +SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp, addr_t load_addr) +{ + Mutex::Locker locker(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); + return section_load_list->SetSectionUnloaded (section_sp, load_addr); +} + +void +SectionLoadHistory::Dump (Stream &s, Target *target) +{ + Mutex::Locker locker(m_mutex); + StopIDToSectionLoadList::iterator pos, end = m_stop_id_to_section_load_list.end(); + for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos) + { + s.Printf("StopID = %u:\n", pos->first); + pos->second->Dump(s, target); + s.EOL(); + } +} + + diff --git a/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp b/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp index 96713c6..82f52f9 100644 --- a/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp +++ b/contrib/llvm/tools/lldb/source/Target/SectionLoadList.cpp @@ -25,6 +25,25 @@ using namespace lldb; using namespace lldb_private; +SectionLoadList::SectionLoadList (const SectionLoadList& rhs) : + m_addr_to_sect(), + m_sect_to_addr(), + m_mutex (Mutex::eMutexTypeRecursive) +{ + Mutex::Locker locker(rhs.m_mutex); + m_addr_to_sect = rhs.m_addr_to_sect; + m_sect_to_addr = rhs.m_sect_to_addr; +} + +void +SectionLoadList::operator=(const SectionLoadList &rhs) +{ + Mutex::Locker lhs_locker (m_mutex); + Mutex::Locker rhs_locker (rhs.m_mutex); + m_addr_to_sect = rhs.m_addr_to_sect; + m_sect_to_addr = rhs.m_sect_to_addr; +} + bool SectionLoadList::IsEmpty() const { diff --git a/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp b/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp index 914969a..3664e8f 100644 --- a/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp +++ b/contrib/llvm/tools/lldb/source/Target/StopInfo.cpp @@ -419,8 +419,15 @@ protected: // The breakpoint site may have many locations associated with it, not all of them valid for // this thread. Skip the ones that aren't: if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) + { + if (log) + { + StreamString s; + bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); + log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.", s.GetData(), thread_sp->GetID()); + } continue; - + } // First run the condition for the breakpoint. If that says we should stop, then we'll run // the callback for the breakpoint. If the callback says we shouldn't stop that will win. @@ -450,6 +457,12 @@ protected: } else { + if (log) + { + StreamString s; + bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); + log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.", s.GetData(), thread_sp->GetID(), condition_says_stop); + } if (!condition_says_stop) continue; } diff --git a/contrib/llvm/tools/lldb/source/Target/SystemRuntime.cpp b/contrib/llvm/tools/lldb/source/Target/SystemRuntime.cpp index 5c07ed3..c3fb9c8 100644 --- a/contrib/llvm/tools/lldb/source/Target/SystemRuntime.cpp +++ b/contrib/llvm/tools/lldb/source/Target/SystemRuntime.cpp @@ -56,6 +56,11 @@ SystemRuntime::DidLaunch() } void +SystemRuntime::Detach() +{ +} + +void SystemRuntime::ModulesDidLoad (ModuleList &module_list) { } diff --git a/contrib/llvm/tools/lldb/source/Target/Target.cpp b/contrib/llvm/tools/lldb/source/Target/Target.cpp index fd9626a..e781626 100644 --- a/contrib/llvm/tools/lldb/source/Target/Target.cpp +++ b/contrib/llvm/tools/lldb/source/Target/Target.cpp @@ -28,6 +28,8 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/Section.h" #include "lldb/Core/SourceManager.h" +#include "lldb/Core/State.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/ValueObject.h" @@ -42,6 +44,7 @@ #include "lldb/lldb-private-log.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Thread.h" @@ -69,12 +72,11 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat m_mutex (Mutex::eMutexTypeRecursive), m_arch (target_arch), m_images (this), - m_section_load_list (), + m_section_load_history (), m_breakpoint_list (false), m_internal_breakpoint_list (true), m_watchpoint_list (), m_process_sp (), - m_valid (true), m_search_filter_sp (), m_image_search_paths (ImageSearchPathsChanged, this), m_scratch_ast_context_ap (), @@ -84,6 +86,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat m_source_manager_ap(), m_stop_hooks (), m_stop_hook_next_id (0), + m_valid (true), m_suppress_stop_hooks (false) { SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed"); @@ -158,7 +161,7 @@ Target::DeleteCurrentProcess () { if (m_process_sp.get()) { - m_section_load_list.Clear(); + m_section_load_history.Clear(); if (m_process_sp->IsAlive()) m_process_sp->Destroy(); @@ -193,7 +196,7 @@ Target::Destroy() m_platform_sp.reset(); m_arch.Clear(); ClearModules(true); - m_section_load_list.Clear(); + m_section_load_history.Clear(); const bool notify = false; m_breakpoint_list.RemoveAll(notify); m_internal_breakpoint_list.RemoveAll(notify); @@ -248,7 +251,7 @@ Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules, { SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -302,7 +305,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, line_no, check_inlines, skip_prologue)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } @@ -314,7 +317,7 @@ Target::CreateBreakpoint (lldb::addr_t addr, bool internal, bool hardware) // it doesn't resolve to section/offset. // Try and resolve as a load address if possible - m_section_load_list.ResolveLoadAddress(addr, so_addr); + GetSectionLoadList().ResolveLoadAddress(addr, so_addr); if (!so_addr.IsValid()) { // The address didn't resolve, so just set this as an absolute address @@ -329,7 +332,7 @@ Target::CreateBreakpoint (Address &addr, bool internal, bool hardware) { SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this())); BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false); } BreakpointSP @@ -354,7 +357,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, func_name_type_mask, Breakpoint::Exact, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -381,7 +384,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, func_names, func_name_type_mask, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -409,7 +412,7 @@ Target::CreateBreakpoint (const FileSpecList *containingModules, num_names, func_name_type_mask, skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } return bp_sp; } @@ -487,7 +490,7 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules, func_regex, skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware); + return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); } lldb::BreakpointSP @@ -497,12 +500,12 @@ Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_ } BreakpointSP -Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware) +Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols) { BreakpointSP bp_sp; if (filter_sp && resolver_sp) { - bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware)); + bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols)); resolver_sp->SetBreakpoint (bp_sp.get()); if (internal) @@ -1004,11 +1007,11 @@ LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target) if (module_sp && !module_sp->LoadScriptingResourceInTarget(target, error, &feedback_stream)) { if (error.AsCString()) - target->GetDebugger().GetErrorStream().Printf("unable to load scripting data for module %s - error reported was %s\n", + target->GetDebugger().GetErrorFile()->Printf("unable to load scripting data for module %s - error reported was %s\n", module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(), error.AsCString()); if (feedback_stream.GetSize()) - target->GetDebugger().GetOutputStream().Printf("%s\n", + target->GetDebugger().GetErrorFile()->Printf("%s\n", feedback_stream.GetData()); } } @@ -1017,7 +1020,7 @@ void Target::ClearModules(bool delete_locations) { ModulesDidUnload (m_images, delete_locations); - GetSectionLoadList().Clear(); + m_section_load_history.Clear(); m_images.Clear(); m_scratch_ast_context_ap.reset(); m_scratch_ast_source_ap.reset(); @@ -1065,7 +1068,7 @@ Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files) FileSpec dependent_file_spec (dependent_files.GetFileSpecPointerAtIndex(i)); FileSpec platform_dependent_file_spec; if (m_platform_sp) - m_platform_sp->GetFile (dependent_file_spec, NULL, platform_dependent_file_spec); + m_platform_sp->GetFileWithUUID (dependent_file_spec, NULL, platform_dependent_file_spec); else platform_dependent_file_spec = dependent_file_spec; @@ -1307,7 +1310,8 @@ Target::ReadMemory (const Address& addr, Address resolved_addr; if (!addr.IsSectionOffset()) { - if (m_section_load_list.IsEmpty()) + SectionLoadList §ion_load_list = GetSectionLoadList(); + if (section_load_list.IsEmpty()) { // No sections are loaded, so we must assume we are not running // yet and anything we are given is a file address. @@ -1321,7 +1325,7 @@ Target::ReadMemory (const Address& addr, // or because we have have a live process that has sections loaded // through the dynamic loader load_addr = addr.GetOffset(); // "addr" doesn't have a section, so its offset is the load address - m_section_load_list.ResolveLoadAddress (load_addr, resolved_addr); + section_load_list.ResolveLoadAddress (load_addr, resolved_addr); } } if (!resolved_addr.IsValid()) @@ -1534,7 +1538,8 @@ Target::ReadPointerFromMemory (const Address& addr, addr_t pointer_vm_addr = scalar.ULongLong(LLDB_INVALID_ADDRESS); if (pointer_vm_addr != LLDB_INVALID_ADDRESS) { - if (m_section_load_list.IsEmpty()) + SectionLoadList §ion_load_list = GetSectionLoadList(); + if (section_load_list.IsEmpty()) { // No sections are loaded, so we must assume we are not running // yet and anything we are given is a file address. @@ -1546,7 +1551,7 @@ Target::ReadPointerFromMemory (const Address& addr, // we have manually loaded some sections with "target modules load ..." // or because we have have a live process that has sections loaded // through the dynamic loader - m_section_load_list.ResolveLoadAddress (pointer_vm_addr, pointer_addr); + section_load_list.ResolveLoadAddress (pointer_vm_addr, pointer_addr); } // We weren't able to resolve the pointer value, so just return // an address with no section @@ -1994,13 +1999,13 @@ Target::GetSourceManager () } -lldb::user_id_t -Target::AddStopHook (Target::StopHookSP &new_hook_sp) +Target::StopHookSP +Target::CreateStopHook () { lldb::user_id_t new_uid = ++m_stop_hook_next_id; - new_hook_sp.reset (new StopHook(shared_from_this(), new_uid)); - m_stop_hooks[new_uid] = new_hook_sp; - return new_uid; + Target::StopHookSP stop_hook_sp (new StopHook(shared_from_this(), new_uid)); + m_stop_hooks[new_uid] = stop_hook_sp; + return stop_hook_sp; } bool @@ -2259,6 +2264,186 @@ Target::Install (ProcessLaunchInfo *launch_info) return error; } +bool +Target::ResolveLoadAddress (addr_t load_addr, Address &so_addr, uint32_t stop_id) +{ + return m_section_load_history.ResolveLoadAddress(stop_id, load_addr, so_addr); +} + +bool +Target::SetSectionLoadAddress (const SectionSP §ion_sp, addr_t new_section_load_addr, bool warn_multiple) +{ + const addr_t old_section_load_addr = m_section_load_history.GetSectionLoadAddress (SectionLoadHistory::eStopIDNow, section_sp); + if (old_section_load_addr != new_section_load_addr) + { + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + if (m_section_load_history.SetSectionLoadAddress (stop_id, section_sp, new_section_load_addr, warn_multiple)) + return true; // Return true if the section load address was changed... + } + return false; // Return false to indicate nothing changed + +} + +bool +Target::SetSectionUnloaded (const lldb::SectionSP §ion_sp) +{ + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + return m_section_load_history.SetSectionUnloaded (stop_id, section_sp); +} + +bool +Target::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t load_addr) +{ + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + return m_section_load_history.SetSectionUnloaded (stop_id, section_sp, load_addr); +} + +void +Target::ClearAllLoadedSections () +{ + m_section_load_history.Clear(); +} + + +Error +Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info) +{ + Error error; + + StateType state = eStateInvalid; + + // Scope to temporarily get the process state in case someone has manually + // remotely connected already to a process and we can skip the platform + // launching. + { + ProcessSP process_sp (GetProcessSP()); + + if (process_sp) + state = process_sp->GetState(); + } + + launch_info.GetFlags().Set (eLaunchFlagDebug); + + // Get the value of synchronous execution here. If you wait till after you have started to + // run, then you could have hit a breakpoint, whose command might switch the value, and + // then you'll pick up that incorrect value. + Debugger &debugger = GetDebugger(); + const bool synchronous_execution = debugger.GetCommandInterpreter().GetSynchronous (); + + PlatformSP platform_sp (GetPlatform()); + + // Finalize the file actions, and if none were given, default to opening + // up a pseudo terminal + const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; + launch_info.FinalizeFileActions (this, default_to_use_pty); + + if (state == eStateConnected) + { + if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)) + { + error.SetErrorString("can't launch in tty when launching through a remote connection"); + return error; + } + } + + if (!launch_info.GetArchitecture().IsValid()) + launch_info.GetArchitecture() = GetArchitecture(); + + if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ()) + { + m_process_sp = GetPlatform()->DebugProcess (launch_info, + debugger, + this, + listener, + error); + } + else + { + if (state == eStateConnected) + { + assert(m_process_sp); + } + else + { + const char *plugin_name = launch_info.GetProcessPluginName(); + CreateProcess (listener, plugin_name, NULL); + } + + if (m_process_sp) + error = m_process_sp->Launch (launch_info); + } + + if (!m_process_sp) + { + if (error.Success()) + error.SetErrorString("failed to launch or debug process"); + return error; + } + + if (error.Success()) + { + if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false) + { + ListenerSP hijack_listener_sp (launch_info.GetHijackListener()); + + StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get()); + + if (state == eStateStopped) + { + if (!synchronous_execution) + m_process_sp->RestoreProcessEvents (); + + error = m_process_sp->PrivateResume(); + + if (error.Success()) + { + if (synchronous_execution) + { + state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get()); + const bool must_be_alive = false; // eStateExited is ok, so this must be false + if (!StateIsStoppedState(state, must_be_alive)) + { + error.SetErrorStringWithFormat("process isn't stopped: %s", StateAsCString(state)); + } + } + } + else + { + Error error2; + error2.SetErrorStringWithFormat("process resume at entry point failed: %s", error.AsCString()); + error = error2; + } + } + else + { + error.SetErrorStringWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state)); + } + } + m_process_sp->RestoreProcessEvents (); + } + else + { + Error error2; + error2.SetErrorStringWithFormat ("process launch failed: %s", error.AsCString()); + error = error2; + } + return error; +} //-------------------------------------------------------------- // Target::StopHook //-------------------------------------------------------------- @@ -2452,6 +2637,8 @@ g_properties[] = "'complete' is the default value for this setting which will load all sections and symbols by reading them from memory (slowest, most accurate). " "'partial' will load sections and attempt to find function bounds without downloading the symbol table (faster, still accurate, missing symbol names). " "'minimal' is the fastest setting and will load section data with no symbols, but should rarely be used as stack frames in these memory regions will be inaccurate and not provide any context (fastest). " }, + { "display-expression-in-crashlogs" , OptionValue::eTypeBoolean , false, false, NULL, NULL, "Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true." }, + { "trap-handler-names" , OptionValue::eTypeArray , true, OptionValue::eTypeString, NULL, NULL, "A list of trap handler function names, e.g. a common Unix user process one is _sigtramp." }, { NULL , OptionValue::eTypeInvalid , false, 0 , NULL, NULL, NULL } }; enum @@ -2483,7 +2670,9 @@ enum ePropertyHexImmediateStyle, ePropertyUseFastStepping, ePropertyLoadScriptFromSymbolFile, - ePropertyMemoryModuleLoadLevel + ePropertyMemoryModuleLoadLevel, + ePropertyDisplayExpressionsInCrashlogs, + ePropertyTrapHandlerNames }; @@ -2862,6 +3051,13 @@ TargetProperties::GetUseFastStepping () const return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); } +bool +TargetProperties::GetDisplayExpressionsInCrashlogs () const +{ + const uint32_t idx = ePropertyDisplayExpressionsInCrashlogs; + return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0); +} + LoadScriptFromSymFile TargetProperties::GetLoadScriptFromSymbolFile () const { @@ -2883,7 +3079,19 @@ TargetProperties::GetMemoryModuleLoadLevel() const return (MemoryModuleLoadLevel)m_collection_sp->GetPropertyAtIndexAsEnumeration(NULL, idx, g_properties[idx].default_uint_value); } +bool +TargetProperties::GetUserSpecifiedTrapHandlerNames (Args &args) const +{ + const uint32_t idx = ePropertyTrapHandlerNames; + return m_collection_sp->GetPropertyAtIndexAsArgs (NULL, idx, args); +} +void +TargetProperties::SetUserSpecifiedTrapHandlerNames (const Args &args) +{ + const uint32_t idx = ePropertyTrapHandlerNames; + m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, args); +} //---------------------------------------------------------------------- // Target::TargetEventData diff --git a/contrib/llvm/tools/lldb/source/Target/Thread.cpp b/contrib/llvm/tools/lldb/source/Target/Thread.cpp index 07f5321..39f2699 100644 --- a/contrib/llvm/tools/lldb/source/Target/Thread.cpp +++ b/contrib/llvm/tools/lldb/source/Target/Thread.cpp @@ -18,6 +18,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Host/Host.h" +#include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" @@ -61,12 +62,14 @@ static PropertyDefinition g_properties[] = { { "step-avoid-regexp", OptionValue::eTypeRegex , true , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." }, + { "step-avoid-libraries", OptionValue::eTypeFileSpecList , true , REG_EXTENDED, NULL, NULL, "A list of libraries that source stepping won't stop in." }, { "trace-thread", OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." }, { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL } }; enum { ePropertyStepAvoidRegex, + ePropertyStepAvoidLibraries, ePropertyEnableThreadTrace }; @@ -132,6 +135,15 @@ ThreadProperties::GetSymbolsToAvoidRegexp() return m_collection_sp->GetPropertyAtIndexAsOptionValueRegex (NULL, idx); } +FileSpecList & +ThreadProperties::GetLibrariesToAvoid() const +{ + const uint32_t idx = ePropertyStepAvoidLibraries; + OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx); + assert(option_value); + return option_value->GetCurrentValue(); +} + bool ThreadProperties::GetTraceEnabledState() const { @@ -2011,6 +2023,7 @@ Thread::GetUnwinder () case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::mips64: + case llvm::Triple::hexagon: m_unwinder_ap.reset (new UnwindLLDB (*this)); break; @@ -2053,3 +2066,125 @@ Thread::IsStillAtLastBreakpointHit () } return false; } + + +Error +Thread::StepIn (bool source_step, + bool avoid_code_without_debug_info) + +{ + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState (process->GetState(), true)) + { + StackFrameSP frame_sp = GetStackFrameAtIndex (0); + ThreadPlanSP new_plan_sp; + const lldb::RunMode run_mode = eOnlyThisThread; + const bool abort_other_plans = false; + + if (source_step && frame_sp && frame_sp->HasDebugInformation ()) + { + SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); + new_plan_sp = QueueThreadPlanForStepInRange (abort_other_plans, + sc.line_entry.range, + sc, + NULL, + run_mode, + avoid_code_without_debug_info); + } + else + { + new_plan_sp = QueueThreadPlanForStepSingleInstruction (false, + abort_other_plans, + run_mode); + } + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID (GetID()); + error = process->Resume(); + } + else + { + error.SetErrorString("process not stopped"); + } + return error; +} + +Error +Thread::StepOver (bool source_step) + +{ + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState (process->GetState(), true)) + { + StackFrameSP frame_sp = GetStackFrameAtIndex (0); + ThreadPlanSP new_plan_sp; + + const lldb::RunMode run_mode = eOnlyThisThread; + const bool abort_other_plans = false; + + if (source_step && frame_sp && frame_sp->HasDebugInformation ()) + { + SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); + new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans, + sc.line_entry.range, + sc, + run_mode); + } + else + { + new_plan_sp = QueueThreadPlanForStepSingleInstruction (true, + abort_other_plans, + run_mode); + } + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID (GetID()); + error = process->Resume(); + } + else + { + error.SetErrorString("process not stopped"); + } + return error; +} + +Error +Thread::StepOut () +{ + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState (process->GetState(), true)) + { + const bool first_instruction = false; + const bool stop_other_threads = false; + const bool abort_other_plans = false; + + ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut (abort_other_plans, + NULL, + first_instruction, + stop_other_threads, + eVoteYes, + eVoteNoOpinion, + 0)); + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID (GetID()); + error = process->Resume(); + } + else + { + error.SetErrorString("process not stopped"); + } + return error; +}
\ No newline at end of file diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp index 1f8b351..4fffdac 100644 --- a/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp +++ b/contrib/llvm/tools/lldb/source/Target/ThreadList.cpp @@ -85,6 +85,17 @@ ThreadList::AddThread (const ThreadSP &thread_sp) m_threads.push_back(thread_sp); } +void +ThreadList::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx) +{ + Mutex::Locker locker(GetMutex()); + if (idx < m_threads.size()) + m_threads.insert(m_threads.begin() + idx, thread_sp); + else + m_threads.push_back (thread_sp); +} + + uint32_t ThreadList::GetSize (bool can_update) { @@ -293,17 +304,31 @@ ThreadList::ShouldStop (Event *event_ptr) { ThreadSP thread_sp(*pos); - did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); + // We should never get a stop for which no thread had a stop reason, but sometimes we do see this - + // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out + // the right thing to do and stopping gives the user control over what to do in this instance. + // + // Note, this causes a problem when you have a thread specific breakpoint, and a bunch of threads hit the breakpoint, + // but not the thread which we are waiting for. All the threads that are not "supposed" to hit the breakpoint + // are marked as having no stop reason, which is right, they should not show a stop reason. But that triggers this + // code and causes us to stop seemingly for no reason. + // + // Since the only way we ever saw this error was on first attach, I'm only going to trigger set did_anybody_stop_for_a_reason + // to true unless this is the first stop. + // + // If this becomes a problem, we'll have to have another StopReason like "StopInfoHidden" which will look invalid + // everywhere but at this check. + + if (thread_sp->GetProcess()->GetStopID() > 1) + did_anybody_stop_for_a_reason = true; + else + did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); const bool thread_should_stop = thread_sp->ShouldStop(event_ptr); if (thread_should_stop) should_stop |= true; } - // We should never get a stop for which no thread had a stop reason, but sometimes we do see this - - // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out - // the right thing to do and stopping gives the user control over what to do in this instance. - if (!should_stop && !did_anybody_stop_for_a_reason) { should_stop = true; diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp index 2cfd29f..c4cb9ab 100644 --- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -16,6 +16,7 @@ #include "lldb/lldb-private-log.h" #include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" #include "lldb/Core/Stream.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Function.h" @@ -273,10 +274,36 @@ ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value) } bool -ThreadPlanStepInRange::FrameMatchesAvoidRegexp () +ThreadPlanStepInRange::FrameMatchesAvoidCriteria () { StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); + + // Check the library list first, as that's cheapest: + bool libraries_say_avoid = false; + FileSpecList libraries_to_avoid (GetThread().GetLibrariesToAvoid()); + size_t num_libraries = libraries_to_avoid.GetSize(); + if (num_libraries > 0) + { + SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule)); + FileSpec frame_library(sc.module_sp->GetFileSpec()); + + if (frame_library) + { + for (size_t i = 0; i < num_libraries; i++) + { + const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i)); + if (FileSpec::Equal (file_spec, frame_library, false)) + { + libraries_say_avoid = true; + break; + } + } + } + } + if (libraries_say_avoid) + return true; + const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get(); if (avoid_regexp_to_use == NULL) avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); @@ -368,8 +395,8 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, if (!should_step_out) { ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); - // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidRegexp. - should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp (); + // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria. + should_step_out = step_in_range_plan->FrameMatchesAvoidCriteria (); } } diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp index 37cd03c..18da6cd 100644 --- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -161,7 +161,7 @@ ThreadPlanStepThrough::ShouldStop (Event *event_ptr) // First, did we hit the backstop breakpoint? if (HitOurBackstopBreakpoint()) { - SetPlanComplete(false); + SetPlanComplete(true); return true; } diff --git a/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp b/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp index af6cef7..d191170 100644 --- a/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp +++ b/contrib/llvm/tools/lldb/source/Target/ThreadPlanTracer.cpp @@ -23,11 +23,13 @@ #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" using namespace lldb; @@ -61,7 +63,7 @@ ThreadPlanTracer::GetLogStream () { TargetSP target_sp (m_thread.CalculateTarget()); if (target_sp) - return &target_sp->GetDebugger().GetOutputStream(); + return target_sp->GetDebugger().GetOutputFile().get(); } return NULL; } diff --git a/contrib/llvm/tools/lldb/source/Target/UnwindAssembly.cpp b/contrib/llvm/tools/lldb/source/Target/UnwindAssembly.cpp index 7213750..af7f86f 100644 --- a/contrib/llvm/tools/lldb/source/Target/UnwindAssembly.cpp +++ b/contrib/llvm/tools/lldb/source/Target/UnwindAssembly.cpp @@ -15,7 +15,7 @@ using namespace lldb; using namespace lldb_private; -UnwindAssembly* +UnwindAssemblySP UnwindAssembly::FindPlugin (const ArchSpec &arch) { UnwindAssemblyCreateInstance create_callback; @@ -24,9 +24,9 @@ UnwindAssembly::FindPlugin (const ArchSpec &arch) (create_callback = PluginManager::GetUnwindAssemblyCreateCallbackAtIndex(idx)) != NULL; ++idx) { - std::unique_ptr<UnwindAssembly> assembly_profiler_ap (create_callback (arch)); + UnwindAssemblySP assembly_profiler_ap (create_callback (arch)); if (assembly_profiler_ap.get ()) - return assembly_profiler_ap.release (); + return assembly_profiler_ap; } return NULL; } diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp index 08e7af7..eccb813 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -80,22 +80,40 @@ StringExtractorGDBRemote::GetServerPacketType () const return eServerPacketType_A; case 'Q': + switch (packet_cstr[1]) { case 'E': - if (PACKET_STARTS_WITH ("QEnvironment:")) return eServerPacketType_QEnvironment; + if (PACKET_STARTS_WITH ("QEnvironment:")) return eServerPacketType_QEnvironment; + if (PACKET_STARTS_WITH ("QEnvironmentHexEncoded:")) return eServerPacketType_QEnvironmentHexEncoded; break; case 'S': - if (PACKET_MATCHES ("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode; - else if (PACKET_STARTS_WITH ("QSetDisableASLR:")) return eServerPacketType_QSetDisableASLR; - else if (PACKET_STARTS_WITH ("QSetSTDIN:")) return eServerPacketType_QSetSTDIN; - else if (PACKET_STARTS_WITH ("QSetSTDOUT:")) return eServerPacketType_QSetSTDOUT; - else if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR; - else if (PACKET_STARTS_WITH ("QSetWorkingDir:")) return eServerPacketType_QSetWorkingDir; + if (PACKET_MATCHES ("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode; + if (PACKET_STARTS_WITH ("QSaveRegisterState")) return eServerPacketType_QSaveRegisterState; + if (PACKET_STARTS_WITH ("QSetDisableASLR:")) return eServerPacketType_QSetDisableASLR; + if (PACKET_STARTS_WITH ("QSetSTDIN:")) return eServerPacketType_QSetSTDIN; + if (PACKET_STARTS_WITH ("QSetSTDOUT:")) return eServerPacketType_QSetSTDOUT; + if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR; + if (PACKET_STARTS_WITH ("QSetWorkingDir:")) return eServerPacketType_QSetWorkingDir; + if (PACKET_STARTS_WITH ("QSetLogging:")) return eServerPacketType_QSetLogging; + if (PACKET_STARTS_WITH ("QSetMaxPacketSize:")) return eServerPacketType_QSetMaxPacketSize; + if (PACKET_STARTS_WITH ("QSetMaxPayloadSize:")) return eServerPacketType_QSetMaxPayloadSize; + if (PACKET_STARTS_WITH ("QSetEnableAsyncProfiling;")) return eServerPacketType_QSetEnableAsyncProfiling; + if (PACKET_STARTS_WITH ("QSyncThreadState:")) return eServerPacketType_QSyncThreadState; break; + case 'L': - if (PACKET_STARTS_WITH ("QLaunchArch:")) return eServerPacketType_QLaunchArch; + if (PACKET_STARTS_WITH ("QLaunchArch:")) return eServerPacketType_QLaunchArch; + if (PACKET_MATCHES("QListThreadsInStopReply")) return eServerPacketType_QListThreadsInStopReply; + break; + + case 'R': + if (PACKET_STARTS_WITH ("QRestoreRegisterState:")) return eServerPacketType_QRestoreRegisterState; + break; + + case 'T': + if (PACKET_MATCHES ("QThreadSuffixSupported")) return eServerPacketType_QThreadSuffixSupported; break; } break; @@ -105,10 +123,12 @@ StringExtractorGDBRemote::GetServerPacketType () const { case 's': if (PACKET_MATCHES ("qsProcessInfo")) return eServerPacketType_qsProcessInfo; + if (PACKET_MATCHES ("qsThreadInfo")) return eServerPacketType_qsThreadInfo; break; case 'f': if (PACKET_STARTS_WITH ("qfProcessInfo")) return eServerPacketType_qfProcessInfo; + if (PACKET_STARTS_WITH ("qfThreadInfo")) return eServerPacketType_qfThreadInfo; break; case 'C': @@ -118,6 +138,9 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'G': if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName; if (PACKET_MATCHES ("qGetWorkingDir")) return eServerPacketType_qGetWorkingDir; + if (PACKET_MATCHES ("qGetPid")) return eServerPacketType_qGetPid; + if (PACKET_STARTS_WITH ("qGetProfileData;")) return eServerPacketType_qGetProfileData; + if (PACKET_MATCHES ("qGDBServerVersion")) return eServerPacketType_qGDBServerVersion; break; case 'H': @@ -133,21 +156,48 @@ StringExtractorGDBRemote::GetServerPacketType () const if (PACKET_MATCHES ("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; break; + case 'M': + if (PACKET_STARTS_WITH ("qMemoryRegionInfo:")) return eServerPacketType_qMemoryRegionInfo; + if (PACKET_MATCHES ("qMemoryRegionInfo")) return eServerPacketType_qMemoryRegionInfoSupported; + break; + case 'P': if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID; - if (PACKET_STARTS_WITH ("qPlatform_shell:")) return eServerPacketType_qPlatform_shell; + if (PACKET_STARTS_WITH ("qPlatform_shell:")) return eServerPacketType_qPlatform_shell; if (PACKET_STARTS_WITH ("qPlatform_mkdir:")) return eServerPacketType_qPlatform_mkdir; if (PACKET_STARTS_WITH ("qPlatform_chmod:")) return eServerPacketType_qPlatform_chmod; + if (PACKET_MATCHES ("qProcessInfo")) return eServerPacketType_qProcessInfo; break; + case 'R': + if (PACKET_STARTS_WITH ("qRcmd,")) return eServerPacketType_qRcmd; + if (PACKET_STARTS_WITH ("qRegisterInfo")) return eServerPacketType_qRegisterInfo; + break; case 'S': if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest; + if (PACKET_MATCHES ("qShlibInfoAddr")) return eServerPacketType_qShlibInfoAddr; + if (PACKET_MATCHES ("qStepPacketSupported")) return eServerPacketType_qStepPacketSupported; + if (PACKET_MATCHES ("qSyncThreadStateSupported")) return eServerPacketType_qSyncThreadStateSupported; + break; + + case 'T': + if (PACKET_STARTS_WITH ("qThreadExtraInfo,")) return eServerPacketType_qThreadExtraInfo; + if (PACKET_STARTS_WITH ("qThreadStopInfo")) return eServerPacketType_qThreadStopInfo; break; case 'U': if (PACKET_STARTS_WITH ("qUserName:")) return eServerPacketType_qUserName; break; + + case 'V': + if (PACKET_MATCHES ("qVAttachOrWaitSupported")) return eServerPacketType_qVAttachOrWaitSupported; + break; + + case 'W': + if (PACKET_STARTS_WITH ("qWatchpointSupportInfo:")) return eServerPacketType_qWatchpointSupportInfo; + if (PACKET_MATCHES ("qWatchpointSupportInfo")) return eServerPacketType_qWatchpointSupportInfoSupported; + break; } break; case 'v': @@ -165,8 +215,85 @@ StringExtractorGDBRemote::GetServerPacketType () const else if (PACKET_STARTS_WITH("vFile:symlink")) return eServerPacketType_vFile_symlink; else if (PACKET_STARTS_WITH("vFile:unlink")) return eServerPacketType_vFile_unlink; + } else { + if (PACKET_STARTS_WITH ("vAttach;")) return eServerPacketType_vAttach; + if (PACKET_STARTS_WITH ("vAttachWait;")) return eServerPacketType_vAttachWait; + if (PACKET_STARTS_WITH ("vAttachOrWait;")) return eServerPacketType_vAttachOrWait; + if (PACKET_STARTS_WITH ("vAttachName;")) return eServerPacketType_vAttachName; + if (PACKET_STARTS_WITH("vCont;")) return eServerPacketType_vCont; + if (PACKET_MATCHES ("vCont?")) return eServerPacketType_vCont_actions; } break; + case '_': + switch (packet_cstr[1]) + { + case 'M': + return eServerPacketType__M; + + case 'm': + return eServerPacketType__m; + } + break; + + case '?': + if (packet_size == 1) return eServerPacketType_stop_reason; + break; + + case 'c': + return eServerPacketType_c; + + case 'C': + return eServerPacketType_C; + + case 'D': + if (packet_size == 1) return eServerPacketType_D; + break; + + case 'g': + if (packet_size == 1) return eServerPacketType_g; + break; + + case 'G': + return eServerPacketType_G; + + case 'H': + return eServerPacketType_H; + + case 'k': + if (packet_size == 1) return eServerPacketType_k; + break; + + case 'm': + return eServerPacketType_m; + + case 'M': + return eServerPacketType_M; + + case 'p': + return eServerPacketType_p; + + case 'P': + return eServerPacketType_P; + + case 's': + if (packet_size == 1) return eServerPacketType_s; + break; + + case 'S': + return eServerPacketType_S; + + case 'T': + return eServerPacketType_T; + + case 'z': + if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') + return eServerPacketType_z; + break; + + case 'Z': + if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') + return eServerPacketType_Z; + break; } return eServerPacketType_unimplemented; } diff --git a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h index 2379882..f8af3ca 100644 --- a/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h +++ b/contrib/llvm/tools/lldb/source/Utility/StringExtractorGDBRemote.h @@ -80,7 +80,66 @@ public: eServerPacketType_vFile_md5, eServerPacketType_vFile_stat, eServerPacketType_vFile_symlink, - eServerPacketType_vFile_unlink + eServerPacketType_vFile_unlink, + // debug server packages + eServerPacketType_QEnvironmentHexEncoded, + eServerPacketType_QListThreadsInStopReply, + eServerPacketType_QRestoreRegisterState, + eServerPacketType_QSaveRegisterState, + eServerPacketType_QSetLogging, + eServerPacketType_QSetMaxPacketSize, + eServerPacketType_QSetMaxPayloadSize, + eServerPacketType_QSetEnableAsyncProfiling, + eServerPacketType_QSyncThreadState, + eServerPacketType_QThreadSuffixSupported, + + eServerPacketType_qsThreadInfo, + eServerPacketType_qfThreadInfo, + eServerPacketType_qGetPid, + eServerPacketType_qGetProfileData, + eServerPacketType_qGDBServerVersion, + eServerPacketType_qMemoryRegionInfo, + eServerPacketType_qMemoryRegionInfoSupported, + eServerPacketType_qProcessInfo, + eServerPacketType_qRcmd, + eServerPacketType_qRegisterInfo, + eServerPacketType_qShlibInfoAddr, + eServerPacketType_qStepPacketSupported, + eServerPacketType_qSyncThreadStateSupported, + eServerPacketType_qThreadExtraInfo, + eServerPacketType_qThreadStopInfo, + eServerPacketType_qVAttachOrWaitSupported, + eServerPacketType_qWatchpointSupportInfo, + eServerPacketType_qWatchpointSupportInfoSupported, + + eServerPacketType_vAttach, + eServerPacketType_vAttachWait, + eServerPacketType_vAttachOrWait, + eServerPacketType_vAttachName, + eServerPacketType_vCont, + eServerPacketType_vCont_actions, // vCont? + + eServerPacketType_stop_reason, // '?' + + eServerPacketType_c, + eServerPacketType_C, + eServerPacketType_D, + eServerPacketType_g, + eServerPacketType_G, + eServerPacketType_H, + eServerPacketType_k, + eServerPacketType_m, + eServerPacketType_M, + eServerPacketType_p, + eServerPacketType_P, + eServerPacketType_s, + eServerPacketType_S, + eServerPacketType_T, + eServerPacketType_Z, + eServerPacketType_z, + + eServerPacketType__M, + eServerPacketType__m, }; ServerPacketType diff --git a/contrib/llvm/tools/lldb/source/lldb-log.cpp b/contrib/llvm/tools/lldb/source/lldb-log.cpp index 5e1dc3a..12ec3a5 100644 --- a/contrib/llvm/tools/lldb/source/lldb-log.cpp +++ b/contrib/llvm/tools/lldb/source/lldb-log.cpp @@ -141,6 +141,7 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm) else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits &= ~LIBLLDB_LOG_UNWIND; else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits &= ~LIBLLDB_LOG_TYPES; else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits &= ~LIBLLDB_LOG_SYMBOLS; + else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits &= ~LIBLLDB_LOG_SYSTEM_RUNTIME; else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES; else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP; else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS; @@ -155,7 +156,10 @@ lldb_private::DisableLog (const char **categories, Stream *feedback_strm) } log->GetMask().Reset (flag_bits); if (flag_bits == 0) + { + log->SetStream(lldb::StreamSP()); g_log_enabled = false; + } } return; @@ -208,6 +212,7 @@ lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const ch else if (0 == ::strcasecmp(arg, "state")) flag_bits |= LIBLLDB_LOG_STATE; else if (0 == ::strcasecmp(arg, "step")) flag_bits |= LIBLLDB_LOG_STEP; else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits |= LIBLLDB_LOG_SYMBOLS; + else if (0 == ::strcasecmp(arg, "system-runtime")) flag_bits |= LIBLLDB_LOG_SYSTEM_RUNTIME; else if (0 == ::strcasecmp(arg, "target")) flag_bits |= LIBLLDB_LOG_TARGET; else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits |= LIBLLDB_LOG_TEMPORARY; else if (0 == ::strcasecmp(arg, "thread")) flag_bits |= LIBLLDB_LOG_THREAD; @@ -256,6 +261,7 @@ lldb_private::ListLogCategories (Stream *strm) " state - log private and public process state changes\n" " step - log step related activities\n" " symbol - log symbol related issues and warnings\n" + " system-runtime - log system runtime events\n" " target - log target events and activities\n" " thread - log thread events and activities\n" " types - log type system related activities\n" diff --git a/contrib/llvm/tools/lldb/source/lldb.cpp b/contrib/llvm/tools/lldb/source/lldb.cpp index ab4e491..519a502 100644 --- a/contrib/llvm/tools/lldb/source/lldb.cpp +++ b/contrib/llvm/tools/lldb/source/lldb.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Mutex.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -107,6 +108,7 @@ lldb_private::Initialize () SymbolFileDWARFDebugMap::Initialize(); ItaniumABILanguageRuntime::Initialize(); #ifndef LLDB_DISABLE_PYTHON + ScriptInterpreterPython::InitializePrivate(); OperatingSystemPython::Initialize(); #endif diff --git a/contrib/llvm/tools/lldb/tools/driver/Driver.cpp b/contrib/llvm/tools/lldb/tools/driver/Driver.cpp index e274242..78d3a7e 100644 --- a/contrib/llvm/tools/lldb/tools/driver/Driver.cpp +++ b/contrib/llvm/tools/lldb/tools/driver/Driver.cpp @@ -18,7 +18,6 @@ #include <string> #include <thread> -#include "IOChannel.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" @@ -83,20 +82,12 @@ static OptionDefinition g_options[] = "Tells the debugger to use the file <filename> as the program to be debugged." }, { LLDB_OPT_SET_3, false, "core" , 'c', required_argument, 0, eArgTypeFilename, "Tells the debugger to use the fullpath to <path> as the core file." }, + { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid, + "Tells the debugger to attach to a process with the given pid." }, { LLDB_OPT_SET_4, true , "attach-name" , 'n', required_argument, 0, eArgTypeProcessName, "Tells the debugger to attach to a process with the given name." }, { LLDB_OPT_SET_4, true , "wait-for" , 'w', no_argument , 0, eArgTypeNone, "Tells the debugger to wait for a process with the given pid or name to launch before attaching." }, - { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid, - "Tells the debugger to attach to a process with the given pid." }, - { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang, - "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. " - "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python " - "extensions have been implemented." }, - { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself." }, - { LLDB_3_TO_5, false, "source-quietly" , 'b', no_argument , 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself." }, { LLDB_3_TO_5, false, "source" , 's', required_argument, 0, eArgTypeFilename, "Tells the debugger to read in and execute the lldb commands in the given file, after any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "one-line" , 'o', required_argument, 0, eArgTypeNone, @@ -105,6 +96,8 @@ static OptionDefinition g_options[] = "Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone, "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." }, + { LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone, + "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." }, { LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone, "Tells the debugger to open source files using the host's \"external editor\" mechanism." }, { LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone, @@ -113,6 +106,12 @@ static OptionDefinition g_options[] = "Do not use colors." }, { LLDB_OPT_SET_6, true , "python-path" , 'P', no_argument , 0, eArgTypeNone, "Prints out the path to the lldb.py file for this version of lldb." }, + { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang, + "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. " + "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python " + "extensions have been implemented." }, + { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone, + "Tells the debugger to print out extra information for debugging itself." }, { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL } }; @@ -121,14 +120,7 @@ static const uint32_t last_option_set_with_args = 2; Driver::Driver () : SBBroadcaster ("Driver"), m_debugger (SBDebugger::Create(false)), - m_editline_pty (), - m_editline_slave_fh (NULL), - m_editline_reader (), - m_io_channel_ap (), - m_option_data (), - m_executing_user_command (false), - m_waiting_for_command (false), - m_done(false) + m_option_data () { // We want to be able to handle CTRL+D in the terminal to have it terminate // certain input @@ -145,24 +137,6 @@ Driver::~Driver () g_debugger_name = NULL; } -void -Driver::CloseIOChannelFile () -{ - // Write an End of File sequence to the file descriptor to ensure any - // read functions can exit. - char eof_str[] = "\x04"; - int mfd = m_editline_pty.GetMasterFileDescriptor(); - if (mfd != -1) - ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str)); - - m_editline_pty.CloseMasterFileDescriptor(); - - if (m_editline_slave_fh) - { - ::fclose (m_editline_slave_fh); - m_editline_slave_fh = NULL; - } -} // This function takes INDENT, which tells how many spaces to output at the front // of each line; TEXT, which is the text that is to be output. It outputs the @@ -346,7 +320,11 @@ ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data) } indent_level -= 5; - + + fprintf (out, "\n%*sNotes:\n", + indent_level, ""); + indent_level += 5; + fprintf (out, "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will be processed from left to right in order, " "\n%*swith the source files and commands interleaved. The same is true of the \"-S\" and \"-O\" options." "\n%*sThe before file and after file sets can intermixed freely, the command parser will sort them out." @@ -356,9 +334,9 @@ ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data) indent_level, "", indent_level, ""); - fprintf (out, "\n%*s(If you don't provide -f then the first argument will be the file to be debugged" - "\n%*s so '%s -- <filename> [<ARG1> [<ARG2>]]' also works." - "\n%*s Remember to end the options with \"--\" if any of your arguments have a \"-\" in them.)\n\n", + fprintf (out, "\n%*sIf you don't provide -f then the first argument will be the file to be debugged" + "\n%*swhich means that '%s -- <filename> [<ARG1> [<ARG2>]]' also works." + "\n%*sBut remember to end the options with \"--\" if any of your arguments have a \"-\" in them.\n\n", indent_level, "", indent_level, "", name, @@ -521,7 +499,7 @@ Driver::ExecuteInitialCommands (bool before_file) const char *executed_command = command; if (is_file) { - ::snprintf (command_string, sizeof(command_string), "command source '%s'", command); + ::snprintf (command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command); executed_command = command_string; } @@ -530,23 +508,27 @@ Driver::ExecuteInitialCommands (bool before_file) { const size_t output_size = result.GetOutputSize(); if (output_size > 0) - m_io_channel_ap->OutWrite (result.GetOutput(dump_stream_only_if_no_immediate), output_size, NO_ASYNC); + { + const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate); + if (cstr) + printf ("%s", cstr); + } const size_t error_size = result.GetErrorSize(); if (error_size > 0) - m_io_channel_ap->OutWrite (result.GetError(dump_stream_only_if_no_immediate), error_size, NO_ASYNC); + { + const char *cstr = result.GetError(dump_stream_only_if_no_immediate); + if (cstr) + printf ("%s", cstr); + } } if (result.Succeeded() == false) { - char error_buffer[1024]; - size_t error_size; const char *type = before_file ? "before file" : "after_file"; if (is_file) - error_size = ::snprintf(error_buffer, sizeof(error_buffer), "Aborting %s command execution, command file: '%s' failed.\n", type, command); + ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command); else - error_size = ::snprintf(error_buffer, sizeof(error_buffer), "Aborting %s command execution, command: '%s' failed.\n", type, command); - - m_io_channel_ap->OutWrite(error_buffer, error_size, NO_ASYNC); + ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command); break; } result.Clear(); @@ -747,7 +729,7 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) m_option_data.m_debug_mode = true; break; - case 'q': + case 'Q': m_option_data.m_source_quietly = true; break; @@ -861,524 +843,9 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) return error; } -size_t -Driver::GetProcessSTDOUT () -{ - // The process has stuff waiting for stdout; get it and write it out to the appropriate place. - char stdio_buffer[1024]; - size_t len; - size_t total_bytes = 0; - while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0) - { - m_io_channel_ap->OutWrite (stdio_buffer, len, NO_ASYNC); - total_bytes += len; - } - return total_bytes; -} - -size_t -Driver::GetProcessSTDERR () -{ - // The process has stuff waiting for stderr; get it and write it out to the appropriate place. - char stdio_buffer[1024]; - size_t len; - size_t total_bytes = 0; - while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0) - { - m_io_channel_ap->ErrWrite (stdio_buffer, len, NO_ASYNC); - total_bytes += len; - } - return total_bytes; -} - -void -Driver::UpdateSelectedThread () -{ - using namespace lldb; - SBProcess process(m_debugger.GetSelectedTarget().GetProcess()); - if (process.IsValid()) - { - SBThread curr_thread (process.GetSelectedThread()); - SBThread thread; - StopReason curr_thread_stop_reason = eStopReasonInvalid; - curr_thread_stop_reason = curr_thread.GetStopReason(); - - if (!curr_thread.IsValid() || - curr_thread_stop_reason == eStopReasonInvalid || - curr_thread_stop_reason == eStopReasonNone) - { - // Prefer a thread that has just completed its plan over another thread as current thread. - SBThread plan_thread; - SBThread other_thread; - const size_t num_threads = process.GetNumThreads(); - size_t i; - for (i = 0; i < num_threads; ++i) - { - thread = process.GetThreadAtIndex(i); - StopReason thread_stop_reason = thread.GetStopReason(); - switch (thread_stop_reason) - { - case eStopReasonInvalid: - case eStopReasonNone: - break; - - case eStopReasonTrace: - case eStopReasonBreakpoint: - case eStopReasonWatchpoint: - case eStopReasonSignal: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonThreadExiting: - if (!other_thread.IsValid()) - other_thread = thread; - break; - case eStopReasonPlanComplete: - if (!plan_thread.IsValid()) - plan_thread = thread; - break; - } - } - if (plan_thread.IsValid()) - process.SetSelectedThread (plan_thread); - else if (other_thread.IsValid()) - process.SetSelectedThread (other_thread); - else - { - if (curr_thread.IsValid()) - thread = curr_thread; - else - thread = process.GetThreadAtIndex(0); - - if (thread.IsValid()) - process.SetSelectedThread (thread); - } - } - } -} - -// This function handles events that were broadcast by the process. -void -Driver::HandleBreakpointEvent (const SBEvent &event) -{ - using namespace lldb; - const uint32_t event_type = SBBreakpoint::GetBreakpointEventTypeFromEvent (event); - - if (event_type & eBreakpointEventTypeAdded - || event_type & eBreakpointEventTypeRemoved - || event_type & eBreakpointEventTypeEnabled - || event_type & eBreakpointEventTypeDisabled - || event_type & eBreakpointEventTypeCommandChanged - || event_type & eBreakpointEventTypeConditionChanged - || event_type & eBreakpointEventTypeIgnoreChanged - || event_type & eBreakpointEventTypeLocationsResolved) - { - // Don't do anything about these events, since the breakpoint commands already echo these actions. - } - else if (event_type & eBreakpointEventTypeLocationsAdded) - { - char message[256]; - uint32_t num_new_locations = SBBreakpoint::GetNumBreakpointLocationsFromEvent(event); - if (num_new_locations > 0) - { - SBBreakpoint breakpoint = SBBreakpoint::GetBreakpointFromEvent(event); - int message_len = ::snprintf (message, sizeof(message), "%d location%s added to breakpoint %d\n", - num_new_locations, - num_new_locations == 1 ? "" : "s", - breakpoint.GetID()); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - } - else if (event_type & eBreakpointEventTypeLocationsRemoved) - { - // These locations just get disabled, not sure it is worth spamming folks about this on the command line. - } - else if (event_type & eBreakpointEventTypeLocationsResolved) - { - // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy. - } -} - -// This function handles events that were broadcast by the process. -void -Driver::HandleProcessEvent (const SBEvent &event) -{ - using namespace lldb; - const uint32_t event_type = event.GetType(); - - if (event_type & SBProcess::eBroadcastBitSTDOUT) - { - // The process has stdout available, get it and write it out to the - // appropriate place. - GetProcessSTDOUT (); - } - else if (event_type & SBProcess::eBroadcastBitSTDERR) - { - // The process has stderr available, get it and write it out to the - // appropriate place. - GetProcessSTDERR (); - } - else if (event_type & SBProcess::eBroadcastBitStateChanged) - { - // Drain all stout and stderr so we don't see any output come after - // we print our prompts - GetProcessSTDOUT (); - GetProcessSTDERR (); - // Something changed in the process; get the event and report the process's current status and location to - // the user. - StateType event_state = SBProcess::GetStateFromEvent (event); - if (event_state == eStateInvalid) - return; - - SBProcess process (SBProcess::GetProcessFromEvent (event)); - assert (process.IsValid()); - - switch (event_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateStepping: - case eStateDetached: - { - char message[1024]; - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " %s\n", process.GetProcessID(), - m_debugger.StateAsCString (event_state)); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - break; - - case eStateRunning: - // Don't be chatty when we run... - break; - - case eStateExited: - { - SBCommandReturnObject result; - m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); - m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); - m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); - } - break; - - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - // Make sure the program hasn't been auto-restarted: - if (SBProcess::GetRestartedFromEvent (event)) - { - size_t num_reasons = SBProcess::GetNumRestartedReasonsFromEvent(event); - if (num_reasons > 0) - { - // FIXME: Do we want to report this, or would that just be annoyingly chatty? - if (num_reasons == 1) - { - char message[1024]; - const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, 0); - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted: %s\n", - process.GetProcessID(), reason ? reason : "<UNKNOWN REASON>"); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - else - { - char message[1024]; - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted, reasons:\n", - process.GetProcessID()); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - for (size_t i = 0; i < num_reasons; i++) - { - const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, i); - int message_len = ::snprintf(message, sizeof(message), "\t%s\n", reason ? reason : "<UNKNOWN REASON>"); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - } - } - } - else - { - if (GetDebugger().GetSelectedTarget() == process.GetTarget()) - { - SBCommandReturnObject result; - UpdateSelectedThread (); - m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); - m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); - m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); - } - else - { - SBStream out_stream; - uint32_t target_idx = GetDebugger().GetIndexOfTarget(process.GetTarget()); - if (target_idx != UINT32_MAX) - out_stream.Printf ("Target %d: (", target_idx); - else - out_stream.Printf ("Target <unknown index>: ("); - process.GetTarget().GetDescription (out_stream, eDescriptionLevelBrief); - out_stream.Printf (") stopped.\n"); - m_io_channel_ap->OutWrite (out_stream.GetData(), out_stream.GetSize(), ASYNC); - } - } - break; - } - } -} - -void -Driver::HandleThreadEvent (const SBEvent &event) -{ - // At present the only thread event we handle is the Frame Changed event, and all we do for that is just - // reprint the thread status for that thread. - using namespace lldb; - const uint32_t event_type = event.GetType(); - if (event_type == SBThread::eBroadcastBitStackChanged - || event_type == SBThread::eBroadcastBitThreadSelected) - { - SBThread thread = SBThread::GetThreadFromEvent (event); - if (thread.IsValid()) - { - SBStream out_stream; - thread.GetStatus(out_stream); - m_io_channel_ap->OutWrite (out_stream.GetData (), out_stream.GetSize (), ASYNC); - } - } -} - -// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit). - -bool -Driver::HandleIOEvent (const SBEvent &event) -{ - bool quit = false; - - const uint32_t event_type = event.GetType(); - - if (event_type & IOChannel::eBroadcastBitHasUserInput) - { - // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for - // handling. - - const char *command_string = SBEvent::GetCStringFromEvent(event); - if (command_string == NULL) - command_string = ""; - SBCommandReturnObject result; - - // We don't want the result to bypass the OutWrite function in IOChannel, as this can result in odd - // output orderings and problems with the prompt. - - // Note that we are in the process of executing a command - m_executing_user_command = true; - - m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true); - - // Note that we are back from executing a user command - m_executing_user_command = false; - - // Display any STDOUT/STDERR _prior_ to emitting the command result text - GetProcessSTDOUT (); - GetProcessSTDERR (); - - const bool only_if_no_immediate = true; - - // Now emit the command output text from the command we just executed - const size_t output_size = result.GetOutputSize(); - if (output_size > 0) - m_io_channel_ap->OutWrite (result.GetOutput(only_if_no_immediate), output_size, NO_ASYNC); - - // Now emit the command error text from the command we just executed - const size_t error_size = result.GetErrorSize(); - if (error_size > 0) - m_io_channel_ap->OutWrite (result.GetError(only_if_no_immediate), error_size, NO_ASYNC); - - // We are done getting and running our command, we can now clear the - // m_waiting_for_command so we can get another one. - m_waiting_for_command = false; - - // If our editline input reader is active, it means another input reader - // got pushed onto the input reader and caused us to become deactivated. - // When the input reader above us gets popped, we will get re-activated - // and our prompt will refresh in our callback - if (m_editline_reader.IsActive()) - { - ReadyForCommand (); - } - } - else if (event_type & IOChannel::eBroadcastBitUserInterrupt) - { - // This is here to handle control-c interrupts from the user. It has not yet really been implemented. - // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER - //m_io_channel_ap->CancelInput(); - // Anything else? Send Interrupt to process? - } - else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || - (event_type & IOChannel::eBroadcastBitThreadDidExit)) - { - // If the IOChannel thread is trying to go away, then it is definitely - // time to end the debugging session. - quit = true; - } - - return quit; -} - -void -Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len) -{ - Driver *driver = (Driver*)baton; - driver->GetFromMaster ((const char *)src, src_len); -} - -void -Driver::GetFromMaster (const char *src, size_t src_len) -{ - // Echo the characters back to the Debugger's stdout, that way if you - // type characters while a command is running, you'll see what you've typed. - FILE *out_fh = m_debugger.GetOutputFileHandle(); - if (out_fh) - ::fwrite (src, 1, src_len, out_fh); -} - -size_t -Driver::EditLineInputReaderCallback -( - void *baton, - SBInputReader *reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - Driver *driver = (Driver *)baton; - - switch (notification) - { - case eInputReaderActivate: - break; - - case eInputReaderReactivate: - if (driver->m_executing_user_command == false) - driver->ReadyForCommand(); - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderAsynchronousOutputWritten: - if (driver->m_io_channel_ap.get() != NULL) - driver->m_io_channel_ap->RefreshPrompt(); - break; - - case eInputReaderInterrupt: - if (driver->m_io_channel_ap.get() != NULL) - { - SBProcess process(driver->GetDebugger().GetSelectedTarget().GetProcess()); - if (!driver->m_io_channel_ap->EditLineHasCharacters() - && process.IsValid() - && (process.GetState() == lldb::eStateRunning || process.GetState() == lldb::eStateAttaching)) - { - process.SendAsyncInterrupt (); - } - else - { - driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC); - // I wish I could erase the entire input line, but there's no public API for that. - driver->m_io_channel_ap->EraseCharsBeforeCursor(); - driver->m_io_channel_ap->RefreshPrompt(); - } - } - break; - - case eInputReaderEndOfFile: - if (driver->m_io_channel_ap.get() != NULL) - { - driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC); - driver->m_io_channel_ap->RefreshPrompt (); - } - write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5); - break; - - case eInputReaderGotToken: - write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len); - break; - - case eInputReaderDone: - break; - } - return bytes_len; -} - void Driver::MainLoop () { -#if defined(_MSC_VER) - m_editline_slave_fh = stdin; - FILE *editline_output_slave_fh = stdout; - lldb_utility::PseudoTerminal editline_output_pty; -#else - - char error_str[1024]; - if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false) - { - ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str); - exit(1); - } - else - { - const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str)); - if (driver_slave_name == NULL) - { - ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str); - exit(2); - } - else - { - m_editline_slave_fh = ::fopen (driver_slave_name, "r+"); - if (m_editline_slave_fh == NULL) - { - SBError error; - error.SetErrorToErrno(); - ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s", - error.GetCString()); - exit(3); - } - - ::setbuf (m_editline_slave_fh, NULL); - } - } - - lldb_utility::PseudoTerminal editline_output_pty; - FILE *editline_output_slave_fh = NULL; - - if (editline_output_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, sizeof (error_str)) == false) - { - ::fprintf (stderr, "error: failed to open output pseudo terminal : %s", error_str); - exit(1); - } - else - { - const char *output_slave_name = editline_output_pty.GetSlaveName (error_str, sizeof(error_str)); - if (output_slave_name == NULL) - { - ::fprintf (stderr, "error: failed to get slave name for output pseudo terminal : %s", error_str); - exit(2); - } - else - { - editline_output_slave_fh = ::fopen (output_slave_name, "r+"); - if (editline_output_slave_fh == NULL) - { - SBError error; - error.SetErrorToErrno(); - ::fprintf (stderr, "error: failed to get open slave for output pseudo terminal : %s", - error.GetCString()); - exit(3); - } - ::setbuf (editline_output_slave_fh, NULL); - } - } -#endif - - // struct termios stdin_termios; - if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; @@ -1394,43 +861,6 @@ Driver::MainLoop () m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); - // You have to drain anything that comes to the master side of the PTY. master_out_comm is - // for that purpose. The reason you need to do this is a curious reason... editline will echo - // characters to the PTY when it gets characters while el_gets is not running, and then when - // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks - // if there are unconsumed characters in the out buffer. - // However, you don't need to do anything with the characters, since editline will dump these - // unconsumed characters after printing the prompt again in el_gets. - - SBCommunication master_out_comm("driver.editline"); - master_out_comm.SetCloseOnEOF (false); - master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false); - master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this); - - if (master_out_comm.ReadThreadStart () == false) - { - ::fprintf (stderr, "error: failed to start master out read thread"); - exit(5); - } - - SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); - - m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this)); - -#if !defined (_MSC_VER) - SBCommunication out_comm_2("driver.editline_output"); - out_comm_2.SetCloseOnEOF (false); - out_comm_2.AdoptFileDesriptor (editline_output_pty.GetMasterFileDescriptor(), false); - out_comm_2.SetReadThreadBytesReceivedCallback (IOChannel::LibeditOutputBytesReceived, m_io_channel_ap.get()); - - if (out_comm_2.ReadThreadStart () == false) - { - ::fprintf (stderr, "error: failed to start libedit output read thread"); - exit (5); - } -#endif - - struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) @@ -1439,286 +869,114 @@ Driver::MainLoop () m_debugger.SetTerminalWidth (window_size.ws_col); } - // Since input can be redirected by the debugger, we must insert our editline - // input reader in the queue so we know when our reader should be active - // and so we can receive bytes only when we are supposed to. - SBError err (m_editline_reader.Initialize (m_debugger, - Driver::EditLineInputReaderCallback, // callback - this, // baton - eInputReaderGranularityByte, // token_size - NULL, // end token - NULL means never done - NULL, // prompt - taken care of elsewhere - false)); // echo input - don't need Debugger - // to do this, we handle it elsewhere + SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); - if (err.Fail()) + // Before we handle any options from the command line, we parse the + // .lldbinit file in the user's home directory. + SBCommandReturnObject result; + sb_interpreter.SourceInitFileInHomeDirectory(result); + if (GetDebugMode()) { - ::fprintf (stderr, "error: %s", err.GetCString()); - exit (6); + result.PutError (m_debugger.GetErrorFileHandle()); + result.PutOutput (m_debugger.GetOutputFileHandle()); } - - m_debugger.PushInputReader (m_editline_reader); - SBListener listener(m_debugger.GetListener()); - if (listener.IsValid()) + // Now we handle options we got from the command line + // First source in the commands specified to be run before the file arguments are processed. + ExecuteInitialCommands(true); + + // Was there a core file specified? + std::string core_file_spec(""); + if (!m_option_data.m_core_file.empty()) + core_file_spec.append("--core ").append(m_option_data.m_core_file); + + char command_string[PATH_MAX * 2]; + const size_t num_args = m_option_data.m_args.size(); + if (num_args > 0) { - - listener.StartListeningForEventClass(m_debugger, - SBTarget::GetBroadcasterClassName(), - SBTarget::eBroadcastBitBreakpointChanged); - listener.StartListeningForEventClass(m_debugger, - SBThread::GetBroadcasterClassName(), - SBThread::eBroadcastBitStackChanged | - SBThread::eBroadcastBitThreadSelected); - listener.StartListeningForEvents (*m_io_channel_ap, - IOChannel::eBroadcastBitHasUserInput | - IOChannel::eBroadcastBitUserInterrupt | - IOChannel::eBroadcastBitThreadShouldExit | - IOChannel::eBroadcastBitThreadDidStart | - IOChannel::eBroadcastBitThreadDidExit); - - if (m_io_channel_ap->Start ()) + char arch_name[64]; + if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) + ::snprintf (command_string, + sizeof (command_string), + "target create --arch=%s %s \"%s\"", + arch_name, + core_file_spec.c_str(), + m_option_data.m_args[0].c_str()); + else + ::snprintf (command_string, + sizeof(command_string), + "target create %s \"%s\"", + core_file_spec.c_str(), + m_option_data.m_args[0].c_str()); + + m_debugger.HandleCommand (command_string); + + if (num_args > 1) { - bool iochannel_thread_exited = false; - - listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(), - SBCommandInterpreter::eBroadcastBitQuitCommandReceived | - SBCommandInterpreter::eBroadcastBitAsynchronousOutputData | - SBCommandInterpreter::eBroadcastBitAsynchronousErrorData); - - // Before we handle any options from the command line, we parse the - // .lldbinit file in the user's home directory. - SBCommandReturnObject result; - sb_interpreter.SourceInitFileInHomeDirectory(result); - if (GetDebugMode()) - { - result.PutError (m_debugger.GetErrorFileHandle()); - result.PutOutput (m_debugger.GetOutputFileHandle()); - } - - // Now we handle options we got from the command line - // First source in the commands specified to be run before the file arguments are processed. - ExecuteInitialCommands(true); - - // Was there a core file specified? - std::string core_file_spec(""); - if (!m_option_data.m_core_file.empty()) - core_file_spec.append("--core ").append(m_option_data.m_core_file); - - char command_string[PATH_MAX * 2]; - const size_t num_args = m_option_data.m_args.size(); - if (num_args > 0) - { - char arch_name[64]; - if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) - ::snprintf (command_string, - sizeof (command_string), - "target create --arch=%s %s \"%s\"", - arch_name, - core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - else - ::snprintf (command_string, - sizeof(command_string), - "target create %s \"%s\"", - core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - - m_debugger.HandleCommand (command_string); - - if (num_args > 1) - { - m_debugger.HandleCommand ("settings clear target.run-args"); - char arg_cstr[1024]; - for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) - { - ::snprintf (arg_cstr, - sizeof(arg_cstr), - "settings append target.run-args \"%s\"", - m_option_data.m_args[arg_idx].c_str()); - m_debugger.HandleCommand (arg_cstr); - } - } - } - else if (!core_file_spec.empty()) - { - ::snprintf (command_string, - sizeof(command_string), - "target create %s", - core_file_spec.c_str()); - m_debugger.HandleCommand (command_string);; - } - - // Now that all option parsing is done, we try and parse the .lldbinit - // file in the current working directory - sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); - if (GetDebugMode()) - { - result.PutError(m_debugger.GetErrorFileHandle()); - result.PutOutput(m_debugger.GetOutputFileHandle()); - } - - // Now execute the commands specified for after the file arguments are processed. - ExecuteInitialCommands(false); - - SBEvent event; - - // Make sure the IO channel is started up before we try to tell it we - // are ready for input - listener.WaitForEventForBroadcasterWithType (UINT32_MAX, - *m_io_channel_ap, - IOChannel::eBroadcastBitThreadDidStart, - event); - // If we were asked to attach, then do that here: - // I'm going to use the command string rather than directly - // calling the API's because then I don't have to recode the - // event handling here. - if (!m_option_data.m_process_name.empty() - || m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID) + m_debugger.HandleCommand ("settings clear target.run-args"); + char arg_cstr[1024]; + for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) { - std::string command_str("process attach "); - if (m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID) - { - command_str.append("-p "); - char pid_buffer[32]; - ::snprintf (pid_buffer, sizeof(pid_buffer), "%" PRIu64, m_option_data.m_process_pid); - command_str.append(pid_buffer); - } - else - { - command_str.append("-n \""); - command_str.append(m_option_data.m_process_name); - command_str.push_back('\"'); - if (m_option_data.m_wait_for) - command_str.append(" -w"); - } - - if (m_debugger.GetOutputFileHandle()) - ::fprintf (m_debugger.GetOutputFileHandle(), - "Attaching to process with:\n %s\n", - command_str.c_str()); - - // Force the attach to be synchronous: - bool orig_async = m_debugger.GetAsync(); - m_debugger.SetAsync(true); - m_debugger.HandleCommand(command_str.c_str()); - m_debugger.SetAsync(orig_async); + ::snprintf (arg_cstr, + sizeof(arg_cstr), + "settings append target.run-args \"%s\"", + m_option_data.m_args[arg_idx].c_str()); + m_debugger.HandleCommand (arg_cstr); } - - ReadyForCommand (); - - while (!GetIsDone()) - { - listener.WaitForEvent (UINT32_MAX, event); - if (event.IsValid()) - { - if (event.GetBroadcaster().IsValid()) - { - uint32_t event_type = event.GetType(); - if (event.BroadcasterMatchesRef (*m_io_channel_ap)) - { - if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || - (event_type & IOChannel::eBroadcastBitThreadDidExit)) - { - SetIsDone(); - if (event_type & IOChannel::eBroadcastBitThreadDidExit) - iochannel_thread_exited = true; - } - else - { - if (HandleIOEvent (event)) - SetIsDone(); - } - } - else if (SBProcess::EventIsProcessEvent (event)) - { - HandleProcessEvent (event); - } - else if (SBBreakpoint::EventIsBreakpointEvent (event)) - { - HandleBreakpointEvent (event); - } - else if (SBThread::EventIsThreadEvent (event)) - { - HandleThreadEvent (event); - } - else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster())) - { - // TODO: deprecate the eBroadcastBitQuitCommandReceived event - // now that we have SBCommandInterpreter::SetCommandOverrideCallback() - // that can take over a command - if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived) - { - SetIsDone(); - } - else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousErrorData) - { - const char *data = SBEvent::GetCStringFromEvent (event); - m_io_channel_ap->ErrWrite (data, strlen(data), ASYNC); - } - else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousOutputData) - { - const char *data = SBEvent::GetCStringFromEvent (event); - m_io_channel_ap->OutWrite (data, strlen(data), ASYNC); - } - } - } - } - } - - master_out_comm.SetReadThreadBytesReceivedCallback(NULL, NULL); - master_out_comm.Disconnect(); - master_out_comm.ReadThreadStop(); - -#if !defined(_MSC_VER) - out_comm_2.SetReadThreadBytesReceivedCallback(NULL, NULL); - out_comm_2.Disconnect(); - out_comm_2.ReadThreadStop(); -#endif - - editline_output_pty.CloseMasterFileDescriptor(); - reset_stdin_termios(); - fclose (stdin); - - CloseIOChannelFile (); - - if (!iochannel_thread_exited) - { - event.Clear(); - listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap, - IOChannel::eBroadcastBitThreadDidExit, - event); - if (!event.IsValid()) - { - // Send end EOF to the driver file descriptor - m_io_channel_ap->Stop(); - } - } - - SBDebugger::Destroy (m_debugger); } } -} + else if (!core_file_spec.empty()) + { + ::snprintf (command_string, + sizeof(command_string), + "target create %s", + core_file_spec.c_str()); + m_debugger.HandleCommand (command_string);; + } + else if (!m_option_data.m_process_name.empty()) + { + ::snprintf (command_string, + sizeof(command_string), + "process attach --name '%s'%s", + m_option_data.m_process_name.c_str(), + m_option_data.m_wait_for ? " --waitfor" : ""); + m_debugger.HandleCommand (command_string); + } + else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) + { + ::snprintf (command_string, + sizeof(command_string), + "process attach --pid %" PRIu64, + m_option_data.m_process_pid); + m_debugger.HandleCommand (command_string); + } + ExecuteInitialCommands(false); -void -Driver::ReadyForCommand () -{ - if (m_waiting_for_command == false) + // Now that all option parsing is done, we try and parse the .lldbinit + // file in the current working directory + sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); + if (GetDebugMode()) { - m_waiting_for_command = true; - BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true); + result.PutError(m_debugger.GetErrorFileHandle()); + result.PutOutput(m_debugger.GetOutputFileHandle()); } + + bool handle_events = true; + bool spawn_thread = false; + m_debugger.RunCommandInterpreter(handle_events, spawn_thread); + + reset_stdin_termios(); + fclose (stdin); + + SBDebugger::Destroy (m_debugger); } + void Driver::ResizeWindow (unsigned short col) { GetDebugger().SetTerminalWidth (col); - if (m_io_channel_ap.get() != NULL) - { - m_io_channel_ap->ElResize(); - } } void diff --git a/contrib/llvm/tools/lldb/tools/driver/Driver.h b/contrib/llvm/tools/lldb/tools/driver/Driver.h index dcfd5ed..6992446 100644 --- a/contrib/llvm/tools/lldb/tools/driver/Driver.h +++ b/contrib/llvm/tools/lldb/tools/driver/Driver.h @@ -22,27 +22,15 @@ #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBError.h" -#include "lldb/API/SBInputReader.h" #define ASYNC true #define NO_ASYNC false class IOChannel; -namespace lldb -{ - class SBInputReader; -} - - class Driver : public lldb::SBBroadcaster { public: - enum { - eBroadcastBitReadyForInput = (1 << 0), - eBroadcastBitThreadShouldExit = (1 << 1) - }; - Driver (); virtual @@ -51,24 +39,6 @@ public: void MainLoop (); - void - PutSTDIN (const char *src, size_t src_len); - - void - GetFromMaster (const char *src, size_t src_len); - - bool - HandleIOEvent (const lldb::SBEvent &event); - - void - HandleProcessEvent (const lldb::SBEvent &event); - - void - HandleBreakpointEvent (const lldb::SBEvent &event); - - void - HandleThreadEvent (const lldb::SBEvent &event); - lldb::SBError ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &do_exit); @@ -137,66 +107,16 @@ public: return m_debugger; } - bool - EditlineReaderIsTop () - { - return m_debugger.InputReaderIsTopReader (m_editline_reader); - } - - bool - GetIsDone () const - { - return m_done; - } - - void - SetIsDone () - { - m_done = true; - } - void ResizeWindow (unsigned short col); private: lldb::SBDebugger m_debugger; - lldb_utility::PseudoTerminal m_editline_pty; - FILE *m_editline_slave_fh; - lldb::SBInputReader m_editline_reader; - std::unique_ptr<IOChannel> m_io_channel_ap; OptionData m_option_data; - bool m_executing_user_command; - bool m_waiting_for_command; - bool m_done; void ResetOptionValues (); - size_t - GetProcessSTDOUT (); - - size_t - GetProcessSTDERR (); - - void - UpdateSelectedThread (); - - void - CloseIOChannelFile (); - - static size_t - EditLineInputReaderCallback (void *baton, - lldb::SBInputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - static void - ReadThreadBytesReceived (void *baton, const void *src, size_t src_len); - - static void - MasterThreadBytesReceived (void *baton, const void *src, size_t src_len); - void ReadyForCommand (); }; diff --git a/contrib/llvm/tools/lldb/tools/driver/ELWrapper.cpp b/contrib/llvm/tools/lldb/tools/driver/ELWrapper.cpp deleted file mode 100644 index 258f47e..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/ELWrapper.cpp +++ /dev/null @@ -1,422 +0,0 @@ -//===-- ELWrapper.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// this file is only relevant for Visual C++ -#if defined( _MSC_VER ) - -#include "lldb/Host/windows/windows.h" - -#include "ELWrapper.h" -#include <vector> -#include <assert.h> - -// index one of the variable arguments -// presuming "(EditLine *el, ..." is first in the argument list -#define GETARG( X ) ( (void* ) *( ( (int**) &el ) + ((X) + 2) ) ) - -// edit line EL_ADDFN function pointer type -typedef unsigned char (*el_addfn_func)(EditLine *e, int ch); - -// edit line wrapper binding container -struct el_binding -{ - // - const char *name; - const char *help; - // function pointer to callback routine - el_addfn_func func; - // ascii key this function is bound to - const char *key; -}; - -// stored key bindings -static std::vector<el_binding*> _bindings; - -//TODO: this should infact be related to the exact edit line context we create -static void *clientData = NULL; - -// store the current prompt string -// default to what we expect to receive anyway -static const char *_prompt = "(lldb) "; - -#if !defined( _WIP_INPUT_METHOD ) - -static char * -el_get_s (char *buffer, int chars) -{ - return gets_s(buffer, chars); -} -#else - -static void -con_output (char _in) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get the cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // output this char - WriteConsoleOutputCharacterA( hout, &_in, 1, info.dwCursorPosition, &written ); - // advance cursor position - info.dwCursorPosition.X++; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); -} - -static void -con_backspace (void) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // nudge cursor backwards - info.dwCursorPosition.X--; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); - // blank out the last character - WriteConsoleOutputCharacterA( hout, " ", 1, info.dwCursorPosition, &written ); -} - -static void -con_return (void) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // move onto the new line - info.dwCursorPosition.X = 0; - info.dwCursorPosition.Y++; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); -} - -static bool -runBind (char _key) -{ - for ( int i=0; i<_bindings.size(); i++ ) - { - el_binding *bind = _bindings[i]; - if ( bind->key[0] == _key ) - { - bind->func( (EditLine*) -1, _key ); - return true; - } - } - return false; -} - -// replacement get_s which is EL_BIND aware -static char * -el_get_s (char *buffer, int chars) -{ - // - char *head = buffer; - // - for ( ;; Sleep( 10 ) ) - { - // - INPUT_RECORD _record; - // - DWORD _read = 0; - if ( ReadConsoleInputA( GetStdHandle( STD_INPUT_HANDLE ), &_record, 1, &_read ) == FALSE ) - break; - // if we didnt read a key - if ( _read == 0 ) - continue; - // only interested in key events - if ( _record.EventType != KEY_EVENT ) - continue; - // is the key down - if (! _record.Event.KeyEvent.bKeyDown ) - continue; - // read the ascii key character - char _key = _record.Event.KeyEvent.uChar.AsciiChar; - // non ascii conformant key press - if ( _key == 0 ) - { - // check the scan code - // if VK_UP scroll back through history - // if VK_DOWN scroll forward through history - continue; - } - // try to execute any bind this key may have - if ( runBind( _key ) ) - continue; - // if we read a return key - if ( _key == '\n' || _key == '\r' ) - { - con_return( ); - break; - } - // key is backspace - if ( _key == 0x8 ) - { - // avoid deleting past beginning - if ( head > buffer ) - { - con_backspace( ); - head--; - } - continue; - } - - // add this key to the input buffer - if ( (head-buffer) < (chars-1) ) - { - con_output( _key ); - *(head++) = _key; - } - } - // insert end of line character - *head = '\0'; - - return buffer; -} -#endif - -// edit line initalise -EditLine * -el_init (const char *, FILE *, FILE *, FILE *) -{ - // - SetConsoleTitleA( "lldb" ); - // return dummy handle - return (EditLine*) -1; -} - -const char * -el_gets (EditLine *el, int *length) -{ - // print the prompt if we have one - if ( _prompt != NULL ) - printf( _prompt ); - // create a buffer for the user input - char *buffer = new char[ MAX_PATH ]; - // try to get user input string - if ( el_get_s( buffer, MAX_PATH ) ) - { - // get the string length in 'length' - while ( buffer[ *length ] != '\0' ) - (*length)++; - // return the input buffer - // remember that this memory has the be free'd somewhere - return buffer; - } - else - { - // on error - delete [] buffer; - return NULL; - } -} - -int -el_set (EditLine *el, int code, ...) -{ - int **arg = (int**) ⪙ - // - switch ( code ) - { - // edit line set prompt message - case ( EL_PROMPT ): - { - // EL_PROMPT, char *(*f)( EditLine *) - // define a prompt printing function as 'f', which is to return a string that - // contains the prompt. - - // get the function pointer from the arg list - void *func_vp = (void*) *(arg+2); - // cast to suitable prototype - const char* (*func_fp)(EditLine*) = (const char*(*)(EditLine *)) func_vp; - // call to get the prompt as a string - _prompt = func_fp( el ); - } - break; - case ( EL_EDITOR ): - { - // EL_EDITOR, const char *mode - // set editing mode to "emacs" or "vi" - } - break; - case ( EL_HIST ): - { - // EL_HIST, History *(*fun)(History *, int op, ... ), const char *ptr - // defines which histroy function to use, which is usualy history(). Ptr should be the - // value returned by history_init(). - } - break; - case ( EL_ADDFN ): - { - // EL_ADDFN, const char *name, const char *help, unsigned char (*func)(EditLine *e, int ch) - // add a user defined function, func), referred to as 'name' which is invoked when a key which is bound to 'name' is - // entered. 'help' is a description of 'name'. at involcation time, 'ch' is the key which caused the invocation. the - // return value of 'func()' should be one of: - // CC_NORM add a normal character - // CC_NEWLINE end of line was entered - // CC_EOF EOF was entered - // CC_ARGHACK expecting further command input as arguments, do nothing visually. - // CC_REFRESH refresh display. - // CC_REFRESH_BEEP refresh display and beep. - // CC_CURSOR cursor moved so update and perform CC_REFRESH - // CC_REDISPLAY redisplay entire input line. this is usefull if a key binding outputs extra information. - // CC_ERROR an error occured. beep and flush tty. - // CC_FATAL fatal error, reset tty to known state. - - el_binding *binding = new el_binding; - binding->name = (const char *) GETARG( 0 ); - binding->help = (const char *) GETARG( 1 ); - binding->func = (el_addfn_func) GETARG( 2 ); - binding->key = 0; - // add this to the bindings list - _bindings.push_back( binding ); - } - break; - case ( EL_BIND ): - { - // EL_BIND, const char *, ..., NULL - // perform the BIND buildin command. Refer to editrc(5) for more information. - - const char *name = (const char*) GETARG( 1 ); - - for ( int i=0; i<_bindings.size(); i++ ) - { - el_binding *bind = _bindings[i]; - if ( strcmp( bind->name, name ) == 0 ) - { - bind->key = (const char *) GETARG( 0 ); - break; - } - } - - } - break; - case ( EL_CLIENTDATA ): - { - clientData = GETARG( 0 ); - } - break; - default: - assert( !"Not Implemented!" ); - } - return 0; -} - -void -el_end (EditLine *el) -{ - assert( !"Not implemented!" ); -} - -void -el_reset (EditLine *) -{ - assert( !"Not implemented!" ); -} - -int -el_getc (EditLine *, char *) -{ - assert( !"Not implemented!" ); - return 0; -} - -void -el_push (EditLine *, char *) -{ - assert( !"Not implemented!" ); -} - -void -el_beep (EditLine *) -{ - Beep( 1000, 500 ); -} - -int -el_parse (EditLine *, int, const char **) -{ - assert( !"Not implemented!" ); - return 0; -} - -int -el_get (EditLine *el, int code, ...) -{ - switch ( code ) - { - case ( EL_CLIENTDATA ): - { - void **dout = (void**) GETARG( 0 ); - *dout = clientData; - } - break; - default: - assert( !"Not implemented!" ); - } - return 0; -} - -int -el_source (EditLine *el, const char *file) -{ - // init edit line by reading the contents of 'file' - // nothing to do here on windows... - return 0; -} - -void -el_resize (EditLine *) -{ - assert( !"Not implemented!" ); -} - -const LineInfo * -el_line (EditLine *el) -{ - assert( !"Not implemented!" ); - return 0; -} - -int -el_insertstr (EditLine *, const char *) -{ - assert( !"Not implemented!" ); - return 0; -} - -void -el_deletestr (EditLine *, int) -{ - assert( !"Not implemented!" ); -} - -History * -history_init (void) -{ - // return dummy handle - return (History*) -1; -} - -void -history_end (History *) -{ - assert( !"Not implemented!" ); -} - -int -history (History *, HistEvent *, int op, ...) -{ - // perform operation 'op' on the history list with optional argumetns as needed by - // the operation. - return 0; -} - -#endif diff --git a/contrib/llvm/tools/lldb/tools/driver/ELWrapper.h b/contrib/llvm/tools/lldb/tools/driver/ELWrapper.h deleted file mode 100644 index a30182d..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/ELWrapper.h +++ /dev/null @@ -1,122 +0,0 @@ -//===-- ELWrapper.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include <stdio.h> - -// EditLine editor function return codes. -// For user-defined function interface -#define CC_NORM 0 -#define CC_NEWLINE 1 -#define CC_EOF 2 -#define CC_ARGHACK 3 -#define CC_REFRESH 4 -#define CC_CURSOR 5 -#define CC_ERROR 6 -#define CC_FATAL 7 -#define CC_REDISPLAY 8 -#define CC_REFRESH_BEEP 9 - -// el_set/el_get parameters -#define EL_PROMPT 0 // , el_pfunc_t -#define EL_TERMINAL 1 // , const char * -#define EL_EDITOR 2 // , const char * -#define EL_SIGNAL 3 // , int); -#define EL_BIND 4 // , const char *, ..., NULL -#define EL_TELLTC 5 // , const char *, ..., NULL -#define EL_SETTC 6 // , const char *, ..., NULL -#define EL_ECHOTC 7 // , const char *, ..., NULL -#define EL_SETTY 8 // , const char *, ..., NULL -#define EL_ADDFN 9 // , const char *, const char *, el_func_t -#define EL_HIST 10 // , hist_fun_t, const char * -#define EL_EDITMODE 11 // , int -#define EL_RPROMPT 12 // , el_pfunc_t -#define EL_GETCFN 13 // , el_rfunc_t -#define EL_CLIENTDATA 14 // , void * -#define EL_UNBUFFERED 15 // , int -#define EL_PREP_TERM 16 // , int -#define EL_GETTC 17 // , const char *, ..., NULL -#define EL_GETFP 18 // , int, FILE ** -#define EL_SETFP 19 // , int, FILE * -#define EL_REFRESH 20 // , void - -#define EL_BUILTIN_GETCFN (NULL) - -// history defines -#define H_FUNC 0 // , UTSL -#define H_SETSIZE 1 // , const int -#define H_GETSIZE 2 // , void -#define H_FIRST 3 // , void -#define H_LAST 4 // , void -#define H_PREV 5 // , void -#define H_NEXT 6 // , void -#define H_CURR 8 // , const int -#define H_SET 7 // , int -#define H_ADD 9 // , const char * -#define H_ENTER 10 // , const char * -#define H_APPEND 11 // , const char * -#define H_END 12 // , void -#define H_NEXT_STR 13 // , const char * -#define H_PREV_STR 14 // , const char * -#define H_NEXT_EVENT 15 // , const int -#define H_PREV_EVENT 16 // , const int -#define H_LOAD 17 // , const char * -#define H_SAVE 18 // , const char * -#define H_CLEAR 19 // , void -#define H_SETUNIQUE 20 // , int -#define H_GETUNIQUE 21 // , void -#define H_DEL 22 // , int - -struct EditLine -{ -}; - -struct LineInfo -{ - const char *buffer; - const char *cursor; - const char *lastchar; -}; - -struct History -{ -}; - -struct HistEvent -{ - int num; - const char *str; -}; - -extern "C" -{ - // edit line API - EditLine *el_init ( const char *, FILE *, FILE *, FILE * ); - const char *el_gets ( EditLine *, int * ); - int el_set ( EditLine *, int, ... ); - - void el_end ( EditLine * ); - void el_reset ( EditLine * ); - int el_getc ( EditLine *, char * ); - void el_push ( EditLine *, char * ); - void el_beep ( EditLine * ); - int el_parse ( EditLine *, int, const char ** ); - int el_get ( EditLine *, int, ... ); - int el_source ( EditLine *, const char * ); - void el_resize ( EditLine * ); - const LineInfo *el_line ( EditLine * ); - int el_insertstr( EditLine *, const char * ); - void el_deletestr( EditLine *, int ); - - // history API - History *history_init( void ); - void history_end ( History * ); - int history ( History *, HistEvent *, int, ... ); -};
\ No newline at end of file diff --git a/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.cpp b/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.cpp deleted file mode 100644 index e7cdfd7..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- GetOptWrapper.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// this file is only relevant for Visual C++ -#if defined( _MSC_VER ) - -#include "GetOptWrapper.h" - -/* - -// already defined in lldbHostCommon.lib due to 'getopt.inc' - -extern int -getopt_long_only -( - int ___argc, - char *const *___argv, - const char *__shortopts, - const struct option *__longopts, - int *__longind -) -{ - return -1; -} -*/ - -#endif
\ No newline at end of file diff --git a/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.h b/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.h deleted file mode 100644 index 9c9cf03..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/GetOptWrapper.h +++ /dev/null @@ -1,49 +0,0 @@ -//===-- GetOptWrapper.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_GetOptWrapper_h_ -#define lldb_GetOptWrapper_h_ - -// from getopt.h -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -// defined int unistd.h -extern int optreset; - -// from getopt.h -extern char *optarg; -extern int optind; -extern int opterr; -extern int optopt; - -// option structure -struct option -{ - const char *name; - // has_arg can't be an enum because some compilers complain about - // type mismatches in all the code that assumes it is an int. - int has_arg; - int *flag; - int val; -}; - -// -extern int -getopt_long_only -( - int ___argc, - char *const *___argv, - const char *__shortopts, - const struct option *__longopts, - int *__longind -); - -#endif // lldb_GetOptWrapper_h_
\ No newline at end of file diff --git a/contrib/llvm/tools/lldb/tools/driver/IOChannel.cpp b/contrib/llvm/tools/lldb/tools/driver/IOChannel.cpp deleted file mode 100644 index 7cba73a..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/IOChannel.cpp +++ /dev/null @@ -1,656 +0,0 @@ -//===-- IOChannel.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Platform.h" -#include "IOChannel.h" - -#include <map> - -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBEvent.h" -#include "lldb/API/SBFileSpec.h" -#include "lldb/API/SBHostOS.h" -#include "lldb/API/SBListener.h" -#include "lldb/API/SBStringList.h" - -#include <string.h> -#include <limits.h> - -using namespace lldb; - -typedef std::map<EditLine *, std::string> PromptMap; -const char *g_default_prompt = "(lldb) "; -PromptMap g_prompt_map; - -// Printing the following string causes libedit to back up to the beginning of the line & blank it out. -const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75}; - -static const char* -el_prompt(EditLine *el) -{ - PromptMap::const_iterator pos = g_prompt_map.find (el); - if (pos == g_prompt_map.end()) - return g_default_prompt; - return pos->second.c_str(); -} - -const char * -IOChannel::GetPrompt () -{ - PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line); - if (pos == g_prompt_map.end()) - return g_default_prompt; - return pos->second.c_str(); -} - -bool -IOChannel::EditLineHasCharacters () -{ - const LineInfo *line_info = el_line(m_edit_line); - if (line_info) - { - // Sometimes we get called after the user has submitted the line, but before editline has - // cleared the buffer. In that case the cursor will be pointing at the newline. That's - // equivalent to having no characters on the line, since it has already been submitted. - if (*line_info->cursor == '\n') - return false; - else - return line_info->cursor != line_info->buffer; - } - else - return false; -} - - -void -IOChannel::EraseCharsBeforeCursor () -{ - const LineInfo *line_info = el_line(m_edit_line); - if (line_info != NULL) - el_deletestr(m_edit_line, line_info->cursor - line_info->buffer); -} - -unsigned char -IOChannel::ElCompletionFn (EditLine *e, int ch) -{ - IOChannel *io_channel; - if (el_get(e, EL_CLIENTDATA, &io_channel) == 0) - { - return io_channel->HandleCompletion (e, ch); - } - else - { - return CC_ERROR; - } -} - -void -IOChannel::ElResize() -{ - el_resize(m_edit_line); -} - -unsigned char -IOChannel::HandleCompletion (EditLine *e, int ch) -{ - assert (e == m_edit_line); - - const LineInfo *line_info = el_line(m_edit_line); - SBStringList completions; - int page_size = 40; - - int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer, - line_info->cursor, - line_info->lastchar, - 0, - -1, - completions); - - if (num_completions == -1) - { - el_insertstr (m_edit_line, m_completion_key); - return CC_REDISPLAY; - } - else if (num_completions == -2) - { - el_deletestr (m_edit_line, line_info->cursor - line_info->buffer); - el_insertstr (m_edit_line, completions.GetStringAtIndex(0)); - return CC_REDISPLAY; - } - - // If we get a longer match display that first. - const char *completion_str = completions.GetStringAtIndex(0); - if (completion_str != NULL && *completion_str != '\0') - { - el_insertstr (m_edit_line, completion_str); - return CC_REDISPLAY; - } - - if (num_completions > 1) - { - const char *comment = "\nAvailable completions:"; - - int num_elements = num_completions + 1; - OutWrite(comment, strlen (comment), NO_ASYNC); - if (num_completions < page_size) - { - for (int i = 1; i < num_elements; i++) - { - completion_str = completions.GetStringAtIndex(i); - OutWrite("\n\t", 2, NO_ASYNC); - OutWrite(completion_str, strlen (completion_str), NO_ASYNC); - } - OutWrite ("\n", 1, NO_ASYNC); - } - else - { - int cur_pos = 1; - char reply; - int got_char; - while (cur_pos < num_elements) - { - int endpoint = cur_pos + page_size; - if (endpoint > num_elements) - endpoint = num_elements; - for (; cur_pos < endpoint; cur_pos++) - { - completion_str = completions.GetStringAtIndex(cur_pos); - OutWrite("\n\t", 2, NO_ASYNC); - OutWrite(completion_str, strlen (completion_str), NO_ASYNC); - } - - if (cur_pos >= num_elements) - { - OutWrite("\n", 1, NO_ASYNC); - break; - } - - OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC); - reply = 'n'; - got_char = el_getc(m_edit_line, &reply); - if (got_char == -1 || reply == 'n') - break; - if (reply == 'a') - page_size = num_elements - cur_pos; - } - } - - } - - if (num_completions == 0) - return CC_REFRESH_BEEP; - else - return CC_REDISPLAY; -} - -IOChannel::IOChannel -( - FILE *editline_in, - FILE *editline_out, - FILE *out, - FILE *err, - Driver *driver -) : - SBBroadcaster ("IOChannel"), - m_output_mutex (), - m_enter_elgets_time (), - m_driver (driver), - m_read_thread (LLDB_INVALID_HOST_THREAD), - m_read_thread_should_exit (false), - m_out_file (out), - m_err_file (err), - m_editline_out (editline_out), - m_command_queue (), - m_completion_key ("\t"), - m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)), - m_history (history_init()), - m_history_event(), - m_getting_command (false), - m_expecting_prompt (false), - m_prompt_str (), - m_refresh_request_pending (false) -{ - assert (m_edit_line); - el_set (m_edit_line, EL_PROMPT, el_prompt); - el_set (m_edit_line, EL_EDITOR, "emacs"); - el_set (m_edit_line, EL_HIST, history, m_history); - el_set (m_edit_line, EL_ADDFN, "lldb_complete", "LLDB completion function", IOChannel::ElCompletionFn); - el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL); - el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string - el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. - el_set (m_edit_line, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. - el_set (m_edit_line, EL_CLIENTDATA, this); - - // Source $PWD/.editrc then $HOME/.editrc - el_source (m_edit_line, NULL); - - assert (m_history); - history (m_history, &m_history_event, H_SETSIZE, 800); - history (m_history, &m_history_event, H_SETUNIQUE, 1); - // Load history - HistorySaveLoad (false); - - // Initialize time that ::el_gets was last called. - m_enter_elgets_time.tv_sec = 0; - m_enter_elgets_time.tv_usec = 0; - - // set the initial state to non flushed - m_output_flushed = false; -} - -IOChannel::~IOChannel () -{ - // Save history - HistorySaveLoad (true); - - if (m_history != NULL) - { - ::history_end (m_history); - m_history = NULL; - } - - if (m_edit_line != NULL) - { - ::el_end (m_edit_line); - m_edit_line = NULL; - } -} - -void -IOChannel::HistorySaveLoad (bool save) -{ - if (m_history != NULL) - { - char history_path[PATH_MAX]; - ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename()); - if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1) - { - const char *path_ptr = history_path; - if (save) - ::history (m_history, &m_history_event, H_SAVE, path_ptr); - else - ::history (m_history, &m_history_event, H_LOAD, path_ptr); - } - } -} - -void -IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len) -{ - IOChannel *io_channel = (IOChannel *) baton; - std::lock_guard<std::recursive_mutex> locker(io_channel->m_output_mutex); - const char *bytes = (const char *) src; - - bool flush = false; - - // See if we have a 'flush' synchronization point in there. - // this is performed from 'fputc ('\0', m_editline_out);' in LibeditGetInput() - if (src_len > 0 && bytes[src_len-1] == '\0') - { - src_len--; - flush = true; - } - - if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt) - { - io_channel->m_prompt_str.append (bytes, src_len); - // Log this to make sure the prompt is really what you think it is. - if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0) - { - io_channel->m_expecting_prompt = false; - io_channel->m_refresh_request_pending = false; - io_channel->OutWrite (io_channel->m_prompt_str.c_str(), - io_channel->m_prompt_str.size(), NO_ASYNC); - io_channel->m_prompt_str.clear(); - } - } - else - { - if (io_channel->m_prompt_str.size() > 0) - io_channel->m_prompt_str.clear(); - std::string tmp_str (bytes, src_len); - if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0) - io_channel->m_refresh_request_pending = false; - io_channel->OutWrite (bytes, src_len, NO_ASYNC); - } - -#if !defined (_MSC_VER) - if (flush) - { - io_channel->m_output_flushed = true; - io_channel->m_output_cond.notify_all(); - } -#endif - -} - -IOChannel::LibeditGetInputResult -IOChannel::LibeditGetInput (std::string &new_line) -{ - IOChannel::LibeditGetInputResult retval = IOChannel::eLibeditGetInputResultUnknown; - if (m_edit_line != NULL) - { - int line_len = 0; - - // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt - // to refresh the prompt after writing data). - SetGettingCommand (true); - m_expecting_prompt = true; - - // Call el_gets to prompt the user and read the user's input. - const char *line = ::el_gets (m_edit_line, &line_len); - -#if !defined (_MSC_VER) - // Force the piped output from el_gets to finish processing. - // el_gets does an fflush internally, which is not sufficient here; it only - // writes the data into m_editline_out, but doesn't affect whether our worker - // thread will read that data yet. So we block here manually. - { - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - m_output_flushed = false; - - // Write a synchronization point into the stream, so we can guarantee - // LibeditOutputBytesReceived has processed everything up till that mark. - fputc ('\0', m_editline_out); - - while (!m_output_flushed) - { - // wait until the condition variable is signaled - m_output_cond.wait(m_output_mutex); - } - } -#endif - - // Re-set the boolean indicating whether or not el_gets is trying to get input. - SetGettingCommand (false); - - if (line) - { - retval = IOChannel::eLibeditGetInputValid; - // strip any newlines off the end of the string... - while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) - --line_len; - if (line_len > 0) - { - ::history (m_history, &m_history_event, H_ENTER, line); - new_line.assign (line, line_len); // Omit the newline - } - else - { - retval = IOChannel::eLibeditGetInputEmpty; - // Someone just hit ENTER, return the empty string - new_line.clear(); - } - // Return true to indicate success even if a string is empty - return retval; - } - else - { - retval = (line_len == 0 ? IOChannel::eLibeditGetInputEOF : IOChannel::eLibeditGetInputResultError); - } - } - // Return false to indicate failure. This can happen when the file handle - // is closed (EOF). - new_line.clear(); - return retval; -} - -thread_result_t -IOChannel::IOReadThread (void *ptr) -{ - IOChannel *myself = static_cast<IOChannel *> (ptr); - myself->Run(); - return NULL; -} - -void -IOChannel::Run () -{ - SBListener listener("IOChannel::Run"); - std::string new_line; - - SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster()); - listener.StartListeningForEvents (interpreter_broadcaster, - SBCommandInterpreter::eBroadcastBitResetPrompt | - SBCommandInterpreter::eBroadcastBitThreadShouldExit | - SBCommandInterpreter::eBroadcastBitQuitCommandReceived); - - listener.StartListeningForEvents (*this, - IOChannel::eBroadcastBitThreadShouldExit); - - listener.StartListeningForEvents (*m_driver, - Driver::eBroadcastBitReadyForInput | - Driver::eBroadcastBitThreadShouldExit); - - // Let anyone know that the IO channel is up and listening and ready for events - BroadcastEventByType (eBroadcastBitThreadDidStart); - bool done = false; - while (!done) - { - SBEvent event; - - listener.WaitForEvent (UINT32_MAX, event); - if (!event.IsValid()) - continue; - - const uint32_t event_type = event.GetType(); - - if (event.GetBroadcaster().IsValid()) - { - if (event.BroadcasterMatchesPtr (m_driver)) - { - if (event_type & Driver::eBroadcastBitReadyForInput) - { - std::string line; - - if (CommandQueueIsEmpty()) - { - IOChannel::LibeditGetInputResult getline_result = LibeditGetInput(line); - if (getline_result == IOChannel::eLibeditGetInputEOF) - { - // EOF occurred - // pretend that a quit was typed so the user gets a potential - // chance to confirm - line.assign("quit"); - } - else if (getline_result == IOChannel::eLibeditGetInputResultError || getline_result == IOChannel::eLibeditGetInputResultUnknown) - { - // some random error occurred, exit and don't ask because the state might be corrupt - done = true; - continue; - } - } - else - { - GetCommandFromQueue (line); - } - - // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN' - // AND TAKE CARE OF THAT HERE. - - SBEvent line_event(IOChannel::eBroadcastBitHasUserInput, - line.c_str(), - line.size()); - BroadcastEvent (line_event); - } - else if (event_type & Driver::eBroadcastBitThreadShouldExit) - { - done = true; - continue; - } - } - else if (event.BroadcasterMatchesRef (interpreter_broadcaster)) - { - switch (event_type) - { - case SBCommandInterpreter::eBroadcastBitResetPrompt: - { - const char *new_prompt = SBEvent::GetCStringFromEvent (event); - if (new_prompt) - g_prompt_map[m_edit_line] = new_prompt; - } - break; - - case SBCommandInterpreter::eBroadcastBitThreadShouldExit: - case SBCommandInterpreter::eBroadcastBitQuitCommandReceived: - done = true; - break; - } - } - else if (event.BroadcasterMatchesPtr (this)) - { - if (event_type & IOChannel::eBroadcastBitThreadShouldExit) - { - done = true; - continue; - } - } - } - } - BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit); - m_driver = NULL; - m_read_thread = 0; -} - -bool -IOChannel::Start () -{ - if (IS_VALID_LLDB_HOST_THREAD(m_read_thread)) - return true; - - m_read_thread = SBHostOS::ThreadCreate("<lldb.driver.commandline_io>", (lldb::thread_func_t) IOChannel::IOReadThread, this, NULL); - - return (IS_VALID_LLDB_HOST_THREAD(m_read_thread)); -} - -bool -IOChannel::Stop () -{ - if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) - return true; - - BroadcastEventByType (eBroadcastBitThreadShouldExit); - - // Don't call Host::ThreadCancel since el_gets won't respond to this - // function call -- the thread will just die and all local variables in - // IOChannel::Run() won't get destructed down which is bad since there is - // a local listener holding onto broadcasters... To ensure proper shutdown, - // a ^D (control-D) sequence (0x04) should be written to other end of the - // the "in" file handle that was passed into the contructor as closing the - // file handle doesn't seem to make el_gets() exit.... - return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL); -} - -void -IOChannel::RefreshPrompt () -{ - // If we are not in the middle of getting input from the user, there is no need to - // refresh the prompt. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (! IsGettingCommand()) - return; - - // If we haven't finished writing the prompt, there's no need to refresh it. - if (m_expecting_prompt) - return; - - if (m_refresh_request_pending) - return; - - ::el_set (m_edit_line, EL_REFRESH); - m_refresh_request_pending = true; -} - -void -IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous) -{ - if (len == 0 || buffer == NULL) - return; - - // We're in the process of exiting -- IOChannel::Run() has already completed - // and set m_driver to NULL - it is time for us to leave now. We might not - // print the final ^D to stdout in this case. We need to do some re-work on - // how the I/O streams are managed at some point. - if (m_driver == NULL) - { - return; - } - - // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (m_driver->EditlineReaderIsTop() && asynchronous) - ::fwrite (undo_prompt_string, 1, 4, m_out_file); - ::fwrite (buffer, 1, len, m_out_file); - if (asynchronous) - m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten); -} - -void -IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous) -{ - if (len == 0 || buffer == NULL) - return; - - // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (asynchronous) - ::fwrite (undo_prompt_string, 1, 4, m_err_file); - ::fwrite (buffer, 1, len, m_err_file); - if (asynchronous) - m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten); -} - -void -IOChannel::AddCommandToQueue (const char *command) -{ - m_command_queue.push (std::string(command)); -} - -bool -IOChannel::GetCommandFromQueue (std::string &cmd) -{ - if (m_command_queue.empty()) - return false; - cmd.swap(m_command_queue.front()); - m_command_queue.pop (); - return true; -} - -int -IOChannel::CommandQueueSize () const -{ - return m_command_queue.size(); -} - -void -IOChannel::ClearCommandQueue () -{ - while (!m_command_queue.empty()) - m_command_queue.pop(); -} - -bool -IOChannel::CommandQueueIsEmpty () const -{ - return m_command_queue.empty(); -} - -bool -IOChannel::IsGettingCommand () const -{ - return m_getting_command; -} - -void -IOChannel::SetGettingCommand (bool new_value) -{ - m_getting_command = new_value; -} diff --git a/contrib/llvm/tools/lldb/tools/driver/IOChannel.h b/contrib/llvm/tools/lldb/tools/driver/IOChannel.h deleted file mode 100644 index 3788673..0000000 --- a/contrib/llvm/tools/lldb/tools/driver/IOChannel.h +++ /dev/null @@ -1,154 +0,0 @@ -//===-- IOChannel.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_IOChannel_h_ -#define lldb_IOChannel_h_ - -#include <thread> -#include <mutex> -#include <atomic> -#include <condition_variable> - -#include <string> -#include <queue> -#include "Driver.h" - -class IOChannel : public lldb::SBBroadcaster -{ -public: - enum { - eBroadcastBitHasUserInput = (1 << 0), - eBroadcastBitUserInterrupt = (1 << 1), - eBroadcastBitThreadShouldExit = (1 << 2), - eBroadcastBitThreadDidExit = (1 << 3), - eBroadcastBitThreadDidStart = (1 << 4), - eBroadcastBitsSTDOUT = (1 << 5), - eBroadcastBitsSTDERR = (1 << 6), - eBroadcastBitsSTDIN = (1 << 7), - eAllEventBits = 0xffffffff - }; - - enum LibeditGetInputResult - { - eLibeditGetInputEOF = 0, - eLibeditGetInputValid = 1, - eLibeditGetInputEmpty = 2, - eLibeditGetInputResultError = 4, - eLibeditGetInputResultUnknown = 0xffffffff - }; - - IOChannel (FILE *editline_in, - FILE *editline_out, - FILE *out, - FILE *err, - Driver *driver = NULL); - - virtual - ~IOChannel (); - - bool - Start (); - - bool - Stop (); - - static lldb::thread_result_t - IOReadThread (void *); - - void - Run (); - - void - OutWrite (const char *buffer, size_t len, bool asynchronous); - - void - ErrWrite (const char *buffer, size_t len, bool asynchronous); - - LibeditGetInputResult - LibeditGetInput (std::string &); - - static void - LibeditOutputBytesReceived (void *baton, const void *src,size_t src_len); - - void - SetPrompt (); - - void - RefreshPrompt (); - - void - AddCommandToQueue (const char *command); - - bool - GetCommandFromQueue (std::string &cmd); - - int - CommandQueueSize () const; - - void - ClearCommandQueue (); - - bool - CommandQueueIsEmpty () const; - - const char * - GetPrompt (); - - bool - EditLineHasCharacters (); - - void - EraseCharsBeforeCursor (); - - static unsigned char - ElCompletionFn (EditLine *e, int ch); - - void - ElResize(); - -protected: - - bool - IsGettingCommand () const; - - void - SetGettingCommand (bool new_value); - -private: - - std::recursive_mutex m_output_mutex; - std::condition_variable_any m_output_cond; - struct timeval m_enter_elgets_time; - - Driver *m_driver; - lldb::thread_t m_read_thread; - bool m_read_thread_should_exit; - FILE *m_out_file; - FILE *m_err_file; - FILE *m_editline_out; - std::queue<std::string> m_command_queue; - const char *m_completion_key; - - EditLine *m_edit_line; - History *m_history; - HistEvent m_history_event; - bool m_getting_command; - bool m_expecting_prompt; - bool m_output_flushed; - std::string m_prompt_str; // for accumlating the prompt as it gets written out by editline - bool m_refresh_request_pending; - - void - HistorySaveLoad (bool save); - - unsigned char - HandleCompletion (EditLine *e, int ch); -}; - -#endif // lldb_IOChannel_h_ diff --git a/contrib/llvm/tools/lldb/tools/driver/Platform.h b/contrib/llvm/tools/lldb/tools/driver/Platform.h index f1fe1e4..faa2991 100644 --- a/contrib/llvm/tools/lldb/tools/driver/Platform.h +++ b/contrib/llvm/tools/lldb/tools/driver/Platform.h @@ -18,9 +18,8 @@ #include <io.h> #include <eh.h> #include <inttypes.h> - #include "ELWrapper.h" #include "lldb/Host/windows/Windows.h" - #include "GetOptWrapper.h" + #include "lldb/Host/HostGetOpt.h" struct timeval { diff --git a/contrib/llvm/tools/lldb/tools/lldb-platform/exports b/contrib/llvm/tools/lldb/tools/lldb-platform/exports new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/contrib/llvm/tools/lldb/tools/lldb-platform/exports diff --git a/contrib/llvm/tools/lldb/tools/lldb-platform/lldb-platform.cpp b/contrib/llvm/tools/lldb/tools/lldb-platform/lldb-platform.cpp index bc9d629..e18ebab 100644 --- a/contrib/llvm/tools/lldb/tools/lldb-platform/lldb-platform.cpp +++ b/contrib/llvm/tools/lldb/tools/lldb-platform/lldb-platform.cpp @@ -11,7 +11,7 @@ // C Includes #include <errno.h> -#include <getopt.h> +#include "lldb/Host/HostGetOpt.h" #include <signal.h> #include <stdint.h> #include <stdio.h> @@ -262,24 +262,18 @@ main (int argc, char *argv[]) std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); if (conn_ap.get()) { - for (int j = 0; j < listen_host_port.size(); j++) + std::string connect_url ("listen://"); + connect_url.append(listen_host_port.c_str()); + + printf ("Listening for a connection from %s...\n", listen_host_port.c_str()); + if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess) { - char c = listen_host_port[j]; - if (c > '9' || c < '0') - printf("WARNING: passing anything but a number as argument to --listen will most probably make connecting impossible.\n"); + printf ("Connection established.\n"); + gdb_server.SetConnection (conn_ap.release()); } - std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) + else { - std::string connect_url ("listen://"); - connect_url.append(listen_host_port.c_str()); - - printf ("Listening for a connection on %s...\n", listen_host_port.c_str()); - if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess) - { - printf ("Connection established.\n"); - gdb_server.SetConnection (conn_ap.release()); - } + printf ("error: %s\n", error.AsCString()); } } |