aboutsummaryrefslogtreecommitdiffstats
path: root/ethereal
diff options
context:
space:
mode:
authorobscuren <geffobscura@gmail.com>2014-07-02 19:08:18 +0800
committerobscuren <geffobscura@gmail.com>2014-07-02 19:08:18 +0800
commit50c093822637c42f43234d08c5f7b273b7117749 (patch)
tree5d9a1e7bad5677fe3b5b2f9f2bed0a6fabaf9175 /ethereal
parent7d0004f058d7e93df684b0524fd52cd2eb1af3e3 (diff)
downloaddexon-50c093822637c42f43234d08c5f7b273b7117749.tar.gz
dexon-50c093822637c42f43234d08c5f7b273b7117749.tar.zst
dexon-50c093822637c42f43234d08c5f7b273b7117749.zip
Break points and debugger commands
Diffstat (limited to 'ethereal')
-rw-r--r--ethereal/assets/debugger/debugger.qml65
-rw-r--r--ethereal/debugger.go84
2 files changed, 124 insertions, 25 deletions
diff --git a/ethereal/assets/debugger/debugger.qml b/ethereal/assets/debugger/debugger.qml
index 3e653882c..b93308b3e 100644
--- a/ethereal/assets/debugger/debugger.qml
+++ b/ethereal/assets/debugger/debugger.qml
@@ -12,7 +12,7 @@ ApplicationWindow {
minimumWidth: 1280
minimumHeight: 700
width: 1290
- height: 700
+ height: 750
property alias codeText: codeEditor.text
property alias dataText: rawDataField.text
@@ -31,6 +31,12 @@ ApplicationWindow {
shortcut: "Ctrl+n"
onTriggered: dbg.next()
}
+
+ MenuItem {
+ text: "Continue"
+ shortcut: "Ctrl+c"
+ onTriggered: dbg.continue()
+ }
}
}
@@ -39,6 +45,7 @@ ApplicationWindow {
property var asmModel: ListModel {
id: asmModel
}
+
TableView {
id: asmTableView
width: 200
@@ -187,6 +194,36 @@ ApplicationWindow {
}
}
+ function exec() {
+ dbg.execCommand(dbgCommand.text);
+ dbgCommand.text = "";
+ }
+ statusBar: StatusBar {
+ height: 30
+
+
+ TextField {
+ id: dbgCommand
+ y: 1
+ x: asmTableView.width
+ width: 500
+ placeholderText: "Debugger command (help for help)"
+ Keys.onReturnPressed: {
+ exec()
+ }
+ }
+
+ Button {
+ anchors {
+ left: dbgCommand.right
+ }
+ text: "Exec"
+ onClicked: {
+ exec()
+ }
+ }
+ }
+
toolBar: ToolBar {
RowLayout {
spacing: 5
@@ -208,11 +245,13 @@ ApplicationWindow {
}
text: "Next"
}
- CheckBox {
- id: breakEachLine
- objectName: "breakEachLine"
- text: "Break each instruction"
- checked: true
+
+ Button {
+ id: debugContinueButton
+ onClicked: {
+ dbg.continue()
+ }
+ text: "Continue"
}
}
}
@@ -261,7 +300,19 @@ ApplicationWindow {
}
function setLog(msg) {
- logModel.insert(0, {message: msg})
+ // Remove first item once we've reached max log items
+ if(logModel.count > 250) {
+ logModel.remove(0)
+ }
+
+ if(msg.len != 0) {
+ if(logTableView.flickableItem.atYEnd) {
+ logModel.append({message: msg})
+ logTableView.positionViewAtRow(logTableView.rowCount - 1, ListView.Contain)
+ } else {
+ logModel.append({message: msg})
+ }
+ }
}
function clearLog() {
diff --git a/ethereal/debugger.go b/ethereal/debugger.go
index 763b26063..911f3bb72 100644
--- a/ethereal/debugger.go
+++ b/ethereal/debugger.go
@@ -6,6 +6,7 @@ import (
"github.com/ethereum/eth-go/ethutil"
"github.com/go-qml/qml"
"math/big"
+ "strconv"
"strings"
)
@@ -13,7 +14,10 @@ type DebuggerWindow struct {
win *qml.Window
engine *qml.Engine
lib *UiLib
- Db *Debugger
+
+ vm *ethchain.Vm
+ Db *Debugger
+ breakPoints []int64
}
func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
@@ -26,9 +30,9 @@ func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
}
win := component.CreateWindow(nil)
- db := &Debugger{win, make(chan bool), make(chan bool), true, false, true}
+ db := &Debugger{win, make(chan bool), make(chan bool), true, false}
- return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db}
+ return &DebuggerWindow{engine: engine, win: win, lib: lib, Db: db, vm: &ethchain.Vm{}}
}
func (self *DebuggerWindow) Show() {
@@ -59,7 +63,6 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
if !self.Db.done {
self.Db.Q <- true
}
- self.Db.breakOnInstr = self.win.Root().ObjectByName("breakEachLine").Bool("checked")
defer func() {
if r := recover(); r != nil {
@@ -90,7 +93,7 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
dis := ethchain.Disassemble(script)
self.win.Root().Call("clearAsm")
- self.win.Root().Call("clearLog")
+ //self.win.Root().Call("clearLog")
for _, str := range dis {
self.win.Root().Call("setAsm", str)
@@ -125,7 +128,9 @@ func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, data
})
vm.Verbose = true
vm.Hook = self.Db.halting
+ vm.BreakPoints = self.breakPoints
+ self.vm = vm
self.Db.done = false
self.Logf("callsize %d", len(script))
go func() {
@@ -165,12 +170,57 @@ func (self *DebuggerWindow) Next() {
self.Db.Next()
}
+func (self *DebuggerWindow) Continue() {
+ self.vm.Stepping = false
+ self.Next()
+}
+
+func (self *DebuggerWindow) ExecCommand(command string) {
+ if len(command) > 0 {
+ cmd := strings.Split(command, " ")
+ switch cmd[0] {
+ case "help":
+ self.Logln("Debgger commands:")
+ self.Logln("break, bp Set breakpoint")
+ case "break", "bp":
+ if len(cmd) > 1 {
+ lineNo, err := strconv.Atoi(cmd[1])
+ if err != nil {
+ self.Logln(err)
+ break
+ }
+ self.breakPoints = append(self.breakPoints, int64(lineNo))
+ self.vm.BreakPoints = self.breakPoints
+ self.Logf("break point set on instruction %d", lineNo)
+ } else {
+ self.Logf("'%s' requires line number", cmd[0])
+ }
+ case "clear":
+ if len(cmd) > 1 {
+ switch cmd[1] {
+ case "break", "bp":
+ self.breakPoints = nil
+ self.vm.BreakPoints = nil
+
+ self.Logln("Breakpoints cleared")
+ default:
+ self.Logf("clear '%s' is not valid", cmd[1])
+ }
+ } else {
+ self.Logln("'clear' requires sub command")
+ }
+
+ default:
+ self.Logf("Unknown command %s", cmd[0])
+ }
+ }
+}
+
type Debugger struct {
win *qml.Window
N chan bool
Q chan bool
done, interrupt bool
- breakOnInstr bool
}
type storeVal struct {
@@ -197,18 +247,16 @@ func (d *Debugger) halting(pc int, op ethchain.OpCode, mem *ethchain.Memory, sta
d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
})
- if d.breakOnInstr {
- out:
- for {
- select {
- case <-d.N:
- break out
- case <-d.Q:
- d.interrupt = true
- d.clearBuffers()
-
- return false
- }
+out:
+ for {
+ select {
+ case <-d.N:
+ break out
+ case <-d.Q:
+ d.interrupt = true
+ d.clearBuffers()
+
+ return false
}
}