1068f8a7eSTamas Berghammer //===-- NativeRegisterContextLinux.cpp --------------------------*- C++ -*-===//
2068f8a7eSTamas Berghammer //
3068f8a7eSTamas Berghammer //                     The LLVM Compiler Infrastructure
4068f8a7eSTamas Berghammer //
5068f8a7eSTamas Berghammer // This file is distributed under the University of Illinois Open Source
6068f8a7eSTamas Berghammer // License. See LICENSE.TXT for details.
7068f8a7eSTamas Berghammer //
8068f8a7eSTamas Berghammer //===----------------------------------------------------------------------===//
9068f8a7eSTamas Berghammer 
10068f8a7eSTamas Berghammer #include "NativeRegisterContextLinux.h"
11068f8a7eSTamas Berghammer 
12068f8a7eSTamas Berghammer #include "lldb/Core/RegisterValue.h"
13068f8a7eSTamas Berghammer #include "lldb/Host/common/NativeProcessProtocol.h"
14068f8a7eSTamas Berghammer #include "lldb/Host/common/NativeThreadProtocol.h"
15068f8a7eSTamas Berghammer #include "lldb/Host/linux/Ptrace.h"
16068f8a7eSTamas Berghammer 
17068f8a7eSTamas Berghammer #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
18068f8a7eSTamas Berghammer 
19068f8a7eSTamas Berghammer using namespace lldb_private;
20068f8a7eSTamas Berghammer using namespace lldb_private::process_linux;
21068f8a7eSTamas Berghammer 
22*b9c1b51eSKate Stone NativeRegisterContextLinux::NativeRegisterContextLinux(
23*b9c1b51eSKate Stone     NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx,
24*b9c1b51eSKate Stone     RegisterInfoInterface *reg_info_interface_p)
25*b9c1b51eSKate Stone     : NativeRegisterContextRegisterInfo(native_thread, concrete_frame_idx,
26*b9c1b51eSKate Stone                                         reg_info_interface_p) {}
27068f8a7eSTamas Berghammer 
28*b9c1b51eSKate Stone lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const {
29*b9c1b51eSKate Stone   // Get the target process whose privileged thread was used for the register
30*b9c1b51eSKate Stone   // read.
31068f8a7eSTamas Berghammer   lldb::ByteOrder byte_order = lldb::eByteOrderInvalid;
32068f8a7eSTamas Berghammer 
33068f8a7eSTamas Berghammer   NativeProcessProtocolSP process_sp(m_thread.GetProcess());
34068f8a7eSTamas Berghammer   if (!process_sp)
35068f8a7eSTamas Berghammer     return byte_order;
36068f8a7eSTamas Berghammer 
37*b9c1b51eSKate Stone   if (!process_sp->GetByteOrder(byte_order)) {
38068f8a7eSTamas Berghammer     // FIXME log here
39068f8a7eSTamas Berghammer   }
40068f8a7eSTamas Berghammer 
41068f8a7eSTamas Berghammer   return byte_order;
42068f8a7eSTamas Berghammer }
43068f8a7eSTamas Berghammer 
44*b9c1b51eSKate Stone Error NativeRegisterContextLinux::ReadRegisterRaw(uint32_t reg_index,
45*b9c1b51eSKate Stone                                                   RegisterValue &reg_value) {
46068f8a7eSTamas Berghammer   const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
47068f8a7eSTamas Berghammer   if (!reg_info)
48068f8a7eSTamas Berghammer     return Error("register %" PRIu32 " not found", reg_index);
49068f8a7eSTamas Berghammer 
50*b9c1b51eSKate Stone   return DoReadRegisterValue(reg_info->byte_offset, reg_info->name,
51*b9c1b51eSKate Stone                              reg_info->byte_size, reg_value);
52068f8a7eSTamas Berghammer }
53068f8a7eSTamas Berghammer 
54*b9c1b51eSKate Stone Error NativeRegisterContextLinux::WriteRegisterRaw(
55*b9c1b51eSKate Stone     uint32_t reg_index, const RegisterValue &reg_value) {
56068f8a7eSTamas Berghammer   uint32_t reg_to_write = reg_index;
57068f8a7eSTamas Berghammer   RegisterValue value_to_write = reg_value;
58068f8a7eSTamas Berghammer 
59068f8a7eSTamas Berghammer   // Check if this is a subregister of a full register.
60068f8a7eSTamas Berghammer   const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
61*b9c1b51eSKate Stone   if (reg_info->invalidate_regs &&
62*b9c1b51eSKate Stone       (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
63068f8a7eSTamas Berghammer     Error error;
64068f8a7eSTamas Berghammer 
65068f8a7eSTamas Berghammer     RegisterValue full_value;
66068f8a7eSTamas Berghammer     uint32_t full_reg = reg_info->invalidate_regs[0];
67068f8a7eSTamas Berghammer     const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);
68068f8a7eSTamas Berghammer 
69068f8a7eSTamas Berghammer     // Read the full register.
70068f8a7eSTamas Berghammer     error = ReadRegister(full_reg_info, full_value);
71068f8a7eSTamas Berghammer     if (error.Fail())
72068f8a7eSTamas Berghammer       return error;
73068f8a7eSTamas Berghammer 
74068f8a7eSTamas Berghammer     lldb::ByteOrder byte_order = GetByteOrder();
75068f8a7eSTamas Berghammer     uint8_t dst[RegisterValue::kMaxRegisterByteSize];
76068f8a7eSTamas Berghammer 
77068f8a7eSTamas Berghammer     // Get the bytes for the full register.
78*b9c1b51eSKate Stone     const uint32_t dest_size = full_value.GetAsMemoryData(
79*b9c1b51eSKate Stone         full_reg_info, dst, sizeof(dst), byte_order, error);
80*b9c1b51eSKate Stone     if (error.Success() && dest_size) {
81068f8a7eSTamas Berghammer       uint8_t src[RegisterValue::kMaxRegisterByteSize];
82068f8a7eSTamas Berghammer 
83068f8a7eSTamas Berghammer       // Get the bytes for the source data.
84*b9c1b51eSKate Stone       const uint32_t src_size = reg_value.GetAsMemoryData(
85*b9c1b51eSKate Stone           reg_info, src, sizeof(src), byte_order, error);
86*b9c1b51eSKate Stone       if (error.Success() && src_size && (src_size < dest_size)) {
87068f8a7eSTamas Berghammer         // Copy the src bytes to the destination.
88068f8a7eSTamas Berghammer         memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
89068f8a7eSTamas Berghammer         // Set this full register as the value to write.
90068f8a7eSTamas Berghammer         value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
91068f8a7eSTamas Berghammer         value_to_write.SetType(full_reg_info);
92068f8a7eSTamas Berghammer         reg_to_write = full_reg;
93068f8a7eSTamas Berghammer       }
94068f8a7eSTamas Berghammer     }
95068f8a7eSTamas Berghammer   }
96068f8a7eSTamas Berghammer 
97*b9c1b51eSKate Stone   const RegisterInfo *const register_to_write_info_p =
98*b9c1b51eSKate Stone       GetRegisterInfoAtIndex(reg_to_write);
99*b9c1b51eSKate Stone   assert(register_to_write_info_p &&
100*b9c1b51eSKate Stone          "register to write does not have valid RegisterInfo");
101068f8a7eSTamas Berghammer   if (!register_to_write_info_p)
102*b9c1b51eSKate Stone     return Error("NativeRegisterContextLinux::%s failed to get RegisterInfo "
103*b9c1b51eSKate Stone                  "for write register index %" PRIu32,
104*b9c1b51eSKate Stone                  __FUNCTION__, reg_to_write);
105068f8a7eSTamas Berghammer 
106c7512fdcSPavel Labath   return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value);
107068f8a7eSTamas Berghammer }
108068f8a7eSTamas Berghammer 
109*b9c1b51eSKate Stone Error NativeRegisterContextLinux::ReadGPR() {
110068f8a7eSTamas Berghammer   void *buf = GetGPRBuffer();
111068f8a7eSTamas Berghammer   if (!buf)
112068f8a7eSTamas Berghammer     return Error("GPR buffer is NULL");
113068f8a7eSTamas Berghammer   size_t buf_size = GetGPRSize();
114068f8a7eSTamas Berghammer 
11519cbe96aSPavel Labath   return DoReadGPR(buf, buf_size);
116068f8a7eSTamas Berghammer }
117068f8a7eSTamas Berghammer 
118*b9c1b51eSKate Stone Error NativeRegisterContextLinux::WriteGPR() {
119068f8a7eSTamas Berghammer   void *buf = GetGPRBuffer();
120068f8a7eSTamas Berghammer   if (!buf)
121068f8a7eSTamas Berghammer     return Error("GPR buffer is NULL");
122068f8a7eSTamas Berghammer   size_t buf_size = GetGPRSize();
123068f8a7eSTamas Berghammer 
12419cbe96aSPavel Labath   return DoWriteGPR(buf, buf_size);
125068f8a7eSTamas Berghammer }
126068f8a7eSTamas Berghammer 
127*b9c1b51eSKate Stone Error NativeRegisterContextLinux::ReadFPR() {
128068f8a7eSTamas Berghammer   void *buf = GetFPRBuffer();
129068f8a7eSTamas Berghammer   if (!buf)
130789da667SSagar Thakur     return Error("FPR buffer is NULL");
131068f8a7eSTamas Berghammer   size_t buf_size = GetFPRSize();
132068f8a7eSTamas Berghammer 
13319cbe96aSPavel Labath   return DoReadFPR(buf, buf_size);
134068f8a7eSTamas Berghammer }
135068f8a7eSTamas Berghammer 
136*b9c1b51eSKate Stone Error NativeRegisterContextLinux::WriteFPR() {
137068f8a7eSTamas Berghammer   void *buf = GetFPRBuffer();
138068f8a7eSTamas Berghammer   if (!buf)
139789da667SSagar Thakur     return Error("FPR buffer is NULL");
140068f8a7eSTamas Berghammer   size_t buf_size = GetFPRSize();
141068f8a7eSTamas Berghammer 
14219cbe96aSPavel Labath   return DoWriteFPR(buf, buf_size);
143068f8a7eSTamas Berghammer }
144068f8a7eSTamas Berghammer 
145*b9c1b51eSKate Stone Error NativeRegisterContextLinux::ReadRegisterSet(void *buf, size_t buf_size,
146*b9c1b51eSKate Stone                                                   unsigned int regset) {
1474a9babb2SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
148*b9c1b51eSKate Stone                                            static_cast<void *>(&regset), buf,
149*b9c1b51eSKate Stone                                            buf_size);
150068f8a7eSTamas Berghammer }
151068f8a7eSTamas Berghammer 
152*b9c1b51eSKate Stone Error NativeRegisterContextLinux::WriteRegisterSet(void *buf, size_t buf_size,
153*b9c1b51eSKate Stone                                                    unsigned int regset) {
1544a9babb2SPavel Labath   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
155*b9c1b51eSKate Stone                                            static_cast<void *>(&regset), buf,
156*b9c1b51eSKate Stone                                            buf_size);
157068f8a7eSTamas Berghammer }
158068f8a7eSTamas Berghammer 
159*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoReadRegisterValue(uint32_t offset,
160068f8a7eSTamas Berghammer                                                       const char *reg_name,
161068f8a7eSTamas Berghammer                                                       uint32_t size,
162*b9c1b51eSKate Stone                                                       RegisterValue &value) {
163c7512fdcSPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
164c7512fdcSPavel Labath 
1654a9babb2SPavel Labath   long data;
1664a9babb2SPavel Labath   Error error = NativeProcessLinux::PtraceWrapper(
167*b9c1b51eSKate Stone       PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset),
168*b9c1b51eSKate Stone       nullptr, 0, &data);
169c7512fdcSPavel Labath 
170c7512fdcSPavel Labath   if (error.Success())
1711bd3c9abSChaoren Lin     // First cast to an unsigned of the same size to avoid sign extension.
1721bd3c9abSChaoren Lin     value.SetUInt64(static_cast<unsigned long>(data));
173c7512fdcSPavel Labath 
174c7512fdcSPavel Labath   if (log)
175*b9c1b51eSKate Stone     log->Printf("NativeRegisterContextLinux::%s() reg %s: 0x%lx", __FUNCTION__,
176*b9c1b51eSKate Stone                 reg_name, data);
177c7512fdcSPavel Labath 
178c7512fdcSPavel Labath   return error;
179068f8a7eSTamas Berghammer }
180068f8a7eSTamas Berghammer 
181*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoWriteRegisterValue(
182*b9c1b51eSKate Stone     uint32_t offset, const char *reg_name, const RegisterValue &value) {
183c7512fdcSPavel Labath   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS));
184c7512fdcSPavel Labath 
185c7512fdcSPavel Labath   void *buf = reinterpret_cast<void *>(value.GetAsUInt64());
186c7512fdcSPavel Labath 
187c7512fdcSPavel Labath   if (log)
188*b9c1b51eSKate Stone     log->Printf("NativeRegisterContextLinux::%s() reg %s: %p", __FUNCTION__,
189*b9c1b51eSKate Stone                 reg_name, buf);
190c7512fdcSPavel Labath 
1914a9babb2SPavel Labath   return NativeProcessLinux::PtraceWrapper(
1924a9babb2SPavel Labath       PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
193068f8a7eSTamas Berghammer }
194068f8a7eSTamas Berghammer 
195*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoReadGPR(void *buf, size_t buf_size) {
196*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
197*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
198068f8a7eSTamas Berghammer }
199068f8a7eSTamas Berghammer 
200*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoWriteGPR(void *buf, size_t buf_size) {
201*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
202*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
203068f8a7eSTamas Berghammer }
204068f8a7eSTamas Berghammer 
205*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoReadFPR(void *buf, size_t buf_size) {
206*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
207*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
208068f8a7eSTamas Berghammer }
209068f8a7eSTamas Berghammer 
210*b9c1b51eSKate Stone Error NativeRegisterContextLinux::DoWriteFPR(void *buf, size_t buf_size) {
211*b9c1b51eSKate Stone   return NativeProcessLinux::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
212*b9c1b51eSKate Stone                                            nullptr, buf, buf_size);
213068f8a7eSTamas Berghammer }
214