diff --git a/cli/debug/debug.go b/cli/debug/debug.go index d7ca207dd42..8e7c16b6134 100644 --- a/cli/debug/debug.go +++ b/cli/debug/debug.go @@ -17,18 +17,23 @@ package debug import ( "context" + "fmt" "os" "os/signal" + "sort" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" "github.com/arduino/arduino-cli/commands/debug" - rpc "github.com/arduino/arduino-cli/rpc/commands" dbg "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/arduino-cli/table" "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/fatih/color" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "google.golang.org/grpc/status" ) var ( @@ -38,6 +43,8 @@ var ( verify bool interpreter string importDir string + printInfo bool + programmer string ) // NewCommand created a new `upload` command @@ -46,15 +53,17 @@ func NewCommand() *cobra.Command { Use: "debug", Short: "Debug Arduino sketches.", Long: "Debug Arduino sketches. (this command opens an interactive gdb session)", - Example: " " + os.Args[0] + " debug -b arduino:samd:mkr1000 /home/user/Arduino/MySketch", + Example: " " + os.Args[0] + " debug -b arduino:samd:mkr1000 -P atmel_ice /home/user/Arduino/MySketch", Args: cobra.MaximumNArgs(1), Run: run, } debugCommand.Flags().StringVarP(&fqbn, "fqbn", "b", "", "Fully Qualified Board Name, e.g.: arduino:avr:uno") debugCommand.Flags().StringVarP(&port, "port", "p", "", "Debug port, e.g.: COM10 or /dev/ttyACM0") + debugCommand.Flags().StringVarP(&programmer, "programmer", "P", "", "Programmer to use for debugging") debugCommand.Flags().StringVar(&interpreter, "interpreter", "console", "Debug interpreter e.g.: console, mi, mi1, mi2, mi3") debugCommand.Flags().StringVarP(&importDir, "input-dir", "", "", "Directory containing binaries for debug.") + debugCommand.Flags().BoolVarP(&printInfo, "info", "I", false, "Show metadata about the debug session instead of starting the debugger.") return debugCommand } @@ -72,20 +81,40 @@ func run(command *cobra.Command, args []string) { } sketchPath := initSketchPath(path) - // Intercept SIGINT and forward them to debug process - ctrlc := make(chan os.Signal, 1) - signal.Notify(ctrlc, os.Interrupt) - - if _, err := debug.Debug(context.Background(), &dbg.DebugConfigReq{ - Instance: &rpc.Instance{Id: instance.GetId()}, + debugConfigRequested := &dbg.DebugConfigReq{ + Instance: instance, Fqbn: fqbn, SketchPath: sketchPath.String(), Port: port, Interpreter: interpreter, ImportDir: importDir, - }, os.Stdin, os.Stdout, ctrlc); err != nil { - feedback.Errorf("Error during Debug: %v", err) - os.Exit(errorcodes.ErrGeneric) + Programmer: programmer, + } + + if printInfo { + + if res, err := debug.GetDebugConfig(context.Background(), debugConfigRequested); err != nil { + if status, ok := status.FromError(err); ok { + feedback.Errorf("Error getting Debug info: %v", status.Message()) + errorcodes.ExitWithGrpcStatus(status) + } + feedback.Errorf("Error getting Debug info: %v", err) + os.Exit(errorcodes.ErrGeneric) + } else { + feedback.PrintResult(&debugInfoResult{res}) + } + + } else { + + // Intercept SIGINT and forward them to debug process + ctrlc := make(chan os.Signal, 1) + signal.Notify(ctrlc, os.Interrupt) + + if _, err := debug.Debug(context.Background(), debugConfigRequested, os.Stdin, os.Stdout, ctrlc); err != nil { + feedback.Errorf("Error during Debug: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + } } @@ -103,3 +132,42 @@ func initSketchPath(sketchPath *paths.Path) *paths.Path { logrus.Infof("Reading sketch from dir: %s", wd) return wd } + +type debugInfoResult struct { + info *dbg.GetDebugConfigResp +} + +func (r *debugInfoResult) Data() interface{} { + return r.info +} + +func (r *debugInfoResult) String() string { + t := table.New() + green := color.New(color.FgHiGreen) + dimGreen := color.New(color.FgGreen) + t.AddRow("Executable to debug", table.NewCell(r.info.GetExecutable(), green)) + t.AddRow("Toolchain type", table.NewCell(r.info.GetToolchain(), green)) + t.AddRow("Toolchain path", table.NewCell(r.info.GetToolchainPath(), dimGreen)) + t.AddRow("Toolchain prefix", table.NewCell(r.info.GetToolchainPrefix(), dimGreen)) + if len(r.info.GetToolchainConfiguration()) > 0 { + conf := properties.NewFromHashmap(r.info.GetToolchainConfiguration()) + keys := conf.Keys() + sort.Strings(keys) + t.AddRow("Toolchain custom configurations") + for _, k := range keys { + t.AddRow(table.NewCell(" - "+k, dimGreen), table.NewCell(conf.Get(k), dimGreen)) + } + } + t.AddRow("GDB Server type", table.NewCell(r.info.GetServer(), green)) + t.AddRow("GDB Server path", table.NewCell(r.info.GetServerPath(), dimGreen)) + if len(r.info.GetServerConfiguration()) > 0 { + conf := properties.NewFromHashmap(r.info.GetServerConfiguration()) + keys := conf.Keys() + sort.Strings(keys) + t.AddRow(fmt.Sprintf("%s custom configurations", r.info.GetServer())) + for _, k := range keys { + t.AddRow(table.NewCell(" - "+k, dimGreen), table.NewCell(conf.Get(k), dimGreen)) + } + } + return t.Render() +} diff --git a/cli/errorcodes/errorcodes.go b/cli/errorcodes/errorcodes.go index 777967e9460..529aead1efd 100644 --- a/cli/errorcodes/errorcodes.go +++ b/cli/errorcodes/errorcodes.go @@ -15,6 +15,13 @@ package errorcodes +import ( + "os" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + // Error codes to be used for os.Exit(). const ( _ = iota // 0 is not a valid exit error code @@ -29,3 +36,14 @@ const ( ErrCoreConfig ErrBadArgument ) + +// ExitWithGrpcStatus will terminate the current process by returing the correct +// error code closest matching the gRPC status. +func ExitWithGrpcStatus(s *status.Status) { + switch s.Code() { + case codes.Unimplemented: + os.Exit(ErrBadArgument) + default: + os.Exit(ErrGeneric) + } +} diff --git a/commands/daemon/debug.go b/commands/daemon/debug.go index b3ecef435a7..88ea30eec9e 100644 --- a/commands/daemon/debug.go +++ b/commands/daemon/debug.go @@ -16,10 +16,12 @@ package daemon import ( + "context" "os" "github.com/arduino/arduino-cli/arduino/utils" cmd "github.com/arduino/arduino-cli/commands/debug" + "github.com/arduino/arduino-cli/rpc/debug" dbg "github.com/arduino/arduino-cli/rpc/debug" "github.com/pkg/errors" ) @@ -64,3 +66,8 @@ func (s *DebugService) Debug(stream dbg.Debug_DebugServer) error { } return stream.Send(resp) } + +// GetDebugConfig return metadata about a debug session +func (s *DebugService) GetDebugConfig(ctx context.Context, req *debug.DebugConfigReq) (*debug.GetDebugConfigResp, error) { + return cmd.GetDebugConfig(ctx, req) +} diff --git a/commands/debug/debug.go b/commands/debug/debug.go index 3a51c10f041..b35cc0c6eb2 100644 --- a/commands/debug/debug.go +++ b/commands/debug/debug.go @@ -21,17 +21,14 @@ import ( "io" "os" "path/filepath" - "strings" + "runtime" "time" - "github.com/arduino/arduino-cli/arduino/cores" "github.com/arduino/arduino-cli/arduino/cores/packagemanager" - "github.com/arduino/arduino-cli/arduino/sketches" "github.com/arduino/arduino-cli/commands" "github.com/arduino/arduino-cli/executils" dbg "github.com/arduino/arduino-cli/rpc/debug" "github.com/arduino/go-paths-helper" - "github.com/arduino/go-properties-orderedmap" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -44,17 +41,15 @@ import ( // It also implements tool process lifecycle management func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out io.Writer, interrupt <-chan os.Signal) (*dbg.DebugResp, error) { - // Get tool commandLine from core recipe + // Get debugging command line to run debugger pm := commands.GetPackageManager(req.GetInstance().GetId()) commandLine, err := getCommandLine(req, pm) if err != nil { return nil, errors.Wrap(err, "Cannot get command line for tool") } - // Transform every path to forward slashes (on Windows some tools further - // escapes the command line so the backslash "\" gets in the way). - for i, param := range commandLine { - commandLine[i] = filepath.ToSlash(param) + for i, arg := range commandLine { + fmt.Printf("%2d: %s\n", i, arg) } // Run Tool @@ -115,130 +110,74 @@ func Debug(ctx context.Context, req *dbg.DebugConfigReq, inStream io.Reader, out // getCommandLine compose a debug command represented by a core recipe func getCommandLine(req *dbg.DebugConfigReq, pm *packagemanager.PackageManager) ([]string, error) { - if req.GetImportFile() != "" { - return nil, errors.New("the ImportFile parameter has been deprecated, use ImportDir instead") - } - - // TODO: make a generic function to extract sketch from request - // and remove duplication in commands/compile.go - if req.GetSketchPath() == "" { - return nil, fmt.Errorf("missing sketchPath") - } - sketchPath := paths.New(req.GetSketchPath()) - sketch, err := sketches.NewSketchFromPath(sketchPath) + debugInfo, err := getDebugProperties(req, pm) if err != nil { - return nil, errors.Wrap(err, "opening sketch") + return nil, err } - fqbnIn := req.GetFqbn() - if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { - fqbnIn = sketch.Metadata.CPU.Fqbn + cmdArgs := []string{} + add := func(s string) { cmdArgs = append(cmdArgs, s) } + + // Add path to GDB Client to command line + var gdbPath *paths.Path + switch debugInfo.GetToolchain() { + case "gcc": + gdbexecutable := debugInfo.ToolchainPrefix + "gdb" + if runtime.GOOS == "windows" { + gdbexecutable += ".exe" + } + gdbPath = paths.New(debugInfo.ToolchainPath).Join(gdbexecutable) + default: + return nil, errors.Errorf("unsupported toolchain '%s'", debugInfo.GetToolchain()) } - if fqbnIn == "" { - return nil, fmt.Errorf("no Fully Qualified Board Name provided") + add(gdbPath.String()) + + // Set GDB interpreter (default value should be "console") + gdbInterpreter := req.GetInterpreter() + if gdbInterpreter == "" { + gdbInterpreter = "console" } - fqbn, err := cores.ParseFQBN(fqbnIn) - if err != nil { - return nil, errors.Wrap(err, "error parsing FQBN") + add("--interpreter=" + gdbInterpreter) + if gdbInterpreter != "console" { + add("-ex") + add("set pagination off") } - // Find target board and board properties - _, _, board, boardProperties, _, err := pm.ResolveFQBN(fqbn) - if err != nil { - return nil, errors.Wrap(err, "error resolving FQBN") - } + // Add extra GDB execution commands + add("-ex") + add("set remotetimeout 5") - // Load programmer tool - toolName, have := boardProperties.GetOk("debug.tool") - if !have || toolName == "" { - return nil, fmt.Errorf("cannot get programmer tool: undefined 'debug.tool' property") - } + // Extract path to GDB Server + switch debugInfo.GetServer() { + case "openocd": + serverCmd := fmt.Sprintf(`target extended-remote | "%s"`, debugInfo.ServerPath) - var referencedPlatformRelease *cores.PlatformRelease - if split := strings.Split(toolName, ":"); len(split) > 2 { - return nil, fmt.Errorf("invalid 'debug.tool' property: %s", toolName) - } else if len(split) == 2 { - referencedPackageName := split[0] - toolName = split[1] - architecture := board.PlatformRelease.Platform.Architecture - - if referencedPackage := pm.Packages[referencedPackageName]; referencedPackage == nil { - return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) - } else if referencedPlatform := referencedPackage.Platforms[architecture]; referencedPlatform == nil { - return nil, fmt.Errorf("required platform %s:%s not installed", referencedPackageName, architecture) - } else { - referencedPlatformRelease = pm.GetInstalledPlatformRelease(referencedPlatform) + if cfg := debugInfo.ServerConfiguration["scripts_dir"]; cfg != "" { + serverCmd += fmt.Sprintf(` -s "%s"`, cfg) } - } - // Build configuration for debug - toolProperties := properties.NewMap() - if referencedPlatformRelease != nil { - toolProperties.Merge(referencedPlatformRelease.Properties) - } - toolProperties.Merge(board.PlatformRelease.Properties) - toolProperties.Merge(board.PlatformRelease.RuntimeProperties()) - toolProperties.Merge(boardProperties) - - requestedToolProperties := toolProperties.SubTree("tools." + toolName) - toolProperties.Merge(requestedToolProperties) - if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { - for _, requiredTool := range requiredTools { - logrus.WithField("tool", requiredTool).Info("Tool required for debug") - toolProperties.Merge(requiredTool.RuntimeProperties()) + if script := debugInfo.ServerConfiguration["script"]; script != "" { + serverCmd += fmt.Sprintf(` --file "%s"`, script) } - } - var importPath *paths.Path - if importDir := req.GetImportDir(); importDir != "" { - importPath = paths.New(importDir) - } else { - // TODO: Create a function to obtain importPath from sketch - importPath = sketch.FullPath - // Add FQBN (without configs part) to export path - fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1) - importPath = importPath.Join("build").Join(fqbnSuffix) - } - if !importPath.Exist() { - return nil, fmt.Errorf("compiled sketch not found in %s", importPath) - } - if !importPath.IsDir() { - return nil, fmt.Errorf("expected compiled sketch in directory %s, but is a file instead", importPath) - } - toolProperties.SetPath("build.path", importPath) - toolProperties.Set("build.project_name", sketch.Name+".ino") - - // Set debug port property - port := req.GetPort() - if port != "" { - toolProperties.Set("debug.port", port) - if strings.HasPrefix(port, "/dev/") { - toolProperties.Set("debug.port.file", port[5:]) - } else { - toolProperties.Set("debug.port.file", port) - } - } + serverCmd += ` -c "gdb_port pipe"` + serverCmd += ` -c "telnet_port 0"` + + add("-ex") + add(serverCmd) - // Set debugger interpreter (default value should be "console") - interpreter := req.GetInterpreter() - if interpreter != "" { - toolProperties.Set("interpreter", interpreter) - } else { - toolProperties.Set("interpreter", "console") + default: + return nil, errors.Errorf("unsupported gdb server '%s'", debugInfo.GetServer()) } - // Build recipe for tool - recipe := toolProperties.Get("debug.pattern") + // Add executable + add(debugInfo.Executable) - // REMOVEME: hotfix for samd core 1.8.5/1.8.6 - if recipe == `"{path}/{cmd}" --interpreter=mi2 -ex "set pagination off" -ex 'target extended-remote | {tools.openocd.path}/{tools.openocd.cmd} -s "{tools.openocd.path}/share/openocd/scripts/" --file "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "gdb_port pipe" -c "telnet_port 0"' {build.path}/{build.project_name}.elf` { - recipe = `"{path}/{cmd}" --interpreter={interpreter} -ex "set remotetimeout 5" -ex "set pagination off" -ex 'target extended-remote | "{tools.openocd.path}/{tools.openocd.cmd}" -s "{tools.openocd.path}/share/openocd/scripts/" --file "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "gdb_port pipe" -c "telnet_port 0"' "{build.path}/{build.project_name}.elf"` + // Transform every path to forward slashes (on Windows some tools further + // escapes the command line so the backslash "\" gets in the way). + for i, param := range cmdArgs { + cmdArgs[i] = filepath.ToSlash(param) } - cmdLine := toolProperties.ExpandPropsInString(recipe) - cmdArgs, err := properties.SplitQuotedString(cmdLine, `"'`, false) - if err != nil { - return nil, fmt.Errorf("invalid recipe '%s': %s", recipe, err) - } return cmdArgs, nil } diff --git a/commands/debug/debug_info.go b/commands/debug/debug_info.go new file mode 100644 index 00000000000..faad0987458 --- /dev/null +++ b/commands/debug/debug_info.go @@ -0,0 +1,169 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package debug + +import ( + "context" + "fmt" + "strings" + + "github.com/arduino/arduino-cli/arduino/cores" + "github.com/arduino/arduino-cli/arduino/cores/packagemanager" + "github.com/arduino/arduino-cli/arduino/sketches" + "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/rpc/debug" + "github.com/arduino/go-paths-helper" + "github.com/arduino/go-properties-orderedmap" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// GetDebugConfig returns metadata to start debugging with the specified board +func GetDebugConfig(ctx context.Context, req *debug.DebugConfigReq) (*debug.GetDebugConfigResp, error) { + pm := commands.GetPackageManager(req.GetInstance().GetId()) + + return getDebugProperties(req, pm) +} + +func getDebugProperties(req *debug.DebugConfigReq, pm *packagemanager.PackageManager) (*debug.GetDebugConfigResp, error) { + // TODO: make a generic function to extract sketch from request + // and remove duplication in commands/compile.go + if req.GetSketchPath() == "" { + return nil, fmt.Errorf("missing sketchPath") + } + sketchPath := paths.New(req.GetSketchPath()) + sketch, err := sketches.NewSketchFromPath(sketchPath) + if err != nil { + return nil, errors.Wrap(err, "opening sketch") + } + + // XXX Remove this code duplication!! + fqbnIn := req.GetFqbn() + if fqbnIn == "" && sketch != nil && sketch.Metadata != nil { + fqbnIn = sketch.Metadata.CPU.Fqbn + } + if fqbnIn == "" { + return nil, fmt.Errorf("no Fully Qualified Board Name provided") + } + fqbn, err := cores.ParseFQBN(fqbnIn) + if err != nil { + return nil, errors.Wrap(err, "error parsing FQBN") + } + + // Find target board and board properties + _, platformRelease, board, boardProperties, referencedPlatformRelease, err := pm.ResolveFQBN(fqbn) + if err != nil { + return nil, errors.Wrap(err, "error resolving FQBN") + } + + // Build configuration for debug + toolProperties := properties.NewMap() + if referencedPlatformRelease != nil { + toolProperties.Merge(referencedPlatformRelease.Properties) + } + toolProperties.Merge(platformRelease.Properties) + toolProperties.Merge(platformRelease.RuntimeProperties()) + toolProperties.Merge(boardProperties) + + // HOTFIX: Remove me when the `arduino:samd` core is updated + if !toolProperties.ContainsKey("debug.executable") { + if platformRelease.String() == "arduino:samd@1.8.9" || platformRelease.String() == "arduino:samd@1.8.8" { + toolProperties.Set("debug.executable", "{build.path}/{build.project_name}.elf") + toolProperties.Set("debug.toolchain", "gcc") + toolProperties.Set("debug.toolchain.path", "{runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/") + toolProperties.Set("debug.toolchain.prefix", "arm-none-eabi-") + toolProperties.Set("debug.server", "openocd") + toolProperties.Set("debug.server.openocd.path", "{runtime.tools.openocd-0.10.0-arduino7.path}/bin/openocd") + toolProperties.Set("debug.server.openocd.scripts_dir", "{runtime.tools.openocd-0.10.0-arduino7.path}/share/openocd/scripts/") + toolProperties.Set("debug.server.openocd.script", "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}") + } + } + + for _, tool := range pm.GetAllInstalledToolsReleases() { + toolProperties.Merge(tool.RuntimeProperties()) + } + if requiredTools, err := pm.FindToolsRequiredForBoard(board); err == nil { + for _, requiredTool := range requiredTools { + logrus.WithField("tool", requiredTool).Info("Tool required for debug") + toolProperties.Merge(requiredTool.RuntimeProperties()) + } + } + + if req.GetProgrammer() != "" { + if p, ok := platformRelease.Programmers[req.GetProgrammer()]; ok { + toolProperties.Merge(p.Properties) + } else if refP, ok := referencedPlatformRelease.Programmers[req.GetProgrammer()]; ok { + toolProperties.Merge(refP.Properties) + } else { + return nil, fmt.Errorf("programmer '%s' not found", req.GetProgrammer()) + } + } + + var importPath *paths.Path + if importDir := req.GetImportDir(); importDir != "" { + importPath = paths.New(importDir) + } else { + // TODO: Create a function to obtain importPath from sketch + importPath = sketch.FullPath + // Add FQBN (without configs part) to export path + fqbnSuffix := strings.Replace(fqbn.StringWithoutConfig(), ":", ".", -1) + importPath = importPath.Join("build").Join(fqbnSuffix) + } + if !importPath.Exist() { + return nil, fmt.Errorf("compiled sketch not found in %s", importPath) + } + if !importPath.IsDir() { + return nil, fmt.Errorf("expected compiled sketch in directory %s, but is a file instead", importPath) + } + toolProperties.SetPath("build.path", importPath) + toolProperties.Set("build.project_name", sketch.Name+".ino") + + // Set debug port property + port := req.GetPort() + if port != "" { + toolProperties.Set("debug.port", port) + if strings.HasPrefix(port, "/dev/") { + toolProperties.Set("debug.port.file", port[5:]) + } else { + toolProperties.Set("debug.port.file", port) + } + } + + // Extract and expand all debugging properties + debugProperties := properties.NewMap() + for k, v := range toolProperties.SubTree("debug").AsMap() { + debugProperties.Set(k, toolProperties.ExpandPropsInString(v)) + } + + if !debugProperties.ContainsKey("executable") { + return nil, status.Error(codes.Unimplemented, fmt.Sprintf("debugging not supported for board %s", req.GetFqbn())) + } + + server := debugProperties.Get("server") + toolchain := debugProperties.Get("toolchain") + return &debug.GetDebugConfigResp{ + Executable: debugProperties.Get("executable"), + Server: server, + ServerPath: debugProperties.Get("server." + server + ".path"), + ServerConfiguration: debugProperties.SubTree("server." + server).AsMap(), + Toolchain: toolchain, + ToolchainPath: debugProperties.Get("toolchain.path"), + ToolchainPrefix: debugProperties.Get("toolchain.prefix"), + ToolchainConfiguration: debugProperties.SubTree("toolchain." + toolchain).AsMap(), + }, nil +} diff --git a/commands/debug/debug_test.go b/commands/debug/debug_test.go index 8d0fd57ad7f..7712ad455a9 100644 --- a/commands/debug/debug_test.go +++ b/commands/debug/debug_test.go @@ -53,12 +53,12 @@ func TestGetCommandLine(t *testing.T) { SketchPath: sketchPath.String(), } - goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + - " --interpreter=console -ex target extended-remote |" + - fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + + goldCommand := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb%s", dataDir, toolExtension) + + " --interpreter=console -ex set remotetimeout 5 -ex target extended-remote |" + + fmt.Sprintf(" \"%s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s\"", dataDir, toolExtension) + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/arduino_zero/openocd_scripts/arduino_zero.cfg\"", customHardware) + - fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/build/arduino-test.samd.arduino_zero_edbg/hello.ino.elf", sketchPath) + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" %s/build/arduino-test.samd.arduino_zero_edbg/hello.ino.elf", sketchPath) command, err := getCommandLine(req, pm) require.Nil(t, err) @@ -74,12 +74,12 @@ func TestGetCommandLine(t *testing.T) { Interpreter: "mi1", } - goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin//arm-none-eabi-gdb%s", dataDir, toolExtension) + - " --interpreter=mi1 -ex target extended-remote |" + - fmt.Sprintf(" %s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s", dataDir, toolExtension) + + goldCommand2 := fmt.Sprintf("%s/arduino-test/tools/arm-none-eabi-gcc/7-2017q4/bin/arm-none-eabi-gdb%s", dataDir, toolExtension) + + " --interpreter=mi1 -ex set pagination off -ex set remotetimeout 5 -ex target extended-remote |" + + fmt.Sprintf(" \"%s/arduino-test/tools/openocd/0.10.0-arduino7/bin/openocd%s\"", dataDir, toolExtension) + fmt.Sprintf(" -s \"%s/arduino-test/tools/openocd/0.10.0-arduino7/share/openocd/scripts/\"", dataDir) + fmt.Sprintf(" --file \"%s/arduino-test/samd/variants/mkr1000/openocd_scripts/arduino_zero.cfg\"", customHardware) + - fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" -c init -c halt %s/build/arduino-test.samd.mkr1000/hello.ino.elf", sketchPath) + fmt.Sprintf(" -c \"gdb_port pipe\" -c \"telnet_port 0\" %s/build/arduino-test.samd.mkr1000/hello.ino.elf", sketchPath) command2, err := getCommandLine(req2, pm) assert.Nil(t, err) diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt index 033fb584fa7..ea2b1c6d3ff 100644 --- a/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/boards.txt @@ -20,7 +20,6 @@ arduino_zero_edbg.name=Arduino Zero (Programming Port) arduino_zero_edbg.vid.0=0x03eb arduino_zero_edbg.pid.0=0x2157 -arduino_zero_edbg.debug.tool=gdb-openocd arduino_zero_edbg.upload.tool=openocd arduino_zero_edbg.upload.protocol=sam-ba arduino_zero_edbg.upload.maximum_size=262144 @@ -55,7 +54,6 @@ mkr1000.pid.2=0x824e mkr1000.vid.3=0x2341 mkr1000.pid.3=0x024e -mkr1000.debug.tool=gdb-openocd mkr1000.upload.tool=bossac mkr1000.upload.protocol=sam-ba mkr1000.upload.maximum_size=262144 diff --git a/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt index 5e61eb4db44..13a012118e8 100644 --- a/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt +++ b/commands/debug/testdata/custom_hardware/arduino-test/samd/platform.txt @@ -113,6 +113,22 @@ recipe.output.save_file={build.project_name}.{build.variant}.{build.preferred_ou recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" recipe.size.regex=\.text\s+([0-9]+).* + +# Debugger configuration (general options) +# ---------------------------------------- +# EXPERIMENTAL feature: +# - this is alpha and may be subject to change without notice +debug.executable={build.path}/{build.project_name}.elf +debug.toolchain=gcc +debug.toolchain.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ +debug.toolchain.prefix=arm-none-eabi- +debug.server=openocd +debug.server.openocd.path={runtime.tools.openocd-0.10.0-arduino7.path}/bin/openocd +debug.server.openocd.path.windows={runtime.tools.openocd-0.10.0-arduino7.path}/bin/openocd.exe +debug.server.openocd.scripts_dir={runtime.tools.openocd-0.10.0-arduino7.path}/share/openocd/scripts/ +debug.server.openocd.script={runtime.platform.path}/variants/{build.variant}/{build.openocdscript} + + # Upload/Debug tools # ------------------ @@ -219,13 +235,3 @@ tools.openocd-withbootsize.erase.pattern= tools.openocd-withbootsize.bootloader.params.verbose=-d2 tools.openocd-withbootsize.bootloader.params.quiet=-d0 tools.openocd-withbootsize.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown" - -# -# GDB (Debugger) -# - -tools.gdb-openocd.path={runtime.tools.arm-none-eabi-gcc-7-2017q4.path}/bin/ -tools.gdb-openocd.cmd=arm-none-eabi-gdb -tools.gdb-openocd.cmd.windows=arm-none-eabi-gdb.exe -tools.gdb-openocd.interpreter=console -tools.gdb-openocd.debug.pattern="{path}/{cmd}" --interpreter={interpreter} -ex 'target extended-remote | {tools.openocd.path}/{tools.openocd.cmd} -s "{tools.openocd.path}/share/openocd/scripts/" --file "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "gdb_port pipe" -c "telnet_port 0" -c init -c halt' {build.path}/{build.project_name}.elf diff --git a/rpc/debug/debug.pb.go b/rpc/debug/debug.pb.go index 78459b85514..30f042c2af2 100644 --- a/rpc/debug/debug.pb.go +++ b/rpc/debug/debug.pb.go @@ -47,7 +47,7 @@ const _ = proto.ProtoPackageIsVersion4 // The top-level message sent by the client for the `Debug` method. // Multiple `DebugReq` messages can be sent but the first message -// must contain a `DebugReq` message to initialize the debug session. +// must contain a `DebugConfigReq` message to initialize the debug session. // All subsequent messages must contain bytes to be sent to the debug session // and must not contain a `DebugReq` message. type DebugReq struct { @@ -132,18 +132,16 @@ type DebugConfigReq struct { // Path to the sketch that is running on the board. The compiled executable // is expected to be located under this path. SketchPath string `protobuf:"bytes,3,opt,name=sketch_path,json=sketchPath,proto3" json:"sketch_path,omitempty"` - // Port of the debugger. Set to `none` if the debugger doesn't use a port. + // Port of the debugger (optional). Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` // Which GDB command interpreter to use. Interpreter string `protobuf:"bytes,5,opt,name=interpreter,proto3" json:"interpreter,omitempty"` - // DEPRECATED: use import_dir instead - // - // Deprecated: Do not use. - ImportFile string `protobuf:"bytes,7,opt,name=import_file,json=importFile,proto3" json:"import_file,omitempty"` // Directory containing the compiled executable. If `import_dir` is not // specified, the executable is assumed to be in // `{sketch_path}/build/{fqbn}/`. ImportDir string `protobuf:"bytes,8,opt,name=import_dir,json=importDir,proto3" json:"import_dir,omitempty"` + // The programmer to use for debugging. + Programmer string `protobuf:"bytes,9,opt,name=programmer,proto3" json:"programmer,omitempty"` } func (x *DebugConfigReq) Reset() { @@ -213,17 +211,16 @@ func (x *DebugConfigReq) GetInterpreter() string { return "" } -// Deprecated: Do not use. -func (x *DebugConfigReq) GetImportFile() string { +func (x *DebugConfigReq) GetImportDir() string { if x != nil { - return x.ImportFile + return x.ImportDir } return "" } -func (x *DebugConfigReq) GetImportDir() string { +func (x *DebugConfigReq) GetProgrammer() string { if x != nil { - return x.ImportDir + return x.Programmer } return "" } @@ -286,6 +283,117 @@ func (x *DebugResp) GetError() string { return "" } +type GetDebugConfigResp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The executable binary to debug + Executable string `protobuf:"bytes,1,opt,name=executable,proto3" json:"executable,omitempty"` + // The toolchain type used for the build (for example "gcc") + Toolchain string `protobuf:"bytes,2,opt,name=toolchain,proto3" json:"toolchain,omitempty"` + // The toolchain directory + ToolchainPath string `protobuf:"bytes,3,opt,name=toolchain_path,json=toolchainPath,proto3" json:"toolchain_path,omitempty"` + // The toolchain architecture prefix (for example "arm-none-eabi-") + ToolchainPrefix string `protobuf:"bytes,4,opt,name=toolchain_prefix,json=toolchainPrefix,proto3" json:"toolchain_prefix,omitempty"` + // The GDB server type used to connect to the programmer/board (for example "openocd") + Server string `protobuf:"bytes,5,opt,name=server,proto3" json:"server,omitempty"` + // The GDB server directory + ServerPath string `protobuf:"bytes,6,opt,name=server_path,json=serverPath,proto3" json:"server_path,omitempty"` + // Extra configuration parameters wrt toolchain + ToolchainConfiguration map[string]string `protobuf:"bytes,7,rep,name=toolchain_configuration,json=toolchainConfiguration,proto3" json:"toolchain_configuration,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Extra configuration parameters wrt GDB server + ServerConfiguration map[string]string `protobuf:"bytes,8,rep,name=server_configuration,json=serverConfiguration,proto3" json:"server_configuration,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *GetDebugConfigResp) Reset() { + *x = GetDebugConfigResp{} + if protoimpl.UnsafeEnabled { + mi := &file_debug_debug_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetDebugConfigResp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetDebugConfigResp) ProtoMessage() {} + +func (x *GetDebugConfigResp) ProtoReflect() protoreflect.Message { + mi := &file_debug_debug_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetDebugConfigResp.ProtoReflect.Descriptor instead. +func (*GetDebugConfigResp) Descriptor() ([]byte, []int) { + return file_debug_debug_proto_rawDescGZIP(), []int{3} +} + +func (x *GetDebugConfigResp) GetExecutable() string { + if x != nil { + return x.Executable + } + return "" +} + +func (x *GetDebugConfigResp) GetToolchain() string { + if x != nil { + return x.Toolchain + } + return "" +} + +func (x *GetDebugConfigResp) GetToolchainPath() string { + if x != nil { + return x.ToolchainPath + } + return "" +} + +func (x *GetDebugConfigResp) GetToolchainPrefix() string { + if x != nil { + return x.ToolchainPrefix + } + return "" +} + +func (x *GetDebugConfigResp) GetServer() string { + if x != nil { + return x.Server + } + return "" +} + +func (x *GetDebugConfigResp) GetServerPath() string { + if x != nil { + return x.ServerPath + } + return "" +} + +func (x *GetDebugConfigResp) GetToolchainConfiguration() map[string]string { + if x != nil { + return x.ToolchainConfiguration + } + return nil +} + +func (x *GetDebugConfigResp) GetServerConfiguration() map[string]string { + if x != nil { + return x.ServerConfiguration + } + return nil +} + var File_debug_debug_proto protoreflect.FileDescriptor var file_debug_debug_proto_rawDesc = []byte{ @@ -301,7 +409,7 @@ var file_debug_debug_proto_rawDesc = []byte{ 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x65, 0x6e, - 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x22, 0xfe, 0x01, 0x0a, 0x0e, 0x44, + 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x22, 0xf9, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x12, 0x3d, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, @@ -313,23 +421,68 @@ var file_debug_debug_proto_rawDesc = []byte{ 0x68, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0b, 0x69, 0x6d, 0x70, 0x6f, 0x72, - 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, - 0x52, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, - 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x22, 0x35, 0x0a, 0x09, 0x44, - 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x73, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x32, 0x57, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x12, 0x4e, 0x0a, 0x05, 0x44, - 0x65, 0x62, 0x75, 0x67, 0x12, 0x1e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x44, 0x65, 0x62, 0x75, - 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2a, 0x5a, 0x28, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, - 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, - 0x63, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6d, 0x70, + 0x6f, 0x72, 0x74, 0x44, 0x69, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, + 0x6d, 0x6d, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x67, + 0x72, 0x61, 0x6d, 0x6d, 0x65, 0x72, 0x22, 0x35, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, + 0x65, 0x73, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xe5, 0x04, + 0x0a, 0x12, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x65, 0x73, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, + 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x6f, 0x6f, + 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x50, 0x72, + 0x65, 0x66, 0x69, 0x78, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x50, 0x61, 0x74, 0x68, 0x12, 0x7d, 0x0a, + 0x17, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x44, + 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, + 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x16, 0x74, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x74, 0x0a, 0x14, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x63, 0x63, 0x2e, + 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, + 0x67, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x52, 0x65, 0x73, 0x70, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x13, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x1a, 0x49, 0x0a, 0x1b, 0x54, 0x6f, 0x6f, 0x6c, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x46, 0x0a, + 0x18, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0xbb, 0x01, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x12, + 0x4e, 0x0a, 0x05, 0x44, 0x65, 0x62, 0x75, 0x67, 0x12, 0x1e, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x1f, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, + 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, + 0x44, 0x65, 0x62, 0x75, 0x67, 0x52, 0x65, 0x73, 0x70, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, + 0x62, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x24, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, + 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x1a, 0x28, 0x2e, 0x63, 0x63, 0x2e, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x47, + 0x65, 0x74, 0x44, 0x65, 0x62, 0x75, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, + 0x70, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x2f, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, + 0x6f, 0x2d, 0x63, 0x6c, 0x69, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -344,23 +497,30 @@ func file_debug_debug_proto_rawDescGZIP() []byte { return file_debug_debug_proto_rawDescData } -var file_debug_debug_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_debug_debug_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_debug_debug_proto_goTypes = []interface{}{ - (*DebugReq)(nil), // 0: cc.arduino.cli.debug.DebugReq - (*DebugConfigReq)(nil), // 1: cc.arduino.cli.debug.DebugConfigReq - (*DebugResp)(nil), // 2: cc.arduino.cli.debug.DebugResp - (*commands.Instance)(nil), // 3: cc.arduino.cli.commands.Instance + (*DebugReq)(nil), // 0: cc.arduino.cli.debug.DebugReq + (*DebugConfigReq)(nil), // 1: cc.arduino.cli.debug.DebugConfigReq + (*DebugResp)(nil), // 2: cc.arduino.cli.debug.DebugResp + (*GetDebugConfigResp)(nil), // 3: cc.arduino.cli.debug.GetDebugConfigResp + nil, // 4: cc.arduino.cli.debug.GetDebugConfigResp.ToolchainConfigurationEntry + nil, // 5: cc.arduino.cli.debug.GetDebugConfigResp.ServerConfigurationEntry + (*commands.Instance)(nil), // 6: cc.arduino.cli.commands.Instance } var file_debug_debug_proto_depIdxs = []int32{ 1, // 0: cc.arduino.cli.debug.DebugReq.debugReq:type_name -> cc.arduino.cli.debug.DebugConfigReq - 3, // 1: cc.arduino.cli.debug.DebugConfigReq.instance:type_name -> cc.arduino.cli.commands.Instance - 0, // 2: cc.arduino.cli.debug.Debug.Debug:input_type -> cc.arduino.cli.debug.DebugReq - 2, // 3: cc.arduino.cli.debug.Debug.Debug:output_type -> cc.arduino.cli.debug.DebugResp - 3, // [3:4] is the sub-list for method output_type - 2, // [2:3] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 6, // 1: cc.arduino.cli.debug.DebugConfigReq.instance:type_name -> cc.arduino.cli.commands.Instance + 4, // 2: cc.arduino.cli.debug.GetDebugConfigResp.toolchain_configuration:type_name -> cc.arduino.cli.debug.GetDebugConfigResp.ToolchainConfigurationEntry + 5, // 3: cc.arduino.cli.debug.GetDebugConfigResp.server_configuration:type_name -> cc.arduino.cli.debug.GetDebugConfigResp.ServerConfigurationEntry + 0, // 4: cc.arduino.cli.debug.Debug.Debug:input_type -> cc.arduino.cli.debug.DebugReq + 1, // 5: cc.arduino.cli.debug.Debug.GetDebugConfig:input_type -> cc.arduino.cli.debug.DebugConfigReq + 2, // 6: cc.arduino.cli.debug.Debug.Debug:output_type -> cc.arduino.cli.debug.DebugResp + 3, // 7: cc.arduino.cli.debug.Debug.GetDebugConfig:output_type -> cc.arduino.cli.debug.GetDebugConfigResp + 6, // [6:8] is the sub-list for method output_type + 4, // [4:6] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_debug_debug_proto_init() } @@ -405,6 +565,18 @@ func file_debug_debug_proto_init() { return nil } } + file_debug_debug_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetDebugConfigResp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -412,7 +584,7 @@ func file_debug_debug_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_debug_debug_proto_rawDesc, NumEnums: 0, - NumMessages: 3, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, @@ -440,6 +612,7 @@ const _ = grpc.SupportPackageIsVersion6 type DebugClient interface { // Start a debug session and communicate with the debugger tool. Debug(ctx context.Context, opts ...grpc.CallOption) (Debug_DebugClient, error) + GetDebugConfig(ctx context.Context, in *DebugConfigReq, opts ...grpc.CallOption) (*GetDebugConfigResp, error) } type debugClient struct { @@ -481,10 +654,20 @@ func (x *debugDebugClient) Recv() (*DebugResp, error) { return m, nil } +func (c *debugClient) GetDebugConfig(ctx context.Context, in *DebugConfigReq, opts ...grpc.CallOption) (*GetDebugConfigResp, error) { + out := new(GetDebugConfigResp) + err := c.cc.Invoke(ctx, "/cc.arduino.cli.debug.Debug/GetDebugConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // DebugServer is the server API for Debug service. type DebugServer interface { // Start a debug session and communicate with the debugger tool. Debug(Debug_DebugServer) error + GetDebugConfig(context.Context, *DebugConfigReq) (*GetDebugConfigResp, error) } // UnimplementedDebugServer can be embedded to have forward compatible implementations. @@ -494,6 +677,9 @@ type UnimplementedDebugServer struct { func (*UnimplementedDebugServer) Debug(Debug_DebugServer) error { return status.Errorf(codes.Unimplemented, "method Debug not implemented") } +func (*UnimplementedDebugServer) GetDebugConfig(context.Context, *DebugConfigReq) (*GetDebugConfigResp, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDebugConfig not implemented") +} func RegisterDebugServer(s *grpc.Server, srv DebugServer) { s.RegisterService(&_Debug_serviceDesc, srv) @@ -525,10 +711,33 @@ func (x *debugDebugServer) Recv() (*DebugReq, error) { return m, nil } +func _Debug_GetDebugConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DebugConfigReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServer).GetDebugConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cc.arduino.cli.debug.Debug/GetDebugConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServer).GetDebugConfig(ctx, req.(*DebugConfigReq)) + } + return interceptor(ctx, in, info, handler) +} + var _Debug_serviceDesc = grpc.ServiceDesc{ ServiceName: "cc.arduino.cli.debug.Debug", HandlerType: (*DebugServer)(nil), - Methods: []grpc.MethodDesc{}, + Methods: []grpc.MethodDesc{ + { + MethodName: "GetDebugConfig", + Handler: _Debug_GetDebugConfig_Handler, + }, + }, Streams: []grpc.StreamDesc{ { StreamName: "Debug", diff --git a/rpc/debug/debug.proto b/rpc/debug/debug.proto index 8d478089176..087022173a3 100644 --- a/rpc/debug/debug.proto +++ b/rpc/debug/debug.proto @@ -26,11 +26,13 @@ service Debug { // Start a debug session and communicate with the debugger tool. rpc Debug (stream DebugReq) returns (stream DebugResp) { } + + rpc GetDebugConfig(DebugConfigReq) returns (GetDebugConfigResp) {} } // The top-level message sent by the client for the `Debug` method. // Multiple `DebugReq` messages can be sent but the first message -// must contain a `DebugReq` message to initialize the debug session. +// must contain a `DebugConfigReq` message to initialize the debug session. // All subsequent messages must contain bytes to be sent to the debug session // and must not contain a `DebugReq` message. message DebugReq { @@ -58,16 +60,16 @@ message DebugConfigReq { // Path to the sketch that is running on the board. The compiled executable // is expected to be located under this path. string sketch_path = 3; - // Port of the debugger. Set to `none` if the debugger doesn't use a port. + // Port of the debugger (optional). string port = 4; // Which GDB command interpreter to use. string interpreter = 5; - // DEPRECATED: use import_dir instead - string import_file = 7 [deprecated = true]; // Directory containing the compiled executable. If `import_dir` is not // specified, the executable is assumed to be in // `{sketch_path}/build/{fqbn}/`. string import_dir = 8; + // The programmer to use for debugging. + string programmer = 9; } // @@ -77,3 +79,22 @@ message DebugResp { // Incoming error output from the debugger tool. string error = 2; } + +message GetDebugConfigResp { + // The executable binary to debug + string executable = 1; + // The toolchain type used for the build (for example "gcc") + string toolchain = 2; + // The toolchain directory + string toolchain_path = 3; + // The toolchain architecture prefix (for example "arm-none-eabi-") + string toolchain_prefix = 4; + // The GDB server type used to connect to the programmer/board (for example "openocd") + string server = 5; + // The GDB server directory + string server_path = 6; + // Extra configuration parameters wrt toolchain + map toolchain_configuration = 7; + // Extra configuration parameters wrt GDB server + map server_configuration = 8; +}