[starnix] Copy the debug address to the cloned process

This is necessary to be able to debug process after they forked, but
before having run exec.

Change-Id: I02802b994b9f034d15d5133cf90eb3e4cd9019f7
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693705
Fuchsia-Auto-Submit: Benjamin Lerman <qsr@google.com>
Reviewed-by: Kevin Lindkvist <lindkvist@google.com>
Commit-Queue: Benjamin Lerman <qsr@google.com>
diff --git a/src/proc/bin/starnix/execution/shared.rs b/src/proc/bin/starnix/execution/shared.rs
index 63d5a6b..c3b6697 100644
--- a/src/proc/bin/starnix/execution/shared.rs
+++ b/src/proc/bin/starnix/execution/shared.rs
@@ -63,9 +63,6 @@
         // Still set the debug address, and clear the debug address from `current_task` to avoid
         // entering this function again.
         match current_task.thread_group.process.set_debug_addr(&debug_address.value) {
-            // TODO(tbodt): When a process execs, it will want to set its debug address again, and
-            // zircon only allows the debug address to be set once. We should figure out how to get
-            // the debugger to handle exec, or maybe kill the process and start a new one on exec.
             Err(zx::Status::ACCESS_DENIED) => {}
             status => status.map_err(|err| from_status_like_fdio!(err))?,
         };
@@ -113,6 +110,29 @@
     Ok(())
 }
 
+pub fn copy_process_debug_addr(
+    source_process: &zx::Process,
+    target_process: &zx::Process,
+) -> Result<(), Errno> {
+    let source_debug_addr =
+        source_process.get_debug_addr().map_err(|err| from_status_like_fdio!(err))?;
+    let target_debug_addr =
+        target_process.get_debug_addr().map_err(|err| from_status_like_fdio!(err))?;
+
+    // TODO: Handle the case where either of the debug address requires to set an interrupt.
+    if source_debug_addr == ZX_PROCESS_DEBUG_ADDR_BREAK_ON_SET as u64 {
+        return Ok(());
+    }
+    if target_debug_addr == ZX_PROCESS_DEBUG_ADDR_BREAK_ON_SET as u64 {
+        return Ok(());
+    }
+    match target_process.set_debug_addr(&source_debug_addr) {
+        Err(zx::Status::ACCESS_DENIED) => {}
+        status => status.map_err(|err| from_status_like_fdio!(err))?,
+    };
+    Ok(())
+}
+
 pub struct StartupHandles {
     pub shell_controller: Option<ServerEnd<fstardev::ShellControllerMarker>>,
 }
diff --git a/src/proc/bin/starnix/task/task.rs b/src/proc/bin/starnix/task/task.rs
index f293fd3..91d7feb 100644
--- a/src/proc/bin/starnix/task/task.rs
+++ b/src/proc/bin/starnix/task/task.rs
@@ -370,6 +370,7 @@
             child_state.signals.alt_stack = state.signals.alt_stack;
             child_state.signals.mask = state.signals.mask;
             self.mm.snapshot_to(&child.mm)?;
+            copy_process_debug_addr(&self.thread_group.process, &child.thread_group.process)?;
         }
 
         if flags & (CLONE_PARENT_SETTID as u64) != 0 {