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