2008-05-29 Guillaume SADEGH <sadegh@lrde.epita.fr> * iface/nips/nips.cc, iface/nips/nips.hh, iface/nips/common.cc, iface/nips/common.hh, iface/nips/Makefile.am: TGBA implementation with the NIPS library. * iface/nips/emptiness_check.cc: Emptiness check on a Promela interface. * iface/nips/dottynips.cc: Dot printer on the NIPS interface. * iface/nips/compile.sh: Add. Wrapper around nips compiler to compile Promela to NIPS bytecode. * iface/nips/nips_vm,iface/nips/nips_vm/bytecode.h, iface/nips/nips_vm/ChangeLog, iface/nips/nips_vm/COPYING, iface/nips/nips_vm/hashtab.c, iface/nips/nips_vm/hashtab.h, iface/nips/nips_vm/INSTALL, iface/nips/nips_vm/instr.c, iface/nips/nips_vm/instr.h, iface/nips/nips_vm/instr_step.c, iface/nips/nips_vm/instr_step.h, iface/nips/nips_vm/instr_tools.c, iface/nips/nips_vm/instr_tools.h, iface/nips/nips_vm/instr_wrap.c, iface/nips/nips_vm/instr_wrap.h, iface/nips/nips_vm/interactive.c, iface/nips/nips_vm/interactive.h, iface/nips/nips_vm/main.c, iface/nips/nips_vm/Makefile, iface/nips/nips_vm/Makefile.am, iface/nips/nips_vm/nips_asm_help.pl, iface/nips/nips_vm/nips_asm_instr.pl, iface/nips/nips_vm/nips_asm.pl, iface/nips/nips_vm/nips_disasm.pl, iface/nips/nips_vm/nipsvm.c, iface/nips/nips_vm/nipsvm.h, iface/nips/nips_vm/README, iface/nips/nips_vm/rt_err.c, iface/nips/nips_vm/rt_err.h, iface/nips/nips_vm/search.c, iface/nips/nips_vm/search.h, iface/nips/nips_vm/split.c, iface/nips/nips_vm/split.h, iface/nips/nips_vm/state.c, iface/nips/nips_vm/state.h, iface/nips/nips_vm/state_inline.h, iface/nips/nips_vm/state_parts.c, iface/nips/nips_vm/state_parts.h, iface/nips/nips_vm/timeval.h, iface/nips/nips_vm/tools.h: NIPS VM added to the SPOT distribution. * configure.ac, iface/Makefile.am: Build system updated for the NIPS front-end.
367 lines
11 KiB
C
367 lines
11 KiB
C
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
|
* Copyright (C) 2005,2006: Stefan Schuermans <stefan@schuermans.info>
|
|
* Michael Weber <michaelw@i2.informatik.rwth-aachen.de>
|
|
* Lehrstuhl fuer Informatik II, RWTH Aachen
|
|
* Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
|
|
#include "bytecode.h"
|
|
#include "interactive.h"
|
|
#include "search.h"
|
|
#include "state.h"
|
|
|
|
|
|
// minimal, default, maximal size of state buffer (in MB)
|
|
#define MINIMAL_BUFFER_LEN_M 1 // 1MB
|
|
#define DEFAULT_BUFFER_LEN_M 256 // 256MB
|
|
#define MAXIMAL_BUFFER_LEN_M 8192 // 8GB
|
|
// minimal, default, maximal hash table parameters (in k entries, in retries)
|
|
#define MINIMAL_HASH_ENTRIES_K 64 // 64k entries (may not be smaller than 64k because of hashtab internals)
|
|
#define DEFAULT_HASH_ENTRIES_K 4096 // 4M entries
|
|
#define MAXIMAL_HASH_ENTRIES_K 131072 // 128M entries
|
|
#define MINIMAL_HASH_RETRIES 2 // 2 retries
|
|
#define DEFAULT_HASH_RETRIES 500 // 500 retries
|
|
#define MAXIMAL_HASH_RETRIES 1000 // 1000 retries (insane)
|
|
// minimal, default, maximal size of state pointer buffer entries (in k entries)
|
|
#define MINIMAL_STATES_MAX_K 1 // 1k entries
|
|
#define DEFAULT_STATES_MAX_K 8 // 8k entries
|
|
#define MAXIMAL_STATES_MAX_K 1024 // 1M entries
|
|
// maximum values are here to ensure that user does not enter utopical values
|
|
// - like 1e9 MB for state buffer size
|
|
// - would result in overflow during multiplication (while converting from MB to bytes)
|
|
// the maximum values can be increased on 64 bit systems
|
|
// and slightly increased on 32 bit systems with 36 bit addresses
|
|
|
|
|
|
// read state from hex string
|
|
// returns boolean result (if successful)
|
|
static int read_hex( char *str, char *state, int max_size )
|
|
{
|
|
unsigned int val;
|
|
for( ; *str != 0; )
|
|
{
|
|
if( sscanf( str, "%2X", &val ) != 1 )
|
|
return 0;
|
|
str += 2;
|
|
if( max_size <= 0 )
|
|
return 0;
|
|
*state = (char)(unsigned char)val;
|
|
state++;
|
|
max_size--;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
char *bytecode_file = "", *bytecode_module = NULL, *graph_file = NULL, *ptr;
|
|
unsigned int depth = 0;
|
|
unsigned int lookup_addr = 0;
|
|
unsigned long buffer_len = DEFAULT_BUFFER_LEN_M * 1048576;
|
|
unsigned long hash_entries = DEFAULT_HASH_ENTRIES_K * 1024;
|
|
unsigned long hash_retries = DEFAULT_HASH_RETRIES;
|
|
unsigned long states_max = DEFAULT_STATES_MAX_K * 1024;
|
|
unsigned long val;
|
|
int have_bytecode_file, have_bytecode_module, breadth_first, have_depth, have_lookup;
|
|
int random, rnd_quiet, print_hex, split, i, arg_err, graph;
|
|
st_bytecode *bytecode;
|
|
FILE *graph_out = NULL;
|
|
char initial_state[1024];
|
|
st_global_state_header *p_ini_state = NULL;
|
|
|
|
printf( "NIPS VM version 1.2.6 date 2007-03-10\n"
|
|
"Copyright (C) 2005,2007: Stefan Schuermans <stefan@schuermans.info>\n"
|
|
" Michael Weber <Michael.Weber@cwi.nl>\n"
|
|
" Lehrstuhl fuer Informatik II, RWTH Aachen\n"
|
|
"Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html\n\n" );
|
|
|
|
// initialize pseudo random number generator
|
|
srand( time( NULL ) );
|
|
|
|
// parse parameters
|
|
arg_err = 0;
|
|
have_bytecode_file = 0;
|
|
have_bytecode_module = 0;
|
|
breadth_first = 0;
|
|
have_depth = 0;
|
|
have_lookup = 0;
|
|
random = 0;
|
|
rnd_quiet = 0;
|
|
print_hex = 0;
|
|
split = 0;
|
|
graph = 0;
|
|
for( i = 1; i < argc && ! arg_err; i++ )
|
|
{
|
|
// breadth first search
|
|
if( strcmp( argv[i], "-B" ) == 0 )
|
|
{
|
|
breadth_first = 1;
|
|
}
|
|
// depth first search
|
|
else if( strcmp( argv[i], "-D" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
depth = (unsigned int)strtoul( argv[i], NULL, 0 );
|
|
have_depth = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// print states in hexadecimal
|
|
else if( strcmp( argv[i], "-H" ) == 0 )
|
|
print_hex = 1;
|
|
// initial state
|
|
else if( strcmp( argv[i], "-I" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
if( read_hex( argv[i], initial_state, sizeof( initial_state ) ) )
|
|
p_ini_state = (st_global_state_header *)initial_state;
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// lookup address
|
|
else if( strcmp( argv[i], "-L" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
lookup_addr = (unsigned int)strtoul( argv[i], NULL, 0 );
|
|
have_lookup = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// random simulation
|
|
else if( strcmp( argv[i], "-R" ) == 0 )
|
|
random = 1, rnd_quiet = 0;
|
|
// quiet random simulation
|
|
else if( strcmp( argv[i], "-Rq" ) == 0 )
|
|
random = 1, rnd_quiet = 1;
|
|
// split up and reassemble states
|
|
else if( strcmp( argv[i], "-S" ) == 0 )
|
|
split = 1;
|
|
// buffer size
|
|
else if( strcmp( argv[i], "-b" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
val = strtoul( argv[i], NULL, 0 );
|
|
if( val >= MINIMAL_BUFFER_LEN_M && val <= MAXIMAL_BUFFER_LEN_M )
|
|
buffer_len = val * 1048576;
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// state graph output
|
|
else if( strcmp( argv[i], "-g" ) == 0 )
|
|
{
|
|
graph = 1;
|
|
}
|
|
// state graph output to file
|
|
else if( strcmp( argv[i], "-gf" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
graph = 1;
|
|
graph_file = argv[i];
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// hash table parameters
|
|
else if( strcmp( argv[i], "-h" ) == 0 )
|
|
{
|
|
if( i + 2 < argc )
|
|
{
|
|
i++;
|
|
val = strtoul( argv[i], NULL, 0 );
|
|
if( val >= MINIMAL_HASH_ENTRIES_K && val <= MAXIMAL_HASH_ENTRIES_K )
|
|
hash_entries = val * 1024;
|
|
else
|
|
arg_err = 1;
|
|
i++;
|
|
val = strtoul( argv[i], NULL, 0 );
|
|
if( val >= MINIMAL_HASH_RETRIES && val <= MAXIMAL_HASH_RETRIES )
|
|
hash_retries = val;
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// state pointer buffer entries
|
|
else if( strcmp( argv[i], "-s" ) == 0 )
|
|
{
|
|
if( i + 1 < argc )
|
|
{
|
|
i++;
|
|
val = strtoul( argv[i], NULL, 0 );
|
|
if( val >= MINIMAL_STATES_MAX_K && val <= MAXIMAL_STATES_MAX_K )
|
|
states_max = val * 1024;
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
// unknown option
|
|
else if( argv[i][0] == '-' )
|
|
arg_err = 1;
|
|
// bytecode file
|
|
else if( ! have_bytecode_file )
|
|
{
|
|
bytecode_file = argv[i];
|
|
have_bytecode_file = 1;
|
|
}
|
|
// bytecode module
|
|
else if( ! have_bytecode_module )
|
|
{
|
|
bytecode_module = argv[i];
|
|
have_bytecode_module = 1;
|
|
}
|
|
// unknown argument
|
|
else
|
|
arg_err = 1;
|
|
}
|
|
if( ! have_bytecode_file ) // no bytecode file -> ...
|
|
arg_err = 1; // ... -> argument error
|
|
|
|
// print usage in case of argument error
|
|
if( arg_err )
|
|
{
|
|
printf( "usage:\n"
|
|
" %s [options] <bytecode file> [<bytecode module>]\n\n"
|
|
"options:\n"
|
|
" -B perform breadth-first search\n"
|
|
" -D <depth> perform depth-first search up to specified depth\n"
|
|
" -H print states in hexadecimal\n"
|
|
" -I <hex-state> use supplied initial state (format: \"[0-9A-F]*\")\n"
|
|
" -L <address> lookup source code location to address\n"
|
|
" -R perform random simulation\n"
|
|
" -Rq perform quiet random simulation\n"
|
|
" -S split up and reassemble states (not for -B or -D)\n"
|
|
" -b <buffer-size> set buffer size to use\n"
|
|
" (in MB, valid: %u..%u, default: %u)\n"
|
|
" -g output state graph in graphviz format (-B, -D)\n"
|
|
" -gf <file> output state graph in graphviz format (-B, -D)\n"
|
|
" -h <entries> <retries> set hash table parameters\n"
|
|
" (in k entries, valid: %u..%u, default: %u,\n"
|
|
" in retries, valid: %u..%u, default: %u)\n"
|
|
" -s <state-count> set number of state pointer buffer entries\n"
|
|
" (in k entries, valid: %u..%u, default: %u)\n\n",
|
|
argv[0],
|
|
MINIMAL_BUFFER_LEN_M, MAXIMAL_BUFFER_LEN_M, DEFAULT_BUFFER_LEN_M,
|
|
MINIMAL_HASH_ENTRIES_K, MAXIMAL_HASH_ENTRIES_K, DEFAULT_HASH_ENTRIES_K,
|
|
MINIMAL_HASH_RETRIES, MAXIMAL_HASH_RETRIES, DEFAULT_HASH_RETRIES,
|
|
MINIMAL_STATES_MAX_K, MAXIMAL_STATES_MAX_K, DEFAULT_STATES_MAX_K );
|
|
return -1;
|
|
}
|
|
|
|
// load bytecode
|
|
bytecode = bytecode_load_from_file( bytecode_file, bytecode_module );
|
|
if( bytecode == NULL )
|
|
{
|
|
if( have_bytecode_module )
|
|
fprintf( stderr, "could not load bytecode module \"%s\" from file \"%s\": %s\n\n",
|
|
bytecode_module, bytecode_file, strerror( errno ) );
|
|
else
|
|
fprintf( stderr, "could not load bytecode from file \"%s\": %s\n\n",
|
|
bytecode_file, strerror( errno ) );
|
|
return -1;
|
|
}
|
|
|
|
// state graph output - generate filename
|
|
i = 1;
|
|
if( graph && graph_file == NULL )
|
|
{
|
|
if( have_bytecode_module )
|
|
i = strlen( bytecode_file ) + strlen( bytecode_module ) + 16;
|
|
else
|
|
i = strlen( bytecode_file ) + 16;
|
|
}
|
|
char graph_file_buf[i]; // allocate buffer for filename
|
|
if( graph && graph_file == NULL )
|
|
{
|
|
if( have_bytecode_module )
|
|
sprintf( graph_file_buf, "%s_%s.dot", bytecode_file, bytecode_module );
|
|
else
|
|
sprintf( graph_file_buf, "%s.dot", bytecode_file );
|
|
graph_file = graph_file_buf;
|
|
}
|
|
// state graph output - open file
|
|
if( graph )
|
|
{
|
|
graph_out = fopen( graph_file, "wt" );
|
|
if( graph_out == NULL )
|
|
fprintf( stderr, "could not open graph output file \"%s\" (%s) -> no graph output\n", graph_file, strerror( errno ) );
|
|
}
|
|
// state graph output - print header
|
|
if( graph_out != NULL )
|
|
{
|
|
fprintf( graph_out, "digraph \"" );
|
|
for( ptr = bytecode_file; *ptr != 0; ptr++ )
|
|
if( *ptr < ' ' || *ptr == '\'' || *ptr == '\"' || *ptr == '\\' )
|
|
fputc( '_', graph_out );
|
|
else
|
|
fputc( *ptr, graph_out );
|
|
if( have_bytecode_module )
|
|
{
|
|
fputc( '_', graph_out );
|
|
for( ptr = bytecode_module; *ptr != 0; ptr++ )
|
|
if( *ptr < ' ' || *ptr == '\'' || *ptr == '\"' || *ptr == '\\' )
|
|
fputc( '_', graph_out );
|
|
else
|
|
fputc( *ptr, graph_out );
|
|
}
|
|
fprintf( graph_out, "\" {\n" );
|
|
}
|
|
|
|
// lookup address
|
|
if( have_lookup )
|
|
{
|
|
st_src_loc loc = bytecode_src_loc( bytecode, lookup_addr );
|
|
printf( "looked up address 0x%08X: line %d col %d\n\n", loc.addr, loc.line, loc.col );
|
|
}
|
|
|
|
// depth-first/breadth-first search
|
|
else if( breadth_first || have_depth )
|
|
search( bytecode, breadth_first, depth, buffer_len, hash_entries, hash_retries,
|
|
graph_out, print_hex, p_ini_state );
|
|
|
|
// interactive/random simulation
|
|
else
|
|
interactive_simulate( bytecode, random, rnd_quiet, print_hex, split,
|
|
buffer_len, states_max, p_ini_state );
|
|
|
|
// state graph output - finish and close file
|
|
if( graph_out != NULL )
|
|
{
|
|
fprintf( graph_out, "}\n" );
|
|
fclose( graph_out );
|
|
}
|
|
|
|
printf( "\n" );
|
|
|
|
// unload bytecode
|
|
bytecode_unload( bytecode );
|
|
return 0;
|
|
}
|
|
|