rvsym

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2022 License: MIT Imports: 18 Imported by: 0

README

Rvsym: a small RISC-V symbolic execution engine

Rvsym can execute rv32im RISC-V programs symbolically.

Building

By default, rvsym uses Boolector as the SMT backend. First you need to set up Boolector:

./pkg/smt/setup-boolector.sh

Then you can build

go build ./cmd/rvsym

Alternatively, you may build with dynamic linking to Z3 if it is installed:

go build -tags z3,noboolector ./cmd/rvsym

In order to build the examples you will also need the RISC-V GNU toolchain. Pre-built toolchains are available from SiFive here. After downloading, unpack the tar archive to /opt/riscv (or if you choose another location, point the RISCV environment variable to your installation).

Usage

See the ./examples/basic directory for a number of example programs. Compile with make, and then run the example of your choosing with rvsym example.elf.

For example, here is get_sign.c:

#include "rvsym.h"

int get_sign(int x) {
    if (x == 0)
        return 0;
    else if (x < 0)
        return -1;
    else
        return 1;
}

int main() {
    int a;
    rvsym_mark_bytes(&a, sizeof(a), "a");
    int r = get_sign(a);
    rvsym_exit();
    return r;
}

Now we compile with the RISC-V toolchain and execute the resulting ELF binary with rvsym. It finds three test cases that exercise each path in the get_sign function.

$ make get_sign.elf
$ rvsym get_sign.elf --summary
--- Test case 0: exit at get_sign.c:20 (0x100a4) ---
a[3:0] -> 0x1
---
--- Test case 1: exit at get_sign.c:20 (0x100a4) ---
a[3:0] -> 0x80000001
---
--- Test case 2: exit at get_sign.c:20 (0x100a4) ---
a[3:0] -> 0x0
---
--- Summary ---
Instructions executed: 148
Total paths: 3
Quiet exits: 0
Unsat exits: 0
Normal exits: 3
Failures: 0
---

Rvsym has the following additional options:

Usage:
  rvsym [OPTIONS] EXE

Application Options:
      --time=    Stop execution after a given amount of seconds
  -s, --summary  Show execution summary
      --elf=     ELF debug information file
      --entry=   Program start address (default: 4096)
  -p, --profile= Dump profiling information to file
  -V, --verbose  Show verbose debug information
  -v, --version  Show version information
  -h, --help     Show this help message

Notes

Rvsym runs in Linux mode for ELF files, and bare-metal mode for .hex or .bin files. In Linux mode, Rvsym sets up the stack properly and provides a limited set of system calls, shown below. In bare-metal mode, Rvsym does not do any set-up. In the future bare-metal mode may include support for exceptions and other privileged CPU features.

The following system calls are provided in Linux mode: exit, open, read, write, lseek, close, fstat (does not provide accurate information), brk. These are a minimal set allowing basic memory allocation and file I/O.

Documentation

Index

Constants

View Source
const (
	AluAdd    = 0b0000000000
	AluSub    = 0b0100000000
	AluSlt    = 0b0000000010
	AluSltu   = 0b0000000011
	AluXor    = 0b0000000100
	AluSll    = 0b0000000001
	AluSrl    = 0b0000000101
	AluSra    = 0b0100000101
	AluOr     = 0b0000000110
	AluAnd    = 0b0000000111
	AluMul    = 0b0000001000
	AluMulH   = 0b0000001001
	AluMulHSU = 0b0000001010
	AluMulHU  = 0b0000001011
	AluDiv    = 0b0000001100
	AluDivU   = 0b0000001101
	AluRem    = 0b0000001110
	AluRemU   = 0b0000001111
)
View Source
const (
	ExitNone = iota
	ExitNormal
	ExitQuiet
	ExitFail
	ExitMem
	ExitUnsat
)
View Source
const (
	OpRarith = 0b0110011
	OpIarith = 0b0010011
	OpBranch = 0b1100011
	OpLui    = 0b0110111
	OpAuipc  = 0b0010111
	OpJal    = 0b1101111
	OpJalr   = 0b1100111
	OpLoad   = 0b0000011
	OpStore  = 0b0100011
	OpFence  = 0b0001111
	OpSys    = 0b1110011
	OpAtomic = 0b0101111
)
View Source
const (
	ExtByte  = 0b000
	ExtHalf  = 0b001
	ExtWord  = 0b010
	ExtByteU = 0b100
	ExtHalfU = 0b101
)
View Source
const (
	InsnEcall  = 0x00000073
	InsnEbreak = 0x00100073
	InsnNop    = 0x00000013
)
View Source
const (
	Rzero = iota
	Rra
	Rsp
	Rgp
	Rtp
	Rt0
	Rt1
	Rt2
	Rs0
	Rs1
	Ra0
	Ra1
	Ra2
	Ra3
	Ra4
	Ra5
	Ra6
	Ra7
	Rs2
	Rs3
	Rs4
	Rs5
	Rs6
	Rs7
	Rs8
	Rs9
	Rs10
	Rs11
	Rt3
	Rt4
	Rt5
	Rt6
)

