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     return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, reg_info->byte_size, reg_value);
54 }
55 
56 Error
57 NativeRegisterContextLinux::WriteRegisterRaw(uint32_t reg_index, const RegisterValue &reg_value)
58 {
59     uint32_t reg_to_write = reg_index;
60     RegisterValue value_to_write = reg_value;
61 
62     // Check if this is a subregister of a full register.
63     const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
64     if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM))
65     {
66         Error error;
67 
68         RegisterValue full_value;
69         uint32_t full_reg = reg_info->invalidate_regs[0];
70         const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
71 
72         // Read the full register.
73         error = ReadRegister(full_reg_info, full_value);
74         if (error.Fail ())
75             return error;
76 
77         lldb::ByteOrder byte_order = GetByteOrder();
78         uint8_t dst[RegisterValue::kMaxRegisterByteSize];
79 
80         // Get the bytes for the full register.
81         const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info,
82                                                                dst,
83                                                                sizeof(dst),
84                                                                byte_order,
85                                                                error);
86         if (error.Success() && dest_size)
87         {
88             uint8_t src[RegisterValue::kMaxRegisterByteSize];
89 
90             // Get the bytes for the source data.
91             const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error);
92             if (error.Success() && src_size && (src_size < dest_size))
93             {
94                 // Copy the src bytes to the destination.
95                 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size);
96                 // Set this full register as the value to write.
97                 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
98                 value_to_write.SetType(full_reg_info);
99                 reg_to_write = full_reg;
100             }
101         }
102     }
103 
104     const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write);
105     assert (register_to_write_info_p && "register to write does not have valid RegisterInfo");
106     if (!register_to_write_info_p)
107         return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write);
108 
109     return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
110 }
111 
112 Error
113 NativeRegisterContextLinux::ReadGPR()
114 {
115     void* buf = GetGPRBuffer();
116     if (!buf)
117         return Error("GPR buffer is NULL");
118     size_t buf_size = GetGPRSize();
119 
120     return DoReadGPR(buf, buf_size);
121 }
122 
123 Error
124 NativeRegisterContextLinux::WriteGPR()
125 {
126     void* buf = GetGPRBuffer();
127     if (!buf)
128         return Error("GPR buffer is NULL");
129     size_t buf_size = GetGPRSize();
130 
131     return DoWriteGPR(buf, buf_size);
132 }
133 
134 Error
135 NativeRegisterContextLinux::ReadFPR()
136 {
137     void* buf = GetFPRBuffer();
138     if (!buf)
139         return Error("FPR buffer is NULL");
140     size_t buf_size = GetFPRSize();
141 
142     return DoReadFPR(buf, buf_size);
143 }
144 
145 Error
146 NativeRegisterContextLinux::WriteFPR()
147 {
148     void* buf = GetFPRBuffer();
149     if (!buf)
150         return Error("FPR buffer is NULL");
151     size_t buf_size = GetFPRSize();
152 
153     return DoWriteFPR(buf, buf_size);
154 }
155 
156 Error
157 NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size, unsigned int regset)
158 {
159     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
160             static_cast<void *>(&regset), buf, buf_size);
161 }
162 
163 Error
164 NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size, unsigned int regset)
165 {
166     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
167             static_cast<void *>(&regset), buf, buf_size);
168 }
169 
170 Error
171 NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset,
172                                                 const char* reg_name,
173                                                 uint32_t size,
174                                                 RegisterValue &value)
175 {
176     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
177 
178     long data;
179     Error error = NativeProcessLinux::PtraceWrapper(
180             PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), nullptr, 0, &data);
181 
182     if (error.Success())
183         // First cast to an unsigned of the same size to avoid sign extension.
184         value.SetUInt64(static_cast<unsigned long>(data));
185 
186     if (log)
187         log->Printf ("NativeRegisterContextLinux::%s() reg %s: 0x%lx", __FUNCTION__, reg_name, data);
188 
189     return error;
190 }
191 
192 Error
193 NativeRegisterContextLinux::DoWriteRegisterValue(uint32_t offset,
194                                                  const char* reg_name,
195                                                  const RegisterValue &value)
196 {
197     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
198 
199     void* buf = reinterpret_cast<void *>(value.GetAsUInt64());
200 
201     if (log)
202         log->Printf ("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__, reg_name, buf);
203 
204     return NativeProcessLinux::PtraceWrapper(
205             PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
206 }
207 
208 Error
209 NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size)
210 {
211     return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(), nullptr, buf, buf_size);
212 }
213 
214 Error
215 NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size)
216 {
217     return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(), nullptr, buf, buf_size);
218 }
219 
220 Error
221 NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size)
222 {
223     return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(), nullptr, buf, buf_size);
224 }
225 
226 Error
227 NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size)
228 {
229     return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(), nullptr, buf, buf_size);
230 }
231