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 | |
21 | using namespace lldb; |
22 | |
23 | LLDB_PLUGIN_DEFINE(ABIAArch64) |
24 | |
25 | void ABIAArch64::Initialize() { |
26 | ABISysV_arm64::Initialize(); |
27 | ABIMacOSX_arm64::Initialize(); |
28 | } |
29 | |
30 | void ABIAArch64::Terminate() { |
31 | ABISysV_arm64::Terminate(); |
32 | ABIMacOSX_arm64::Terminate(); |
33 | } |
34 | |
35 | lldb::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 | |
52 | lldb::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 | |
68 | std::pair<uint32_t, uint32_t> |
69 | ABIAArch64::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 | |
77 | std::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 | |
84 | uint32_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 | |
102 | static void addPartialRegisters( |
103 | std::vector<lldb_private::DynamicRegisterInfo::Register> ®s, |
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 | |
131 | void ABIAArch64::AugmentRegisterInfo( |
132 | std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) { |
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, ®_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 | |