1 //===-- NativeRegisterContextLinux_ppc64le.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 // This implementation is related to the OpenPOWER ABI for Power Architecture
11 // 64-bit ELF V2 ABI
12 
13 #if defined(__powerpc64__)
14 
15 #include "NativeRegisterContextLinux_ppc64le.h"
16 
17 #include "lldb/Core/RegisterValue.h"
18 #include "lldb/Host/common/NativeProcessProtocol.h"
19 #include "lldb/Utility/DataBufferHeap.h"
20 #include "lldb/Utility/Log.h"
21 #include "lldb/Utility/Status.h"
22 
23 #include "Plugins/Process/Linux/NativeProcessLinux.h"
24 #include "Plugins/Process/Linux/Procfs.h"
25 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
26 #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h"
27 
28 // System includes - They have to be included after framework includes because
29 // they define some
30 // macros which collide with variable names in other modules
31 #include <sys/socket.h>
32 #include <elf.h>
33 #include <asm/ptrace.h>
34 
35 #define REG_CONTEXT_SIZE GetGPRSize()
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 using namespace lldb_private::process_linux;
40 
41 static const uint32_t g_gpr_regnums_ppc64le[] = {
42     gpr_r0_ppc64le,   gpr_r1_ppc64le,  gpr_r2_ppc64le,     gpr_r3_ppc64le,
43     gpr_r4_ppc64le,   gpr_r5_ppc64le,  gpr_r6_ppc64le,     gpr_r7_ppc64le,
44     gpr_r8_ppc64le,   gpr_r9_ppc64le,  gpr_r10_ppc64le,    gpr_r11_ppc64le,
45     gpr_r12_ppc64le,  gpr_r13_ppc64le, gpr_r14_ppc64le,    gpr_r15_ppc64le,
46     gpr_r16_ppc64le,  gpr_r17_ppc64le, gpr_r18_ppc64le,    gpr_r19_ppc64le,
47     gpr_r20_ppc64le,  gpr_r21_ppc64le, gpr_r22_ppc64le,    gpr_r23_ppc64le,
48     gpr_r24_ppc64le,  gpr_r25_ppc64le, gpr_r26_ppc64le,    gpr_r27_ppc64le,
49     gpr_r28_ppc64le,  gpr_r29_ppc64le, gpr_r30_ppc64le,    gpr_r31_ppc64le,
50     gpr_pc_ppc64le,   gpr_msr_ppc64le, gpr_origr3_ppc64le, gpr_ctr_ppc64le,
51     gpr_lr_ppc64le,   gpr_xer_ppc64le, gpr_cr_ppc64le,     gpr_softe_ppc64le,
52     gpr_trap_ppc64le,
53 };
54 
55 namespace {
56 // Number of register sets provided by this context.
57 enum { k_num_register_sets = 1 };
58 }
59 
60 static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = {
61     {"General Purpose Registers", "gpr", k_num_gpr_registers_ppc64le,
62      g_gpr_regnums_ppc64le},
63 };
64 
65 NativeRegisterContextLinux *
66 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
67     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
68     uint32_t concrete_frame_idx) {
69   switch (target_arch.GetMachine()) {
70   case llvm::Triple::ppc64le:
71     return new NativeRegisterContextLinux_ppc64le(target_arch, native_thread,
72                                               concrete_frame_idx);
73   default:
74     llvm_unreachable("have no register context for architecture");
75   }
76 }
77 
78 NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le(
79     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
80     uint32_t concrete_frame_idx)
81     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
82                                  new RegisterInfoPOSIX_ppc64le(target_arch)) {
83   if (target_arch.GetMachine() != llvm::Triple::ppc64le) {
84     llvm_unreachable("Unhandled target architecture.");
85   }
86 
87   ::memset(&m_gpr_ppc64le, 0, sizeof(m_gpr_ppc64le));
88 }
89 
90 uint32_t NativeRegisterContextLinux_ppc64le::GetRegisterSetCount() const {
91   return k_num_register_sets;
92 }
93 
94 const RegisterSet *
95 NativeRegisterContextLinux_ppc64le::GetRegisterSet(uint32_t set_index) const {
96   if (set_index < k_num_register_sets)
97     return &g_reg_sets_ppc64le[set_index];
98 
99   return nullptr;
100 }
101 
102 uint32_t NativeRegisterContextLinux_ppc64le::GetUserRegisterCount() const {
103   uint32_t count = 0;
104   for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index)
105     count += g_reg_sets_ppc64le[set_index].num_registers;
106   return count;
107 }
108 
109 Status NativeRegisterContextLinux_ppc64le::ReadRegister(
110     const RegisterInfo *reg_info, RegisterValue &reg_value) {
111   Status error;
112 
113   if (!reg_info) {
114     error.SetErrorString("reg_info NULL");
115     return error;
116   }
117 
118   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
119 
120   if (IsGPR(reg)) {
121     error = ReadGPR();
122     if (error.Fail())
123       return error;
124 
125     uint8_t *src = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
126     reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size,
127                                 eByteOrderLittle, error);
128   } else {
129     return Status("failed - register wasn't recognized to be a GPR, "
130                   "read strategy unknown");
131   }
132 
133   return error;
134 }
135 
136 Status NativeRegisterContextLinux_ppc64le::WriteRegister(
137     const RegisterInfo *reg_info, const RegisterValue &reg_value) {
138   Status error;
139   if (!reg_info)
140     return Status("reg_info NULL");
141 
142   const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB];
143   if (reg_index == LLDB_INVALID_REGNUM)
144     return Status("no lldb regnum for %s", reg_info && reg_info->name
145                                                ? reg_info->name
146                                                : "<unknown register>");
147 
148   if (IsGPR(reg_index)) {
149       error = ReadGPR();
150       if (error.Fail())
151         return error;
152 
153       uint8_t *dst = (uint8_t *) &m_gpr_ppc64le + reg_info->byte_offset;
154       ::memcpy(dst, reg_value.GetBytes(), reg_value.GetByteSize());
155 
156       error = WriteGPR();
157       if (error.Fail())
158         return error;
159 
160       return Status();
161   }
162 
163   return Status("failed - register wasn't recognized to be a GPR, "
164                 "write strategy unknown");
165 }
166 
167 Status NativeRegisterContextLinux_ppc64le::ReadAllRegisterValues(
168     lldb::DataBufferSP &data_sp) {
169   Status error;
170 
171   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
172   if (!data_sp)
173     return Status("failed to allocate DataBufferHeap instance of size %" PRIu64,
174                   REG_CONTEXT_SIZE);
175 
176   error = ReadGPR();
177   if (error.Fail())
178     return error;
179 
180   uint8_t *dst = data_sp->GetBytes();
181   if (dst == nullptr) {
182     error.SetErrorStringWithFormat("DataBufferHeap instance of size %" PRIu64
183                                    " returned a null pointer",
184                                    REG_CONTEXT_SIZE);
185     return error;
186   }
187 
188   ::memcpy(dst, &m_gpr_ppc64le, GetGPRSize());
189 
190   return error;
191 }
192 
193 Status NativeRegisterContextLinux_ppc64le::WriteAllRegisterValues(
194     const lldb::DataBufferSP &data_sp) {
195   Status error;
196 
197   if (!data_sp) {
198     error.SetErrorStringWithFormat(
199         "NativeRegisterContextLinux_ppc64le::%s invalid data_sp provided",
200         __FUNCTION__);
201     return error;
202   }
203 
204   if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) {
205     error.SetErrorStringWithFormat(
206         "NativeRegisterContextLinux_ppc64le::%s data_sp contained mismatched "
207         "data size, expected %" PRIu64 ", actual %" PRIu64,
208         __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize());
209     return error;
210   }
211 
212   uint8_t *src = data_sp->GetBytes();
213   if (src == nullptr) {
214     error.SetErrorStringWithFormat("NativeRegisterContextLinux_ppc64le::%s "
215                                    "DataBuffer::GetBytes() returned a null "
216                                    "pointer",
217                                    __FUNCTION__);
218     return error;
219   }
220 
221   ::memcpy(&m_gpr_ppc64le, src, GetGPRSize());
222   error = WriteGPR();
223 
224   return error;
225 }
226 
227 bool NativeRegisterContextLinux_ppc64le::IsGPR(unsigned reg) const {
228   return reg <= k_last_gpr_ppc64le; // GPR's come first.
229 }
230 
231 Status NativeRegisterContextLinux_ppc64le::DoReadGPR(
232     void *buf, size_t buf_size) {
233   int regset = NT_PRSTATUS;
234   return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGS, m_thread.GetID(),
235                                            &regset, buf, buf_size);
236 }
237 
238 Status NativeRegisterContextLinux_ppc64le::DoWriteGPR(
239     void *buf, size_t buf_size) {
240   int regset = NT_PRSTATUS;
241   return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGS, m_thread.GetID(),
242                                            &regset, buf, buf_size);
243 }
244 
245 #endif // defined(__powerpc64__)
246