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 29 EmulatorBaton(NativeProcessProtocol &process, 30 NativeRegisterContext ®_context) 31 : m_process(process), m_reg_context(reg_context) {} 32 }; 33 34 } // anonymous namespace 35 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 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 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 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 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); 95 } 96 97 static int GetSoftwareBreakpointSize(const ArchSpec &arch, 98 lldb::addr_t next_flags) { 99 if (arch.GetMachine() == llvm::Triple::arm) { 100 if (next_flags & 0x20) 101 // Thumb mode 102 return 2; 103 // Arm mode 104 return 4; 105 } 106 if (arch.IsMIPS() || arch.GetTriple().isPPC64() || 107 arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) 108 return 4; 109 return 0; 110 } 111 112 static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc, 113 lldb::addr_t next_flags, 114 NativeProcessProtocol &process) { 115 int size_hint = GetSoftwareBreakpointSize(arch, next_flags); 116 Status error; 117 error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false); 118 119 // If setting the breakpoint fails because pc is out of the address 120 // space, ignore it and let the debugee segfault. 121 if (error.GetError() == EIO || error.GetError() == EFAULT) 122 return Status(); 123 if (error.Fail()) 124 return error; 125 126 return Status(); 127 } 128 129 Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( 130 NativeThreadProtocol &thread) { 131 Status error; 132 NativeProcessProtocol &process = thread.GetProcess(); 133 NativeRegisterContext ®ister_context = thread.GetRegisterContext(); 134 const ArchSpec &arch = process.GetArchitecture(); 135 136 std::unique_ptr<EmulateInstruction> emulator_up( 137 EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying, 138 nullptr)); 139 140 if (emulator_up == nullptr) 141 return Status::FromErrorString("Instruction emulator not found!"); 142 143 EmulatorBaton baton(process, register_context); 144 emulator_up->SetBaton(&baton); 145 emulator_up->SetReadMemCallback(&ReadMemoryCallback); 146 emulator_up->SetReadRegCallback(&ReadRegisterCallback); 147 emulator_up->SetWriteMemCallback(&WriteMemoryCallback); 148 emulator_up->SetWriteRegCallback(&WriteRegisterCallback); 149 150 if (!emulator_up->ReadInstruction()) { 151 // try to get at least the size of next instruction to set breakpoint. 152 auto instr_size = emulator_up->GetLastInstrSize(); 153 if (!instr_size) 154 return Status::FromErrorString("Read instruction failed!"); 155 bool success = false; 156 auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric, 157 LLDB_REGNUM_GENERIC_PC, 158 LLDB_INVALID_ADDRESS, &success); 159 if (!success) 160 return Status::FromErrorString("Reading pc failed!"); 161 lldb::addr_t next_pc = pc + *instr_size; 162 auto result = 163 SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process); 164 m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); 165 return result; 166 } 167 168 bool emulation_result = 169 emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); 170 171 const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( 172 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); 173 const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( 174 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); 175 176 auto pc_it = 177 baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); 178 auto flags_it = reg_info_flags == nullptr 179 ? baton.m_register_values.end() 180 : baton.m_register_values.find( 181 reg_info_flags->kinds[eRegisterKindDWARF]); 182 183 lldb::addr_t next_pc; 184 lldb::addr_t next_flags; 185 if (emulation_result) { 186 assert(pc_it != baton.m_register_values.end() && 187 "Emulation was successfull but PC wasn't updated"); 188 next_pc = pc_it->second.GetAsUInt64(); 189 190 if (flags_it != baton.m_register_values.end()) 191 next_flags = flags_it->second.GetAsUInt64(); 192 else 193 next_flags = ReadFlags(register_context); 194 } else if (pc_it == baton.m_register_values.end()) { 195 // Emulate instruction failed and it haven't changed PC. Advance PC with 196 // the size of the current opcode because the emulation of all 197 // PC modifying instruction should be successful. The failure most 198 // likely caused by a not supported instruction which don't modify PC. 199 next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); 200 next_flags = ReadFlags(register_context); 201 } else { 202 // The instruction emulation failed after it modified the PC. It is an 203 // unknown error where we can't continue because the next instruction is 204 // modifying the PC but we don't know how. 205 return Status::FromErrorString( 206 "Instruction emulation failed unexpectedly."); 207 } 208 auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process); 209 m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); 210 return result; 211 } 212