Variables

View Source
var RegNames = map[int]string{
	0:  "zero",
	1:  "ra",
	2:  "sp",
	3:  "gp",
	4:  "tp",
	5:  "t0",
	6:  "t1",
	7:  "t2",
	8:  "s0",
	9:  "s1",
	10: "a0",
	11: "a1",
	12: "a2",
	13: "a3",
	14: "a4",
	15: "a5",
	16: "a6",
	17: "a7",
	18: "s2",
	19: "s3",
	20: "s4",
	21: "s5",
	22: "s6",
	23: "s7",
	24: "s8",
	25: "s9",
	26: "s10",
	27: "s11",
	28: "t3",
	29: "t4",
	30: "t5",
	31: "t6",
}

Functions

func SetLogger

func SetLogger(l *log.Logger)

SetLogger assigns a package-wide logger.

Types

type AluOp

type AluOp int

type Assignment

type Assignment struct {
	Name string
	Val  int32
}

type Branch

type Branch struct {
	// contains filtered or unexported fields
}

type Checkpoint

type Checkpoint struct {
	// contains filtered or unexported fields
}

type EcallFn

type EcallFn func(*Machine, *smt.Solver)

type ElfLoader

type ElfLoader struct{}

func (*ElfLoader) Load

func (l *ElfLoader) Load(data []byte) ([]Segment, uint32, error)

type EmuMode

type EmuMode byte
const (
	EmuLinux EmuMode = iota
	EmuBareMetal
	EmuUnderConstrained
)

type Engine

type Engine struct {
	Stats Stats
	// contains filtered or unexported fields
}

func NewEngine

func NewEngine(segs []Segment, entry uint32, mode EmuMode) *Engine

func (*Engine) NumTestCases

func (e *Engine) NumTestCases() int

func (*Engine) Step

func (e *Engine) Step() bool

func (*Engine) Summary

func (e *Engine) Summary() string

func (*Engine) TestCases

func (e *Engine) TestCases() []TestCase

type ExitStatus

type ExitStatus byte

func (ExitStatus) String

func (e ExitStatus) String() string

type FdTable

type FdTable struct {
	// contains filtered or unexported fields
}

func NewFdTable

func NewFdTable() FdTable

func (FdTable) Copy

func (t FdTable) Copy() FdTable

type IHexLoader

type IHexLoader struct {
	Entry uint32
}

func (*IHexLoader) Load

func (l *IHexLoader) Load(data []byte) ([]Segment, uint32, error)

type ImmType

type ImmType int
const (
	ImmTypeI ImmType = iota
	ImmTypeS
	ImmTypeB
	ImmTypeJ
	ImmTypeU
)

type Loader

type Loader interface {
	Load(data []byte) (segs []Segment, entry uint32, err error)
}

type Machine

type Machine struct {
	Status Status
	// contains filtered or unexported fields
}

func NewMachine

func NewMachine(pc int32, mem *Memory) *Machine

func Restore

func Restore(cp *Checkpoint, s *smt.Solver) *Machine

func (*Machine) AddCond

func (m *Machine) AddCond(cond smt.Bool, checksat bool, s *smt.Solver)

func (*Machine) Checkpoint

func (m *Machine) Checkpoint(cond smt.Bool) *Checkpoint

func (*Machine) Exec

func (m *Machine) Exec(s *smt.Solver) (isz int32)

func (*Machine) Reg

func (m *Machine) Reg(reg uint32) smt.Int32

func (*Machine) RegConc

func (m *Machine) RegConc(reg uint32) (int32, bool)

func (*Machine) RegConcretize

func (m *Machine) RegConcretize(reg uint32, s *smt.Solver) (int32, bool)

func (*Machine) SymExit

func (m *Machine) SymExit(s *smt.Solver)

func (*Machine) SymFail

func (m *Machine) SymFail(s *smt.Solver)

func (*Machine) SymMarkArray

func (m *Machine) SymMarkArray(s *smt.Solver)

func (*Machine) SymMarkBytes

func (m *Machine) SymMarkBytes(s *smt.Solver)

func (*Machine) SymPrint

func (m *Machine) SymPrint(s *smt.Solver)

func (*Machine) SymQuietExit

func (m *Machine) SymQuietExit(s *smt.Solver)

