• mbaxter's avatar
    cannon: Modularize mipsevm packages (#11135) · 4584c976
    mbaxter authored
    * cannon: Isolate test utilities, rework types to avoid circular dependencies
    
    * cannon: Rollback changes to MIPSEVM.EncodePreimageOracleInput
    
    * cannon: Move open_mips_tests to tests subpackage
    
    * cannon: Update some paths to open_mips_tests
    
    * cannon: Collect oracle utils, move generic tests to tests package
    
    * cannon: Move common state constants and utilities to core pkg
    
    * cannon: Move state.go and state_mt.go into impls package
    
    * cannon: Create a memory subpackage
    
    * cannon: Create exec pkg for mips logic
    
    * cannon: Wrap remaining core files in isolated pkgs
    
    * cannon: Create a few more subpackages
    
    * cannon: Rename state_mt to state
    
    * cannon: Move hex utility
    
    * cannon: Pull loading functionality out of patch.go
    
    * cannon: Remove 'MT' prefixes on multi_threaded/state.go symbols
    
    * cannon: Add compile-time PreimageOracle check back in
    
    * cannon: Undo excessive nesting in core package
    
    * cannon: Reorganize single- and multithreaded pkgs
    
    * cannon: Rename test_util pkg to testutil
    
    * cannon: Move instrumented_state logic into singlethreaded pkg
    
    * cannon: Fix test paths
    
    * cannon: Move core pkgs back to root mipsevm pkg
    
    * cannon: Flatten util pkg back into main mipsevm pkg
    
    * cannon: Cleanup - don't use vmstate for mipsevm pkg
    
    * cannon: Add godoc for FPVMState.GetRegisters()
    
    * cannon: Cleanup - fix pkg name, fn visibility
    4584c976
load_elf.go 2.55 KB
package cmd

import (
	"debug/elf"
	"fmt"

	"github.com/urfave/cli/v2"

	"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
	"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
	"github.com/ethereum-optimism/optimism/op-service/jsonutil"
)

var (
	LoadELFPathFlag = &cli.PathFlag{
		Name:      "path",
		Usage:     "Path to 32-bit big-endian MIPS ELF file",
		TakesFile: true,
		Required:  true,
	}
	LoadELFPatchFlag = &cli.StringSliceFlag{
		Name:     "patch",
		Usage:    "Type of patching to do",
		Value:    cli.NewStringSlice("go", "stack"),
		Required: false,
	}
	LoadELFOutFlag = &cli.PathFlag{
		Name:     "out",
		Usage:    "Output path to write JSON state to. State is dumped to stdout if set to -. Not written if empty.",
		Value:    "state.json",
		Required: false,
	}
	LoadELFMetaFlag = &cli.PathFlag{
		Name:     "meta",
		Usage:    "Write metadata file, for symbol lookup during program execution. None if empty.",
		Value:    "meta.json",
		Required: false,
	}
)

func LoadELF(ctx *cli.Context) error {
	elfPath := ctx.Path(LoadELFPathFlag.Name)
	elfProgram, err := elf.Open(elfPath)
	if err != nil {
		return fmt.Errorf("failed to open ELF file %q: %w", elfPath, err)
	}
	if elfProgram.Machine != elf.EM_MIPS {
		return fmt.Errorf("ELF is not big-endian MIPS R3000, but got %q", elfProgram.Machine.String())
	}
	state, err := program.LoadELF(elfProgram, singlethreaded.CreateInitialState)
	if err != nil {
		return fmt.Errorf("failed to load ELF data into VM state: %w", err)
	}
	for _, typ := range ctx.StringSlice(LoadELFPatchFlag.Name) {
		switch typ {
		case "stack":
			err = program.PatchStack(state)
		case "go":
			err = program.PatchGo(elfProgram, state)
		default:
			return fmt.Errorf("unrecognized form of patching: %q", typ)
		}
		if err != nil {
			return fmt.Errorf("failed to apply patch %s: %w", typ, err)
		}
	}
	meta, err := program.MakeMetadata(elfProgram)
	if err != nil {
		return fmt.Errorf("failed to compute program metadata: %w", err)
	}
	if err := jsonutil.WriteJSON[*program.Metadata](ctx.Path(LoadELFMetaFlag.Name), meta, OutFilePerm); err != nil {
		return fmt.Errorf("failed to output metadata: %w", err)
	}
	return jsonutil.WriteJSON[*singlethreaded.State](ctx.Path(LoadELFOutFlag.Name), state, OutFilePerm)
}

var LoadELFCommand = &cli.Command{
	Name:        "load-elf",
	Usage:       "Load ELF file into Cannon JSON state",
	Description: "Load ELF file into Cannon JSON state, optionally patch out functions",
	Action:      LoadELF,
	Flags: []cli.Flag{
		LoadELFPathFlag,
		LoadELFPatchFlag,
		LoadELFOutFlag,
		LoadELFMetaFlag,
	},
}