xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 &reg_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 &reg_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 &reg_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 &register_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