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