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 &reg : 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 &reg : 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 &reg_info,
76                                                   DataExtractor &reg_data,
77                                                   RegisterContext &reg_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