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(NativeThreadProtocol &native_thread,
23                                                        uint32_t concrete_frame_idx,
24                                                        RegisterInfoInterface *reg_info_interface_p) :
25 	NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx, reg_info_interface_p)
26 {}
27 
28 lldb::ByteOrder
29 NativeRegisterContextLinux::GetByteOrder() const
30 {
31     // Get the target process whose privileged thread was used for the register read.
32     lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
33 
34     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
35     if (!process_sp)
36         return byte_order;
37 
38     if (!process_sp->GetByteOrder (byte_order))
39     {
40         // FIXME log here
41     }
42 
43     return byte_order;
44 }
45 
46 Error
47 NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index, RegisterValue &reg_value)
48 {
49     const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
50     if (!reg_info)
51     	return Error("register %" PRIu32 " not found", reg_index);
52 
53     NativeProcessProtocolSP process_sp(m_thread.GetProcess());
54     if (!process_sp)
55         return Error("NativeProcessProtocol is NULL");
56 
57     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
58     return process_p->DoOperation([&] {
59         return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value);
60     });
61 }
62 
63 Error
64 NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue &reg_value)
65 {
66     uint32_t reg_to_write = reg_index;
67     RegisterValue value_to_write = reg_value;
68 
69     // Check if this is a subregister of a full register.
70     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
71     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
72     {
73 		Error error;
74 
75         RegisterValue full_value;
76         uint32_t full_reg = reg_info->invalidate_regs[0];
77         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
78 
79         // Read the full register.
80         error = ReadRegister(full_reg_info, full_value);
81         if (error.Fail ())
82             return error;
83 
84         lldb::ByteOrder byte_order = GetByteOrder();
85         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
86 
87         // Get the bytes for the full register.
88         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
89                                                                dst,
90                                                                sizeof(dst),
91                                                                byte_order,
92                                                                error);
93         if (error.Success() && dest_size)
94         {
95             uint8_t src[RegisterValue::kMaxRegisterByteSize];
96 
97             // Get the bytes for the source data.
98             const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
99             if (error.Success() && src_size && (src_size < dest_size))
100             {
101                 // Copy the src bytes to the destination.
102                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
103                 // Set this full register as the value to write.
104                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
105                 value_to_write.SetType(full_reg_info);
106                 reg_to_write = full_reg;
107             }
108         }
109     }
110 
111     NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
112     if (!process_sp)
113 	    return Error("NativeProcessProtocol is NULL");
114 
115     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
116     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
117     if (!register_to_write_info_p)
118         return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
119 
120     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*> (process_sp.get ());
121     return process_p->DoOperation([&] {
122         return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
123     });
124 }
125 
126 Error
127 NativeRegisterContextLinux::ReadGPR()
128 {
129 	NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
130     if (!process_sp)
131         return Error("NativeProcessProtocol is NULL");
132 
133     void* buf = GetGPRBuffer();
134     if (!buf)
135     	return Error("GPR buffer is NULL");
136     size_t buf_size = GetGPRSize();
137 
138     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
139     return process_p->DoOperation([&] { return DoReadGPR(buf, buf_size); });
140 }
141 
142 Error
143 NativeRegisterContextLinux::WriteGPR()
144 {
145 	NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
146     if (!process_sp)
147         return Error("NativeProcessProtocol is NULL");
148 
149     void* buf = GetGPRBuffer();
150     if (!buf)
151     	return Error("GPR buffer is NULL");
152     size_t buf_size = GetGPRSize();
153 
154     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
155     return process_p->DoOperation([&] { return DoWriteGPR(buf, buf_size); });
156 }
157 
158 Error
159 NativeRegisterContextLinux::ReadFPR()
160 {
161 	NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
162     if (!process_sp)
163         return Error("NativeProcessProtocol is NULL");
164 
165     void* buf = GetFPRBuffer();
166     if (!buf)
167     	return Error("GPR buffer is NULL");
168     size_t buf_size = GetFPRSize();
169 
170     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
171     return process_p->DoOperation([&] { return DoReadFPR(buf, buf_size); });
172 }
173 
174 Error
175 NativeRegisterContextLinux::WriteFPR()
176 {
177 	NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
178     if (!process_sp)
179         return Error("NativeProcessProtocol is NULL");
180 
181     void* buf = GetFPRBuffer();
182     if (!buf)
183     	return Error("GPR buffer is NULL");
184     size_t buf_size = GetFPRSize();
185 
186     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
187     return process_p->DoOperation([&] { return DoWriteFPR(buf, buf_size); });
188 }
189 
190 Error
191 NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset)
192 {
193     NativeProcessProtocolSP process_sp (m_thread.GetProcess());
194     if (!process_sp)
195         return Error("NativeProcessProtocol is NULL");
196     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
197 
198     return process_p->DoOperation([&] {
199         Error error;
200         NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
201                 static_cast<void *>(&regset), buf, buf_size, error);
202         return error;
203     });
204 }
205 
206 Error
207 NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset)
208 {
209     NativeProcessProtocolSP process_sp (m_thread.GetProcess());
210     if (!process_sp)
211         return Error("NativeProcessProtocol is NULL");
212     NativeProcessLinux* process_p = static_cast<NativeProcessLinux*>(process_sp.get());
213 
214     return process_p->DoOperation([&] {
215         Error error;
216         NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
217                 static_cast<void *>(&regset), buf, buf_size, error);
218         return error;
219     });
220 }
221 
222 Error
223 NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset,
224                                                 const char* reg_name,
225                                                 uint32_t size,
226                                                 RegisterValue &value)
227 {
228     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
229     Error error;
230 
231     lldb::addr_t data = NativeProcessLinux::PtraceWrapper(
232             PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), nullptr, 0, error);
233 
234     if (error.Success())
235         value = data;
236 
237     if (log)
238         log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%" PRIx64, __FUNCTION__, reg_name, data);
239 
240     return error;
241 }
242 
243 Error
244 NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset,
245                                                  const char* reg_name,
246                                                  const RegisterValue &value)
247 {
248     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
249 
250     void* buf = reinterpret_cast<void *>(value.GetAsUInt64());
251 
252     if (log)
253         log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf);
254 
255     Error error;
256     NativeProcessLinux::PtraceWrapper(
257             PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf, 0, error);
258 
259     return error;
260 }
261 
262 Error
263 NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size)
264 {
265     Error error;
266     NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size, error);
267     return error;
268 }
269 
270 Error
271 NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size)
272 {
273     Error error;
274     NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size, error);
275     return error;
276 }
277 
278 Error
279 NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size)
280 {
281     Error error;
282     NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size, error);
283     return error;
284 }
285 
286 Error
287 NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size)
288 {
289     Error error;
290     NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size, error);
291     return error;
292 }
293