1 //===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "NativeProcessSoftwareSingleStep.h"
10
11 #include "lldb/Core/EmulateInstruction.h"
12 #include "lldb/Host/common/NativeRegisterContext.h"
13 #include "lldb/Utility/RegisterValue.h"
14
15 #include <unordered_map>
16
17 using namespace lldb;
18 using namespace lldb_private;
19
20 namespace {
21
22 struct EmulatorBaton {
23 NativeProcessProtocol &m_process;
24 NativeRegisterContext &m_reg_context;
25
26 // eRegisterKindDWARF -> RegsiterValue
27 std::unordered_map<uint32_t, RegisterValue> m_register_values;
28
EmulatorBaton__anonae1e265e0111::EmulatorBaton29 EmulatorBaton(NativeProcessProtocol &process,
30 NativeRegisterContext ®_context)
31 : m_process(process), m_reg_context(reg_context) {}
32 };
33
34 } // anonymous namespace
35
ReadMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,void * dst,size_t length)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);
40
41 size_t bytes_read;
42 emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read);
43 return bytes_read;
44 }
45
ReadRegisterCallback(EmulateInstruction * instruction,void * baton,const RegisterInfo * reg_info,RegisterValue & reg_value)46 static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
47 const RegisterInfo *reg_info,
48 RegisterValue ®_value) {
49 EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
50
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;
55 return true;
56 }
57
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]);
64
65 Status error =
66 emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value);
67 if (error.Success())
68 return true;
69
70 return false;
71 }
72
WriteRegisterCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,const RegisterInfo * reg_info,const RegisterValue & 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]] =
79 reg_value;
80 return true;
81 }
82
WriteMemoryCallback(EmulateInstruction * instruction,void * baton,const EmulateInstruction::Context & context,lldb::addr_t addr,const void * dst,size_t length)83 static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
84 const EmulateInstruction::Context &context,
85 lldb::addr_t addr, const void *dst,
86 size_t length) {
87 return length;
88 }
89
SetSoftwareBreakpoint(lldb::addr_t bp_addr,unsigned bp_size,NativeProcessProtocol & process)90 static Status SetSoftwareBreakpoint(lldb::addr_t bp_addr, unsigned bp_size,
91 NativeProcessProtocol &process) {
92 Status error;
93 error = process.SetBreakpoint(bp_addr, bp_size, /*hardware=*/false);
94
95 // If setting the breakpoint fails because pc is out of the address
96 // space, ignore it and let the debugee segfault.
97 if (error.GetError() == EIO || error.GetError() == EFAULT)
98 return Status();
99 if (error.Fail())
100 return error;
101
102 return Status();
103 }
104
SetupSoftwareSingleStepping(NativeThreadProtocol & thread)105 Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping(
106 NativeThreadProtocol &thread) {
107 Status error;
108 NativeProcessProtocol &process = thread.GetProcess();
109 NativeRegisterContext ®ister_context = thread.GetRegisterContext();
110 const ArchSpec &arch = process.GetArchitecture();
111
112 std::unique_ptr<EmulateInstruction> emulator_up(
113 EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying,
114 nullptr));
115 if (emulator_up == nullptr)
116 return Status::FromErrorString("Instruction emulator not found!");
117
118 EmulatorBaton baton(process, register_context);
119 emulator_up->SetBaton(&baton);
120 emulator_up->SetReadMemCallback(&ReadMemoryCallback);
121 emulator_up->SetReadRegCallback(&ReadRegisterCallback);
122 emulator_up->SetWriteMemCallback(&WriteMemoryCallback);
123 emulator_up->SetWriteRegCallback(&WriteRegisterCallback);
124
125 auto bp_locaions_predictor =
126 EmulateInstruction::CreateBreakpointLocationPredictor(
127 std::move(emulator_up));
128
129 auto bp_locations = bp_locaions_predictor->GetBreakpointLocations(error);
130 if (error.Fail())
131 return error;
132
133 for (auto &&bp_addr : bp_locations) {
134 auto bp_size = bp_locaions_predictor->GetBreakpointSize(bp_addr);
135 if (auto err = bp_size.takeError())
136 return Status(toString(std::move(err)));
137
138 error = SetSoftwareBreakpoint(bp_addr, *bp_size, process);
139 if (error.Fail())
140 return error;
141 }
142
143 m_threads_stepping_with_breakpoint.insert({thread.GetID(), bp_locations});
144 return error;
145 }
146