1 //===-- NativeRegisterContextLinux_arm.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 #if defined(__arm__) 11 12 #include "NativeRegisterContextLinux_arm.h" 13 14 #include "lldb/Core/DataBufferHeap.h" 15 #include "lldb/Core/Error.h" 16 #include "lldb/Core/RegisterValue.h" 17 18 #include "Plugins/Process/Utility/RegisterContextLinux_arm.h" 19 20 #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof (m_fpr)) 21 22 using namespace lldb; 23 using namespace lldb_private; 24 using namespace lldb_private::process_linux; 25 26 // arm general purpose registers. 27 static const uint32_t g_gpr_regnums_arm[] = 28 { 29 gpr_r0_arm, 30 gpr_r1_arm, 31 gpr_r2_arm, 32 gpr_r3_arm, 33 gpr_r4_arm, 34 gpr_r5_arm, 35 gpr_r6_arm, 36 gpr_r7_arm, 37 gpr_r8_arm, 38 gpr_r9_arm, 39 gpr_r10_arm, 40 gpr_r11_arm, 41 gpr_r12_arm, 42 gpr_sp_arm, 43 gpr_lr_arm, 44 gpr_pc_arm, 45 gpr_cpsr_arm, 46 LLDB_INVALID_REGNUM // register sets need to end with this flag 47 }; 48 static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == k_num_gpr_registers_arm, \ 49 "g_gpr_regnums_arm has wrong number of register infos"); 50 51 // arm floating point registers. 52 static const uint32_t g_fpu_regnums_arm[] = 53 { 54 fpu_s0_arm, 55 fpu_s1_arm, 56 fpu_s2_arm, 57 fpu_s3_arm, 58 fpu_s4_arm, 59 fpu_s5_arm, 60 fpu_s6_arm, 61 fpu_s7_arm, 62 fpu_s8_arm, 63 fpu_s9_arm, 64 fpu_s10_arm, 65 fpu_s11_arm, 66 fpu_s12_arm, 67 fpu_s13_arm, 68 fpu_s14_arm, 69 fpu_s15_arm, 70 fpu_s16_arm, 71 fpu_s17_arm, 72 fpu_s18_arm, 73 fpu_s19_arm, 74 fpu_s20_arm, 75 fpu_s21_arm, 76 fpu_s22_arm, 77 fpu_s23_arm, 78 fpu_s24_arm, 79 fpu_s25_arm, 80 fpu_s26_arm, 81 fpu_s27_arm, 82 fpu_s28_arm, 83 fpu_s29_arm, 84 fpu_s30_arm, 85 fpu_s31_arm, 86 fpu_fpscr_arm, 87 LLDB_INVALID_REGNUM // register sets need to end with this flag 88 }; 89 static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == k_num_fpr_registers_arm, \ 90 "g_fpu_regnums_arm has wrong number of register infos"); 91 92 namespace { 93 // Number of register sets provided by this context. 94 enum 95 { 96 k_num_register_sets = 2 97 }; 98 } 99 100 // Register sets for arm. 101 static const RegisterSet 102 g_reg_sets_arm[k_num_register_sets] = 103 { 104 { "General Purpose Registers", "gpr", k_num_gpr_registers_arm, g_gpr_regnums_arm }, 105 { "Floating Point Registers", "fpu", k_num_fpr_registers_arm, g_fpu_regnums_arm } 106 }; 107 108 NativeRegisterContextLinux* 109 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, 110 NativeThreadProtocol &native_thread, 111 uint32_t concrete_frame_idx) 112 { 113 return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); 114 } 115 116 NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm (const ArchSpec& target_arch, 117 NativeThreadProtocol &native_thread, 118 uint32_t concrete_frame_idx) : 119 NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm(target_arch)) 120 { 121 switch (target_arch.GetMachine()) 122 { 123 case llvm::Triple::arm: 124 m_reg_info.num_registers = k_num_registers_arm; 125 m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; 126 m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; 127 m_reg_info.last_gpr = k_last_gpr_arm; 128 m_reg_info.first_fpr = k_first_fpr_arm; 129 m_reg_info.last_fpr = k_last_fpr_arm; 130 m_reg_info.first_fpr_v = fpu_s0_arm; 131 m_reg_info.last_fpr_v = fpu_s31_arm; 132 m_reg_info.gpr_flags = gpr_cpsr_arm; 133 break; 134 default: 135 assert(false && "Unhandled target architecture."); 136 break; 137 } 138 139 ::memset(&m_fpr, 0, sizeof (m_fpr)); 140 ::memset(&m_gpr_arm, 0, sizeof (m_gpr_arm)); 141 } 142 143 uint32_t 144 NativeRegisterContextLinux_arm::GetRegisterSetCount () const 145 { 146 return k_num_register_sets; 147 } 148 149 uint32_t 150 NativeRegisterContextLinux_arm::GetUserRegisterCount() const 151 { 152 uint32_t count = 0; 153 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 154 count += g_reg_sets_arm[set_index].num_registers; 155 return count; 156 } 157 158 const RegisterSet * 159 NativeRegisterContextLinux_arm::GetRegisterSet (uint32_t set_index) const 160 { 161 if (set_index < k_num_register_sets) 162 return &g_reg_sets_arm[set_index]; 163 164 return nullptr; 165 } 166 167 Error 168 NativeRegisterContextLinux_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 169 { 170 Error error; 171 172 if (!reg_info) 173 { 174 error.SetErrorString ("reg_info NULL"); 175 return error; 176 } 177 178 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 179 180 if (IsFPR(reg)) 181 { 182 error = ReadFPR(); 183 if (error.Fail()) 184 return error; 185 } 186 else 187 { 188 uint32_t full_reg = reg; 189 bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 190 191 if (is_subreg) 192 { 193 // Read the full aligned 64-bit register. 194 full_reg = reg_info->invalidate_regs[0]; 195 } 196 197 error = ReadRegisterRaw(full_reg, reg_value); 198 199 if (error.Success ()) 200 { 201 // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 202 if (is_subreg && (reg_info->byte_offset & 0x1)) 203 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 204 205 // If our return byte size was greater than the return value reg size, then 206 // use the type specified by reg_info rather than the uint64_t default 207 if (reg_value.GetByteSize() > reg_info->byte_size) 208 reg_value.SetType(reg_info); 209 } 210 return error; 211 } 212 213 // Get pointer to m_fpr variable and set the data from it. 214 assert (reg_info->byte_offset < sizeof m_fpr); 215 uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; 216 switch (reg_info->byte_size) 217 { 218 case 2: 219 reg_value.SetUInt16(*(uint16_t *)src); 220 break; 221 case 4: 222 reg_value.SetUInt32(*(uint32_t *)src); 223 break; 224 case 8: 225 reg_value.SetUInt64(*(uint64_t *)src); 226 break; 227 default: 228 assert(false && "Unhandled data size."); 229 error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); 230 break; 231 } 232 233 return error; 234 } 235 236 Error 237 NativeRegisterContextLinux_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 238 { 239 if (!reg_info) 240 return Error ("reg_info NULL"); 241 242 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 243 if (reg_index == LLDB_INVALID_REGNUM) 244 return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 245 246 if (IsGPR(reg_index)) 247 return WriteRegisterRaw(reg_index, reg_value); 248 249 if (IsFPR(reg_index)) 250 { 251 // Get pointer to m_fpr variable and set the data to it. 252 assert (reg_info->byte_offset < sizeof(m_fpr)); 253 uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; 254 switch (reg_info->byte_size) 255 { 256 case 2: 257 *(uint16_t *)dst = reg_value.GetAsUInt16(); 258 break; 259 case 4: 260 *(uint32_t *)dst = reg_value.GetAsUInt32(); 261 break; 262 case 8: 263 *(uint64_t *)dst = reg_value.GetAsUInt64(); 264 break; 265 default: 266 assert(false && "Unhandled data size."); 267 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 268 } 269 270 Error error = WriteFPR(); 271 if (error.Fail()) 272 return error; 273 274 return Error (); 275 } 276 277 return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 278 } 279 280 Error 281 NativeRegisterContextLinux_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 282 { 283 Error error; 284 285 data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 286 if (!data_sp) 287 return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, (uint64_t)REG_CONTEXT_SIZE); 288 289 error = ReadGPR(); 290 if (error.Fail()) 291 return error; 292 293 error = ReadFPR(); 294 if (error.Fail()) 295 return error; 296 297 uint8_t *dst = data_sp->GetBytes (); 298 if (dst == nullptr) 299 { 300 error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", (uint64_t)REG_CONTEXT_SIZE); 301 return error; 302 } 303 304 ::memcpy (dst, &m_gpr_arm, GetGPRSize()); 305 dst += GetGPRSize(); 306 ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 307 308 return error; 309 } 310 311 Error 312 NativeRegisterContextLinux_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 313 { 314 Error error; 315 316 if (!data_sp) 317 { 318 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 319 return error; 320 } 321 322 if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 323 { 324 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, (uint64_t)REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 325 return error; 326 } 327 328 329 uint8_t *src = data_sp->GetBytes (); 330 if (src == nullptr) 331 { 332 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 333 return error; 334 } 335 ::memcpy (&m_gpr_arm, src, GetRegisterInfoInterface ().GetGPRSize ()); 336 337 error = WriteGPR(); 338 if (error.Fail()) 339 return error; 340 341 src += GetRegisterInfoInterface ().GetGPRSize (); 342 ::memcpy (&m_fpr, src, sizeof(m_fpr)); 343 344 error = WriteFPR(); 345 if (error.Fail()) 346 return error; 347 348 return error; 349 } 350 351 bool 352 NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const 353 { 354 return reg <= m_reg_info.last_gpr; // GPR's come first. 355 } 356 357 bool 358 NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const 359 { 360 return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 361 } 362 363 #endif // defined(__arm__) 364