1 //===-- NativeRegisterContextLinux.cpp ------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NativeRegisterContextLinux.h" 10 11 #include "Plugins/Process/Linux/NativeProcessLinux.h" 12 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 13 #include "lldb/Host/HostInfo.h" 14 #include "lldb/Host/common/NativeProcessProtocol.h" 15 #include "lldb/Host/common/NativeThreadProtocol.h" 16 #include "lldb/Host/linux/Ptrace.h" 17 #include "lldb/Utility/RegisterValue.h" 18 #include <sys/uio.h> 19 20 using namespace lldb_private; 21 using namespace lldb_private::process_linux; 22 23 lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { 24 return m_thread.GetProcess().GetByteOrder(); 25 } 26 27 Status NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, 28 RegisterValue ®_value) { 29 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); 30 if (!reg_info) 31 return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", 32 reg_index); 33 34 return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, 35 reg_info->byte_size, reg_value); 36 } 37 38 Status 39 NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, 40 const RegisterValue ®_value) { 41 uint32_t reg_to_write = reg_index; 42 RegisterValue value_to_write = reg_value; 43 44 // Check if this is a subregister of a full register. 45 const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); 46 assert(reg_info && "Expected valid register info for reg_index."); 47 if (reg_info->invalidate_regs && 48 (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { 49 Status error; 50 51 RegisterValue full_value; 52 uint32_t full_reg = reg_info->invalidate_regs[0]; 53 const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); 54 55 // Read the full register. 56 error = ReadRegister(full_reg_info, full_value); 57 if (error.Fail()) { 58 // full_reg_info was nullptr, or we couldn't read the register. 59 return error; 60 } 61 62 lldb::ByteOrder byte_order = GetByteOrder(); 63 RegisterValue::BytesContainer dst(full_reg_info->byte_size); 64 65 // Get the bytes for the full register. 66 const uint32_t dest_size = full_value.GetAsMemoryData( 67 *full_reg_info, dst.data(), dst.size(), byte_order, error); 68 if (error.Success() && dest_size) { 69 RegisterValue::BytesContainer src(reg_info->byte_size); 70 71 // Get the bytes for the source data. 72 const uint32_t src_size = reg_value.GetAsMemoryData( 73 *reg_info, src.data(), src.size(), byte_order, error); 74 if (error.Success() && src_size && (src_size < dest_size)) { 75 // Copy the src bytes to the destination. 76 memcpy(dst.data() + (reg_info->byte_offset & 0x1), src.data(), 77 src_size); 78 // Set this full register as the value to write. 79 value_to_write.SetBytes(dst.data(), full_value.GetByteSize(), 80 byte_order); 81 value_to_write.SetType(*full_reg_info); 82 reg_to_write = full_reg; 83 } 84 } 85 } 86 87 const RegisterInfo *const register_to_write_info_p = 88 GetRegisterInfoAtIndex(reg_to_write); 89 assert(register_to_write_info_p && 90 "register to write does not have valid RegisterInfo"); 91 if (!register_to_write_info_p) 92 return Status::FromErrorStringWithFormat( 93 "NativeRegisterContextLinux::%s failed to get RegisterInfo " 94 "for write register index %" PRIu32, 95 __FUNCTION__, reg_to_write); 96 97 return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, 98 reg_value); 99 } 100 101 Status NativeRegisterContextLinux::ReadGPR() { 102 return NativeProcessLinux::PtraceWrapper( 103 PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); 104 } 105 106 Status NativeRegisterContextLinux::WriteGPR() { 107 return NativeProcessLinux::PtraceWrapper( 108 PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize()); 109 } 110 111 Status NativeRegisterContextLinux::ReadFPR() { 112 return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), 113 nullptr, GetFPRBuffer(), 114 GetFPRSize()); 115 } 116 117 Status NativeRegisterContextLinux::WriteFPR() { 118 return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), 119 nullptr, GetFPRBuffer(), 120 GetFPRSize()); 121 } 122 123 Status NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, 124 unsigned int regset) { 125 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 126 static_cast<void *>(®set), buf, 127 buf_size); 128 } 129 130 Status NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, 131 unsigned int regset) { 132 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 133 static_cast<void *>(®set), buf, 134 buf_size); 135 } 136 137 Status NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, 138 const char *reg_name, 139 uint32_t size, 140 RegisterValue &value) { 141 Log *log = GetLog(POSIXLog::Registers); 142 143 long data; 144 Status error = NativeProcessLinux::PtraceWrapper( 145 PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), 146 nullptr, 0, &data); 147 148 if (error.Success()) 149 // First cast to an unsigned of the same size to avoid sign extension. 150 value.SetUInt(static_cast<unsigned long>(data), size); 151 152 LLDB_LOG(log, "{0}: {1:x}", reg_name, data); 153 return error; 154 } 155 156 Status NativeRegisterContextLinux::DoWriteRegisterValue( 157 uint32_t offset, const char *reg_name, const RegisterValue &value) { 158 Log *log = GetLog(POSIXLog::Registers); 159 160 void *buf = reinterpret_cast<void *>(value.GetAsUInt64()); 161 LLDB_LOG(log, "{0}: {1}", reg_name, buf); 162 163 return NativeProcessLinux::PtraceWrapper( 164 PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf); 165 } 166 167 llvm::Expected<ArchSpec> 168 NativeRegisterContextLinux::DetermineArchitectureViaGPR(lldb::tid_t tid, 169 size_t gpr64_size) { 170 std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(gpr64_size); 171 struct iovec iov; 172 iov.iov_base = data.get(); 173 iov.iov_len = gpr64_size; 174 unsigned int regset = llvm::ELF::NT_PRSTATUS; 175 Status ST = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 176 &iov, sizeof(iov)); 177 if (ST.Fail()) 178 return ST.ToError(); 179 return HostInfo::GetArchitecture( 180 iov.iov_len < gpr64_size ? HostInfo::eArchKind32 : HostInfo::eArchKind64); 181 } 182