18244fc50SMichał Górny //===-- NativeProcessSoftwareSingleStep.cpp -------------------------------===// 28244fc50SMichał Górny // 38244fc50SMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 48244fc50SMichał Górny // See https://llvm.org/LICENSE.txt for license information. 58244fc50SMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68244fc50SMichał Górny // 78244fc50SMichał Górny //===----------------------------------------------------------------------===// 88244fc50SMichał Górny 98244fc50SMichał Górny #include "NativeProcessSoftwareSingleStep.h" 108244fc50SMichał Górny 118244fc50SMichał Górny #include "lldb/Core/EmulateInstruction.h" 128244fc50SMichał Górny #include "lldb/Host/common/NativeRegisterContext.h" 138244fc50SMichał Górny #include "lldb/Utility/RegisterValue.h" 148244fc50SMichał Górny 158244fc50SMichał Górny #include <unordered_map> 168244fc50SMichał Górny 178244fc50SMichał Górny using namespace lldb; 188244fc50SMichał Górny using namespace lldb_private; 198244fc50SMichał Górny 208244fc50SMichał Górny namespace { 218244fc50SMichał Górny 228244fc50SMichał Górny struct EmulatorBaton { 238244fc50SMichał Górny NativeProcessProtocol &m_process; 248244fc50SMichał Górny NativeRegisterContext &m_reg_context; 258244fc50SMichał Górny 268244fc50SMichał Górny // eRegisterKindDWARF -> RegsiterValue 278244fc50SMichał Górny std::unordered_map<uint32_t, RegisterValue> m_register_values; 288244fc50SMichał Górny 298244fc50SMichał Górny EmulatorBaton(NativeProcessProtocol &process, 308244fc50SMichał Górny NativeRegisterContext ®_context) 318244fc50SMichał Górny : m_process(process), m_reg_context(reg_context) {} 328244fc50SMichał Górny }; 338244fc50SMichał Górny 348244fc50SMichał Górny } // anonymous namespace 358244fc50SMichał Górny 368244fc50SMichał Górny static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, 378244fc50SMichał Górny const EmulateInstruction::Context &context, 388244fc50SMichał Górny lldb::addr_t addr, void *dst, size_t length) { 398244fc50SMichał Górny EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); 408244fc50SMichał Górny 418244fc50SMichał Górny size_t bytes_read; 428244fc50SMichał Górny emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); 438244fc50SMichał Górny return bytes_read; 448244fc50SMichał Górny } 458244fc50SMichał Górny 468244fc50SMichał Górny static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, 478244fc50SMichał Górny const RegisterInfo *reg_info, 488244fc50SMichał Górny RegisterValue ®_value) { 498244fc50SMichał Górny EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); 508244fc50SMichał Górny 518244fc50SMichał Górny auto it = emulator_baton->m_register_values.find( 528244fc50SMichał Górny reg_info->kinds[eRegisterKindDWARF]); 538244fc50SMichał Górny if (it != emulator_baton->m_register_values.end()) { 548244fc50SMichał Górny reg_value = it->second; 558244fc50SMichał Górny return true; 568244fc50SMichał Górny } 578244fc50SMichał Górny 588244fc50SMichał Górny // The emulator only fill in the dwarf regsiter numbers (and in some case the 598244fc50SMichał Górny // generic register numbers). Get the full register info from the register 608244fc50SMichał Górny // context based on the dwarf register numbers. 618244fc50SMichał Górny const RegisterInfo *full_reg_info = 628244fc50SMichał Górny emulator_baton->m_reg_context.GetRegisterInfo( 638244fc50SMichał Górny eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); 648244fc50SMichał Górny 658244fc50SMichał Górny Status error = 668244fc50SMichał Górny emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); 678244fc50SMichał Górny if (error.Success()) 688244fc50SMichał Górny return true; 698244fc50SMichał Górny 708244fc50SMichał Górny return false; 718244fc50SMichał Górny } 728244fc50SMichał Górny 738244fc50SMichał Górny static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, 748244fc50SMichał Górny const EmulateInstruction::Context &context, 758244fc50SMichał Górny const RegisterInfo *reg_info, 768244fc50SMichał Górny const RegisterValue ®_value) { 778244fc50SMichał Górny EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); 788244fc50SMichał Górny emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = 798244fc50SMichał Górny reg_value; 808244fc50SMichał Górny return true; 818244fc50SMichał Górny } 828244fc50SMichał Górny 838244fc50SMichał Górny static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, 848244fc50SMichał Górny const EmulateInstruction::Context &context, 858244fc50SMichał Górny lldb::addr_t addr, const void *dst, 868244fc50SMichał Górny size_t length) { 878244fc50SMichał Górny return length; 888244fc50SMichał Górny } 898244fc50SMichał Górny 908244fc50SMichał Górny static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { 918244fc50SMichał Górny const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( 928244fc50SMichał Górny eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); 938244fc50SMichał Górny return regsiter_context.ReadRegisterAsUnsigned(flags_info, 948244fc50SMichał Górny LLDB_INVALID_ADDRESS); 958244fc50SMichał Górny } 968244fc50SMichał Górny 97a1ffabc4Sita-sc static int GetSoftwareBreakpointSize(const ArchSpec &arch, 98a1ffabc4Sita-sc lldb::addr_t next_flags) { 99a1ffabc4Sita-sc if (arch.GetMachine() == llvm::Triple::arm) { 100a1ffabc4Sita-sc if (next_flags & 0x20) 101a1ffabc4Sita-sc // Thumb mode 102a1ffabc4Sita-sc return 2; 103a1ffabc4Sita-sc // Arm mode 104a1ffabc4Sita-sc return 4; 105a1ffabc4Sita-sc } 106a1ffabc4Sita-sc if (arch.IsMIPS() || arch.GetTriple().isPPC64() || 107a1ffabc4Sita-sc arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) 108a1ffabc4Sita-sc return 4; 109a1ffabc4Sita-sc return 0; 110a1ffabc4Sita-sc } 111a1ffabc4Sita-sc 112a1ffabc4Sita-sc static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc, 113a1ffabc4Sita-sc lldb::addr_t next_flags, 114a1ffabc4Sita-sc NativeProcessProtocol &process) { 115a1ffabc4Sita-sc int size_hint = GetSoftwareBreakpointSize(arch, next_flags); 116a1ffabc4Sita-sc Status error; 117a1ffabc4Sita-sc error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false); 118a1ffabc4Sita-sc 119a1ffabc4Sita-sc // If setting the breakpoint fails because pc is out of the address 120a1ffabc4Sita-sc // space, ignore it and let the debugee segfault. 121a1ffabc4Sita-sc if (error.GetError() == EIO || error.GetError() == EFAULT) 122a1ffabc4Sita-sc return Status(); 123a1ffabc4Sita-sc if (error.Fail()) 124a1ffabc4Sita-sc return error; 125a1ffabc4Sita-sc 126a1ffabc4Sita-sc return Status(); 127a1ffabc4Sita-sc } 128a1ffabc4Sita-sc 1298244fc50SMichał Górny Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( 1308244fc50SMichał Górny NativeThreadProtocol &thread) { 1318244fc50SMichał Górny Status error; 1328244fc50SMichał Górny NativeProcessProtocol &process = thread.GetProcess(); 1338244fc50SMichał Górny NativeRegisterContext ®ister_context = thread.GetRegisterContext(); 1348244fc50SMichał Górny const ArchSpec &arch = process.GetArchitecture(); 1358244fc50SMichał Górny 1368244fc50SMichał Górny std::unique_ptr<EmulateInstruction> emulator_up( 1378244fc50SMichał Górny EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying, 1388244fc50SMichał Górny nullptr)); 1398244fc50SMichał Górny 1408244fc50SMichał Górny if (emulator_up == nullptr) 141*0642cd76SAdrian Prantl return Status::FromErrorString("Instruction emulator not found!"); 1428244fc50SMichał Górny 1438244fc50SMichał Górny EmulatorBaton baton(process, register_context); 1448244fc50SMichał Górny emulator_up->SetBaton(&baton); 1458244fc50SMichał Górny emulator_up->SetReadMemCallback(&ReadMemoryCallback); 1468244fc50SMichał Górny emulator_up->SetReadRegCallback(&ReadRegisterCallback); 1478244fc50SMichał Górny emulator_up->SetWriteMemCallback(&WriteMemoryCallback); 1488244fc50SMichał Górny emulator_up->SetWriteRegCallback(&WriteRegisterCallback); 1498244fc50SMichał Górny 150a1ffabc4Sita-sc if (!emulator_up->ReadInstruction()) { 151a1ffabc4Sita-sc // try to get at least the size of next instruction to set breakpoint. 152a1ffabc4Sita-sc auto instr_size = emulator_up->GetLastInstrSize(); 153a1ffabc4Sita-sc if (!instr_size) 154*0642cd76SAdrian Prantl return Status::FromErrorString("Read instruction failed!"); 155a1ffabc4Sita-sc bool success = false; 156a1ffabc4Sita-sc auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric, 157a1ffabc4Sita-sc LLDB_REGNUM_GENERIC_PC, 158a1ffabc4Sita-sc LLDB_INVALID_ADDRESS, &success); 159a1ffabc4Sita-sc if (!success) 160*0642cd76SAdrian Prantl return Status::FromErrorString("Reading pc failed!"); 161a1ffabc4Sita-sc lldb::addr_t next_pc = pc + *instr_size; 162a1ffabc4Sita-sc auto result = 163a1ffabc4Sita-sc SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process); 164a1ffabc4Sita-sc m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); 165a1ffabc4Sita-sc return result; 166a1ffabc4Sita-sc } 1678244fc50SMichał Górny 1688244fc50SMichał Górny bool emulation_result = 1698244fc50SMichał Górny emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); 1708244fc50SMichał Górny 1718244fc50SMichał Górny const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( 1728244fc50SMichał Górny eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); 1738244fc50SMichał Górny const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( 1748244fc50SMichał Górny eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); 1758244fc50SMichał Górny 1768244fc50SMichał Górny auto pc_it = 1778244fc50SMichał Górny baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); 17895e2949aSEmmmer auto flags_it = reg_info_flags == nullptr 17995e2949aSEmmmer ? baton.m_register_values.end() 18095e2949aSEmmmer : baton.m_register_values.find( 18195e2949aSEmmmer reg_info_flags->kinds[eRegisterKindDWARF]); 1828244fc50SMichał Górny 1838244fc50SMichał Górny lldb::addr_t next_pc; 1848244fc50SMichał Górny lldb::addr_t next_flags; 1858244fc50SMichał Górny if (emulation_result) { 1868244fc50SMichał Górny assert(pc_it != baton.m_register_values.end() && 1878244fc50SMichał Górny "Emulation was successfull but PC wasn't updated"); 1888244fc50SMichał Górny next_pc = pc_it->second.GetAsUInt64(); 1898244fc50SMichał Górny 1908244fc50SMichał Górny if (flags_it != baton.m_register_values.end()) 1918244fc50SMichał Górny next_flags = flags_it->second.GetAsUInt64(); 1928244fc50SMichał Górny else 1938244fc50SMichał Górny next_flags = ReadFlags(register_context); 1948244fc50SMichał Górny } else if (pc_it == baton.m_register_values.end()) { 1958244fc50SMichał Górny // Emulate instruction failed and it haven't changed PC. Advance PC with 1968244fc50SMichał Górny // the size of the current opcode because the emulation of all 1978244fc50SMichał Górny // PC modifying instruction should be successful. The failure most 1988244fc50SMichał Górny // likely caused by a not supported instruction which don't modify PC. 1998244fc50SMichał Górny next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); 2008244fc50SMichał Górny next_flags = ReadFlags(register_context); 2018244fc50SMichał Górny } else { 2028244fc50SMichał Górny // The instruction emulation failed after it modified the PC. It is an 2038244fc50SMichał Górny // unknown error where we can't continue because the next instruction is 2048244fc50SMichał Górny // modifying the PC but we don't know how. 205*0642cd76SAdrian Prantl return Status::FromErrorString( 206*0642cd76SAdrian Prantl "Instruction emulation failed unexpectedly."); 2078244fc50SMichał Górny } 208a1ffabc4Sita-sc auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process); 2098244fc50SMichał Górny m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); 210a1ffabc4Sita-sc return result; 2118244fc50SMichał Górny } 212