@@ -6215,3 +6215,177 @@ void ProcessGDBRemote::DidExec() {
62156215 }
62166216 Process::DidExec ();
62176217}
6218+
6219+ llvm::Error ProcessGDBRemote::UpdateBreakpointSitesNotBatched (
6220+ const std::map<lldb::BreakpointSiteSP, Process::BreakpointAction>
6221+ &site_to_action) {
6222+ llvm::Error joined = llvm::Error::success ();
6223+ for (auto &[site, action] : site_to_action) {
6224+ llvm::Error error = action == Process::BreakpointAction::Enable
6225+ ? DoEnableBreakpointSite (*site)
6226+ : DoDisableBreakpointSite (*site);
6227+ joined = llvm::joinErrors (std::move (joined), std::move (error));
6228+ }
6229+ return joined;
6230+ }
6231+
6232+ static llvm::Expected<StringExtractorGDBRemote>
6233+ SendMultiBreakpointPacket (GDBRemoteCommunicationClient &gdb_comm,
6234+ llvm::StringRef packet_str,
6235+ std::chrono::seconds interrupt_timeout) {
6236+ StringExtractorGDBRemote response;
6237+ GDBRemoteCommunication::PacketResult packet_result =
6238+ gdb_comm.SendPacketAndWaitForResponse (packet_str, response,
6239+ interrupt_timeout);
6240+ if (packet_result != GDBRemoteCommunication::PacketResult::Success)
6241+ return llvm::createStringErrorV (
6242+ " MultiBreakpoint failed to send packet: '{0}'" , packet_str);
6243+
6244+ if (response.IsUnsupportedResponse ())
6245+ return llvm::createStringErrorV (
6246+ " MultiBreakpoint unsupported response: '{0}'" , response.GetStringRef ());
6247+
6248+ return response;
6249+ }
6250+
6251+ // / Parse a MultiBreakpoint response into per-request results.
6252+ // / Returns a vector of results: std::nullopt means OK, a uint8_t value is the
6253+ // / error code from an Exx response.
6254+ static llvm::SmallVector<std::optional<uint8_t >>
6255+ ParseMultiBreakpointResponse (llvm::StringRef response_str) {
6256+ llvm::SmallVector<std::optional<uint8_t >> results;
6257+ llvm::SmallVector<llvm::StringRef> tokens;
6258+
6259+ // KeepEmpty = false to ignore trailings `;` in the response.
6260+ response_str.split (tokens, ' ;' , -1 , /* KeepEmpty=*/ false );
6261+ for (llvm::StringRef token : tokens) {
6262+ if (token == " OK" ) {
6263+ results.push_back (std::nullopt );
6264+ continue ;
6265+ }
6266+ if (token.size () != 3 || !token.starts_with (" E" )) {
6267+ results.push_back (uint8_t (0xff ));
6268+ continue ;
6269+ }
6270+ uint8_t error_code = 0 ;
6271+ if (token.drop_front (1 ).getAsInteger (16 , error_code))
6272+ results.push_back (0xff );
6273+ else
6274+ results.push_back (error_code);
6275+ }
6276+ return results;
6277+ }
6278+
6279+ // / Determine the GDB stoppoint type for a breakpoint site by checking which
6280+ // / packet types the remote supports (for insertions), or by checking the site
6281+ // / type (for deletions).
6282+ static std::optional<GDBStoppointType>
6283+ GetStoppointType (BreakpointSite &site, bool insert,
6284+ GDBRemoteCommunicationClient &gdb_comm) {
6285+ if (insert) {
6286+ if (!site.HardwareRequired () &&
6287+ gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
6288+ return eBreakpointSoftware;
6289+ if (gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware))
6290+ return eBreakpointHardware;
6291+ return std::nullopt ;
6292+ }
6293+
6294+ switch (site.GetType ()) {
6295+ case BreakpointSite::eExternal:
6296+ return eBreakpointSoftware;
6297+ case BreakpointSite::eHardware:
6298+ return eBreakpointHardware;
6299+ case BreakpointSite::eSoftware:
6300+ return std::nullopt ;
6301+ }
6302+ llvm_unreachable (" unhandled BreakpointSite type" );
6303+ }
6304+
6305+ namespace {
6306+ struct BreakpointPacketInfo {
6307+ BreakpointSite &site;
6308+ size_t trap_opcode;
6309+ GDBStoppointType type;
6310+ bool is_enable;
6311+ };
6312+
6313+ llvm::raw_ostream &operator <<(llvm::raw_ostream &stream,
6314+ const BreakpointPacketInfo &info) {
6315+ char packet = info.is_enable ? ' Z' : ' z' ;
6316+ return stream << llvm::formatv (" {0}{1},{2:x-},{3:x-}" , packet,
6317+ static_cast <int >(info.type ),
6318+ info.site .GetLoadAddress (), info.trap_opcode );
6319+ }
6320+ } // namespace
6321+
6322+ llvm::Error ProcessGDBRemote::UpdateBreakpointSites (
6323+ const std::map<lldb::BreakpointSiteSP, BreakpointAction> &site_to_action) {
6324+ if (site_to_action.empty ())
6325+ return llvm::Error::success ();
6326+ if (!m_gdb_comm.GetMultiBreakpointSupported ())
6327+ return UpdateBreakpointSitesNotBatched (site_to_action);
6328+
6329+ Log *log = GetLog (GDBRLog::Breakpoints);
6330+
6331+ std::vector<BreakpointPacketInfo> breakpoint_infos;
6332+
6333+ for (auto [site, action] : site_to_action) {
6334+ addr_t addr = site->GetLoadAddress ();
6335+ size_t trap_opcode = GetSoftwareBreakpointTrapOpcode (site.get ());
6336+ std::optional<GDBStoppointType> type =
6337+ GetStoppointType (*site, action == BreakpointAction::Enable, m_gdb_comm);
6338+ if (!type) {
6339+ LLDB_LOG (log, " MultiBreakpoint: site {0} at {1:x} can't be batched" ,
6340+ site->GetID (), addr);
6341+ return UpdateBreakpointSitesNotBatched (site_to_action);
6342+ }
6343+ breakpoint_infos.push_back (
6344+ {*site, trap_opcode, *type, action == BreakpointAction::Enable});
6345+ }
6346+
6347+ std::string packet_str;
6348+ llvm::raw_string_ostream stream (packet_str);
6349+ stream << " MultiBreakpoint:" ;
6350+ llvm::interleave (breakpoint_infos, stream, " ;" );
6351+
6352+ llvm::Expected<StringExtractorGDBRemote> response =
6353+ SendMultiBreakpointPacket (m_gdb_comm, packet_str, GetInterruptTimeout ());
6354+
6355+ if (!response) {
6356+ LLDB_LOG_ERROR (log, response.takeError (), " MultiBreakpoint failed: {0}" );
6357+ return UpdateBreakpointSitesNotBatched (site_to_action);
6358+ }
6359+
6360+ llvm::SmallVector<std::optional<uint8_t >> results =
6361+ ParseMultiBreakpointResponse (response->GetStringRef ());
6362+
6363+ // This is a protocol violation, do nothing.
6364+ if (results.size () != site_to_action.size ())
6365+ return llvm::createStringErrorV (
6366+ " MultiBreakpoint response count mismatch (expected {0}, got {1})" ,
6367+ site_to_action.size (), results.size ());
6368+
6369+ // Process results: mark successful sites as enabled/disabled, retry failed
6370+ // sites individually.
6371+ llvm::Error joined = llvm::Error::success ();
6372+ for (auto [error_code, bp_info] : llvm::zip (results, breakpoint_infos)) {
6373+ BreakpointSite &site = bp_info.site ;
6374+ if (error_code == std::nullopt ) {
6375+ SetBreakpointSiteEnabled (site, bp_info.is_enable );
6376+ if (bp_info.is_enable )
6377+ site.SetType (bp_info.type == eBreakpointHardware
6378+ ? BreakpointSite::eHardware
6379+ : BreakpointSite::eExternal);
6380+ continue ;
6381+ }
6382+ LLDB_LOG (log,
6383+ " MultiBreakpoint: site {0} at {1:x} failed (E{2:X-2}), retrying" ,
6384+ site.GetID (), site.GetLoadAddress (), *error_code);
6385+ llvm::Error error = bp_info.is_enable ? DoEnableBreakpointSite (site)
6386+ : DoDisableBreakpointSite (site);
6387+ joined = llvm::joinErrors (std::move (joined), std::move (error));
6388+ }
6389+
6390+ return joined;
6391+ }
0 commit comments