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