[Lldb-commits] [lldb] [lldb] Handle accelerator plugin breakpoint actions on the client (PR #201489)
satyanarayana reddy janga via lldb-commits
lldb-commits at lists.llvm.org
Thu Jun 4 19:12:14 PDT 2026
================
@@ -4124,6 +4143,168 @@ bool ProcessGDBRemote::NewThreadNotifyBreakpointHit(
return false;
}
+namespace {
+/// Baton that carries the breakpoint hit arguments to the accelerator plugin
+/// breakpoint callback.
+class AcceleratorBreakpointCallbackBaton
+ : public TypedBaton<AcceleratorBreakpointHitArgs> {
+public:
+ explicit AcceleratorBreakpointCallbackBaton(
+ std::unique_ptr<AcceleratorBreakpointHitArgs> data)
+ : TypedBaton(std::move(data)) {}
+};
+} // namespace
+
+Status
+ProcessGDBRemote::HandleAcceleratorActions(const AcceleratorActions &actions) {
+ Log *log = GetLog(GDBRLog::Process);
+
+ // The same set of actions can be delivered to the client more than once: a
+ // plugin may keep reporting the same actions (with the same identifier) on
+ // subsequent native stops until its state advances. The identifier uniquely
+ // names a set of actions for a plugin, so skip any set we have already
+ // processed to avoid re-running its side effects (e.g. setting the same
+ // breakpoints again).
+ auto it = m_processed_accelerator_actions.find(actions.plugin_name);
+ if (it != m_processed_accelerator_actions.end() &&
+ it->second == actions.identifier) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::HandleAcceleratorActions skipping already "
+ "processed actions for plugin '{0}' with identifier {1}",
+ actions.plugin_name, actions.identifier);
+ return Status();
+ }
+ m_processed_accelerator_actions[actions.plugin_name] = actions.identifier;
+
+ if (!actions.breakpoints.empty())
+ return HandleAcceleratorBreakpoints(actions);
+
+ return Status();
+}
+
+Status ProcessGDBRemote::HandleAcceleratorBreakpoints(
+ const AcceleratorActions &actions) {
+ Target &target = GetTarget();
+ Status error;
+ for (const AcceleratorBreakpointInfo &bp : actions.breakpoints) {
+ // Carry data with the breakpoint so the callback can notify the plugin
+ // when the breakpoint is hit.
+ auto args_up = std::make_unique<AcceleratorBreakpointHitArgs>();
+ args_up->plugin_name = actions.plugin_name;
+ args_up->breakpoint = bp;
+
+ BreakpointSP bp_sp;
+ if (bp.by_name) {
+ FileSpecList bp_modules;
+ if (bp.by_name->shlib && !bp.by_name->shlib->empty())
+ bp_modules.Append(FileSpec(*bp.by_name->shlib));
+ bp_sp = target.CreateBreakpoint(
+ bp_modules.GetSize() ? &bp_modules : nullptr, // Containing modules.
+ nullptr, // Containing source.
+ bp.by_name->function_name.c_str(), // Function name.
+ eFunctionNameTypeFull, // Function name type.
+ eLanguageTypeUnknown, // Language type.
+ 0, // Byte offset.
+ false, // Offset is insn count.
+ eLazyBoolNo, // Skip prologue.
+ true, // Internal breakpoint.
+ false); // Request hardware.
+ } else if (bp.by_address) {
+ bp_sp = target.CreateBreakpoint(bp.by_address->load_address,
+ /*internal=*/true,
+ /*request_hardware=*/false);
+ } else {
+ // Record the first error but keep setting the remaining breakpoints.
+ if (error.Success())
+ error = Status::FromErrorStringWithFormatv(
+ "accelerator breakpoint {0} has neither a by_name nor a by_address "
+ "specification",
+ bp.identifier);
+ continue;
+ }
+
+ if (!bp_sp) {
+ if (error.Success())
+ error = Status::FromErrorStringWithFormatv(
+ "failed to set accelerator breakpoint {0}", bp.identifier);
+ continue;
+ }
+
+ // Give the internal breakpoint a meaningful description for stop reasons.
+ bp_sp->SetBreakpointKind("accelerator-plugin");
+ auto baton_sp = std::make_shared<AcceleratorBreakpointCallbackBaton>(
+ std::move(args_up));
+ bp_sp->SetCallback(AcceleratorBreakpointHitCallback, baton_sp,
+ /*is_synchronous=*/true);
+ }
+ return error;
+}
+
+bool ProcessGDBRemote::AcceleratorBreakpointHitCallback(
+ void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+ ProcessSP process_sp = context->exe_ctx_ref.GetProcessSP();
+ ProcessGDBRemote *process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ return process->AcceleratorBreakpointHit(baton, context, break_id,
+ break_loc_id);
+}
+
+bool ProcessGDBRemote::AcceleratorBreakpointHit(
+ void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id) {
+ AcceleratorBreakpointHitArgs *callback_data =
+ static_cast<AcceleratorBreakpointHitArgs *>(baton);
+ // Copy the args so we can fill in requested symbol values before notifying
+ // lldb-server.
+ AcceleratorBreakpointHitArgs args = *callback_data;
+ Target &target = GetTarget();
+
+ const std::vector<std::string> &symbol_names = args.breakpoint.symbol_names;
+ args.symbol_values.resize(symbol_names.size());
+ for (size_t i = 0; i < symbol_names.size(); ++i) {
+ args.symbol_values[i].name = symbol_names[i];
+ SymbolContextList sc_list;
+ target.GetImages().FindSymbolsWithNameAndType(ConstString(symbol_names[i]),
+ eSymbolTypeAny, sc_list);
+ for (const SymbolContext &sc : sc_list) {
+ if (!sc.symbol)
+ continue;
+ addr_t load_addr = sc.symbol->GetAddress().GetLoadAddress(&target);
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ args.symbol_values[i].value = load_addr;
----------------
satyajanga wrote:
Yes, it is std::optional<lldb::addr_t>.
https://github.com/llvm/llvm-project/pull/201489
More information about the lldb-commits
mailing list