1 //===-- ArchitectureAArch64.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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Plugins/Architecture/AArch64/ArchitectureAArch64.h" 10 #include "lldb/Core/PluginManager.h" 11 #include "lldb/Target/RegisterContext.h" 12 #include "lldb/Utility/ArchSpec.h" 13 #include "lldb/Utility/DataBufferHeap.h" 14 #include "lldb/Utility/DataExtractor.h" 15 16 using namespace lldb_private; 17 using namespace lldb; 18 19 LLDB_PLUGIN_DEFINE(ArchitectureAArch64) 20 21 void ArchitectureAArch64::Initialize() { 22 PluginManager::RegisterPlugin(GetPluginNameStatic(), 23 "AArch64-specific algorithms", 24 &ArchitectureAArch64::Create); 25 } 26 27 void ArchitectureAArch64::Terminate() { 28 PluginManager::UnregisterPlugin(&ArchitectureAArch64::Create); 29 } 30 31 std::unique_ptr<Architecture> 32 ArchitectureAArch64::Create(const ArchSpec &arch) { 33 auto machine = arch.GetMachine(); 34 if (machine != llvm::Triple::aarch64 && machine != llvm::Triple::aarch64_be && 35 machine != llvm::Triple::aarch64_32) { 36 return nullptr; 37 } 38 return std::unique_ptr<Architecture>(new ArchitectureAArch64()); 39 } 40 41 static void 42 UpdateARM64SVERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, 43 uint64_t vg) { 44 // SVE Z register size is vg x 8 bytes. 45 uint32_t z_reg_byte_size = vg * 8; 46 47 // SVE vector length has changed, accordingly set size of Z, P and FFR 48 // registers. Also invalidate register offsets it will be recalculated 49 // after SVE register size update. 50 for (auto ® : regs) { 51 if (reg.value_regs == nullptr) { 52 if (reg.name[0] == 'z' && isdigit(reg.name[1])) 53 reg.byte_size = z_reg_byte_size; 54 else if (reg.name[0] == 'p' && isdigit(reg.name[1])) 55 reg.byte_size = vg; 56 else if (strcmp(reg.name, "ffr") == 0) 57 reg.byte_size = vg; 58 } 59 reg.byte_offset = LLDB_INVALID_INDEX32; 60 } 61 } 62 63 static void 64 UpdateARM64SMERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, 65 uint64_t svg) { 66 for (auto ® : regs) { 67 if (strcmp(reg.name, "za") == 0) { 68 // ZA is a register with size (svg*8) * (svg*8). A square essentially. 69 reg.byte_size = (svg * 8) * (svg * 8); 70 } 71 reg.byte_offset = LLDB_INVALID_INDEX32; 72 } 73 } 74 75 bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo ®_info, 76 DataExtractor ®_data, 77 RegisterContext ®_context 78 79 ) const { 80 // Once we start to reconfigure registers, we cannot read any of them. 81 // So we must read VG and SVG up front. 82 83 const uint64_t fail_value = LLDB_INVALID_ADDRESS; 84 std::optional<uint64_t> vg_reg_value; 85 const RegisterInfo *vg_reg_info = reg_info.GetRegisterInfo("vg"); 86 if (vg_reg_info) { 87 uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB]; 88 uint64_t reg_value = 89 reg_context.ReadRegisterAsUnsigned(vg_reg_num, fail_value); 90 if (reg_value != fail_value && reg_value <= 32) 91 vg_reg_value = reg_value; 92 } 93 94 std::optional<uint64_t> svg_reg_value; 95 const RegisterInfo *svg_reg_info = reg_info.GetRegisterInfo("svg"); 96 if (svg_reg_info) { 97 uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB]; 98 uint64_t reg_value = 99 reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value); 100 if (reg_value != fail_value && reg_value <= 32) 101 svg_reg_value = reg_value; 102 } 103 104 if (!vg_reg_value && !svg_reg_value) 105 return false; 106 107 auto regs = reg_info.registers<DynamicRegisterInfo::reg_collection_range>(); 108 if (vg_reg_value) 109 UpdateARM64SVERegistersInfos(regs, *vg_reg_value); 110 if (svg_reg_value) 111 UpdateARM64SMERegistersInfos(regs, *svg_reg_value); 112 113 // At this point if we have updated any registers, their offsets will all be 114 // invalid. If we did, we need to update them all. 115 reg_info.ConfigureOffsets(); 116 // From here we are able to read registers again. 117 118 // Make a heap based buffer that is big enough to store all registers 119 reg_data.SetData( 120 std::make_shared<DataBufferHeap>(reg_info.GetRegisterDataByteSize(), 0)); 121 reg_data.SetByteOrder(reg_context.GetByteOrder()); 122 123 return true; 124 } 125