xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- EmulateInstructionRISCV.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 #ifndef LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_EMULATEINSTRUCTIONRISCV_H
10 #define LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_EMULATEINSTRUCTIONRISCV_H
11 
12 #include "RISCVInstructions.h"
13 
14 #include "lldb/Core/EmulateInstruction.h"
15 #include "lldb/Interpreter/OptionValue.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/RegisterValue.h"
18 #include "lldb/Utility/Status.h"
19 #include <optional>
20 
21 namespace lldb_private {
22 
23 class RISCVSingleStepBreakpointLocationsPredictor
24     : public SingleStepBreakpointLocationsPredictor {
25 public:
RISCVSingleStepBreakpointLocationsPredictor(std::unique_ptr<EmulateInstruction> emulator)26   RISCVSingleStepBreakpointLocationsPredictor(
27       std::unique_ptr<EmulateInstruction> emulator)
28       : SingleStepBreakpointLocationsPredictor{std::move(emulator)} {}
29 
30   BreakpointLocations GetBreakpointLocations(Status &status) override;
31 
32   llvm::Expected<unsigned> GetBreakpointSize(lldb::addr_t bp_addr) override;
33 
34 private:
FoundLoadReserve(const RISCVInst & inst)35   static bool FoundLoadReserve(const RISCVInst &inst) {
36     return std::holds_alternative<LR_W>(inst) ||
37            std::holds_alternative<LR_D>(inst);
38   }
39 
FoundStoreConditional(const RISCVInst & inst)40   static bool FoundStoreConditional(const RISCVInst &inst) {
41     return std::holds_alternative<SC_W>(inst) ||
42            std::holds_alternative<SC_D>(inst);
43   }
44 
45   BreakpointLocations HandleAtomicSequence(lldb::addr_t pc, Status &error);
46 
47   static constexpr size_t s_max_atomic_sequence_length = 64;
48 };
49 
50 class EmulateInstructionRISCV : public EmulateInstruction {
51 public:
GetPluginNameStatic()52   static llvm::StringRef GetPluginNameStatic() { return "riscv"; }
53 
GetPluginDescriptionStatic()54   static llvm::StringRef GetPluginDescriptionStatic() {
55     return "Emulate instructions for the RISC-V architecture.";
56   }
57 
SupportsThisInstructionType(InstructionType inst_type)58   static bool SupportsThisInstructionType(InstructionType inst_type) {
59     switch (inst_type) {
60     case eInstructionTypeAny:
61     case eInstructionTypePCModifying:
62       return true;
63     case eInstructionTypePrologueEpilogue:
64     case eInstructionTypeAll:
65       return false;
66     }
67     llvm_unreachable("Fully covered switch above!");
68   }
69 
70   static bool SupportsThisArch(const ArchSpec &arch);
71 
72   static lldb_private::EmulateInstruction *
73   CreateInstance(const lldb_private::ArchSpec &arch, InstructionType inst_type);
74 
75   static void Initialize();
76 
77   static void Terminate();
78 
79 public:
EmulateInstructionRISCV(const ArchSpec & arch)80   EmulateInstructionRISCV(const ArchSpec &arch) : EmulateInstruction(arch) {}
81 
GetPluginName()82   llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
83 
SupportsEmulatingInstructionsOfType(InstructionType inst_type)84   bool SupportsEmulatingInstructionsOfType(InstructionType inst_type) override {
85     return SupportsThisInstructionType(inst_type);
86   }
87 
88   bool SetTargetTriple(const ArchSpec &arch) override;
89   bool ReadInstruction() override;
GetLastInstrSize()90   std::optional<uint32_t> GetLastInstrSize() override { return m_last_size; }
91   bool EvaluateInstruction(uint32_t options) override;
92   bool TestEmulation(Stream &out_stream, ArchSpec &arch,
93                      OptionValueDictionary *test_data) override;
94   std::optional<RegisterInfo> GetRegisterInfo(lldb::RegisterKind reg_kind,
95                                               uint32_t reg_num) override;
96 
97   std::optional<DecodeResult> ReadInstructionAt(lldb::addr_t addr);
98   std::optional<DecodeResult> Decode(uint32_t inst);
99   bool Execute(DecodeResult inst, bool ignore_cond);
100 
101   template <typename T>
102   std::enable_if_t<std::is_integral_v<T>, std::optional<T>>
ReadMem(uint64_t addr)103   ReadMem(uint64_t addr) {
104     EmulateInstructionRISCV::Context ctx;
105     ctx.type = EmulateInstruction::eContextRegisterLoad;
106     ctx.SetNoArgs();
107     bool success = false;
108     T result = ReadMemoryUnsigned(ctx, addr, sizeof(T), T(), &success);
109     if (!success)
110       return {}; // aka return false
111     return result;
112   }
113 
WriteMem(uint64_t addr,uint64_t value)114   template <typename T> bool WriteMem(uint64_t addr, uint64_t value) {
115     EmulateInstructionRISCV::Context ctx;
116     ctx.type = EmulateInstruction::eContextRegisterStore;
117     ctx.SetNoArgs();
118     return WriteMemoryUnsigned(ctx, addr, value, sizeof(T));
119   }
120 
121   llvm::RoundingMode GetRoundingMode();
122   bool SetAccruedExceptions(llvm::APFloatBase::opStatus);
123 
124 private:
125   BreakpointLocationsPredictorCreator
GetSingleStepBreakpointLocationsPredictorCreator()126   GetSingleStepBreakpointLocationsPredictorCreator() override {
127     return [](std::unique_ptr<EmulateInstruction> emulator_up) {
128       return std::make_unique<RISCVSingleStepBreakpointLocationsPredictor>(
129           std::move(emulator_up));
130     };
131   }
132   /// Last decoded instruction from m_opcode
133   DecodeResult m_decoded;
134   /// Last decoded instruction size estimate.
135   std::optional<uint32_t> m_last_size;
136 };
137 
138 } // namespace lldb_private
139 
140 #endif // LLDB_SOURCE_PLUGINS_INSTRUCTION_RISCV_EMULATEINSTRUCTIONRISCV_H
141