// Helper script for remote gdb package main import ( "bufio" "flag" "fmt" "io" "os" "path" "strconv" "strings" "golang.org/x/crypto/ssh" ) var ( optUser = flag.String("user", "default", "username for ssh user") optPassword = flag.String("pass", "", "password") optGdbPort = flag.Uint("port", 10001, "remote gdb port to use") ) func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] hostname program args\n", os.Args[0]) flag.PrintDefaults() } flag.Parse() if flag.NArg() < 2 { flag.Usage() os.Exit(2) } connection, err := createConnection(flag.Arg(0), *optUser, *optPassword) if err != nil { fmt.Fprintf(os.Stderr, "Can't connect to host: %s", err.Error()) os.Exit(1) } defer connection.Close() err = deployFile(connection, flag.Arg(1), path.Base(flag.Arg(1)), "0755") if err != nil { fmt.Fprintf(os.Stderr, "Can't deploy file: %s", err.Error()) os.Exit(1) } session, err := startGDB(connection, "./"+path.Base(flag.Arg(1))) if err != nil { fmt.Fprintf(os.Stderr, "Can't start gdb: %s", err.Error()) os.Exit(1) } defer session.Close() } func startGDB(client *ssh.Client, remoteCommand string) (*ssh.Session, error) { session, err := client.NewSession() if err != nil { return nil, err } output, err := session.StderrPipe() if err != nil { return nil, err } err = session.Start("exec nohup gdbserver --once :" + strconv.Itoa(int(*optGdbPort)) + " " + remoteCommand) if err != nil { return nil, err } reader := bufio.NewReader(output) for line, err := reader.ReadString('\n'); err == nil; line, err = reader.ReadString('\n') { if strings.HasPrefix(line, "Listening on port") { println(line) break } } return session, nil } func deployFile(client *ssh.Client, localPath, remotePath string, permissions string) error { reader, err := os.Open(localPath) if err != nil { return err } defer reader.Close() st, err := reader.Stat() if err != nil { return err } session, err := client.NewSession() if err != nil { return err } defer session.Close() writer, _ := session.StdinPipe() go func() { fmt.Fprintf(writer, "C%s %d %s\n", permissions, st.Size(), path.Base(remotePath)) io.Copy(writer, reader) writer.Write([]byte{0x00}) writer.Close() }() return session.Run("/usr/bin/scp -t " + path.Dir(remotePath)) } func createConnection(host string, username string, password string) (*ssh.Client, error) { config := &ssh.ClientConfig{ User: username, Auth: []ssh.AuthMethod{ ssh.Password(password), }, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } return ssh.Dial("tcp", host, config) }