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 "ABIAArch64.h"
10 #ifdef LLDB_ENABLE_ALL
11 #include "ABIMacOSX_arm64.h"
12 #endif // LLDB_ENABLE_ALL
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 
20 LLDB_PLUGIN_DEFINE(ABIAArch64)
21 
22 void ABIAArch64::Initialize() {
23   ABISysV_arm64::Initialize();
24 #ifdef LLDB_ENABLE_ALL
25   ABIMacOSX_arm64::Initialize();
26 #endif // LLDB_ENABLE_ALL
27 }
28 
29 void ABIAArch64::Terminate() {
30   ABISysV_arm64::Terminate();
31 #ifdef LLDB_ENABLE_ALL
32   ABIMacOSX_arm64::Terminate();
33 #endif // LLDB_ENABLE_ALL
34 }
35 
36 lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) {
37   if (lldb::ProcessSP process_sp = GetProcessSP())
38     return FixAddress(pc, process_sp->GetCodeAddressMask());
39   return pc;
40 }
41 
42 lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) {
43   if (lldb::ProcessSP process_sp = GetProcessSP())
44     return FixAddress(pc, process_sp->GetDataAddressMask());
45   return pc;
46 }
47 
48 std::pair<uint32_t, uint32_t>
49 ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) {
50   if (name == "pc")
51     return {LLDB_INVALID_REGNUM, arm64_dwarf::pc};
52   if (name == "cpsr")
53     return {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr};
54   return MCBasedABI::GetEHAndDWARFNums(name);
55 }
56 
57 std::string ABIAArch64::GetMCName(std::string reg) {
58   MapRegisterName(reg, "v", "q");
59   MapRegisterName(reg, "x29", "fp");
60   MapRegisterName(reg, "x30", "lr");
61   return reg;
62 }
63 
64 uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) {
65   return llvm::StringSwitch<uint32_t>(name)
66       .Case("pc", LLDB_REGNUM_GENERIC_PC)
67       .Cases("lr", "x30", LLDB_REGNUM_GENERIC_RA)
68       .Cases("sp", "x31", LLDB_REGNUM_GENERIC_SP)
69       .Cases("fp", "x29", LLDB_REGNUM_GENERIC_FP)
70       .Case("cpsr", LLDB_REGNUM_GENERIC_FLAGS)
71       .Case("x0", LLDB_REGNUM_GENERIC_ARG1)
72       .Case("x1", LLDB_REGNUM_GENERIC_ARG2)
73       .Case("x2", LLDB_REGNUM_GENERIC_ARG3)
74       .Case("x3", LLDB_REGNUM_GENERIC_ARG4)
75       .Case("x4", LLDB_REGNUM_GENERIC_ARG5)
76       .Case("x5", LLDB_REGNUM_GENERIC_ARG6)
77       .Case("x6", LLDB_REGNUM_GENERIC_ARG7)
78       .Case("x7", LLDB_REGNUM_GENERIC_ARG8)
79       .Default(LLDB_INVALID_REGNUM);
80 }
81 
82 static void addPartialRegisters(
83     std::vector<lldb_private::DynamicRegisterInfo::Register> &regs,
84     llvm::ArrayRef<llvm::Optional<uint32_t>> full_reg_indices,
85     uint32_t full_reg_size, const char *partial_reg_format,
86     uint32_t partial_reg_size, lldb::Encoding encoding, lldb::Format format) {
87   for (auto it : llvm::enumerate(full_reg_indices)) {
88     llvm::Optional<uint32_t> full_reg_index = it.value();
89     if (!full_reg_index ||
90         regs[full_reg_index.getValue()].byte_size != full_reg_size)
91       return;
92 
93     lldb_private::DynamicRegisterInfo::Register partial_reg{
94         lldb_private::ConstString(
95             llvm::formatv(partial_reg_format, it.index()).str()),
96         lldb_private::ConstString(),
97         lldb_private::ConstString("supplementary registers"),
98         partial_reg_size,
99         LLDB_INVALID_INDEX32,
100         encoding,
101         format,
102         LLDB_INVALID_REGNUM,
103         LLDB_INVALID_REGNUM,
104         LLDB_INVALID_REGNUM,
105         LLDB_INVALID_REGNUM,
106         {full_reg_index.getValue()},
107         {}};
108     addSupplementaryRegister(regs, partial_reg);
109   }
110 }
111 
112 void ABIAArch64::AugmentRegisterInfo(
113     std::vector<lldb_private::DynamicRegisterInfo::Register> &regs) {
114   lldb_private::MCBasedABI::AugmentRegisterInfo(regs);
115 
116   lldb_private::ConstString sp_string{"sp"};
117 
118   std::array<llvm::Optional<uint32_t>, 32> x_regs;
119   std::array<llvm::Optional<uint32_t>, 32> v_regs;
120 
121   for (auto it : llvm::enumerate(regs)) {
122     lldb_private::DynamicRegisterInfo::Register &info = it.value();
123     // GDB sends x31 as "sp".  Add the "x31" alt_name for convenience.
124     if (info.name == sp_string && !info.alt_name)
125       info.alt_name.SetCString("x31");
126 
127     unsigned int reg_num;
128     auto get_reg = [&info, &reg_num](const char *prefix) {
129       llvm::StringRef reg_name = info.name.GetStringRef();
130       llvm::StringRef alt_name = info.alt_name.GetStringRef();
131       return (reg_name.consume_front(prefix) &&
132               llvm::to_integer(reg_name, reg_num, 10) && reg_num < 32) ||
133              (alt_name.consume_front(prefix) &&
134               llvm::to_integer(alt_name, reg_num, 10) && reg_num < 32);
135     };
136 
137     if (get_reg("x"))
138       x_regs[reg_num] = it.index();
139     else if (get_reg("v"))
140       v_regs[reg_num] = it.index();
141     // if we have at least one subregister, abort
142     else if (get_reg("w") || get_reg("s") || get_reg("d"))
143       return;
144   }
145 
146   // Create aliases for partial registers: wN for xN, and sN/dN for vN.
147   addPartialRegisters(regs, x_regs, 8, "w{0}", 4, lldb::eEncodingUint,
148                       lldb::eFormatHex);
149   addPartialRegisters(regs, v_regs, 16, "s{0}", 4, lldb::eEncodingIEEE754,
150                       lldb::eFormatFloat);
151   addPartialRegisters(regs, v_regs, 16, "d{0}", 8, lldb::eEncodingIEEE754,
152                       lldb::eFormatFloat);
153 }
154