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