// Helper script for remote gdb // Copyright (C) 2017 Moritz Bitsch // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . 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), "/tmp/"+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, "/tmp/"+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 { fmt.Printf("Deploy: %s -> %s\n", localPath, remotePath) 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) }