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