func (*Machine) SysBrk

func (m *Machine) SysBrk(s *smt.Solver)

func (*Machine) SysClose

func (m *Machine) SysClose(s *smt.Solver)

func (*Machine) SysExit

func (m *Machine) SysExit(s *smt.Solver)

func (*Machine) SysFstat

func (m *Machine) SysFstat(s *smt.Solver)

func (*Machine) SysLseek

func (m *Machine) SysLseek(s *smt.Solver)

func (*Machine) SysOpen

func (m *Machine) SysOpen(s *smt.Solver)

func (*Machine) SysRead

func (m *Machine) SysRead(s *smt.Solver)

func (*Machine) SysWrite

func (m *Machine) SysWrite(s *smt.Solver)

func (*Machine) TestCase

func (m *Machine) TestCase(s *smt.Solver) (TestCase, bool)

func (*Machine) WriteReg

func (m *Machine) WriteReg(reg uint32, val smt.Int32)

type Memory

type Memory struct {
	// contains filtered or unexported fields
}

func NewMemory

func NewMemory() *Memory

func (*Memory) Copy

func (m *Memory) Copy() *Memory

func (*Memory) MakeSymAddrRegion

func (m *Memory) MakeSymAddrRegion(base, length uint32, s *smt.Solver)

MakeSymAddrRegion marks the given region as a region of memory that can be symbolically addressed.

func (*Memory) Read16

func (m *Memory) Read16(addr smt.Int32, s *smt.Solver) (smt.Int32, bool)

Read16 reads the 16-bit value at addr. Returns false if not found.

func (*Memory) Read16u

func (m *Memory) Read16u(addr smt.Int32, s *smt.Solver) (smt.Int32, bool)

Read16u reads the 16-bit unsigned value at addr. Returns false if not found.

func (*Memory) Read8

func (m *Memory) Read8(addr smt.Int32, s *smt.Solver) (smt.Int32, bool)

Read8 reads the 8-bit value at addr. Returns false if not found.

func (*Memory) Read8u

func (m *Memory) Read8u(addr smt.Int32, s *smt.Solver) (smt.Int32, bool)

Read8u reads the 8-bit unsigned value at addr. Returns false if not found.

func (*Memory) ReadBytes

func (m *Memory) ReadBytes(addr uint32, data []byte, s *smt.Solver) bool

func (*Memory) ReadWord

func (m *Memory) ReadWord(addr smt.Int32, s *smt.Solver) (smt.Int32, bool)

func (*Memory) Write16

func (m *Memory) Write16(addr, val smt.Int32, s *smt.Solver) bool

Write16 writes a 16-bit value (truncated) at addr. Returns false if the access is out of bounds.

func (*Memory) Write8

func (m *Memory) Write8(addr, val smt.Int32, s *smt.Solver) bool

Write8 writes an 8-bit value (truncated) at addr.

func (*Memory) WriteBytes

func (m *Memory) WriteBytes(addr uint32, data []byte, s *smt.Solver) bool

func (*Memory) WriteWord

func (m *Memory) WriteWord(addr, val smt.Int32, s *smt.Solver) bool

type RawLoader

type RawLoader struct {
	Entry uint32
}

func (*RawLoader) Load

func (l *RawLoader) Load(data []byte) ([]Segment, uint32, error)

type Segment

type Segment struct {
	// contains filtered or unexported fields
}

type Stats

type Stats struct {
	Exits map[ExitStatus]int
	Steps int
	Forks int
}

type Status

type Status struct {
	Err   error
	HasBr bool
	Br    Branch
	Exit  ExitStatus
}

type SymVal

type SymVal struct {
	// contains filtered or unexported fields
}

type SysState

type SysState struct {
	// contains filtered or unexported fields
}

func NewSysState

func NewSysState(brk uint32) *SysState

func (*SysState) Copy

func (s *SysState) Copy() *SysState

type TestCase

type TestCase struct {
	Assignments []Assignment
	Exit        ExitStatus
	Pc          int32
	Err         error
}

func (TestCase) String

func (tc TestCase) String() string

func (TestCase) StringHex

func (tc TestCase) StringHex(hex bool) string

Directories

Path Synopsis
cmd
Package hashmap provides an implementation of a hashmap.
Package hashmap provides an implementation of a hashmap.
pkg
smt
smt/z3
Package z3 checks the satisfiability of logical formulas.
Package z3 checks the satisfiability of logical formulas.
smt/z3/z3log
Package z3log exposes Z3's interaction log.
Package z3log exposes Z3's interaction log.
Package rvc decompresses rv32c instructions
Package rvc decompresses rv32c instructions

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL