diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h index be760637c03e..b2d5f2d7f1a2 100644 --- a/include/lldb/Core/ArchSpec.h +++ b/include/lldb/Core/ArchSpec.h @@ -1,718 +1,728 @@ //===-- ArchSpec.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_ArchSpec_h_ #define liblldb_ArchSpec_h_ #if defined(__cplusplus) #include "lldb/lldb-forward.h" #include "lldb/Core/ConstString.h" #include "llvm/ADT/Triple.h" namespace lldb_private { struct CoreDefinition; //---------------------------------------------------------------------- /// @class ArchSpec ArchSpec.h "lldb/Core/ArchSpec.h" /// @brief An architecture specification class. /// /// A class designed to be created from a cpu type and subtype, a /// string representation, or an llvm::Triple. Keeping all of the /// conversions of strings to architecture enumeration values confined /// to this class allows new architecture support to be added easily. //---------------------------------------------------------------------- class ArchSpec { public: enum MIPSSubType { eMIPSSubType_unknown, eMIPSSubType_mips32, eMIPSSubType_mips32r2, eMIPSSubType_mips32r6, eMIPSSubType_mips32el, eMIPSSubType_mips32r2el, eMIPSSubType_mips32r6el, eMIPSSubType_mips64, eMIPSSubType_mips64r2, eMIPSSubType_mips64r6, eMIPSSubType_mips64el, eMIPSSubType_mips64r2el, eMIPSSubType_mips64r6el, }; // Masks for the ases word of an ABI flags structure. enum MIPSASE { eMIPSAse_dsp = 0x00000001, // DSP ASE eMIPSAse_dspr2 = 0x00000002, // DSP R2 ASE eMIPSAse_eva = 0x00000004, // Enhanced VA Scheme eMIPSAse_mcu = 0x00000008, // MCU (MicroController) ASE eMIPSAse_mdmx = 0x00000010, // MDMX ASE eMIPSAse_mips3d = 0x00000020, // MIPS-3D ASE eMIPSAse_mt = 0x00000040, // MT ASE eMIPSAse_smartmips = 0x00000080, // SmartMIPS ASE eMIPSAse_virt = 0x00000100, // VZ ASE eMIPSAse_msa = 0x00000200, // MSA ASE eMIPSAse_mips16 = 0x00000400, // MIPS16 ASE eMIPSAse_micromips = 0x00000800, // MICROMIPS ASE eMIPSAse_xpa = 0x00001000, // XPA ASE eMIPSAse_mask = 0x00001fff, eMIPSABI_O32 = 0x00002000, eMIPSABI_N32 = 0x00004000, eMIPSABI_N64 = 0x00008000, eMIPSABI_O64 = 0x00020000, eMIPSABI_EABI32 = 0x00040000, eMIPSABI_EABI64 = 0x00080000, eMIPSABI_mask = 0x000ff000 }; // MIPS Floating point ABI Values enum MIPS_ABI_FP { eMIPS_ABI_FP_ANY = 0x00000000, eMIPS_ABI_FP_DOUBLE = 0x00100000, // hard float / -mdouble-float eMIPS_ABI_FP_SINGLE = 0x00200000, // hard float / -msingle-float eMIPS_ABI_FP_SOFT = 0x00300000, // soft float eMIPS_ABI_FP_OLD_64 = 0x00400000, // -mips32r2 -mfp64 eMIPS_ABI_FP_XX = 0x00500000, // -mfpxx eMIPS_ABI_FP_64 = 0x00600000, // -mips32r2 -mfp64 eMIPS_ABI_FP_64A = 0x00700000, // -mips32r2 -mfp64 -mno-odd-spreg eMIPS_ABI_FP_mask = 0x00700000 }; // ARM specific e_flags enum ARMeflags { eARM_abi_soft_float = 0x00000200, eARM_abi_hard_float = 0x00000400 }; enum Core { eCore_arm_generic, eCore_arm_armv4, eCore_arm_armv4t, eCore_arm_armv5, eCore_arm_armv5e, eCore_arm_armv5t, eCore_arm_armv6, eCore_arm_armv6m, eCore_arm_armv7, eCore_arm_armv7f, eCore_arm_armv7s, eCore_arm_armv7k, eCore_arm_armv7m, eCore_arm_armv7em, eCore_arm_xscale, eCore_thumb, eCore_thumbv4t, eCore_thumbv5, eCore_thumbv5e, eCore_thumbv6, eCore_thumbv6m, eCore_thumbv7, eCore_thumbv7s, eCore_thumbv7k, eCore_thumbv7f, eCore_thumbv7m, eCore_thumbv7em, eCore_arm_arm64, eCore_arm_armv8, eCore_arm_aarch64, eCore_mips32, eCore_mips32r2, eCore_mips32r3, eCore_mips32r5, eCore_mips32r6, eCore_mips32el, eCore_mips32r2el, eCore_mips32r3el, eCore_mips32r5el, eCore_mips32r6el, eCore_mips64, eCore_mips64r2, eCore_mips64r3, eCore_mips64r5, eCore_mips64r6, eCore_mips64el, eCore_mips64r2el, eCore_mips64r3el, eCore_mips64r5el, eCore_mips64r6el, eCore_ppc_generic, eCore_ppc_ppc601, eCore_ppc_ppc602, eCore_ppc_ppc603, eCore_ppc_ppc603e, eCore_ppc_ppc603ev, eCore_ppc_ppc604, eCore_ppc_ppc604e, eCore_ppc_ppc620, eCore_ppc_ppc750, eCore_ppc_ppc7400, eCore_ppc_ppc7450, eCore_ppc_ppc970, eCore_ppc64_generic, eCore_ppc64_ppc970_64, eCore_s390x_generic, eCore_sparc_generic, eCore_sparc9_generic, eCore_x86_32_i386, eCore_x86_32_i486, eCore_x86_32_i486sx, eCore_x86_32_i686, 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, eCore_kalimba3, eCore_kalimba4, eCore_kalimba5, kNumCores, kCore_invalid, // The following constants are used for wildcard matching only kCore_any, kCore_arm_any, kCore_ppc_any, kCore_ppc64_any, kCore_x86_32_any, kCore_x86_64_any, kCore_hexagon_any, kCore_arm_first = eCore_arm_generic, kCore_arm_last = eCore_arm_xscale, kCore_thumb_first = eCore_thumb, kCore_thumb_last = eCore_thumbv7em, kCore_ppc_first = eCore_ppc_generic, kCore_ppc_last = eCore_ppc_ppc970, kCore_ppc64_first = eCore_ppc64_generic, kCore_ppc64_last = eCore_ppc64_ppc970_64, kCore_x86_32_first = eCore_x86_32_i386, kCore_x86_32_last = eCore_x86_32_i686, kCore_x86_64_first = eCore_x86_64_x86_64, kCore_x86_64_last = eCore_x86_64_x86_64h, kCore_hexagon_first = eCore_hexagon_generic, kCore_hexagon_last = eCore_hexagon_hexagonv5, kCore_kalimba_first = eCore_kalimba3, kCore_kalimba_last = eCore_kalimba5, kCore_mips32_first = eCore_mips32, kCore_mips32_last = eCore_mips32r6, kCore_mips32el_first = eCore_mips32el, kCore_mips32el_last = eCore_mips32r6el, kCore_mips64_first = eCore_mips64, kCore_mips64_last = eCore_mips64r6, kCore_mips64el_first = eCore_mips64el, kCore_mips64el_last = eCore_mips64r6el, kCore_mips_first = eCore_mips32, kCore_mips_last = eCore_mips64r6el }; typedef void (* StopInfoOverrideCallbackType)(lldb_private::Thread &thread); //------------------------------------------------------------------ /// Default constructor. /// /// Default constructor that initializes the object with invalid /// cpu type and subtype values. //------------------------------------------------------------------ ArchSpec (); //------------------------------------------------------------------ /// Constructor over triple. /// /// Constructs an ArchSpec with properties consistent with the given /// Triple. //------------------------------------------------------------------ explicit ArchSpec (const llvm::Triple &triple); explicit ArchSpec (const char *triple_cstr); explicit ArchSpec (const char *triple_cstr, Platform *platform); //------------------------------------------------------------------ /// Constructor over architecture name. /// /// Constructs an ArchSpec with properties consistent with the given /// object type and architecture name. //------------------------------------------------------------------ explicit ArchSpec (ArchitectureType arch_type, uint32_t cpu_type, uint32_t cpu_subtype); //------------------------------------------------------------------ /// Destructor. //------------------------------------------------------------------ ~ArchSpec (); //------------------------------------------------------------------ /// Assignment operator. /// /// @param[in] rhs another ArchSpec object to copy. /// /// @return A const reference to this object. //------------------------------------------------------------------ const ArchSpec& operator= (const ArchSpec& rhs); static size_t AutoComplete (const char *name, StringList &matches); //------------------------------------------------------------------ /// Returns a static string representing the current architecture. /// /// @return A static string correcponding to the current /// architecture. //------------------------------------------------------------------ const char * GetArchitectureName () const; //----------------------------------------------------------------- /// if MIPS architecture return true. /// /// @return a boolean value. //----------------------------------------------------------------- bool IsMIPS() const; //------------------------------------------------------------------ /// Returns a string representing current architecture as a target CPU /// for tools like compiler, disassembler etc. /// /// @return A string representing target CPU for the current /// architecture. //------------------------------------------------------------------ std::string GetClangTargetCPU (); //------------------------------------------------------------------ /// Clears the object state. /// /// Clears the object state back to a default invalid state. //------------------------------------------------------------------ void Clear (); //------------------------------------------------------------------ /// Returns the size in bytes of an address of the current /// architecture. /// /// @return The byte size of an address of the current architecture. //------------------------------------------------------------------ uint32_t GetAddressByteSize () const; //------------------------------------------------------------------ /// Returns a machine family for the current architecture. /// /// @return An LLVM arch type. //------------------------------------------------------------------ llvm::Triple::ArchType 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 /// HostInfo::GetDistributionId (). ///------------------------------------------------------------------ void SetDistributionId (const char* distribution_id); //------------------------------------------------------------------ /// Tests if this ArchSpec is valid. /// /// @return True if the current architecture is valid, false /// otherwise. //------------------------------------------------------------------ bool IsValid () const { return m_core >= eCore_arm_generic && m_core < kNumCores; } + //------------------------------------------------------------------ + /// Return a string representing target application ABI. + /// + /// @return A string representing target application ABI. + //------------------------------------------------------------------ + std::string GetTargetABI() const; + + bool TripleVendorWasSpecified() const { return !m_triple.getVendorName().empty(); } bool TripleVendorIsUnspecifiedUnknown() const { return m_triple.getVendor() == llvm::Triple::UnknownVendor && m_triple.getVendorName().empty(); } bool TripleOSWasSpecified() const { return !m_triple.getOSName().empty(); } bool TripleEnvironmentWasSpecified () const { return !m_triple.getEnvironmentName().empty(); } bool TripleOSIsUnspecifiedUnknown() const { return m_triple.getOS() == llvm::Triple::UnknownOS && m_triple.getOSName().empty(); } //------------------------------------------------------------------ /// Merges fields from another ArchSpec into this ArchSpec. /// /// This will use the supplied ArchSpec to fill in any fields of /// the triple in this ArchSpec which were unspecified. This can /// be used to refine a generic ArchSpec with a more specific one. /// For example, if this ArchSpec's triple is something like /// i386-unknown-unknown-unknown, and we have a triple which is /// x64-pc-windows-msvc, then merging that triple into this one /// will result in the triple i386-pc-windows-msvc. /// //------------------------------------------------------------------ void MergeFrom(const ArchSpec &other); //------------------------------------------------------------------ /// Change the architecture object type, CPU type and OS type. /// /// @param[in] arch_type The object type of this ArchSpec. /// /// @param[in] cpu The required CPU type. /// /// @param[in] os The optional OS type /// The default value of 0 was choosen to from the ELF spec value /// ELFOSABI_NONE. ELF is the only one using this parameter. If another /// format uses this parameter and 0 does not work, use a value over /// 255 because in the ELF header this is value is only a byte. /// /// @return True if the object, and CPU were successfully set. /// /// As a side effect, the vendor value is usually set to unknown. /// The exections are /// aarch64-apple-ios /// arm-apple-ios /// thumb-apple-ios /// x86-apple- /// x86_64-apple- /// /// As a side effect, the os value is usually set to unknown /// The exceptions are /// *-*-aix /// aarch64-apple-ios /// arm-apple-ios /// thumb-apple-ios /// powerpc-apple-darwin /// *-*-freebsd /// *-*-linux /// *-*-netbsd /// *-*-openbsd /// *-*-solaris //------------------------------------------------------------------ bool SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os = 0); //------------------------------------------------------------------ /// Returns the byte order for the architecture specification. /// /// @return The endian enumeration for the current endianness of /// the architecture specification //------------------------------------------------------------------ lldb::ByteOrder GetByteOrder () const; //------------------------------------------------------------------ /// Sets this ArchSpec's byte order. /// /// In the common case there is no need to call this method as the /// byte order can almost always be determined by the architecture. /// However, many CPU's are bi-endian (ARM, Alpha, PowerPC, etc) /// and the default/assumed byte order may be incorrect. //------------------------------------------------------------------ void SetByteOrder (lldb::ByteOrder byte_order) { m_byte_order = byte_order; } uint32_t GetMinimumOpcodeByteSize() const; uint32_t GetMaximumOpcodeByteSize() const; Core GetCore () const { return m_core; } uint32_t GetMachOCPUType () const; uint32_t GetMachOCPUSubType () const; //------------------------------------------------------------------ /// Architecture data byte width accessor /// /// @return the size in 8-bit (host) bytes of a minimum addressable /// unit from the Architecture's data bus //------------------------------------------------------------------ uint32_t GetDataByteSize() const; //------------------------------------------------------------------ /// Architecture code byte width accessor /// /// @return the size in 8-bit (host) bytes of a minimum addressable /// unit from the Architecture's code bus //------------------------------------------------------------------ uint32_t GetCodeByteSize() const; //------------------------------------------------------------------ /// Architecture tripple accessor. /// /// @return A triple describing this ArchSpec. //------------------------------------------------------------------ llvm::Triple & GetTriple () { return m_triple; } //------------------------------------------------------------------ /// Architecture tripple accessor. /// /// @return A triple describing this ArchSpec. //------------------------------------------------------------------ const llvm::Triple & GetTriple () const { return m_triple; } void DumpTriple(Stream &s) const; //------------------------------------------------------------------ /// Architecture tripple setter. /// /// Configures this ArchSpec according to the given triple. If the /// triple has unknown components in all of the vendor, OS, and /// the optional environment field (i.e. "i386-unknown-unknown") /// then default values are taken from the host. Architecture and /// environment components are used to further resolve the CPU type /// and subtype, endian characteristics, etc. /// /// @return A triple describing this ArchSpec. //------------------------------------------------------------------ bool SetTriple (const llvm::Triple &triple); bool SetTriple (const char *triple_cstr); bool SetTriple (const char *triple_cstr, Platform *platform); //------------------------------------------------------------------ /// Returns the default endianness of the architecture. /// /// @return The endian enumeration for the default endianness of /// the architecture. //------------------------------------------------------------------ lldb::ByteOrder GetDefaultEndian () const; //------------------------------------------------------------------ /// Returns true if 'char' is a signed type by defualt in the /// architecture false otherwise /// /// @return True if 'char' is a signed type by default on the /// architecture and false otherwise. //------------------------------------------------------------------ bool CharIsSignedByDefault () const; //------------------------------------------------------------------ /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu /// type match between them. /// e.g. armv7s is not an exact match with armv7 - this would return false /// /// @return true if the two ArchSpecs match. //------------------------------------------------------------------ bool IsExactMatch (const ArchSpec& rhs) const; //------------------------------------------------------------------ /// Compare an ArchSpec to another ArchSpec, requiring a compatible /// cpu type match between them. /// e.g. armv7s is compatible with armv7 - this method would return true /// /// @return true if the two ArchSpecs are compatible //------------------------------------------------------------------ bool IsCompatibleMatch (const ArchSpec& rhs) const; //------------------------------------------------------------------ /// Get a stop info override callback for the current architecture. /// /// Most platform specific code should go in lldb_private::Platform, /// but there are cases where no matter which platform you are on /// certain things hold true. /// /// This callback is currently intended to handle cases where a /// program stops at an instruction that won't get executed and it /// allows the stop reasonm, like "breakpoint hit", to be replaced /// with a different stop reason like "no stop reason". /// /// This is specifically used for ARM in Thumb code when we stop in /// an IT instruction (if/then/else) where the instruction won't get /// executed and therefore it wouldn't be correct to show the program /// stopped at the current PC. The code is generic and applies to all /// ARM CPUs. /// /// @return NULL or a valid stop info override callback for the /// current architecture. //------------------------------------------------------------------ StopInfoOverrideCallbackType GetStopInfoOverrideCallback () const; bool IsFullySpecifiedTriple () const; void PiecewiseTripleCompare (const ArchSpec &other, bool &arch_different, bool &vendor_different, bool &os_different, bool &os_version_different, bool &env_different); //------------------------------------------------------------------ /// Detect whether this architecture uses thumb code exclusively /// /// Some embedded ARM chips (e.g. the ARM Cortex M0-7 line) can /// only execute the Thumb instructions, never Arm. We should normally /// pick up arm/thumbness from their the processor status bits (cpsr/xpsr) /// or hints on each function - but when doing bare-boards low level /// debugging (especially common with these embedded processors), we may /// not have those things easily accessible. /// /// @return true if this is an arm ArchSpec which can only execute Thumb /// instructions //------------------------------------------------------------------ bool IsAlwaysThumbInstructions () const; uint32_t GetFlags () const { return m_flags; } void SetFlags (uint32_t flags) { m_flags = flags; } + void SetFlags(std::string elf_abi); + protected: bool IsEqualTo (const ArchSpec& rhs, bool exact_match) const; llvm::Triple m_triple; Core m_core; lldb::ByteOrder m_byte_order; // Additional arch flags which we cannot get from triple and core // For MIPS these are application specific extensions like // micromips, mips16 etc. uint32_t m_flags; ConstString m_distribution_id; // Called when m_def or m_entry are changed. Fills in all remaining // members with default values. void CoreUpdated (bool update_triple); }; //------------------------------------------------------------------ /// @fn bool operator< (const ArchSpec& lhs, const ArchSpec& rhs) /// @brief Less than operator. /// /// Tests two ArchSpec objects to see if \a lhs is less than \a /// rhs. /// /// @param[in] lhs The Left Hand Side ArchSpec object to compare. /// @param[in] rhs The Left Hand Side ArchSpec object to compare. /// /// @return true if \a lhs is less than \a rhs //------------------------------------------------------------------ bool operator< (const ArchSpec& lhs, const ArchSpec& rhs); } // namespace lldb_private #endif // #if defined(__cplusplus) #endif // #ifndef liblldb_ArchSpec_h_ diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp index 24aba81350a6..efdbf11d93e3 100644 --- a/source/Core/ArchSpec.cpp +++ b/source/Core/ArchSpec.cpp @@ -1,1611 +1,1646 @@ //===-- ArchSpec.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/ArchSpec.h" // C Includes // C++ Includes #include #include #include // Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/Support/COFF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Host.h" // Project includes #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StringList.h" #include "lldb/Host/Endian.h" #include "lldb/Host/HostInfo.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/NameMatches.h" #include "lldb/Utility/SafeMachO.h" #include "Plugins/Process/Utility/ARMDefines.h" #include "Plugins/Process/Utility/InstructionUtils.h" using namespace lldb; using namespace lldb_private; static bool cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match); namespace lldb_private { struct CoreDefinition { ByteOrder default_byte_order; uint32_t addr_byte_size; uint32_t min_opcode_byte_size; uint32_t max_opcode_byte_size; llvm::Triple::ArchType machine; ArchSpec::Core core; const char * const name; }; } // namespace lldb_private // This core information can be looked using the ArchSpec::Core as the index static const CoreDefinition g_core_definitions[] = { { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_generic , "arm" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4 , "armv4" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4t , "armv4t" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5 , "armv5" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5e , "armv5e" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5t , "armv5t" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv6 , "armv6" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv6m , "armv6m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7 , "armv7" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7f , "armv7f" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7s , "armv7s" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7k , "armv7k" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7m , "armv7m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7em , "armv7em" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_xscale , "xscale" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumb , "thumb" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv4t , "thumbv4t" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5 , "thumbv5" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5e , "thumbv5e" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv6 , "thumbv6" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv6m , "thumbv6m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7 , "thumbv7" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7f , "thumbv7f" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7s , "thumbv7s" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_arm64 , "arm64" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_armv8 , "armv8" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::aarch64, ArchSpec::eCore_arm_aarch64 , "aarch64" }, // mips32, mips32r2, mips32r3, mips32r5, mips32r6 { eByteOrderBig , 4, 2, 4, llvm::Triple::mips , ArchSpec::eCore_mips32 , "mips" }, { eByteOrderBig , 4, 2, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r2 , "mipsr2" }, { eByteOrderBig , 4, 2, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r3 , "mipsr3" }, { eByteOrderBig , 4, 2, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r5 , "mipsr5" }, { eByteOrderBig , 4, 2, 4, llvm::Triple::mips , ArchSpec::eCore_mips32r6 , "mipsr6" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32el , "mipsel" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r2el , "mipsr2el" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r3el , "mipsr3el" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r5el , "mipsr5el" }, { eByteOrderLittle, 4, 2, 4, llvm::Triple::mipsel, ArchSpec::eCore_mips32r6el , "mipsr6el" }, // mips64, mips64r2, mips64r3, mips64r5, mips64r6 { eByteOrderBig , 8, 2, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64 , "mips64" }, { eByteOrderBig , 8, 2, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r2 , "mips64r2" }, { eByteOrderBig , 8, 2, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r3 , "mips64r3" }, { eByteOrderBig , 8, 2, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r5 , "mips64r5" }, { eByteOrderBig , 8, 2, 4, llvm::Triple::mips64 , ArchSpec::eCore_mips64r6 , "mips64r6" }, { eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64el , "mips64el" }, { eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r2el , "mips64r2el" }, { eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r3el , "mips64r3el" }, { eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r5el , "mips64r5el" }, { eByteOrderLittle, 8, 2, 4, llvm::Triple::mips64el, ArchSpec::eCore_mips64r6el , "mips64r6el" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "powerpc" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc601 , "ppc601" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc602 , "ppc602" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603 , "ppc603" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603e , "ppc603e" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603ev , "ppc603ev" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604 , "ppc604" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604e , "ppc604e" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc620 , "ppc620" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc750 , "ppc750" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7400 , "ppc7400" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7450 , "ppc7450" }, { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc970 , "ppc970" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_generic , "powerpc64" }, { eByteOrderBig , 8, 4, 4, llvm::Triple::ppc64 , ArchSpec::eCore_ppc64_ppc970_64 , "ppc970-64" }, { eByteOrderBig , 8, 2, 6, llvm::Triple::systemz, ArchSpec::eCore_s390x_generic , "s390x" }, { eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" }, { eByteOrderLittle, 8, 4, 4, llvm::Triple::sparcv9, ArchSpec::eCore_sparc9_generic , "sparcv9" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i386 , "i386" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486 , "i486" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" }, { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i686 , "i686" }, { 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" }, { eByteOrderBig , 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba3 , "kalimba3" }, { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba4 , "kalimba4" }, { eByteOrderLittle, 4, 1, 1 , llvm::Triple::kalimba , ArchSpec::eCore_kalimba5 , "kalimba5" } }; // Ensure that we have an entry in the g_core_definitions for each core. If you comment out an entry above, // you will need to comment out the corresponding ArchSpec::Core enumeration. static_assert(sizeof(g_core_definitions) / sizeof(CoreDefinition) == ArchSpec::kNumCores, "make sure we have one core definition for each core"); struct ArchDefinitionEntry { ArchSpec::Core core; uint32_t cpu; uint32_t sub; uint32_t cpu_mask; uint32_t sub_mask; }; struct ArchDefinition { ArchitectureType type; size_t num_entries; const ArchDefinitionEntry *entries; const char *name; }; size_t ArchSpec::AutoComplete (const char *name, StringList &matches) { if (name && name[0]) { for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) { if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name)) matches.AppendString (g_core_definitions[i].name); } } else { for (uint32_t i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) matches.AppendString (g_core_definitions[i].name); } return matches.GetSize(); } #define CPU_ANY (UINT32_MAX) //===----------------------------------------------------------------------===// // A table that gets searched linearly for matches. This table is used to // convert cpu type and subtypes to architecture names, and to convert // architecture names to cpu types and subtypes. The ordering is important and // allows the precedence to be set when the table is built. #define SUBTYPE_MASK 0x00FFFFFFu static const ArchDefinitionEntry g_macho_arch_entries[] = { { ArchSpec::eCore_arm_generic , llvm::MachO::CPU_TYPE_ARM , CPU_ANY, UINT32_MAX , UINT32_MAX }, { ArchSpec::eCore_arm_generic , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv4 , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv6 , llvm::MachO::CPU_TYPE_ARM , 6 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv6m , llvm::MachO::CPU_TYPE_ARM , 14 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv5e , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv5t , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_xscale , llvm::MachO::CPU_TYPE_ARM , 8 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7 , llvm::MachO::CPU_TYPE_ARM , 9 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7f , llvm::MachO::CPU_TYPE_ARM , 10 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7s , llvm::MachO::CPU_TYPE_ARM , 11 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_armv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 1 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , 13 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_arm_arm64 , llvm::MachO::CPU_TYPE_ARM64 , CPU_ANY, UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumb , llvm::MachO::CPU_TYPE_ARM , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv4t , llvm::MachO::CPU_TYPE_ARM , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv5 , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv5e , llvm::MachO::CPU_TYPE_ARM , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv6 , llvm::MachO::CPU_TYPE_ARM , 6 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv6m , llvm::MachO::CPU_TYPE_ARM , 14 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7 , llvm::MachO::CPU_TYPE_ARM , 9 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7f , llvm::MachO::CPU_TYPE_ARM , 10 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7s , llvm::MachO::CPU_TYPE_ARM , 11 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7k , llvm::MachO::CPU_TYPE_ARM , 12 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7m , llvm::MachO::CPU_TYPE_ARM , 15 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_thumbv7em , llvm::MachO::CPU_TYPE_ARM , 16 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_generic , llvm::MachO::CPU_TYPE_POWERPC , CPU_ANY, UINT32_MAX , UINT32_MAX }, { ArchSpec::eCore_ppc_generic , llvm::MachO::CPU_TYPE_POWERPC , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc601 , llvm::MachO::CPU_TYPE_POWERPC , 1 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc602 , llvm::MachO::CPU_TYPE_POWERPC , 2 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc603 , llvm::MachO::CPU_TYPE_POWERPC , 3 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc603e , llvm::MachO::CPU_TYPE_POWERPC , 4 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc603ev , llvm::MachO::CPU_TYPE_POWERPC , 5 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc604 , llvm::MachO::CPU_TYPE_POWERPC , 6 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc604e , llvm::MachO::CPU_TYPE_POWERPC , 7 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc620 , llvm::MachO::CPU_TYPE_POWERPC , 8 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc750 , llvm::MachO::CPU_TYPE_POWERPC , 9 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc7400 , llvm::MachO::CPU_TYPE_POWERPC , 10 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc7450 , llvm::MachO::CPU_TYPE_POWERPC , 11 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc_ppc970 , llvm::MachO::CPU_TYPE_POWERPC , 100 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc64_generic , llvm::MachO::CPU_TYPE_POWERPC64 , 0 , UINT32_MAX , SUBTYPE_MASK }, { ArchSpec::eCore_ppc64_ppc970_64 , llvm::MachO::CPU_TYPE_POWERPC64 , 100 , UINT32_MAX , SUBTYPE_MASK }, { 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_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_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 } }; static const ArchDefinition g_macho_arch_def = { eArchTypeMachO, llvm::array_lengthof(g_macho_arch_entries), g_macho_arch_entries, "mach-o" }; //===----------------------------------------------------------------------===// // A table that gets searched linearly for matches. This table is used to // convert cpu type and subtypes to architecture names, and to convert // architecture names to cpu types and subtypes. The ordering is important and // allows the precedence to be set when the table is built. static const ArchDefinitionEntry g_elf_arch_entries[] = { { ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc { ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386 { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_IAMCU , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel MCU // FIXME: is this correct? { ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64 { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM { ArchSpec::eCore_arm_aarch64 , llvm::ELF::EM_AARCH64, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM64 { ArchSpec::eCore_s390x_generic , llvm::ELF::EM_S390 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SystemZ { 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_mips32 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32 { ArchSpec::eCore_mips32r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2 { ArchSpec::eCore_mips32r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6 { ArchSpec::eCore_mips32el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32el { ArchSpec::eCore_mips32r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r2el { ArchSpec::eCore_mips32r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips32r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips32r6el { ArchSpec::eCore_mips64 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64 { ArchSpec::eCore_mips64r2 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2 { ArchSpec::eCore_mips64r6 , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6 { ArchSpec::eCore_mips64el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64el { ArchSpec::eCore_mips64r2el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r2el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r2el { ArchSpec::eCore_mips64r6el , llvm::ELF::EM_MIPS , ArchSpec::eMIPSSubType_mips64r6el, 0xFFFFFFFFu, 0xFFFFFFFFu }, // mips64r6el { ArchSpec::eCore_hexagon_generic , llvm::ELF::EM_HEXAGON, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // HEXAGON { ArchSpec::eCore_kalimba3 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v3, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA { ArchSpec::eCore_kalimba4 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v4, 0xFFFFFFFFu, 0xFFFFFFFFu }, // KALIMBA { ArchSpec::eCore_kalimba5 , llvm::ELF::EM_CSR_KALIMBA, llvm::Triple::KalimbaSubArch_v5, 0xFFFFFFFFu, 0xFFFFFFFFu } // KALIMBA }; static const ArchDefinition g_elf_arch_def = { eArchTypeELF, llvm::array_lengthof(g_elf_arch_entries), g_elf_arch_entries, "elf", }; static const ArchDefinitionEntry g_coff_arch_entries[] = { { ArchSpec::eCore_x86_32_i386 , llvm::COFF::IMAGE_FILE_MACHINE_I386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80x86 { ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC { ArchSpec::eCore_ppc_generic , llvm::COFF::IMAGE_FILE_MACHINE_POWERPCFP, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC (with FPU) { ArchSpec::eCore_arm_generic , llvm::COFF::IMAGE_FILE_MACHINE_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM { ArchSpec::eCore_arm_armv7 , llvm::COFF::IMAGE_FILE_MACHINE_ARMNT , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7 { ArchSpec::eCore_thumb , llvm::COFF::IMAGE_FILE_MACHINE_THUMB , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARMv7 { ArchSpec::eCore_x86_64_x86_64, llvm::COFF::IMAGE_FILE_MACHINE_AMD64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // AMD64 }; static const ArchDefinition g_coff_arch_def = { eArchTypeCOFF, llvm::array_lengthof(g_coff_arch_entries), g_coff_arch_entries, "pe-coff", }; //===----------------------------------------------------------------------===// // Table of all ArchDefinitions static const ArchDefinition *g_arch_definitions[] = { &g_macho_arch_def, &g_elf_arch_def, &g_coff_arch_def }; static const size_t k_num_arch_definitions = llvm::array_lengthof(g_arch_definitions); //===----------------------------------------------------------------------===// // Static helper functions. // Get the architecture definition for a given object type. static const ArchDefinition * FindArchDefinition (ArchitectureType arch_type) { for (unsigned int i = 0; i < k_num_arch_definitions; ++i) { const ArchDefinition *def = g_arch_definitions[i]; if (def->type == arch_type) return def; } return nullptr; } // Get an architecture definition by name. static const CoreDefinition * FindCoreDefinition (llvm::StringRef name) { for (unsigned int i = 0; i < llvm::array_lengthof(g_core_definitions); ++i) { if (name.equals_lower(g_core_definitions[i].name)) return &g_core_definitions[i]; } return nullptr; } static inline const CoreDefinition * FindCoreDefinition (ArchSpec::Core core) { if (core >= 0 && core < llvm::array_lengthof(g_core_definitions)) return &g_core_definitions[core]; return nullptr; } // Get a definition entry by cpu type and subtype. static const ArchDefinitionEntry * FindArchDefinitionEntry (const ArchDefinition *def, uint32_t cpu, uint32_t sub) { if (def == nullptr) return nullptr; const ArchDefinitionEntry *entries = def->entries; for (size_t i = 0; i < def->num_entries; ++i) { if (entries[i].cpu == (cpu & entries[i].cpu_mask)) if (entries[i].sub == (sub & entries[i].sub_mask)) return &entries[i]; } return nullptr; } static const ArchDefinitionEntry * FindArchDefinitionEntry (const ArchDefinition *def, ArchSpec::Core core) { if (def == nullptr) return nullptr; const ArchDefinitionEntry *entries = def->entries; for (size_t i = 0; i < def->num_entries; ++i) { if (entries[i].core == core) return &entries[i]; } return nullptr; } //===----------------------------------------------------------------------===// // Constructors and destructors. ArchSpec::ArchSpec() : m_triple (), m_core (kCore_invalid), m_byte_order (eByteOrderInvalid), m_flags (0), m_distribution_id () { } ArchSpec::ArchSpec (const char *triple_cstr, Platform *platform) : m_triple (), m_core (kCore_invalid), m_byte_order (eByteOrderInvalid), m_flags (0), m_distribution_id () { if (triple_cstr) SetTriple(triple_cstr, platform); } ArchSpec::ArchSpec (const char *triple_cstr) : m_triple (), m_core (kCore_invalid), m_byte_order (eByteOrderInvalid), m_flags (0), m_distribution_id () { if (triple_cstr) SetTriple(triple_cstr); } ArchSpec::ArchSpec(const llvm::Triple &triple) : m_triple (), m_core (kCore_invalid), m_byte_order (eByteOrderInvalid), m_flags (0), m_distribution_id () { SetTriple(triple); } ArchSpec::ArchSpec (ArchitectureType arch_type, uint32_t cpu, uint32_t subtype) : m_triple (), m_core (kCore_invalid), m_byte_order (eByteOrderInvalid), m_flags (0), m_distribution_id () { SetArchitecture (arch_type, cpu, subtype); } ArchSpec::~ArchSpec() = default; //===----------------------------------------------------------------------===// // Assignment and initialization. const ArchSpec& ArchSpec::operator= (const ArchSpec& rhs) { if (this != &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; m_flags = rhs.m_flags; } return *this; } void ArchSpec::Clear() { m_triple = llvm::Triple(); m_core = kCore_invalid; m_byte_order = eByteOrderInvalid; m_distribution_id.Clear (); m_flags = 0; } //===----------------------------------------------------------------------===// // Predicates. const char * ArchSpec::GetArchitectureName () const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) return core_def->name; return "unknown"; } bool ArchSpec::IsMIPS() const { const llvm::Triple::ArchType machine = GetMachine(); if(machine == llvm::Triple::mips || machine == llvm::Triple::mipsel || machine == llvm::Triple::mips64 || machine == llvm::Triple::mips64el) return true; return false; } -std::string -ArchSpec::GetClangTargetCPU () -{ - std::string cpu; - const llvm::Triple::ArchType machine = GetMachine(); + +std::string ArchSpec::GetTargetABI() const { + + std::string abi; + + if (IsMIPS()) { + switch (GetFlags() & ArchSpec::eMIPSABI_mask) { + case ArchSpec::eMIPSABI_N64: + abi = "n64"; + return abi; + case ArchSpec::eMIPSABI_N32: + abi = "n32"; + return abi; + case ArchSpec::eMIPSABI_O32: + abi = "o32"; + return abi; + default: + return abi; + } + } + return abi; +} + +void ArchSpec::SetFlags(std::string elf_abi) { + + uint32_t flag = GetFlags(); + if (IsMIPS()) { + if (elf_abi == "n64") + flag |= ArchSpec::eMIPSABI_N64; + else if (elf_abi == "n32") + flag |= ArchSpec::eMIPSABI_N32; + else if (elf_abi == "o32") + flag |= ArchSpec::eMIPSABI_O32; + } + SetFlags(flag); +} + +std::string ArchSpec::GetClangTargetCPU() { + std::string cpu; + const llvm::Triple::ArchType machine = GetMachine(); if (machine == llvm::Triple::mips || machine == llvm::Triple::mipsel || machine == llvm::Triple::mips64 || machine == llvm::Triple::mips64el) { switch (m_core) { case ArchSpec::eCore_mips32: case ArchSpec::eCore_mips32el: cpu = "mips32"; break; case ArchSpec::eCore_mips32r2: case ArchSpec::eCore_mips32r2el: cpu = "mips32r2"; break; case ArchSpec::eCore_mips32r3: case ArchSpec::eCore_mips32r3el: cpu = "mips32r3"; break; case ArchSpec::eCore_mips32r5: case ArchSpec::eCore_mips32r5el: cpu = "mips32r5"; break; case ArchSpec::eCore_mips32r6: case ArchSpec::eCore_mips32r6el: cpu = "mips32r6"; break; case ArchSpec::eCore_mips64: case ArchSpec::eCore_mips64el: cpu = "mips64"; break; case ArchSpec::eCore_mips64r2: case ArchSpec::eCore_mips64r2el: cpu = "mips64r2"; break; case ArchSpec::eCore_mips64r3: case ArchSpec::eCore_mips64r3el: cpu = "mips64r3"; break; case ArchSpec::eCore_mips64r5: case ArchSpec::eCore_mips64r5el: cpu = "mips64r5"; break; case ArchSpec::eCore_mips64r6: case ArchSpec::eCore_mips64r6el: cpu = "mips64r6"; break; default: break; } } return cpu; } uint32_t ArchSpec::GetMachOCPUType () const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) { const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core); if (arch_def) { return arch_def->cpu; } } return LLDB_INVALID_CPUTYPE; } uint32_t ArchSpec::GetMachOCPUSubType () const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) { const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core); if (arch_def) { return arch_def->sub; } } return LLDB_INVALID_CPUTYPE; } uint32_t ArchSpec::GetDataByteSize () const { switch (m_core) { case eCore_kalimba3: return 4; case eCore_kalimba4: return 1; case eCore_kalimba5: return 4; default: return 1; } return 1; } uint32_t ArchSpec::GetCodeByteSize () const { switch (m_core) { case eCore_kalimba3: return 4; case eCore_kalimba4: return 1; case eCore_kalimba5: return 1; default: return 1; } return 1; } llvm::Triple::ArchType ArchSpec::GetMachine () const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) return core_def->machine; 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 { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) { if (core_def->machine == llvm::Triple::mips64 || core_def->machine == llvm::Triple::mips64el) { // For N32/O32 applications Address size is 4 bytes. if (m_flags & (eMIPSABI_N32 | eMIPSABI_O32)) return 4; } return core_def->addr_byte_size; } return 0; } ByteOrder ArchSpec::GetDefaultEndian () const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) return core_def->default_byte_order; return eByteOrderInvalid; } bool ArchSpec::CharIsSignedByDefault () const { switch (m_triple.getArch()) { default: return true; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: return m_triple.isOSDarwin() || m_triple.isOSWindows(); case llvm::Triple::ppc: case llvm::Triple::ppc64: return m_triple.isOSDarwin(); case llvm::Triple::ppc64le: case llvm::Triple::systemz: case llvm::Triple::xcore: return false; } } lldb::ByteOrder ArchSpec::GetByteOrder () const { if (m_byte_order == eByteOrderInvalid) return GetDefaultEndian(); return m_byte_order; } //===----------------------------------------------------------------------===// // Mutators. bool ArchSpec::SetTriple (const llvm::Triple &triple) { m_triple = triple; llvm::StringRef arch_name (m_triple.getArchName()); const CoreDefinition *core_def = FindCoreDefinition (arch_name); if (core_def) { m_core = core_def->core; // Set the byte order to the default byte order for an architecture. // This can be modified if needed for cases when cores handle both // big and little endian m_byte_order = core_def->default_byte_order; } else { Clear(); } return IsValid(); } static bool ParseMachCPUDashSubtypeTriple (const char *triple_cstr, ArchSpec &arch) { // Accept "12-10" or "12.10" as cpu type/subtype if (isdigit(triple_cstr[0])) { char *end = nullptr; errno = 0; uint32_t cpu = (uint32_t)::strtoul (triple_cstr, &end, 0); if (errno == 0 && cpu != 0 && end && ((*end == '-') || (*end == '.'))) { errno = 0; uint32_t sub = (uint32_t)::strtoul (end + 1, &end, 0); if (errno == 0 && end && ((*end == '-') || (*end == '.') || (*end == '\0'))) { if (arch.SetArchitecture (eArchTypeMachO, cpu, sub)) { if (*end == '-') { llvm::StringRef vendor_os (end + 1); size_t dash_pos = vendor_os.find('-'); if (dash_pos != llvm::StringRef::npos) { llvm::StringRef vendor_str(vendor_os.substr(0, dash_pos)); arch.GetTriple().setVendorName(vendor_str); const size_t vendor_start_pos = dash_pos+1; dash_pos = vendor_os.find('-', vendor_start_pos); if (dash_pos == llvm::StringRef::npos) { if (vendor_start_pos < vendor_os.size()) arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos)); } else { arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos, dash_pos - vendor_start_pos)); } } } return true; } } } } return false; } bool ArchSpec::SetTriple (const char *triple_cstr) { if (triple_cstr && triple_cstr[0]) { if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this)) return true; llvm::StringRef triple_stref (triple_cstr); if (triple_stref.startswith (LLDB_ARCH_DEFAULT)) { // Special case for the current host default architectures... if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKind32); else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKind64); else if (triple_stref.equals (LLDB_ARCH_DEFAULT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); } else { std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref)); triple_stref = normalized_triple_sstr; SetTriple (llvm::Triple (triple_stref)); } } else Clear(); return IsValid(); } bool ArchSpec::SetTriple (const char *triple_cstr, Platform *platform) { if (triple_cstr && triple_cstr[0]) { if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this)) return true; llvm::StringRef triple_stref (triple_cstr); if (triple_stref.startswith (LLDB_ARCH_DEFAULT)) { // Special case for the current host default architectures... if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKind32); else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKind64); else if (triple_stref.equals (LLDB_ARCH_DEFAULT)) *this = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); } else { ArchSpec raw_arch (triple_cstr); std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref)); triple_stref = normalized_triple_sstr; llvm::Triple normalized_triple (triple_stref); const bool os_specified = normalized_triple.getOSName().size() > 0; const bool vendor_specified = normalized_triple.getVendorName().size() > 0; const bool env_specified = normalized_triple.getEnvironmentName().size() > 0; // If we got an arch only, then default the vendor, os, environment // to match the platform if one is supplied if (!(os_specified || vendor_specified || env_specified)) { if (platform) { // If we were given a platform, use the platform's system // architecture. If this is not available (might not be // connected) use the first supported architecture. ArchSpec compatible_arch; if (platform->IsCompatibleArchitecture (raw_arch, false, &compatible_arch)) { if (compatible_arch.IsValid()) { const llvm::Triple &compatible_triple = compatible_arch.GetTriple(); if (!vendor_specified) normalized_triple.setVendor(compatible_triple.getVendor()); if (!os_specified) normalized_triple.setOS(compatible_triple.getOS()); if (!env_specified && compatible_triple.getEnvironmentName().size()) normalized_triple.setEnvironment(compatible_triple.getEnvironment()); } } else { *this = raw_arch; return IsValid(); } } else { // No platform specified, fall back to the host system for // the default vendor, os, and environment. llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple()); if (!vendor_specified) normalized_triple.setVendor(host_triple.getVendor()); if (!vendor_specified) normalized_triple.setOS(host_triple.getOS()); if (!env_specified && host_triple.getEnvironmentName().size()) normalized_triple.setEnvironment(host_triple.getEnvironment()); } } SetTriple (normalized_triple); } } else Clear(); return IsValid(); } void ArchSpec::MergeFrom(const ArchSpec &other) { if (TripleVendorIsUnspecifiedUnknown() && !other.TripleVendorIsUnspecifiedUnknown()) GetTriple().setVendor(other.GetTriple().getVendor()); if (TripleOSIsUnspecifiedUnknown() && !other.TripleOSIsUnspecifiedUnknown()) GetTriple().setOS(other.GetTriple().getOS()); if (GetTriple().getArch() == llvm::Triple::UnknownArch) GetTriple().setArch(other.GetTriple().getArch()); if (GetTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && !TripleVendorWasSpecified()) { if (other.TripleVendorWasSpecified()) GetTriple().setEnvironment(other.GetTriple().getEnvironment()); } // If this and other are both arm ArchSpecs and this ArchSpec is a generic "some kind of arm" // spec but the other ArchSpec is a specific arm core, adopt the specific arm core. if (GetTriple().getArch() == llvm::Triple::arm && other.GetTriple().getArch() == llvm::Triple::arm && IsCompatibleMatch (other) && GetCore() == ArchSpec::eCore_arm_generic && other.GetCore() != ArchSpec::eCore_arm_generic) { m_core = other.GetCore(); CoreUpdated (true); } } bool ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub, uint32_t os) { m_core = kCore_invalid; bool update_triple = true; const ArchDefinition *arch_def = FindArchDefinition(arch_type); if (arch_def) { const ArchDefinitionEntry *arch_def_entry = FindArchDefinitionEntry (arch_def, cpu, sub); if (arch_def_entry) { const CoreDefinition *core_def = FindCoreDefinition (arch_def_entry->core); if (core_def) { m_core = core_def->core; update_triple = false; // Always use the architecture name because it might be more descriptive // than the architecture enum ("armv7" -> llvm::Triple::arm). m_triple.setArchName(llvm::StringRef(core_def->name)); if (arch_type == eArchTypeMachO) { m_triple.setVendor (llvm::Triple::Apple); // Don't set the OS. It could be simulator, macosx, ios, watchos, tvos. We could // get close with the cpu type - but we can't get it right all of the time. Better // to leave this unset so other sections of code will set it when they have more // information. // NB: don't call m_triple.setOS (llvm::Triple::UnknownOS). That sets the OSName to // "unknown" and the ArchSpec::TripleVendorWasSpecified() method says that any // OSName setting means it was specified. } else if (arch_type == eArchTypeELF) { switch (os) { case llvm::ELF::ELFOSABI_AIX: m_triple.setOS (llvm::Triple::OSType::AIX); break; case llvm::ELF::ELFOSABI_FREEBSD: m_triple.setOS (llvm::Triple::OSType::FreeBSD); break; case llvm::ELF::ELFOSABI_GNU: m_triple.setOS (llvm::Triple::OSType::Linux); break; case llvm::ELF::ELFOSABI_NETBSD: m_triple.setOS (llvm::Triple::OSType::NetBSD); break; case llvm::ELF::ELFOSABI_OPENBSD: m_triple.setOS (llvm::Triple::OSType::OpenBSD); break; case llvm::ELF::ELFOSABI_SOLARIS: m_triple.setOS (llvm::Triple::OSType::Solaris); break; } } else { m_triple.setVendor (llvm::Triple::UnknownVendor); m_triple.setOS (llvm::Triple::UnknownOS); } // Fall back onto setting the machine type if the arch by name failed... if (m_triple.getArch () == llvm::Triple::UnknownArch) m_triple.setArch (core_def->machine); } } } CoreUpdated(update_triple); return IsValid(); } uint32_t ArchSpec::GetMinimumOpcodeByteSize() const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) return core_def->min_opcode_byte_size; return 0; } uint32_t ArchSpec::GetMaximumOpcodeByteSize() const { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) return core_def->max_opcode_byte_size; return 0; } bool ArchSpec::IsExactMatch (const ArchSpec& rhs) const { return IsEqualTo (rhs, true); } bool ArchSpec::IsCompatibleMatch (const ArchSpec& rhs) const { return IsEqualTo (rhs, false); } static bool isCompatibleEnvironment(llvm::Triple::EnvironmentType lhs, llvm::Triple::EnvironmentType rhs) { if (lhs == rhs) return true; // If any of the environment is unknown then they are compatible if (lhs == llvm::Triple::UnknownEnvironment || rhs == llvm::Triple::UnknownEnvironment) return true; // If one of the environment is Android and the other one is EABI then they are considered to // be compatible. This is required as a workaround for shared libraries compiled for Android // without the NOTE section indicating that they are using the Android ABI. if ((lhs == llvm::Triple::Android && rhs == llvm::Triple::EABI) || (rhs == llvm::Triple::Android && lhs == llvm::Triple::EABI) || (lhs == llvm::Triple::GNUEABI && rhs == llvm::Triple::EABI) || (rhs == llvm::Triple::GNUEABI && lhs == llvm::Triple::EABI) || (lhs == llvm::Triple::GNUEABIHF && rhs == llvm::Triple::EABIHF) || (rhs == llvm::Triple::GNUEABIHF && lhs == llvm::Triple::EABIHF)) return true; return false; } bool ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const { // explicitly ignoring m_distribution_id in this method. if (GetByteOrder() != rhs.GetByteOrder()) return false; const ArchSpec::Core lhs_core = GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); const bool core_match = cores_match (lhs_core, rhs_core, true, exact_match); if (core_match) { const llvm::Triple &lhs_triple = GetTriple(); const llvm::Triple &rhs_triple = rhs.GetTriple(); const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor(); const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor(); if (lhs_triple_vendor != rhs_triple_vendor) { const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified(); const bool lhs_vendor_specified = TripleVendorWasSpecified(); // Both architectures had the vendor specified, so if they aren't // equal then we return false if (rhs_vendor_specified && lhs_vendor_specified) return false; // Only fail if both vendor types are not unknown if (lhs_triple_vendor != llvm::Triple::UnknownVendor && rhs_triple_vendor != llvm::Triple::UnknownVendor) return false; } const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS(); const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS(); if (lhs_triple_os != rhs_triple_os) { const bool rhs_os_specified = rhs.TripleOSWasSpecified(); const bool lhs_os_specified = TripleOSWasSpecified(); // Both architectures had the OS specified, so if they aren't // equal then we return false if (rhs_os_specified && lhs_os_specified) return false; // Only fail if both os types are not unknown if (lhs_triple_os != llvm::Triple::UnknownOS && rhs_triple_os != llvm::Triple::UnknownOS) return false; } const llvm::Triple::EnvironmentType lhs_triple_env = lhs_triple.getEnvironment(); const llvm::Triple::EnvironmentType rhs_triple_env = rhs_triple.getEnvironment(); if (!isCompatibleEnvironment(lhs_triple_env, rhs_triple_env)) return false; return true; } return false; } //===----------------------------------------------------------------------===// // Helper methods. void ArchSpec::CoreUpdated (bool update_triple) { const CoreDefinition *core_def = FindCoreDefinition (m_core); if (core_def) { if (update_triple) m_triple = llvm::Triple(core_def->name, "unknown", "unknown"); m_byte_order = core_def->default_byte_order; } else { if (update_triple) m_triple = llvm::Triple(); m_byte_order = eByteOrderInvalid; } } //===----------------------------------------------------------------------===// // Operators. static bool cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match) { if (core1 == core2) return true; switch (core1) { case ArchSpec::kCore_any: return true; case ArchSpec::eCore_arm_generic: if (enforce_exact_match) break; LLVM_FALLTHROUGH; case ArchSpec::kCore_arm_any: if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last) return true; if (core2 >= ArchSpec::kCore_thumb_first && core2 <= ArchSpec::kCore_thumb_last) return true; 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; break; case ArchSpec::kCore_x86_64_any: if ((core2 >= ArchSpec::kCore_x86_64_first && core2 <= ArchSpec::kCore_x86_64_last) || (core2 == ArchSpec::kCore_x86_64_any)) return true; break; case ArchSpec::kCore_ppc_any: if ((core2 >= ArchSpec::kCore_ppc_first && core2 <= ArchSpec::kCore_ppc_last) || (core2 == ArchSpec::kCore_ppc_any)) return true; break; case ArchSpec::kCore_ppc64_any: if ((core2 >= ArchSpec::kCore_ppc64_first && core2 <= ArchSpec::kCore_ppc64_last) || (core2 == ArchSpec::kCore_ppc64_any)) return true; break; case ArchSpec::eCore_arm_armv6m: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_generic) return true; try_inverse = false; if (core2 == ArchSpec::eCore_arm_armv7) return true; if (core2 == ArchSpec::eCore_arm_armv6m) return true; } break; case ArchSpec::kCore_hexagon_any: if ((core2 >= ArchSpec::kCore_hexagon_first && core2 <= ArchSpec::kCore_hexagon_last) || (core2 == ArchSpec::kCore_hexagon_any)) return true; break; // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization // Cortex-M0 - ARMv6-M - armv6m // Cortex-M3 - ARMv7-M - armv7m // Cortex-M4 - ARMv7E-M - armv7em case ArchSpec::eCore_arm_armv7em: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_generic) return true; if (core2 == ArchSpec::eCore_arm_armv7m) return true; if (core2 == ArchSpec::eCore_arm_armv6m) return true; if (core2 == ArchSpec::eCore_arm_armv7) return true; try_inverse = true; } break; // v. https://en.wikipedia.org/wiki/ARM_Cortex-M#Silicon_customization // Cortex-M0 - ARMv6-M - armv6m // Cortex-M3 - ARMv7-M - armv7m // Cortex-M4 - ARMv7E-M - armv7em case ArchSpec::eCore_arm_armv7m: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_generic) return true; if (core2 == ArchSpec::eCore_arm_armv6m) return true; if (core2 == ArchSpec::eCore_arm_armv7) return true; if (core2 == ArchSpec::eCore_arm_armv7em) return true; try_inverse = true; } break; case ArchSpec::eCore_arm_armv7f: case ArchSpec::eCore_arm_armv7k: case ArchSpec::eCore_arm_armv7s: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_generic) return true; if (core2 == ArchSpec::eCore_arm_armv7) return true; try_inverse = false; } break; case ArchSpec::eCore_x86_64_x86_64h: if (!enforce_exact_match) { try_inverse = false; if (core2 == ArchSpec::eCore_x86_64_x86_64) return true; } break; case ArchSpec::eCore_arm_armv8: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_arm64) return true; if (core2 == ArchSpec::eCore_arm_aarch64) return true; try_inverse = false; } break; case ArchSpec::eCore_arm_aarch64: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_arm64) return true; if (core2 == ArchSpec::eCore_arm_armv8) return true; try_inverse = false; } break; case ArchSpec::eCore_arm_arm64: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_arm_aarch64) return true; if (core2 == ArchSpec::eCore_arm_armv8) return true; try_inverse = false; } break; case ArchSpec::eCore_mips32: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last) return true; try_inverse = false; } break; case ArchSpec::eCore_mips32el: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last) return true; try_inverse = false; } break; case ArchSpec::eCore_mips64: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && core2 <= ArchSpec::kCore_mips32_last) return true; if (core2 >= ArchSpec::kCore_mips64_first && core2 <= ArchSpec::kCore_mips64_last) return true; try_inverse = false; } break; case ArchSpec::eCore_mips64el: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= ArchSpec::kCore_mips32el_last) return true; if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= ArchSpec::kCore_mips64el_last) return true; try_inverse = false; } break; case ArchSpec::eCore_mips64r2: case ArchSpec::eCore_mips64r3: case ArchSpec::eCore_mips64r5: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && core2 <= (core1 - 10)) return true; if (core2 >= ArchSpec::kCore_mips64_first && core2 <= (core1 - 1)) return true; try_inverse = false; } break; case ArchSpec::eCore_mips64r2el: case ArchSpec::eCore_mips64r3el: case ArchSpec::eCore_mips64r5el: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= (core1 - 10)) return true; if (core2 >= ArchSpec::kCore_mips64el_first && core2 <= (core1 - 1)) return true; try_inverse = false; } break; case ArchSpec::eCore_mips32r2: case ArchSpec::eCore_mips32r3: case ArchSpec::eCore_mips32r5: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32_first && core2 <= core1) return true; } break; case ArchSpec::eCore_mips32r2el: case ArchSpec::eCore_mips32r3el: case ArchSpec::eCore_mips32r5el: if (!enforce_exact_match) { if (core2 >= ArchSpec::kCore_mips32el_first && core2 <= core1) return true; } break; case ArchSpec::eCore_mips32r6: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6) return true; } break; case ArchSpec::eCore_mips32r6el: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el) return true; } break; case ArchSpec::eCore_mips64r6: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_mips32 || core2 == ArchSpec::eCore_mips32r6) return true; if (core2 == ArchSpec::eCore_mips64 || core2 == ArchSpec::eCore_mips64r6) return true; } break; case ArchSpec::eCore_mips64r6el: if (!enforce_exact_match) { if (core2 == ArchSpec::eCore_mips32el || core2 == ArchSpec::eCore_mips32r6el) return true; if (core2 == ArchSpec::eCore_mips64el || core2 == ArchSpec::eCore_mips64r6el) return true; } break; default: break; } if (try_inverse) return cores_match (core2, core1, false, enforce_exact_match); return false; } bool lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs) { const ArchSpec::Core lhs_core = lhs.GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); return lhs_core < rhs_core; } static void StopInfoOverrideCallbackTypeARM(lldb_private::Thread &thread) { // We need to check if we are stopped in Thumb mode in a IT instruction // and detect if the condition doesn't pass. If this is the case it means // we won't actually execute this instruction. If this happens we need to // clear the stop reason to no thread plans think we are stopped for a // reason and the plans should keep going. // // We do this because when single stepping many ARM processes, debuggers // often use the BVR/BCR registers that says "stop when the PC is not // equal to its current value". This method of stepping means we can end // up stopping on instructions inside an if/then block that wouldn't get // executed. By fixing this we can stop the debugger from seeming like // you stepped through both the "if" _and_ the "else" clause when source // level stepping because the debugger stops regardless due to the BVR/BCR // triggering a stop. // // It also means we can set breakpoints on instructions inside an an // if/then block and correctly skip them if we use the BKPT instruction. // The ARM and Thumb BKPT instructions are unconditional even when executed // in a Thumb IT block. // // If your debugger inserts software traps in ARM/Thumb code, it will // need to use 16 and 32 bit instruction for 16 and 32 bit thumb // instructions respectively. If your debugger inserts a 16 bit thumb // trap on top of a 32 bit thumb instruction for an opcode that is inside // an if/then, it will change the it/then to conditionally execute your // 16 bit trap and then cause your program to crash if it executes the // trailing 16 bits (the second half of the 32 bit thumb instruction you // partially overwrote). RegisterContextSP reg_ctx_sp (thread.GetRegisterContext()); if (reg_ctx_sp) { const uint32_t cpsr = reg_ctx_sp->GetFlags(0); if (cpsr != 0) { // Read the J and T bits to get the ISETSTATE const uint32_t J = Bit32(cpsr, 24); const uint32_t T = Bit32(cpsr, 5); const uint32_t ISETSTATE = J << 1 | T; if (ISETSTATE == 0) { // NOTE: I am pretty sure we want to enable the code below // that detects when we stop on an instruction in ARM mode // that is conditional and the condition doesn't pass. This // can happen if you set a breakpoint on an instruction that // is conditional. We currently will _always_ stop on the // instruction which is bad. You can also run into this while // single stepping and you could appear to run code in the "if" // and in the "else" clause because it would stop at all of the // conditional instructions in both. // In such cases, we really don't want to stop at this location. // I will check with the lldb-dev list first before I enable this. #if 0 // ARM mode: check for condition on intsruction const addr_t pc = reg_ctx_sp->GetPC(); Error error; // If we fail to read the opcode we will get UINT64_MAX as the // result in "opcode" which we can use to detect if we read a // valid opcode. const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error); if (opcode <= UINT32_MAX) { const uint32_t condition = Bits32((uint32_t)opcode, 31, 28); if (!ARMConditionPassed(condition, cpsr)) { // We ARE stopped on an ARM instruction whose condition doesn't // pass so this instruction won't get executed. // Regardless of why it stopped, we need to clear the stop info thread.SetStopInfo (StopInfoSP()); } } #endif } else if (ISETSTATE == 1) { // Thumb mode const uint32_t ITSTATE = Bits32 (cpsr, 15, 10) << 2 | Bits32 (cpsr, 26, 25); if (ITSTATE != 0) { const uint32_t condition = Bits32(ITSTATE, 7, 4); if (!ARMConditionPassed(condition, cpsr)) { // We ARE stopped in a Thumb IT instruction on an instruction whose // condition doesn't pass so this instruction won't get executed. // Regardless of why it stopped, we need to clear the stop info thread.SetStopInfo (StopInfoSP()); } } } } } } ArchSpec::StopInfoOverrideCallbackType ArchSpec::GetStopInfoOverrideCallback () const { const llvm::Triple::ArchType machine = GetMachine(); if (machine == llvm::Triple::arm) return StopInfoOverrideCallbackTypeARM; return nullptr; } bool ArchSpec::IsFullySpecifiedTriple () const { const auto& user_specified_triple = GetTriple(); bool user_triple_fully_specified = false; if ((user_specified_triple.getOS() != llvm::Triple::UnknownOS) || TripleOSWasSpecified()) { if ((user_specified_triple.getVendor() != llvm::Triple::UnknownVendor) || TripleVendorWasSpecified()) { const unsigned unspecified = 0; if (user_specified_triple.getOSMajorVersion() != unspecified) { user_triple_fully_specified = true; } } } return user_triple_fully_specified; } void ArchSpec::PiecewiseTripleCompare (const ArchSpec &other, bool &arch_different, bool &vendor_different, bool &os_different, bool &os_version_different, bool &env_different) { const llvm::Triple &me(GetTriple()); const llvm::Triple &them(other.GetTriple()); arch_different = (me.getArch() != them.getArch()); vendor_different = (me.getVendor() != them.getVendor()); os_different = (me.getOS() != them.getOS()); os_version_different = (me.getOSMajorVersion() != them.getOSMajorVersion()); env_different = (me.getEnvironment() != them.getEnvironment()); } bool ArchSpec::IsAlwaysThumbInstructions () const { std::string Error; if (GetTriple().getArch() == llvm::Triple::arm || GetTriple().getArch() == llvm::Triple::thumb) { // v. https://en.wikipedia.org/wiki/ARM_Cortex-M // // Cortex-M0 through Cortex-M7 are ARM processor cores which can only // execute thumb instructions. We map the cores to arch names like this: // // Cortex-M0, Cortex-M0+, Cortex-M1: armv6m // Cortex-M3: armv7m // Cortex-M4, Cortex-M7: armv7em if (GetCore() == ArchSpec::Core::eCore_arm_armv7m || GetCore() == ArchSpec::Core::eCore_arm_armv7em || GetCore() == ArchSpec::Core::eCore_arm_armv6m) { return true; } } return false; } void ArchSpec::DumpTriple(Stream &s) const { const llvm::Triple &triple = GetTriple(); llvm::StringRef arch_str = triple.getArchName(); llvm::StringRef vendor_str = triple.getVendorName(); llvm::StringRef os_str = triple.getOSName(); llvm::StringRef environ_str = triple.getEnvironmentName(); s.Printf("%s-%s-%s", arch_str.empty() ? "*" : arch_str.str().c_str(), vendor_str.empty() ? "*" : vendor_str.str().c_str(), os_str.empty() ? "*" : os_str.str().c_str() ); if (!environ_str.empty()) s.Printf("-%s", environ_str.str().c_str()); } diff --git a/source/Core/RegisterValue.cpp b/source/Core/RegisterValue.cpp index d9085d7f0bae..d739dd6b5902 100644 --- a/source/Core/RegisterValue.cpp +++ b/source/Core/RegisterValue.cpp @@ -1,1034 +1,1037 @@ //===-- RegisterValue.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/RegisterValue.h" // C Includes // C++ Includes #include // Other libraries and framework includes #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" // Project includes #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamString.h" #include "lldb/Interpreter/Args.h" #include "lldb/Host/StringConvert.h" using namespace lldb; using namespace lldb_private; bool RegisterValue::Dump (Stream *s, const RegisterInfo *reg_info, bool prefix_with_name, bool prefix_with_alt_name, Format format, uint32_t reg_name_right_align_at) const { DataExtractor data; if (GetData (data)) { bool name_printed = false; // For simplicity, alignment of the register name printing applies only // in the most common case where: // // prefix_with_name^prefix_with_alt_name is true // StreamString format_string; if (reg_name_right_align_at && (prefix_with_name^prefix_with_alt_name)) format_string.Printf("%%%us", reg_name_right_align_at); else format_string.Printf("%%s"); const char *fmt = format_string.GetData(); if (prefix_with_name) { if (reg_info->name) { s->Printf (fmt, reg_info->name); name_printed = true; } else if (reg_info->alt_name) { s->Printf (fmt, reg_info->alt_name); prefix_with_alt_name = false; name_printed = true; } } if (prefix_with_alt_name) { if (name_printed) s->PutChar ('/'); if (reg_info->alt_name) { s->Printf (fmt, reg_info->alt_name); name_printed = true; } else if (!name_printed) { // No alternate name but we were asked to display a name, so show the main name s->Printf (fmt, reg_info->name); name_printed = true; } } if (name_printed) s->PutCString (" = "); if (format == eFormatDefault) format = reg_info->format; data.Dump (s, 0, // Offset in "data" format, // Format to use when dumping reg_info->byte_size, // item_byte_size 1, // item_count UINT32_MAX, // num_per_line LLDB_INVALID_ADDRESS, // base_addr 0, // item_bit_size 0); // item_bit_offset return true; } return false; } bool RegisterValue::GetData (DataExtractor &data) const { return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0; } uint32_t RegisterValue::GetAsMemoryData (const RegisterInfo *reg_info, void *dst, uint32_t dst_len, lldb::ByteOrder dst_byte_order, Error &error) const { if (reg_info == nullptr) { error.SetErrorString ("invalid register info argument."); return 0; } // ReadRegister should have already been called on this object prior to // calling this. if (GetType() == eTypeInvalid) { // No value has been read into this object... error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name); return 0; } if (dst_len > kMaxRegisterByteSize) { error.SetErrorString ("destination is too big"); return 0; } const uint32_t src_len = reg_info->byte_size; // Extract the register data into a data extractor DataExtractor reg_data; if (!GetData(reg_data)) { error.SetErrorString ("invalid register value to copy into"); return 0; } // Prepare a memory buffer that contains some or all of the register value const uint32_t bytes_copied = reg_data.CopyByteOrderedData (0, // src offset src_len, // src length dst, // dst buffer dst_len, // dst length dst_byte_order); // dst byte order if (bytes_copied == 0) error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name); return bytes_copied; } uint32_t RegisterValue::SetFromMemoryData (const RegisterInfo *reg_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Error &error) { if (reg_info == nullptr) { error.SetErrorString ("invalid register info argument."); return 0; } // Moving from addr into a register // // Case 1: src_len == dst_len // // |AABBCCDD| Address contents // |AABBCCDD| Register contents // // Case 2: src_len > dst_len // // Error! (The register should always be big enough to hold the data) // // Case 3: src_len < dst_len // // |AABB| Address contents // |AABB0000| Register contents [on little-endian hardware] // |0000AABB| Register contents [on big-endian hardware] if (src_len > kMaxRegisterByteSize) { error.SetErrorStringWithFormat ("register buffer is too small to receive %u bytes of data.", src_len); return 0; } const uint32_t dst_len = reg_info->byte_size; if (src_len > dst_len) { error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len); return 0; } // Use a data extractor to correctly copy and pad the bytes read into the // register value DataExtractor src_data (src, src_len, src_byte_order, 4); error = SetValueFromData(reg_info, src_data, 0, true); if (error.Fail()) return 0; // If SetValueFromData succeeded, we must have copied all of src_len return src_len; } bool RegisterValue::GetScalarValue (Scalar &scalar) const { switch (m_type) { case eTypeInvalid: break; case eTypeBytes: { switch (buffer.length) { default: break; case 1: scalar = *(const uint8_t *)buffer.bytes; return true; case 2: scalar = *(const uint16_t *)buffer.bytes; return true; case 4: scalar = *(const uint32_t *)buffer.bytes; return true; case 8: scalar = *(const uint64_t *)buffer.bytes; return true; case 16: case 32: if (buffer.length % sizeof(uint64_t) == 0) { const auto length_in_bits = buffer.length * 8; const auto length_in_uint64 = buffer.length / sizeof(uint64_t); scalar = llvm::APInt(length_in_bits, llvm::ArrayRef((const uint64_t *)buffer.bytes, length_in_uint64)); return true; } break; } } break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: scalar = m_scalar; return true; } return false; } void RegisterValue::Clear() { m_type = eTypeInvalid; } RegisterValue::Type RegisterValue::SetType (const RegisterInfo *reg_info) { // To change the type, we simply copy the data in again, using the new format RegisterValue copy; DataExtractor copy_data; if (copy.CopyValue(*this) && copy.GetData(copy_data)) SetValueFromData(reg_info, copy_data, 0, true); return m_type; } Error RegisterValue::SetValueFromData (const RegisterInfo *reg_info, DataExtractor &src, lldb::offset_t src_offset, bool partial_data_ok) { Error error; if (src.GetByteSize() == 0) { error.SetErrorString ("empty data."); return error; } if (reg_info->byte_size == 0) { error.SetErrorString ("invalid register info."); return error; } uint32_t src_len = src.GetByteSize() - src_offset; if (!partial_data_ok && (src_len < reg_info->byte_size)) { error.SetErrorString ("not enough data."); return error; } // Cap the data length if there is more than enough bytes for this register // value if (src_len > reg_info->byte_size) src_len = reg_info->byte_size; // Zero out the value in case we get partial data... memset (buffer.bytes, 0, sizeof (buffer.bytes)); type128 int128; m_type = eTypeInvalid; switch (reg_info->encoding) { case eEncodingInvalid: break; case eEncodingUint: case eEncodingSint: if (reg_info->byte_size == 1) SetUInt8(src.GetMaxU32(&src_offset, src_len)); else if (reg_info->byte_size <= 2) SetUInt16(src.GetMaxU32(&src_offset, src_len)); else if (reg_info->byte_size <= 4) SetUInt32(src.GetMaxU32(&src_offset, src_len)); else if (reg_info->byte_size <= 8) SetUInt64(src.GetMaxU64(&src_offset, src_len)); else if (reg_info->byte_size <= 16) { uint64_t data1 = src.GetU64 (&src_offset); uint64_t data2 = src.GetU64 (&src_offset); if (src.GetByteSize() == eByteOrderBig) { int128.x[0] = data1; int128.x[1] = data2; } else { int128.x[0] = data2; int128.x[1] = data1; } SetUInt128 (llvm::APInt(128, 2, int128.x)); } break; case eEncodingIEEE754: if (reg_info->byte_size == sizeof(float)) SetFloat(src.GetFloat(&src_offset)); else if (reg_info->byte_size == sizeof(double)) SetDouble(src.GetDouble(&src_offset)); else if (reg_info->byte_size == sizeof(long double)) SetLongDouble(src.GetLongDouble(&src_offset)); break; case eEncodingVector: { m_type = eTypeBytes; buffer.length = reg_info->byte_size; buffer.byte_order = src.GetByteOrder(); assert (buffer.length <= kMaxRegisterByteSize); if (buffer.length > kMaxRegisterByteSize) buffer.length = kMaxRegisterByteSize; if (src.CopyByteOrderedData (src_offset, // offset within "src" to start extracting data src_len, // src length buffer.bytes, // dst buffer buffer.length, // dst length buffer.byte_order) == 0)// dst byte order { error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name); return error; } } } if (m_type == eTypeInvalid) error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name); return error; } static inline void StripSpaces(llvm::StringRef &Str) { while (!Str.empty() && isspace(Str[0])) Str = Str.substr(1); while (!Str.empty() && isspace(Str.back())) Str = Str.substr(0, Str.size()-1); } static inline void LStrip(llvm::StringRef &Str, char c) { if (!Str.empty() && Str.front() == c) Str = Str.substr(1); } static inline void RStrip(llvm::StringRef &Str, char c) { if (!Str.empty() && Str.back() == c) Str = Str.substr(0, Str.size()-1); } // Helper function for RegisterValue::SetValueFromCString() static bool ParseVectorEncoding(const RegisterInfo *reg_info, const char *vector_str, const uint32_t byte_size, RegisterValue *reg_value) { // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}". llvm::StringRef Str(vector_str); StripSpaces(Str); LStrip(Str, '{'); RStrip(Str, '}'); StripSpaces(Str); char Sep = ' '; // The first split should give us: // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e'). std::pair Pair = Str.split(Sep); std::vector bytes; unsigned byte = 0; // Using radix auto-sensing by passing 0 as the radix. // Keep on processing the vector elements as long as the parsing succeeds and the vector size is < byte_size. while (!Pair.first.getAsInteger(0, byte) && bytes.size() < byte_size) { bytes.push_back(byte); Pair = Pair.second.split(Sep); } // Check for vector of exact byte_size elements. if (bytes.size() != byte_size) return false; reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle); return true; } Error RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *value_str) { Error error; if (reg_info == nullptr) { error.SetErrorString ("Invalid register info argument."); return error; } if (value_str == nullptr || value_str[0] == '\0') { error.SetErrorString ("Invalid c-string value string."); return error; } bool success = false; const uint32_t byte_size = reg_info->byte_size; static float flt_val; static double dbl_val; static long double ldbl_val; switch (reg_info->encoding) { case eEncodingInvalid: error.SetErrorString ("Invalid encoding."); break; case eEncodingUint: if (byte_size <= sizeof (uint64_t)) { uint64_t uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str); else if (!Args::UInt64ValueIsValidForByteSize (uval64, byte_size)) error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte unsigned integer value", uval64, byte_size); else { if (!SetUInt (uval64, reg_info->byte_size)) error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size); } } else { error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size); return error; } break; case eEncodingSint: if (byte_size <= sizeof (long long)) { uint64_t sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success); if (!success) error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str); else if (!Args::SInt64ValueIsValidForByteSize (sval64, byte_size)) error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte signed integer value", sval64, byte_size); else { if (!SetUInt (sval64, reg_info->byte_size)) error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size); } } else { error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size); return error; } break; case eEncodingIEEE754: if (byte_size == sizeof (float)) { if (::sscanf (value_str, "%f", &flt_val) == 1) { m_scalar = flt_val; m_type = eTypeFloat; } else error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str); } else if (byte_size == sizeof (double)) { if (::sscanf (value_str, "%lf", &dbl_val) == 1) { m_scalar = dbl_val; m_type = eTypeDouble; } else error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str); } else if (byte_size == sizeof (long double)) { if (::sscanf (value_str, "%Lf", &ldbl_val) == 1) { m_scalar = ldbl_val; m_type = eTypeLongDouble; } else error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str); } else { error.SetErrorStringWithFormat ("unsupported float byte size: %u", byte_size); return error; } break; case eEncodingVector: if (!ParseVectorEncoding(reg_info, value_str, byte_size, this)) error.SetErrorString ("unrecognized vector encoding string value."); break; } if (error.Fail()) m_type = eTypeInvalid; return error; } bool RegisterValue::SignExtend (uint32_t sign_bitpos) { switch (m_type) { case eTypeInvalid: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: return m_scalar.SignExtend(sign_bitpos); case eTypeFloat: case eTypeDouble: case eTypeLongDouble: case eTypeBytes: break; } return false; } bool RegisterValue::CopyValue (const RegisterValue &rhs) { m_type = rhs.m_type; switch (m_type) { case eTypeInvalid: return false; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: m_scalar = rhs.m_scalar; break; case eTypeBytes: assert (rhs.buffer.length <= kMaxRegisterByteSize); ::memcpy (buffer.bytes, rhs.buffer.bytes, kMaxRegisterByteSize); buffer.length = rhs.buffer.length; buffer.byte_order = rhs.buffer.byte_order; break; } return true; } uint16_t RegisterValue::GetAsUInt16 (uint16_t fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt8: case eTypeUInt16: return m_scalar.UShort(fail_value); case eTypeBytes: { switch (buffer.length) { default: break; case 1: case 2: return *(const uint16_t *)buffer.bytes; } } break; } if (success_ptr) *success_ptr = false; return fail_value; } uint32_t RegisterValue::GetAsUInt32 (uint32_t fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.UInt(fail_value); case eTypeBytes: { switch (buffer.length) { default: break; case 1: case 2: case 4: return *(const uint32_t *)buffer.bytes; } } break; } if (success_ptr) *success_ptr = false; return fail_value; } uint64_t RegisterValue::GetAsUInt64 (uint64_t fail_value, bool *success_ptr) const { - if (success_ptr) - *success_ptr = true; - switch (m_type) - { - default: break; - case eTypeUInt8: - case eTypeUInt16: - case eTypeUInt32: - case eTypeUInt64: - case eTypeFloat: - case eTypeDouble: - case eTypeLongDouble: return m_scalar.ULongLong(fail_value); - case eTypeBytes: - { - switch (buffer.length) - { - default: break; - case 1: - case 2: - case 4: - case 8: return *(const uint64_t *)buffer.bytes; - } - } - break; + if (success_ptr) + *success_ptr = true; + switch (m_type) { + default: + break; + case eTypeUInt8: + case eTypeUInt16: + case eTypeUInt32: + case eTypeUInt64: + case eTypeFloat: + case eTypeDouble: + case eTypeLongDouble: + return m_scalar.ULongLong(fail_value); + case eTypeBytes: { + switch (buffer.length) { + default: + break; + case 1: + return *(const uint8_t *)buffer.bytes; + case 2: + return *(const uint16_t *)buffer.bytes; + case 4: + return *(const uint32_t *)buffer.bytes; + case 8: + return *(const uint64_t *)buffer.bytes; } - if (success_ptr) - *success_ptr = false; - return fail_value; + } break; + } + if (success_ptr) + *success_ptr = false; + return fail_value; } llvm::APInt RegisterValue::GetAsUInt128 (const llvm::APInt& fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.UInt128(fail_value); case eTypeBytes: { switch (buffer.length) { default: break; case 1: case 2: case 4: case 8: case 16: return llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, ((const type128 *)buffer.bytes)->x); } } break; } if (success_ptr) *success_ptr = false; return fail_value; } float RegisterValue::GetAsFloat (float fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.Float(fail_value); } if (success_ptr) *success_ptr = false; return fail_value; } double RegisterValue::GetAsDouble (double fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.Double(fail_value); } if (success_ptr) *success_ptr = false; return fail_value; } long double RegisterValue::GetAsLongDouble (long double fail_value, bool *success_ptr) const { if (success_ptr) *success_ptr = true; switch (m_type) { default: break; case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.LongDouble(); } if (success_ptr) *success_ptr = false; return fail_value; } const void * RegisterValue::GetBytes () const { switch (m_type) { case eTypeInvalid: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.GetBytes(); case eTypeBytes: return buffer.bytes; } return nullptr; } uint32_t RegisterValue::GetByteSize () const { switch (m_type) { case eTypeInvalid: break; case eTypeUInt8: return 1; case eTypeUInt16: return 2; case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar.GetByteSize(); case eTypeBytes: return buffer.length; } return 0; } bool RegisterValue::SetUInt (uint64_t uint, uint32_t byte_size) { if (byte_size == 0) { SetUInt64 (uint); } else if (byte_size == 1) { SetUInt8 (uint); } else if (byte_size <= 2) { SetUInt16 (uint); } else if (byte_size <= 4) { SetUInt32 (uint); } else if (byte_size <= 8) { SetUInt64 (uint); } else if (byte_size <= 16) { SetUInt128 (llvm::APInt(128, uint)); } else return false; return true; } void RegisterValue::SetBytes (const void *bytes, size_t length, lldb::ByteOrder byte_order) { // If this assertion fires off we need to increase the size of // buffer.bytes, or make it something that is allocated on // the heap. Since the data buffer is in a union, we can't make it // a collection class like SmallVector... if (bytes && length > 0) { assert (length <= sizeof (buffer.bytes) && "Storing too many bytes in a RegisterValue."); m_type = eTypeBytes; buffer.length = length; memcpy (buffer.bytes, bytes, length); buffer.byte_order = byte_order; } else { m_type = eTypeInvalid; buffer.length = 0; } } bool RegisterValue::operator == (const RegisterValue &rhs) const { if (m_type == rhs.m_type) { switch (m_type) { case eTypeInvalid: return true; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar == rhs.m_scalar; case eTypeBytes: if (buffer.length != rhs.buffer.length) return false; else { uint8_t length = buffer.length; if (length > kMaxRegisterByteSize) length = kMaxRegisterByteSize; return memcmp (buffer.bytes, rhs.buffer.bytes, length) == 0; } break; } } return false; } bool RegisterValue::operator != (const RegisterValue &rhs) const { if (m_type != rhs.m_type) return true; switch (m_type) { case eTypeInvalid: return false; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: case eTypeFloat: case eTypeDouble: case eTypeLongDouble: return m_scalar != rhs.m_scalar; case eTypeBytes: if (buffer.length != rhs.buffer.length) { return true; } else { uint8_t length = buffer.length; if (length > kMaxRegisterByteSize) length = kMaxRegisterByteSize; return memcmp (buffer.bytes, rhs.buffer.bytes, length) != 0; } break; } return true; } bool RegisterValue::ClearBit (uint32_t bit) { switch (m_type) { case eTypeInvalid: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: if (bit < (GetByteSize() * 8)) { return m_scalar.ClearBit(bit); } break; case eTypeFloat: case eTypeDouble: case eTypeLongDouble: break; case eTypeBytes: if (buffer.byte_order == eByteOrderBig || buffer.byte_order == eByteOrderLittle) { uint32_t byte_idx; if (buffer.byte_order == eByteOrderBig) byte_idx = buffer.length - (bit / 8) - 1; else byte_idx = bit / 8; const uint32_t byte_bit = bit % 8; if (byte_idx < buffer.length) { buffer.bytes[byte_idx] &= ~(1u << byte_bit); return true; } } break; } return false; } bool RegisterValue::SetBit (uint32_t bit) { switch (m_type) { case eTypeInvalid: break; case eTypeUInt8: case eTypeUInt16: case eTypeUInt32: case eTypeUInt64: case eTypeUInt128: if (bit < (GetByteSize() * 8)) { return m_scalar.SetBit(bit); } break; case eTypeFloat: case eTypeDouble: case eTypeLongDouble: break; case eTypeBytes: if (buffer.byte_order == eByteOrderBig || buffer.byte_order == eByteOrderLittle) { uint32_t byte_idx; if (buffer.byte_order == eByteOrderBig) byte_idx = buffer.length - (bit / 8) - 1; else byte_idx = bit / 8; const uint32_t byte_bit = bit % 8; if (byte_idx < buffer.length) { buffer.bytes[byte_idx] |= (1u << byte_bit); return true; } } break; } return false; } diff --git a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp index f74871544b69..bf8ab3a658b3 100644 --- a/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp +++ b/source/Plugins/ABI/SysV-mips64/ABISysV_mips64.cpp @@ -1,895 +1,923 @@ //===-- ABISysV_mips64.cpp --------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ABISysV_mips64.h" // C Includes // C++ Includes // Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" // Project includes #include "lldb/Core/ConstString.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectRegister.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Target.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; enum dwarf_regnums { dwarf_r0 = 0, dwarf_r1, dwarf_r2, dwarf_r3, dwarf_r4, dwarf_r5, dwarf_r6, dwarf_r7, dwarf_r8, dwarf_r9, dwarf_r10, dwarf_r11, dwarf_r12, dwarf_r13, dwarf_r14, dwarf_r15, dwarf_r16, dwarf_r17, dwarf_r18, dwarf_r19, dwarf_r20, dwarf_r21, dwarf_r22, dwarf_r23, dwarf_r24, dwarf_r25, dwarf_r26, dwarf_r27, dwarf_r28, dwarf_r29, dwarf_r30, dwarf_r31, dwarf_sr, dwarf_lo, dwarf_hi, dwarf_bad, dwarf_cause, dwarf_pc }; static const RegisterInfo g_register_infos_mips64[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE REGS INVALIDATE REGS // ======== ====== == === ============= ========== ============= ================= ==================== ================= ==================== ========== =============== { "r0" , "zero", 8, 0, eEncodingUint, eFormatHex, { dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r1" , "AT", 8, 0, eEncodingUint, eFormatHex, { dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r2" , "v0", 8, 0, eEncodingUint, eFormatHex, { dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r3" , "v1", 8, 0, eEncodingUint, eFormatHex, { dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r4" , "arg1", 8, 0, eEncodingUint, eFormatHex, { dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r5" , "arg2", 8, 0, eEncodingUint, eFormatHex, { dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r6" , "arg3", 8, 0, eEncodingUint, eFormatHex, { dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r7" , "arg4", 8, 0, eEncodingUint, eFormatHex, { dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r8" , "arg5", 8, 0, eEncodingUint, eFormatHex, { dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r9" , "arg6", 8, 0, eEncodingUint, eFormatHex, { dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r10" , "arg7", 8, 0, eEncodingUint, eFormatHex, { dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r11" , "arg8", 8, 0, eEncodingUint, eFormatHex, { dwarf_r11, dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r12" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r13" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r14" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r15" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r16" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r17" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r18" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r19" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r20" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r21" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r22" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r23" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r24" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r25" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r26" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r27" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r28" , "gp", 8, 0, eEncodingUint, eFormatHex, { dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r29" , "sp", 8, 0, eEncodingUint, eFormatHex, { dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r30" , "fp", 8, 0, eEncodingUint, eFormatHex, { dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "r31" , "ra", 8, 0, eEncodingUint, eFormatHex, { dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "sr" , nullptr,4, 0, eEncodingUint, eFormatHex, { dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "lo" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "hi" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "bad" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "cause" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, { "pc" , nullptr,8, 0, eEncodingUint, eFormatHex, { dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr }, }; static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos_mips64); const lldb_private::RegisterInfo * ABISysV_mips64::GetRegisterInfoArray (uint32_t &count) { count = k_num_register_infos; return g_register_infos_mips64; } size_t ABISysV_mips64::GetRedZoneSize () const { return 0; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ ABISP ABISysV_mips64::CreateInstance (const ArchSpec &arch) { static ABISP g_abi_sp; const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch(); if ((arch_type == llvm::Triple::mips64) || (arch_type == llvm::Triple::mips64el)) { if (!g_abi_sp) g_abi_sp.reset (new ABISysV_mips64); return g_abi_sp; } return ABISP(); } bool ABISysV_mips64::PrepareTrivialCall (Thread &thread, addr_t sp, addr_t func_addr, addr_t return_addr, llvm::ArrayRef args) const { Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); if (log) { StreamString s; s.Printf("ABISysV_mips64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, (uint64_t)return_addr); for (size_t i = 0; i < args.size(); ++i) s.Printf (", arg%zd = 0x%" PRIx64, i + 1, args[i]); s.PutCString (")"); log->PutCString(s.GetString().c_str()); } RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return false; const RegisterInfo *reg_info = nullptr; if (args.size() > 8) // TODO handle more than 8 arguments return false; for (size_t i = 0; i < args.size(); ++i) { reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i); if (log) log->Printf("About to write arg%zd (0x%" PRIx64 ") into %s", i + 1, args[i], reg_info->name); if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i])) return false; } // First, align the SP if (log) log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull)); sp &= ~(0xfull); // 16-byte alignment Error error; const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); const RegisterInfo *ra_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0); const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0); if (log) log->Printf("Writing R0: 0x%" PRIx64, (uint64_t)0); /* Write r0 with 0, in case we are stopped in syscall, * such setting prevents automatic decrement of the PC. * This clears the bug 23659 for MIPS. */ if (!reg_ctx->WriteRegisterFromUnsigned (r0_info, (uint64_t)0)) return false; if (log) log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp); // Set "sp" to the requested value if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp)) return false; if (log) log->Printf("Writing RA: 0x%" PRIx64, (uint64_t)return_addr); // Set "ra" to the return address if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_info, return_addr)) return false; if (log) log->Printf("Writing PC: 0x%" PRIx64, (uint64_t)func_addr); // Set pc to the address of the called function. if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr)) return false; if (log) log->Printf("Writing r25: 0x%" PRIx64, (uint64_t)func_addr); // All callers of position independent functions must place the address of the called function in t9 (r25) if (!reg_ctx->WriteRegisterFromUnsigned (r25_info, func_addr)) return false; return true; } bool ABISysV_mips64::GetArgumentValues (Thread &thread, ValueList &values) const { return false; } Error ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp) { Error error; if (!new_value_sp) { error.SetErrorString("Empty value object for return value."); return error; } CompilerType compiler_type = new_value_sp->GetCompilerType(); if (!compiler_type) { error.SetErrorString ("Null clang type for return value."); return error; } Thread *thread = frame_sp->GetThread().get(); RegisterContext *reg_ctx = thread->GetRegisterContext().get(); if (!reg_ctx) error.SetErrorString("no registers are available"); DataExtractor data; Error data_error; size_t num_bytes = new_value_sp->GetData(data, data_error); if (data_error.Fail()) { error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString()); return error; } const uint32_t type_flags = compiler_type.GetTypeInfo(nullptr); if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer ) { lldb::offset_t offset = 0; if (num_bytes <= 16) { const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0); if (num_bytes <= 8) { uint64_t raw_value = data.GetMaxU64(&offset, num_bytes); if (!reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value)) error.SetErrorString ("failed to write register r2"); } else { uint64_t raw_value = data.GetMaxU64(&offset, 8); if (reg_ctx->WriteRegisterFromUnsigned (r2_info, raw_value)) { const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0); raw_value = data.GetMaxU64(&offset, num_bytes - offset); if (!reg_ctx->WriteRegisterFromUnsigned (r3_info, raw_value)) error.SetErrorString ("failed to write register r3"); } else error.SetErrorString ("failed to write register r2"); } } else { error.SetErrorString("We don't support returning longer than 128 bit integer values at present."); } } else if (type_flags & eTypeIsFloat) { error.SetErrorString("TODO: Handle Float Types."); } } else if (type_flags & eTypeIsVector) { error.SetErrorString("returning vector values are not supported"); } return error; } ValueObjectSP ABISysV_mips64::GetReturnValueObjectSimple (Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; return return_valobj_sp; } ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_compiler_type) const { ValueObjectSP return_valobj_sp; Value value; Error error; ExecutionContext exe_ctx (thread.shared_from_this()); if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr) return return_valobj_sp; value.SetCompilerType(return_compiler_type); RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) return return_valobj_sp; Target *target = exe_ctx.GetTargetPtr(); const ArchSpec target_arch = target->GetArchitecture(); ByteOrder target_byte_order = target_arch.GetByteOrder(); const size_t byte_size = return_compiler_type.GetByteSize(nullptr); const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); uint32_t fp_flag = target_arch.GetFlags () & lldb_private::ArchSpec::eMIPS_ABI_FP_mask; const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0); const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0); if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { value.SetValueType(Value::eValueTypeScalar); bool success = false; if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { // Extract the register context so we can read arguments from registers // In MIPS register "r2" (v0) holds the integer function return values uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); const bool is_signed = (type_flags & eTypeIsSigned) != 0; switch (byte_size) { default: break; case sizeof(uint64_t): if (is_signed) value.GetScalar() = (int64_t)(raw_value); else value.GetScalar() = (uint64_t)(raw_value); success = true; break; case sizeof(uint32_t): if (is_signed) value.GetScalar() = (int32_t)(raw_value & UINT32_MAX); else value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX); success = true; break; case sizeof(uint16_t): if (is_signed) value.GetScalar() = (int16_t)(raw_value & UINT16_MAX); else value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX); success = true; break; case sizeof(uint8_t): if (is_signed) value.GetScalar() = (int8_t)(raw_value & UINT8_MAX); else value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX); success = true; break; } } else if (type_flags & eTypeIsFloat) { if (type_flags & eTypeIsComplex) { // Don't handle complex yet. } else if (IsSoftFloat(fp_flag)) { uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0); switch (byte_size) { case 4: value.GetScalar() = *((float *)(&raw_value)); success = true; break; case 8: value.GetScalar() = *((double *)(&raw_value)); success = true; break; case 16: uint64_t result[2]; if (target_byte_order == eByteOrderLittle) { result[0] = raw_value; result[1] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); value.GetScalar() = *((long double *)(result)); } else { result[0] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0); result[1] = raw_value; value.GetScalar() = *((long double *)(result)); } success = true; break; } } else { if (byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; DataExtractor f0_data; reg_ctx->ReadRegister (f0_info, f0_value); f0_value.GetData(f0_data); lldb::offset_t offset = 0; if (byte_size == sizeof(float)) { value.GetScalar() = (float) f0_data.GetFloat(&offset); success = true; } else if (byte_size == sizeof(double)) { value.GetScalar() = (double) f0_data.GetDouble(&offset); success = true; } else if (byte_size == sizeof(long double)) { const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); RegisterValue f2_value; DataExtractor f2_data; reg_ctx->ReadRegister (f2_info, f2_value); DataExtractor *copy_from_extractor = nullptr; DataBufferSP data_sp (new DataBufferHeap(16, 0)); DataExtractor return_ext (data_sp, target_byte_order, target->GetArchitecture().GetAddressByteSize()); if (target_byte_order == eByteOrderLittle) { copy_from_extractor = &f0_data; copy_from_extractor->CopyByteOrderedData (0, 8, data_sp->GetBytes(), byte_size - 8, target_byte_order); f2_value.GetData(f2_data); copy_from_extractor = &f2_data; copy_from_extractor->CopyByteOrderedData (0, 8, data_sp->GetBytes() + 8, byte_size - 8, target_byte_order); } else { copy_from_extractor = &f0_data; copy_from_extractor->CopyByteOrderedData (0, 8, data_sp->GetBytes() + 8, byte_size - 8, target_byte_order); f2_value.GetData(f2_data); copy_from_extractor = &f2_data; copy_from_extractor->CopyByteOrderedData (0, 8, data_sp->GetBytes(), byte_size - 8, target_byte_order); } return_valobj_sp = ValueObjectConstResult::Create (&thread, return_compiler_type, ConstString(""), return_ext); return return_valobj_sp; } } } } if (success) return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass || type_flags & eTypeIsVector) { // Any structure of up to 16 bytes in size is returned in the registers. if (byte_size <= 16) { - DataBufferSP data_sp (new DataBufferHeap(16, 0)); - DataExtractor return_ext (data_sp, - target_byte_order, - target->GetArchitecture().GetAddressByteSize()); + DataBufferSP data_sp(new DataBufferHeap(16, 0)); + DataExtractor return_ext(data_sp, target_byte_order, + target->GetArchitecture().GetAddressByteSize()); RegisterValue r2_value, r3_value, f0_value, f1_value, f2_value; + // Tracks how much bytes of r2 and r3 registers we've consumed so far + uint32_t integer_bytes = 0; + + // True if return values are in FP return registers. + bool use_fp_regs = 0; + // True if we found any non floating point field in structure. + bool found_non_fp_field = 0; + // True if return values are in r2 register. + bool use_r2 = 0; + // True if return values are in r3 register. + bool use_r3 = 0; + // True if the result is copied into our data buffer + bool sucess = 0; + std::string name; + bool is_complex; + uint32_t count; + const uint32_t num_children = return_compiler_type.GetNumFields(); + + // A structure consisting of one or two FP values (and nothing else) will + // be returned in the two FP return-value registers i.e fp0 and fp2. + + if (num_children <= 2) + { + uint64_t field_bit_offset = 0; + + // Check if this structure contains only floating point fields + for (uint32_t idx = 0; idx < num_children; idx++) + { + CompilerType field_compiler_type = + return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, + nullptr, nullptr); + + if (field_compiler_type.IsFloatingPointType(count, is_complex)) + use_fp_regs = 1; + else + found_non_fp_field = 1; + } + + if (use_fp_regs && !found_non_fp_field) + { + // We have one or two FP-only values in this structure. Get it from + // f0/f2 registers. + DataExtractor f0_data, f1_data, f2_data; + const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); + const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); + const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); + + reg_ctx->ReadRegister(f0_info, f0_value); + reg_ctx->ReadRegister(f2_info, f2_value); + + f0_value.GetData(f0_data); + + + for (uint32_t idx = 0; idx < num_children; idx++) + { + CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(idx, name, + &field_bit_offset, + nullptr, nullptr); + const size_t field_byte_width = field_compiler_type.GetByteSize(nullptr); + + DataExtractor *copy_from_extractor = nullptr; + uint64_t return_value[2]; + offset_t offset = 0; + + if (idx == 0) + { + // This case is for long double type. + if (field_byte_width == 16) + { + + // If structure contains long double type, then it is returned + // in fp0/fp1 registers. + + + + if (target_byte_order == eByteOrderLittle) + { + return_value[0] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[1] = f1_data.GetU64(&offset); + } + else + { + return_value[1] = f0_data.GetU64(&offset); + reg_ctx->ReadRegister(f1_info, f1_value); + f1_value.GetData(f1_data); + offset = 0; + return_value[0] = f1_data.GetU64(&offset); + } + + f0_data.SetData(return_value, field_byte_width, + target_byte_order); + } + copy_from_extractor = &f0_data; // This is in f0, copy from + + // register to our result + // structure + } + else + { + f2_value.GetData(f2_data); + // This is in f2, copy from register to our result structure + copy_from_extractor = &f2_data; + } - uint32_t integer_bytes = 0; // Tracks how much bytes of r2 and r3 registers we've consumed so far - bool use_fp_regs = 0; // True if return values are in FP return registers. - bool found_non_fp_field = 0; // True if we found any non floating point field in structure. - bool use_r2 = 0; // True if return values are in r2 register. - bool use_r3 = 0; // True if return values are in r3 register. - bool sucess = 0; // True if the result is copied into our data buffer - std::string name; - bool is_complex; - uint32_t count; - const uint32_t num_children = return_compiler_type.GetNumFields (); - - // A structure consisting of one or two FP values (and nothing else) will be - // returned in the two FP return-value registers i.e fp0 and fp2. - if (num_children <= 2) - { - uint64_t field_bit_offset = 0; - - // Check if this structure contains only floating point fields - for (uint32_t idx = 0; idx < num_children; idx++) - { - CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, nullptr, nullptr); - - if (field_compiler_type.IsFloatingPointType (count, is_complex)) - use_fp_regs = 1; - else - found_non_fp_field = 1; - } - - if (use_fp_regs && !found_non_fp_field) - { - // We have one or two FP-only values in this structure. Get it from f0/f2 registers. - DataExtractor f0_data, f1_data, f2_data; - const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); - const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); - const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0); - - reg_ctx->ReadRegister (f0_info, f0_value); - reg_ctx->ReadRegister (f2_info, f2_value); - - f0_value.GetData(f0_data); - f2_value.GetData(f2_data); - - for (uint32_t idx = 0; idx < num_children; idx++) - { - CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, nullptr, nullptr); - const size_t field_byte_width = field_compiler_type.GetByteSize(nullptr); + // Sanity check to avoid crash + if (!copy_from_extractor || field_byte_width > copy_from_extractor->GetByteSize()) + return return_valobj_sp; - DataExtractor *copy_from_extractor = nullptr; + // copy the register contents into our data buffer + copy_from_extractor->CopyByteOrderedData(0, field_byte_width,data_sp->GetBytes() + (field_bit_offset / 8), + field_byte_width, target_byte_order); + } - if (idx == 0) - { - if (field_byte_width == 16) // This case is for long double type. - { - // If structure contains long double type, then it is returned in fp0/fp1 registers. - reg_ctx->ReadRegister (f1_info, f1_value); - f1_value.GetData(f1_data); - - if (target_byte_order == eByteOrderLittle) - { - f0_data.Append(f1_data); - copy_from_extractor = &f0_data; - } - else - { - f1_data.Append(f0_data); - copy_from_extractor = &f1_data; - } - } - else - copy_from_extractor = &f0_data; // This is in f0, copy from register to our result structure - } - else - copy_from_extractor = &f2_data; // This is in f2, copy from register to our result structure - - // Sanity check to avoid crash - if (!copy_from_extractor || field_byte_width > copy_from_extractor->GetByteSize()) - return return_valobj_sp; - - // copy the register contents into our data buffer - copy_from_extractor->CopyByteOrderedData (0, - field_byte_width, - data_sp->GetBytes() + (field_bit_offset/8), - field_byte_width, - target_byte_order); - } - - // The result is in our data buffer. Create a variable object out of it - return_valobj_sp = ValueObjectConstResult::Create (&thread, - return_compiler_type, - ConstString(""), - return_ext); - - return return_valobj_sp; - } - } + // The result is in our data buffer. Create a variable object out of + // it + return_valobj_sp = ValueObjectConstResult::Create(&thread, return_compiler_type, ConstString(""), + return_ext); + return return_valobj_sp; + } + } + + // If we reach here, it means this structure either contains more than two fields or // it contains at least one non floating point type. // In that case, all fields are returned in GP return registers. for (uint32_t idx = 0; idx < num_children; idx++) { uint64_t field_bit_offset = 0; bool is_signed; uint32_t padding; CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, nullptr, nullptr); const size_t field_byte_width = field_compiler_type.GetByteSize(nullptr); // if we don't know the size of the field (e.g. invalid type), just bail out if (field_byte_width == 0) break; uint32_t field_byte_offset = field_bit_offset/8; if (field_compiler_type.IsIntegerOrEnumerationType (is_signed) || field_compiler_type.IsPointerType () || field_compiler_type.IsFloatingPointType (count, is_complex)) { padding = field_byte_offset - integer_bytes; if (integer_bytes < 8) { // We have not yet consumed r2 completely. if (integer_bytes + field_byte_width + padding <= 8) { // This field fits in r2, copy its value from r2 to our result structure integer_bytes = integer_bytes + field_byte_width + padding; // Increase the consumed bytes. use_r2 = 1; } else { // There isn't enough space left in r2 for this field, so this will be in r3. integer_bytes = integer_bytes + field_byte_width + padding; // Increase the consumed bytes. use_r3 = 1; } } // We already have consumed at-least 8 bytes that means r2 is done, and this field will be in r3. // Check if this field can fit in r3. else if (integer_bytes + field_byte_width + padding <= 16) { integer_bytes = integer_bytes + field_byte_width + padding; use_r3 = 1; } else { // There isn't any space left for this field, this should not happen as we have already checked // the overall size is not greater than 16 bytes. For now, return a nullptr return value object. return return_valobj_sp; } } } // Vector types upto 16 bytes are returned in GP return registers if (type_flags & eTypeIsVector) { if (byte_size <= 8) use_r2 = 1; else { use_r2 = 1; use_r3 = 1; } } if (use_r2) { reg_ctx->ReadRegister (r2_info, r2_value); const size_t bytes_copied = r2_value.GetAsMemoryData (r2_info, data_sp->GetBytes(), r2_info->byte_size, target_byte_order, error); if (bytes_copied != r2_info->byte_size) return return_valobj_sp; sucess = 1; } if (use_r3) { reg_ctx->ReadRegister (r3_info, r3_value); const size_t bytes_copied = r3_value.GetAsMemoryData (r3_info, data_sp->GetBytes() + r2_info->byte_size, r3_info->byte_size, target_byte_order, error); if (bytes_copied != r3_info->byte_size) return return_valobj_sp; sucess = 1; } if (sucess) { // The result is in our data buffer. Create a variable object out of it return_valobj_sp = ValueObjectConstResult::Create (&thread, return_compiler_type, ConstString(""), return_ext); } return return_valobj_sp; } // Any structure/vector greater than 16 bytes in size is returned in memory. // The pointer to that memory is returned in r2. uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("r2", 0), 0); // We have got the address. Create a memory object out of it return_valobj_sp = ValueObjectMemory::Create(&thread, "", Address(mem_address, nullptr), return_compiler_type); } return return_valobj_sp; } bool ABISysV_mips64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind (eRegisterKindDWARF); UnwindPlan::RowSP row(new UnwindPlan::Row); // Our Call Frame Address is the stack pointer value row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0); // The previous PC is in the RA row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true); unwind_plan.AppendRow (row); // All other registers are the same. unwind_plan.SetSourceName ("mips64 at-func-entry default"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetReturnAddressRegister(dwarf_r31); return true; } bool ABISysV_mips64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind (eRegisterKindDWARF); UnwindPlan::RowSP row(new UnwindPlan::Row); row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0); row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true); unwind_plan.AppendRow (row); unwind_plan.SetSourceName ("mips64 default unwind plan"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); return true; } bool ABISysV_mips64::RegisterIsVolatile (const RegisterInfo *reg_info) { return !RegisterIsCalleeSaved (reg_info); } bool ABISysV_mips64::IsSoftFloat (uint32_t fp_flag) const { return (fp_flag == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT); } bool ABISysV_mips64::RegisterIsCalleeSaved (const RegisterInfo *reg_info) { if (reg_info) { // Preserved registers are : // r16-r23, r28, r29, r30, r31 int reg = ((reg_info->byte_offset) / 8); bool save = (reg >= 16) && (reg <= 23); save |= (reg >= 28) && (reg <= 31); return save; } return false; } void ABISysV_mips64::Initialize() { PluginManager::RegisterPlugin (GetPluginNameStatic(), "System V ABI for mips64 targets", CreateInstance); } void ABISysV_mips64::Terminate() { PluginManager::UnregisterPlugin (CreateInstance); } lldb_private::ConstString ABISysV_mips64::GetPluginNameStatic() { static ConstString g_name("sysv-mips64"); return g_name; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ lldb_private::ConstString ABISysV_mips64::GetPluginName() { return GetPluginNameStatic(); } uint32_t ABISysV_mips64::GetPluginVersion() { return 1; } diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index df0a008ff5f7..0188c5d30724 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -1,230 +1,230 @@ //===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "NativeRegisterContextLinux.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/Host/linux/Ptrace.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" using namespace lldb_private; using namespace lldb_private::process_linux; NativeRegisterContextLinux::NativeRegisterContextLinux(NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, RegisterInfoInterface *reg_info_interface_p) : NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, reg_info_interface_p) {} lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { // Get the target process whose privileged thread was used for the register read. lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); if (!process_sp) return byte_order; if (!process_sp->GetByteOrder (byte_order)) { // FIXME log here } return byte_order; } Error NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value) { const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); if (!reg_info) return Error("register %" PRIu32 " not found", reg_index); return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value); } Error NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue ®_value) { uint32_t reg_to_write = reg_index; RegisterValue value_to_write = reg_value; // Check if this is a subregister of a full register. const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { Error error; RegisterValue full_value; uint32_t full_reg = reg_info->invalidate_regs[0]; const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); // Read the full register. error = ReadRegister(full_reg_info, full_value); if (error.Fail ()) return error; lldb::ByteOrder byte_order = GetByteOrder(); uint8_t dst[RegisterValue::kMaxRegisterByteSize]; // Get the bytes for the full register. const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, dst, sizeof(dst), byte_order, error); if (error.Success() && dest_size) { uint8_t src[RegisterValue::kMaxRegisterByteSize]; // Get the bytes for the source data. const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); if (error.Success() && src_size && (src_size < dest_size)) { // Copy the src bytes to the destination. memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); // Set this full register as the value to write. value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); value_to_write.SetType(full_reg_info); reg_to_write = full_reg; } } } const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); if (!register_to_write_info_p) return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); } Error NativeRegisterContextLinux::ReadGPR() { void* buf = GetGPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetGPRSize(); return DoReadGPR(buf, buf_size); } Error NativeRegisterContextLinux::WriteGPR() { void* buf = GetGPRBuffer(); if (!buf) return Error("GPR buffer is NULL"); size_t buf_size = GetGPRSize(); return DoWriteGPR(buf, buf_size); } Error NativeRegisterContextLinux::ReadFPR() { void* buf = GetFPRBuffer(); if (!buf) return Error("FPR buffer is NULL"); size_t buf_size = GetFPRSize(); return DoReadFPR(buf, buf_size); } Error NativeRegisterContextLinux::WriteFPR() { void* buf = GetFPRBuffer(); if (!buf) return Error("FPR buffer is NULL"); size_t buf_size = GetFPRSize(); return DoWriteFPR(buf, buf_size); } Error NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset) { return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), static_cast(®set), buf, buf_size); } Error NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset) { return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), static_cast(®set), buf, buf_size); } Error NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, const char* reg_name, uint32_t size, RegisterValue &value) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); long data; Error error = NativeProcessLinux::PtraceWrapper( PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast(offset), nullptr, 0, &data); if (error.Success()) - // First cast to an unsigned of the same size to avoid sign extension. - value.SetUInt64(static_cast(data)); + // First cast to an unsigned of the same size to avoid sign extension. + value.SetUInt(static_cast(data), size); if (log) log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%lx", __FUNCTION__, reg_name, data); return error; } Error NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset, const char* reg_name, const RegisterValue &value) { Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS)); void* buf = reinterpret_cast(value.GetAsUInt64()); if (log) log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf); return NativeProcessLinux::PtraceWrapper( PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast(offset), buf); } Error NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) { return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size); } Error NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) { return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size); } Error NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) { return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); } Error NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) { return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size); } diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index d5a61722da87..892ce4e24afc 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -1,1441 +1,1462 @@ //===-- NativeRegisterContextLinux_mips64.cpp ---------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined (__mips__) #include "NativeRegisterContextLinux_mips64.h" // C Includes // C++ Includes // Other libraries and framework includes #include "lldb/Core/Error.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Log.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Host.h" #include "lldb/Core/EmulateInstruction.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-private-enumerations.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" #include "Plugins/Process/Utility/RegisterContextLinux_mips.h" #define NT_MIPS_MSA 0x600 #define CONFIG5_FRE (1 << 8) #define SR_FR (1 << 26) #define NUM_REGISTERS 32 #include #include #ifndef PTRACE_GET_WATCH_REGS enum pt_watch_style { pt_watch_style_mips32, pt_watch_style_mips64 }; struct mips32_watch_regs { uint32_t watchlo[8]; uint16_t watchhi[8]; uint16_t watch_masks[8]; uint32_t num_valid; } __attribute__((aligned(8))); struct mips64_watch_regs { uint64_t watchlo[8]; uint16_t watchhi[8]; uint16_t watch_masks[8]; uint32_t num_valid; } __attribute__((aligned(8))); struct pt_watch_regs { enum pt_watch_style style; union { struct mips32_watch_regs mips32; struct mips64_watch_regs mips64; }; }; #define PTRACE_GET_WATCH_REGS 0xd0 #define PTRACE_SET_WATCH_REGS 0xd1 #endif #define W (1 << 0) #define R (1 << 1) #define I (1 << 2) #define IRW (I | R | W) struct pt_watch_regs default_watch_regs; using namespace lldb_private; using namespace lldb_private::process_linux; // ---------------------------------------------------------------------------- // Private namespace. // ---------------------------------------------------------------------------- namespace { // mips general purpose registers. const uint32_t g_gp_regnums_mips[] = { gpr_zero_mips, gpr_r1_mips, gpr_r2_mips, gpr_r3_mips, gpr_r4_mips, gpr_r5_mips, gpr_r6_mips, gpr_r7_mips, gpr_r8_mips, gpr_r9_mips, gpr_r10_mips, gpr_r11_mips, gpr_r12_mips, gpr_r13_mips, gpr_r14_mips, gpr_r15_mips, gpr_r16_mips, gpr_r17_mips, gpr_r18_mips, gpr_r19_mips, gpr_r20_mips, gpr_r21_mips, gpr_r22_mips, gpr_r23_mips, gpr_r24_mips, gpr_r25_mips, gpr_r26_mips, gpr_r27_mips, gpr_gp_mips, gpr_sp_mips, gpr_r30_mips, gpr_ra_mips, gpr_sr_mips, gpr_mullo_mips, gpr_mulhi_mips, gpr_badvaddr_mips, gpr_cause_mips, gpr_pc_mips, gpr_config5_mips, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_gp_regnums_mips) / sizeof(g_gp_regnums_mips[0])) - 1 == k_num_gpr_registers_mips, "g_gp_regnums_mips has wrong number of register infos"); // mips floating point registers. const uint32_t g_fp_regnums_mips[] = { fpr_f0_mips, fpr_f1_mips, fpr_f2_mips, fpr_f3_mips, fpr_f4_mips, fpr_f5_mips, fpr_f6_mips, fpr_f7_mips, fpr_f8_mips, fpr_f9_mips, fpr_f10_mips, fpr_f11_mips, fpr_f12_mips, fpr_f13_mips, fpr_f14_mips, fpr_f15_mips, fpr_f16_mips, fpr_f17_mips, fpr_f18_mips, fpr_f19_mips, fpr_f20_mips, fpr_f21_mips, fpr_f22_mips, fpr_f23_mips, fpr_f24_mips, fpr_f25_mips, fpr_f26_mips, fpr_f27_mips, fpr_f28_mips, fpr_f29_mips, fpr_f30_mips, fpr_f31_mips, fpr_fcsr_mips, fpr_fir_mips, fpr_config5_mips, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_fp_regnums_mips) / sizeof(g_fp_regnums_mips[0])) - 1 == k_num_fpr_registers_mips, "g_fp_regnums_mips has wrong number of register infos"); // mips MSA registers. const uint32_t g_msa_regnums_mips[] = { msa_w0_mips, msa_w1_mips, msa_w2_mips, msa_w3_mips, msa_w4_mips, msa_w5_mips, msa_w6_mips, msa_w7_mips, msa_w8_mips, msa_w9_mips, msa_w10_mips, msa_w11_mips, msa_w12_mips, msa_w13_mips, msa_w14_mips, msa_w15_mips, msa_w16_mips, msa_w17_mips, msa_w18_mips, msa_w19_mips, msa_w20_mips, msa_w21_mips, msa_w22_mips, msa_w23_mips, msa_w24_mips, msa_w25_mips, msa_w26_mips, msa_w27_mips, msa_w28_mips, msa_w29_mips, msa_w30_mips, msa_w31_mips, msa_fcsr_mips, msa_fir_mips, msa_mcsr_mips, msa_mir_mips, msa_config5_mips, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_msa_regnums_mips) / sizeof(g_msa_regnums_mips[0])) - 1 == k_num_msa_registers_mips, "g_msa_regnums_mips has wrong number of register infos"); // mips64 general purpose registers. const uint32_t g_gp_regnums_mips64[] = { gpr_zero_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64, gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64, gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64, gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64, gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64, gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64, gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64, gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64, gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64, gpr_cause_mips64, gpr_pc_mips64, gpr_config5_mips64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) - 1 == k_num_gpr_registers_mips64, "g_gp_regnums_mips64 has wrong number of register infos"); // mips64 floating point registers. const uint32_t g_fp_regnums_mips64[] = { fpr_f0_mips64, fpr_f1_mips64, fpr_f2_mips64, fpr_f3_mips64, fpr_f4_mips64, fpr_f5_mips64, fpr_f6_mips64, fpr_f7_mips64, fpr_f8_mips64, fpr_f9_mips64, fpr_f10_mips64, fpr_f11_mips64, fpr_f12_mips64, fpr_f13_mips64, fpr_f14_mips64, fpr_f15_mips64, fpr_f16_mips64, fpr_f17_mips64, fpr_f18_mips64, fpr_f19_mips64, fpr_f20_mips64, fpr_f21_mips64, fpr_f22_mips64, fpr_f23_mips64, fpr_f24_mips64, fpr_f25_mips64, fpr_f26_mips64, fpr_f27_mips64, fpr_f28_mips64, fpr_f29_mips64, fpr_f30_mips64, fpr_f31_mips64, fpr_fcsr_mips64, fpr_fir_mips64, fpr_config5_mips64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_fp_regnums_mips64) / sizeof(g_fp_regnums_mips64[0])) - 1 == k_num_fpr_registers_mips64, "g_fp_regnums_mips64 has wrong number of register infos"); // mips64 MSA registers. const uint32_t g_msa_regnums_mips64[] = { msa_w0_mips64, msa_w1_mips64, msa_w2_mips64, msa_w3_mips64, msa_w4_mips64, msa_w5_mips64, msa_w6_mips64, msa_w7_mips64, msa_w8_mips64, msa_w9_mips64, msa_w10_mips64, msa_w11_mips64, msa_w12_mips64, msa_w13_mips64, msa_w14_mips64, msa_w15_mips64, msa_w16_mips64, msa_w17_mips64, msa_w18_mips64, msa_w19_mips64, msa_w20_mips64, msa_w21_mips64, msa_w22_mips64, msa_w23_mips64, msa_w24_mips64, msa_w25_mips64, msa_w26_mips64, msa_w27_mips64, msa_w28_mips64, msa_w29_mips64, msa_w30_mips64, msa_w31_mips64, msa_fcsr_mips64, msa_fir_mips64, msa_mcsr_mips64, msa_mir_mips64, msa_config5_mips64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_msa_regnums_mips64) / sizeof(g_msa_regnums_mips64[0])) - 1 == k_num_msa_registers_mips64, "g_msa_regnums_mips64 has wrong number of register infos"); // Number of register sets provided by this context. enum { k_num_register_sets = 3 }; // Register sets for mips. static const RegisterSet g_reg_sets_mips[k_num_register_sets] = { { "General Purpose Registers", "gpr", k_num_gpr_registers_mips, g_gp_regnums_mips }, { "Floating Point Registers", "fpu", k_num_fpr_registers_mips, g_fp_regnums_mips }, { "MSA Registers", "msa", k_num_msa_registers_mips, g_msa_regnums_mips } }; // Register sets for mips64. static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = { { "General Purpose Registers", "gpr", k_num_gpr_registers_mips64, g_gp_regnums_mips64 }, { "Floating Point Registers", "fpu", k_num_fpr_registers_mips64, g_fp_regnums_mips64 }, { "MSA Registers", "msa", k_num_msa_registers_mips64, g_msa_regnums_mips64 }, }; } // end of anonymous namespace NativeRegisterContextLinux* NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx) { return new NativeRegisterContextLinux_mips64(target_arch, native_thread, concrete_frame_idx); } #define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR_linux_mips) + sizeof(MSA_linux_mips)) // ---------------------------------------------------------------------------- // NativeRegisterContextLinux_mips64 members. // ---------------------------------------------------------------------------- static RegisterInfoInterface* CreateRegisterInfoInterface(const ArchSpec& target_arch) { if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { // 32-bit hosts run with a RegisterContextLinux_mips context. return new RegisterContextLinux_mips(target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); } else { assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); // mips64 hosts know how to work with 64-bit and 32-bit EXEs using the mips64 register context. return new RegisterContextLinux_mips64 (target_arch, NativeRegisterContextLinux_mips64::IsMSAAvailable()); } } NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch, NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx) : NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)) { switch (target_arch.GetMachine ()) { case llvm::Triple::mips: case llvm::Triple::mipsel: m_reg_info.num_registers = k_num_registers_mips; m_reg_info.num_gpr_registers = k_num_gpr_registers_mips; m_reg_info.num_fpr_registers = k_num_fpr_registers_mips; m_reg_info.last_gpr = k_last_gpr_mips; m_reg_info.first_fpr = k_first_fpr_mips; m_reg_info.last_fpr = k_last_fpr_mips; m_reg_info.first_msa = k_first_msa_mips; m_reg_info.last_msa = k_last_msa_mips; break; case llvm::Triple::mips64: case llvm::Triple::mips64el: m_reg_info.num_registers = k_num_registers_mips64; m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64; m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64; m_reg_info.last_gpr = k_last_gpr_mips64; m_reg_info.first_fpr = k_first_fpr_mips64; m_reg_info.last_fpr = k_last_fpr_mips64; m_reg_info.first_msa = k_first_msa_mips64; m_reg_info.last_msa = k_last_msa_mips64; break; default: assert(false && "Unhandled target architecture."); break; } // Initialize m_iovec to point to the buffer and buffer size // using the conventions of Berkeley style UIO structures, as required // by PTRACE extensions. m_iovec.iov_base = &m_msa; m_iovec.iov_len = sizeof(MSA_linux_mips); // init h/w watchpoint addr map for (int index = 0;index <= MAX_NUM_WP; index++) hw_addr_map[index] = LLDB_INVALID_ADDRESS; ::memset(&m_gpr, 0, sizeof(GPR_linux_mips)); ::memset(&m_fpr, 0, sizeof(FPR_linux_mips)); ::memset(&m_msa, 0, sizeof(MSA_linux_mips)); } uint32_t NativeRegisterContextLinux_mips64::GetRegisterSetCount () const { return k_num_register_sets; } lldb::addr_t NativeRegisterContextLinux_mips64::GetPCfromBreakpointLocation (lldb::addr_t fail_value) { Error error; RegisterValue pc_value; lldb::addr_t pc = fail_value; Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("NativeRegisterContextLinux_mips64::%s Reading PC from breakpoint location", __FUNCTION__); // PC register is at index 34 of the register array const RegisterInfo *const pc_info_p = GetRegisterInfoAtIndex (gpr_pc_mips64); error = ReadRegister (pc_info_p, pc_value); if (error.Success ()) { pc = pc_value.GetAsUInt64 (); // CAUSE register is at index 37 of the register array const RegisterInfo *const cause_info_p = GetRegisterInfoAtIndex (gpr_cause_mips64); RegisterValue cause_value; ReadRegister (cause_info_p, cause_value); uint64_t cause = cause_value.GetAsUInt64 (); if (log) log->Printf ("NativeRegisterContextLinux_mips64::%s PC 0x%" PRIx64 " Cause 0x%" PRIx64, __FUNCTION__, pc, cause); /* * The breakpoint might be in a delay slot. In this case PC points * to the delayed branch instruction rather then the instruction * in the delay slot. If the CAUSE.BD flag is set then adjust the * PC based on the size of the branch instruction. */ if ((cause & (1 << 31)) != 0) { lldb::addr_t branch_delay = 0; branch_delay = 4; // FIXME - Adjust according to size of branch instruction at PC pc = pc + branch_delay; pc_value.SetUInt64 (pc); WriteRegister (pc_info_p, pc_value); if (log) log->Printf ("NativeRegisterContextLinux_mips64::%s New PC 0x%" PRIx64, __FUNCTION__, pc); } } return pc; } const RegisterSet * NativeRegisterContextLinux_mips64::GetRegisterSet (uint32_t set_index) const { if (set_index >= k_num_register_sets) return nullptr; switch (GetRegisterInfoInterface ().GetTargetArchitecture ().GetMachine ()) { case llvm::Triple::mips64: case llvm::Triple::mips64el: return &g_reg_sets_mips64[set_index]; case llvm::Triple::mips: case llvm::Triple::mipsel: return &g_reg_sets_mips[set_index]; default: assert (false && "Unhandled target architecture."); return nullptr; } return nullptr; } lldb_private::Error NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) { Error error; if (!reg_info) { error.SetErrorString ("reg_info NULL"); return error; } const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + uint8_t byte_size = reg_info->byte_size; if (reg == LLDB_INVALID_REGNUM) { - // This is likely an internal register for lldb use only and should not be directly queried. - error.SetErrorStringWithFormat ("register \"%s\" is an internal-only lldb register, cannot read directly", reg_info->name); + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); return error; } if (IsMSA(reg) && !IsMSAAvailable()) { error.SetErrorString ("MSA not available on this processor"); return error; } if (IsMSA(reg) || IsFPR(reg)) { - uint8_t *src; + uint8_t *src = nullptr; + lldbassert(reg_info->byte_offset < sizeof(UserArea)); error = ReadCP1(); if (!error.Success()) { error.SetErrorString ("failed to read co-processor 1 register"); return error; } if (IsFPR(reg)) { - assert (reg_info->byte_offset < sizeof(UserArea)); - src = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr)); + if (IsFR0() && (byte_size != 4)) + { + byte_size = 4; + uint8_t ptrace_index; + ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + src = ReturnFPOffset(ptrace_index, reg_info->byte_offset); + } + else + src = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); } else - { - assert (reg_info->byte_offset < sizeof(UserArea)); - src = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr)); - } - switch (reg_info->byte_size) + src = (uint8_t *)&m_msa + reg_info->byte_offset - + (sizeof(m_gpr) + sizeof(m_fpr)); + switch (byte_size) { case 4: - reg_value.SetUInt32(*(uint32_t *)src); - break; + reg_value.SetUInt32(*(uint32_t *)src); + break; case 8: - reg_value.SetUInt64(*(uint64_t *)src); - break; + reg_value.SetUInt64(*(uint64_t *)src); + break; case 16: - reg_value.SetBytes((const void *)src, 16, GetByteOrder()); - break; + reg_value.SetBytes((const void *)src, 16, GetByteOrder()); + break; default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); - break; + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, + reg_info->byte_size); + break; } } else { error = ReadRegisterRaw(reg, reg_value); } return error; } lldb_private::Error NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) { Error error; assert (reg_info && "reg_info is null"); const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; if (reg_index == LLDB_INVALID_REGNUM) return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); if (IsMSA(reg_index) && !IsMSAAvailable()) { error.SetErrorString ("MSA not available on this processor"); return error; } if (IsFPR(reg_index) || IsMSA(reg_index)) { - uint8_t *dst; - uint64_t *src; + uint8_t *dst = nullptr; + uint64_t *src = nullptr; + uint8_t byte_size = reg_info->byte_size; + lldbassert(reg_info->byte_offset < sizeof(UserArea)); // Initialise the FP and MSA buffers by reading all co-processor 1 registers ReadCP1(); if (IsFPR(reg_index)) { - assert (reg_info->byte_offset < sizeof(UserArea)); - dst = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr)); + if (IsFR0() && (byte_size != 4)) + { + byte_size = 4; + uint8_t ptrace_index; + ptrace_index = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + dst = ReturnFPOffset(ptrace_index, reg_info->byte_offset); + } + else + dst = (uint8_t *)&m_fpr + reg_info->byte_offset - sizeof(m_gpr); } else - { - assert (reg_info->byte_offset < sizeof(UserArea)); - dst = (uint8_t *)&m_msa + reg_info->byte_offset - (sizeof(m_gpr) + sizeof(m_fpr)); - } - switch (reg_info->byte_size) + dst = (uint8_t *)&m_msa + reg_info->byte_offset - + (sizeof(m_gpr) + sizeof(m_fpr)); + switch (byte_size) { case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; case 16: - src = (uint64_t *)reg_value.GetBytes(); - *(uint64_t *)dst = *src; - *(uint64_t *)(dst + 8) = *(src + 1); - break; + src = (uint64_t *)reg_value.GetBytes(); + *(uint64_t *)dst = *src; + *(uint64_t *)(dst + 8) = *(src + 1); + break; default: - assert(false && "Unhandled data size."); - error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); - break; + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat("unhandled byte size: %" PRIu32, + reg_info->byte_size); + break; } error = WriteCP1(); if (!error.Success()) { - error.SetErrorString ("failed to write co-processor 1 register"); + error.SetErrorString("failed to write co-processor 1 register"); return error; } } else { error = WriteRegisterRaw(reg_index, reg_value); } return error; } Error NativeRegisterContextLinux_mips64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { Error error; data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); if (!data_sp) { error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); return error; } error = ReadGPR(); if (!error.Success()) { error.SetErrorString ("ReadGPR() failed"); return error; } error = ReadCP1(); if (!error.Success()) { error.SetErrorString ("ReadCP1() failed"); return error; } uint8_t *dst = data_sp->GetBytes (); if (dst == nullptr) { error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); return error; } ::memcpy (dst, &m_gpr, GetRegisterInfoInterface ().GetGPRSize ()); dst += GetRegisterInfoInterface ().GetGPRSize (); ::memcpy (dst, &m_fpr, GetFPRSize ()); dst += GetFPRSize (); ::memcpy (dst, &m_msa, sizeof(MSA_linux_mips)); return error; } Error NativeRegisterContextLinux_mips64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { Error error; if (!data_sp) { error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s invalid data_sp provided", __FUNCTION__); return error; } if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) { error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); return error; } uint8_t *src = data_sp->GetBytes (); if (src == nullptr) { error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); return error; } ::memcpy (&m_gpr, src, GetRegisterInfoInterface ().GetGPRSize ()); src += GetRegisterInfoInterface ().GetGPRSize (); ::memcpy (&m_fpr, src, GetFPRSize ()); src += GetFPRSize (); ::memcpy (&m_msa, src, sizeof(MSA_linux_mips)); error = WriteGPR(); if (!error.Success()) { error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteGPR() failed", __FUNCTION__); return error; } error = WriteCP1(); if (!error.Success()) { error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteCP1() failed", __FUNCTION__); return error; } return error; } Error NativeRegisterContextLinux_mips64::ReadCP1() { Error error; - uint8_t *src, *dst; + uint8_t *src = nullptr; + uint8_t *dst = nullptr; lldb::ByteOrder byte_order = GetByteOrder(); - uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig); + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); if (IsMSAAvailable()) { error = NativeRegisterContextLinux::ReadRegisterSet(&m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); src = (uint8_t *)&m_msa + (IsBigEndian * 8); dst = (uint8_t *)&m_fpr; for ( int i = 0; i < NUM_REGISTERS; i++) { // Copy fp values from msa buffer fetched via ptrace *(uint64_t *) dst = *(uint64_t *) src; src = src + 16; dst = dst + 8; } m_fpr.fir = m_msa.fir; m_fpr.fcsr = m_msa.fcsr; m_fpr.config5 = m_msa.config5; } else { error = NativeRegisterContextLinux::ReadFPR(); } + return error; +} - // TODO: Add support for FRE - if (IsFR0()) +uint8_t * +NativeRegisterContextLinux_mips64::ReturnFPOffset(uint8_t reg_index, + uint32_t byte_offset) +{ + uint8_t *fp_buffer_ptr = nullptr; + lldb::ByteOrder byte_order = GetByteOrder(); + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); + if (reg_index % 2) { - src = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4); - dst = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4); - for (int i = 0; i < (NUM_REGISTERS / 2); i++) - { - // copy odd single from top of neighbouring even double - *(uint32_t *) dst = *(uint32_t *) src; - src = src + 16; - dst = dst + 16; - } + uint8_t offset_diff = (IsBigEndian) ? 8 : 4; + fp_buffer_ptr = (uint8_t *)&m_fpr + byte_offset + - offset_diff - sizeof(m_gpr); } - - return error; + else + { + fp_buffer_ptr = (uint8_t *)&m_fpr + byte_offset + + 4 * (IsBigEndian) - sizeof(m_gpr); + } + return fp_buffer_ptr; } Error NativeRegisterContextLinux_mips64::WriteCP1() { Error error; - uint8_t *src, *dst; + uint8_t *src = nullptr; + uint8_t *dst = nullptr; lldb::ByteOrder byte_order = GetByteOrder(); - uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig); - - // TODO: Add support for FRE - if (IsFR0()) - { - src = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4); - dst = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4); - for (int i = 0; i < (NUM_REGISTERS / 2); i++) - { - // copy odd single to top of neighbouring even double - *(uint32_t *) dst = *(uint32_t *) src; - src = src + 16; - dst = dst + 16; - } - } + bool IsBigEndian = (byte_order == lldb::eByteOrderBig); if (IsMSAAvailable()) { dst = (uint8_t *)&m_msa + (IsBigEndian * 8); src = (uint8_t *)&m_fpr; for (int i = 0; i < NUM_REGISTERS; i++) { // Copy fp values to msa buffer for ptrace *(uint64_t *) dst = *(uint64_t *) src; dst = dst + 16; src = src + 8; } m_msa.fir = m_fpr.fir; m_msa.fcsr = m_fpr.fcsr; m_msa.config5 = m_fpr.config5; error = NativeRegisterContextLinux::WriteRegisterSet(&m_iovec, sizeof(MSA_linux_mips), NT_MIPS_MSA); } else { error = NativeRegisterContextLinux::WriteFPR(); } return error; } bool NativeRegisterContextLinux_mips64::IsFR0() { const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex (gpr_sr_mips64); RegisterValue reg_value; ReadRegister (reg_info_p, reg_value); uint64_t value = reg_value.GetAsUInt64(); return (!(value & SR_FR)); } bool NativeRegisterContextLinux_mips64::IsFRE() { const RegisterInfo *const reg_info_p = GetRegisterInfoAtIndex (gpr_config5_mips64); RegisterValue reg_value; ReadRegister (reg_info_p, reg_value); uint64_t config5 = reg_value.GetAsUInt64(); return (config5 & CONFIG5_FRE); } bool NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const { return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr); } static uint32_t GetWatchHi (struct pt_watch_regs *regs, uint32_t index) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) return regs->mips32.watchhi[index]; else if (regs->style == pt_watch_style_mips64) return regs->mips64.watchhi[index]; if(log) log->Printf("Invalid watch register style"); return 0; } static void SetWatchHi (struct pt_watch_regs *regs, uint32_t index, uint16_t value) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) regs->mips32.watchhi[index] = value; else if (regs->style == pt_watch_style_mips64) regs->mips64.watchhi[index] = value; if(log) log->Printf("Invalid watch register style"); return; } static lldb::addr_t GetWatchLo (struct pt_watch_regs *regs, uint32_t index) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) return regs->mips32.watchlo[index]; else if (regs->style == pt_watch_style_mips64) return regs->mips64.watchlo[index]; if(log) log->Printf("Invalid watch register style"); return LLDB_INVALID_ADDRESS; } static void SetWatchLo (struct pt_watch_regs *regs, uint32_t index, uint64_t value) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) regs->mips32.watchlo[index] = (uint32_t) value; else if (regs->style == pt_watch_style_mips64) regs->mips64.watchlo[index] = value; if(log) log->Printf("Invalid watch register style"); return; } static uint32_t GetIRWMask (struct pt_watch_regs *regs, uint32_t index) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) return regs->mips32.watch_masks[index] & IRW; else if (regs->style == pt_watch_style_mips64) return regs->mips64.watch_masks[index] & IRW; if(log) log->Printf("Invalid watch register style"); return 0; } static uint32_t GetRegMask (struct pt_watch_regs *regs, uint32_t index) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (regs->style == pt_watch_style_mips32) return regs->mips32.watch_masks[index] & ~IRW; else if (regs->style == pt_watch_style_mips64) return regs->mips64.watch_masks[index] & ~IRW; if(log) log->Printf("Invalid watch register style"); return 0; } static lldb::addr_t GetRangeMask (lldb::addr_t mask) { lldb::addr_t mask_bit = 1; while (mask_bit < mask) { mask = mask | mask_bit; mask_bit <<= 1; } return mask; } static int GetVacantWatchIndex (struct pt_watch_regs *regs, lldb::addr_t addr, uint32_t size, uint32_t irw, uint32_t num_valid) { lldb::addr_t last_byte = addr + size - 1; lldb::addr_t mask = GetRangeMask (addr ^ last_byte) | IRW; lldb::addr_t base_addr = addr & ~mask; // Check if this address is already watched by previous watch points. lldb::addr_t lo; uint16_t hi; uint32_t vacant_watches = 0; for (uint32_t index = 0; index < num_valid; index++) { lo = GetWatchLo (regs, index); if (lo != 0 && irw == ((uint32_t) lo & irw)) { hi = GetWatchHi (regs, index) | IRW; lo &= ~(lldb::addr_t) hi; if (addr >= lo && last_byte <= (lo + hi)) return index; } else vacant_watches++; } // Now try to find a vacant index if(vacant_watches > 0) { vacant_watches = 0; for (uint32_t index = 0; index < num_valid; index++) { lo = GetWatchLo (regs, index); if (lo == 0 && irw == (GetIRWMask (regs, index) & irw)) { if (mask <= (GetRegMask (regs, index) | IRW)) { // It fits, we can use it. SetWatchLo (regs, index, base_addr | irw); SetWatchHi (regs, index, mask & ~IRW); return index; } else { // It doesn't fit, but has the proper IRW capabilities vacant_watches++; } } } if (vacant_watches > 1) { // Split this watchpoint accross several registers struct pt_watch_regs regs_copy; regs_copy = *regs; lldb::addr_t break_addr; uint32_t segment_size; for (uint32_t index = 0; index < num_valid; index++) { lo = GetWatchLo (®s_copy, index); hi = GetRegMask (®s_copy, index) | IRW; if (lo == 0 && irw == (hi & irw)) { lo = addr & ~(lldb::addr_t) hi; break_addr = lo + hi + 1; if (break_addr >= addr + size) segment_size = size; else segment_size = break_addr - addr; mask = GetRangeMask (addr ^ (addr + segment_size - 1)); SetWatchLo (®s_copy, index, (addr & ~mask) | irw); SetWatchHi (®s_copy, index, mask & ~IRW); if (break_addr >= addr + size) { *regs = regs_copy; return index; } size = addr + size - break_addr; addr = break_addr; } } } } return LLDB_INVALID_INDEX32; } bool NativeRegisterContextLinux_mips64::IsMSA(uint32_t reg_index) const { return (m_reg_info.first_msa <= reg_index && reg_index <= m_reg_info.last_msa); } bool NativeRegisterContextLinux_mips64::IsMSAAvailable() { MSA_linux_mips msa_buf; unsigned int regset = NT_MIPS_MSA; Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, Host::GetCurrentProcessID(), static_cast(®set), &msa_buf, sizeof(MSA_linux_mips)); if (error.Success() && msa_buf.mir) { return true; } return false; } Error NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_hit) { if (wp_index >= NumSupportedHardwareWatchpoints()) return Error("Watchpoint index out of range"); // reading the current state of watch regs struct pt_watch_regs watch_readback; Error error = DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); if (GetWatchHi (&watch_readback, wp_index) & (IRW)) { // clear hit flag in watchhi SetWatchHi (&watch_readback, wp_index, (GetWatchHi (&watch_readback, wp_index) & ~(IRW))); DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&watch_readback)); is_hit = true; return error; } is_hit = false; return error; } Error NativeRegisterContextLinux_mips64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) { uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { bool is_hit; Error error = IsWatchpointHit(wp_index, is_hit); if (error.Fail()) { wp_index = LLDB_INVALID_INDEX32; } else if (is_hit) { return error; } } wp_index = LLDB_INVALID_INDEX32; return Error(); } Error NativeRegisterContextLinux_mips64::IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) { is_vacant = false; return Error("MIPS TODO: NativeRegisterContextLinux_mips64::IsWatchpointVacant not implemented"); } bool NativeRegisterContextLinux_mips64::ClearHardwareWatchpoint(uint32_t wp_index) { if (wp_index >= NumSupportedHardwareWatchpoints()) return false; struct pt_watch_regs regs; // First reading the current state of watch regs DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); if (regs.style == pt_watch_style_mips32) { regs.mips32.watchlo[wp_index] = default_watch_regs.mips32.watchlo[wp_index]; regs.mips32.watchhi[wp_index] = default_watch_regs.mips32.watchhi[wp_index]; regs.mips32.watch_masks[wp_index] = default_watch_regs.mips32.watch_masks[wp_index]; } else // pt_watch_style_mips64 { regs.mips64.watchlo[wp_index] = default_watch_regs.mips64.watchlo[wp_index]; regs.mips64.watchhi[wp_index] = default_watch_regs.mips64.watchhi[wp_index]; regs.mips64.watch_masks[wp_index] = default_watch_regs.mips64.watch_masks[wp_index]; } Error error = DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); if(!error.Fail()) { hw_addr_map[wp_index] = LLDB_INVALID_ADDRESS; return true; } return false; } Error NativeRegisterContextLinux_mips64::ClearAllHardwareWatchpoints() { return DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(&default_watch_regs)); } Error NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex ( lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { Error error; error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::SetHardwareWatchpointWithIndex not implemented"); return error; } uint32_t NativeRegisterContextLinux_mips64::SetHardwareWatchpoint ( lldb::addr_t addr, size_t size, uint32_t watch_flags) { struct pt_watch_regs regs; // First reading the current state of watch regs DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); // Try if a new watch point fits in this state int index = GetVacantWatchIndex (®s, addr, size, watch_flags, NumSupportedHardwareWatchpoints()); // New watchpoint doesn't fit if (index == LLDB_INVALID_INDEX32) return LLDB_INVALID_INDEX32; // It fits, so we go ahead with updating the state of watch regs DoWriteWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); // Storing exact address hw_addr_map[index] = addr; return index; } lldb::addr_t NativeRegisterContextLinux_mips64::GetWatchpointAddress (uint32_t wp_index) { if (wp_index >= NumSupportedHardwareWatchpoints()) return LLDB_INVALID_ADDRESS; return hw_addr_map[wp_index]; } struct EmulatorBaton { lldb::addr_t m_watch_hit_addr; NativeProcessLinux* m_process; NativeRegisterContext* m_reg_context; EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) : m_watch_hit_addr(LLDB_INVALID_ADDRESS), m_process(process), m_reg_context(reg_context) {} }; static size_t ReadMemoryCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t length) { size_t bytes_read; EmulatorBaton* emulator_baton = static_cast(baton); emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); return bytes_read; } static size_t WriteMemoryCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t length) { return length; } static bool ReadRegisterCallback (EmulateInstruction *instruction, void *baton, const RegisterInfo *reg_info, RegisterValue ®_value) { EmulatorBaton* emulator_baton = static_cast(baton); const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo( lldb::eRegisterKindDWARF, reg_info->kinds[lldb::eRegisterKindDWARF]); Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); if (error.Success()) return true; return false; } static bool WriteRegisterCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { if (reg_info->kinds[lldb::eRegisterKindDWARF] == dwarf_bad_mips64) { EmulatorBaton* emulator_baton = static_cast(baton); emulator_baton->m_watch_hit_addr = reg_value.GetAsUInt64 (); } return true; } /* * MIPS Linux kernel returns a masked address (last 3bits are masked) * when a HW watchpoint is hit. However user may not have set a watchpoint * on this address. Emulate instruction at PC and find the base address of * the load/store instruction. This will give the exact address used to * read/write the variable. Send this exact address to client so that * it can decide to stop or continue the thread. */ lldb::addr_t NativeRegisterContextLinux_mips64::GetWatchpointHitAddress (uint32_t wp_index) { if (wp_index >= NumSupportedHardwareWatchpoints()) return LLDB_INVALID_ADDRESS; lldb_private::ArchSpec arch; arch = GetRegisterInfoInterface().GetTargetArchitecture(); std::unique_ptr emulator_ap( EmulateInstruction::FindPlugin(arch, lldb_private::eInstructionTypeAny, nullptr)); if (emulator_ap == nullptr) return LLDB_INVALID_ADDRESS; EmulatorBaton baton(static_cast(m_thread.GetProcess().get()), this); emulator_ap->SetBaton (&baton); emulator_ap->SetReadMemCallback (&ReadMemoryCallback); emulator_ap->SetReadRegCallback (&ReadRegisterCallback); emulator_ap->SetWriteMemCallback (&WriteMemoryCallback); emulator_ap->SetWriteRegCallback (&WriteRegisterCallback); if (!emulator_ap->ReadInstruction()) return LLDB_INVALID_ADDRESS; if (emulator_ap->EvaluateInstruction(lldb::eEmulateInstructionOptionNone)) return baton.m_watch_hit_addr; return LLDB_INVALID_ADDRESS; } uint32_t NativeRegisterContextLinux_mips64::NumSupportedHardwareWatchpoints () { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); struct pt_watch_regs regs; static int num_valid = 0; if (!num_valid) { DoReadWatchPointRegisterValue(m_thread.GetID(), static_cast(®s)); default_watch_regs = regs; // Keeping default watch regs values for future use switch (regs.style) { case pt_watch_style_mips32: num_valid = regs.mips32.num_valid; // Using num_valid as cache return num_valid; case pt_watch_style_mips64: num_valid = regs.mips64.num_valid; return num_valid; default: if(log) log->Printf("NativeRegisterContextLinux_mips64::%s Error: Unrecognized watch register style", __FUNCTION__); } return 0; } return num_valid; } -Error -NativeRegisterContextLinux_mips64::DoReadRegisterValue(uint32_t offset, - const char* reg_name, - uint32_t size, - RegisterValue &value) + +Error NativeRegisterContextLinux_mips64::ReadRegisterRaw(uint32_t reg_index, + RegisterValue &value) { - GPR_linux_mips regs; - ::memset(®s, 0, sizeof(GPR_linux_mips)); + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); - // Clear all bits in RegisterValue before writing actual value read from ptrace to avoid garbage value in 32-bit MSB - value.SetBytes((void *)(((unsigned char *)®s) + offset), 8, GetByteOrder()); - Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); - if (error.Success()) - { - lldb_private::ArchSpec arch; - if (m_thread.GetProcess()->GetArchitecture(arch)) - { - void* target_address = ((uint8_t*)®s) + offset + 4 * (arch.GetMachine() == llvm::Triple::mips); - uint32_t target_size; - if ((::strcmp(reg_name, "sr") == 0) || (::strcmp(reg_name, "cause") == 0) || (::strcmp(reg_name, "config5") == 0)) - target_size = 4; - else - target_size = arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8; - value.SetBytes(target_address, target_size, arch.GetByteOrder()); - } - else - error.SetErrorString("failed to get architecture"); - } - return error; + if (!reg_info) + return Error("register %" PRIu32 " not found", reg_index); + + uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + + if ((offset == ptrace_sr_mips) || (offset == ptrace_config5_mips)) + return Read_SR_Config(reg_info->byte_offset, reg_info->name, + reg_info->byte_size, value); + + return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size, + value); } -Error -NativeRegisterContextLinux_mips64::DoWriteRegisterValue(uint32_t offset, - const char* reg_name, - const RegisterValue &value) +Error NativeRegisterContextLinux_mips64::WriteRegisterRaw( + uint32_t reg_index, const RegisterValue &value) +{ + const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); + + if (!reg_info) + return Error("register %" PRIu32 " not found", reg_index); + + if (reg_info->invalidate_regs) + lldbassert(false && "reg_info->invalidate_regs is unhandled"); + + uint32_t offset = reg_info->kinds[lldb::eRegisterKindProcessPlugin]; + return DoWriteRegisterValue(offset, reg_info->name, value); +} + +Error NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset, + const char *reg_name, + uint32_t size, + RegisterValue &value) { GPR_linux_mips regs; - Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); + ::memset(®s, 0, sizeof(GPR_linux_mips)); + + Error error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), + NULL, ®s, sizeof regs); if (error.Success()) { lldb_private::ArchSpec arch; if (m_thread.GetProcess()->GetArchitecture(arch)) { - ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8); - error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), NULL, ®s, sizeof regs); + void *target_address = ((uint8_t *)®s) + offset + + 4 * (arch.GetMachine() == llvm::Triple::mips); + value.SetUInt(*(uint32_t *)target_address, size); } else error.SetErrorString("failed to get architecture"); } return error; } Error NativeRegisterContextLinux_mips64::DoReadWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback) { return NativeProcessLinux::PtraceWrapper( PTRACE_GET_WATCH_REGS, m_thread.GetID(), watch_readback); } Error NativeRegisterContextLinux_mips64::DoWriteWatchPointRegisterValue(lldb::tid_t tid, void* watch_reg_value) { return NativeProcessLinux::PtraceWrapper(PTRACE_SET_WATCH_REGS, m_thread.GetID(), watch_reg_value); } #endif // defined (__mips__) diff --git a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h index 9368645116e9..20c32075379c 100644 --- a/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h +++ b/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h @@ -1,167 +1,171 @@ //===-- NativeRegisterContextLinux_mips64.h ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined (__mips__) #ifndef lldb_NativeRegisterContextLinux_mips64_h #define lldb_NativeRegisterContextLinux_mips64_h #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" #include "Plugins/Process/Utility/RegisterContext_mips.h" #include "Plugins/Process/Utility/lldb-mips-linux-register-enums.h" #define MAX_NUM_WP 8 namespace lldb_private { namespace process_linux { class NativeProcessLinux; class NativeRegisterContextLinux_mips64 : public NativeRegisterContextLinux { public: NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch, NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx); uint32_t GetRegisterSetCount () const override; lldb::addr_t GetPCfromBreakpointLocation (lldb::addr_t fail_value = LLDB_INVALID_ADDRESS) override; lldb::addr_t GetWatchpointHitAddress (uint32_t wp_index) override; const RegisterSet * GetRegisterSet (uint32_t set_index) const override; Error ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) override; Error WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) override; Error ReadAllRegisterValues (lldb::DataBufferSP &data_sp) override; Error WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) override; Error ReadCP1(); Error WriteCP1(); Error IsWatchpointHit (uint32_t wp_index, bool &is_hit) override; + uint8_t *ReturnFPOffset(uint8_t reg_index, uint32_t byte_offset); + + Error GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) override; Error IsWatchpointVacant (uint32_t wp_index, bool &is_vacant) override; bool ClearHardwareWatchpoint (uint32_t wp_index) override; Error ClearAllHardwareWatchpoints () override; Error SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index); uint32_t SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) override; lldb::addr_t GetWatchpointAddress (uint32_t wp_index) override; uint32_t NumSupportedHardwareWatchpoints () override; static bool IsMSAAvailable(); protected: + Error - DoReadRegisterValue(uint32_t offset, - const char* reg_name, - uint32_t size, - RegisterValue &value) override; + Read_SR_Config(uint32_t offset, const char *reg_name, uint32_t size, + RegisterValue &value); Error - DoWriteRegisterValue(uint32_t offset, - const char* reg_name, - const RegisterValue &value) override; + ReadRegisterRaw(uint32_t reg_index, RegisterValue &value) override; Error DoReadWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback); + Error + WriteRegisterRaw(uint32_t reg_index, + const RegisterValue &value) override; + Error DoWriteWatchPointRegisterValue(lldb::tid_t tid, void* watch_readback); bool IsFR0(); bool IsFRE(); bool IsFPR(uint32_t reg_index) const; bool IsMSA(uint32_t reg_index) const; void* GetGPRBuffer() override { return &m_gpr; } void* GetFPRBuffer() override { return &m_fpr; } size_t GetFPRSize() override { return sizeof(FPR_linux_mips); } private: // Info about register ranges. struct RegInfo { uint32_t num_registers; uint32_t num_gpr_registers; uint32_t num_fpr_registers; uint32_t last_gpr; uint32_t first_fpr; uint32_t last_fpr; uint32_t first_msa; uint32_t last_msa; }; RegInfo m_reg_info; GPR_linux_mips m_gpr; FPR_linux_mips m_fpr; MSA_linux_mips m_msa; lldb::addr_t hw_addr_map[MAX_NUM_WP]; IOVEC_mips m_iovec; }; } // namespace process_linux } // namespace lldb_private #endif // #ifndef lldb_NativeRegisterContextLinux_mips64_h #endif // defined (__mips__) diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips.h b/source/Plugins/Process/Utility/RegisterInfos_mips.h index 5852d799aa9b..81294e7b0d97 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_mips.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips.h @@ -1,194 +1,301 @@ //===-- RegisterInfos_mips.h -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// // C Includes #include // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" #include "lldb/Core/dwarf.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, gpr) + \ LLVM_EXTENSION offsetof(GPR_linux_mips, regname)) // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR_linux_mips, regname)) // Computes the offset of the given MSA in the extended data area. #define MSA_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, msa) + \ LLVM_EXTENSION offsetof(MSA_linux_mips, regname)) // Note that the size and offset will be updated by platform-specific classes. -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((GPR_linux_mips*)NULL)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL, NULL, 0} +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((GPR_linux_mips *) NULL)->reg) / 2, \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + gpr_##reg##_mips }, \ + NULL, NULL, NULL, 0 \ + } const uint8_t dwarf_opcode_mips [] = { llvm::dwarf::DW_OP_regx, dwarf_sr_mips, llvm::dwarf::DW_OP_lit1, llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr }; -#define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL, dwarf_opcode_mips, sizeof(dwarf_opcode_mips)} +#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_mips *) NULL)->reg), \ + FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + fpr_##reg##_mips }, \ + NULL, NULL, dwarf_opcode_mips, \ + sizeof(dwarf_opcode_mips) \ + } -#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL, NULL, 0} +#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_mips *) NULL)->reg), \ + FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + fpr_##reg##_mips }, \ + NULL, NULL, NULL, 0 \ + } #define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \ eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL, NULL, 0} #define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL, NULL, 0} // RegisterKind: EH_Frame, DWARF, Generic, Procss Plugin, LLDB -static RegisterInfo -g_register_infos_mips[] = -{ - DEFINE_GPR (zero, "zero", dwarf_zero_mips, dwarf_zero_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r1, "at", dwarf_r1_mips, dwarf_r1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r2, nullptr, dwarf_r2_mips, dwarf_r2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r3, nullptr, dwarf_r3_mips, dwarf_r3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r4, nullptr, dwarf_r4_mips, dwarf_r4_mips, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), - DEFINE_GPR (r5, nullptr, dwarf_r5_mips, dwarf_r5_mips, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), - DEFINE_GPR (r6, nullptr, dwarf_r6_mips, dwarf_r6_mips, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), - DEFINE_GPR (r7, nullptr, dwarf_r7_mips, dwarf_r7_mips, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), - DEFINE_GPR (r8, nullptr, dwarf_r8_mips, dwarf_r8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r9, nullptr, dwarf_r9_mips, dwarf_r9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r10, nullptr, dwarf_r10_mips, dwarf_r10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r11, nullptr, dwarf_r11_mips, dwarf_r11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r12, nullptr, dwarf_r12_mips, dwarf_r12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r13, nullptr, dwarf_r13_mips, dwarf_r13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r14, nullptr, dwarf_r14_mips, dwarf_r14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r15, nullptr, dwarf_r15_mips, dwarf_r15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r16, nullptr, dwarf_r16_mips, dwarf_r16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r17, nullptr, dwarf_r17_mips, dwarf_r17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r18, nullptr, dwarf_r18_mips, dwarf_r18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r19, nullptr, dwarf_r19_mips, dwarf_r19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r20, nullptr, dwarf_r20_mips, dwarf_r20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r21, nullptr, dwarf_r21_mips, dwarf_r21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r22, nullptr, dwarf_r22_mips, dwarf_r22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r23, nullptr, dwarf_r23_mips, dwarf_r23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r24, nullptr, dwarf_r24_mips, dwarf_r24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r25, nullptr, dwarf_r25_mips, dwarf_r25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r26, nullptr, dwarf_r26_mips, dwarf_r26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (r27, nullptr, dwarf_r27_mips, dwarf_r27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (gp, "gp", dwarf_gp_mips, dwarf_gp_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (sp, "sp", dwarf_sp_mips, dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), - DEFINE_GPR (r30, "fp", dwarf_r30_mips, dwarf_r30_mips, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), - DEFINE_GPR (ra, "ra", dwarf_ra_mips, dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), - DEFINE_GPR (sr, "status", dwarf_sr_mips, dwarf_sr_mips, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), - DEFINE_GPR (mullo, nullptr, dwarf_lo_mips, dwarf_lo_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (mulhi, nullptr, dwarf_hi_mips, dwarf_hi_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (badvaddr, nullptr, dwarf_bad_mips, dwarf_bad_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (cause, nullptr, dwarf_cause_mips, dwarf_cause_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR (pc, nullptr, dwarf_pc_mips, dwarf_pc_mips, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), - DEFINE_GPR (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f0, nullptr, dwarf_f0_mips, dwarf_f0_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f1, nullptr, dwarf_f1_mips, dwarf_f1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f2, nullptr, dwarf_f2_mips, dwarf_f2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f3, nullptr, dwarf_f3_mips, dwarf_f3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f4, nullptr, dwarf_f4_mips, dwarf_f4_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f5, nullptr, dwarf_f5_mips, dwarf_f5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f6, nullptr, dwarf_f6_mips, dwarf_f6_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f7, nullptr, dwarf_f7_mips, dwarf_f7_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f8, nullptr, dwarf_f8_mips, dwarf_f8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f9, nullptr, dwarf_f9_mips, dwarf_f9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f10, nullptr, dwarf_f10_mips, dwarf_f10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f11, nullptr, dwarf_f11_mips, dwarf_f11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f12, nullptr, dwarf_f12_mips, dwarf_f12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f13, nullptr, dwarf_f13_mips, dwarf_f13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f14, nullptr, dwarf_f14_mips, dwarf_f14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f15, nullptr, dwarf_f15_mips, dwarf_f15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f16, nullptr, dwarf_f16_mips, dwarf_f16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f17, nullptr, dwarf_f17_mips, dwarf_f17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f18, nullptr, dwarf_f18_mips, dwarf_f18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f19, nullptr, dwarf_f19_mips, dwarf_f19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f20, nullptr, dwarf_f20_mips, dwarf_f20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f21, nullptr, dwarf_f21_mips, dwarf_f21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f22, nullptr, dwarf_f22_mips, dwarf_f22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f23, nullptr, dwarf_f23_mips, dwarf_f23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f24, nullptr, dwarf_f24_mips, dwarf_f24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f25, nullptr, dwarf_f25_mips, dwarf_f25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f26, nullptr, dwarf_f26_mips, dwarf_f26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f27, nullptr, dwarf_f27_mips, dwarf_f27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f28, nullptr, dwarf_f28_mips, dwarf_f28_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f29, nullptr, dwarf_f29_mips, dwarf_f29_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f30, nullptr, dwarf_f30_mips, dwarf_f30_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f31, nullptr, dwarf_f31_mips, dwarf_f31_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w0, nullptr, dwarf_w0_mips, dwarf_w0_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w1, nullptr, dwarf_w1_mips, dwarf_w1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w2, nullptr, dwarf_w2_mips, dwarf_w2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w3, nullptr, dwarf_w3_mips, dwarf_w3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w4, nullptr, dwarf_w4_mips, dwarf_w4_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w5, nullptr, dwarf_w5_mips, dwarf_w5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w6, nullptr, dwarf_w6_mips, dwarf_w6_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w7, nullptr, dwarf_w7_mips, dwarf_w7_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w8, nullptr, dwarf_w8_mips, dwarf_w8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w9, nullptr, dwarf_w9_mips, dwarf_w9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w10, nullptr, dwarf_w10_mips, dwarf_w10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w11, nullptr, dwarf_w11_mips, dwarf_w11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w12, nullptr, dwarf_w12_mips, dwarf_w12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w13, nullptr, dwarf_w13_mips, dwarf_w13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w14, nullptr, dwarf_w14_mips, dwarf_w14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w15, nullptr, dwarf_w15_mips, dwarf_w15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w16, nullptr, dwarf_w16_mips, dwarf_w16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w17, nullptr, dwarf_w17_mips, dwarf_w17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w18, nullptr, dwarf_w18_mips, dwarf_w18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w19, nullptr, dwarf_w19_mips, dwarf_w19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w20, nullptr, dwarf_w10_mips, dwarf_w20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w21, nullptr, dwarf_w21_mips, dwarf_w21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w22, nullptr, dwarf_w22_mips, dwarf_w22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w23, nullptr, dwarf_w23_mips, dwarf_w23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w24, nullptr, dwarf_w24_mips, dwarf_w24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w25, nullptr, dwarf_w25_mips, dwarf_w25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w26, nullptr, dwarf_w26_mips, dwarf_w26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w27, nullptr, dwarf_w27_mips, dwarf_w27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w28, nullptr, dwarf_w28_mips, dwarf_w28_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w29, nullptr, dwarf_w29_mips, dwarf_w29_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w30, nullptr, dwarf_w30_mips, dwarf_w30_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w31, nullptr, dwarf_w31_mips, dwarf_w31_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (mcsr, nullptr, dwarf_mcsr_mips, dwarf_mcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (mir, nullptr, dwarf_mir_mips, dwarf_mir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM) +static RegisterInfo g_register_infos_mips[] = { + DEFINE_GPR(zero, "zero", dwarf_zero_mips, dwarf_zero_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r1, "at", dwarf_r1_mips, dwarf_r1_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(r2, nullptr, dwarf_r2_mips, dwarf_r2_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(r3, nullptr, dwarf_r3_mips, dwarf_r3_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(r4, nullptr, dwarf_r4_mips, dwarf_r4_mips, + LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR(r5, nullptr, dwarf_r5_mips, dwarf_r5_mips, + LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR(r6, nullptr, dwarf_r6_mips, dwarf_r6_mips, + LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR(r7, nullptr, dwarf_r7_mips, dwarf_r7_mips, + LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR(r8, nullptr, dwarf_r8_mips, dwarf_r8_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(r9, nullptr, dwarf_r9_mips, dwarf_r9_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(r10, nullptr, dwarf_r10_mips, dwarf_r10_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r11, nullptr, dwarf_r11_mips, dwarf_r11_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r12, nullptr, dwarf_r12_mips, dwarf_r12_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r13, nullptr, dwarf_r13_mips, dwarf_r13_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r14, nullptr, dwarf_r14_mips, dwarf_r14_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r15, nullptr, dwarf_r15_mips, dwarf_r15_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r16, nullptr, dwarf_r16_mips, dwarf_r16_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r17, nullptr, dwarf_r17_mips, dwarf_r17_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r18, nullptr, dwarf_r18_mips, dwarf_r18_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r19, nullptr, dwarf_r19_mips, dwarf_r19_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r20, nullptr, dwarf_r20_mips, dwarf_r20_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r21, nullptr, dwarf_r21_mips, dwarf_r21_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r22, nullptr, dwarf_r22_mips, dwarf_r22_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r23, nullptr, dwarf_r23_mips, dwarf_r23_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r24, nullptr, dwarf_r24_mips, dwarf_r24_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r25, nullptr, dwarf_r25_mips, dwarf_r25_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r26, nullptr, dwarf_r26_mips, dwarf_r26_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r27, nullptr, dwarf_r27_mips, dwarf_r27_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(gp, "gp", dwarf_gp_mips, dwarf_gp_mips, LLDB_INVALID_REGNUM), + DEFINE_GPR(sp, "sp", dwarf_sp_mips, dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR(r30, "fp", dwarf_r30_mips, dwarf_r30_mips, + LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR(ra, "ra", dwarf_ra_mips, dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR(sr, "status", dwarf_sr_mips, dwarf_sr_mips, + LLDB_REGNUM_GENERIC_FLAGS), + DEFINE_GPR(mullo, nullptr, dwarf_lo_mips, dwarf_lo_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips, dwarf_hi_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips, dwarf_bad_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(cause, nullptr, dwarf_cause_mips, dwarf_cause_mips, + LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, nullptr, dwarf_pc_mips, dwarf_pc_mips, + LLDB_REGNUM_GENERIC_PC), + DEFINE_GPR(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f0, nullptr, dwarf_f0_mips, dwarf_f0_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f1, nullptr, dwarf_f1_mips, dwarf_f1_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f2, nullptr, dwarf_f2_mips, dwarf_f2_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f3, nullptr, dwarf_f3_mips, dwarf_f3_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f4, nullptr, dwarf_f4_mips, dwarf_f4_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f5, nullptr, dwarf_f5_mips, dwarf_f5_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f6, nullptr, dwarf_f6_mips, dwarf_f6_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f7, nullptr, dwarf_f7_mips, dwarf_f7_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f8, nullptr, dwarf_f8_mips, dwarf_f8_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f9, nullptr, dwarf_f9_mips, dwarf_f9_mips, LLDB_INVALID_REGNUM), + DEFINE_FPR(f10, nullptr, dwarf_f10_mips, dwarf_f10_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f11, nullptr, dwarf_f11_mips, dwarf_f11_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f12, nullptr, dwarf_f12_mips, dwarf_f12_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f13, nullptr, dwarf_f13_mips, dwarf_f13_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f14, nullptr, dwarf_f14_mips, dwarf_f14_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f15, nullptr, dwarf_f15_mips, dwarf_f15_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f16, nullptr, dwarf_f16_mips, dwarf_f16_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f17, nullptr, dwarf_f17_mips, dwarf_f17_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f18, nullptr, dwarf_f18_mips, dwarf_f18_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f19, nullptr, dwarf_f19_mips, dwarf_f19_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f20, nullptr, dwarf_f20_mips, dwarf_f20_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f21, nullptr, dwarf_f21_mips, dwarf_f21_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f22, nullptr, dwarf_f22_mips, dwarf_f22_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f23, nullptr, dwarf_f23_mips, dwarf_f23_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f24, nullptr, dwarf_f24_mips, dwarf_f24_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f25, nullptr, dwarf_f25_mips, dwarf_f25_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f26, nullptr, dwarf_f26_mips, dwarf_f26_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f27, nullptr, dwarf_f27_mips, dwarf_f27_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f28, nullptr, dwarf_f28_mips, dwarf_f28_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f29, nullptr, dwarf_f29_mips, dwarf_f29_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f30, nullptr, dwarf_f30_mips, dwarf_f30_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f31, nullptr, dwarf_f31_mips, dwarf_f31_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w0, nullptr, dwarf_w0_mips, dwarf_w0_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w1, nullptr, dwarf_w1_mips, dwarf_w1_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w2, nullptr, dwarf_w2_mips, dwarf_w2_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w3, nullptr, dwarf_w3_mips, dwarf_w3_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w4, nullptr, dwarf_w4_mips, dwarf_w4_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w5, nullptr, dwarf_w5_mips, dwarf_w5_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w6, nullptr, dwarf_w6_mips, dwarf_w6_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w7, nullptr, dwarf_w7_mips, dwarf_w7_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w8, nullptr, dwarf_w8_mips, dwarf_w8_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w9, nullptr, dwarf_w9_mips, dwarf_w9_mips, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM), + DEFINE_MSA(w10, nullptr, dwarf_w10_mips, dwarf_w10_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w11, nullptr, dwarf_w11_mips, dwarf_w11_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w12, nullptr, dwarf_w12_mips, dwarf_w12_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w13, nullptr, dwarf_w13_mips, dwarf_w13_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w14, nullptr, dwarf_w14_mips, dwarf_w14_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w15, nullptr, dwarf_w15_mips, dwarf_w15_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w16, nullptr, dwarf_w16_mips, dwarf_w16_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w17, nullptr, dwarf_w17_mips, dwarf_w17_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w18, nullptr, dwarf_w18_mips, dwarf_w18_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w19, nullptr, dwarf_w19_mips, dwarf_w19_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w20, nullptr, dwarf_w10_mips, dwarf_w20_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w21, nullptr, dwarf_w21_mips, dwarf_w21_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w22, nullptr, dwarf_w22_mips, dwarf_w22_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w23, nullptr, dwarf_w23_mips, dwarf_w23_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w24, nullptr, dwarf_w24_mips, dwarf_w24_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w25, nullptr, dwarf_w25_mips, dwarf_w25_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w26, nullptr, dwarf_w26_mips, dwarf_w26_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w27, nullptr, dwarf_w27_mips, dwarf_w27_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w28, nullptr, dwarf_w28_mips, dwarf_w28_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w29, nullptr, dwarf_w29_mips, dwarf_w29_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w30, nullptr, dwarf_w30_mips, dwarf_w30_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w31, nullptr, dwarf_w31_mips, dwarf_w31_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(mcsr, nullptr, dwarf_mcsr_mips, dwarf_mcsr_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(mir, nullptr, dwarf_mir_mips, dwarf_mir_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM) }; static_assert((sizeof(g_register_infos_mips) / sizeof(g_register_infos_mips[0])) == k_num_registers_mips, "g_register_infos_mips has wrong number of register infos"); #undef GPR_OFFSET #undef FPR_OFFSET #undef MSA_OFFSET #undef DEFINE_GPR #undef DEFINE_FPR #undef DEFINE_FPR_INFO #undef DEFINE_MSA #undef DEFINE_MSA_INFO #endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT diff --git a/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/source/Plugins/Process/Utility/RegisterInfos_mips64.h index c0691b754103..5e9c503ca880 100644 --- a/source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ b/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -1,255 +1,388 @@ //===-- RegisterInfos_mips64.h ----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // C Includes #include // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" #include "lldb/Core/dwarf.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT // Computes the offset of the given GPR in the user data area. #ifdef LINUX_MIPS64 #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, gpr) + \ LLVM_EXTENSION offsetof(GPR_linux_mips, regname)) #else #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname)) #endif // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR_linux_mips, regname)) // Computes the offset of the given MSA in the extended data area. #define MSA_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, msa) + \ LLVM_EXTENSION offsetof(MSA_linux_mips, regname)) // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB // Note that the size and offset will be updated by platform-specific classes. #ifdef LINUX_MIPS64 - #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((GPR_linux_mips *) 0)->reg), \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + gpr_##reg##_mips64 }, \ + NULL, NULL, NULL, 0 \ + } #else #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR_freebsd_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} #endif -#define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} +#define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((GPR_linux_mips *) 0)->reg) / 2, \ + GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + gpr_##reg##_mips64 }, \ + NULL, NULL, NULL, 0 \ + } const uint8_t dwarf_opcode_mips64 [] = { llvm::dwarf::DW_OP_regx, dwarf_sr_mips64, llvm::dwarf::DW_OP_lit1, llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr }; +#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_mips *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + fpr_##reg##_mips64 }, \ + NULL, NULL, dwarf_opcode_mips64, \ + sizeof(dwarf_opcode_mips64) \ + } -#define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL, dwarf_opcode_mips64, sizeof(dwarf_opcode_mips64)} +#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \ + { \ + #reg, alt, sizeof(((FPR_linux_mips *) 0)->reg), \ + FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, ptrace_##reg##_mips, \ + fpr_##reg##_mips64 }, \ + NULL, NULL, NULL, 0 \ + } -#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ - { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL, NULL, 0} #define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \ eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL, NULL, 0} #define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \ eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL, NULL, 0} static RegisterInfo g_register_infos_mips64[] = { // General purpose registers. EH_Frame, DWARF, Generic, Process Plugin #ifndef LINUX_MIPS64 DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM), DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM), DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM), DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM), DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), DEFINE_GPR(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(ic, nullptr, dwarf_ic_mips64, dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(dummy, nullptr, dwarf_dummy_mips64, dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), #else - DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), - DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), - DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), - DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), - DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM), - DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM), - DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM), - DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM), - DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), - DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), - DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), - DEFINE_GPR_INFO(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), - DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR_INFO(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), - DEFINE_GPR_INFO(config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR (f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO (config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w0, nullptr, dwarf_w0_mips64, dwarf_w0_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w1, nullptr, dwarf_w1_mips64, dwarf_w1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w2, nullptr, dwarf_w2_mips64, dwarf_w2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w3, nullptr, dwarf_w3_mips64, dwarf_w3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w4, nullptr, dwarf_w4_mips64, dwarf_w4_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w5, nullptr, dwarf_w5_mips64, dwarf_w5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w6, nullptr, dwarf_w6_mips64, dwarf_w6_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w7, nullptr, dwarf_w7_mips64, dwarf_w7_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w8, nullptr, dwarf_w8_mips64, dwarf_w8_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w9, nullptr, dwarf_w9_mips64, dwarf_w9_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w10, nullptr, dwarf_w10_mips64, dwarf_w10_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w11, nullptr, dwarf_w11_mips64, dwarf_w11_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w12, nullptr, dwarf_w12_mips64, dwarf_w12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w13, nullptr, dwarf_w13_mips64, dwarf_w13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w14, nullptr, dwarf_w14_mips64, dwarf_w14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w15, nullptr, dwarf_w15_mips64, dwarf_w15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w16, nullptr, dwarf_w16_mips64, dwarf_w16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w17, nullptr, dwarf_w17_mips64, dwarf_w17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w18, nullptr, dwarf_w18_mips64, dwarf_w18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w19, nullptr, dwarf_w19_mips64, dwarf_w19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w20, nullptr, dwarf_w10_mips64, dwarf_w20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w21, nullptr, dwarf_w21_mips64, dwarf_w21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w22, nullptr, dwarf_w22_mips64, dwarf_w22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w23, nullptr, dwarf_w23_mips64, dwarf_w23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w24, nullptr, dwarf_w24_mips64, dwarf_w24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w25, nullptr, dwarf_w25_mips64, dwarf_w25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w26, nullptr, dwarf_w26_mips64, dwarf_w26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w27, nullptr, dwarf_w27_mips64, dwarf_w27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w28, nullptr, dwarf_w28_mips64, dwarf_w28_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w29, nullptr, dwarf_w29_mips64, dwarf_w29_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w30, nullptr, dwarf_w30_mips64, dwarf_w30_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA (w31, nullptr, dwarf_w31_mips64, dwarf_w31_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (mcsr, nullptr, dwarf_mcsr_mips64, dwarf_mcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (mir, nullptr, dwarf_mir_mips64, dwarf_mir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO (config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM) + DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, + LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, + LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, + LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, + LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, + LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, + LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, + LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, + LLDB_REGNUM_GENERIC_ARG8), + DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, + LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, + LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, + LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR_INFO(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, + LLDB_REGNUM_GENERIC_FLAGS), + DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR_INFO(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, + LLDB_INVALID_REGNUM), + DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, + LLDB_REGNUM_GENERIC_PC), + DEFINE_GPR_INFO(config5, nullptr, dwarf_config5_mips64, + dwarf_config5_mips64, LLDB_INVALID_REGNUM), + DEFINE_FPR(f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR(f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, + LLDB_INVALID_REGNUM), + DEFINE_FPR_INFO(config5, nullptr, dwarf_config5_mips64, + dwarf_config5_mips64, LLDB_INVALID_REGNUM), + DEFINE_MSA(w0, nullptr, dwarf_w0_mips64, dwarf_w0_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w1, nullptr, dwarf_w1_mips64, dwarf_w1_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w2, nullptr, dwarf_w2_mips64, dwarf_w2_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w3, nullptr, dwarf_w3_mips64, dwarf_w3_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w4, nullptr, dwarf_w4_mips64, dwarf_w4_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w5, nullptr, dwarf_w5_mips64, dwarf_w5_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w6, nullptr, dwarf_w6_mips64, dwarf_w6_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w7, nullptr, dwarf_w7_mips64, dwarf_w7_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w8, nullptr, dwarf_w8_mips64, dwarf_w8_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w9, nullptr, dwarf_w9_mips64, dwarf_w9_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w10, nullptr, dwarf_w10_mips64, dwarf_w10_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w11, nullptr, dwarf_w11_mips64, dwarf_w11_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w12, nullptr, dwarf_w12_mips64, dwarf_w12_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w13, nullptr, dwarf_w13_mips64, dwarf_w13_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w14, nullptr, dwarf_w14_mips64, dwarf_w14_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w15, nullptr, dwarf_w15_mips64, dwarf_w15_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w16, nullptr, dwarf_w16_mips64, dwarf_w16_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w17, nullptr, dwarf_w17_mips64, dwarf_w17_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w18, nullptr, dwarf_w18_mips64, dwarf_w18_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w19, nullptr, dwarf_w19_mips64, dwarf_w19_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w20, nullptr, dwarf_w10_mips64, dwarf_w20_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w21, nullptr, dwarf_w21_mips64, dwarf_w21_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w22, nullptr, dwarf_w22_mips64, dwarf_w22_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w23, nullptr, dwarf_w23_mips64, dwarf_w23_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w24, nullptr, dwarf_w24_mips64, dwarf_w24_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w25, nullptr, dwarf_w25_mips64, dwarf_w25_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w26, nullptr, dwarf_w26_mips64, dwarf_w26_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w27, nullptr, dwarf_w27_mips64, dwarf_w27_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w28, nullptr, dwarf_w28_mips64, dwarf_w28_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w29, nullptr, dwarf_w29_mips64, dwarf_w29_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w30, nullptr, dwarf_w30_mips64, dwarf_w30_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA(w31, nullptr, dwarf_w31_mips64, dwarf_w31_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(mcsr, nullptr, dwarf_mcsr_mips64, dwarf_mcsr_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(mir, nullptr, dwarf_mir_mips64, dwarf_mir_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_MSA_INFO(config5, nullptr, dwarf_config5_mips64, + dwarf_config5_mips64, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM) #endif }; static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64, "g_register_infos_mips64 has wrong number of register infos"); #undef DEFINE_GPR #undef DEFINE_GPR_INFO #undef DEFINE_FPR #undef DEFINE_FPR_INFO #undef DEFINE_MSA #undef DEFINE_MSA_INFO #undef GPR_OFFSET #undef FPR_OFFSET #undef MSA_OFFSET #endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT diff --git a/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h b/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h index 6c00025edfdf..46ebf4ba06e3 100644 --- a/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h +++ b/source/Plugins/Process/Utility/lldb-mips-linux-register-enums.h @@ -1,285 +1,363 @@ //===-- lldb-mips-linux-register-enums.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_mips_linux_register_enums_h #define lldb_mips_linux_register_enums_h namespace lldb_private { // LLDB register codes (e.g. RegisterKind == eRegisterKindLLDB) //--------------------------------------------------------------------------- // Internal codes for all mips registers. //--------------------------------------------------------------------------- enum { k_first_gpr_mips, gpr_zero_mips = k_first_gpr_mips, gpr_r1_mips, gpr_r2_mips, gpr_r3_mips, gpr_r4_mips, gpr_r5_mips, gpr_r6_mips, gpr_r7_mips, gpr_r8_mips, gpr_r9_mips, gpr_r10_mips, gpr_r11_mips, gpr_r12_mips, gpr_r13_mips, gpr_r14_mips, gpr_r15_mips, gpr_r16_mips, gpr_r17_mips, gpr_r18_mips, gpr_r19_mips, gpr_r20_mips, gpr_r21_mips, gpr_r22_mips, gpr_r23_mips, gpr_r24_mips, gpr_r25_mips, gpr_r26_mips, gpr_r27_mips, gpr_gp_mips, gpr_sp_mips, gpr_r30_mips, gpr_ra_mips, gpr_sr_mips, gpr_mullo_mips, gpr_mulhi_mips, gpr_badvaddr_mips, gpr_cause_mips, gpr_pc_mips, gpr_config5_mips, k_last_gpr_mips = gpr_config5_mips, k_first_fpr_mips, fpr_f0_mips = k_first_fpr_mips, fpr_f1_mips, fpr_f2_mips, fpr_f3_mips, fpr_f4_mips, fpr_f5_mips, fpr_f6_mips, fpr_f7_mips, fpr_f8_mips, fpr_f9_mips, fpr_f10_mips, fpr_f11_mips, fpr_f12_mips, fpr_f13_mips, fpr_f14_mips, fpr_f15_mips, fpr_f16_mips, fpr_f17_mips, fpr_f18_mips, fpr_f19_mips, fpr_f20_mips, fpr_f21_mips, fpr_f22_mips, fpr_f23_mips, fpr_f24_mips, fpr_f25_mips, fpr_f26_mips, fpr_f27_mips, fpr_f28_mips, fpr_f29_mips, fpr_f30_mips, fpr_f31_mips, fpr_fcsr_mips, fpr_fir_mips, fpr_config5_mips, k_last_fpr_mips = fpr_config5_mips, k_first_msa_mips, msa_w0_mips = k_first_msa_mips, msa_w1_mips, msa_w2_mips, msa_w3_mips, msa_w4_mips, msa_w5_mips, msa_w6_mips, msa_w7_mips, msa_w8_mips, msa_w9_mips, msa_w10_mips, msa_w11_mips, msa_w12_mips, msa_w13_mips, msa_w14_mips, msa_w15_mips, msa_w16_mips, msa_w17_mips, msa_w18_mips, msa_w19_mips, msa_w20_mips, msa_w21_mips, msa_w22_mips, msa_w23_mips, msa_w24_mips, msa_w25_mips, msa_w26_mips, msa_w27_mips, msa_w28_mips, msa_w29_mips, msa_w30_mips, msa_w31_mips, msa_fcsr_mips, msa_fir_mips, msa_mcsr_mips, msa_mir_mips, msa_config5_mips, k_last_msa_mips = msa_config5_mips, k_num_registers_mips, k_num_gpr_registers_mips = k_last_gpr_mips - k_first_gpr_mips + 1, k_num_fpr_registers_mips = k_last_fpr_mips - k_first_fpr_mips + 1, k_num_msa_registers_mips = k_last_msa_mips - k_first_msa_mips + 1, k_num_user_registers_mips = k_num_gpr_registers_mips + k_num_fpr_registers_mips + k_num_msa_registers_mips }; //--------------------------------------------------------------------------- // Internal codes for all mips64 registers. //--------------------------------------------------------------------------- enum { k_first_gpr_mips64, gpr_zero_mips64 = k_first_gpr_mips64, gpr_r1_mips64, gpr_r2_mips64, gpr_r3_mips64, gpr_r4_mips64, gpr_r5_mips64, gpr_r6_mips64, gpr_r7_mips64, gpr_r8_mips64, gpr_r9_mips64, gpr_r10_mips64, gpr_r11_mips64, gpr_r12_mips64, gpr_r13_mips64, gpr_r14_mips64, gpr_r15_mips64, gpr_r16_mips64, gpr_r17_mips64, gpr_r18_mips64, gpr_r19_mips64, gpr_r20_mips64, gpr_r21_mips64, gpr_r22_mips64, gpr_r23_mips64, gpr_r24_mips64, gpr_r25_mips64, gpr_r26_mips64, gpr_r27_mips64, gpr_gp_mips64, gpr_sp_mips64, gpr_r30_mips64, gpr_ra_mips64, gpr_sr_mips64, gpr_mullo_mips64, gpr_mulhi_mips64, gpr_badvaddr_mips64, gpr_cause_mips64, gpr_pc_mips64, gpr_config5_mips64, k_last_gpr_mips64 = gpr_config5_mips64, k_first_fpr_mips64, fpr_f0_mips64 = k_first_fpr_mips64, fpr_f1_mips64, fpr_f2_mips64, fpr_f3_mips64, fpr_f4_mips64, fpr_f5_mips64, fpr_f6_mips64, fpr_f7_mips64, fpr_f8_mips64, fpr_f9_mips64, fpr_f10_mips64, fpr_f11_mips64, fpr_f12_mips64, fpr_f13_mips64, fpr_f14_mips64, fpr_f15_mips64, fpr_f16_mips64, fpr_f17_mips64, fpr_f18_mips64, fpr_f19_mips64, fpr_f20_mips64, fpr_f21_mips64, fpr_f22_mips64, fpr_f23_mips64, fpr_f24_mips64, fpr_f25_mips64, fpr_f26_mips64, fpr_f27_mips64, fpr_f28_mips64, fpr_f29_mips64, fpr_f30_mips64, fpr_f31_mips64, fpr_fcsr_mips64, fpr_fir_mips64, fpr_config5_mips64, k_last_fpr_mips64 = fpr_config5_mips64, k_first_msa_mips64, msa_w0_mips64 = k_first_msa_mips64, msa_w1_mips64, msa_w2_mips64, msa_w3_mips64, msa_w4_mips64, msa_w5_mips64, msa_w6_mips64, msa_w7_mips64, msa_w8_mips64, msa_w9_mips64, msa_w10_mips64, msa_w11_mips64, msa_w12_mips64, msa_w13_mips64, msa_w14_mips64, msa_w15_mips64, msa_w16_mips64, msa_w17_mips64, msa_w18_mips64, msa_w19_mips64, msa_w20_mips64, msa_w21_mips64, msa_w22_mips64, msa_w23_mips64, msa_w24_mips64, msa_w25_mips64, msa_w26_mips64, msa_w27_mips64, msa_w28_mips64, msa_w29_mips64, msa_w30_mips64, msa_w31_mips64, msa_fcsr_mips64, msa_fir_mips64, msa_mcsr_mips64, msa_mir_mips64, msa_config5_mips64, k_last_msa_mips64 = msa_config5_mips64, k_num_registers_mips64, k_num_gpr_registers_mips64 = k_last_gpr_mips64 - k_first_gpr_mips64 + 1, k_num_fpr_registers_mips64 = k_last_fpr_mips64 - k_first_fpr_mips64 + 1, k_num_msa_registers_mips64 = k_last_msa_mips64 - k_first_msa_mips64 + 1, k_num_user_registers_mips64 = k_num_gpr_registers_mips64 + k_num_fpr_registers_mips64 + k_num_msa_registers_mips64 }; + +// Register no. for RegisterKind = eRegisterKindProcessPlugin +// The ptrace request PTRACE_PEEKUSER/PTRACE_POKEUSER used this number +enum { + ptrace_zero_mips, + ptrace_r1_mips, + ptrace_r2_mips, + ptrace_r3_mips, + ptrace_r4_mips, + ptrace_r5_mips, + ptrace_r6_mips, + ptrace_r7_mips, + ptrace_r8_mips, + ptrace_r9_mips, + ptrace_r10_mips, + ptrace_r11_mips, + ptrace_r12_mips, + ptrace_r13_mips, + ptrace_r14_mips, + ptrace_r15_mips, + ptrace_r16_mips, + ptrace_r17_mips, + ptrace_r18_mips, + ptrace_r19_mips, + ptrace_r20_mips, + ptrace_r21_mips, + ptrace_r22_mips, + ptrace_r23_mips, + ptrace_r24_mips, + ptrace_r25_mips, + ptrace_r26_mips, + ptrace_r27_mips, + ptrace_gp_mips, + ptrace_sp_mips, + ptrace_r30_mips, + ptrace_ra_mips, + ptrace_f0_mips, + ptrace_f1_mips, + ptrace_f2_mips, + ptrace_f3_mips, + ptrace_f4_mips, + ptrace_f5_mips, + ptrace_f6_mips, + ptrace_f7_mips, + ptrace_f8_mips, + ptrace_f9_mips, + ptrace_f10_mips, + ptrace_f11_mips, + ptrace_f12_mips, + ptrace_f13_mips, + ptrace_f14_mips, + ptrace_f15_mips, + ptrace_f16_mips, + ptrace_f17_mips, + ptrace_f18_mips, + ptrace_f19_mips, + ptrace_f20_mips, + ptrace_f21_mips, + ptrace_f22_mips, + ptrace_f23_mips, + ptrace_f24_mips, + ptrace_f25_mips, + ptrace_f26_mips, + ptrace_f27_mips, + ptrace_f28_mips, + ptrace_f29_mips, + ptrace_f30_mips, + ptrace_f31_mips, + ptrace_pc_mips, + ptrace_cause_mips, + ptrace_badvaddr_mips, + ptrace_mulhi_mips, + ptrace_mullo_mips, + ptrace_fcsr_mips, + ptrace_fir_mips, + ptrace_sr_mips, + ptrace_config5_mips +}; } #endif // #ifndef lldb_mips_linux_register_enums_h diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c90706a88b84..a792bbbd1385 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1,4627 +1,4634 @@ //===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "GDBRemoteCommunicationClient.h" // C Includes #include #include // C++ Includes #include #include // Other libraries and framework includes #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Target.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/UnixSignals.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "lldb/Host/Config.h" #if defined (HAVE_LIBCOMPRESSION) #include #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteCommunicationClient constructor //---------------------------------------------------------------------- GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet"), m_supports_not_sending_acks(eLazyBoolCalculate), m_supports_thread_suffix(eLazyBoolCalculate), m_supports_threads_in_stop_reply(eLazyBoolCalculate), m_supports_vCont_all(eLazyBoolCalculate), m_supports_vCont_any(eLazyBoolCalculate), m_supports_vCont_c(eLazyBoolCalculate), m_supports_vCont_C(eLazyBoolCalculate), m_supports_vCont_s(eLazyBoolCalculate), m_supports_vCont_S(eLazyBoolCalculate), m_qHostInfo_is_valid(eLazyBoolCalculate), m_curr_pid_is_valid(eLazyBoolCalculate), m_qProcessInfo_is_valid(eLazyBoolCalculate), m_qGDBServerVersion_is_valid(eLazyBoolCalculate), m_supports_alloc_dealloc_memory(eLazyBoolCalculate), m_supports_memory_region_info(eLazyBoolCalculate), m_supports_watchpoint_support_info(eLazyBoolCalculate), m_supports_detach_stay_stopped(eLazyBoolCalculate), m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), m_attach_or_wait_reply(eLazyBoolCalculate), m_prepare_for_reg_writing_reply(eLazyBoolCalculate), m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), m_avoid_g_packets(eLazyBoolCalculate), m_supports_QSaveRegisterState(eLazyBoolCalculate), m_supports_qXfer_auxv_read(eLazyBoolCalculate), m_supports_qXfer_libraries_read(eLazyBoolCalculate), m_supports_qXfer_libraries_svr4_read(eLazyBoolCalculate), m_supports_qXfer_features_read(eLazyBoolCalculate), m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), m_supports_jThreadExtendedInfo(eLazyBoolCalculate), m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), m_supports_z1(true), m_supports_z2(true), m_supports_z3(true), m_supports_z4(true), m_supports_QEnvironment(true), m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true), m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), m_supports_jThreadsInfo(true), m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), m_curr_tid_run(LLDB_INVALID_THREAD_ID), m_num_supported_hardware_watchpoints(0), m_async_mutex(), m_async_packet_predicate(false), m_async_packet(), m_async_result(PacketResult::Success), m_async_response(), m_async_signal(-1), m_interrupt_sent(false), m_thread_id_to_used_usec_map(), m_host_arch(), m_process_arch(), m_os_version_major(UINT32_MAX), m_os_version_minor(UINT32_MAX), m_os_version_update(UINT32_MAX), m_os_build(), m_os_kernel(), m_hostname(), m_gdb_server_name(), m_gdb_server_version(UINT32_MAX), m_default_packet_timeout(0), m_max_packet_size(0) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { if (IsConnected()) Disconnect(); } bool GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr) { ResetDiscoverableSettings(false); // Start the read thread after we send the handshake ack since if we // fail to send the handshake ack, there is no reason to continue... if (SendAck()) { // 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 = ReadPacket (response, timeout_usec, false); // The return value from QueryNoAckModeSupported() is true if the packet // was sent and _any_ response (including UNIMPLEMENTED) was received), // or false if no response was received. This quickly tells us if we have // a live connection to a remote GDB server... if (QueryNoAckModeSupported()) { return true; } else { if (error_ptr) error_ptr->SetErrorString("failed to get reply to handshake packet"); } } else { if (error_ptr) error_ptr->SetErrorString("failed to send the handshake ack"); } return false; } bool GDBRemoteCommunicationClient::GetEchoSupported () { if (m_supports_qEcho == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qEcho == eLazyBoolYes; } 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; } bool GDBRemoteCommunicationClient::GetQXferAuxvReadSupported () { if (m_supports_qXfer_auxv_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_auxv_read == eLazyBoolYes; } bool GDBRemoteCommunicationClient::GetQXferFeaturesReadSupported () { if (m_supports_qXfer_features_read == eLazyBoolCalculate) { GetRemoteQSupported(); } return m_supports_qXfer_features_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) { m_send_acks = true; m_supports_not_sending_acks = eLazyBoolNo; // This is the first real packet that we'll send in a debug session and it may take a little // longer than normal to receive a reply. Wait at least 6 seconds for a reply to this packet. const uint32_t minimum_timeout = 6; uint32_t old_timeout = GetPacketTimeoutInMicroSeconds() / lldb_private::TimeValue::MicroSecPerSec; GDBRemoteCommunication::ScopedTimeout timeout (*this, std::max (old_timeout, minimum_timeout)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_send_acks = false; m_supports_not_sending_acks = eLazyBoolYes; } return true; } } return false; } void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported () { if (m_supports_threads_in_stop_reply == eLazyBoolCalculate) { m_supports_threads_in_stop_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_threads_in_stop_reply = eLazyBoolYes; } } } bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported () { if (m_attach_or_wait_reply == eLazyBoolCalculate) { m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_attach_or_wait_reply = eLazyBoolYes; } } if (m_attach_or_wait_reply == eLazyBoolYes) return true; else return false; } bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported () { if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate) { m_prepare_for_reg_writing_reply = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_prepare_for_reg_writing_reply = eLazyBoolYes; } } if (m_prepare_for_reg_writing_reply == eLazyBoolYes) return true; else return false; } void GDBRemoteCommunicationClient::ResetDiscoverableSettings (bool did_exec) { if (did_exec == false) { // Hard reset everything, this is when we first connect to a GDB server m_supports_not_sending_acks = eLazyBoolCalculate; m_supports_thread_suffix = eLazyBoolCalculate; m_supports_threads_in_stop_reply = eLazyBoolCalculate; m_supports_vCont_c = eLazyBoolCalculate; m_supports_vCont_C = eLazyBoolCalculate; m_supports_vCont_s = eLazyBoolCalculate; m_supports_vCont_S = eLazyBoolCalculate; m_supports_p = eLazyBoolCalculate; m_supports_x = eLazyBoolCalculate; m_supports_QSaveRegisterState = eLazyBoolCalculate; m_qHostInfo_is_valid = eLazyBoolCalculate; m_curr_pid_is_valid = eLazyBoolCalculate; m_qGDBServerVersion_is_valid = eLazyBoolCalculate; m_supports_alloc_dealloc_memory = eLazyBoolCalculate; m_supports_memory_region_info = eLazyBoolCalculate; m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; m_avoid_g_packets = eLazyBoolCalculate; m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; m_supports_qXfer_features_read = eLazyBoolCalculate; m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; m_supports_qProcessInfoPID = true; m_supports_qfProcessInfo = true; m_supports_qUserName = true; m_supports_qGroupName = true; m_supports_qThreadStopInfo = true; m_supports_z0 = true; m_supports_z1 = true; m_supports_z2 = true; m_supports_z3 = true; m_supports_z4 = true; m_supports_QEnvironment = true; m_supports_QEnvironmentHexEncoded = true; m_supports_qSymbol = true; m_qSymbol_requests_done = false; m_supports_qModuleInfo = true; m_host_arch.Clear(); m_os_version_major = UINT32_MAX; m_os_version_minor = UINT32_MAX; m_os_version_update = UINT32_MAX; m_os_build.clear(); m_os_kernel.clear(); m_hostname.clear(); m_gdb_server_name.clear(); m_gdb_server_version = UINT32_MAX; m_default_packet_timeout = 0; m_max_packet_size = 0; } // These flags should be reset when we first connect to a GDB server // and when our inferior process execs m_qProcessInfo_is_valid = eLazyBoolCalculate; m_process_arch.Clear(); } void GDBRemoteCommunicationClient::GetRemoteQSupported () { // Clear out any capabilities we expect to see in the qSupported response m_supports_qXfer_auxv_read = eLazyBoolNo; m_supports_qXfer_libraries_read = eLazyBoolNo; m_supports_qXfer_libraries_svr4_read = eLazyBoolNo; m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if not, we assume no limit // build the qSupported packet std::vector features = {"xmlRegisters=i386,arm,mips"}; StreamString packet; packet.PutCString( "qSupported" ); for ( uint32_t i = 0; i < features.size( ); ++i ) { packet.PutCString( i==0 ? ":" : ";"); packet.PutCString( features[i].c_str( ) ); } StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet.GetData(), response, /*send_async=*/false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); if (::strstr (response_cstr, "qXfer:auxv:read+")) m_supports_qXfer_auxv_read = eLazyBoolYes; 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; if (::strstr (response_cstr, "qXfer:features:read+")) m_supports_qXfer_features_read = eLazyBoolYes; // Look for a list of compressions in the features list e.g. // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-deflate,lzma const char *features_list = ::strstr (response_cstr, "qXfer:features:"); if (features_list) { const char *compressions = ::strstr (features_list, "SupportedCompressions="); if (compressions) { std::vector supported_compressions; compressions += sizeof ("SupportedCompressions=") - 1; const char *end_of_compressions = strchr (compressions, ';'); if (end_of_compressions == NULL) { end_of_compressions = strchr (compressions, '\0'); } const char *current_compression = compressions; while (current_compression < end_of_compressions) { const char *next_compression_name = strchr (current_compression, ','); const char *end_of_this_word = next_compression_name; if (next_compression_name == NULL || end_of_compressions < next_compression_name) { end_of_this_word = end_of_compressions; } if (end_of_this_word) { if (end_of_this_word == current_compression) { current_compression++; } else { std::string this_compression (current_compression, end_of_this_word - current_compression); supported_compressions.push_back (this_compression); current_compression = end_of_this_word + 1; } } else { supported_compressions.push_back (current_compression); current_compression = end_of_compressions; } } if (supported_compressions.size() > 0) { MaybeEnableCompression (supported_compressions); } } } if (::strstr (response_cstr, "qEcho")) m_supports_qEcho = eLazyBoolYes; else m_supports_qEcho = eLazyBoolNo; 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 () { if (m_supports_thread_suffix == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_thread_suffix = eLazyBoolNo; if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_thread_suffix = eLazyBoolYes; } } return m_supports_thread_suffix; } bool GDBRemoteCommunicationClient::GetVContSupported (char flavor) { if (m_supports_vCont_c == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_vCont_any = eLazyBoolNo; m_supports_vCont_all = eLazyBoolNo; m_supports_vCont_c = eLazyBoolNo; m_supports_vCont_C = eLazyBoolNo; m_supports_vCont_s = eLazyBoolNo; m_supports_vCont_S = eLazyBoolNo; if (SendPacketAndWaitForResponse("vCont?", response, false) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().c_str(); if (::strstr (response_cstr, ";c")) m_supports_vCont_c = eLazyBoolYes; if (::strstr (response_cstr, ";C")) m_supports_vCont_C = eLazyBoolYes; if (::strstr (response_cstr, ";s")) m_supports_vCont_s = eLazyBoolYes; if (::strstr (response_cstr, ";S")) m_supports_vCont_S = eLazyBoolYes; if (m_supports_vCont_c == eLazyBoolYes && m_supports_vCont_C == eLazyBoolYes && m_supports_vCont_s == eLazyBoolYes && m_supports_vCont_S == eLazyBoolYes) { m_supports_vCont_all = eLazyBoolYes; } if (m_supports_vCont_c == eLazyBoolYes || m_supports_vCont_C == eLazyBoolYes || m_supports_vCont_s == eLazyBoolYes || m_supports_vCont_S == eLazyBoolYes) { m_supports_vCont_any = eLazyBoolYes; } } } switch (flavor) { case 'a': return m_supports_vCont_any; case 'A': return m_supports_vCont_all; case 'c': return m_supports_vCont_c; case 'C': return m_supports_vCont_C; case 's': return m_supports_vCont_s; case 'S': return m_supports_vCont_S; default: break; } return false; } // Check if the target supports 'p' packet. It sends out a 'p' // packet and checks the response. A normal packet will tell us // that support is available. // // Takes a valid thread ID because p needs to apply to a thread. bool GDBRemoteCommunicationClient::GetpPacketSupported (lldb::tid_t tid) { if (m_supports_p == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_p = eLazyBoolNo; char packet[256]; if (GetThreadSuffixSupported()) snprintf(packet, sizeof(packet), "p0;thread:%" PRIx64 ";", tid); else snprintf(packet, sizeof(packet), "p0"); if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsNormalResponse()) m_supports_p = eLazyBoolYes; } } return m_supports_p; } StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { // Get information on all threads at one using the "jThreadsInfo" packet StructuredData::ObjectSP object_sp; if (m_supports_jThreadsInfo) { StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { m_supports_jThreadsInfo = false; } else if (!response.Empty()) { object_sp = StructuredData::ParseJSON (response.GetStringRef()); } } } return object_sp; } bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported () { if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jThreadExtendedInfo = eLazyBoolNo; if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jThreadExtendedInfo = eLazyBoolYes; } } } return m_supports_jThreadExtendedInfo; } bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported () { if (m_supports_jLoadedDynamicLibrariesInfos == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; } } } return m_supports_jLoadedDynamicLibrariesInfos; } bool GDBRemoteCommunicationClient::GetxPacketSupported () { if (m_supports_x == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_x = eLazyBoolNo; char packet[256]; snprintf (packet, sizeof (packet), "x0,0"); if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_x = eLazyBoolYes; } } return m_supports_x; } 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; } // Concatenate the result so far (skipping 'm' or 'l') response_string.append(this_string, 1, std::string::npos); if (first_char == 'l') // We're done return PacketResult::Success; } } GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, StringExtractorGDBRemote &response, bool send_async ) { return SendPacketAndWaitForResponse (payload, ::strlen (payload), response, send_async); } 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) { const size_t max_response_retries = 3; for (size_t i=0; iPrintf("error: packet with payload \"%*s\" got invalid response \"%s\": %s", (int)payload_length, payload, response.GetStringRef().c_str(), (i == (max_response_retries - 1)) ? "using invalid response and giving up" : "ignoring response and waiting for another"); } } return packet_result; } GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketAndWaitForResponse ( const char *payload, size_t payload_length, StringExtractorGDBRemote &response, bool send_async ) { PacketResult packet_result = PacketResult::ErrorSendFailed; Mutex::Locker locker; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); // In order to stop async notifications from being processed in the middle of the // send/receive sequence Hijack the broadcast. Then rebroadcast any events when we are done. static ListenerSP hijack_listener_sp(Listener::MakeListener("lldb.NotifyHijacker")); HijackBroadcaster(hijack_listener_sp, eBroadcastBitGdbReadThreadGotNotify); if (GetSequenceMutex (locker)) { packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } else { if (send_async) { if (IsRunning()) { std::lock_guard guard(m_async_mutex); m_async_packet.assign(payload, payload_length); m_async_response.CopyResponseValidator(response); m_async_packet_predicate.SetValue (true, eBroadcastNever); if (log) log->Printf ("async: async packet = %s", m_async_packet.c_str()); bool timed_out = false; if (SendInterrupt(locker, 2, timed_out)) { if (m_interrupt_sent) { m_interrupt_sent = false; TimeValue timeout_time; timeout_time = TimeValue::Now(); timeout_time.OffsetWithSeconds (m_packet_timeout); if (log) log->Printf ("async: sent interrupt"); if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out)) { if (log) log->Printf ("async: got response"); // Swap the response buffer to avoid malloc and string copy response.GetStringRef().swap (m_async_response.GetStringRef()); packet_result = m_async_result; } else { if (log) log->Printf ("async: timed out waiting for response"); } // Make sure we wait until the continue packet has been sent again... if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out)) { if (log) { if (timed_out) log->Printf ("async: timed out waiting for process to resume, but process was resumed"); else log->Printf ("async: async packet sent"); } } else { if (log) log->Printf ("async: timed out waiting for process to resume"); } } else { // We had a racy condition where we went to send the interrupt // yet we were able to get the lock, so the process must have // just stopped? if (log) log->Printf ("async: got lock without sending interrupt"); // Send the packet normally since we got the lock packet_result = SendPacketAndWaitForResponseNoLock (payload, payload_length, response); } } else { if (log) log->Printf ("async: failed to interrupt"); } m_async_response.SetResponseValidator(nullptr, nullptr); } else { if (log) log->Printf ("async: not running, async is ignored"); } } else { if (log) log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload); } } // Remove our Hijacking listener from the broadcast. RestoreBroadcaster(); // If a notification event occurred, rebroadcast since it can now be processed safely. EventSP event_sp; if (hijack_listener_sp->GetNextEvent(event_sp)) BroadcastEvent(event_sp); return packet_result; } static const char *end_delimiter = "--end--;"; static const int end_delimiter_len = 8; std::string GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData ( ProcessGDBRemote *process, StringExtractorGDBRemote& profileDataExtractor ) { std::map new_thread_id_to_used_usec_map; std::stringstream final_output; std::string name, value; // Going to assuming thread_used_usec comes first, else bail out. while (profileDataExtractor.GetNameColonValue(name, value)) { if (name.compare("thread_used_id") == 0) { StringExtractor threadIDHexExtractor(value.c_str()); uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0); bool has_used_usec = false; uint32_t curr_used_usec = 0; std::string usec_name, usec_value; uint32_t input_file_pos = profileDataExtractor.GetFilePos(); if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) { if (usec_name.compare("thread_used_usec") == 0) { has_used_usec = true; curr_used_usec = strtoull(usec_value.c_str(), NULL, 0); } else { // We didn't find what we want, it is probably // an older version. Bail out. profileDataExtractor.SetFilePos(input_file_pos); } } if (has_used_usec) { uint32_t prev_used_usec = 0; std::map::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id); if (iterator != m_thread_id_to_used_usec_map.end()) { prev_used_usec = m_thread_id_to_used_usec_map[thread_id]; } uint32_t real_used_usec = curr_used_usec - prev_used_usec; // A good first time record is one that runs for at least 0.25 sec bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000); bool good_subsequent_time = (prev_used_usec > 0) && ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id))); if (good_first_time || good_subsequent_time) { // We try to avoid doing too many index id reservation, // resulting in fast increase of index ids. final_output << name << ":"; int32_t index_id = process->AssignIndexIDToThread(thread_id); final_output << index_id << ";"; final_output << usec_name << ":" << usec_value << ";"; } else { // Skip past 'thread_used_name'. std::string local_name, local_value; profileDataExtractor.GetNameColonValue(local_name, local_value); } // Store current time as previous time so that they can be compared later. new_thread_id_to_used_usec_map[thread_id] = curr_used_usec; } else { // Bail out and use old string. final_output << name << ":" << value << ";"; } } else { final_output << name << ":" << value << ";"; } } final_output << end_delimiter; m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map; return final_output.str(); } bool GDBRemoteCommunicationClient::SendvContPacket ( ProcessGDBRemote *process, const char *payload, size_t packet_length, StringExtractorGDBRemote &response ) { m_curr_tid = LLDB_INVALID_THREAD_ID; Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); // we want to lock down packet sending while we continue Mutex::Locker locker(m_sequence_mutex); // here we broadcast this before we even send the packet!! // this signals doContinue() to exit BroadcastEvent(eBroadcastBitRunPacketSent, NULL); // set the public state to running m_public_is_running.SetValue(true, eBroadcastNever); // Set the starting continue packet into "continue_packet". This packet // may change if we are interrupted and we continue after an async packet... std::string continue_packet(payload, packet_length); if (log) log->Printf("GDBRemoteCommunicationClient::%s () sending vCont packet: %s", __FUNCTION__, continue_packet.c_str()); if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) return false; // set the private state to running and broadcast this m_private_is_running.SetValue(true, eBroadcastAlways); if (log) log->Printf("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); // wait for the response to the vCont if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; } return false; } StateType GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse ( ProcessGDBRemote *process, const char *payload, size_t packet_length, StringExtractorGDBRemote &response ) { m_curr_tid = LLDB_INVALID_THREAD_ID; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__); Mutex::Locker locker(m_sequence_mutex); StateType state = eStateRunning; m_public_is_running.SetValue (true, eBroadcastNever); // Set the starting continue packet into "continue_packet". This packet // may change if we are interrupted and we continue after an async packet... std::string continue_packet(payload, packet_length); const auto sigstop_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGSTOP"); const auto sigint_signo = process->GetUnixSignals()->GetSignalNumberFromName("SIGINT"); bool got_async_packet = false; bool broadcast_sent = false; while (state == eStateRunning) { if (!got_async_packet) { if (log) log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str()); if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) != PacketResult::Success) state = eStateInvalid; else m_interrupt_sent = false; if (! broadcast_sent) { BroadcastEvent(eBroadcastBitRunPacketSent, NULL); broadcast_sent = true; } m_private_is_running.SetValue (true, eBroadcastAlways); } got_async_packet = false; if (log) log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(%s)", __FUNCTION__, continue_packet.c_str()); if (ReadPacket(response, UINT32_MAX, false) == PacketResult::Success) { if (response.Empty()) state = eStateInvalid; else { const char stop_type = response.GetChar(); if (log) log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str()); switch (stop_type) { case 'T': case 'S': { if (process->GetStopID() == 0) { if (process->GetID() == LLDB_INVALID_PROCESS_ID) { lldb::pid_t pid = GetCurrentProcessID (); if (pid != LLDB_INVALID_PROCESS_ID) process->SetID (pid); } process->BuildDynamicRegisterInfo (true); } // Privately notify any internal threads that we have stopped // in case we wanted to interrupt our process, yet we might // send a packet and continue without returning control to the // user. m_private_is_running.SetValue (false, eBroadcastAlways); const uint8_t signo = response.GetHexU8 (UINT8_MAX); bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue(); if (continue_after_async || m_interrupt_sent) { // We sent an interrupt packet to stop the inferior process // for an async signal or to send an async packet while running // but we might have been single stepping and received the // stop packet for the step instead of for the interrupt packet. // Typically when an interrupt is sent a SIGINT or SIGSTOP // is used, so if we get anything else, we need to try and // get another stop reply packet that may have been sent // due to sending the interrupt when the target is stopped // which will just re-send a copy of the last stop reply // packet. If we don't do this, then the reply for our // async packet will be the repeat stop reply packet and cause // a lot of trouble for us! We also have some debugserver // binaries that would send two stop replies anytime the process // was interrupted, so we need to also check for an extra // stop reply packet if we interrupted the process const bool received_nonstop_signal = signo != sigint_signo && signo != sigstop_signo; if (m_interrupt_sent || received_nonstop_signal) { if (received_nonstop_signal) continue_after_async = false; // Try for a very brief time (0.1s) to get another stop reply // packet to make sure it doesn't get in the way StringExtractorGDBRemote extra_stop_reply_packet; uint32_t timeout_usec = 100000; if (ReadPacket (extra_stop_reply_packet, timeout_usec, false) == PacketResult::Success) { switch (extra_stop_reply_packet.GetChar()) { case 'T': case 'S': // We did get an extra stop reply, which means // our interrupt didn't stop the target so we // shouldn't continue after the async signal // or packet is sent... continue_after_async = false; break; } } } } if (m_async_signal != -1) { if (log) log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal)); // Save off the async signal we are supposed to send const int async_signal = m_async_signal; // Clear the async signal member so we don't end up // sending the signal multiple times... m_async_signal = -1; // Check which signal we stopped with if (signo == async_signal) { if (log) log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo)); // We already stopped with a signal that we wanted // to stop with, so we are done } else { // We stopped with a different signal that the one // we wanted to stop with, so now we must resume // with the signal we want char signal_packet[32]; int signal_packet_len = 0; signal_packet_len = ::snprintf (signal_packet, sizeof (signal_packet), "C%2.2x", async_signal); if (log) log->Printf ("async: stopped with signal %s, resume with %s", Host::GetSignalAsCString (signo), Host::GetSignalAsCString (async_signal)); // Set the continue packet to resume even if the // interrupt didn't cause our stop (ignore continue_after_async) continue_packet.assign(signal_packet, signal_packet_len); continue; } } else if (m_async_packet_predicate.GetValue()) { Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS)); // We are supposed to send an asynchronous packet while // we are running. m_async_response.Clear(); if (m_async_packet.empty()) { m_async_result = PacketResult::ErrorSendFailed; if (packet_log) packet_log->Printf ("async: error: empty async packet"); } else { if (packet_log) packet_log->Printf ("async: sending packet"); 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 // ready... m_async_packet_predicate.SetValue(false, eBroadcastAlways); if (packet_log) packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async); // Set the continue packet to resume if our interrupt // for the async packet did cause the stop if (continue_after_async) { // Reverting this for now as it is causing deadlocks // in programs (). In the future // we should check our thread list and "do the right thing" // for new threads that show up while we stop and run async // packets. Setting the packet to 'c' to continue all threads // is the right thing to do 99.99% of the time because if a // thread was single stepping, and we sent an interrupt, we // will notice above that we didn't stop due to an interrupt // but stopped due to stepping and we would _not_ continue. continue_packet.assign (1, 'c'); continue; } } // Stop with signal and thread info state = eStateStopped; } break; case 'W': case 'X': // process exited state = eStateExited; break; case 'O': // STDOUT { got_async_packet = true; std::string inferior_stdout; inferior_stdout.reserve(response.GetBytesLeft () / 2); uint8_t ch; while (response.GetHexU8Ex(ch)) { if (ch != 0) inferior_stdout.append(1, (char)ch); } process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size()); } break; case 'A': // Async miscellaneous reply. Right now, only profile data is coming through this channel. { got_async_packet = true; std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A' if (m_partial_profile_data.length() > 0) { m_partial_profile_data.append(input); input = m_partial_profile_data; m_partial_profile_data.clear(); } size_t found, pos = 0, len = input.length(); while ((found = input.find(end_delimiter, pos)) != std::string::npos) { StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str()); std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor); process->BroadcastAsyncProfileData (profile_data); pos = found + end_delimiter_len; } if (pos < len) { // Last incomplete chunk. m_partial_profile_data = input.substr(pos); } } break; case 'E': // ERROR state = eStateInvalid; break; default: if (log) log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__); state = eStateInvalid; break; } } } else { if (log) log->Printf ("GDBRemoteCommunicationClient::%s () ReadPacket(...) => false", __FUNCTION__); state = eStateInvalid; } } if (log) log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state)); response.SetFilePos(0); m_private_is_running.SetValue (false, eBroadcastAlways); m_public_is_running.SetValue (false, eBroadcastAlways); return state; } bool GDBRemoteCommunicationClient::SendAsyncSignal (int signo) { std::lock_guard guard(m_async_mutex); m_async_signal = signo; bool timed_out = false; Mutex::Locker locker; if (SendInterrupt (locker, 1, timed_out)) return true; m_async_signal = -1; return false; } // This function takes a mutex locker as a parameter in case the GetSequenceMutex // actually succeeds. If it doesn't succeed in acquiring the sequence mutex // (the expected result), then it will send the halt packet. If it does succeed // then the caller that requested the interrupt will want to keep the sequence // locked down so that no one else can send packets while the caller has control. // This function usually gets called when we are running and need to stop the // target. It can also be used when we are running and we need to do something // else (like read/write memory), so we need to interrupt the running process // (gdb remote protocol requires this), and do what we need to do, then resume. bool GDBRemoteCommunicationClient::SendInterrupt ( Mutex::Locker& locker, uint32_t seconds_to_wait_for_stop, bool &timed_out ) { timed_out = false; Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); if (IsRunning()) { // Only send an interrupt if our debugserver is running... if (GetSequenceMutex (locker)) { if (log) log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt"); } else { // Someone has the mutex locked waiting for a response or for the // inferior to stop, so send the interrupt on the down low... char ctrl_c = '\x03'; ConnectionStatus status = eConnectionStatusSuccess; size_t bytes_written = Write (&ctrl_c, 1, status, NULL); if (log) log->PutCString("send packet: \\x03"); if (bytes_written > 0) { m_interrupt_sent = true; if (seconds_to_wait_for_stop) { TimeValue timeout; if (seconds_to_wait_for_stop) { timeout = TimeValue::Now(); timeout.OffsetWithSeconds (seconds_to_wait_for_stop); } if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out)) { if (log) log->PutCString ("SendInterrupt () - sent interrupt, private state stopped"); return true; } else { if (log) log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume"); } } else { if (log) log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop..."); return true; } } else { if (log) log->Printf ("SendInterrupt () - failed to write interrupt"); } return false; } } else { if (log) log->Printf ("SendInterrupt () - not running"); } return true; } lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID (bool allow_lazy) { if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes) return m_curr_pid; // First try to retrieve the pid via the qProcessInfo request. GetCurrentProcessInfo (allow_lazy); if (m_curr_pid_is_valid == eLazyBoolYes) { // We really got it. return m_curr_pid; } else { // If we don't get a response for qProcessInfo, check if $qC gives us a result. // $qC only returns a real process id on older debugserver and lldb-platform stubs. // The gdb remote protocol documents $qC as returning the thread id, which newer // debugserver and lldb-gdbserver stubs return correctly. StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false) == PacketResult::Success) { if (response.GetChar() == 'Q') { if (response.GetChar() == 'C') { m_curr_pid = response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID); if (m_curr_pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; } } } } // If we don't get a response for $qC, check if $qfThreadID gives us a result. if (m_curr_pid == LLDB_INVALID_PROCESS_ID) { std::vector thread_ids; bool sequence_mutex_unavailable; size_t size; size = GetCurrentThreadIDs (thread_ids, sequence_mutex_unavailable); if (size && sequence_mutex_unavailable == false) { m_curr_pid = thread_ids.front(); m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; } } } return LLDB_INVALID_PROCESS_ID; } bool GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str) { error_str.clear(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; if (response.GetChar() == 'E') { // A string the describes what failed when launching... error_str = response.GetStringRef().substr(1); } else { error_str.assign ("unknown error occurred launching process"); } } else { error_str.assign ("timed out waiting for app to launch"); } return false; } int GDBRemoteCommunicationClient::SendArgumentsPacket (const ProcessLaunchInfo &launch_info) { // Since we don't get the send argv0 separate from the executable path, we need to // make sure to use the actual executable path found in the launch_info... std::vector argv; FileSpec exe_file = launch_info.GetExecutableFile(); std::string exe_path; const char *arg = NULL; const Args &launch_args = launch_info.GetArguments(); if (exe_file) exe_path = exe_file.GetPath(false); else { arg = launch_args.GetArgumentAtIndex(0); if (arg) exe_path = arg; } if (!exe_path.empty()) { argv.push_back(exe_path.c_str()); for (uint32_t i=1; (arg = launch_args.GetArgumentAtIndex(i)) != NULL; ++i) { if (arg) argv.push_back(arg); } } if (!argv.empty()) { StreamString packet; packet.PutChar('A'); for (size_t i = 0, n = argv.size(); i < n; ++i) { arg = argv[i]; const int arg_len = strlen(arg); if (i > 0) packet.PutChar(','); packet.Printf("%i,%i,", arg_len * 2, (int)i); packet.PutBytesAsRawHex8 (arg, arg_len); } StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value) { if (name_equal_value && name_equal_value[0]) { StreamString packet; bool send_hex_encoding = false; for (const char *p = name_equal_value; *p != '\0' && send_hex_encoding == false; ++p) { if (isprint(*p)) { switch (*p) { case '$': case '#': case '*': case '}': send_hex_encoding = true; break; default: break; } } else { // We have non printable characters, lets hex encode this... send_hex_encoding = true; } } StringExtractorGDBRemote response; if (send_hex_encoding) { if (m_supports_QEnvironmentHexEncoded) { packet.PutCString("QEnvironmentHexEncoded:"); packet.PutBytesAsRawHex8 (name_equal_value, strlen(name_equal_value)); if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; if (response.IsUnsupportedResponse()) m_supports_QEnvironmentHexEncoded = false; } } } else if (m_supports_QEnvironment) { packet.Printf("QEnvironment:%s", name_equal_value); if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; if (response.IsUnsupportedResponse()) m_supports_QEnvironment = false; } } } return -1; } int GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch) { if (arch && arch[0]) { StreamString packet; packet.Printf("QLaunchArch:%s", arch); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SendLaunchEventDataPacket (char const *data, bool *was_supported) { if (data && *data != '\0') { StreamString packet; packet.Printf("QSetProcessEvent:%s", data); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) { if (was_supported) *was_supported = true; return 0; } else if (response.IsUnsupportedResponse()) { if (was_supported) *was_supported = false; return -1; } else { uint8_t error = response.GetError(); if (was_supported) *was_supported = true; if (error) return error; } } } return -1; } bool GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major, uint32_t &minor, uint32_t &update) { if (GetHostInfo ()) { if (m_os_version_major != UINT32_MAX) { major = m_os_version_major; minor = m_os_version_minor; update = m_os_version_update; return true; } } return false; } bool GDBRemoteCommunicationClient::GetOSBuildString (std::string &s) { if (GetHostInfo ()) { if (!m_os_build.empty()) { s = m_os_build; return true; } } s.clear(); return false; } bool GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s) { if (GetHostInfo ()) { if (!m_os_kernel.empty()) { s = m_os_kernel; return true; } } s.clear(); return false; } bool GDBRemoteCommunicationClient::GetHostname (std::string &s) { if (GetHostInfo ()) { if (!m_hostname.empty()) { s = m_hostname; return true; } } s.clear(); return false; } ArchSpec GDBRemoteCommunicationClient::GetSystemArchitecture () { if (GetHostInfo ()) return m_host_arch; return ArchSpec(); } const lldb_private::ArchSpec & GDBRemoteCommunicationClient::GetProcessArchitecture () { if (m_qProcessInfo_is_valid == eLazyBoolCalculate) GetCurrentProcessInfo (); return m_process_arch; } bool GDBRemoteCommunicationClient::GetGDBServerVersion() { if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) { m_gdb_server_name.clear(); m_gdb_server_version = 0; m_qGDBServerVersion_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse ("qGDBServerVersion", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { std::string name; std::string value; bool success = false; while (response.GetNameColonValue(name, value)) { if (name.compare("name") == 0) { success = true; m_gdb_server_name.swap(value); } else if (name.compare("version") == 0) { size_t dot_pos = value.find('.'); if (dot_pos != std::string::npos) value[dot_pos] = '\0'; const uint32_t version = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); if (version != UINT32_MAX) { success = true; m_gdb_server_version = version; } } } if (success) m_qGDBServerVersion_is_valid = eLazyBoolYes; } } } return m_qGDBServerVersion_is_valid == eLazyBoolYes; } void GDBRemoteCommunicationClient::MaybeEnableCompression (std::vector supported_compressions) { CompressionType avail_type = CompressionType::None; std::string avail_name; #if defined (HAVE_LIBCOMPRESSION) // libcompression is weak linked so test if compression_decode_buffer() is available if (compression_decode_buffer != NULL && avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lzfse") { avail_type = CompressionType::LZFSE; avail_name = compression; break; } } } #endif #if defined (HAVE_LIBCOMPRESSION) // libcompression is weak linked so test if compression_decode_buffer() is available if (compression_decode_buffer != NULL && avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { avail_type = CompressionType::ZlibDeflate; avail_name = compression; break; } } } #endif #if defined (HAVE_LIBZ) if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { avail_type = CompressionType::ZlibDeflate; avail_name = compression; break; } } } #endif #if defined (HAVE_LIBCOMPRESSION) // libcompression is weak linked so test if compression_decode_buffer() is available if (compression_decode_buffer != NULL && avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lz4") { avail_type = CompressionType::LZ4; avail_name = compression; break; } } } #endif #if defined (HAVE_LIBCOMPRESSION) // libcompression is weak linked so test if compression_decode_buffer() is available if (compression_decode_buffer != NULL && avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "lzma") { avail_type = CompressionType::LZMA; avail_name = compression; break; } } } #endif if (avail_type != CompressionType::None) { StringExtractorGDBRemote response; std::string packet = "QEnableCompression:type:" + avail_name + ";"; if (SendPacketAndWaitForResponse (packet.c_str(), response, false) != PacketResult::Success) return; if (response.IsOKResponse()) { m_compression_type = avail_type; } } } const char * GDBRemoteCommunicationClient::GetGDBServerProgramName() { if (GetGDBServerVersion()) { if (!m_gdb_server_name.empty()) return m_gdb_server_name.c_str(); } return NULL; } uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() { if (GetGDBServerVersion()) return m_gdb_server_version; return 0; } bool GDBRemoteCommunicationClient::GetDefaultThreadId (lldb::tid_t &tid) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qC",response,false) != PacketResult::Success) return false; if (!response.IsNormalResponse()) return false; if (response.GetChar() == 'Q' && response.GetChar() == 'C') tid = response.GetHexMaxU32(true, -1); return true; } bool GDBRemoteCommunicationClient::GetHostInfo (bool force) { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS)); if (force || m_qHostInfo_is_valid == eLazyBoolCalculate) { m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse ("qHostInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { std::string name; std::string value; uint32_t cpu = LLDB_INVALID_CPUTYPE; uint32_t sub = 0; std::string arch_name; 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; uint32_t num_keys_decoded = 0; while (response.GetNameColonValue(name, value)) { if (name.compare("cputype") == 0) { // exception type in big endian hex cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0); if (cpu != LLDB_INVALID_CPUTYPE) ++num_keys_decoded; } else if (name.compare("cpusubtype") == 0) { // exception count in big endian hex sub = StringConvert::ToUInt32 (value.c_str(), 0, 0); if (sub != 0) ++num_keys_decoded; } else if (name.compare("arch") == 0) { arch_name.swap (value); ++num_keys_decoded; } else if (name.compare("triple") == 0) { extractor.GetStringRef ().swap (value); extractor.SetFilePos(0); 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); extractor.SetFilePos(0); extractor.GetHexByteString (m_os_build); ++num_keys_decoded; } else if (name.compare("hostname") == 0) { extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString (m_hostname); ++num_keys_decoded; } else if (name.compare("os_kernel") == 0) { extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString (m_os_kernel); ++num_keys_decoded; } else if (name.compare("ostype") == 0) { os_name.swap (value); ++num_keys_decoded; } else if (name.compare("vendor") == 0) { vendor_name.swap(value); ++num_keys_decoded; } else if (name.compare("endian") == 0) { ++num_keys_decoded; if (value.compare("little") == 0) byte_order = eByteOrderLittle; else if (value.compare("big") == 0) byte_order = eByteOrderBig; else if (value.compare("pdp") == 0) byte_order = eByteOrderPDP; else --num_keys_decoded; } else if (name.compare("ptrsize") == 0) { pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 0); if (pointer_byte_size != 0) ++num_keys_decoded; } else if ((name.compare("os_version") == 0) || (name.compare("version") == 0)) // Older debugserver binaries used the "version" key instead of "os_version"... { Args::StringToVersion (value.c_str(), m_os_version_major, m_os_version_minor, m_os_version_update); if (m_os_version_major != UINT32_MAX) ++num_keys_decoded; } else if (name.compare("watchpoint_exceptions_received") == 0) { ++num_keys_decoded; if (strcmp(value.c_str(),"before") == 0) m_watchpoints_trigger_after_instruction = eLazyBoolNo; else if (strcmp(value.c_str(),"after") == 0) m_watchpoints_trigger_after_instruction = eLazyBoolYes; else --num_keys_decoded; } else if (name.compare("default_packet_timeout") == 0) { m_default_packet_timeout = StringConvert::ToUInt32(value.c_str(), 0); if (m_default_packet_timeout > 0) { SetPacketTimeout(m_default_packet_timeout); ++num_keys_decoded; } } } if (num_keys_decoded > 0) m_qHostInfo_is_valid = eLazyBoolYes; if (triple.empty()) { if (arch_name.empty()) { if (cpu != LLDB_INVALID_CPUTYPE) { m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub); if (pointer_byte_size) { assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert (byte_order == m_host_arch.GetByteOrder()); } if (!vendor_name.empty()) m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); if (!os_name.empty()) m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); } } else { std::string triple; triple += arch_name; if (!vendor_name.empty() || !os_name.empty()) { triple += '-'; if (vendor_name.empty()) triple += "unknown"; else triple += vendor_name; triple += '-'; if (os_name.empty()) triple += "unknown"; else triple += os_name; } m_host_arch.SetTriple (triple.c_str()); llvm::Triple &host_triple = m_host_arch.GetTriple(); if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin) { switch (m_host_arch.GetMachine()) { case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: host_triple.setOS(llvm::Triple::IOS); break; default: host_triple.setOS(llvm::Triple::MacOSX); break; } } if (pointer_byte_size) { assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert (byte_order == m_host_arch.GetByteOrder()); } } } else { m_host_arch.SetTriple (triple.c_str()); if (pointer_byte_size) { assert (pointer_byte_size == m_host_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert (byte_order == m_host_arch.GetByteOrder()); } if (log) log->Printf ("GDBRemoteCommunicationClient::%s parsed host architecture as %s, triple as %s from triple text %s", __FUNCTION__, m_host_arch.GetArchitectureName () ? m_host_arch.GetArchitectureName () : "", m_host_arch.GetTriple ().getTriple ().c_str(), triple.c_str ()); } if (!distribution_id.empty ()) m_host_arch.SetDistributionId (distribution_id.c_str ()); } } } return m_qHostInfo_is_valid == eLazyBoolYes; } int GDBRemoteCommunicationClient::SendAttach ( lldb::pid_t pid, StringExtractorGDBRemote& response ) { if (pid != LLDB_INVALID_PROCESS_ID) { 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) == PacketResult::Success) { if (response.IsErrorResponse()) return response.GetError(); return 0; } } return -1; } int GDBRemoteCommunicationClient::SendStdinNotification (const char* data, size_t data_len) { StreamString packet; packet.PutCString("I"); packet.PutBytesAsRawHex8(data, data_len); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { return 0; } return response.GetError(); } const lldb_private::ArchSpec & GDBRemoteCommunicationClient::GetHostArchitecture () { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo (); return m_host_arch; } uint32_t GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout () { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo (); return m_default_packet_timeout; } addr_t GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions) { if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { m_supports_alloc_dealloc_memory = eLazyBoolYes; char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s", (uint64_t)size, permissions & lldb::ePermissionsReadable ? "r" : "", permissions & lldb::ePermissionsWritable ? "w" : "", permissions & lldb::ePermissionsExecutable ? "x" : ""); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; else if (!response.IsErrorResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } else { m_supports_alloc_dealloc_memory = eLazyBoolNo; } } return LLDB_INVALID_ADDRESS; } bool GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr) { if (m_supports_alloc_dealloc_memory != eLazyBoolNo) { m_supports_alloc_dealloc_memory = eLazyBoolYes; char packet[64]; 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) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; else if (response.IsOKResponse()) return true; } else { m_supports_alloc_dealloc_memory = eLazyBoolNo; } } return false; } Error GDBRemoteCommunicationClient::Detach (bool keep_stopped) { Error error; if (keep_stopped) { if (m_supports_detach_stay_stopped == eLazyBoolCalculate) { char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success && response.IsOKResponse()) { m_supports_detach_stay_stopped = eLazyBoolYes; } else { m_supports_detach_stay_stopped = eLazyBoolNo; } } if (m_supports_detach_stay_stopped == eLazyBoolNo) { error.SetErrorString("Stays stopped not supported by this target."); return error; } else { StringExtractorGDBRemote response; PacketResult packet_result = SendPacketAndWaitForResponse ("D1", 2, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending extended disconnect packet failed."); } } else { StringExtractorGDBRemote response; PacketResult packet_result = SendPacketAndWaitForResponse ("D", 1, response, false); if (packet_result != PacketResult::Success) error.SetErrorString ("Sending disconnect packet failed."); } return error; } Error GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr, lldb_private::MemoryRegionInfo ®ion_info) { Error error; region_info.Clear(); if (m_supports_memory_region_info != eLazyBoolNo) { m_supports_memory_region_info = eLazyBoolYes; char packet[64]; 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) == PacketResult::Success) { std::string name; std::string value; addr_t addr_value; bool success = true; bool saw_permissions = false; while (success && response.GetNameColonValue(name, value)) { if (name.compare ("start") == 0) { addr_value = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success); if (success) region_info.GetRange().SetRangeBase(addr_value); } else if (name.compare ("size") == 0) { addr_value = StringConvert::ToUInt64(value.c_str(), 0, 16, &success); if (success) region_info.GetRange().SetByteSize (addr_value); } else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid()) { saw_permissions = true; if (region_info.GetRange().Contains (addr)) { if (value.find('r') != std::string::npos) region_info.SetReadable (MemoryRegionInfo::eYes); else region_info.SetReadable (MemoryRegionInfo::eNo); if (value.find('w') != std::string::npos) region_info.SetWritable (MemoryRegionInfo::eYes); else region_info.SetWritable (MemoryRegionInfo::eNo); if (value.find('x') != std::string::npos) region_info.SetExecutable (MemoryRegionInfo::eYes); else region_info.SetExecutable (MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eYes); } else { // The reported region does not contain this address -- we're looking at an unmapped page region_info.SetReadable (MemoryRegionInfo::eNo); region_info.SetWritable (MemoryRegionInfo::eNo); region_info.SetExecutable (MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); } } else if (name.compare ("error") == 0) { StringExtractorGDBRemote name_extractor; // Swap "value" over into "name_extractor" name_extractor.GetStringRef().swap(value); // Now convert the HEX bytes into a string value name_extractor.GetHexByteString (value); error.SetErrorString(value.c_str()); } } // We got a valid address range back but no permissions -- which means this is an unmapped page if (region_info.GetRange().IsValid() && saw_permissions == false) { region_info.SetReadable (MemoryRegionInfo::eNo); region_info.SetWritable (MemoryRegionInfo::eNo); region_info.SetExecutable (MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); } } else { m_supports_memory_region_info = eLazyBoolNo; } } if (m_supports_memory_region_info == eLazyBoolNo) { error.SetErrorString("qMemoryRegionInfo is not supported"); } if (error.Fail()) region_info.Clear(); return error; } Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num) { Error error; if (m_supports_watchpoint_support_info == eLazyBoolYes) { num = m_num_supported_hardware_watchpoints; return error; } // Set num to 0 first. num = 0; if (m_supports_watchpoint_support_info != eLazyBoolNo) { char packet[64]; const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; std::string name; std::string value; while (response.GetNameColonValue(name, value)) { if (name.compare ("num") == 0) { num = StringConvert::ToUInt32(value.c_str(), 0, 0); m_num_supported_hardware_watchpoints = num; } } } else { m_supports_watchpoint_support_info = eLazyBoolNo; } } if (m_supports_watchpoint_support_info == eLazyBoolNo) { error.SetErrorString("qWatchpointSupportInfo is not supported"); } return error; } lldb_private::Error GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after, const ArchSpec &arch) { Error error(GetWatchpointSupportInfo(num)); if (error.Success()) error = GetWatchpointsTriggerAfterInstruction(after, arch); return error; } lldb_private::Error GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after, const ArchSpec &arch) { Error error; llvm::Triple::ArchType atype = arch.GetMachine(); // we assume watchpoints will happen after running the relevant opcode // and we only want to override this behavior if we have explicitly // received a qHostInfo telling us otherwise if (m_qHostInfo_is_valid != eLazyBoolYes) { // On targets like MIPS, watchpoint exceptions are always generated // before the instruction is executed. The connected target may not // support qHostInfo or qWatchpointSupportInfo packets. if (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el) after = false; else after = true; } else { // For MIPS, set m_watchpoints_trigger_after_instruction to eLazyBoolNo // if it is not calculated before. if (m_watchpoints_trigger_after_instruction == eLazyBoolCalculate && (atype == llvm::Triple::mips || atype == llvm::Triple::mipsel || atype == llvm::Triple::mips64 || atype == llvm::Triple::mips64el)) m_watchpoints_trigger_after_instruction = eLazyBoolNo; after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo); } return error; } int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDIN:"); packet.PutCStringAsRawHex8(path.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDOUT:"); packet.PutCStringAsRawHex8(path.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { if (file_spec) { std::string path{file_spec.GetPath(false)}; StreamString packet; packet.PutCString("QSetSTDERR:"); packet.PutCStringAsRawHex8(path.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse ("qGetWorkingDir", response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) return false; if (response.IsErrorResponse()) return false; std::string cwd; response.GetHexByteString(cwd); working_dir.SetFile(cwd, false, GetHostArchitecture()); return !cwd.empty(); } return false; } int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { if (working_dir) { std::string path{working_dir.GetPath(false)}; StreamString packet; packet.PutCString("QSetWorkingDir:"); packet.PutCStringAsRawHex8(path.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } } return -1; } int GDBRemoteCommunicationClient::SetDisableASLR (bool enable) { char packet[32]; 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) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } return -1; } int GDBRemoteCommunicationClient::SetDetachOnError (bool enable) { char packet[32]; const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDetachOnError:%i", enable ? 1 : 0); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); if (error) return error; } return -1; } bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info) { if (response.IsNormalResponse()) { 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)) { if (name.compare("pid") == 0) { process_info.SetProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); } else if (name.compare("ppid") == 0) { process_info.SetParentProcessID (StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0)); } else if (name.compare("uid") == 0) { process_info.SetUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("euid") == 0) { process_info.SetEffectiveUserID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("gid") == 0) { process_info.SetGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("egid") == 0) { process_info.SetEffectiveGroupID (StringConvert::ToUInt32 (value.c_str(), UINT32_MAX, 0)); } else if (name.compare("triple") == 0) { StringExtractor extractor; extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString (value); process_info.GetArchitecture ().SetTriple (value.c_str()); } else if (name.compare("name") == 0) { StringExtractor extractor; // The process name from ASCII hex bytes since we can't // control the characters in a process name extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString (value); process_info.GetExecutableFile().SetFile (value.c_str(), false); } else if (name.compare("cputype") == 0) { cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); } else if (name.compare("cpusubtype") == 0) { sub = StringConvert::ToUInt32 (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) return true; } return false; } bool GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) { process_info.Clear(); if (m_supports_qProcessInfoPID) { char packet[32]; 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) == PacketResult::Success) { return DecodeProcessInfoResponse (response, process_info); } else { m_supports_qProcessInfoPID = false; return false; } } return false; } bool GDBRemoteCommunicationClient::GetCurrentProcessInfo (bool allow_lazy) { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); if (allow_lazy) { if (m_qProcessInfo_is_valid == eLazyBoolYes) return true; if (m_qProcessInfo_is_valid == eLazyBoolNo) return false; } GetHostInfo (); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse ("qProcessInfo", response, false) == PacketResult::Success) { if (response.IsNormalResponse()) { std::string name; std::string value; uint32_t cpu = LLDB_INVALID_CPUTYPE; uint32_t sub = 0; std::string arch_name; std::string os_name; std::string vendor_name; std::string triple; + std::string elf_abi; uint32_t pointer_byte_size = 0; StringExtractor extractor; ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { if (name.compare("cputype") == 0) { cpu = StringConvert::ToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16); if (cpu != LLDB_INVALID_CPUTYPE) ++num_keys_decoded; } else if (name.compare("cpusubtype") == 0) { sub = StringConvert::ToUInt32 (value.c_str(), 0, 16); if (sub != 0) ++num_keys_decoded; } else if (name.compare("triple") == 0) { StringExtractor extractor; extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString (triple); ++num_keys_decoded; } else if (name.compare("ostype") == 0) { os_name.swap (value); ++num_keys_decoded; } else if (name.compare("vendor") == 0) { vendor_name.swap(value); ++num_keys_decoded; } else if (name.compare("endian") == 0) { ++num_keys_decoded; if (value.compare("little") == 0) byte_order = eByteOrderLittle; else if (value.compare("big") == 0) byte_order = eByteOrderBig; else if (value.compare("pdp") == 0) byte_order = eByteOrderPDP; else --num_keys_decoded; } else if (name.compare("ptrsize") == 0) { pointer_byte_size = StringConvert::ToUInt32 (value.c_str(), 0, 16); if (pointer_byte_size != 0) ++num_keys_decoded; } else if (name.compare("pid") == 0) { pid = StringConvert::ToUInt64(value.c_str(), 0, 16); if (pid != LLDB_INVALID_PROCESS_ID) ++num_keys_decoded; } + else if (name.compare("elf_abi") == 0) + { + elf_abi = value; + ++num_keys_decoded; + } } if (num_keys_decoded > 0) m_qProcessInfo_is_valid = eLazyBoolYes; if (pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; m_curr_pid = pid; } // Set the ArchSpec from the triple if we have it. if (!triple.empty ()) { m_process_arch.SetTriple (triple.c_str ()); + m_process_arch.SetFlags(elf_abi); if (pointer_byte_size) { assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); } } else if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty()) { llvm::Triple triple(llvm::Twine("-") + vendor_name + "-" + os_name); assert(triple.getObjectFormat() != llvm::Triple::UnknownObjectFormat); switch (triple.getObjectFormat()) { case llvm::Triple::MachO: m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub); break; case llvm::Triple::ELF: m_process_arch.SetArchitecture (eArchTypeELF, cpu, sub); break; case llvm::Triple::COFF: m_process_arch.SetArchitecture (eArchTypeCOFF, cpu, sub); break; case llvm::Triple::UnknownObjectFormat: if (log) log->Printf("error: failed to determine target architecture"); return false; } if (pointer_byte_size) { assert (pointer_byte_size == m_process_arch.GetAddressByteSize()); } if (byte_order != eByteOrderInvalid) { assert (byte_order == m_process_arch.GetByteOrder()); } m_process_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); m_process_arch.GetTriple().setOSName(llvm::StringRef (os_name)); m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name)); m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name)); } return true; } } else { m_qProcessInfo_is_valid = eLazyBoolNo; } return false; } uint32_t GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { process_infos.Clear(); if (m_supports_qfProcessInfo) { StreamString packet; packet.PutCString ("qfProcessInfo"); if (!match_info.MatchAllProcesses()) { packet.PutChar (':'); const char *name = match_info.GetProcessInfo().GetName(); bool has_name_match = false; if (name && name[0]) { has_name_match = true; NameMatchType name_match_type = match_info.GetNameMatchType(); switch (name_match_type) { case eNameMatchIgnore: has_name_match = false; break; case eNameMatchEquals: packet.PutCString ("name_match:equals;"); break; case eNameMatchContains: packet.PutCString ("name_match:contains;"); break; case eNameMatchStartsWith: packet.PutCString ("name_match:starts_with;"); break; case eNameMatchEndsWith: packet.PutCString ("name_match:ends_with;"); break; case eNameMatchRegularExpression: packet.PutCString ("name_match:regex;"); break; } if (has_name_match) { packet.PutCString ("name:"); packet.PutBytesAsRawHex8(name, ::strlen(name)); packet.PutChar (';'); } } if (match_info.GetProcessInfo().ProcessIDIsValid()) packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID()); if (match_info.GetProcessInfo().ParentProcessIDIsValid()) packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID()); if (match_info.GetProcessInfo().UserIDIsValid()) packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID()); if (match_info.GetProcessInfo().GroupIDIsValid()) packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID()); if (match_info.GetProcessInfo().EffectiveUserIDIsValid()) packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID()); if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID()); if (match_info.GetProcessInfo().EffectiveGroupIDIsValid()) packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0); if (match_info.GetProcessInfo().GetArchitecture().IsValid()) { const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture(); const llvm::Triple &triple = match_arch.GetTriple(); packet.PutCString("triple:"); packet.PutCString(triple.getTriple().c_str()); packet.PutChar (';'); } } StringExtractorGDBRemote response; // Increase timeout as the first qfProcessInfo packet takes a long time // on Android. The value of 1min was arrived at empirically. GDBRemoteCommunication::ScopedTimeout timeout (*this, 60); if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success) { do { ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse (response, process_info)) break; process_infos.Append(process_info); response.GetStringRef().clear(); response.SetFilePos(0); } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false) == PacketResult::Success); } else { m_supports_qfProcessInfo = false; return 0; } } return process_infos.GetSize(); } bool GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name) { if (m_supports_qUserName) { char packet[32]; 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) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is // the hex encoded user name and should make up the entire packet. // If there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) return true; } } else { m_supports_qUserName = false; return false; } } return false; } bool GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name) { if (m_supports_qGroupName) { char packet[32]; 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) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is // the hex encoded group name and should make up the entire packet. // If there are any non-hex ASCII bytes, the length won't match below.. if (response.GetHexByteString (name) * 2 == response.GetStringRef().size()) return true; } } else { m_supports_qGroupName = false; return false; } } return false; } bool GDBRemoteCommunicationClient::SetNonStopMode (const bool enable) { // Form non-stop packet request char packet[32]; const int packet_len = ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable); assert(packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; // Send to target if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) if (response.IsOKResponse()) return true; // Failed or not supported return false; } static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size, uint32_t recv_size) { packet.Clear(); 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; } } } template T calculate_standard_deviation(const std::vector &v) { T sum = std::accumulate(std::begin(v), std::end(v), T(0)); T mean = sum / (T)v.size(); T accum = T(0); std::for_each (std::begin(v), std::end(v), [&](const T d) { T delta = d - mean; accum += delta * delta; }); T stdev = sqrt(accum / (v.size()-1)); return stdev; } void GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets, uint32_t max_send, uint32_t max_recv, bool json, Stream &strm) { uint32_t i; TimeValue start_time, end_time; uint64_t total_time_nsec; if (SendSpeedTestPacket (0, 0)) { StreamString packet; if (json) strm.Printf("{ \"packet_speeds\" : {\n \"num_packets\" : %u,\n \"results\" : [", num_packets); else strm.Printf("Testing sending %u packets of various sizes:\n", num_packets); strm.Flush(); uint32_t result_idx = 0; uint32_t send_size; std::vector packet_times; for (send_size = 0; send_size <= max_send; send_size ? send_size *= 2 : send_size = 4) { for (uint32_t recv_size = 0; recv_size <= max_recv; recv_size ? recv_size *= 2 : recv_size = 4) { MakeSpeedTestPacket (packet, send_size, recv_size); packet_times.clear(); // Test how long it takes to send 'num_packets' packets start_time = TimeValue::Now(); for (i=0; i(packet_times); if (json) { strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 ", \"standard_deviation_nsec\" : %9" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec, (uint64_t)standard_deviation); ++result_idx; } else { strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) in %" PRIu64 ".%9.9" PRIu64 " sec for %9.2f packets/sec (%10.6f ms per packet) with standard deviation of %10.6f ms\n", send_size, recv_size, total_time_nsec / TimeValue::NanoSecPerSec, total_time_nsec % TimeValue::NanoSecPerSec, packets_per_second, average_ms_per_packet, standard_deviation/(float)TimeValue::NanoSecPerMilliSec); } strm.Flush(); } } const uint64_t k_recv_amount = 4*1024*1024; // Receive amount in bytes const float k_recv_amount_mb = (float)k_recv_amount/(1024.0f*1024.0f); if (json) strm.Printf("\n ]\n },\n \"download_speed\" : {\n \"byte_size\" : %" PRIu64 ",\n \"results\" : [", k_recv_amount); else strm.Printf("Testing receiving %2.1fMB of data using varying receive packet sizes:\n", k_recv_amount_mb); strm.Flush(); send_size = 0; result_idx = 0; for (uint32_t recv_size = 32; recv_size <= max_recv; recv_size *= 2) { MakeSpeedTestPacket (packet, send_size, recv_size); // If we have a receive size, test how long it takes to receive 4MB of data if (recv_size > 0) { start_time = TimeValue::Now(); uint32_t bytes_read = 0; uint32_t packet_count = 0; while (bytes_read < k_recv_amount) { StringExtractorGDBRemote response; SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false); bytes_read += recv_size; ++packet_count; } end_time = TimeValue::Now(); total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970(); float mb_second = ((((float)k_recv_amount)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec) / (1024.0*1024.0); float packets_per_second = (((float)packet_count)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec; float total_ms = (float)total_time_nsec/(float)TimeValue::NanoSecPerMilliSec; float average_ms_per_packet = total_ms / packet_count; if (json) { strm.Printf ("%s\n {\"send_size\" : %6" PRIu32 ", \"recv_size\" : %6" PRIu32 ", \"total_time_nsec\" : %12" PRIu64 " }", result_idx > 0 ? "," : "", send_size, recv_size, total_time_nsec); ++result_idx; } else { strm.Printf ("qSpeedTest(send=%-7u, recv=%-7u) %6u packets needed to receive %2.1fMB in %" PRIu64 ".%9.9" PRIu64 " sec for %f MB/sec for %9.2f packets/sec (%10.6f ms per packet)\n", send_size, recv_size, packet_count, k_recv_amount_mb, total_time_nsec / TimeValue::NanoSecPerSec, total_time_nsec % TimeValue::NanoSecPerSec, mb_second, packets_per_second, average_ms_per_packet); } strm.Flush(); } } if (json) strm.Printf("\n ]\n }\n}\n"); else strm.EOL(); } } bool GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size) { 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; } } StringExtractorGDBRemote response; return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) == PacketResult::Success; } bool GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostname, lldb::pid_t &pid, uint16_t &port, std::string &socket_name) { pid = LLDB_INVALID_PROCESS_ID; port = 0; socket_name.clear(); StringExtractorGDBRemote response; StreamString stream; stream.PutCString("qLaunchGDBServer;"); std::string hostname; if (remote_accept_hostname && remote_accept_hostname[0]) hostname = remote_accept_hostname; else { if (HostInfo::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(); // give the process a few seconds to startup GDBRemoteCommunication::ScopedTimeout timeout (*this, 10); if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { std::string name; std::string value; StringExtractor extractor; while (response.GetNameColonValue(name, value)) { if (name.compare("port") == 0) port = StringConvert::ToUInt32(value.c_str(), 0, 0); else if (name.compare("pid") == 0) pid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); else if (name.compare("socket_name") == 0) { extractor.GetStringRef().swap(value); extractor.SetFilePos(0); extractor.GetHexByteString(value); socket_name = value; } } return true; } return false; } size_t GDBRemoteCommunicationClient::QueryGDBServer (std::vector>& connection_urls) { connection_urls.clear(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) return 0; StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); if (!data) return 0; StructuredData::Array* array = data->GetAsArray(); if (!array) return 0; for (size_t i = 0, count = array->GetSize(); i < count; ++i) { StructuredData::Dictionary* element = nullptr; if (!array->GetItemAtIndexAsDictionary(i, element)) continue; uint16_t port = 0; if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) port = port_osp->GetIntegerValue(0); std::string socket_name; if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) socket_name = socket_name_osp->GetStringValue(); if (port != 0 || !socket_name.empty()) connection_urls.emplace_back(port, socket_name); } return connection_urls.size(); } bool GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) { StreamString stream; stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) return true; } return false; } bool GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) { if (m_curr_tid == tid) return true; char packet[32]; int packet_len; if (tid == UINT64_MAX) packet_len = ::snprintf (packet, sizeof(packet), "Hg-1"); else 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) == PacketResult::Success) { if (response.IsOKResponse()) { m_curr_tid = tid; return true; } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hg packet. * The reply from '?' packet could be as simple as 'S05'. There is no packet which can * give us pid and/or tid. Assume pid=tid=1 in such cases. */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid = 1; return true; } } return false; } bool GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid) { if (m_curr_tid_run == tid) return true; char packet[32]; int packet_len; if (tid == UINT64_MAX) packet_len = ::snprintf (packet, sizeof(packet), "Hc-1"); else packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { m_curr_tid_run = tid; return true; } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for Hc packet. * The reply from '?' packet could be as simple as 'S05'. There is no packet which can * give us pid and/or tid. Assume pid=tid=1 in such cases. */ if (response.IsUnsupportedResponse() && IsConnected()) { m_curr_tid_run = 1; return true; } } return false; } bool GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response) { if (SendPacketAndWaitForResponse("?", 1, response, false) == PacketResult::Success) return response.IsNormalResponse(); return false; } bool GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response) { if (m_supports_qThreadStopInfo) { 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) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_qThreadStopInfo = false; else if (response.IsNormalResponse()) return true; else return false; } else { m_supports_qThreadStopInfo = false; } } return false; } uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, __FUNCTION__, insert ? "add" : "remove", addr); // 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), "%c%i,%" PRIx64 ",%x", insert ? 'Z' : 'z', type, addr, length); // Check we haven't overwritten the end of the packet buffer assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; // Make sure the response is either "OK", "EXX" where XX are two hex digits, or "" (unsupported) response.SetResponseValidatorToOKErrorNotSupported(); // 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; // Error while setting breakpoint, send back specific error if (response.IsErrorResponse()) return response.GetError(); // 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; case eStoppointInvalid: return UINT8_MAX; } } } // Signal generic failure return UINT8_MAX; } size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector &thread_ids, bool &sequence_mutex_unavailable) { Mutex::Locker locker; thread_ids.clear(); if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex")) { sequence_mutex_unavailable = false; StringExtractorGDBRemote response; 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') break; if (ch == 'm') { do { tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); if (tid != LLDB_INVALID_THREAD_ID) { thread_ids.push_back (tid); } ch = response.GetChar(); // Skip the command separator } while (ch == ','); // Make sure we got a comma separator } } /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for * qProcessInfo, qC and qfThreadInfo packets. The reply from '?' packet could * be as simple as 'S05'. There is no packet which can give us pid and/or tid. * Assume pid=tid=1 in such cases. */ if (response.IsUnsupportedResponse() && thread_ids.size() == 0 && IsConnected()) { thread_ids.push_back (1); } } else { #if defined (LLDB_CONFIGURATION_DEBUG) // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"); #else Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); if (log) log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'"); #endif sequence_mutex_unavailable = true; } return thread_ids.size(); } lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { if (!IsRunning()) { StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false) == PacketResult::Success) { if (response.IsNormalResponse()) return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); } } return LLDB_INVALID_ADDRESS; } lldb_private::Error GDBRemoteCommunicationClient::RunShellCommand(const char *command, // Shouldn't be NULL const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit 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 { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); stream.PutBytesAsRawHex8(command, strlen(command)); stream.PutChar(','); stream.PutHex32(timeout_sec); if (working_dir) { std::string path{working_dir.GetPath(false)}; stream.PutChar(','); stream.PutCStringAsRawHex8(path.c_str()); } const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return Error("malformed reply"); if (response.GetChar() != ',') return Error("malformed reply"); uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); if (exitcode == UINT32_MAX) return Error("unable to run remote process"); else if (status_ptr) *status_ptr = exitcode; if (response.GetChar() != ',') return Error("malformed reply"); uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); if (signo_ptr) *signo_ptr = signo; if (response.GetChar() != ',') return Error("malformed reply"); std::string output; response.GetEscapedBinaryData(output); if (command_output) command_output->assign(output); return Error(); } return Error("unable to send packet"); } Error GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, uint32_t file_permissions) { std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_mkdir:"); stream.PutHex32(file_permissions); stream.PutChar(','); stream.PutCStringAsRawHex8(path.c_str()); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) return Error("failed to send '%s' packet", packet); if (response.GetChar() != 'F') return Error("invalid response to '%s' packet", packet); return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } Error GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) { std::string path{file_spec.GetPath(false)}; lldb_private::StreamString stream; stream.PutCString("qPlatform_chmod:"); stream.PutHex32(file_permissions); stream.PutChar(','); stream.PutCStringAsRawHex8(path.c_str()); const char *packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) != PacketResult::Success) return Error("failed to send '%s' packet", packet); if (response.GetChar() != 'F') return Error("invalid response to '%s' packet", packet); return Error(response.GetU32(UINT32_MAX), eErrorTypePOSIX); } static uint64_t ParseHostIOPacketResponse (StringExtractorGDBRemote &response, uint64_t fail_result, Error &error) { response.SetFilePos(0); if (response.GetChar() != 'F') return fail_result; int32_t result = response.GetS32 (-2); if (result == -2) return fail_result; if (response.GetChar() == ',') { int result_errno = response.GetS32 (-2); if (result_errno != -2) error.SetError(result_errno, eErrorTypePOSIX); else error.SetError(-1, eErrorTypeGeneric); } else error.Clear(); return result; } lldb::user_id_t GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, uint32_t flags, mode_t mode, Error &error) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:open:"); if (path.empty()) return UINT64_MAX; stream.PutCStringAsRawHex8(path.c_str()); stream.PutChar(','); stream.PutHex32(flags); stream.PutChar(','); stream.PutHex32(mode); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, UINT64_MAX, error); } return UINT64_MAX; } bool GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, Error &error) { lldb_private::StreamString stream; stream.Printf("vFile:close:%i", (int)fd); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { return ParseHostIOPacketResponse (response, -1, error) == 0; } return false; } // Extension of host I/O packets to get the file size. lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:size:"); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return UINT64_MAX; uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); return retcode; } return UINT64_MAX; } Error GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) { std::string path{file_spec.GetPath(false)}; Error error; lldb_private::StreamString stream; stream.PutCString("vFile:mode:"); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); } else { const uint32_t mode = response.GetS32(-1); if (static_cast(mode) == -1) { if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); else error.SetErrorToGenericError(); } else error.SetErrorToGenericError(); } else { file_permissions = mode & (S_IRWXU|S_IRWXG|S_IRWXO); } } } else { error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); } return error; } uint64_t GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Error &error) { lldb_private::StreamString stream; stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return 0; uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); if (retcode == UINT32_MAX) return retcode; const char next = (response.Peek() ? *response.Peek() : 0); if (next == ',') return 0; if (next == ';') { response.GetChar(); // skip the semicolon std::string buffer; if (response.GetEscapedBinaryData(buffer)) { const uint64_t data_to_write = std::min(dst_len, buffer.size()); if (data_to_write > 0) memcpy(dst, &buffer[0], data_to_write); return data_to_write; } } } return 0; } uint64_t GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, uint64_t offset, const void* src, uint64_t src_len, Error &error) { lldb_private::StreamGDBRemote stream; stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); stream.PutEscapedBytes(src, src_len); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat("write file failed"); return 0; } uint64_t bytes_written = response.GetU64(UINT64_MAX); if (bytes_written == UINT64_MAX) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } return 0; } return bytes_written; } else { error.SetErrorString ("failed to send vFile:pwrite packet"); } return 0; } Error GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, const FileSpec &dst) { std::string src_path{src.GetPath(false)}, dst_path{dst.GetPath(false)}; Error error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:symlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here stream.PutCStringAsRawHex8(dst_path.c_str()); stream.PutChar(','); stream.PutCStringAsRawHex8(src_path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } } } else { // Should have returned with 'F[,]' error.SetErrorStringWithFormat("symlink failed"); } } else { error.SetErrorString ("failed to send vFile:symlink packet"); } return error; } Error GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { std::string path{file_spec.GetPath(false)}; Error error; lldb_private::StreamGDBRemote stream; stream.PutCString("vFile:unlink:"); // the unix symlink() command reverses its parameters where the dst if first, // so we follow suit here stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); if (result != 0) { error.SetErrorToGenericError(); if (response.GetChar() == ',') { int response_errno = response.GetS32(-1); if (response_errno > 0) error.SetError(response_errno, lldb::eErrorTypePOSIX); } } } else { // Should have returned with 'F[,]' error.SetErrorStringWithFormat("unlink failed"); } } else { error.SetErrorString ("failed to send vFile:unlink packet"); } return error; } // Extension of host I/O packets to get whether a file exists. bool GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:exists:"); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; if (response.GetChar() != ',') return false; bool retcode = (response.GetChar() != '0'); return retcode; } return false; } bool GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec, uint64_t &high, uint64_t &low) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:MD5:"); stream.PutCStringAsRawHex8(path.c_str()); const char* packet = stream.GetData(); int packet_len = stream.GetSize(); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, packet_len, response, false) == PacketResult::Success) { if (response.GetChar() != 'F') return false; if (response.GetChar() != ',') return false; if (response.Peek() && *response.Peek() == 'x') return false; low = response.GetHexMaxU64(false, UINT64_MAX); high = response.GetHexMaxU64(false, UINT64_MAX); return true; } return false; } bool GDBRemoteCommunicationClient::AvoidGPackets (ProcessGDBRemote *process) { // Some targets have issues with g/G packets and we need to avoid using them if (m_avoid_g_packets == eLazyBoolCalculate) { if (process) { m_avoid_g_packets = eLazyBoolNo; const ArchSpec &arch = process->GetTarget().GetArchitecture(); if (arch.IsValid() && arch.GetTriple().getVendor() == llvm::Triple::Apple && arch.GetTriple().getOS() == llvm::Triple::IOS && arch.GetTriple().getArch() == llvm::Triple::aarch64) { m_avoid_g_packets = eLazyBoolYes; uint32_t gdb_server_version = GetGDBServerProgramVersion(); if (gdb_server_version != 0) { const char *gdb_server_name = GetGDBServerProgramName(); if (gdb_server_name && strcmp(gdb_server_name, "debugserver") == 0) { if (gdb_server_version >= 310) m_avoid_g_packets = eLazyBoolNo; } } } } } return m_avoid_g_packets == eLazyBoolYes; } bool GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, uint32_t reg, StringExtractorGDBRemote &response) { Mutex::Locker locker; if (GetSequenceMutex (locker, "Didn't get sequence mutex for p packet.")) { const bool thread_suffix_supported = GetThreadSuffixSupported(); if (thread_suffix_supported || SetCurrentThread(tid)) { char packet[64]; int packet_len = 0; if (thread_suffix_supported) packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, tid); else packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg); assert (packet_len < ((int)sizeof(packet) - 1)); return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; } bool GDBRemoteCommunicationClient::ReadAllRegisters (lldb::tid_t tid, StringExtractorGDBRemote &response) { Mutex::Locker locker; if (GetSequenceMutex (locker, "Didn't get sequence mutex for g packet.")) { const bool thread_suffix_supported = GetThreadSuffixSupported(); if (thread_suffix_supported || SetCurrentThread(tid)) { char packet[64]; int packet_len = 0; // Get all registers in one packet if (thread_suffix_supported) packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", tid); else packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); return SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success; } } return false; } bool GDBRemoteCommunicationClient::SaveRegisterState (lldb::tid_t tid, uint32_t &save_id) { save_id = 0; // Set to invalid save ID if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; m_supports_QSaveRegisterState = eLazyBoolYes; Mutex::Locker locker; if (GetSequenceMutex (locker, "Didn't get sequence mutex for QSaveRegisterState.")) { const bool thread_suffix_supported = GetThreadSuffixSupported(); if (thread_suffix_supported || SetCurrentThread(tid)) { char packet[256]; if (thread_suffix_supported) ::snprintf (packet, sizeof(packet), "QSaveRegisterState;thread:%4.4" PRIx64 ";", tid); else ::snprintf(packet, sizeof(packet), "QSaveRegisterState"); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { // This packet isn't supported, don't try calling it again m_supports_QSaveRegisterState = eLazyBoolNo; } const uint32_t response_save_id = response.GetU32(0); if (response_save_id != 0) { save_id = response_save_id; return true; } } } } return false; } bool GDBRemoteCommunicationClient::RestoreRegisterState (lldb::tid_t tid, uint32_t save_id) { // We use the "m_supports_QSaveRegisterState" variable here because the // QSaveRegisterState and QRestoreRegisterState packets must both be supported in // order to be useful if (m_supports_QSaveRegisterState == eLazyBoolNo) return false; Mutex::Locker locker; if (GetSequenceMutex (locker, "Didn't get sequence mutex for QRestoreRegisterState.")) { const bool thread_suffix_supported = GetThreadSuffixSupported(); if (thread_suffix_supported || SetCurrentThread(tid)) { char packet[256]; if (thread_suffix_supported) ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u;thread:%4.4" PRIx64 ";", save_id, tid); else ::snprintf (packet, sizeof(packet), "QRestoreRegisterState:%u" PRIx64 ";", save_id); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(packet, response, false) == PacketResult::Success) { if (response.IsOKResponse()) { return true; } else if (response.IsUnsupportedResponse()) { // This packet isn't supported, don't try calling this packet or // QSaveRegisterState again... m_supports_QSaveRegisterState = eLazyBoolNo; } } } } return false; } bool GDBRemoteCommunicationClient::GetModuleInfo (const FileSpec& module_file_spec, const lldb_private::ArchSpec& arch_spec, ModuleSpec &module_spec) { if (!m_supports_qModuleInfo) return false; std::string module_path = module_file_spec.GetPath (false); if (module_path.empty ()) return false; StreamString packet; packet.PutCString("qModuleInfo:"); packet.PutCStringAsRawHex8(module_path.c_str()); packet.PutCString(";"); const auto& triple = arch_spec.GetTriple().getTriple(); packet.PutCStringAsRawHex8(triple.c_str()); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) != PacketResult::Success) return false; if (response.IsErrorResponse ()) return false; if (response.IsUnsupportedResponse ()) { m_supports_qModuleInfo = false; return false; } std::string name; std::string value; bool success; StringExtractor extractor; module_spec.Clear (); module_spec.GetFileSpec () = module_file_spec; while (response.GetNameColonValue (name, value)) { if (name == "uuid" || name == "md5") { extractor.GetStringRef ().swap (value); extractor.SetFilePos (0); extractor.GetHexByteString (value); module_spec.GetUUID().SetFromCString (value.c_str(), value.size() / 2); } else if (name == "triple") { extractor.GetStringRef ().swap (value); extractor.SetFilePos (0); extractor.GetHexByteString (value); module_spec.GetArchitecture().SetTriple (value.c_str ()); } else if (name == "file_offset") { const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); if (success) module_spec.SetObjectOffset (ival); } else if (name == "file_size") { const auto ival = StringConvert::ToUInt64 (value.c_str (), 0, 16, &success); if (success) module_spec.SetObjectSize (ival); } else if (name == "file_path") { extractor.GetStringRef ().swap (value); extractor.SetFilePos (0); extractor.GetHexByteString (value); module_spec.GetFileSpec() = FileSpec(value.c_str(), false, arch_spec); } } return true; } // query the target remote for extended information using the qXfer packet // // example: object='features', annex='target.xml', out= // return: 'true' on success // 'false' on failure (err set) bool GDBRemoteCommunicationClient::ReadExtFeature (const lldb_private::ConstString object, const lldb_private::ConstString annex, std::string & out, lldb_private::Error & err) { std::stringstream output; StringExtractorGDBRemote chunk; uint64_t size = GetRemoteMaxPacketSize(); if (size == 0) size = 0x1000; size = size - 1; // Leave space for the 'm' or 'l' character in the response int offset = 0; bool active = true; // loop until all data has been read while ( active ) { // send query extended feature packet std::stringstream packet; packet << "qXfer:" << object.AsCString("") << ":read:" << annex.AsCString("") << ":" << std::hex << offset << "," << std::hex << size; GDBRemoteCommunication::PacketResult res = SendPacketAndWaitForResponse( packet.str().c_str(), chunk, false ); if ( res != GDBRemoteCommunication::PacketResult::Success ) { err.SetErrorString( "Error sending $qXfer packet" ); return false; } const std::string & str = chunk.GetStringRef( ); if ( str.length() == 0 ) { // should have some data in chunk err.SetErrorString( "Empty response from $qXfer packet" ); return false; } // check packet code switch ( str[0] ) { // last chunk case ( 'l' ): active = false; LLVM_FALLTHROUGH; // more chunks case ( 'm' ) : if ( str.length() > 1 ) output << &str[1]; offset += size; break; // unknown chunk default: err.SetErrorString( "Invalid continuation code from $qXfer packet" ); return false; } } out = output.str( ); err.Success( ); return true; } // Notify the target that gdb is prepared to serve symbol lookup requests. // packet: "qSymbol::" // reply: // OK The target does not need to look up any (more) symbols. // qSymbol: The target requests the value of symbol sym_name (hex encoded). // LLDB may provide the value by sending another qSymbol packet // in the form of"qSymbol::". // // Three examples: // // lldb sends: qSymbol:: // lldb receives: OK // Remote gdb stub does not need to know the addresses of any symbols, lldb does not // need to ask again in this session. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol::64697370617463685f71756575655f6f666673657473 // lldb receives: OK // Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb does not know // the address at this time. lldb needs to send qSymbol:: again when it has more // solibs loaded. // // lldb sends: qSymbol:: // lldb receives: qSymbol:64697370617463685f71756575655f6f666673657473 // lldb sends: qSymbol:2bc97554:64697370617463685f71756575655f6f666673657473 // lldb receives: OK // Remote gdb stub asks for address of 'dispatch_queue_offsets'. lldb says that it // is at address 0x2bc97554. Remote gdb stub sends 'OK' indicating that it does not // need any more symbols. lldb does not need to ask again in this session. void GDBRemoteCommunicationClient::ServeSymbolLookups(lldb_private::Process *process) { // Set to true once we've resolved a symbol to an address for the remote stub. // If we get an 'OK' response after this, the remote stub doesn't need any more // symbols and we can stop asking. bool symbol_response_provided = false; // Is this the inital qSymbol:: packet? bool first_qsymbol_query = true; if (m_supports_qSymbol && m_qSymbol_requests_done == false) { Mutex::Locker locker; if (GetSequenceMutex(locker, "GDBRemoteCommunicationClient::ServeSymbolLookups() failed due to not getting the sequence mutex")) { StreamString packet; packet.PutCString ("qSymbol::"); StringExtractorGDBRemote response; while (SendPacketAndWaitForResponseNoLock(packet.GetData(), packet.GetSize(), response) == PacketResult::Success) { if (response.IsOKResponse()) { if (symbol_response_provided || first_qsymbol_query) { m_qSymbol_requests_done = true; } // We are done serving symbols requests return; } first_qsymbol_query = false; if (response.IsUnsupportedResponse()) { // qSymbol is not supported by the current GDB server we are connected to m_supports_qSymbol = false; return; } else { llvm::StringRef response_str(response.GetStringRef()); if (response_str.startswith("qSymbol:")) { response.SetFilePos(strlen("qSymbol:")); std::string symbol_name; if (response.GetHexByteString(symbol_name)) { if (symbol_name.empty()) return; addr_t symbol_load_addr = LLDB_INVALID_ADDRESS; lldb_private::SymbolContextList sc_list; if (process->GetTarget().GetImages().FindSymbolsWithNameAndType(ConstString(symbol_name), eSymbolTypeAny, sc_list)) { const size_t num_scs = sc_list.GetSize(); for (size_t sc_idx=0; sc_idxGetType()) { case eSymbolTypeInvalid: case eSymbolTypeAbsolute: case eSymbolTypeUndefined: case eSymbolTypeSourceFile: case eSymbolTypeHeaderFile: case eSymbolTypeObjectFile: case eSymbolTypeCommonBlock: case eSymbolTypeBlock: case eSymbolTypeLocal: case eSymbolTypeParam: case eSymbolTypeVariable: case eSymbolTypeVariableType: case eSymbolTypeLineEntry: case eSymbolTypeLineHeader: case eSymbolTypeScopeBegin: case eSymbolTypeScopeEnd: case eSymbolTypeAdditional: case eSymbolTypeCompiler: case eSymbolTypeInstrumentation: case eSymbolTypeTrampoline: break; case eSymbolTypeCode: case eSymbolTypeResolver: case eSymbolTypeData: case eSymbolTypeRuntime: case eSymbolTypeException: case eSymbolTypeObjCClass: case eSymbolTypeObjCMetaClass: case eSymbolTypeObjCIVar: case eSymbolTypeReExported: symbol_load_addr = sc.symbol->GetLoadAddress(&process->GetTarget()); break; } } } } } // This is the normal path where our symbol lookup was successful and we want // to send a packet with the new symbol value and see if another lookup needs to be // done. // Change "packet" to contain the requested symbol value and name packet.Clear(); packet.PutCString("qSymbol:"); if (symbol_load_addr != LLDB_INVALID_ADDRESS) { packet.Printf("%" PRIx64, symbol_load_addr); symbol_response_provided = true; } else { symbol_response_provided = false; } packet.PutCString(":"); packet.PutBytesAsRawHex8(symbol_name.data(), symbol_name.size()); continue; // go back to the while loop and send "packet" and wait for another response } } } } // If we make it here, the symbol request packet response wasn't valid or // our symbol lookup failed so we must abort return; } } } diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 7f876fb393d9..26a2e697e854 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1,1256 +1,1256 @@ //===-- GDBRemoteCommunicationServerCommon.cpp ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "GDBRemoteCommunicationServerCommon.h" #include // C Includes // C++ Includes #include #include // Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "lldb/Core/Log.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Config.h" #include "lldb/Host/Endian.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Interpreter/Args.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" // Project includes #include "ProcessGDBRemoteLog.h" #include "Utility/StringExtractorGDBRemote.h" #ifdef __ANDROID__ #include "lldb/Host/android/HostInfoAndroid.h" #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; #ifdef __ANDROID__ const static uint32_t g_default_packet_timeout_sec = 20; // seconds #else const static uint32_t g_default_packet_timeout_sec = 0; // not specified #endif //---------------------------------------------------------------------- // GDBRemoteCommunicationServerCommon constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServerCommon::GDBRemoteCommunicationServerCommon(const char *comm_name, const char *listener_name) : GDBRemoteCommunicationServer (comm_name, listener_name), m_process_launch_info (), m_process_launch_error (), m_proc_infos (), m_proc_infos_index (0), m_thread_suffix_supported (false), m_list_threads_in_stop_reply (false) { RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_A, &GDBRemoteCommunicationServerCommon::Handle_A); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironment, &GDBRemoteCommunicationServerCommon::Handle_QEnvironment); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QEnvironmentHexEncoded, &GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfProcessInfo, &GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGroupName, &GDBRemoteCommunicationServerCommon::Handle_qGroupName); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qHostInfo, &GDBRemoteCommunicationServerCommon::Handle_qHostInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QLaunchArch, &GDBRemoteCommunicationServerCommon::Handle_QLaunchArch); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess, &GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, &GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qEcho, &GDBRemoteCommunicationServerCommon::Handle_qEcho); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qModuleInfo, &GDBRemoteCommunicationServerCommon::Handle_qModuleInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_chmod, &GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_mkdir, &GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qPlatform_shell, &GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID, &GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDetachOnError, &GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDERR, &GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDIN, &GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT, &GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSpeedTest, &GDBRemoteCommunicationServerCommon::Handle_qSpeedTest); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsProcessInfo, &GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode, &GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qSupported, &GDBRemoteCommunicationServerCommon::Handle_qSupported); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, &GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qUserName, &GDBRemoteCommunicationServerCommon::Handle_qUserName); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_close, &GDBRemoteCommunicationServerCommon::Handle_vFile_Close); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_exists, &GDBRemoteCommunicationServerCommon::Handle_vFile_Exists); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_md5, &GDBRemoteCommunicationServerCommon::Handle_vFile_MD5); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_mode, &GDBRemoteCommunicationServerCommon::Handle_vFile_Mode); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_open, &GDBRemoteCommunicationServerCommon::Handle_vFile_Open); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pread, &GDBRemoteCommunicationServerCommon::Handle_vFile_pRead); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_pwrite, &GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_size, &GDBRemoteCommunicationServerCommon::Handle_vFile_Size); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_stat, &GDBRemoteCommunicationServerCommon::Handle_vFile_Stat); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_symlink, &GDBRemoteCommunicationServerCommon::Handle_vFile_symlink); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vFile_unlink, &GDBRemoteCommunicationServerCommon::Handle_vFile_unlink); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- GDBRemoteCommunicationServerCommon::~GDBRemoteCommunicationServerCommon() { } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qHostInfo (StringExtractorGDBRemote &packet) { StreamString response; // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00 ArchSpec host_arch(HostInfo::GetArchitecture()); const llvm::Triple &host_triple = host_arch.GetTriple(); response.PutCString("triple:"); 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(";"); } // Only send out MachO info when lldb-platform/llgs is running on a MachO host. #if defined(__APPLE__) uint32_t cpu = host_arch.GetMachOCPUType(); uint32_t sub = host_arch.GetMachOCPUSubType(); if (cpu != LLDB_INVALID_CPUTYPE) response.Printf ("cputype:%u;", cpu); if (sub != LLDB_INVALID_CPUTYPE) response.Printf ("cpusubtype:%u;", sub); if (cpu == ArchSpec::kCore_arm_any) response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. else response.Printf("watchpoint_exceptions_received:after;"); #else if (host_arch.GetMachine() == llvm::Triple::aarch64 || host_arch.GetMachine() == llvm::Triple::aarch64_be || host_arch.GetMachine() == llvm::Triple::arm || host_arch.GetMachine() == llvm::Triple::armeb || host_arch.GetMachine() == llvm::Triple::mips64 || host_arch.GetMachine() == llvm::Triple::mips64el || host_arch.GetMachine() == llvm::Triple::mips || host_arch.GetMachine() == llvm::Triple::mipsel) response.Printf("watchpoint_exceptions_received:before;"); else response.Printf("watchpoint_exceptions_received:after;"); #endif switch (endian::InlHostByteOrder()) { case eByteOrderBig: response.PutCString ("endian:big;"); break; case eByteOrderLittle: response.PutCString ("endian:little;"); break; case eByteOrderPDP: response.PutCString ("endian:pdp;"); break; default: response.PutCString ("endian:unknown;"); break; } uint32_t major = UINT32_MAX; uint32_t minor = UINT32_MAX; uint32_t update = UINT32_MAX; if (HostInfo::GetOSVersion(major, minor, update)) { if (major != UINT32_MAX) { response.Printf("os_version:%u", major); if (minor != UINT32_MAX) { response.Printf(".%u", minor); if (update != UINT32_MAX) response.Printf(".%u", update); } response.PutChar(';'); } } std::string s; if (HostInfo::GetOSBuildString(s)) { response.PutCString ("os_build:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } if (HostInfo::GetOSKernelDescription(s)) { response.PutCString ("os_kernel:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } #if defined(__APPLE__) #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) // For iOS devices, we are connected through a USB Mux so we never pretend // to actually have a hostname as far as the remote lldb that is connecting // to this lldb-platform is concerned response.PutCString ("hostname:"); response.PutCStringAsRawHex8("127.0.0.1"); response.PutChar(';'); #else // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } #endif // #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #else // #if defined(__APPLE__) if (HostInfo::GetHostname(s)) { response.PutCString ("hostname:"); response.PutCStringAsRawHex8(s.c_str()); response.PutChar(';'); } #endif // #if defined(__APPLE__) if (g_default_packet_timeout_sec > 0) response.Printf ("default_packet_timeout:%u;", g_default_packet_timeout_sec); return SendPacketNoLock (response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet) { // Packet format: "qProcessInfoPID:%i" where %i is the pid packet.SetFilePos (::strlen ("qProcessInfoPID:")); lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID); if (pid != LLDB_INVALID_PROCESS_ID) { ProcessInstanceInfo proc_info; if (Host::GetProcessInfo (pid, proc_info)) { StreamString response; CreateProcessInfoResponse (proc_info, response); return SendPacketNoLock (response.GetData(), response.GetSize()); } } return SendErrorResponse (1); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo (StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; m_proc_infos.Clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen ("qfProcessInfo")); if (packet.GetChar() == ':') { std::string key; std::string value; while (packet.GetNameColonValue(key, value)) { bool success = true; if (key.compare("name") == 0) { StringExtractor extractor; extractor.GetStringRef().swap(value); extractor.GetHexByteString (value); match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false); } else if (key.compare("name_match") == 0) { if (value.compare("equals") == 0) { match_info.SetNameMatchType (eNameMatchEquals); } else if (value.compare("starts_with") == 0) { match_info.SetNameMatchType (eNameMatchStartsWith); } else if (value.compare("ends_with") == 0) { match_info.SetNameMatchType (eNameMatchEndsWith); } else if (value.compare("contains") == 0) { match_info.SetNameMatchType (eNameMatchContains); } else if (value.compare("regex") == 0) { match_info.SetNameMatchType (eNameMatchRegularExpression); } else { success = false; } } else if (key.compare("pid") == 0) { match_info.GetProcessInfo().SetProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("parent_pid") == 0) { match_info.GetProcessInfo().SetParentProcessID (StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success)); } else if (key.compare("uid") == 0) { match_info.GetProcessInfo().SetUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("gid") == 0) { match_info.GetProcessInfo().SetGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("euid") == 0) { match_info.GetProcessInfo().SetEffectiveUserID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("egid") == 0) { match_info.GetProcessInfo().SetEffectiveGroupID (StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0, &success)); } else if (key.compare("all_users") == 0) { match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success)); } else if (key.compare("triple") == 0) { match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL); } else { success = false; } if (!success) return SendErrorResponse (2); } } if (Host::FindProcesses (match_info, m_proc_infos)) { // We found something, return the first item by calling the get // subsequent process info packet handler... return Handle_qsProcessInfo (packet); } return SendErrorResponse (3); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo (StringExtractorGDBRemote &packet) { if (m_proc_infos_index < m_proc_infos.GetSize()) { StreamString response; CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); ++m_proc_infos_index; return SendPacketNoLock (response.GetData(), response.GetSize()); } return SendErrorResponse (4); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qUserName (StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf("GDBRemoteCommunicationServerCommon::%s begin", __FUNCTION__); // Packet format: "qUserName:%i" where %i is the uid packet.SetFilePos(::strlen ("qUserName:")); uint32_t uid = packet.GetU32 (UINT32_MAX); if (uid != UINT32_MAX) { std::string name; if (HostInfo::LookupUserName(uid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } if (log) log->Printf("GDBRemoteCommunicationServerCommon::%s end", __FUNCTION__); #endif return SendErrorResponse (5); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qGroupName (StringExtractorGDBRemote &packet) { #if !defined(LLDB_DISABLE_POSIX) // Packet format: "qGroupName:%i" where %i is the gid packet.SetFilePos(::strlen ("qGroupName:")); uint32_t gid = packet.GetU32 (UINT32_MAX); if (gid != UINT32_MAX) { std::string name; if (HostInfo::LookupGroupName(gid, name)) { StreamString response; response.PutCStringAsRawHex8 (name.c_str()); return SendPacketNoLock (response.GetData(), response.GetSize()); } } #endif return SendErrorResponse (6); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qSpeedTest (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qSpeedTest:")); std::string key; std::string value; bool success = packet.GetNameColonValue(key, value); if (success && key.compare("response_size") == 0) { uint32_t response_size = StringConvert::ToUInt32(value.c_str(), 0, 0, &success); if (success) { if (response_size == 0) return SendOKResponse(); StreamString response; uint32_t bytes_left = response_size; response.PutCString("data:"); while (bytes_left > 0) { if (bytes_left >= 26) { response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left -= 26; } else { response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); bytes_left = 0; } } return SendPacketNoLock (response.GetData(), response.GetSize()); } } return SendErrorResponse (7); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Open (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:open:")); std::string path; packet.GetHexByteStringTerminatedBy(path,','); if (!path.empty()) { if (packet.GetChar() == ',') { uint32_t flags = File::ConvertOpenOptionsForPOSIXOpen( packet.GetHexMaxU32(false, 0)); if (packet.GetChar() == ',') { mode_t mode = packet.GetHexMaxU32(false, 0600); Error error; const FileSpec path_spec{path, true}; int fd = ::open(path_spec.GetCString(), flags, mode); const int save_errno = fd == -1 ? errno : 0; StreamString response; response.PutChar('F'); response.Printf("%i", fd); if (save_errno) response.Printf(",%i", save_errno); return SendPacketNoLock(response.GetData(), response.GetSize()); } } } return SendErrorResponse(18); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Close (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:close:")); int fd = packet.GetS32(-1); Error error; int err = -1; int save_errno = 0; if (fd >= 0) { err = close(fd); save_errno = err == -1 ? errno : 0; } else { save_errno = EINVAL; } StreamString response; response.PutChar('F'); response.Printf("%i", err); if (save_errno) response.Printf(",%i", save_errno); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_pRead (StringExtractorGDBRemote &packet) { #ifdef _WIN32 // Not implemented on Windows return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pRead() unimplemented"); #else StreamGDBRemote response; packet.SetFilePos(::strlen("vFile:pread:")); int fd = packet.GetS32(-1); if (packet.GetChar() == ',') { uint64_t count = packet.GetU64(UINT64_MAX); if (packet.GetChar() == ',') { uint64_t offset = packet.GetU64(UINT32_MAX); if (count == UINT64_MAX) { response.Printf("F-1:%i", EINVAL); return SendPacketNoLock(response.GetData(), response.GetSize()); } std::string buffer(count, 0); const ssize_t bytes_read = ::pread (fd, &buffer[0], buffer.size(), offset); const int save_errno = bytes_read == -1 ? errno : 0; response.PutChar('F'); response.Printf("%zi", bytes_read); if (save_errno) response.Printf(",%i", save_errno); else { response.PutChar(';'); response.PutEscapedBytes(&buffer[0], bytes_read); } return SendPacketNoLock(response.GetData(), response.GetSize()); } } return SendErrorResponse(21); #endif } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite (StringExtractorGDBRemote &packet) { #ifdef _WIN32 return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_pWrite() unimplemented"); #else packet.SetFilePos(::strlen("vFile:pwrite:")); StreamGDBRemote response; response.PutChar('F'); int fd = packet.GetU32(UINT32_MAX); if (packet.GetChar() == ',') { off_t offset = packet.GetU64(UINT32_MAX); if (packet.GetChar() == ',') { std::string buffer; if (packet.GetEscapedBinaryData(buffer)) { const ssize_t bytes_written = ::pwrite (fd, buffer.data(), buffer.size(), offset); const int save_errno = bytes_written == -1 ? errno : 0; response.Printf("%zi", bytes_written); if (save_errno) response.Printf(",%i", save_errno); } else { response.Printf ("-1,%i", EINVAL); } return SendPacketNoLock(response.GetData(), response.GetSize()); } } return SendErrorResponse(27); #endif } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Size (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:size:")); std::string path; packet.GetHexByteString(path); if (!path.empty()) { lldb::user_id_t retcode = FileSystem::GetFileSize(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutHex64(retcode); if (retcode == UINT64_MAX) { response.PutChar(','); response.PutHex64(retcode); // TODO: replace with Host::GetSyswideErrorCode() } return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(22); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Mode (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:mode:")); std::string path; packet.GetHexByteString(path); if (!path.empty()) { Error error; const uint32_t mode = File::GetPermissions(FileSpec{path, true}, error); StreamString response; response.Printf("F%u", mode); if (mode == 0 || error.Fail()) response.Printf(",%i", (int)error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(23); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Exists (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:exists:")); std::string path; packet.GetHexByteString(path); if (!path.empty()) { bool retcode = FileSystem::GetFileExists(FileSpec(path.c_str(), false)); StreamString response; response.PutChar('F'); response.PutChar(','); if (retcode) response.PutChar('1'); else response.PutChar('0'); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(24); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_symlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:symlink:")); std::string dst, src; packet.GetHexByteStringTerminatedBy(dst, ','); packet.GetChar(); // Skip ',' char packet.GetHexByteString(src); Error error = FileSystem::Symlink(FileSpec{src, true}, FileSpec{dst, false}); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_unlink (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:unlink:")); std::string path; packet.GetHexByteString(path); Error error = FileSystem::Unlink(FileSpec{path, true}); StreamString response; response.Printf("F%u,%u", error.GetError(), error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qPlatform_shell (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_shell:")); std::string path; std::string working_dir; packet.GetHexByteStringTerminatedBy(path,','); if (!path.empty()) { if (packet.GetChar() == ',') { // FIXME: add timeout to qPlatform_shell packet // uint32_t timeout = packet.GetHexMaxU32(false, 32); uint32_t timeout = 10; if (packet.GetChar() == ',') packet.GetHexByteString(working_dir); int status, signo; std::string output; Error err = Host::RunShellCommand(path.c_str(), FileSpec{working_dir, true}, &status, &signo, &output, timeout); StreamGDBRemote response; if (err.Fail()) { response.PutCString("F,"); response.PutHex32(UINT32_MAX); } else { response.PutCString("F,"); response.PutHex32(status); response.PutChar(','); response.PutHex32(signo); response.PutChar(','); response.PutEscapedBytes(output.c_str(), output.size()); } return SendPacketNoLock(response.GetData(), response.GetSize()); } } return SendErrorResponse(24); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_Stat (StringExtractorGDBRemote &packet) { return SendUnimplementedResponse("GDBRemoteCommunicationServerCommon::Handle_vFile_Stat() unimplemented"); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("vFile:MD5:")); std::string path; packet.GetHexByteString(path); if (!path.empty()) { uint64_t a,b; StreamGDBRemote response; if (!FileSystem::CalculateMD5(FileSpec(path.c_str(), false), a, b)) { response.PutCString("F,"); response.PutCString("x"); } else { response.PutCString("F,"); response.PutHex64(a); response.PutHex64(b); } return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(25); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qPlatform_mkdir (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_mkdir:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); if (packet.GetChar() == ',') { std::string path; packet.GetHexByteString(path); Error error = FileSystem::MakeDirectory(FileSpec{path, false}, mode); StreamGDBRemote response; response.Printf("F%u", error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(20); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qPlatform_chmod (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("qPlatform_chmod:")); mode_t mode = packet.GetHexMaxU32(false, UINT32_MAX); if (packet.GetChar() == ',') { std::string path; packet.GetHexByteString(path); Error error = FileSystem::SetFilePermissions(FileSpec{path, true}, mode); StreamGDBRemote response; response.Printf("F%u", error.GetError()); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(19); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qSupported (StringExtractorGDBRemote &packet) { StreamGDBRemote response; // Features common to lldb-platform and llgs. uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less response.Printf ("PacketSize=%x", max_packet_size); response.PutCString (";QStartNoAckMode+"); response.PutCString (";QThreadSuffixSupported+"); response.PutCString (";QListThreadsInStopReply+"); response.PutCString (";qEcho+"); #if defined(__linux__) response.PutCString (";qXfer:auxv:read+"); #endif return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QThreadSuffixSupported (StringExtractorGDBRemote &packet) { m_thread_suffix_supported = true; return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QListThreadsInStopReply (StringExtractorGDBRemote &packet) { m_list_threads_in_stop_reply = true; return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QSetDetachOnError (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetDetachOnError:")); if (packet.GetU32(0)) m_process_launch_info.GetFlags().Set (eLaunchFlagDetachOnError); else m_process_launch_info.GetFlags().Clear (eLaunchFlagDetachOnError); return SendOKResponse (); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet) { // Send response first before changing m_send_acks to we ack this packet PacketResult packet_result = SendOKResponse (); m_send_acks = false; return packet_result; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDIN:")); FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = false; const bool write = true; if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } return SendErrorResponse (15); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDOUT:")); FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; const bool write = false; if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } return SendErrorResponse (16); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetSTDERR:")); FileAction file_action; std::string path; packet.GetHexByteString(path); const bool read = true; const bool write = false; if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); return SendOKResponse (); } return SendErrorResponse (17); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet) { if (m_process_launch_error.Success()) return SendOKResponse(); StreamString response; response.PutChar('E'); response.PutCString(m_process_launch_error.AsCString("")); return SendPacketNoLock (response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QEnvironment (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QEnvironment:")); const uint32_t bytes_left = packet.GetBytesLeft(); if (bytes_left > 0) { m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek()); return SendOKResponse (); } return SendErrorResponse (12); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen("QEnvironmentHexEncoded:")); const uint32_t bytes_left = packet.GetBytesLeft(); if (bytes_left > 0) { std::string str; packet.GetHexByteString(str); m_process_launch_info.GetEnvironmentEntries().AppendArgument(str.c_str()); return SendOKResponse(); } return SendErrorResponse(12); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_QLaunchArch (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QLaunchArch:")); const uint32_t bytes_left = packet.GetBytesLeft(); if (bytes_left > 0) { const char* arch_triple = packet.Peek(); ArchSpec arch_spec(arch_triple,NULL); m_process_launch_info.SetArchitecture(arch_spec); return SendOKResponse(); } return SendErrorResponse(13); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_A (StringExtractorGDBRemote &packet) { // The 'A' packet is the most over designed packet ever here with // redundant argument indexes, redundant argument lengths and needed hex // encoded argument string values. Really all that is needed is a comma // separated hex encoded argument value list, but we will stay true to the // documented version of the 'A' packet here... Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); int actual_arg_index = 0; packet.SetFilePos(1); // Skip the 'A' bool success = true; while (success && packet.GetBytesLeft() > 0) { // Decode the decimal argument string length. This length is the // number of hex nibbles in the argument string value. const uint32_t arg_len = packet.GetU32(UINT32_MAX); if (arg_len == UINT32_MAX) success = false; else { // Make sure the argument hex string length is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument index. We ignore this really because // who would really send down the arguments in a random order??? const uint32_t arg_idx = packet.GetU32(UINT32_MAX); if (arg_idx == UINT32_MAX) success = false; else { // Make sure the argument index is followed by a comma if (packet.GetChar() != ',') success = false; else { // Decode the argument string value from hex bytes // back into a UTF8 string and make sure the length // matches the one supplied in the packet std::string arg; if (packet.GetHexByteStringFixedLength(arg, arg_len) != (arg_len / 2)) success = false; else { // If there are any bytes left if (packet.GetBytesLeft()) { if (packet.GetChar() != ',') success = false; } if (success) { if (arg_idx == 0) m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false); m_process_launch_info.GetArguments().AppendArgument(arg.c_str()); if (log) log->Printf ("LLGSPacketHandler::%s added arg %d: \"%s\"", __FUNCTION__, actual_arg_index, arg.c_str ()); ++actual_arg_index; } } } } } } } if (success) { m_process_launch_error = LaunchProcess (); if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { return SendOKResponse (); } else { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf("LLGSPacketHandler::%s failed to launch exe: %s", __FUNCTION__, m_process_launch_error.AsCString()); } } return SendErrorResponse (8); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qEcho (StringExtractorGDBRemote &packet) { // Just echo back the exact same packet for qEcho... return SendPacketNoLock(packet.GetStringRef().c_str(), packet.GetStringRef().size()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qModuleInfo (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qModuleInfo:")); std::string module_path; packet.GetHexByteStringTerminatedBy(module_path, ';'); if (module_path.empty()) return SendErrorResponse (1); if (packet.GetChar() != ';') return SendErrorResponse (2); std::string triple; packet.GetHexByteString(triple); ArchSpec arch(triple.c_str()); const FileSpec req_module_path_spec(module_path.c_str(), true); const FileSpec module_path_spec = FindModuleFile(req_module_path_spec.GetPath(), arch); const ModuleSpec module_spec(module_path_spec, arch); ModuleSpecList module_specs; if (!ObjectFile::GetModuleSpecifications(module_path_spec, 0, 0, module_specs)) return SendErrorResponse (3); ModuleSpec matched_module_spec; if (!module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) return SendErrorResponse (4); const auto file_offset = matched_module_spec.GetObjectOffset(); const auto file_size = matched_module_spec.GetObjectSize(); const auto uuid_str = matched_module_spec.GetUUID().GetAsString(""); StreamGDBRemote response; if (uuid_str.empty()) { std::string md5_hash; if (!FileSystem::CalculateMD5AsString(matched_module_spec.GetFileSpec(), file_offset, file_size, md5_hash)) return SendErrorResponse (5); response.PutCString ("md5:"); response.PutCStringAsRawHex8(md5_hash.c_str()); } else{ response.PutCString ("uuid:"); response.PutCStringAsRawHex8(uuid_str.c_str()); } response.PutChar(';'); const auto &module_arch = matched_module_spec.GetArchitecture(); response.PutCString("triple:"); response.PutCStringAsRawHex8( module_arch.GetTriple().getTriple().c_str()); response.PutChar(';'); response.PutCString("file_path:"); response.PutCStringAsRawHex8(module_path_spec.GetCString()); response.PutChar(';'); response.PutCString("file_offset:"); response.PutHex64(file_offset); response.PutChar(';'); response.PutCString("file_size:"); response.PutHex64(file_size); response.PutChar(';'); return SendPacketNoLock(response.GetData(), response.GetSize()); } void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response) { response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;", proc_info.GetProcessID(), proc_info.GetParentProcessID(), proc_info.GetUserID(), proc_info.GetGroupID(), proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID()); response.PutCString ("name:"); response.PutCStringAsRawHex8(proc_info.GetExecutableFile().GetCString()); response.PutChar(';'); const ArchSpec &proc_arch = proc_info.GetArchitecture(); if (proc_arch.IsValid()) { const llvm::Triple &proc_triple = proc_arch.GetTriple(); response.PutCString("triple:"); response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); } } void GDBRemoteCommunicationServerCommon::CreateProcessInfoResponse_DebugServerStyle ( const ProcessInstanceInfo &proc_info, StreamString &response) { response.Printf ("pid:%" PRIx64 ";parent-pid:%" PRIx64 ";real-uid:%x;real-gid:%x;effective-uid:%x;effective-gid:%x;", proc_info.GetProcessID(), proc_info.GetParentProcessID(), proc_info.GetUserID(), proc_info.GetGroupID(), proc_info.GetEffectiveUserID(), proc_info.GetEffectiveGroupID()); const ArchSpec &proc_arch = proc_info.GetArchitecture(); if (proc_arch.IsValid()) { const llvm::Triple &proc_triple = proc_arch.GetTriple(); #if defined(__APPLE__) // We'll send cputype/cpusubtype. const uint32_t cpu_type = proc_arch.GetMachOCPUType(); if (cpu_type != 0) response.Printf ("cputype:%" PRIx32 ";", cpu_type); const uint32_t cpu_subtype = proc_arch.GetMachOCPUSubType(); if (cpu_subtype != 0) response.Printf ("cpusubtype:%" PRIx32 ";", cpu_subtype); const std::string vendor = proc_triple.getVendorName (); if (!vendor.empty ()) response.Printf ("vendor:%s;", vendor.c_str ()); #else // We'll send the triple. response.PutCString("triple:"); response.PutCStringAsRawHex8(proc_triple.getTriple().c_str()); response.PutChar(';'); #endif std::string ostype = proc_triple.getOSName (); // Adjust so ostype reports ios for Apple/ARM and Apple/ARM64. if (proc_triple.getVendor () == llvm::Triple::Apple) { switch (proc_triple.getArch ()) { case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::aarch64: ostype = "ios"; break; default: // No change. break; } } response.Printf ("ostype:%s;", ostype.c_str ()); switch (proc_arch.GetByteOrder ()) { case lldb::eByteOrderLittle: response.PutCString ("endian:little;"); break; case lldb::eByteOrderBig: response.PutCString ("endian:big;"); break; case lldb::eByteOrderPDP: response.PutCString ("endian:pdp;"); break; default: // Nothing. break; } - if (proc_triple.isArch64Bit ()) - response.PutCString ("ptrsize:8;"); - else if (proc_triple.isArch32Bit ()) - response.PutCString ("ptrsize:4;"); - else if (proc_triple.isArch16Bit ()) - response.PutCString ("ptrsize:2;"); + // In case of MIPS64, pointer size is depend on ELF ABI + // For N32 the pointer size is 4 and for N64 it is 8 + std::string abi = proc_arch.GetTargetABI(); + if (!abi.empty()) + response.Printf("elf_abi:%s;", abi.c_str()); + response.Printf("ptrsize:%d;", proc_arch.GetAddressByteSize()); } } FileSpec GDBRemoteCommunicationServerCommon::FindModuleFile(const std::string& module_path, const ArchSpec& arch) { #ifdef __ANDROID__ return HostInfoAndroid::ResolveLibraryPath(module_path, arch); #else return FileSpec(module_path.c_str(), true); #endif }