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 ®_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 ®_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 ®set, 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 ®set, buf, buf_size); 243 } 244 245 #endif // defined(__powerpc64__) 246