Skip to content

Implement debug feature #590

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Feb 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3e861b7
Implement first draft of debugger gRPC service
Feb 14, 2020
0119a90
Working stdio streaming
cmaglie Feb 17, 2020
a106a4f
Improved stdio passing via GRPC
cmaglie Feb 17, 2020
b16874d
Adjusted protoc definitions
cmaglie Feb 17, 2020
d9077eb
Handle errors gracefully
cmaglie Feb 17, 2020
e86ae80
Add recipe calculation to debug command
Feb 17, 2020
879367b
First implementation of debug
cmaglie Feb 17, 2020
7648814
updated client example for testing
Feb 17, 2020
3960fea
Implement debug command
Feb 19, 2020
5228709
Implement copyStream
Feb 19, 2020
9d314ab
Refactor stream helpers
Feb 19, 2020
8d44e6f
Extract recipe creation from debug command
Feb 19, 2020
9923f62
Add test for debug recipe generation
Feb 19, 2020
378b8bf
Cosmetics here and there
Feb 19, 2020
74fa6df
Refreshed client example
Feb 19, 2020
e8d9071
Replace with utils function
Feb 20, 2020
3888017
Remove debug leftover
Feb 20, 2020
e0e07c5
Refreshed client example
Feb 20, 2020
c2681b3
Moved debug proto to its package
Feb 20, 2020
11452d5
Removed sketch.json
Feb 20, 2020
a85376f
Apply general cosmetics
Feb 20, 2020
83cf94e
Add test binaries
Feb 20, 2020
da07d3d
Added test case for windows path flavor
Feb 20, 2020
abc9353
Use path.FromSlash to test debug tool command generation cross platfo…
Feb 21, 2020
fa39675
Avoid pipe leaking via closing readers and writes in case of abnormal…
Feb 21, 2020
3650865
Update client example to better catch gdb prompt
Feb 21, 2020
34e7854
Error messages cosmetics
Feb 21, 2020
5d9be12
Use errors.Wrap instead of fmt.Errorf
cmaglie Feb 21, 2020
600c1d5
Use errors.Wrap instead of fmt.Errorf
cmaglie Feb 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tasks:
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/commands/*.proto'
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/monitor/*.proto'
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/settings/*.proto'
- '{{ default "protoc" .PROTOC_BINARY }} --proto_path=rpc --go_out=plugins=grpc,paths=source_relative:rpc ./rpc/debug/*.proto'

build:
desc: Build the project
Expand Down
1 change: 0 additions & 1 deletion arduino/cores/packagemanager/package_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,6 @@ func (tr *ToolReleaseActions) Get() (*cores.ToolRelease, error) {

// GetInstalledPlatformRelease returns the PlatformRelease installed (it is chosen)
func (pm *PackageManager) GetInstalledPlatformRelease(platform *cores.Platform) *cores.PlatformRelease {
pm.Log.Infof("Selecting installed platform release for %s", platform)
releases := platform.GetAllInstalled()
if len(releases) == 0 {
return nil
Expand Down
58 changes: 58 additions & 0 deletions arduino/utils/stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 [email protected].

package utils

import "io"

// FeedStreamTo creates a pipe to pass data to the writer function.
// FeedStreamTo returns the io.Writer side of the pipe, on which the user can write data
func FeedStreamTo(writer func(data []byte)) io.Writer {
r, w := io.Pipe()
go func() {
data := make([]byte, 1024)
for {
if n, err := r.Read(data); err == nil {
writer(data[:n])
} else {
r.Close()
return
}
}
}()
return w
}

// ConsumeStreamFrom creates a pipe to consume data from the reader function.
// ConsumeStreamFrom returns the io.Reader side of the pipe, which the user can use to consume the data
func ConsumeStreamFrom(reader func() ([]byte, error)) io.Reader {
r, w := io.Pipe()
go func() {
for {
if data, err := reader(); err != nil {
if err == io.EOF {
w.Close()
} else {
w.CloseWithError(err)
}
return
} else if _, err := w.Write(data); err != nil {
w.Close()
return
}
}
}()
return r
}
2 changes: 2 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/arduino/arduino-cli/cli/config"
"github.com/arduino/arduino-cli/cli/core"
"github.com/arduino/arduino-cli/cli/daemon"
"github.com/arduino/arduino-cli/cli/debug"
"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cli/cli/generatedocs"
Expand Down Expand Up @@ -77,6 +78,7 @@ func createCliCommandTree(cmd *cobra.Command) {
cmd.AddCommand(lib.NewCommand())
cmd.AddCommand(sketch.NewCommand())
cmd.AddCommand(upload.NewCommand())
cmd.AddCommand(debug.NewCommand())
cmd.AddCommand(version.NewCommand())

cmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the logs on the standard output.")
Expand Down
12 changes: 8 additions & 4 deletions cli/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/arduino/arduino-cli/cli/globals"
"github.com/arduino/arduino-cli/commands/daemon"
srv_commands "github.com/arduino/arduino-cli/rpc/commands"
srv_debug "github.com/arduino/arduino-cli/rpc/debug"
srv_monitor "github.com/arduino/arduino-cli/rpc/monitor"
srv_settings "github.com/arduino/arduino-cli/rpc/settings"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -73,16 +74,19 @@ func runDaemonCommand(cmd *cobra.Command, args []string) {
VersionString: globals.VersionInfo.VersionString,
})

// register the monitors service
// Register the monitors service
srv_monitor.RegisterMonitorServer(s, &daemon.MonitorService{})

// register the settings service
// Register the settings service
srv_settings.RegisterSettingsServer(s, &daemon.SettingsService{})

// Register the debug session service
srv_debug.RegisterDebugServer(s, &daemon.DebugService{})

if !daemonize {
// When parent process ends terminate also the daemon
go func() {
// stdin is closed when the controlling parent process ends
// Stdin is closed when the controlling parent process ends
_, _ = io.Copy(ioutil.Discard, os.Stdin)
os.Exit(0)
}()
Expand Down Expand Up @@ -115,6 +119,6 @@ func runDaemonCommand(cmd *cobra.Command, args []string) {
// This message will show up on the stdout of the daemon process so that gRPC clients know it is time to connect.
logrus.Infof("Daemon is listening on TCP port %s...", port)
if err := s.Serve(lis); err != nil {
logrus.Fatalf("failed to serve: %v", err)
logrus.Fatalf("Failed to serve: %v", err)
}
}
96 changes: 96 additions & 0 deletions cli/debug/debug.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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 [email protected].

package debug

import (
"context"
"os"

"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"
dbg "github.com/arduino/arduino-cli/rpc/debug"
"github.com/arduino/go-paths-helper"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var (
fqbn string
port string
verbose bool
verify bool
importFile string
)

// NewCommand created a new `upload` command
func NewCommand() *cobra.Command {
debugCommand := &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",
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", "", "Upload port, e.g.: COM10 or /dev/ttyACM0")
debugCommand.Flags().StringVarP(&importFile, "input", "i", "", "Input file to be uploaded for debug.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says "to be uploaded", but I did not see any code that actually uploads? Instead, I think it assumes that this .elf file is already uploaded?


return debugCommand
}

func run(command *cobra.Command, args []string) {
instance, err := instance.CreateInstance()
if err != nil {
feedback.Errorf("Error during Debug: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

var path *paths.Path
if len(args) > 0 {
path = paths.New(args[0])
}
sketchPath := initSketchPath(path)

if _, err := debug.Debug(context.Background(), &dbg.DebugConfigReq{
Instance: &dbg.Instance{Id: instance.GetId()},
Fqbn: fqbn,
SketchPath: sketchPath.String(),
Port: port,
ImportFile: importFile,
}, os.Stdin, os.Stdout); err != nil {
feedback.Errorf("Error during Debug: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
}

// initSketchPath returns the current working directory
func initSketchPath(sketchPath *paths.Path) *paths.Path {
if sketchPath != nil {
return sketchPath
}

wd, err := paths.Getwd()
if err != nil {
feedback.Errorf("Couldn't get current working directory: %v", err)
os.Exit(errorcodes.ErrGeneric)
}
logrus.Infof("Reading sketch from dir: %s", wd)
return wd
}
7 changes: 4 additions & 3 deletions client_example/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ module github.com/arduino/arduino-cli/client_example

go 1.13

replace github.com/arduino/arduino-cli => ../

require (
github.com/arduino/arduino-cli v0.0.0-20200109150215-ffa84fdaab21
github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 // indirect
google.golang.org/grpc v1.23.0
)
google.golang.org/grpc v1.27.0
)
Loading