@@ -5498,6 +5498,31 @@ void ProcessGDBRemote::DidForkSwitchSoftwareBreakpoints(bool enable) {
54985498 });
54995499}
55005500
5501+ void ProcessGDBRemote::DidForkSwitchHardwareTraps (bool enable) {
5502+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware)) {
5503+ GetBreakpointSiteList ().ForEach ([this , enable](BreakpointSite *bp_site) {
5504+ if (bp_site->IsEnabled () &&
5505+ bp_site->GetType () == BreakpointSite::eHardware) {
5506+ m_gdb_comm.SendGDBStoppointTypePacket (
5507+ eBreakpointHardware, enable, bp_site->GetLoadAddress (),
5508+ GetSoftwareBreakpointTrapOpcode (bp_site), GetInterruptTimeout ());
5509+ }
5510+ });
5511+ }
5512+
5513+ WatchpointList &wps = GetTarget ().GetWatchpointList ();
5514+ size_t wp_count = wps.GetSize ();
5515+ for (size_t i = 0 ; i < wp_count; ++i) {
5516+ WatchpointSP wp = wps.GetByIndex (i);
5517+ if (wp->IsEnabled ()) {
5518+ GDBStoppointType type = GetGDBStoppointType (wp.get ());
5519+ m_gdb_comm.SendGDBStoppointTypePacket (type, enable, wp->GetLoadAddress (),
5520+ wp->GetByteSize (),
5521+ GetInterruptTimeout ());
5522+ }
5523+ }
5524+ }
5525+
55015526void ProcessGDBRemote::DidFork (lldb::pid_t child_pid, lldb::tid_t child_tid) {
55025527 Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
55035528
@@ -5506,30 +5531,58 @@ void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
55065531 // anyway.
55075532 lldb::tid_t parent_tid = m_thread_ids.front ();
55085533
5509- if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware)) {
5510- // Switch to the new process to clear breakpoints there.
5511- if (!m_gdb_comm.SetCurrentThread (child_tid, child_pid)) {
5512- LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to set pid/tid" );
5513- return ;
5514- }
5534+ lldb::pid_t follow_pid, detach_pid;
5535+ lldb::tid_t follow_tid, detach_tid;
5536+
5537+ switch (GetFollowForkMode ()) {
5538+ case eFollowParent:
5539+ follow_pid = parent_pid;
5540+ follow_tid = parent_tid;
5541+ detach_pid = child_pid;
5542+ detach_tid = child_tid;
5543+ break ;
5544+ case eFollowChild:
5545+ follow_pid = child_pid;
5546+ follow_tid = child_tid;
5547+ detach_pid = parent_pid;
5548+ detach_tid = parent_tid;
5549+ break ;
5550+ }
55155551
5516- // Disable all software breakpoints in the forked process.
5552+ // Switch to the process that is going to be detached.
5553+ if (!m_gdb_comm.SetCurrentThread (detach_tid, detach_pid)) {
5554+ LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to set pid/tid" );
5555+ return ;
5556+ }
5557+
5558+ // Disable all software breakpoints in the forked process.
5559+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
55175560 DidForkSwitchSoftwareBreakpoints (false );
55185561
5519- // Reset gdb-remote to the original process.
5520- if (!m_gdb_comm.SetCurrentThread (parent_tid, parent_pid)) {
5521- LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to reset pid/tid" );
5522- return ;
5523- }
5562+ // Remove hardware breakpoints / watchpoints from parent process if we're
5563+ // following child.
5564+ if (GetFollowForkMode () == eFollowChild)
5565+ DidForkSwitchHardwareTraps (false );
5566+
5567+ // Switch to the process that is going to be followed
5568+ if (!m_gdb_comm.SetCurrentThread (follow_tid, follow_pid) ||
5569+ !m_gdb_comm.SetCurrentThreadForRun (follow_tid, follow_pid)) {
5570+ LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to reset pid/tid" );
5571+ return ;
55245572 }
55255573
5526- LLDB_LOG (log, " Detaching forked child {0}" , child_pid );
5527- Status error = m_gdb_comm.Detach (false , child_pid );
5574+ LLDB_LOG (log, " Detaching process {0}" , detach_pid );
5575+ Status error = m_gdb_comm.Detach (false , detach_pid );
55285576 if (error.Fail ()) {
55295577 LLDB_LOG (log, " ProcessGDBRemote::DidFork() detach packet send failed: {0}" ,
55305578 error.AsCString () ? error.AsCString () : " <unknown error>" );
55315579 return ;
55325580 }
5581+
5582+ // Hardware breakpoints/watchpoints are not inherited implicitly,
5583+ // so we need to readd them if we're following child.
5584+ if (GetFollowForkMode () == eFollowChild)
5585+ DidForkSwitchHardwareTraps (true );
55335586}
55345587
55355588void ProcessGDBRemote::DidVFork (lldb::pid_t child_pid, lldb::tid_t child_tid) {
@@ -5542,8 +5595,40 @@ void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) {
55425595 if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
55435596 DidForkSwitchSoftwareBreakpoints (false );
55445597
5545- LLDB_LOG (log, " Detaching forked child {0}" , child_pid);
5546- Status error = m_gdb_comm.Detach (false , child_pid);
5598+ lldb::pid_t detach_pid;
5599+ lldb::tid_t detach_tid;
5600+
5601+ switch (GetFollowForkMode ()) {
5602+ case eFollowParent:
5603+ detach_pid = child_pid;
5604+ detach_tid = child_tid;
5605+ break ;
5606+ case eFollowChild:
5607+ detach_pid = m_gdb_comm.GetCurrentProcessID ();
5608+ // Any valid TID will suffice, thread-relevant actions will set a proper TID
5609+ // anyway.
5610+ detach_tid = m_thread_ids.front ();
5611+
5612+ // Switch to the parent process before detaching it.
5613+ if (!m_gdb_comm.SetCurrentThread (detach_tid, detach_pid)) {
5614+ LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to set pid/tid" );
5615+ return ;
5616+ }
5617+
5618+ // Remove hardware breakpoints / watchpoints from the parent process.
5619+ DidForkSwitchHardwareTraps (false );
5620+
5621+ // Switch to the child process.
5622+ if (!m_gdb_comm.SetCurrentThread (child_tid, child_pid) ||
5623+ !m_gdb_comm.SetCurrentThreadForRun (child_tid, child_pid)) {
5624+ LLDB_LOG (log, " ProcessGDBRemote::DidFork() unable to reset pid/tid" );
5625+ return ;
5626+ }
5627+ break ;
5628+ }
5629+
5630+ LLDB_LOG (log, " Detaching process {0}" , detach_pid);
5631+ Status error = m_gdb_comm.Detach (false , detach_pid);
55475632 if (error.Fail ()) {
55485633 LLDB_LOG (log,
55495634 " ProcessGDBRemote::DidFork() detach packet send failed: {0}" ,
@@ -5560,3 +5645,11 @@ void ProcessGDBRemote::DidVForkDone() {
55605645 if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
55615646 DidForkSwitchSoftwareBreakpoints (true );
55625647}
5648+
5649+ void ProcessGDBRemote::DidExec () {
5650+ // If we are following children, vfork is finished by exec (rather than
5651+ // vforkdone that is submitted for parent).
5652+ if (GetFollowForkMode () == eFollowChild)
5653+ m_vfork_in_progress = false ;
5654+ Process::DidExec ();
5655+ }
0 commit comments