diff options
Diffstat (limited to 'gdb-native.go')
-rw-r--r-- | gdb-native.go | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/gdb-native.go b/gdb-native.go new file mode 100644 index 0000000..a4e6189 --- /dev/null +++ b/gdb-native.go @@ -0,0 +1,164 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "os/exec" + "syscall" + "time" + + "github.com/Sirupsen/logrus" + "github.com/kr/pty" +) + +type GdbNative struct { + log *logrus.Logger + ccmd string + aargs []string + eenv []string + + exeCmd *exec.Cmd + fdPty *os.File + + // callbacks + cbOnDisconnect func(error) + cbRead func(timestamp, stdout, stderr string) + cbInferiorRead func(timestamp, stdout, stderr string) + cbOnExit func(code int, err error) + + running bool +} + +// NewGdbNative creates a new instance of GdbNative +func NewGdbNative(log *logrus.Logger, args []string, env []string) *GdbNative { + return &GdbNative{ + log: log, + ccmd: "/usr/bin/gdb", + aargs: args, + eenv: env, + } +} + +// SetConfig set additional config fields +func (g *GdbNative) SetConfig(name string, value interface{}) error { + return fmt.Errorf("Unknown %s field", name) +} + +// Init initializes gdb XDS +func (g *GdbNative) Init() (int, error) { + + // Create the exec command + g.exeCmd = exec.Command(g.ccmd, g.aargs...) + + return 0, nil +} + +// Close +func (g *GdbNative) Close() error { + g.cbOnDisconnect = nil + g.cbOnExit = nil + g.cbRead = nil + g.cbInferiorRead = nil + + g.running = false + + return nil +} + +// Start sends a request to start remotely gdb within xds-server +func (g *GdbNative) Start(inferiorTTY bool) (int, error) { + var err error + + // Start pty and consequently gdb process + if g.fdPty, err = pty.Start(g.exeCmd); err != nil { + return int(syscall.ESPIPE), err + } + + g.running = true + + // Monitor gdb process EOF + go func() { + // Execute command and wait EOF + err := g.exeCmd.Wait() + g.cbOnDisconnect(err) + g.running = false + }() + + // Handle STDOUT + go func() { + sc := bufio.NewScanner(g.fdPty) + sc.Split(split) + for sc.Scan() { + if g.cbRead != nil { + g.cbRead(time.Now().String(), sc.Text(), "") + } + if !g.running { + return + } + } + }() + + return 0, nil +} + +// Cmd returns the command name +func (g *GdbNative) Cmd() string { + return g.ccmd +} + +// Args returns the list of arguments +func (g *GdbNative) Args() []string { + return g.aargs +} + +// Env returns the list of environment variables +func (g *GdbNative) Env() []string { + return g.eenv +} + +// OnError doesn't make sens +func (g *GdbNative) OnError(f func(error)) { + // nothing to do +} + +// OnDisconnect is called when stdin is disconnected +func (g *GdbNative) OnDisconnect(f func(error)) { + g.cbOnDisconnect = f +} + +// OnExit calls when exit event is received +func (g *GdbNative) OnExit(f func(code int, err error)) { + g.cbOnExit = f +} + +// Read calls when a message/string event is received on stdout or stderr +func (g *GdbNative) Read(f func(timestamp, stdout, stderr string)) { + g.cbRead = f +} + +// InferiorRead calls when a message/string event is received on stdout or stderr of the debugged program (IOW inferior) +func (g *GdbNative) InferiorRead(f func(timestamp, stdout, stderr string)) { + g.cbInferiorRead = f +} + +// Write writes message/string into gdb stdin +func (g *GdbNative) Write(args ...interface{}) error { + s := fmt.Sprint(args...) + _, err := g.fdPty.Write([]byte(s)) + return err +} + +// SendSignal is used to send a signal to remote process/gdb +func (g *GdbNative) SendSignal(sig os.Signal) error { + return g.exeCmd.Process.Signal(sig) +} + +//***** Private functions ***** + +func split(data []byte, atEOF bool) (advance int, token []byte, err error) { + if atEOF && len(data) == 0 { + return 0, nil, nil + } + return len(data), data, nil +} |