| 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(format: "register %" PRIu32 " not found" , |
| 32 | reg_index); |
| 33 | |
| 34 | return DoReadRegisterValue(offset: GetPtraceOffset(reg_index), reg_name: reg_info->name, |
| 35 | size: reg_info->byte_size, value&: 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(reg_index: full_reg); |
| 54 | |
| 55 | // Read the full register. |
| 56 | error = ReadRegister(reg_info: full_reg_info, reg_value&: 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 | reg_info: *full_reg_info, dst: dst.data(), dst_len: dst.size(), dst_byte_order: 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: *reg_info, dst: src.data(), dst_len: src.size(), dst_byte_order: byte_order, error); |
| 74 | if (error.Success() && src_size && (src_size < dest_size)) { |
| 75 | // Copy the src bytes to the destination. |
| 76 | memcpy(dest: dst.data() + (reg_info->byte_offset & 0x1), src: src.data(), |
| 77 | n: src_size); |
| 78 | // Set this full register as the value to write. |
| 79 | value_to_write.SetBytes(bytes: dst.data(), length: 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_index: 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 | format: "NativeRegisterContextLinux::%s failed to get RegisterInfo " |
| 94 | "for write register index %" PRIu32, |
| 95 | __FUNCTION__, reg_to_write); |
| 96 | |
| 97 | return DoWriteRegisterValue(offset: GetPtraceOffset(reg_index), reg_name: reg_info->name, |
| 98 | value: reg_value); |
| 99 | } |
| 100 | |
| 101 | Status NativeRegisterContextLinux::ReadGPR() { |
| 102 | return NativeProcessLinux::PtraceWrapper( |
| 103 | PTRACE_GETREGS, pid: m_thread.GetID(), addr: nullptr, data: GetGPRBuffer(), data_size: GetGPRSize()); |
| 104 | } |
| 105 | |
| 106 | Status NativeRegisterContextLinux::WriteGPR() { |
| 107 | return NativeProcessLinux::PtraceWrapper( |
| 108 | PTRACE_SETREGS, pid: m_thread.GetID(), addr: nullptr, data: GetGPRBuffer(), data_size: GetGPRSize()); |
| 109 | } |
| 110 | |
| 111 | Status NativeRegisterContextLinux::ReadFPR() { |
| 112 | return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, pid: m_thread.GetID(), |
| 113 | addr: nullptr, data: GetFPRBuffer(), |
| 114 | data_size: GetFPRSize()); |
| 115 | } |
| 116 | |
| 117 | Status NativeRegisterContextLinux::WriteFPR() { |
| 118 | return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, pid: m_thread.GetID(), |
| 119 | addr: nullptr, data: GetFPRBuffer(), |
| 120 | data_size: GetFPRSize()); |
| 121 | } |
| 122 | |
| 123 | Status NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, |
| 124 | unsigned int regset) { |
| 125 | return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, pid: m_thread.GetID(), |
| 126 | addr: static_cast<void *>(®set), data: buf, |
| 127 | data_size: buf_size); |
| 128 | } |
| 129 | |
| 130 | Status NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, |
| 131 | unsigned int regset) { |
| 132 | return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, pid: m_thread.GetID(), |
| 133 | addr: static_cast<void *>(®set), data: buf, |
| 134 | data_size: 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(mask: POSIXLog::Registers); |
| 142 | |
| 143 | long data; |
| 144 | Status error = NativeProcessLinux::PtraceWrapper( |
| 145 | req: PTRACE_PEEKUSER, pid: m_thread.GetID(), addr: reinterpret_cast<void *>(offset), |
| 146 | data: nullptr, data_size: 0, result: &data); |
| 147 | |
| 148 | if (error.Success()) |
| 149 | // First cast to an unsigned of the same size to avoid sign extension. |
| 150 | value.SetUInt(uint: static_cast<unsigned long>(data), byte_size: 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(mask: 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 | req: PTRACE_POKEUSER, pid: m_thread.GetID(), addr: reinterpret_cast<void *>(offset), data: 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[]>(num: 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, pid: tid, addr: ®set, |
| 176 | data: &iov, data_size: sizeof(iov)); |
| 177 | if (ST.Fail()) |
| 178 | return ST.ToError(); |
| 179 | return HostInfo::GetArchitecture( |
| 180 | arch_kind: iov.iov_len < gpr64_size ? HostInfo::eArchKind32 : HostInfo::eArchKind64); |
| 181 | } |
| 182 | |