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