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