1 //===-- NativeRegisterContextLinux_arm64.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_arm64.h" 11 12 #include "lldb/lldb-private-forward.h" 13 #include "lldb/Core/DataBufferHeap.h" 14 #include "lldb/Core/Error.h" 15 #include "lldb/Core/RegisterValue.h" 16 #include "lldb/Host/common/NativeProcessProtocol.h" 17 #include "lldb/Host/common/NativeThreadProtocol.h" 18 #include "Plugins/Process/Linux/NativeProcessLinux.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 // ARM64 general purpose registers. 27 static const uint32_t g_gpr_regnums_arm64[] = 28 { 29 gpr_x0_arm64, 30 gpr_x1_arm64, 31 gpr_x2_arm64, 32 gpr_x3_arm64, 33 gpr_x4_arm64, 34 gpr_x5_arm64, 35 gpr_x6_arm64, 36 gpr_x7_arm64, 37 gpr_x8_arm64, 38 gpr_x9_arm64, 39 gpr_x10_arm64, 40 gpr_x11_arm64, 41 gpr_x12_arm64, 42 gpr_x13_arm64, 43 gpr_x14_arm64, 44 gpr_x15_arm64, 45 gpr_x16_arm64, 46 gpr_x17_arm64, 47 gpr_x18_arm64, 48 gpr_x19_arm64, 49 gpr_x20_arm64, 50 gpr_x21_arm64, 51 gpr_x22_arm64, 52 gpr_x23_arm64, 53 gpr_x24_arm64, 54 gpr_x25_arm64, 55 gpr_x26_arm64, 56 gpr_x27_arm64, 57 gpr_x28_arm64, 58 gpr_fp_arm64, 59 gpr_lr_arm64, 60 gpr_sp_arm64, 61 gpr_pc_arm64, 62 gpr_cpsr_arm64, 63 LLDB_INVALID_REGNUM // register sets need to end with this flag 64 }; 65 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ 66 "g_gpr_regnums_arm64 has wrong number of register infos"); 67 68 // ARM64 floating point registers. 69 static const uint32_t g_fpu_regnums_arm64[] = 70 { 71 fpu_v0_arm64, 72 fpu_v1_arm64, 73 fpu_v2_arm64, 74 fpu_v3_arm64, 75 fpu_v4_arm64, 76 fpu_v5_arm64, 77 fpu_v6_arm64, 78 fpu_v7_arm64, 79 fpu_v8_arm64, 80 fpu_v9_arm64, 81 fpu_v10_arm64, 82 fpu_v11_arm64, 83 fpu_v12_arm64, 84 fpu_v13_arm64, 85 fpu_v14_arm64, 86 fpu_v15_arm64, 87 fpu_v16_arm64, 88 fpu_v17_arm64, 89 fpu_v18_arm64, 90 fpu_v19_arm64, 91 fpu_v20_arm64, 92 fpu_v21_arm64, 93 fpu_v22_arm64, 94 fpu_v23_arm64, 95 fpu_v24_arm64, 96 fpu_v25_arm64, 97 fpu_v26_arm64, 98 fpu_v27_arm64, 99 fpu_v28_arm64, 100 fpu_v29_arm64, 101 fpu_v30_arm64, 102 fpu_v31_arm64, 103 fpu_fpsr_arm64, 104 fpu_fpcr_arm64, 105 LLDB_INVALID_REGNUM // register sets need to end with this flag 106 }; 107 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ 108 "g_fpu_regnums_arm64 has wrong number of register infos"); 109 110 namespace { 111 // Number of register sets provided by this context. 112 enum 113 { 114 k_num_register_sets = 2 115 }; 116 } 117 118 // Register sets for ARM64. 119 static const RegisterSet 120 g_reg_sets_arm64[k_num_register_sets] = 121 { 122 { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, 123 { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } 124 }; 125 126 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 ( 127 NativeThreadProtocol &native_thread, 128 uint32_t concrete_frame_idx, 129 RegisterInfoInterface *reg_info_interface_p) : 130 NativeRegisterContextRegisterInfo (native_thread, concrete_frame_idx, reg_info_interface_p) 131 { 132 switch (reg_info_interface_p->m_target_arch.GetMachine()) 133 { 134 case llvm::Triple::aarch64: 135 m_reg_info.num_registers = k_num_registers_arm64; 136 m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; 137 m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; 138 m_reg_info.last_gpr = k_last_gpr_arm64; 139 m_reg_info.first_fpr = k_first_fpr_arm64; 140 m_reg_info.last_fpr = k_last_fpr_arm64; 141 m_reg_info.first_fpr_v = fpu_v0_arm64; 142 m_reg_info.last_fpr_v = fpu_v31_arm64; 143 m_reg_info.gpr_flags = gpr_cpsr_arm64; 144 break; 145 default: 146 assert(false && "Unhandled target architecture."); 147 break; 148 } 149 150 ::memset(&m_fpr, 0, sizeof (m_fpr)); 151 ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64)); 152 } 153 154 uint32_t 155 NativeRegisterContextLinux_arm64::GetRegisterSetCount () const 156 { 157 return k_num_register_sets; 158 } 159 160 const RegisterSet * 161 NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const 162 { 163 if (set_index < k_num_register_sets) 164 return &g_reg_sets_arm64[set_index]; 165 166 return nullptr; 167 } 168 169 Error 170 NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 171 { 172 Error error; 173 174 if (!reg_info) 175 { 176 error.SetErrorString ("reg_info NULL"); 177 return error; 178 } 179 180 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 181 182 if (IsFPR(reg)) 183 { 184 if (!ReadFPR()) 185 { 186 error.SetErrorString ("failed to read floating point register"); 187 return error; 188 } 189 } 190 else 191 { 192 uint32_t full_reg = reg; 193 bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 194 195 if (is_subreg) 196 { 197 // Read the full aligned 64-bit register. 198 full_reg = reg_info->invalidate_regs[0]; 199 } 200 201 error = ReadRegisterRaw(full_reg, reg_value); 202 203 if (error.Success ()) 204 { 205 // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 206 if (is_subreg && (reg_info->byte_offset & 0x1)) 207 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 208 209 // If our return byte size was greater than the return value reg size, then 210 // use the type specified by reg_info rather than the uint64_t default 211 if (reg_value.GetByteSize() > reg_info->byte_size) 212 reg_value.SetType(reg_info); 213 } 214 return error; 215 } 216 217 // Get pointer to m_fpr variable and set the data from it. 218 assert (reg_info->byte_offset < sizeof m_fpr); 219 uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; 220 switch (reg_info->byte_size) 221 { 222 case 2: 223 reg_value.SetUInt16(*(uint16_t *)src); 224 break; 225 case 4: 226 reg_value.SetUInt32(*(uint32_t *)src); 227 break; 228 case 8: 229 reg_value.SetUInt64(*(uint64_t *)src); 230 break; 231 default: 232 assert(false && "Unhandled data size."); 233 error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); 234 break; 235 } 236 237 return error; 238 } 239 240 Error 241 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 242 { 243 if (!reg_info) 244 return Error ("reg_info NULL"); 245 246 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 247 if (reg_index == LLDB_INVALID_REGNUM) 248 return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 249 250 if (IsGPR(reg_index)) 251 return WriteRegisterRaw(reg_index, reg_value); 252 253 if (IsFPR(reg_index)) 254 { 255 // Get pointer to m_fpr variable and set the data to it. 256 assert (reg_info->byte_offset < sizeof(m_fpr)); 257 uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; 258 switch (reg_info->byte_size) 259 { 260 case 2: 261 *(uint16_t *)dst = reg_value.GetAsUInt16(); 262 break; 263 case 4: 264 *(uint32_t *)dst = reg_value.GetAsUInt32(); 265 break; 266 case 8: 267 *(uint64_t *)dst = reg_value.GetAsUInt64(); 268 break; 269 default: 270 assert(false && "Unhandled data size."); 271 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 272 } 273 274 if (!WriteFPR()) 275 { 276 return Error ("NativeRegisterContextLinux_arm64::WriteRegister: WriteFPR failed"); 277 } 278 279 return Error (); 280 } 281 282 return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 283 } 284 285 Error 286 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 287 { 288 Error error; 289 290 data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 291 if (!data_sp) 292 return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 293 294 if (!ReadGPR ()) 295 { 296 error.SetErrorString ("ReadGPR() failed"); 297 return error; 298 } 299 300 if (!ReadFPR ()) 301 { 302 error.SetErrorString ("ReadFPR() failed"); 303 return error; 304 } 305 306 uint8_t *dst = data_sp->GetBytes (); 307 if (dst == nullptr) 308 { 309 error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 310 return error; 311 } 312 313 ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 314 dst += GetGPRSize(); 315 ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 316 317 return error; 318 } 319 320 Error 321 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 322 { 323 Error error; 324 325 if (!data_sp) 326 { 327 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 328 return error; 329 } 330 331 if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 332 { 333 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 334 return error; 335 } 336 337 338 uint8_t *src = data_sp->GetBytes (); 339 if (src == nullptr) 340 { 341 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 342 return error; 343 } 344 ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 345 346 if (!WriteGPR ()) 347 { 348 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteGPR() failed", __FUNCTION__); 349 return error; 350 } 351 352 src += GetRegisterInfoInterface ().GetGPRSize (); 353 ::memcpy (&m_fpr, src, sizeof(m_fpr)); 354 355 if (!WriteFPR ()) 356 { 357 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s WriteFPR() failed", __FUNCTION__); 358 return error; 359 } 360 361 return error; 362 } 363 364 Error 365 NativeRegisterContextLinux_arm64::WriteRegisterRaw (uint32_t reg_index, const RegisterValue ®_value) 366 { 367 Error error; 368 369 uint32_t reg_to_write = reg_index; 370 RegisterValue value_to_write = reg_value; 371 372 // Check if this is a subregister of a full register. 373 const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index); 374 if (reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) 375 { 376 RegisterValue full_value; 377 uint32_t full_reg = reg_info->invalidate_regs[0]; 378 const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg); 379 380 // Read the full register. 381 error = ReadRegister(full_reg_info, full_value); 382 if (error.Fail ()) 383 return error; 384 385 lldb::ByteOrder byte_order = GetByteOrder(); 386 uint8_t dst[RegisterValue::kMaxRegisterByteSize]; 387 388 // Get the bytes for the full register. 389 const uint32_t dest_size = full_value.GetAsMemoryData (full_reg_info, 390 dst, 391 sizeof(dst), 392 byte_order, 393 error); 394 if (error.Success() && dest_size) 395 { 396 uint8_t src[RegisterValue::kMaxRegisterByteSize]; 397 398 // Get the bytes for the source data. 399 const uint32_t src_size = reg_value.GetAsMemoryData (reg_info, src, sizeof(src), byte_order, error); 400 if (error.Success() && src_size && (src_size < dest_size)) 401 { 402 // Copy the src bytes to the destination. 403 memcpy (dst + (reg_info->byte_offset & 0x1), src, src_size); 404 // Set this full register as the value to write. 405 value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order); 406 value_to_write.SetType(full_reg_info); 407 reg_to_write = full_reg; 408 } 409 } 410 } 411 412 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 413 if (!process_sp) 414 { 415 error.SetErrorString ("NativeProcessProtocol is NULL"); 416 return error; 417 } 418 419 const RegisterInfo *const register_to_write_info_p = GetRegisterInfoAtIndex (reg_to_write); 420 assert (register_to_write_info_p && "register to write does not have valid RegisterInfo"); 421 if (!register_to_write_info_p) 422 { 423 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_arm64::%s failed to get RegisterInfo for write register index %" PRIu32, __FUNCTION__, reg_to_write); 424 return error; 425 } 426 427 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 428 return process_p->WriteRegisterValue(m_thread.GetID(), 429 register_to_write_info_p->byte_offset, 430 register_to_write_info_p->name, 431 value_to_write); 432 } 433 434 Error 435 NativeRegisterContextLinux_arm64::ReadRegisterRaw (uint32_t reg_index, RegisterValue ®_value) 436 { 437 Error error; 438 const RegisterInfo *const reg_info = GetRegisterInfoAtIndex (reg_index); 439 if (!reg_info) 440 { 441 error.SetErrorStringWithFormat ("register %" PRIu32 " not found", reg_index); 442 return error; 443 } 444 445 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 446 if (!process_sp) 447 { 448 error.SetErrorString ("NativeProcessProtocol is NULL"); 449 return error; 450 } 451 452 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 453 return process_p->ReadRegisterValue(m_thread.GetID(), 454 reg_info->byte_offset, 455 reg_info->name, 456 reg_info->byte_size, 457 reg_value); 458 } 459 460 bool 461 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 462 { 463 return reg <= m_reg_info.last_gpr; // GPR's come first. 464 } 465 466 bool 467 NativeRegisterContextLinux_arm64::ReadGPR() 468 { 469 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 470 if (!process_sp) 471 return false; 472 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 473 474 return process_p->ReadGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success(); 475 } 476 477 bool 478 NativeRegisterContextLinux_arm64::WriteGPR() 479 { 480 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 481 if (!process_sp) 482 return false; 483 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 484 485 return process_p->WriteGPR (m_thread.GetID (), &m_gpr_arm64, GetRegisterInfoInterface ().GetGPRSize ()).Success(); 486 } 487 488 bool 489 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 490 { 491 return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 492 } 493 494 bool 495 NativeRegisterContextLinux_arm64::ReadFPR () 496 { 497 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 498 if (!process_sp) 499 return false; 500 501 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 502 return process_p->ReadFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success(); 503 } 504 505 bool 506 NativeRegisterContextLinux_arm64::WriteFPR () 507 { 508 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 509 if (!process_sp) 510 return false; 511 512 NativeProcessLinux *const process_p = reinterpret_cast<NativeProcessLinux*> (process_sp.get ()); 513 return process_p->WriteFPR (m_thread.GetID (), &m_fpr, sizeof (m_fpr)).Success(); 514 } 515 516 lldb::ByteOrder 517 NativeRegisterContextLinux_arm64::GetByteOrder() const 518 { 519 // Get the target process whose privileged thread was used for the register read. 520 lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; 521 522 NativeProcessProtocolSP process_sp (m_thread.GetProcess ()); 523 if (!process_sp) 524 return byte_order; 525 526 if (!process_sp->GetByteOrder (byte_order)) 527 { 528 // FIXME log here 529 } 530 531 return byte_order; 532 } 533 534 size_t 535 NativeRegisterContextLinux_arm64::GetGPRSize() const 536 { 537 return GetRegisterInfoInterface().GetGPRSize(); 538 } 539