Skip to content

Instantly share code, notes, and snippets.

@matthijskooijman
Created September 25, 2015 16:18
Show Gist options
  • Save matthijskooijman/89152be7c5a5040df245 to your computer and use it in GitHub Desktop.
Save matthijskooijman/89152be7c5a5040df245 to your computer and use it in GitHub Desktop.
package main
import (
// "os/exec"
"github.com/cyrus-and/gdb"
"log"
"os"
"bufio"
"strings"
"fmt"
"encoding/json"
)
const openocdPath = "/home/matthijs/.arduino15/packages/arduino/tools/openocd/0.9.0-arduino/bin/openocd"
const gdbPath = "/home/matthijs/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-gdb"
const openocdScripts = "/home/matthijs/.arduino15/packages/arduino/tools/openocd/0.9.0-arduino/share/openocd/scripts/"
const openocdConfig = "/home/matthijs/.arduino15/packages/arduino/hardware/samd/1.6.1/variants/arduino_zero/openocd_scripts/arduino_zero.cfg"
const elf = "/tmp/build8600053f19645e2961d8ec07ec4ee74e.tmp/Blink.ino.elf"
func logLines(str string) {
lines := strings.Split(str, "\n")
for i, line := range lines {
if line != "" || i == 0 || i < len(lines) - 1 {
log.Println(line)
}
}
}
func logThing(thing interface{}) {
pretty, _ := json.MarshalIndent(thing, "", " ")
logLines(string(pretty))
}
func onNotification(notification map[string]interface{}) {
switch notification["type"] {
case "console", "log":
logLines(fmt.Sprint(notification["payload"]))
default:
logThing(notification)
}
}
func main() {
/*
openocd := exec.Command(openocdPath, "-s", openocdScripts, "-f", openocdConfig)
openocd.Stdout = os.Stdout
openocd.Stderr = os.Stderr
err := openocd.Start()
if err != nil {
log.Fatal(err)
}
defer openocd.Process.Kill()
*/
gdb.GdbCommand = gdbPath
gdb, err := gdb.New(onNotification)
if err != nil {
log.Fatal(err)
}
defer gdb.Exit()
_, err = gdb.Send("file-exec-and-symbols", elf)
if err != nil {
log.Fatal(err)
}
_, err = gdb.Send("gdb-set remotelogfile /tmp/golog")
if err != nil {
log.Fatal(err)
}
// Let gdb start openocd and connect to it through its
// stdin/stdout. This prevents the need for openocd to listen on
// a network port, and the associated security risks.
//
// All arguments to gdb.Send (except the first commandname) will
// be quoted before sending them to gdb. Since target-select is
// not implemented as a proper mi command inside gdb, but simply
// executes the "target" CLI passing the arguments as-is, adding
// quotes to "remote" and the pipe breaks their processing.
//
// Anything sent after the pipe is passed as-is to /bin/sh by
// gdb, so the actual openocd command and its arguments are
// passed to gdb.Send separately, so it will apply quoting to
// them (which can then be unquoted by sh).
//
// TODO: gdb.Send uses simple quoting, which leaves in special
// characters such as $ and ` which can still be executed by the
// shell. Ideally, gdb would have a specific MI command for
// executing the pipe, where each MI argument becomes a
// commandline argument and doesn't involve the shell at all,
// but without that we should make sure to apply more thorough
// escaping to the openocd command.
_, err = gdb.Send("target-select remote | ", openocdPath, "-c", "gdb_port pipe", "--search", openocdScripts, "--file", openocdConfig)
if err != nil {
log.Fatal(err)
}
bio := bufio.NewReader(os.Stdin)
for {
line, _, err := bio.ReadLine()
if err != nil {
log.Fatal(err)
}
if string(line) == "int" {
fmt.Fprintln(os.Stderr, ">>> Sending interrupt...")
gdb.Interrupt()
continue
}
fmt.Fprintln(os.Stderr, ">>> ", string(line))
result, err := gdb.Send(string(line))
switch {
case err != nil:
log.Print(err)
case result["class"] == "done" || result["class"] == "running":
if payload, ok := result["payload"]; ok {
logThing(payload)
}
default:
logThing(result)
}
}
}
func gdb_connect_tcp(gdb gdb.Gdb) {
// Giving arguments to gdb.Send separately causes them to be
// quoted. Since target-select is not implemented as a proper mi
// command inside gdb, but simply executes the "target" CLI
// passing the arguments as-is, adding quotes breaks the
// processing of these arguments. By putting them in the command
// argument to gdb.Send, the values are passed unquoted, making
// this command work.
result, err := gdb.Send("target-select remote localhost:3333")
log.Print(result)
if err != nil {
log.Fatal(err)
}
}
// TODO: http://openocd.org/doc/html/GDB-and-OpenOCD.html#Configuring-GDB-for-OpenOCD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment