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