1 | //===-- RegisterFlagsLinux_arm64.h ------------------------------*- C++ -*-===// |
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 | #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H |
10 | #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H |
11 | |
12 | #include "lldb/Target/RegisterFlags.h" |
13 | #include "llvm/ADT/StringRef.h" |
14 | #include <functional> |
15 | |
16 | namespace lldb_private { |
17 | |
18 | struct RegisterInfo; |
19 | |
20 | /// This class manages the storage and detection of register field information |
21 | /// for Arm64 Linux registers. The same register may have different fields on |
22 | /// different CPUs. This class abstracts out the field detection process so we |
23 | /// can use it on live processes and core files. |
24 | /// |
25 | /// The general way to use this class is: |
26 | /// * Make an instance somewhere that will last as long as the debug session |
27 | /// (because your final register info will point to this instance). |
28 | /// * Read hardware capabilities from a core note, binary, prctl, etc. |
29 | /// * Pass those to DetectFields. |
30 | /// * Call UpdateRegisterInfo with your RegisterInfo to add pointers |
31 | /// to the detected fields for all registers listed in this class. |
32 | /// |
33 | /// This must be done in that order, and you should ensure that if multiple |
34 | /// threads will reference the information, a mutex is used to make sure only |
35 | /// one calls DetectFields. |
36 | class LinuxArm64RegisterFlags { |
37 | public: |
38 | /// For the registers listed in this class, detect which fields are |
39 | /// present. Must be called before UpdateRegisterInfos. |
40 | /// If called more than once, fields will be redetected each time from |
41 | /// scratch. If you do not have access to hwcap, just pass 0 for each one, you |
42 | /// will only get unconditional fields. |
43 | void DetectFields(uint64_t hwcap, uint64_t hwcap2); |
44 | |
45 | /// Add the field information of any registers named in this class, |
46 | /// to the relevant RegisterInfo instances. Note that this will be done |
47 | /// with a pointer to the instance of this class that you call this on, so |
48 | /// the lifetime of that instance must be at least that of the register info. |
49 | void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs); |
50 | |
51 | /// Returns true if field detection has been run at least once. |
52 | bool HasDetected() const { return m_has_detected; } |
53 | |
54 | private: |
55 | using Fields = std::vector<RegisterFlags::Field>; |
56 | using DetectorFn = std::function<Fields(uint64_t, uint64_t)>; |
57 | |
58 | static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2); |
59 | static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2); |
60 | static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2); |
61 | static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2); |
62 | static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2); |
63 | |
64 | struct RegisterEntry { |
65 | RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector) |
66 | : m_name(name), m_flags(std::string(name) + "_flags" , size, {{"" , 0}}), |
67 | m_detector(detector) {} |
68 | |
69 | llvm::StringRef m_name; |
70 | RegisterFlags m_flags; |
71 | DetectorFn m_detector; |
72 | } m_registers[5] = { |
73 | RegisterEntry("cpsr" , 4, DetectCPSRFields), |
74 | RegisterEntry("fpsr" , 4, DetectFPSRFields), |
75 | RegisterEntry("fpcr" , 4, DetectFPCRFields), |
76 | RegisterEntry("mte_ctrl" , 8, DetectMTECtrlFields), |
77 | RegisterEntry("svcr" , 8, DetectSVCRFields), |
78 | }; |
79 | |
80 | // Becomes true once field detection has been run for all registers. |
81 | bool m_has_detected = false; |
82 | }; |
83 | |
84 | } // namespace lldb_private |
85 | |
86 | #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H |