diff --git a/cmd/bingo/main.go b/cmd/bingo/main.go index 3f56e70..df15886 100644 --- a/cmd/bingo/main.go +++ b/cmd/bingo/main.go @@ -4,7 +4,8 @@ import ( "log" "os" "os/signal" - "syscall" + + "golang.org/x/sys/unix" "github.com/bingosuite/bingo/config" websocket "github.com/bingosuite/bingo/internal/ws" @@ -28,7 +29,7 @@ func main() { // Set up signal handling for graceful shutdown sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM) + signal.Notify(sigChan, os.Interrupt, unix.SIGTERM) // Wait for shutdown signal <-sigChan diff --git a/go.mod b/go.mod index 470f467..3df868c 100644 --- a/go.mod +++ b/go.mod @@ -68,7 +68,7 @@ require ( golang.org/x/mod v0.27.0 // indirect golang.org/x/net v0.43.0 // indirect golang.org/x/sync v0.17.0 // indirect - golang.org/x/sys v0.35.0 // indirect + golang.org/x/sys v0.41.0 // indirect golang.org/x/term v0.34.0 golang.org/x/text v0.29.0 // indirect golang.org/x/tools v0.36.0 // indirect diff --git a/go.sum b/go.sum index 3ca58b5..09d8120 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,8 @@ golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= diff --git a/internal/debugger/debugger.go b/internal/debugger/debugger_linux_amd64.go similarity index 89% rename from internal/debugger/debugger.go rename to internal/debugger/debugger_linux_amd64.go index 5429a2f..3c33ec3 100644 --- a/internal/debugger/debugger.go +++ b/internal/debugger/debugger_linux_amd64.go @@ -8,10 +8,11 @@ import ( "path/filepath" "runtime" "strings" - "syscall" "time" "github.com/bingosuite/bingo/internal/debuginfo" + + "golang.org/x/sys/unix" ) var ( @@ -115,7 +116,7 @@ func (d *Debugger) StartWithDebug(path string) { cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.SysProcAttr = &syscall.SysProcAttr{Ptrace: true} + cmd.SysProcAttr = &unix.SysProcAttr{Ptrace: true} if err := cmd.Start(); err != nil { log.Printf("[Debugger] Failed to start target: %v", err) @@ -130,7 +131,7 @@ func (d *Debugger) StartWithDebug(path string) { log.Printf("[Debugger] Started process with PID: %d and PGID: %d\n", dbInf.Target.PID, dbInf.Target.PGID) // Enable tracking threads spawned from target and killing target once Bingo exits - if err := syscall.PtraceSetOptions(dbInf.Target.PID, syscall.PTRACE_O_TRACECLONE|ptraceOExitKill); err != nil { + if err := unix.PtraceSetOptions(dbInf.Target.PID, unix.PTRACE_O_TRACECLONE|ptraceOExitKill); err != nil { log.Printf("[Debugger] Failed to set TRACECLONE and EXITKILL options on target: %v", err) panic(err) } @@ -140,8 +141,8 @@ func (d *Debugger) StartWithDebug(path string) { // We want to catch the initial SIGTRAP sent by process creation. When this is caught, we know that the target just started and we can ask the user where they want to set their breakpoints // The message we print to the console will be removed in the future, it's just for debugging purposes for now. - var waitStatus syscall.WaitStatus - if _, status := syscall.Wait4(d.DebugInfo.Target.PID, &waitStatus, 0, nil); status != nil { + var waitStatus unix.WaitStatus + if _, status := unix.Wait4(d.DebugInfo.Target.PID, &waitStatus, 0, nil); status != nil { log.Printf("[Debugger] Received SIGTRAP from process creation: %v", status) } @@ -167,8 +168,8 @@ func (d *Debugger) StartWithDebug(path string) { func (d *Debugger) Continue(pid int) { // Read registers - var regs syscall.PtraceRegs - if err := syscall.PtraceGetRegs(pid, ®s); err != nil { + var regs unix.PtraceRegs + if err := unix.PtraceGetRegs(pid, ®s); err != nil { log.Printf("[Debugger] Failed to get registers: %v", err) panic(err) } @@ -184,22 +185,22 @@ func (d *Debugger) Continue(pid int) { regs.Rip = bpAddr // Rewind Rip by 1 - if err := syscall.PtraceSetRegs(pid, ®s); err != nil { + if err := unix.PtraceSetRegs(pid, ®s); err != nil { log.Printf("[Debugger] Failed to restore registers: %v", err) panic(err) } // Step over the instruction we previously removed to put the breakpoint // TODO: decide if we want to call debugger.SingleStep() for this or just the system - if err := syscall.PtraceSingleStep(pid); err != nil { + if err := unix.PtraceSingleStep(pid); err != nil { log.Printf("[Debugger] Failed to single-step: %v", err) panic(err) } // TODO: only trigger for step over signal - var waitStatus syscall.WaitStatus + var waitStatus unix.WaitStatus // Wait until the program lets us know we stepped over (handle cases where we get another signal which Wait4 would consume) - if _, err := syscall.Wait4(pid, &waitStatus, 0, nil); err != nil { + if _, err := unix.Wait4(pid, &waitStatus, 0, nil); err != nil { log.Printf("[Debugger] Failed to wait for the single-step: %v", err) panic(err) } @@ -212,7 +213,7 @@ func (d *Debugger) Continue(pid int) { // Resume execution // TODO: decide if we want to call debugger.Continue() for this or just the system call - if err := syscall.PtraceCont(pid, 0); err != nil { + if err := unix.PtraceCont(pid, 0); err != nil { log.Printf("[Debugger] Failed to resume target execution: %v", err) panic(err) } @@ -221,7 +222,7 @@ func (d *Debugger) Continue(pid int) { func (d *Debugger) SingleStep(pid int) { - if err := syscall.PtraceSingleStep(pid); err != nil { + if err := unix.PtraceSingleStep(pid); err != nil { log.Printf("[Debugger] Failed to single-step: %v", err) panic(err) } @@ -232,7 +233,7 @@ func (d *Debugger) StopDebug() { // Detach from the target process, letting it continue running if d.DebugInfo.Target.PID > 0 { log.Printf("[Debugger] Detaching from target process (PID: %d)", d.DebugInfo.Target.PID) - if err := syscall.PtraceDetach(d.DebugInfo.Target.PID); err != nil { + if err := unix.PtraceDetach(d.DebugInfo.Target.PID); err != nil { log.Printf("[Debugger] Failed to detach from target process: %v (might have already exited)", err) panic(err) } @@ -253,10 +254,10 @@ func (d *Debugger) SetBreakpoint(pid int, line int) error { } original := make([]byte, len(bpCode)) - if _, err := syscall.PtracePeekData(pid, uintptr(pc), original); err != nil { + if _, err := unix.PtracePeekData(pid, uintptr(pc), original); err != nil { return fmt.Errorf("failed to read original machine code into memory: %v for PID: %d", err, pid) } - if _, err := syscall.PtracePokeData(pid, uintptr(pc), bpCode); err != nil { + if _, err := unix.PtracePokeData(pid, uintptr(pc), bpCode); err != nil { return fmt.Errorf("failed to write breakpoint into memory: %v", err) } d.Breakpoints[pc] = original @@ -269,7 +270,7 @@ func (d *Debugger) ClearBreakpoint(pid int, line int) error { if err != nil { return fmt.Errorf("failed to get PC of line %v: %v", line, err) } - if _, err := syscall.PtracePokeData(pid, uintptr(pc), d.Breakpoints[pc]); err != nil { + if _, err := unix.PtracePokeData(pid, uintptr(pc), d.Breakpoints[pc]); err != nil { return fmt.Errorf("failed to write breakpoint into memory: %v", err) } return nil @@ -288,8 +289,8 @@ func (d *Debugger) mainDebugLoop() { } // Wait until any of the child processes of the target is interrupted or ends - var waitStatus syscall.WaitStatus - wpid, err := syscall.Wait4(-1*d.DebugInfo.Target.PGID, &waitStatus, syscall.WNOHANG, nil) + var waitStatus unix.WaitStatus + wpid, err := unix.Wait4(-1*d.DebugInfo.Target.PGID, &waitStatus, unix.WNOHANG, nil) if err != nil { log.Printf("[Debugger] Failed to wait for the target or any of its threads: %v", err) // Don't panic, just exit gracefully @@ -317,13 +318,13 @@ func (d *Debugger) mainDebugLoop() { } } else { // Only stop on breakpoints caused by our debugger, ignore any other event like spawning of new threads - if waitStatus.StopSignal() == syscall.SIGTRAP && waitStatus.TrapCause() != syscall.PTRACE_EVENT_CLONE { + if waitStatus.StopSignal() == unix.SIGTRAP && waitStatus.TrapCause() != unix.PTRACE_EVENT_CLONE { //TODO: improve error handling and messages d.breakpointHit(wpid) } else { - if err := syscall.PtraceCont(wpid, 0); err != nil { + if err := unix.PtraceCont(wpid, 0); err != nil { log.Printf("[Debugger] Failed to resume target execution: %v for PID: %d", err, wpid) // Don't panic, might have been detached return @@ -364,7 +365,7 @@ func (d *Debugger) initialBreakpointHit() { } case "continue": log.Println("[Debugger] Continuing from initial breakpoint") - if err := syscall.PtraceCont(d.DebugInfo.Target.PID, 0); err != nil { + if err := unix.PtraceCont(d.DebugInfo.Target.PID, 0); err != nil { log.Printf("[Debugger] Failed to resume target execution: %v", err) panic(err) } @@ -386,8 +387,8 @@ func (d *Debugger) initialBreakpointHit() { func (d *Debugger) breakpointHit(pid int) { // Get register information to determine location - var regs syscall.PtraceRegs - if err := syscall.PtraceGetRegs(pid, ®s); err != nil { + var regs unix.PtraceRegs + if err := unix.PtraceGetRegs(pid, ®s); err != nil { log.Printf("[Debugger] Failed to get registers: %v", err) panic(err) } diff --git a/internal/debuginfo/debug_info.go b/internal/debuginfo/debug_info.go index ad3896e..8b55089 100644 --- a/internal/debuginfo/debug_info.go +++ b/internal/debuginfo/debug_info.go @@ -4,7 +4,8 @@ import ( "debug/elf" "debug/gosym" "fmt" - "syscall" + + "golang.org/x/sys/unix" ) type Target struct { @@ -48,7 +49,7 @@ func NewDebugInfo(path string, pid int) (*DebugInfo, error) { sourceFile, _, _ := symTable.PCToLine(symTable.LookupFunc("main.main").Entry) // Need this to wait on threads - pgid, err := syscall.Getpgid(pid) + pgid, err := unix.Getpgid(pid) if err != nil { return nil, fmt.Errorf("error getting PGID: %v", err) }