This revision was automatically updated to reflect the committed changes.
Closed by commit rL292937: FreeBSD ARM support for software single step
(authored by emaste).
Changed prior to commit:
https://reviews.llvm.org/D25756?vs=79987&id=85581#toc
Repository:
rL LLVM
https://reviews.llvm.org/D25756
Files:
lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
Index: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
+++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -1141,11 +1141,19 @@
case SI_KERNEL:
case TRAP_BRKPT:
- if (log)
- log->Printf(
- "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64,
- __FUNCTION__, tid);
- message = ProcessMessage::Break(tid);
+ if (monitor->m_process->IsSoftwareStepBreakpoint(tid)) {
+ if (log)
+ log->Printf("ProcessMonitor::%s() received sw single step breakpoint "
+ "event, tid = %" PRIu64,
+ __FUNCTION__, tid);
+ message = ProcessMessage::Trace(tid);
+ } else {
+ if (log)
+ log->Printf(
+ "ProcessMonitor::%s() received breakpoint event, tid = %" PRIu64,
+ __FUNCTION__, tid);
+ message = ProcessMessage::Break(tid);
+ }
break;
}
Index: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
===================================================================
--- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
+++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -171,7 +171,25 @@
virtual FreeBSDThread *CreateNewFreeBSDThread(lldb_private::Process &process,
lldb::tid_t tid);
+ static bool SingleStepBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ lldb_private::Error SetupSoftwareSingleStepping(lldb::tid_t tid);
+
+ lldb_private::Error SetSoftwareSingleStepBreakpoint(lldb::tid_t tid,
+ lldb::addr_t addr);
+
+ bool IsSoftwareStepBreakpoint(lldb::tid_t tid);
+
+ bool SupportHardwareSingleStepping() const;
+
+ typedef std::vector<lldb::tid_t> tid_collection;
+ tid_collection &GetStepTids() { return m_step_tids; }
+
protected:
+ static const size_t MAX_TRAP_OPCODE_SIZE = 8;
+
/// Target byte order.
lldb::ByteOrder m_byte_order;
@@ -207,10 +225,10 @@
friend class FreeBSDThread;
- typedef std::vector<lldb::tid_t> tid_collection;
tid_collection m_suspend_tids;
tid_collection m_run_tids;
tid_collection m_step_tids;
+ std::map<lldb::tid_t, lldb::break_id_t> m_threads_stepping_with_breakpoint;
int m_resume_signo;
};
Index: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
===================================================================
--- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
+++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -13,6 +13,7 @@
// C++ Includes
#include <mutex>
+#include <unordered_map>
// Other libraries and framework includes
#include "lldb/Core/PluginManager.h"
@@ -122,6 +123,7 @@
std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
bool do_step = false;
+ bool software_single_step = !SupportHardwareSingleStepping();
for (tid_collection::const_iterator t_pos = m_run_tids.begin(),
t_end = m_run_tids.end();
@@ -133,6 +135,11 @@
t_pos != t_end; ++t_pos) {
m_monitor->ThreadSuspend(*t_pos, false);
do_step = true;
+ if (software_single_step) {
+ Error error = SetupSoftwareSingleStepping(*t_pos);
+ if (error.Fail())
+ return error;
+ }
}
for (tid_collection::const_iterator t_pos = m_suspend_tids.begin(),
t_end = m_suspend_tids.end();
@@ -145,7 +152,7 @@
if (log)
log->Printf("process %" PRIu64 " resuming (%s)", GetID(),
do_step ? "step" : "continue");
- if (do_step)
+ if (do_step && !software_single_step)
m_monitor->SingleStep(GetID(), m_resume_signo);
else
m_monitor->Resume(GetID(), m_resume_signo);
@@ -913,3 +920,194 @@
"no platform or not the host - how did we get here with ProcessFreeBSD?");
return DataBufferSP();
}
+
+struct EmulatorBaton {
+ ProcessFreeBSD *m_process;
+ RegisterContext *m_reg_context;
+
+ // eRegisterKindDWARF -> RegisterValue
+ std::unordered_map<uint32_t, RegisterValue> m_register_values;
+
+ EmulatorBaton(ProcessFreeBSD *process, RegisterContext *reg_context)
+ : m_process(process), m_reg_context(reg_context) {}
+};
+
+static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, void *dst, size_t length) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+ Error error;
+ size_t bytes_read =
+ emulator_baton->m_process->DoReadMemory(addr, dst, length, error);
+ if (!error.Success())
+ bytes_read = 0;
+ return bytes_read;
+}
+
+static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue ®_value) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+
+ auto it = emulator_baton->m_register_values.find(
+ reg_info->kinds[eRegisterKindDWARF]);
+ if (it != emulator_baton->m_register_values.end()) {
+ reg_value = it->second;
+ return true;
+ }
+
+ // The emulator only fills in the dwarf register numbers (and in some cases
+ // the generic register numbers). Get the full register info from the
+ // register context based on the dwarf register numbers.
+ const RegisterInfo *full_reg_info =
+ emulator_baton->m_reg_context->GetRegisterInfo(
+ eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]);
+
+ bool error =
+ emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value);
+ return error;
+}
+
+static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue ®_value) {
+ EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton);
+ emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] =
+ reg_value;
+ return true;
+}
+
+static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr, const void *dst,
+ size_t length) {
+ return length;
+}
+
+bool ProcessFreeBSD::SingleStepBreakpointHit(
+ void *baton, lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id, lldb::user_id_t break_loc_id) {
+ return false;
+}
+
+Error ProcessFreeBSD::SetSoftwareSingleStepBreakpoint(lldb::tid_t tid,
+ lldb::addr_t addr) {
+ Error error;
+
+ Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
+ if (log) {
+ log->Printf("ProcessFreeBSD::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+ log->Printf("SoftwareBreakpoint::%s addr = 0x%" PRIx64, __FUNCTION__, addr);
+ }
+
+ // Validate the address.
+ if (addr == LLDB_INVALID_ADDRESS)
+ return Error("ProcessFreeBSD::%s invalid load address specified.",
+ __FUNCTION__);
+
+ Breakpoint *const sw_step_break =
+ m_process->GetTarget().CreateBreakpoint(addr, true, false).get();
+ sw_step_break->SetCallback(SingleStepBreakpointHit, this, true);
+ sw_step_break->SetBreakpointKind("software-signle-step");
+
+ if (log)
+ log->Printf("ProcessFreeBSD::%s addr = 0x%" PRIx64 " -- SUCCESS",
+ __FUNCTION__, addr);
+
+ m_threads_stepping_with_breakpoint.insert({tid, sw_step_break->GetID()});
+ return Error();
+}
+
+bool ProcessFreeBSD::IsSoftwareStepBreakpoint(lldb::tid_t tid) {
+ ThreadSP thread = GetThreadList().FindThreadByID(tid);
+ if (!thread)
+ return false;
+
+ assert(thread->GetRegisterContext());
+ lldb::addr_t stop_pc = thread->GetRegisterContext()->GetPC();
+
+ const auto &iter = m_threads_stepping_with_breakpoint.find(tid);
+ if (iter == m_threads_stepping_with_breakpoint.end())
+ return false;
+
+ lldb::break_id_t bp_id = iter->second;
+ BreakpointSP bp = GetTarget().GetBreakpointByID(bp_id);
+ if (!bp)
+ return false;
+
+ BreakpointLocationSP bp_loc = bp->FindLocationByAddress(stop_pc);
+ if (!bp_loc)
+ return false;
+
+ GetTarget().RemoveBreakpointByID(bp_id);
+ m_threads_stepping_with_breakpoint.erase(tid);
+ return true;
+}
+
+bool ProcessFreeBSD::SupportHardwareSingleStepping() const {
+ lldb_private::ArchSpec arch = GetTarget().GetArchitecture();
+ if (arch.GetMachine() == llvm::Triple::arm ||
+ arch.GetMachine() == llvm::Triple::mips64 ||
+ arch.GetMachine() == llvm::Triple::mips64el ||
+ arch.GetMachine() == llvm::Triple::mips ||
+ arch.GetMachine() == llvm::Triple::mipsel)
+ return false;
+ return true;
+}
+
+Error ProcessFreeBSD::SetupSoftwareSingleStepping(lldb::tid_t tid) {
+ std::unique_ptr<EmulateInstruction> emulator_ap(
+ EmulateInstruction::FindPlugin(GetTarget().GetArchitecture(),
+ eInstructionTypePCModifying, nullptr));
+
+ if (emulator_ap == nullptr)
+ return Error("Instruction emulator not found!");
+
+ FreeBSDThread *thread = static_cast<FreeBSDThread *>(
+ m_thread_list.FindThreadByID(tid, false).get());
+ if (thread == NULL)
+ return Error("Thread not found not found!");
+
+ lldb::RegisterContextSP register_context_sp = thread->GetRegisterContext();
+
+ EmulatorBaton baton(this, register_context_sp.get());
+ emulator_ap->SetBaton(&baton);
+ emulator_ap->SetReadMemCallback(&ReadMemoryCallback);
+ emulator_ap->SetReadRegCallback(&ReadRegisterCallback);
+ emulator_ap->SetWriteMemCallback(&WriteMemoryCallback);
+ emulator_ap->SetWriteRegCallback(&WriteRegisterCallback);
+
+ if (!emulator_ap->ReadInstruction())
+ return Error("Read instruction failed!");
+
+ bool emulation_result =
+ emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC);
+ const RegisterInfo *reg_info_pc = register_context_sp->GetRegisterInfo(
+ eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ auto pc_it =
+ baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]);
+
+ lldb::addr_t next_pc;
+ if (emulation_result) {
+ assert(pc_it != baton.m_register_values.end() &&
+ "Emulation was successful but PC wasn't updated");
+ next_pc = pc_it->second.GetAsUInt64();
+ } else if (pc_it == baton.m_register_values.end()) {
+ // Emulate instruction failed and it haven't changed PC. Advance PC
+ // with the size of the current opcode because the emulation of all
+ // PC modifying instruction should be successful. The failure most
+ // likely caused by a not supported instruction which don't modify PC.
+ next_pc =
+ register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize();
+ } else {
+ // The instruction emulation failed after it modified the PC. It is an
+ // unknown error where we can't continue because the next instruction is
+ // modifying the PC but we don't know how.
+ return Error("Instruction emulation failed unexpectedly");
+ }
+
+ SetSoftwareSingleStepBreakpoint(tid, next_pc);
+ return Error();
+}
Index: lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
===================================================================
--- lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
+++ lldb/trunk/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -549,6 +549,12 @@
// FreeBSD kernel as of 10.x, does not support thumb breakpoints
return 0;
}
+
+ static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7};
+ size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode);
+ assert(bp_site);
+ if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size))
+ return trap_opcode_size;
}
LLVM_FALLTHROUGH;
default:
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits