Commit 6e06fa53 authored by Inphi's avatar Inphi Committed by GitHub

cannon: Enable program VM debugging for tests (#11582)

* cannon: Enable program VM debugging for tests

- Also add a symbol lookup routine to the FPVM interface for
  convenience.

* mbaxter suggestion
parent 8c17425a
...@@ -69,4 +69,8 @@ type FPVM interface { ...@@ -69,4 +69,8 @@ type FPVM interface {
// GetDebugInfo returns debug information about the VM // GetDebugInfo returns debug information about the VM
GetDebugInfo() *DebugInfo GetDebugInfo() *DebugInfo
// LookupSymbol returns the symbol located at the specified address.
// May return an empty string if there's no symbol table available.
LookupSymbol(addr uint32) string
} }
...@@ -23,6 +23,7 @@ type InstrumentedState struct { ...@@ -23,6 +23,7 @@ type InstrumentedState struct {
stackTracker ThreadedStackTracker stackTracker ThreadedStackTracker
preimageOracle *exec.TrackingPreimageOracleReader preimageOracle *exec.TrackingPreimageOracleReader
meta *program.Metadata
} }
var _ mipsevm.FPVM = (*InstrumentedState)(nil) var _ mipsevm.FPVM = (*InstrumentedState)(nil)
...@@ -53,6 +54,7 @@ func (m *InstrumentedState) InitDebug(meta *program.Metadata) error { ...@@ -53,6 +54,7 @@ func (m *InstrumentedState) InitDebug(meta *program.Metadata) error {
return err return err
} }
m.stackTracker = stackTracker m.stackTracker = stackTracker
m.meta = meta
return nil return nil
} }
...@@ -116,3 +118,10 @@ func (m *InstrumentedState) GetDebugInfo() *mipsevm.DebugInfo { ...@@ -116,3 +118,10 @@ func (m *InstrumentedState) GetDebugInfo() *mipsevm.DebugInfo {
func (m *InstrumentedState) Traceback() { func (m *InstrumentedState) Traceback() {
m.stackTracker.Traceback() m.stackTracker.Traceback()
} }
func (m *InstrumentedState) LookupSymbol(addr uint32) string {
if m.meta == nil {
return ""
}
return m.meta.LookupSymbol(addr)
}
...@@ -32,7 +32,7 @@ func TestInstrumentedState_Claim(t *testing.T) { ...@@ -32,7 +32,7 @@ func TestInstrumentedState_Claim(t *testing.T) {
} }
func TestInstrumentedState_MultithreadedProgram(t *testing.T) { func TestInstrumentedState_MultithreadedProgram(t *testing.T) {
state := testutil.LoadELFProgram(t, "../../testdata/example/bin/multithreaded.elf", CreateInitialState, false) state, _ := testutil.LoadELFProgram(t, "../../testdata/example/bin/multithreaded.elf", CreateInitialState, false)
oracle := testutil.StaticOracle(t, []byte{}) oracle := testutil.StaticOracle(t, []byte{})
var stdOutBuf, stdErrBuf bytes.Buffer var stdOutBuf, stdErrBuf bytes.Buffer
...@@ -56,7 +56,7 @@ func TestInstrumentedState_MultithreadedProgram(t *testing.T) { ...@@ -56,7 +56,7 @@ func TestInstrumentedState_MultithreadedProgram(t *testing.T) {
func TestInstrumentedState_Alloc(t *testing.T) { func TestInstrumentedState_Alloc(t *testing.T) {
t.Skip("TODO(client-pod#906): Currently failing - need to debug.") t.Skip("TODO(client-pod#906): Currently failing - need to debug.")
state := testutil.LoadELFProgram(t, "../../testdata/example/bin/alloc.elf", CreateInitialState, false) state, _ := testutil.LoadELFProgram(t, "../../testdata/example/bin/alloc.elf", CreateInitialState, false)
const numAllocs = 100 // where each alloc is a 32 MiB chunk const numAllocs = 100 // where each alloc is a 32 MiB chunk
oracle := testutil.AllocOracle(t, numAllocs) oracle := testutil.AllocOracle(t, numAllocs)
......
...@@ -119,3 +119,10 @@ func (m *InstrumentedState) GetDebugInfo() *mipsevm.DebugInfo { ...@@ -119,3 +119,10 @@ func (m *InstrumentedState) GetDebugInfo() *mipsevm.DebugInfo {
func (m *InstrumentedState) Traceback() { func (m *InstrumentedState) Traceback() {
m.stackTracker.Traceback() m.stackTracker.Traceback()
} }
func (m *InstrumentedState) LookupSymbol(addr uint32) string {
if m.meta == nil {
return ""
}
return m.meta.LookupSymbol(addr)
}
...@@ -161,13 +161,17 @@ func multiThreadedVmFactory(po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, ...@@ -161,13 +161,17 @@ func multiThreadedVmFactory(po mipsevm.PreimageOracle, stdOut, stdErr io.Writer,
type ElfVMFactory func(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM type ElfVMFactory func(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM
func singleThreadElfVmFactory(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM { func singleThreadElfVmFactory(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM {
state := testutil.LoadELFProgram(t, elfFile, singlethreaded.CreateInitialState, true) state, meta := testutil.LoadELFProgram(t, elfFile, singlethreaded.CreateInitialState, true)
return singlethreaded.NewInstrumentedState(state, po, stdOut, stdErr, nil) fpvm := singlethreaded.NewInstrumentedState(state, po, stdOut, stdErr, meta)
require.NoError(t, fpvm.InitDebug())
return fpvm
} }
func multiThreadElfVmFactory(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM { func multiThreadElfVmFactory(t require.TestingT, elfFile string, po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger) mipsevm.FPVM {
state := testutil.LoadELFProgram(t, elfFile, multithreaded.CreateInitialState, false) state, meta := testutil.LoadELFProgram(t, elfFile, multithreaded.CreateInitialState, false)
return multithreaded.NewInstrumentedState(state, po, stdOut, stdErr, log) fpvm := multithreaded.NewInstrumentedState(state, po, stdOut, stdErr, log)
require.NoError(t, fpvm.InitDebug(meta))
return fpvm
} }
type VersionedVMTestCase struct { type VersionedVMTestCase struct {
......
...@@ -9,9 +9,11 @@ import ( ...@@ -9,9 +9,11 @@ import (
"github.com/ethereum-optimism/optimism/cannon/mipsevm/program" "github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
) )
func LoadELFProgram[T mipsevm.FPVMState](t require.TestingT, name string, initState program.CreateInitialFPVMState[T], doPatchGo bool) T { func LoadELFProgram[T mipsevm.FPVMState](t require.TestingT, name string, initState program.CreateInitialFPVMState[T], doPatchGo bool) (T, *program.Metadata) {
elfProgram, err := elf.Open(name) elfProgram, err := elf.Open(name)
require.NoError(t, err, "open ELF file") require.NoError(t, err, "open ELF file")
meta, err := program.MakeMetadata(elfProgram)
require.NoError(t, err, "load metadata")
state, err := program.LoadELF(elfProgram, initState) state, err := program.LoadELF(elfProgram, initState)
require.NoError(t, err, "load ELF into state") require.NoError(t, err, "load ELF into state")
...@@ -22,5 +24,5 @@ func LoadELFProgram[T mipsevm.FPVMState](t require.TestingT, name string, initSt ...@@ -22,5 +24,5 @@ func LoadELFProgram[T mipsevm.FPVMState](t require.TestingT, name string, initSt
} }
require.NoError(t, program.PatchStack(state), "add initial stack") require.NoError(t, program.PatchStack(state), "add initial stack")
return state return state, meta
} }
...@@ -93,7 +93,7 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa ...@@ -93,7 +93,7 @@ func RunVMTests_OpenMips[T mipsevm.FPVMState](t *testing.T, stateFactory StateFa
} }
func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) { func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) {
state := LoadELFProgram(t, "../../testdata/example/bin/hello.elf", initState, doPatchGo) state, _ := LoadELFProgram(t, "../../testdata/example/bin/hello.elf", initState, doPatchGo)
var stdOutBuf, stdErrBuf bytes.Buffer var stdOutBuf, stdErrBuf bytes.Buffer
us := vmFactory(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger()) us := vmFactory(state, nil, io.MultiWriter(&stdOutBuf, os.Stdout), io.MultiWriter(&stdErrBuf, os.Stderr), CreateLogger())
...@@ -114,7 +114,7 @@ func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.Create ...@@ -114,7 +114,7 @@ func RunVMTest_Hello[T mipsevm.FPVMState](t *testing.T, initState program.Create
} }
func RunVMTest_Claim[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) { func RunVMTest_Claim[T mipsevm.FPVMState](t *testing.T, initState program.CreateInitialFPVMState[T], vmFactory VMFactory[T], doPatchGo bool) {
state := LoadELFProgram(t, "../../testdata/example/bin/claim.elf", initState, doPatchGo) state, _ := LoadELFProgram(t, "../../testdata/example/bin/claim.elf", initState, doPatchGo)
oracle, expectedStdOut, expectedStdErr := ClaimTestOracle(t) oracle, expectedStdOut, expectedStdErr := ClaimTestOracle(t)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment