1 //===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
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 "NativeProcessSoftwareSingleStep.h"
10 
11 #include "lldb/Core/EmulateInstruction.h"
12 #include "lldb/Host/common/NativeRegisterContext.h"
13 #include "lldb/Utility/RegisterValue.h"
14 
15 #include <unordered_map>
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 namespace {
21 
22 struct EmulatorBaton {
23   NativeProcessProtocol &m_process;
24   NativeRegisterContext &m_reg_context;
25 
26   // eRegisterKindDWARF -> RegsiterValue
27   std::unordered_map<uint32_t, RegisterValue> m_register_values;
28 
EmulatorBaton__anonab17a5260111::EmulatorBaton29   EmulatorBaton(NativeProcessProtocol &process,
30                 NativeRegisterContext &reg_context)
31       : m_process(process), m_reg_context(reg_context) {}
32 };
33 
34 } // anonymous namespace
35 
ReadMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t length)36 static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
37                                  const EmulateInstruction::Context &context,
38                                  lldb::addr_t addr, void *dst, size_t length) {
39   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
40 
41   size_t bytes_read;
42   emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);
43   return bytes_read;
44 }
45 
ReadRegisterCallback(EmulateInstruction * instruction,void * baton,const RegisterInfo * reg_info,RegisterValue & reg_value)46 static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
47                                  const RegisterInfo *reg_info,
48                                  RegisterValue &reg_value) {
49   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
50 
51   auto it = emulator_baton->m_register_values.find(
52       reg_info->kinds[eRegisterKindDWARF]);
53   if (it != emulator_baton->m_register_values.end()) {
54     reg_value = it->second;
55     return true;
56   }
57 
58   // The emulator only fill in the dwarf regsiter numbers (and in some case the
59   // generic register numbers). Get the full register info from the register
60   // context based on the dwarf register numbers.
61   const RegisterInfo *full_reg_info =
62       emulator_baton->m_reg_context.GetRegisterInfo(
63           eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
64 
65   Status error =
66       emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);
67   if (error.Success())
68     return true;
69 
70   return false;
71 }
72 
WriteRegisterCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & reg_value)73 static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
74                                   const EmulateInstruction::Context &context,
75                                   const RegisterInfo *reg_info,
76                                   const RegisterValue &reg_value) {
77   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
78   emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
79       reg_value;
80   return true;
81 }
82 
WriteMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t length)83 static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
84                                   const EmulateInstruction::Context &context,
85                                   lldb::addr_t addr, const void *dst,
86                                   size_t length) {
87   return length;
88 }
89 
ReadFlags(NativeRegisterContext & regsiter_context)90 static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
91   const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(
92       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
93   return regsiter_context.ReadRegisterAsUnsigned(flags_info,
94                                                  LLDB_INVALID_ADDRESS);
95 }
96 
SetupSoftwareSingleStepping(NativeThreadProtocol & thread)97 Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
98     NativeThreadProtocol &thread) {
99   Status error;
100   NativeProcessProtocol &process = thread.GetProcess();
101   NativeRegisterContext &register_context = thread.GetRegisterContext();
102   const ArchSpec &arch = process.GetArchitecture();
103 
104   std::unique_ptr<EmulateInstruction> emulator_up(
105       EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
106                                      nullptr));
107 
108   if (emulator_up == nullptr)
109     return Status("Instruction emulator not found!");
110 
111   EmulatorBaton baton(process, register_context);
112   emulator_up->SetBaton(&baton);
113   emulator_up->SetReadMemCallback(&ReadMemoryCallback);
114   emulator_up->SetReadRegCallback(&ReadRegisterCallback);
115   emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
116   emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
117 
118   if (!emulator_up->ReadInstruction())
119     return Status("Read instruction failed!");
120 
121   bool emulation_result =
122       emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
123 
124   const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
125       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
126   const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
127       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
128 
129   auto pc_it =
130       baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
131   auto flags_it = reg_info_flags == nullptr
132                       ? baton.m_register_values.end()
133                       : baton.m_register_values.find(
134                             reg_info_flags->kinds[eRegisterKindDWARF]);
135 
136   lldb::addr_t next_pc;
137   lldb::addr_t next_flags;
138   if (emulation_result) {
139     assert(pc_it != baton.m_register_values.end() &&
140            "Emulation was successfull but PC wasn't updated");
141     next_pc = pc_it->second.GetAsUInt64();
142 
143     if (flags_it != baton.m_register_values.end())
144       next_flags = flags_it->second.GetAsUInt64();
145     else
146       next_flags = ReadFlags(register_context);
147   } else if (pc_it == baton.m_register_values.end()) {
148     // Emulate instruction failed and it haven't changed PC. Advance PC with
149     // the size of the current opcode because the emulation of all
150     // PC modifying instruction should be successful. The failure most
151     // likely caused by a not supported instruction which don't modify PC.
152     next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();
153     next_flags = ReadFlags(register_context);
154   } else {
155     // The instruction emulation failed after it modified the PC. It is an
156     // unknown error where we can't continue because the next instruction is
157     // modifying the PC but we don't  know how.
158     return Status("Instruction emulation failed unexpectedly.");
159   }
160 
161   int size_hint = 0;
162   if (arch.GetMachine() == llvm::Triple::arm) {
163     if (next_flags & 0x20) {
164       // Thumb mode
165       size_hint = 2;
166     } else {
167       // Arm mode
168       size_hint = 4;
169     }
170   } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
171              arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
172     size_hint = 4;
173   error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false);
174 
175   // If setting the breakpoint fails because next_pc is out of the address
176   // space, ignore it and let the debugee segfault.
177   if (error.GetError() == EIO || error.GetError() == EFAULT) {
178     return Status();
179   } else if (error.Fail())
180     return error;
181 
182   m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
183 
184   return Status();
185 }
186