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 &reg_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 &reg_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 *>(&regset), 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 *>(&regset), 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