cli,compiler: support emitting debug info in a file

This commit is contained in:
Evgenii Stratonikov 2020-04-02 15:38:53 +03:00
parent 5d3da26e1e
commit 5bdee683e6
3 changed files with 40 additions and 13 deletions

View file

@ -92,6 +92,10 @@ func NewCommands() []cli.Command {
Name: "debug, d", Name: "debug, d",
Usage: "Debug mode will print out additional information after a compiling", Usage: "Debug mode will print out additional information after a compiling",
}, },
cli.StringFlag{
Name: "emitdebug",
Usage: "Emit debug info in a separate file",
},
}, },
}, },
{ {
@ -348,6 +352,8 @@ func contractCompile(ctx *cli.Context) error {
o := &compiler.Options{ o := &compiler.Options{
Outfile: ctx.String("out"), Outfile: ctx.String("out"),
Debug: ctx.Bool("debug"), Debug: ctx.Bool("debug"),
DebugInfo: ctx.String("emitdebug"),
} }
result, err := compiler.CompileAndSave(src, o) result, err := compiler.CompileAndSave(src, o)

View file

@ -1313,19 +1313,19 @@ func newCodegen(info *buildInfo, pkg *loader.PackageInfo) *codegen {
} }
// CodeGen compiles the program to bytecode. // CodeGen compiles the program to bytecode.
func CodeGen(info *buildInfo) ([]byte, error) { func CodeGen(info *buildInfo) ([]byte, *DebugInfo, error) {
pkg := info.program.Package(info.initialPackage) pkg := info.program.Package(info.initialPackage)
c := newCodegen(info, pkg) c := newCodegen(info, pkg)
if err := c.compile(info, pkg); err != nil { if err := c.compile(info, pkg); err != nil {
return nil, err return nil, nil, err
} }
buf := c.prog.Bytes() buf := c.prog.Bytes()
if err := c.writeJumps(buf); err != nil { if err := c.writeJumps(buf); err != nil {
return nil, err return nil, nil, err
} }
return buf, nil return buf, c.emitDebugInfo(), nil
} }
func (c *codegen) resolveFuncDecls(f *ast.File) { func (c *codegen) resolveFuncDecls(f *ast.File) {

View file

@ -2,11 +2,13 @@ package compiler
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"go/parser" "go/parser"
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath"
"strings" "strings"
"golang.org/x/tools/go/loader" "golang.org/x/tools/go/loader"
@ -22,6 +24,9 @@ type Options struct {
// The name of the output file. // The name of the output file.
Outfile string Outfile string
// The name of the output for debug info.
DebugInfo string
// Debug outputs a hex encoded string of the generated bytecode. // Debug outputs a hex encoded string of the generated bytecode.
Debug bool Debug bool
} }
@ -52,12 +57,7 @@ func getBuildInfo(src interface{}) (*buildInfo, error) {
// Compile compiles a Go program into bytecode that can run on the NEO virtual machine. // Compile compiles a Go program into bytecode that can run on the NEO virtual machine.
func Compile(r io.Reader) ([]byte, error) { func Compile(r io.Reader) ([]byte, error) {
ctx, err := getBuildInfo(r) buf, _, err := CompileWithDebugInfo(r)
if err != nil {
return nil, err
}
buf, err := CodeGen(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,6 +65,15 @@ func Compile(r io.Reader) ([]byte, error) {
return buf, nil return buf, nil
} }
// CompileWithDebugInfo compiles a Go program into bytecode and emits debug info.
func CompileWithDebugInfo(r io.Reader) ([]byte, *DebugInfo, error) {
ctx, err := getBuildInfo(r)
if err != nil {
return nil, nil, err
}
return CodeGen(ctx)
}
// CompileAndSave will compile and save the file to disk. // CompileAndSave will compile and save the file to disk.
func CompileAndSave(src string, o *Options) ([]byte, error) { func CompileAndSave(src string, o *Options) ([]byte, error) {
if !strings.HasSuffix(src, ".go") { if !strings.HasSuffix(src, ".go") {
@ -81,11 +90,23 @@ func CompileAndSave(src string, o *Options) ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
b, err = Compile(bytes.NewReader(b)) b, di, err := CompileWithDebugInfo(bytes.NewReader(b))
if err != nil { if err != nil {
return nil, fmt.Errorf("error while trying to compile smart contract file: %v", err) return nil, fmt.Errorf("error while trying to compile smart contract file: %v", err)
} }
out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext) out := fmt.Sprintf("%s.%s", o.Outfile, o.Ext)
return b, ioutil.WriteFile(out, b, os.ModePerm) err = ioutil.WriteFile(out, b, os.ModePerm)
if o.DebugInfo == "" {
return b, err
}
p, err := filepath.Abs(src)
if err != nil {
return b, err
}
di.Documents = append(di.Documents, p)
data, err := json.Marshal(di)
if err != nil {
return b, err
}
return b, ioutil.WriteFile(o.DebugInfo, data, os.ModePerm)
} }