1//===-- AArch66.h ---------------------------------------------------------===//
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 "lldb/lldb-types.h"
10
11#include "ABIAArch64.h"
12#include "ABIMacOSX_arm64.h"
13#include "ABISysV_arm64.h"
14#include "Utility/ARM64_DWARF_Registers.h"
15#include "lldb/Core/PluginManager.h"
16#include "lldb/Target/Process.h"
17
18#include <bitset>
19#include <optional>
20
21using namespace lldb;
22
23LLDB_PLUGIN_DEFINE(ABIAArch64)
24
25void ABIAArch64::Initialize() {
26 ABISysV_arm64::Initialize();
27 ABIMacOSX_arm64::Initialize();
28}
29
30void ABIAArch64::Terminate() {
31 ABISysV_arm64::Terminate();
32 ABIMacOSX_arm64::Terminate();
33}
34
35lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) {
36 if (lldb::ProcessSP process_sp = GetProcessSP()) {
37 // b55 is the highest bit outside TBI (if it's enabled), use
38 // it to determine if the high bits are set to 0 or 1.
39 const addr_t pac_sign_extension = 0x0080000000000000ULL;
40 addr_t mask = process_sp->GetCodeAddressMask();
41 // Test if the high memory mask has been overriden separately
42 if (pc & pac_sign_extension &&
43 process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK)
44 mask = process_sp->GetHighmemCodeAddressMask();
45
46 if (mask != LLDB_INVALID_ADDRESS_MASK)
47 return FixAddress(pc, mask);
48 }
49 return pc;
50}
51
52lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) {
53 if (lldb::ProcessSP process_sp = GetProcessSP()) {
54 // b55 is the highest bit outside TBI (if it's enabled), use
55 // it to determine if the high bits are set to 0 or 1.
56 const addr_t pac_sign_extension = 0x0080000000000000ULL;
57 addr_t mask = process_sp->GetDataAddressMask();
58 // Test if the high memory mask has been overriden separately
59 if (pc & pac_sign_extension &&
60 process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK)
61 mask = process_sp->GetHighmemDataAddressMask();
62 if (mask != LLDB_INVALID_ADDRESS_MASK)
63 return FixAddress(pc, mask);
64 }
65 return pc;
66}
67
68std::pair<uint32_t, uint32_t>
69ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) {
70 if (name == "pc")
71 return {LLDB_INVALID_REGNUM, arm64_dwarf::pc};
72 if (name == "cpsr")
73 return {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr};
74 return MCBasedABI::GetEHAndDWARFNums(reg: name);
75}
76
77std::string ABIAArch64::GetMCName(std::string reg) {
78 MapRegisterName(reg, from_prefix: "v", to_prefix: "q");
79 MapRegisterName(reg, from_prefix: "x29", to_prefix: "fp");
80 MapRegisterName(reg, from_prefix: "x30", to_prefix: "lr");
81 return reg;
82}
83
84uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) {
85 return llvm::StringSwitch<uint32_t>(name)
86 .Case(S: "pc", LLDB_REGNUM_GENERIC_PC)
87 .Cases(S0: "lr", S1: "x30", LLDB_REGNUM_GENERIC_RA)
88 .Cases(S0: "sp", S1: "x31", LLDB_REGNUM_GENERIC_SP)
89 .Cases(S0: "fp", S1: "x29", LLDB_REGNUM_GENERIC_FP)
90 .Case(S: "cpsr", LLDB_REGNUM_GENERIC_FLAGS)
91 .Case(S: "x0", LLDB_REGNUM_GENERIC_ARG1)
92 .Case(S: "x1", LLDB_REGNUM_GENERIC_ARG2)
93 .Case(S: "x2", LLDB_REGNUM_GENERIC_ARG3)
94 .Case(S: "x3", LLDB_REGNUM_GENERIC_ARG4)
95 .Case(S: "x4", LLDB_REGNUM_GENERIC_ARG5)
96 .Case(S: "x5", LLDB_REGNUM_GENERIC_ARG6)
97 .Case(S: "x6", LLDB_REGNUM_GENERIC_ARG7)
98 .Case(S: "x7", LLDB_REGNUM_GENERIC_ARG8)
99 .Default(LLDB_INVALID_REGNUM);
100}
101
102static void addPartialRegisters(
103 std::vector<lldb_private::DynamicRegisterInfo::Register> &regs,
104 llvm::ArrayRef<std::optional<uint32_t>> full_reg_indices,
105 uint32_t full_reg_size, const char *partial_reg_format,
106 uint32_t partial_reg_size, lldb::Encoding encoding, lldb::Format format) {
107 for (auto it : llvm::enumerate(First&: full_reg_indices)) {
108 std::optional<uint32_t> full_reg_index = it.value();
109 if (!full_reg_index || regs[*full_reg_index].byte_size != full_reg_size)
110 return;
111
112 lldb_private::DynamicRegisterInfo::Register partial_reg{
113 .name: lldb_private::ConstString(
114 llvm::formatv(Fmt: partial_reg_format, Vals: it.index()).str()),
115 .alt_name: lldb_private::ConstString(),
116 .set_name: lldb_private::ConstString("supplementary registers"),
117 .byte_size: partial_reg_size,
118 LLDB_INVALID_INDEX32,
119 .encoding: encoding,
120 .format: format,
121 LLDB_INVALID_REGNUM,
122 LLDB_INVALID_REGNUM,
123 LLDB_INVALID_REGNUM,
124 LLDB_INVALID_REGNUM,
125 .value_regs: {*full_reg_index},
126 .invalidate_regs: {}};
127 addSupplementaryRegister(regs, new_reg_info: partial_reg);
128 }
129}
130
131void ABIAArch64::AugmentRegisterInfo(
132 std::vector<lldb_private::DynamicRegisterInfo::Register> &regs) {
133 lldb_private::MCBasedABI::AugmentRegisterInfo(regs);
134
135 lldb_private::ConstString sp_string{"sp"};
136
137 std::array<std::optional<uint32_t>, 32> x_regs;
138 std::array<std::optional<uint32_t>, 32> v_regs;
139
140 for (auto it : llvm::enumerate(First&: regs)) {
141 lldb_private::DynamicRegisterInfo::Register &info = it.value();
142 // GDB sends x31 as "sp". Add the "x31" alt_name for convenience.
143 if (info.name == sp_string && !info.alt_name)
144 info.alt_name.SetCString("x31");
145
146 unsigned int reg_num;
147 auto get_reg = [&info, &reg_num](const char *prefix) {
148 llvm::StringRef reg_name = info.name.GetStringRef();
149 llvm::StringRef alt_name = info.alt_name.GetStringRef();
150 return (reg_name.consume_front(Prefix: prefix) &&
151 llvm::to_integer(S: reg_name, Num&: reg_num, Base: 10) && reg_num < 32) ||
152 (alt_name.consume_front(Prefix: prefix) &&
153 llvm::to_integer(S: alt_name, Num&: reg_num, Base: 10) && reg_num < 32);
154 };
155
156 if (get_reg("x"))
157 x_regs[reg_num] = it.index();
158 else if (get_reg("v"))
159 v_regs[reg_num] = it.index();
160 // if we have at least one subregister, abort
161 else if (get_reg("w") || get_reg("s") || get_reg("d"))
162 return;
163 }
164
165 // Create aliases for partial registers: wN for xN, and sN/dN for vN.
166 addPartialRegisters(regs, full_reg_indices: x_regs, full_reg_size: 8, partial_reg_format: "w{0}", partial_reg_size: 4, encoding: lldb::eEncodingUint,
167 format: lldb::eFormatHex);
168 addPartialRegisters(regs, full_reg_indices: v_regs, full_reg_size: 16, partial_reg_format: "s{0}", partial_reg_size: 4, encoding: lldb::eEncodingIEEE754,
169 format: lldb::eFormatFloat);
170 addPartialRegisters(regs, full_reg_indices: v_regs, full_reg_size: 16, partial_reg_format: "d{0}", partial_reg_size: 8, encoding: lldb::eEncodingIEEE754,
171 format: lldb::eFormatFloat);
172}
173

source code of lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp