xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1344a3780SDimitry Andric //===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
2344a3780SDimitry Andric //
3344a3780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4344a3780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5344a3780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6344a3780SDimitry Andric //
7344a3780SDimitry Andric //===----------------------------------------------------------------------===//
8344a3780SDimitry Andric 
9344a3780SDimitry Andric #include "NativeProcessSoftwareSingleStep.h"
10344a3780SDimitry Andric 
11344a3780SDimitry Andric #include "lldb/Core/EmulateInstruction.h"
12344a3780SDimitry Andric #include "lldb/Host/common/NativeRegisterContext.h"
13344a3780SDimitry Andric #include "lldb/Utility/RegisterValue.h"
14344a3780SDimitry Andric 
15344a3780SDimitry Andric #include <unordered_map>
16344a3780SDimitry Andric 
17344a3780SDimitry Andric using namespace lldb;
18344a3780SDimitry Andric using namespace lldb_private;
19344a3780SDimitry Andric 
20344a3780SDimitry Andric namespace {
21344a3780SDimitry Andric 
22344a3780SDimitry Andric struct EmulatorBaton {
23344a3780SDimitry Andric   NativeProcessProtocol &m_process;
24344a3780SDimitry Andric   NativeRegisterContext &m_reg_context;
25344a3780SDimitry Andric 
26344a3780SDimitry Andric   // eRegisterKindDWARF -> RegsiterValue
27344a3780SDimitry Andric   std::unordered_map<uint32_t, RegisterValue> m_register_values;
28344a3780SDimitry Andric 
EmulatorBaton__anon3d2037330111::EmulatorBaton29344a3780SDimitry Andric   EmulatorBaton(NativeProcessProtocol &process,
30344a3780SDimitry Andric                 NativeRegisterContext &reg_context)
31344a3780SDimitry Andric       : m_process(process), m_reg_context(reg_context) {}
32344a3780SDimitry Andric };
33344a3780SDimitry Andric 
34344a3780SDimitry Andric } // anonymous namespace
35344a3780SDimitry Andric 
ReadMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t length)36344a3780SDimitry Andric static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
37344a3780SDimitry Andric                                  const EmulateInstruction::Context &context,
38344a3780SDimitry Andric                                  lldb::addr_t addr, void *dst, size_t length) {
39344a3780SDimitry Andric   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
40344a3780SDimitry Andric 
41344a3780SDimitry Andric   size_t bytes_read;
42344a3780SDimitry Andric   emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);
43344a3780SDimitry Andric   return bytes_read;
44344a3780SDimitry Andric }
45344a3780SDimitry Andric 
ReadRegisterCallback(EmulateInstruction * instruction,void * baton,const RegisterInfo * reg_info,RegisterValue & reg_value)46344a3780SDimitry Andric static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
47344a3780SDimitry Andric                                  const RegisterInfo *reg_info,
48344a3780SDimitry Andric                                  RegisterValue &reg_value) {
49344a3780SDimitry Andric   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
50344a3780SDimitry Andric 
51344a3780SDimitry Andric   auto it = emulator_baton->m_register_values.find(
52344a3780SDimitry Andric       reg_info->kinds[eRegisterKindDWARF]);
53344a3780SDimitry Andric   if (it != emulator_baton->m_register_values.end()) {
54344a3780SDimitry Andric     reg_value = it->second;
55344a3780SDimitry Andric     return true;
56344a3780SDimitry Andric   }
57344a3780SDimitry Andric 
58344a3780SDimitry Andric   // The emulator only fill in the dwarf regsiter numbers (and in some case the
59344a3780SDimitry Andric   // generic register numbers). Get the full register info from the register
60344a3780SDimitry Andric   // context based on the dwarf register numbers.
61344a3780SDimitry Andric   const RegisterInfo *full_reg_info =
62344a3780SDimitry Andric       emulator_baton->m_reg_context.GetRegisterInfo(
63344a3780SDimitry Andric           eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
64344a3780SDimitry Andric 
65344a3780SDimitry Andric   Status error =
66344a3780SDimitry Andric       emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);
67344a3780SDimitry Andric   if (error.Success())
68344a3780SDimitry Andric     return true;
69344a3780SDimitry Andric 
70344a3780SDimitry Andric   return false;
71344a3780SDimitry Andric }
72344a3780SDimitry Andric 
WriteRegisterCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & reg_value)73344a3780SDimitry Andric static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
74344a3780SDimitry Andric                                   const EmulateInstruction::Context &context,
75344a3780SDimitry Andric                                   const RegisterInfo *reg_info,
76344a3780SDimitry Andric                                   const RegisterValue &reg_value) {
77344a3780SDimitry Andric   EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
78344a3780SDimitry Andric   emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
79344a3780SDimitry Andric       reg_value;
80344a3780SDimitry Andric   return true;
81344a3780SDimitry Andric }
82344a3780SDimitry Andric 
WriteMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t length)83344a3780SDimitry Andric static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
84344a3780SDimitry Andric                                   const EmulateInstruction::Context &context,
85344a3780SDimitry Andric                                   lldb::addr_t addr, const void *dst,
86344a3780SDimitry Andric                                   size_t length) {
87344a3780SDimitry Andric   return length;
88344a3780SDimitry Andric }
89344a3780SDimitry Andric 
ReadFlags(NativeRegisterContext & regsiter_context)90344a3780SDimitry Andric static lldb::addr_t ReadFlags(NativeRegisterContext &regsiter_context) {
91344a3780SDimitry Andric   const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo(
92344a3780SDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
93344a3780SDimitry Andric   return regsiter_context.ReadRegisterAsUnsigned(flags_info,
94344a3780SDimitry Andric                                                  LLDB_INVALID_ADDRESS);
95344a3780SDimitry Andric }
96344a3780SDimitry Andric 
GetSoftwareBreakpointSize(const ArchSpec & arch,lldb::addr_t next_flags)97ac9a064cSDimitry Andric static int GetSoftwareBreakpointSize(const ArchSpec &arch,
98ac9a064cSDimitry Andric                                      lldb::addr_t next_flags) {
99ac9a064cSDimitry Andric   if (arch.GetMachine() == llvm::Triple::arm) {
100ac9a064cSDimitry Andric     if (next_flags & 0x20)
101ac9a064cSDimitry Andric       // Thumb mode
102ac9a064cSDimitry Andric       return 2;
103ac9a064cSDimitry Andric     // Arm mode
104ac9a064cSDimitry Andric     return 4;
105ac9a064cSDimitry Andric   }
106ac9a064cSDimitry Andric   if (arch.IsMIPS() || arch.GetTriple().isPPC64() ||
107ac9a064cSDimitry Andric       arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch())
108ac9a064cSDimitry Andric     return 4;
109ac9a064cSDimitry Andric   return 0;
110ac9a064cSDimitry Andric }
111ac9a064cSDimitry Andric 
SetSoftwareBreakpointOnPC(const ArchSpec & arch,lldb::addr_t pc,lldb::addr_t next_flags,NativeProcessProtocol & process)112ac9a064cSDimitry Andric static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc,
113ac9a064cSDimitry Andric                                         lldb::addr_t next_flags,
114ac9a064cSDimitry Andric                                         NativeProcessProtocol &process) {
115ac9a064cSDimitry Andric   int size_hint = GetSoftwareBreakpointSize(arch, next_flags);
116ac9a064cSDimitry Andric   Status error;
117ac9a064cSDimitry Andric   error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false);
118ac9a064cSDimitry Andric 
119ac9a064cSDimitry Andric   // If setting the breakpoint fails because pc is out of the address
120ac9a064cSDimitry Andric   // space, ignore it and let the debugee segfault.
121ac9a064cSDimitry Andric   if (error.GetError() == EIO || error.GetError() == EFAULT)
122ac9a064cSDimitry Andric     return Status();
123ac9a064cSDimitry Andric   if (error.Fail())
124ac9a064cSDimitry Andric     return error;
125ac9a064cSDimitry Andric 
126ac9a064cSDimitry Andric   return Status();
127ac9a064cSDimitry Andric }
128ac9a064cSDimitry Andric 
SetupSoftwareSingleStepping(NativeThreadProtocol & thread)129344a3780SDimitry Andric Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
130344a3780SDimitry Andric     NativeThreadProtocol &thread) {
131344a3780SDimitry Andric   Status error;
132344a3780SDimitry Andric   NativeProcessProtocol &process = thread.GetProcess();
133344a3780SDimitry Andric   NativeRegisterContext &register_context = thread.GetRegisterContext();
134344a3780SDimitry Andric   const ArchSpec &arch = process.GetArchitecture();
135344a3780SDimitry Andric 
136344a3780SDimitry Andric   std::unique_ptr<EmulateInstruction> emulator_up(
137344a3780SDimitry Andric       EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
138344a3780SDimitry Andric                                      nullptr));
139344a3780SDimitry Andric 
140344a3780SDimitry Andric   if (emulator_up == nullptr)
141344a3780SDimitry Andric     return Status("Instruction emulator not found!");
142344a3780SDimitry Andric 
143344a3780SDimitry Andric   EmulatorBaton baton(process, register_context);
144344a3780SDimitry Andric   emulator_up->SetBaton(&baton);
145344a3780SDimitry Andric   emulator_up->SetReadMemCallback(&ReadMemoryCallback);
146344a3780SDimitry Andric   emulator_up->SetReadRegCallback(&ReadRegisterCallback);
147344a3780SDimitry Andric   emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
148344a3780SDimitry Andric   emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
149344a3780SDimitry Andric 
150ac9a064cSDimitry Andric   if (!emulator_up->ReadInstruction()) {
151ac9a064cSDimitry Andric     // try to get at least the size of next instruction to set breakpoint.
152ac9a064cSDimitry Andric     auto instr_size = emulator_up->GetLastInstrSize();
153ac9a064cSDimitry Andric     if (!instr_size)
154344a3780SDimitry Andric       return Status("Read instruction failed!");
155ac9a064cSDimitry Andric     bool success = false;
156ac9a064cSDimitry Andric     auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric,
157ac9a064cSDimitry Andric                                                 LLDB_REGNUM_GENERIC_PC,
158ac9a064cSDimitry Andric                                                 LLDB_INVALID_ADDRESS, &success);
159ac9a064cSDimitry Andric     if (!success)
160ac9a064cSDimitry Andric       return Status("Reading pc failed!");
161ac9a064cSDimitry Andric     lldb::addr_t next_pc = pc + *instr_size;
162ac9a064cSDimitry Andric     auto result =
163ac9a064cSDimitry Andric         SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process);
164ac9a064cSDimitry Andric     m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
165ac9a064cSDimitry Andric     return result;
166ac9a064cSDimitry Andric   }
167344a3780SDimitry Andric 
168344a3780SDimitry Andric   bool emulation_result =
169344a3780SDimitry Andric       emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
170344a3780SDimitry Andric 
171344a3780SDimitry Andric   const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo(
172344a3780SDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
173344a3780SDimitry Andric   const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo(
174344a3780SDimitry Andric       eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
175344a3780SDimitry Andric 
176344a3780SDimitry Andric   auto pc_it =
177344a3780SDimitry Andric       baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
178e3b55780SDimitry Andric   auto flags_it = reg_info_flags == nullptr
179e3b55780SDimitry Andric                       ? baton.m_register_values.end()
180e3b55780SDimitry Andric                       : baton.m_register_values.find(
181e3b55780SDimitry Andric                             reg_info_flags->kinds[eRegisterKindDWARF]);
182344a3780SDimitry Andric 
183344a3780SDimitry Andric   lldb::addr_t next_pc;
184344a3780SDimitry Andric   lldb::addr_t next_flags;
185344a3780SDimitry Andric   if (emulation_result) {
186344a3780SDimitry Andric     assert(pc_it != baton.m_register_values.end() &&
187344a3780SDimitry Andric            "Emulation was successfull but PC wasn't updated");
188344a3780SDimitry Andric     next_pc = pc_it->second.GetAsUInt64();
189344a3780SDimitry Andric 
190344a3780SDimitry Andric     if (flags_it != baton.m_register_values.end())
191344a3780SDimitry Andric       next_flags = flags_it->second.GetAsUInt64();
192344a3780SDimitry Andric     else
193344a3780SDimitry Andric       next_flags = ReadFlags(register_context);
194344a3780SDimitry Andric   } else if (pc_it == baton.m_register_values.end()) {
195344a3780SDimitry Andric     // Emulate instruction failed and it haven't changed PC. Advance PC with
196344a3780SDimitry Andric     // the size of the current opcode because the emulation of all
197344a3780SDimitry Andric     // PC modifying instruction should be successful. The failure most
198344a3780SDimitry Andric     // likely caused by a not supported instruction which don't modify PC.
199344a3780SDimitry Andric     next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize();
200344a3780SDimitry Andric     next_flags = ReadFlags(register_context);
201344a3780SDimitry Andric   } else {
202344a3780SDimitry Andric     // The instruction emulation failed after it modified the PC. It is an
203344a3780SDimitry Andric     // unknown error where we can't continue because the next instruction is
204344a3780SDimitry Andric     // modifying the PC but we don't  know how.
205344a3780SDimitry Andric     return Status("Instruction emulation failed unexpectedly.");
206344a3780SDimitry Andric   }
207ac9a064cSDimitry Andric   auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process);
208344a3780SDimitry Andric   m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc});
209ac9a064cSDimitry Andric   return result;
210344a3780SDimitry Andric }
211