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
16using namespace lldb_private;
17using namespace lldb;
18
19LLDB_PLUGIN_DEFINE(ArchitectureAArch64)
20
21void ArchitectureAArch64::Initialize() {
22 PluginManager::RegisterPlugin(name: GetPluginNameStatic(),
23 description: "AArch64-specific algorithms",
24 create_callback: &ArchitectureAArch64::Create);
25}
26
27void ArchitectureAArch64::Terminate() {
28 PluginManager::UnregisterPlugin(create_callback: &ArchitectureAArch64::Create);
29}
30
31std::unique_ptr<Architecture>
32ArchitectureAArch64::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
41static void
42UpdateARM64SVERegistersInfos(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(s1: reg.name, s2: "ffr") == 0)
57 reg.byte_size = vg;
58 }
59 reg.byte_offset = LLDB_INVALID_INDEX32;
60 }
61}
62
63static void
64UpdateARM64SMERegistersInfos(DynamicRegisterInfo::reg_collection_range regs,
65 uint64_t svg) {
66 for (auto &reg : regs) {
67 if (strcmp(s1: reg.name, s2: "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
75bool 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(reg_name: "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(reg: 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(reg_name: "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(reg: 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: *vg_reg_value);
110 if (svg_reg_value)
111 UpdateARM64SMERegistersInfos(regs, svg: *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 data_sp: std::make_shared<DataBufferHeap>(args: reg_info.GetRegisterDataByteSize(), args: 0));
121 reg_data.SetByteOrder(reg_context.GetByteOrder());
122
123 return true;
124}
125

source code of lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp