647 lines · cpp
1//===-- NativeRegisterContextWindows_arm.cpp ------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#if defined(__arm__) || defined(_M_ARM)10 11#include "NativeRegisterContextWindows_arm.h"12#include "NativeThreadWindows.h"13#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h"14#include "ProcessWindowsLog.h"15#include "lldb/Host/HostInfo.h"16#include "lldb/Host/HostThread.h"17#include "lldb/Host/windows/HostThreadWindows.h"18#include "lldb/Host/windows/windows.h"19 20#include "lldb/Utility/Log.h"21#include "lldb/Utility/RegisterValue.h"22#include "llvm/ADT/STLExtras.h"23 24using namespace lldb;25using namespace lldb_private;26 27#define REG_CONTEXT_SIZE sizeof(::CONTEXT)28 29namespace {30static const uint32_t g_gpr_regnums_arm[] = {31 gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm,32 gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm,33 gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm,34 gpr_pc_arm, gpr_cpsr_arm,35 LLDB_INVALID_REGNUM // Register set must be terminated with this flag36};37static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) ==38 k_num_gpr_registers_arm,39 "g_gpr_regnums_arm has wrong number of register infos");40 41static const uint32_t g_fpr_regnums_arm[] = {42 fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm,43 fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm,44 fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm,45 fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm,46 fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm,47 fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm,48 fpu_s30_arm, fpu_s31_arm,49 50 fpu_d0_arm, fpu_d1_arm, fpu_d2_arm, fpu_d3_arm, fpu_d4_arm,51 fpu_d5_arm, fpu_d6_arm, fpu_d7_arm, fpu_d8_arm, fpu_d9_arm,52 fpu_d10_arm, fpu_d11_arm, fpu_d12_arm, fpu_d13_arm, fpu_d14_arm,53 fpu_d15_arm, fpu_d16_arm, fpu_d17_arm, fpu_d18_arm, fpu_d19_arm,54 fpu_d20_arm, fpu_d21_arm, fpu_d22_arm, fpu_d23_arm, fpu_d24_arm,55 fpu_d25_arm, fpu_d26_arm, fpu_d27_arm, fpu_d28_arm, fpu_d29_arm,56 fpu_d30_arm, fpu_d31_arm,57 58 fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm,59 fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm,60 fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm,61 fpu_q15_arm,62 63 fpu_fpscr_arm,64 LLDB_INVALID_REGNUM // Register set must be terminated with this flag65};66static_assert(((sizeof g_fpr_regnums_arm / sizeof g_fpr_regnums_arm[0]) - 1) ==67 k_num_fpr_registers_arm,68 "g_fpu_regnums_arm has wrong number of register infos");69 70static const RegisterSet g_reg_sets_arm[] = {71 {"General Purpose Registers", "gpr", std::size(g_gpr_regnums_arm) - 1,72 g_gpr_regnums_arm},73 {"Floating Point Registers", "fpr", std::size(g_fpr_regnums_arm) - 1,74 g_fpr_regnums_arm},75};76 77enum { k_num_register_sets = 2 };78 79} // namespace80 81static RegisterInfoInterface *82CreateRegisterInfoInterface(const ArchSpec &target_arch) {83 assert((HostInfo::GetArchitecture().GetAddressByteSize() == 4) &&84 "Register setting path assumes this is a 32-bit host");85 return new RegisterInfoPOSIX_arm(target_arch);86}87 88static Status GetThreadContextHelper(lldb::thread_t thread_handle,89 PCONTEXT context_ptr,90 const DWORD control_flag) {91 Log *log = GetLog(WindowsLog::Registers);92 Status error;93 94 memset(context_ptr, 0, sizeof(::CONTEXT));95 context_ptr->ContextFlags = control_flag;96 if (!::GetThreadContext(thread_handle, context_ptr)) {97 error = Status(GetLastError(), eErrorTypeWin32);98 LLDB_LOG(log, "{0} GetThreadContext failed with error {1}", __FUNCTION__,99 error);100 return error;101 }102 return Status();103}104 105static Status SetThreadContextHelper(lldb::thread_t thread_handle,106 PCONTEXT context_ptr) {107 Log *log = GetLog(WindowsLog::Registers);108 Status error;109 // It's assumed that the thread has stopped.110 if (!::SetThreadContext(thread_handle, context_ptr)) {111 error = Status(GetLastError(), eErrorTypeWin32);112 LLDB_LOG(log, "{0} SetThreadContext failed with error {1}", __FUNCTION__,113 error);114 return error;115 }116 return Status();117}118 119std::unique_ptr<NativeRegisterContextWindows>120NativeRegisterContextWindows::CreateHostNativeRegisterContextWindows(121 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) {122 // TODO: Register context for a WoW64 application?123 124 // Register context for a native 64-bit application.125 return std::make_unique<NativeRegisterContextWindows_arm>(target_arch,126 native_thread);127}128 129NativeRegisterContextWindows_arm::NativeRegisterContextWindows_arm(130 const ArchSpec &target_arch, NativeThreadProtocol &native_thread)131 : NativeRegisterContextRegisterInfo(132 native_thread, CreateRegisterInfoInterface(target_arch)) {}133 134bool NativeRegisterContextWindows_arm::IsGPR(uint32_t reg_index) const {135 return (reg_index >= k_first_gpr_arm && reg_index <= k_last_gpr_arm);136}137 138bool NativeRegisterContextWindows_arm::IsFPR(uint32_t reg_index) const {139 return (reg_index >= k_first_fpr_arm && reg_index <= k_last_fpr_arm);140}141 142uint32_t NativeRegisterContextWindows_arm::GetRegisterSetCount() const {143 return k_num_register_sets;144}145 146const RegisterSet *147NativeRegisterContextWindows_arm::GetRegisterSet(uint32_t set_index) const {148 if (set_index >= k_num_register_sets)149 return nullptr;150 return &g_reg_sets_arm[set_index];151}152 153Status NativeRegisterContextWindows_arm::GPRRead(const uint32_t reg,154 RegisterValue ®_value) {155 ::CONTEXT tls_context;156 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER;157 Status error =158 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag);159 if (error.Fail())160 return error;161 162 switch (reg) {163 case gpr_r0_arm:164 reg_value.SetUInt32(tls_context.R0);165 break;166 case gpr_r1_arm:167 reg_value.SetUInt32(tls_context.R1);168 break;169 case gpr_r2_arm:170 reg_value.SetUInt32(tls_context.R2);171 break;172 case gpr_r3_arm:173 reg_value.SetUInt32(tls_context.R3);174 break;175 case gpr_r4_arm:176 reg_value.SetUInt32(tls_context.R4);177 break;178 case gpr_r5_arm:179 reg_value.SetUInt32(tls_context.R5);180 break;181 case gpr_r6_arm:182 reg_value.SetUInt32(tls_context.R6);183 break;184 case gpr_r7_arm:185 reg_value.SetUInt32(tls_context.R7);186 break;187 case gpr_r8_arm:188 reg_value.SetUInt32(tls_context.R8);189 break;190 case gpr_r9_arm:191 reg_value.SetUInt32(tls_context.R9);192 break;193 case gpr_r10_arm:194 reg_value.SetUInt32(tls_context.R10);195 break;196 case gpr_r11_arm:197 reg_value.SetUInt32(tls_context.R11);198 break;199 case gpr_r12_arm:200 reg_value.SetUInt32(tls_context.R12);201 break;202 case gpr_sp_arm:203 reg_value.SetUInt32(tls_context.Sp);204 break;205 case gpr_lr_arm:206 reg_value.SetUInt32(tls_context.Lr);207 break;208 case gpr_pc_arm:209 reg_value.SetUInt32(tls_context.Pc);210 break;211 case gpr_cpsr_arm:212 reg_value.SetUInt32(tls_context.Cpsr);213 break;214 }215 216 return error;217}218 219Status220NativeRegisterContextWindows_arm::GPRWrite(const uint32_t reg,221 const RegisterValue ®_value) {222 ::CONTEXT tls_context;223 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_INTEGER;224 auto thread_handle = GetThreadHandle();225 Status error =226 GetThreadContextHelper(thread_handle, &tls_context, context_flag);227 if (error.Fail())228 return error;229 230 switch (reg) {231 case gpr_r0_arm:232 tls_context.R0 = reg_value.GetAsUInt32();233 break;234 case gpr_r1_arm:235 tls_context.R1 = reg_value.GetAsUInt32();236 break;237 case gpr_r2_arm:238 tls_context.R2 = reg_value.GetAsUInt32();239 break;240 case gpr_r3_arm:241 tls_context.R3 = reg_value.GetAsUInt32();242 break;243 case gpr_r4_arm:244 tls_context.R4 = reg_value.GetAsUInt32();245 break;246 case gpr_r5_arm:247 tls_context.R5 = reg_value.GetAsUInt32();248 break;249 case gpr_r6_arm:250 tls_context.R6 = reg_value.GetAsUInt32();251 break;252 case gpr_r7_arm:253 tls_context.R7 = reg_value.GetAsUInt32();254 break;255 case gpr_r8_arm:256 tls_context.R8 = reg_value.GetAsUInt32();257 break;258 case gpr_r9_arm:259 tls_context.R9 = reg_value.GetAsUInt32();260 break;261 case gpr_r10_arm:262 tls_context.R10 = reg_value.GetAsUInt32();263 break;264 case gpr_r11_arm:265 tls_context.R11 = reg_value.GetAsUInt32();266 break;267 case gpr_r12_arm:268 tls_context.R12 = reg_value.GetAsUInt32();269 break;270 case gpr_sp_arm:271 tls_context.Sp = reg_value.GetAsUInt32();272 break;273 case gpr_lr_arm:274 tls_context.Lr = reg_value.GetAsUInt32();275 break;276 case gpr_pc_arm:277 tls_context.Pc = reg_value.GetAsUInt32();278 break;279 case gpr_cpsr_arm:280 tls_context.Cpsr = reg_value.GetAsUInt32();281 break;282 }283 284 return SetThreadContextHelper(thread_handle, &tls_context);285}286 287Status NativeRegisterContextWindows_arm::FPRRead(const uint32_t reg,288 RegisterValue ®_value) {289 ::CONTEXT tls_context;290 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT;291 Status error =292 GetThreadContextHelper(GetThreadHandle(), &tls_context, context_flag);293 if (error.Fail())294 return error;295 296 switch (reg) {297 case fpu_s0_arm:298 case fpu_s1_arm:299 case fpu_s2_arm:300 case fpu_s3_arm:301 case fpu_s4_arm:302 case fpu_s5_arm:303 case fpu_s6_arm:304 case fpu_s7_arm:305 case fpu_s8_arm:306 case fpu_s9_arm:307 case fpu_s10_arm:308 case fpu_s11_arm:309 case fpu_s12_arm:310 case fpu_s13_arm:311 case fpu_s14_arm:312 case fpu_s15_arm:313 case fpu_s16_arm:314 case fpu_s17_arm:315 case fpu_s18_arm:316 case fpu_s19_arm:317 case fpu_s20_arm:318 case fpu_s21_arm:319 case fpu_s22_arm:320 case fpu_s23_arm:321 case fpu_s24_arm:322 case fpu_s25_arm:323 case fpu_s26_arm:324 case fpu_s27_arm:325 case fpu_s28_arm:326 case fpu_s29_arm:327 case fpu_s30_arm:328 case fpu_s31_arm:329 reg_value.SetUInt32(tls_context.S[reg - fpu_s0_arm],330 RegisterValue::eTypeFloat);331 break;332 333 case fpu_d0_arm:334 case fpu_d1_arm:335 case fpu_d2_arm:336 case fpu_d3_arm:337 case fpu_d4_arm:338 case fpu_d5_arm:339 case fpu_d6_arm:340 case fpu_d7_arm:341 case fpu_d8_arm:342 case fpu_d9_arm:343 case fpu_d10_arm:344 case fpu_d11_arm:345 case fpu_d12_arm:346 case fpu_d13_arm:347 case fpu_d14_arm:348 case fpu_d15_arm:349 case fpu_d16_arm:350 case fpu_d17_arm:351 case fpu_d18_arm:352 case fpu_d19_arm:353 case fpu_d20_arm:354 case fpu_d21_arm:355 case fpu_d22_arm:356 case fpu_d23_arm:357 case fpu_d24_arm:358 case fpu_d25_arm:359 case fpu_d26_arm:360 case fpu_d27_arm:361 case fpu_d28_arm:362 case fpu_d29_arm:363 case fpu_d30_arm:364 case fpu_d31_arm:365 reg_value.SetUInt64(tls_context.D[reg - fpu_d0_arm],366 RegisterValue::eTypeDouble);367 break;368 369 case fpu_q0_arm:370 case fpu_q1_arm:371 case fpu_q2_arm:372 case fpu_q3_arm:373 case fpu_q4_arm:374 case fpu_q5_arm:375 case fpu_q6_arm:376 case fpu_q7_arm:377 case fpu_q8_arm:378 case fpu_q9_arm:379 case fpu_q10_arm:380 case fpu_q11_arm:381 case fpu_q12_arm:382 case fpu_q13_arm:383 case fpu_q14_arm:384 case fpu_q15_arm:385 reg_value.SetBytes(&tls_context.Q[reg - fpu_q0_arm], 16,386 endian::InlHostByteOrder());387 break;388 389 case fpu_fpscr_arm:390 reg_value.SetUInt32(tls_context.Fpscr);391 break;392 }393 394 return error;395}396 397Status398NativeRegisterContextWindows_arm::FPRWrite(const uint32_t reg,399 const RegisterValue ®_value) {400 ::CONTEXT tls_context;401 DWORD context_flag = CONTEXT_CONTROL | CONTEXT_FLOATING_POINT;402 auto thread_handle = GetThreadHandle();403 Status error =404 GetThreadContextHelper(thread_handle, &tls_context, context_flag);405 if (error.Fail())406 return error;407 408 switch (reg) {409 case fpu_s0_arm:410 case fpu_s1_arm:411 case fpu_s2_arm:412 case fpu_s3_arm:413 case fpu_s4_arm:414 case fpu_s5_arm:415 case fpu_s6_arm:416 case fpu_s7_arm:417 case fpu_s8_arm:418 case fpu_s9_arm:419 case fpu_s10_arm:420 case fpu_s11_arm:421 case fpu_s12_arm:422 case fpu_s13_arm:423 case fpu_s14_arm:424 case fpu_s15_arm:425 case fpu_s16_arm:426 case fpu_s17_arm:427 case fpu_s18_arm:428 case fpu_s19_arm:429 case fpu_s20_arm:430 case fpu_s21_arm:431 case fpu_s22_arm:432 case fpu_s23_arm:433 case fpu_s24_arm:434 case fpu_s25_arm:435 case fpu_s26_arm:436 case fpu_s27_arm:437 case fpu_s28_arm:438 case fpu_s29_arm:439 case fpu_s30_arm:440 case fpu_s31_arm:441 tls_context.S[reg - fpu_s0_arm] = reg_value.GetAsUInt32();442 break;443 444 case fpu_d0_arm:445 case fpu_d1_arm:446 case fpu_d2_arm:447 case fpu_d3_arm:448 case fpu_d4_arm:449 case fpu_d5_arm:450 case fpu_d6_arm:451 case fpu_d7_arm:452 case fpu_d8_arm:453 case fpu_d9_arm:454 case fpu_d10_arm:455 case fpu_d11_arm:456 case fpu_d12_arm:457 case fpu_d13_arm:458 case fpu_d14_arm:459 case fpu_d15_arm:460 case fpu_d16_arm:461 case fpu_d17_arm:462 case fpu_d18_arm:463 case fpu_d19_arm:464 case fpu_d20_arm:465 case fpu_d21_arm:466 case fpu_d22_arm:467 case fpu_d23_arm:468 case fpu_d24_arm:469 case fpu_d25_arm:470 case fpu_d26_arm:471 case fpu_d27_arm:472 case fpu_d28_arm:473 case fpu_d29_arm:474 case fpu_d30_arm:475 case fpu_d31_arm:476 tls_context.D[reg - fpu_d0_arm] = reg_value.GetAsUInt64();477 break;478 479 case fpu_q0_arm:480 case fpu_q1_arm:481 case fpu_q2_arm:482 case fpu_q3_arm:483 case fpu_q4_arm:484 case fpu_q5_arm:485 case fpu_q6_arm:486 case fpu_q7_arm:487 case fpu_q8_arm:488 case fpu_q9_arm:489 case fpu_q10_arm:490 case fpu_q11_arm:491 case fpu_q12_arm:492 case fpu_q13_arm:493 case fpu_q14_arm:494 case fpu_q15_arm:495 memcpy(&tls_context.Q[reg - fpu_q0_arm], reg_value.GetBytes(), 16);496 break;497 498 case fpu_fpscr_arm:499 tls_context.Fpscr = reg_value.GetAsUInt32();500 break;501 }502 503 return SetThreadContextHelper(thread_handle, &tls_context);504}505 506Status507NativeRegisterContextWindows_arm::ReadRegister(const RegisterInfo *reg_info,508 RegisterValue ®_value) {509 Status error;510 if (!reg_info) {511 error = Status::FromErrorString("reg_info NULL");512 return error;513 }514 515 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];516 if (reg == LLDB_INVALID_REGNUM) {517 // This is likely an internal register for lldb use only and should not be518 // directly queried.519 error = Status::FromErrorStringWithFormat(520 "register \"%s\" is an internal-only lldb "521 "register, cannot read directly",522 reg_info->name);523 return error;524 }525 526 if (IsGPR(reg))527 return GPRRead(reg, reg_value);528 529 if (IsFPR(reg))530 return FPRRead(reg, reg_value);531 532 return Status::FromErrorString("unimplemented");533}534 535Status NativeRegisterContextWindows_arm::WriteRegister(536 const RegisterInfo *reg_info, const RegisterValue ®_value) {537 Status error;538 539 if (!reg_info) {540 error = Status::FromErrorString("reg_info NULL");541 return error;542 }543 544 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];545 if (reg == LLDB_INVALID_REGNUM) {546 // This is likely an internal register for lldb use only and should not be547 // directly written.548 error = Status::FromErrorStringWithFormat(549 "register \"%s\" is an internal-only lldb "550 "register, cannot write directly",551 reg_info->name);552 return error;553 }554 555 if (IsGPR(reg))556 return GPRWrite(reg, reg_value);557 558 if (IsFPR(reg))559 return FPRWrite(reg, reg_value);560 561 return Status::FromErrorString("unimplemented");562}563 564Status NativeRegisterContextWindows_arm::ReadAllRegisterValues(565 lldb::WritableDataBufferSP &data_sp) {566 const size_t data_size = REG_CONTEXT_SIZE;567 data_sp = std::make_shared<DataBufferHeap>(data_size, 0);568 ::CONTEXT tls_context;569 Status error =570 GetThreadContextHelper(GetThreadHandle(), &tls_context, CONTEXT_ALL);571 if (error.Fail())572 return error;573 574 uint8_t *dst = data_sp->GetBytes();575 ::memcpy(dst, &tls_context, data_size);576 return error;577}578 579Status NativeRegisterContextWindows_arm::WriteAllRegisterValues(580 const lldb::DataBufferSP &data_sp) {581 Status error;582 const size_t data_size = REG_CONTEXT_SIZE;583 if (!data_sp) {584 error = Status::FromErrorStringWithFormat(585 "NativeRegisterContextWindows_arm::%s invalid data_sp provided",586 __FUNCTION__);587 return error;588 }589 590 if (data_sp->GetByteSize() != data_size) {591 error = Status::FromErrorStringWithFormatv(592 "data_sp contained mismatched data size, expected {0}, actual {1}",593 data_size, data_sp->GetByteSize());594 return error;595 }596 597 ::CONTEXT tls_context;598 memcpy(&tls_context, data_sp->GetBytes(), data_size);599 return SetThreadContextHelper(GetThreadHandle(), &tls_context);600}601 602Status NativeRegisterContextWindows_arm::IsWatchpointHit(uint32_t wp_index,603 bool &is_hit) {604 return Status::FromErrorString("unimplemented");605}606 607Status NativeRegisterContextWindows_arm::GetWatchpointHitIndex(608 uint32_t &wp_index, lldb::addr_t trap_addr) {609 return Status::FromErrorString("unimplemented");610}611 612Status NativeRegisterContextWindows_arm::IsWatchpointVacant(uint32_t wp_index,613 bool &is_vacant) {614 return Status::FromErrorString("unimplemented");615}616 617Status NativeRegisterContextWindows_arm::SetHardwareWatchpointWithIndex(618 lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {619 return Status::FromErrorString("unimplemented");620}621 622bool NativeRegisterContextWindows_arm::ClearHardwareWatchpoint(623 uint32_t wp_index) {624 return false;625}626 627Status NativeRegisterContextWindows_arm::ClearAllHardwareWatchpoints() {628 return Status::FromErrorString("unimplemented");629}630 631uint32_t NativeRegisterContextWindows_arm::SetHardwareWatchpoint(632 lldb::addr_t addr, size_t size, uint32_t watch_flags) {633 return LLDB_INVALID_INDEX32;634}635 636lldb::addr_t637NativeRegisterContextWindows_arm::GetWatchpointAddress(uint32_t wp_index) {638 return LLDB_INVALID_ADDRESS;639}640 641uint32_t NativeRegisterContextWindows_arm::NumSupportedHardwareWatchpoints() {642 // Not implemented643 return 0;644}645 646#endif // defined(__arm__) || defined(_M_ARM)647