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