1 //===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "NativeRegisterContextLinux.h" 11 12 #include "lldb/Core/RegisterValue.h" 13 #include "lldb/Host/common/NativeProcessProtocol.h" 14 #include "lldb/Host/common/NativeThreadProtocol.h" 15 #include "lldb/Host/linux/Ptrace.h" 16 17 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 18 19 using namespace lldb_private; 20 using namespace lldb_private::process_linux; 21 22 NativeRegisterContextLinux::NativeRegisterContextLinux( 23 NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx, 24 RegisterInfoInterface *reg_info_interface_p) 25 : NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, 26 reg_info_interface_p) {} 27 28 lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { 29 // Get the target process whose privileged thread was used for the register 30 // read. 31 lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; 32 33 if (!m_thread.GetProcess().GetByteOrder(byte_order)) { 34 // FIXME log here 35 } 36 37 return byte_order; 38 } 39 40 Status NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, 41 RegisterValue ®_value) { 42 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index); 43 if (!reg_info) 44 return Status("register %" PRIu32 " not found", reg_index); 45 46 return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, 47 reg_info->byte_size, reg_value); 48 } 49 50 Status 51 NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, 52 const RegisterValue ®_value) { 53 uint32_t reg_to_write = reg_index; 54 RegisterValue value_to_write = reg_value; 55 56 // Check if this is a subregister of a full register. 57 const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); 58 if (reg_info->invalidate_regs && 59 (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) { 60 Status error; 61 62 RegisterValue full_value; 63 uint32_t full_reg = reg_info->invalidate_regs[0]; 64 const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); 65 66 // Read the full register. 67 error = ReadRegister(full_reg_info, full_value); 68 if (error.Fail()) 69 return error; 70 71 lldb::ByteOrder byte_order = GetByteOrder(); 72 uint8_t dst[RegisterValue::kMaxRegisterByteSize]; 73 74 // Get the bytes for the full register. 75 const uint32_t dest_size = full_value.GetAsMemoryData( 76 full_reg_info, dst, sizeof(dst), byte_order, error); 77 if (error.Success() && dest_size) { 78 uint8_t src[RegisterValue::kMaxRegisterByteSize]; 79 80 // Get the bytes for the source data. 81 const uint32_t src_size = reg_value.GetAsMemoryData( 82 reg_info, src, sizeof(src), byte_order, error); 83 if (error.Success() && src_size && (src_size < dest_size)) { 84 // Copy the src bytes to the destination. 85 memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size); 86 // Set this full register as the value to write. 87 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); 88 value_to_write.SetType(full_reg_info); 89 reg_to_write = full_reg; 90 } 91 } 92 } 93 94 const RegisterInfo *const register_to_write_info_p = 95 GetRegisterInfoAtIndex(reg_to_write); 96 assert(register_to_write_info_p && 97 "register to write does not have valid RegisterInfo"); 98 if (!register_to_write_info_p) 99 return Status("NativeRegisterContextLinux::%s failed to get RegisterInfo " 100 "for write register index %" PRIu32, 101 __FUNCTION__, reg_to_write); 102 103 return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); 104 } 105 106 Status NativeRegisterContextLinux::ReadGPR() { 107 void *buf = GetGPRBuffer(); 108 if (!buf) 109 return Status("GPR buffer is NULL"); 110 size_t buf_size = GetGPRSize(); 111 112 return DoReadGPR(buf, buf_size); 113 } 114 115 Status NativeRegisterContextLinux::WriteGPR() { 116 void *buf = GetGPRBuffer(); 117 if (!buf) 118 return Status("GPR buffer is NULL"); 119 size_t buf_size = GetGPRSize(); 120 121 return DoWriteGPR(buf, buf_size); 122 } 123 124 Status NativeRegisterContextLinux::ReadFPR() { 125 void *buf = GetFPRBuffer(); 126 if (!buf) 127 return Status("FPR buffer is NULL"); 128 size_t buf_size = GetFPRSize(); 129 130 return DoReadFPR(buf, buf_size); 131 } 132 133 Status NativeRegisterContextLinux::WriteFPR() { 134 void *buf = GetFPRBuffer(); 135 if (!buf) 136 return Status("FPR buffer is NULL"); 137 size_t buf_size = GetFPRSize(); 138 139 return DoWriteFPR(buf, buf_size); 140 } 141 142 Status NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, 143 unsigned int regset) { 144 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), 145 static_cast<void *>(®set), buf, 146 buf_size); 147 } 148 149 Status NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, 150 unsigned int regset) { 151 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 152 static_cast<void *>(®set), buf, 153 buf_size); 154 } 155 156 Status NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset, 157 const char *reg_name, 158 uint32_t size, 159 RegisterValue &value) { 160 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); 161 162 long data; 163 Status error = NativeProcessLinux::PtraceWrapper( 164 PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), 165 nullptr, 0, &data); 166 167 if (error.Success()) 168 // First cast to an unsigned of the same size to avoid sign extension. 169 value.SetUInt(static_cast<unsigned long>(data), size); 170 171 LLDB_LOG(log, "{0}: {1:x}", reg_name, data); 172 return error; 173 } 174 175 Status NativeRegisterContextLinux::DoWriteRegisterValue( 176 uint32_t offset, const char *reg_name, const RegisterValue &value) { 177 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); 178 179 void *buf = reinterpret_cast<void *>(value.GetAsUInt64()); 180 LLDB_LOG(log, "{0}: {1}", reg_name, buf); 181 182 return NativeProcessLinux::PtraceWrapper( 183 PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf); 184 } 185 186 Status NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) { 187 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), 188 nullptr, buf, buf_size); 189 } 190 191 Status NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) { 192 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), 193 nullptr, buf, buf_size); 194 } 195 196 Status NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) { 197 return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), 198 nullptr, buf, buf_size); 199 } 200 201 Status NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) { 202 return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), 203 nullptr, buf, buf_size); 204 } 205