NIPS VM added to the SPOT distribution.
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.
This commit is contained in:
parent
543190f2bc
commit
bc5f13bb4e
57 changed files with 11464 additions and 3 deletions
42
ChangeLog
42
ChangeLog
|
|
@ -1,3 +1,45 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
* src/Makefile.am (_.cc): Fix for `make tags`.
|
||||||
|
|
||||||
2008-04-16 Damien Lefortier <dam@lrde.epita.fr>
|
2008-04-16 Damien Lefortier <dam@lrde.epita.fr>
|
||||||
|
|
||||||
* configure.ac, Makefile.am: Add src/eltltest/ support.
|
* configure.ac, Makefile.am: Add src/eltltest/ support.
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ AC_CONFIG_FILES([
|
||||||
iface/Makefile
|
iface/Makefile
|
||||||
iface/gspn/Makefile
|
iface/gspn/Makefile
|
||||||
iface/gspn/defs
|
iface/gspn/defs
|
||||||
|
iface/nips/Makefile
|
||||||
|
iface/nips/nips_vm/Makefile
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/eltlast/Makefile
|
src/eltlast/Makefile
|
||||||
src/eltlenv/Makefile
|
src/eltlenv/Makefile
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
## Copyright (C) 2003 Laboratoire d'Informatique de Paris 6 (LIP6),
|
## Copyright (C) 2003, 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
## et Marie Curie.
|
## et Marie Curie.
|
||||||
##
|
##
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
## 02111-1307, USA.
|
## 02111-1307, USA.
|
||||||
|
|
||||||
|
SUBDIRS = nips
|
||||||
|
|
||||||
if WITH_GSPN
|
if WITH_GSPN
|
||||||
SUBDIRS = gspn
|
SUBDIRS += gspn
|
||||||
endif
|
endif
|
||||||
|
|
|
||||||
2
iface/nips/.gitignore
vendored
Normal file
2
iface/nips/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.lo
|
||||||
|
TAGS
|
||||||
46
iface/nips/Makefile.am
Normal file
46
iface/nips/Makefile.am
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
## Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
## département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
## et Marie Curie.
|
||||||
|
##
|
||||||
|
## This file is part of Spot, a model checking library.
|
||||||
|
##
|
||||||
|
## Spot is free software; you can redistribute it and/or modify it
|
||||||
|
## under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
## License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public License
|
||||||
|
## along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
## 02111-1307, USA.
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -I$(top_srcdir)/src $(BUDDY_CPPFLAGS) -I$(srcdir)/nips_vm
|
||||||
|
AM_CXXFLAGS = $(WARNING_CXXFLAGS)
|
||||||
|
|
||||||
|
nipsdir = $(pkgincludedir)/nips
|
||||||
|
|
||||||
|
nips_HEADERS = \
|
||||||
|
common.hh \
|
||||||
|
nips.hh
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libspotnips.la
|
||||||
|
libspotnips_la_LIBADD = $(top_builddir)/src/libspot.la
|
||||||
|
libspotnips_la_SOURCES = \
|
||||||
|
common.cc \
|
||||||
|
nips.cc
|
||||||
|
|
||||||
|
noinst_PROGRAMS = \
|
||||||
|
dottynips
|
||||||
|
|
||||||
|
dottynips_SOURCES = dottynips.cc
|
||||||
|
dottynips_LDADD = libspotnips.la $(builddir)/nips_vm/libnipsvm.la
|
||||||
|
|
||||||
|
empt_check_SOURCES = emptiness_check.cc
|
||||||
|
empt_check_LDADD = libspotnips.la $(builddir)/nips_vm/libnipsvm.la
|
||||||
|
|
||||||
|
SUBDIRS = nips_vm
|
||||||
38
iface/nips/common.cc
Normal file
38
iface/nips/common.cc
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
// et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
#include "common.hh"
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& os, const nips_exception& e)
|
||||||
|
{
|
||||||
|
if (e.get_err_defined())
|
||||||
|
os << e.get_where() << " exited with " << e.get_err();
|
||||||
|
else
|
||||||
|
os << e.get_where() << " with no exit value";
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
}
|
||||||
72
iface/nips/common.hh
Normal file
72
iface/nips/common.hh
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
// et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
#ifndef SPOT_IFACE_NIPS_COMMON_HH
|
||||||
|
# define SPOT_IFACE_NIPS_COMMON_HH
|
||||||
|
|
||||||
|
# include <string>
|
||||||
|
# include <iosfwd>
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
|
||||||
|
/// An exception used to forward NIPS errors.
|
||||||
|
class nips_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nips_exception(const std::string& where, int err)
|
||||||
|
: err_(err), where_(where), err_defined_(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
nips_exception(const std::string& where)
|
||||||
|
: err_(-1), where_(where), err_defined_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_err() const
|
||||||
|
{
|
||||||
|
return err_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
get_where() const
|
||||||
|
{
|
||||||
|
return where_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_err_defined() const
|
||||||
|
{
|
||||||
|
return err_defined_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int err_;
|
||||||
|
std::string where_;
|
||||||
|
bool err_defined_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const nips_exception& e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SPOT_IFACE_NIPS_COMMON_HH
|
||||||
35
iface/nips/compile.sh
Executable file
35
iface/nips/compile.sh
Executable file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
NIPS_COMPILER=~/lrde/vmssg/nips_c/CodeGen
|
||||||
|
NIPS_ASSEMBLER=~/lrde/vmssg/nips_vm/nips_asm.pl
|
||||||
|
THISDIR=`pwd`
|
||||||
|
|
||||||
|
if [ ! -f "$NIPS_COMPILER" ]; then
|
||||||
|
echo "You have to specify the path of your NIPS compiler (CodeGen)"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$NIPS_ASSEMBLER" ]; then
|
||||||
|
echo "You have to specify the path of your NIPS assembler (nips_asm.pl)"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "usage : $0 promela_model"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
FILE="$(cd `dirname $1`; pwd)/`basename $1`"
|
||||||
|
TMP_FILE="/tmp/`basename $1`"
|
||||||
|
|
||||||
|
cpp "$FILE" | sed 's/^#.*$//' > "$TMP_FILE"
|
||||||
|
|
||||||
|
cd `dirname $NIPS_COMPILER`
|
||||||
|
./`basename $NIPS_COMPILER` "$TMP_FILE"
|
||||||
|
|
||||||
|
cd `dirname $NIPS_ASSEMBLER`
|
||||||
|
./`basename $NIPS_ASSEMBLER` "$TMP_FILE.s"
|
||||||
|
|
||||||
|
mv "$TMP_FILE.b" "$FILE.b"
|
||||||
|
|
||||||
|
echo "$FILE".b
|
||||||
48
iface/nips/dottynips.cc
Normal file
48
iface/nips/dottynips.cc
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
// et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
#include "nips.hh"
|
||||||
|
#include "tgbaalgos/dotty.hh"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
std::cerr << "usage: " << argv[0] << " promela_bytecode" << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
spot::bdd_dict* dict = new spot::bdd_dict();
|
||||||
|
spot::nips_interface nips(dict, argv[1]);
|
||||||
|
spot::tgba* a = nips.automaton();
|
||||||
|
|
||||||
|
spot::dotty_reachable(std::cout, a);
|
||||||
|
|
||||||
|
delete a;
|
||||||
|
delete dict;
|
||||||
|
}
|
||||||
|
catch (spot::nips_exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << e << std::endl;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
129
iface/nips/emptiness_check.cc
Normal file
129
iface/nips/emptiness_check.cc
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire
|
||||||
|
// d'Informatique de Paris 6 (LIP6), département Systèmes Répartis
|
||||||
|
// Coopératifs (SRC), Université Pierre et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include "common.hh"
|
||||||
|
#include "nips.hh"
|
||||||
|
#include "tgbaalgos/gtec/gtec.hh"
|
||||||
|
#include "tgbaalgos/gtec/ce.hh"
|
||||||
|
#include "tgbaalgos/projrun.hh"
|
||||||
|
|
||||||
|
void
|
||||||
|
display_stats(const spot::unsigned_statistics* s)
|
||||||
|
{
|
||||||
|
assert(s);
|
||||||
|
spot::unsigned_statistics::stats_map::const_iterator i;
|
||||||
|
for (i = s->stats.begin(); i != s->stats.end(); ++i)
|
||||||
|
std::cout << i->first << " = " << (s->*i->second)() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// enum {Couvreur, Couvreur2} check = Couvreur;
|
||||||
|
bool compute_counter_example = true;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
std::cerr << "usage: " << argv[0] << "[OPTIONS...] promela_bytecode"
|
||||||
|
<< std::endl
|
||||||
|
<< "with OPTIONS :" << std::endl
|
||||||
|
<< " -c compute an example" << std::endl
|
||||||
|
<< " (instead of just checking for emptiness)" << std::endl
|
||||||
|
<< " -eALGO use ALGO emptiness-check (default)" << std::endl
|
||||||
|
<< "Where ALGO should be one of:" << std::endl
|
||||||
|
<< " Cou99(OPTIONS) (the default)" << std::endl
|
||||||
|
<< " CVWY90(OPTIONS)" << std::endl
|
||||||
|
<< " GV04(OPTIONS)" << std::endl
|
||||||
|
<< " SE05(OPTIONS)" << std::endl
|
||||||
|
<< " Tau03(OPTIONS)" << std::endl
|
||||||
|
<< " Tau03_opt(OPTIONS)" << std::endl;
|
||||||
|
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int arg_index = 1;
|
||||||
|
spot::emptiness_check_instantiator* echeck_inst = 0;
|
||||||
|
const char* echeck_algo = "Cou99";
|
||||||
|
|
||||||
|
for (; arg_index < argc - 1; ++arg_index)
|
||||||
|
{
|
||||||
|
if (!strcmp(argv[arg_index], "-c"))
|
||||||
|
compute_counter_example = false;
|
||||||
|
else if (!strncmp(argv[arg_index], "-e", 2))
|
||||||
|
{
|
||||||
|
echeck_algo = 2 + argv[arg_index];
|
||||||
|
if (!*echeck_algo)
|
||||||
|
echeck_algo = "Cou99";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* err;
|
||||||
|
echeck_inst =
|
||||||
|
spot::emptiness_check_instantiator::construct(echeck_algo, &err);
|
||||||
|
if (!echeck_inst)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to parse argument of -e near `"
|
||||||
|
<< err << "'" << std::endl;
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
spot::bdd_dict* dict = new spot::bdd_dict();
|
||||||
|
spot::nips_interface nips(dict, argv[arg_index]);
|
||||||
|
spot::tgba* a = nips.automaton();
|
||||||
|
|
||||||
|
spot::emptiness_check* ec = echeck_inst->instantiate(a);
|
||||||
|
spot::emptiness_check_result* res = ec->check();
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
{
|
||||||
|
if (compute_counter_example)
|
||||||
|
{
|
||||||
|
spot::tgba_run* run = res->accepting_run();
|
||||||
|
spot::print_tgba_run(std::cout, a, run);
|
||||||
|
std::cout << "non empty" << std::endl;
|
||||||
|
ec->print_stats(std::cout);
|
||||||
|
delete run;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "non empty" << std::endl;
|
||||||
|
ec->print_stats(std::cout);
|
||||||
|
}
|
||||||
|
delete res;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "empty" << std::endl;
|
||||||
|
ec->print_stats(std::cout);
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
delete ec;
|
||||||
|
}
|
||||||
|
catch (spot::nips_exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << e << std::endl;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
423
iface/nips/nips.cc
Normal file
423
iface/nips/nips.cc
Normal file
|
|
@ -0,0 +1,423 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
// et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include "misc/hashfunc.hh"
|
||||||
|
#include "nips.hh"
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Callback for errors
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Callback for error which continues on assertions
|
||||||
|
nipsvm_status_t
|
||||||
|
search_error_callback(nipsvm_errorcode_t err, nipsvm_pid_t pid,
|
||||||
|
nipsvm_pc_t pc, void *)
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
|
||||||
|
nipsvm_errorstring (str, sizeof str, err, pid, pc);
|
||||||
|
std::cerr << "RUNTIME ERROR (" << err << "): " << str << std::endl;
|
||||||
|
|
||||||
|
// Continue on assertions
|
||||||
|
if (err == 9)
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
throw nips_exception(std::string(str), static_cast<int>(err));
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback for error which fails on assertions
|
||||||
|
nipsvm_status_t
|
||||||
|
search_error_callback_assert(nipsvm_errorcode_t err, nipsvm_pid_t pid,
|
||||||
|
nipsvm_pc_t pc, void *)
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
|
||||||
|
nipsvm_errorstring (str, sizeof str, err, pid, pc);
|
||||||
|
std::cerr << "RUNTIME ERROR (" << err << "): " << str << std::endl;
|
||||||
|
|
||||||
|
throw nips_exception(std::string(str), static_cast<int>(err));
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// state_nips
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class state_nips: public state
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
state_nips(nipsvm_state_t* s)
|
||||||
|
{
|
||||||
|
state_nips_init(s);
|
||||||
|
nips_state_ = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
state_nips(nipsvm_state_t* s, nipsvm_state_t* nips_state)
|
||||||
|
{
|
||||||
|
state_nips_init(s);
|
||||||
|
nips_state_ = nips_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void state_nips_init(nipsvm_state_t* s)
|
||||||
|
{
|
||||||
|
ref_ = new unsigned(1);
|
||||||
|
unsigned long size = nipsvm_state_size(s);
|
||||||
|
unsigned long size_buf = size;
|
||||||
|
char* state_as_char = new char[size];
|
||||||
|
state_ = reinterpret_cast<nipsvm_state_t*>(state_as_char);
|
||||||
|
nipsvm_state_copy(size, s, &state_as_char, &size_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
state_nips(const state* other)
|
||||||
|
: ref_(new unsigned(1))
|
||||||
|
{
|
||||||
|
const state_nips* o = dynamic_cast<const state_nips*>(other);
|
||||||
|
assert(o);
|
||||||
|
ref_ = o->ref_;
|
||||||
|
++(*ref_);
|
||||||
|
state_ = o->state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~state_nips()
|
||||||
|
{
|
||||||
|
--(*ref_);
|
||||||
|
if (*ref_ == 0)
|
||||||
|
{
|
||||||
|
delete[] state_;
|
||||||
|
delete ref_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lazy computation for the hash.
|
||||||
|
void
|
||||||
|
hash_comp()
|
||||||
|
{
|
||||||
|
size_t size = nipsvm_state_size(get_state());
|
||||||
|
hash_ = 0;
|
||||||
|
size_t* state = reinterpret_cast<size_t*>(get_state());
|
||||||
|
size_t full_size = (size - (size % sizeof (size_t))) / sizeof (size_t);
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < full_size; ++i)
|
||||||
|
hash_ ^= wang32_hash(state[i]);
|
||||||
|
|
||||||
|
// Hash on the remainder.
|
||||||
|
unsigned remainder = 0;
|
||||||
|
char* state_in_char = reinterpret_cast<char*>(state);
|
||||||
|
size_t init_pos = i * sizeof (size_t);
|
||||||
|
unsigned j;
|
||||||
|
for (j = 0; j < (size % sizeof (size_t)); ++j)
|
||||||
|
remainder = remainder * 0x100 + state_in_char[init_pos + j];
|
||||||
|
for (; j < sizeof (size_t); ++j)
|
||||||
|
remainder *= 0x100;
|
||||||
|
hash_ ^= remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int
|
||||||
|
compare(const state* other) const
|
||||||
|
{
|
||||||
|
const state_nips* o = dynamic_cast<const state_nips*>(other);
|
||||||
|
assert(o);
|
||||||
|
return reinterpret_cast<char*>(o->get_state())
|
||||||
|
- reinterpret_cast<char*>(get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t
|
||||||
|
hash() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<char*>(get_state()) - static_cast<char*>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual state_nips* clone() const
|
||||||
|
{
|
||||||
|
return new state_nips(get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
nipsvm_state_t*
|
||||||
|
get_state() const
|
||||||
|
{
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
nipsvm_state_t*
|
||||||
|
get_nips_state() const
|
||||||
|
{
|
||||||
|
return nips_state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned* ref_;
|
||||||
|
nipsvm_state_t* state_;
|
||||||
|
nipsvm_state_t* nips_state_;
|
||||||
|
}; // state_nips
|
||||||
|
|
||||||
|
// Callback for successors
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
nipsvm_status_t
|
||||||
|
successor_state_callback(size_t, nipsvm_state_t *succ,
|
||||||
|
nipsvm_transition_information_t *,
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
std::list<state_nips*> *succ_list =
|
||||||
|
reinterpret_cast<std::list<state_nips*>*>(context);
|
||||||
|
|
||||||
|
succ_list->push_back(new state_nips(succ));
|
||||||
|
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tgba_succ_iterator_nips
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class tgba_succ_iterator_nips : public tgba_succ_iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::list<state_nips*> s_list;
|
||||||
|
tgba_succ_iterator_nips(const state_nips* parent);
|
||||||
|
~tgba_succ_iterator_nips();
|
||||||
|
virtual void first();
|
||||||
|
virtual void next();
|
||||||
|
virtual bool done() const;
|
||||||
|
virtual state* current_state() const;
|
||||||
|
virtual bdd current_condition() const;
|
||||||
|
virtual bdd current_acceptance_conditions() const;
|
||||||
|
s_list* succ_list_get() const;
|
||||||
|
private:
|
||||||
|
const state_nips* parent_;
|
||||||
|
bool has_acceptance_condition_;
|
||||||
|
bdd acceptance_condition_;
|
||||||
|
s_list* succ_list_;
|
||||||
|
s_list::iterator iterator_;
|
||||||
|
};
|
||||||
|
|
||||||
|
tgba_succ_iterator_nips::tgba_succ_iterator_nips(const state_nips* parent)
|
||||||
|
: parent_(parent), has_acceptance_condition_(false),
|
||||||
|
acceptance_condition_(bddfalse), succ_list_(new s_list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_succ_iterator_nips::~tgba_succ_iterator_nips()
|
||||||
|
{
|
||||||
|
// s_list::iterator it = succ_list_->begin();
|
||||||
|
// for (; it != succ_list_->end(); ++it)
|
||||||
|
// delete *it;
|
||||||
|
delete succ_list_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tgba_succ_iterator_nips::first()
|
||||||
|
{
|
||||||
|
iterator_ = succ_list_->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tgba_succ_iterator_nips::next()
|
||||||
|
{
|
||||||
|
++iterator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
tgba_succ_iterator_nips::done() const
|
||||||
|
{
|
||||||
|
return iterator_ == succ_list_->end();
|
||||||
|
}
|
||||||
|
|
||||||
|
state*
|
||||||
|
tgba_succ_iterator_nips::current_state() const
|
||||||
|
{
|
||||||
|
assert(!done());
|
||||||
|
return *iterator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_succ_iterator_nips::current_condition() const
|
||||||
|
{
|
||||||
|
return (nipsvm_state_monitor_acc_or_term(parent_->get_state()) ?
|
||||||
|
bddtrue : bddfalse);
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_succ_iterator_nips::current_acceptance_conditions() const
|
||||||
|
{
|
||||||
|
return (nipsvm_state_monitor_acc_or_term(parent_->get_state()) ?
|
||||||
|
bddtrue : bddfalse);
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_succ_iterator_nips::s_list*
|
||||||
|
tgba_succ_iterator_nips::succ_list_get() const
|
||||||
|
{
|
||||||
|
return succ_list_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tgba_nips
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class tgba_nips: public tgba
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
tgba_nips(bdd_dict* dict, nipsvm_t* nipsvm);
|
||||||
|
tgba_nips(const tgba_nips& other);
|
||||||
|
tgba_nips& operator=(const tgba_nips& other);
|
||||||
|
virtual ~tgba_nips();
|
||||||
|
virtual state* get_init_state() const;
|
||||||
|
virtual tgba_succ_iterator*
|
||||||
|
succ_iter(const state* local_state,
|
||||||
|
const state* global_state,
|
||||||
|
const tgba* global_automaton) const;
|
||||||
|
virtual bdd_dict* get_dict() const;
|
||||||
|
virtual std::string format_state(const state* state) const;
|
||||||
|
virtual bdd all_acceptance_conditions() const;
|
||||||
|
virtual bdd neg_acceptance_conditions() const;
|
||||||
|
protected:
|
||||||
|
virtual bdd compute_support_conditions(const spot::state* state) const;
|
||||||
|
virtual bdd compute_support_variables(const spot::state* state) const;
|
||||||
|
private:
|
||||||
|
bdd_dict* dict_;
|
||||||
|
nipsvm_t* nipsvm_;
|
||||||
|
}; //tgba_nips
|
||||||
|
|
||||||
|
tgba_nips::tgba_nips(bdd_dict* dict, nipsvm_t* nipsvm)
|
||||||
|
: dict_(dict), nipsvm_(nipsvm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_nips::tgba_nips(const tgba_nips& other)
|
||||||
|
: tgba()
|
||||||
|
{
|
||||||
|
dict_ = other.dict_;
|
||||||
|
nipsvm_ = other.nipsvm_;
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_nips&
|
||||||
|
tgba_nips::operator=(const tgba_nips& other)
|
||||||
|
{
|
||||||
|
if (&other != this)
|
||||||
|
{
|
||||||
|
dict_ = other.dict_;
|
||||||
|
nipsvm_ = other.nipsvm_;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_nips::~tgba_nips()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
state*
|
||||||
|
tgba_nips::get_init_state() const
|
||||||
|
{
|
||||||
|
return new state_nips(nipsvm_initial_state(nipsvm_));
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba_succ_iterator*
|
||||||
|
tgba_nips::succ_iter(const state* local_state,
|
||||||
|
const state*,
|
||||||
|
const tgba*) const
|
||||||
|
{
|
||||||
|
const state_nips* state =
|
||||||
|
reinterpret_cast<const state_nips*>(local_state);
|
||||||
|
|
||||||
|
tgba_succ_iterator_nips* iter = new tgba_succ_iterator_nips(state);
|
||||||
|
nipsvm_scheduler_iter(nipsvm_, state->get_state(),
|
||||||
|
static_cast<void *>(iter->succ_list_get()));
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd_dict* tgba_nips::get_dict() const
|
||||||
|
{
|
||||||
|
return dict_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
tgba_nips::format_state(const state* state) const
|
||||||
|
{
|
||||||
|
const state_nips* s = dynamic_cast<const state_nips*>(state);
|
||||||
|
unsigned size = global_state_to_str(s->get_state(), 0, 0, 0);
|
||||||
|
char buf[size];
|
||||||
|
|
||||||
|
global_state_to_str(s->get_state(), 0, buf, size);
|
||||||
|
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_nips::all_acceptance_conditions() const
|
||||||
|
{
|
||||||
|
return bddtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_nips::neg_acceptance_conditions() const
|
||||||
|
{
|
||||||
|
return bddtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_nips::compute_support_conditions(const spot::state*) const
|
||||||
|
{
|
||||||
|
return bddtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdd
|
||||||
|
tgba_nips::compute_support_variables(const spot::state*) const
|
||||||
|
{
|
||||||
|
return bddtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // anonymous
|
||||||
|
|
||||||
|
// nips_interface
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
nips_interface::nips_interface(bdd_dict* dict,
|
||||||
|
const std::string& filename)
|
||||||
|
: dict_(dict)
|
||||||
|
{
|
||||||
|
bytecode_ = bytecode_load_from_file(filename.c_str(), 0);
|
||||||
|
|
||||||
|
if (bytecode_ == 0)
|
||||||
|
throw nips_exception("bytecode_load_from_file()");
|
||||||
|
|
||||||
|
int res = nipsvm_init(&nipsvm_, bytecode_, successor_state_callback,
|
||||||
|
search_error_callback);
|
||||||
|
|
||||||
|
if (res != 0)
|
||||||
|
throw nips_exception("nipsvm_init()", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
nips_interface::~nips_interface()
|
||||||
|
{
|
||||||
|
nipsvm_finalize(&nipsvm_);
|
||||||
|
bytecode_unload(bytecode_);
|
||||||
|
}
|
||||||
|
|
||||||
|
tgba* nips_interface::automaton()
|
||||||
|
{
|
||||||
|
return new tgba_nips(dict_, &nipsvm_);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
iface/nips/nips.hh
Normal file
65
iface/nips/nips.hh
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Copyright (C) 2008 Laboratoire d'Informatique de Paris 6 (LIP6),
|
||||||
|
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
|
||||||
|
// et Marie Curie.
|
||||||
|
//
|
||||||
|
// This file is part of Spot, a model checking library.
|
||||||
|
//
|
||||||
|
// Spot is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation; either version 2 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Spot is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||||
|
// License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Spot; see the file COPYING. If not, write to the Free
|
||||||
|
// Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
// 02111-1307, USA.
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SPOT_IFACE_NIPS_NIPS_HH
|
||||||
|
# define SPOT_IFACE_NIPS_NIPS_HH
|
||||||
|
|
||||||
|
// Do not include nipsvm.h here, or it will polute the user's
|
||||||
|
// namespace with internal C symbols.
|
||||||
|
|
||||||
|
# include <string>
|
||||||
|
# include "tgba/tgba.hh"
|
||||||
|
# include "common.hh"
|
||||||
|
|
||||||
|
// Damn, nipsvm.h is include, to fix.
|
||||||
|
# include "nipsvm.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace spot
|
||||||
|
{
|
||||||
|
|
||||||
|
/// \brief An interface to provide a PROMELA front-end.
|
||||||
|
///
|
||||||
|
/// This interface let to use a Promela model as a Büchi automata.
|
||||||
|
/// It uses the NIPS library, which provied a virtual machine for
|
||||||
|
/// the state-space exploration of a Promela model, therefore, models
|
||||||
|
/// must be compiled with the NIPS compiler
|
||||||
|
/// (http://wwwhome.cs.utwente.nl/~michaelw/nips/).
|
||||||
|
///
|
||||||
|
/// With this interface, properties to check aren't defined with the Spot LTL
|
||||||
|
/// representation, but in defining correctness claims (a monitor) in the
|
||||||
|
/// Promela model (see chapter 4, The Spin Model Checker: Primer and
|
||||||
|
/// reference manual, Gerard J.Holzmann).
|
||||||
|
class nips_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nips_interface(bdd_dict* dict, const std::string& filename);
|
||||||
|
~nips_interface();
|
||||||
|
tgba* automaton();
|
||||||
|
private:
|
||||||
|
bdd_dict* dict_;
|
||||||
|
nipsvm_t nipsvm_;
|
||||||
|
nipsvm_bytecode_t* bytecode_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SPOT_IFACE_NIPS_NIPS_HH
|
||||||
43
iface/nips/nips_vm/BUGS
Normal file
43
iface/nips/nips_vm/BUGS
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
REPORTING BUGS
|
||||||
|
==============
|
||||||
|
|
||||||
|
Please report any bugs encountered to
|
||||||
|
|
||||||
|
Michael.Weber@cwi.nl
|
||||||
|
|
||||||
|
|
||||||
|
Please include enough information in a bug report that someone reading
|
||||||
|
it can reproduce the problem.
|
||||||
|
|
||||||
|
|
||||||
|
KNOWN ISSUES
|
||||||
|
============
|
||||||
|
|
||||||
|
[The gaps in the number sequence belong to old bug descriptions which
|
||||||
|
have gone away.]
|
||||||
|
|
||||||
|
#1:
|
||||||
|
The VM is relatively slow on Intel Xeon CPUs (compared to AMD64).
|
||||||
|
Probable reasons:
|
||||||
|
* Cache effects; Xeon has only 512kB cache
|
||||||
|
* Pipeline stalls; Xeon has a very deep pipeline, such that
|
||||||
|
mispredicted branches are very expensive. The inner loop of the
|
||||||
|
VM does a lot of unpredictable branching...
|
||||||
|
|
||||||
|
#2: 2006-02-22
|
||||||
|
Processes do not die in stack order. No idea why this is needed at
|
||||||
|
all.
|
||||||
|
|
||||||
|
Also, if within the last step(sic!) a process-local variable is set
|
||||||
|
and then the process dies, the never claim might not see it. This
|
||||||
|
is a more serious issue. Ways around it: put "l: goto l;" at the
|
||||||
|
end of such a process.
|
||||||
|
|
||||||
|
http://spinroot.com/spin/Man/_pid.html:
|
||||||
|
"Process instantiation numbers begin at zero for the first process
|
||||||
|
created and count up for every new process added.
|
||||||
|
[...]
|
||||||
|
When a process terminates, it can only die and make its _pid number
|
||||||
|
available for the creation of another process, if and when it has
|
||||||
|
the highest _pid number in the system. This means that processes can
|
||||||
|
only die in the reverse order of their creation (in stack order)."
|
||||||
674
iface/nips/nips_vm/COPYING
Normal file
674
iface/nips/nips_vm/COPYING
Normal file
|
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
231
iface/nips/nips_vm/ChangeLog
Normal file
231
iface/nips/nips_vm/ChangeLog
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
2007-03-27 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* Released version 1.2.7
|
||||||
|
|
||||||
|
2007-03-26 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* nipsvm.c (simple_error_cb): added, fixes segfault in
|
||||||
|
error callback which received the wrong context;
|
||||||
|
reported by <timo.lindfors@iki.fi>
|
||||||
|
|
||||||
|
2007-03-10 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* Released version 1.2.6
|
||||||
|
|
||||||
|
* search.c (search): silenced warning on MacOS X
|
||||||
|
|
||||||
|
* instr_step.c (instr_succ): code cleanup:
|
||||||
|
p_monitor
|
||||||
|
|
||||||
|
* Makefile (LDFLAGS_LIB): MacOS X support
|
||||||
|
|
||||||
|
2006-07-06 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* nips_disasm.pl: emit !modflags only of non-empty
|
||||||
|
|
||||||
|
* nips_asm.pl: if set, use NIPS_HOME to locate *.pl files
|
||||||
|
|
||||||
|
2006-06-27 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* main.c: adjusted version
|
||||||
|
* search.c: initialize n_atomic_steps to zero (lost in last commit)
|
||||||
|
|
||||||
|
2006-06-06 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* Released version 1.2.5
|
||||||
|
|
||||||
|
* search.c: count and print number of atomic steps.
|
||||||
|
|
||||||
|
2006-05-19 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* nipsvm.c (nipsvm_default_error_cb): removed extra comment
|
||||||
|
|
||||||
|
* tests/spin/pftp: commented out unused variable
|
||||||
|
|
||||||
|
* bytecode.h, bytecode.c (bytecode_str_inf): added interface to
|
||||||
|
query structure information.
|
||||||
|
TODO: use binary search to find record.
|
||||||
|
TODO: adapt interface for bytecode_src_loc
|
||||||
|
|
||||||
|
2006-03-14 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* instr.c (instr_load_special_timeout): renamed to instr_lds_timeout
|
||||||
|
(instr_load_special_pid): renamed to instr_lds_pid
|
||||||
|
(instr_load_special_nrpr): renamed to instr_lds_nrpr
|
||||||
|
(instr_load_special_last): renamed to instr_lds_last
|
||||||
|
(instr_load_special_np): renamed to instr_lds_np
|
||||||
|
(instr_lrun): fixed storage size bug
|
||||||
|
(instr_run_intern): fixed storage size bug
|
||||||
|
|
||||||
|
2006-03-13 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* Makefile (MACHINE): set MACHINE if compiler target
|
||||||
|
architecture cannot be worked out from ``gcc -dumpmachine'', e.g.
|
||||||
|
``make MACHINE=x86_64-linux''
|
||||||
|
(CFLAGS): use -m64 for x86_64
|
||||||
|
(CFLAGS_LIB): use -fPIC by default on x86, except for win32
|
||||||
|
|
||||||
|
2006-03-11 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* state.c (channel_to_str): more unsignedness fixes
|
||||||
|
* instr.c (instr_chnew): more unsignedness fixes
|
||||||
|
* hashtab.c (hashtab_get_pos): more unsignedness fixes
|
||||||
|
|
||||||
|
* Makefile: changed way to detect mingw32 compiler to make it work
|
||||||
|
with ming32 cross compiler, use -DSMALLSTACK by default in windows
|
||||||
|
(TARGET): set TARGET to cross compile, e.g.:
|
||||||
|
``make TARGET=i586-mingw32msvc all''
|
||||||
|
* search.c: use #ifdef WIN32 ... #endif for windows specific
|
||||||
|
sections
|
||||||
|
* timeval.h: shift platform specifics here, just include if needed
|
||||||
|
* instr_step.c: conditionalize on SMALLSTACK
|
||||||
|
|
||||||
|
2006-03-09 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* hashtab.c (hashtab_hash): fixed signedness oversight
|
||||||
|
|
||||||
|
2006-02-23 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* BUGS: Added Bug#2.
|
||||||
|
|
||||||
|
* instr_step.c (instr_succ): extension of finite paths only if
|
||||||
|
monitor is present.
|
||||||
|
|
||||||
|
* state_inline.h (global_state_compare): add type cast so that
|
||||||
|
C++ compilers don't choke. Note, that this function is
|
||||||
|
deprecated, still.
|
||||||
|
|
||||||
|
* nipsvm.h: comment cosmetics
|
||||||
|
|
||||||
|
2006-02-17 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* nips_disasm.pl: very simple bytecode-to-C stub generator.
|
||||||
|
The generated function must be inserted manually into the VM
|
||||||
|
currently. Also, giving such a specialized VM a different
|
||||||
|
bytecode file than was used for generating the C stub results
|
||||||
|
in hilarious behavior. Not recommended.
|
||||||
|
|
||||||
|
Speedup: yes, but not very large. Much is eaten by complicated
|
||||||
|
PC handling. Possible optimizations: move instruction decoding
|
||||||
|
out of execution loop (requires quite some surgery)
|
||||||
|
|
||||||
|
* nips_asm_instr.pl (get_instructions): tag instructions whether
|
||||||
|
they change control-flow or yield errors.
|
||||||
|
(instruction_cfun): bytecode to C-function name mapping
|
||||||
|
|
||||||
|
* instr.c (instr_ldc): renamed from instr_load_constant to match
|
||||||
|
functions names generated by disassembler script
|
||||||
|
(instr_trunc): renamed from instr_truncate
|
||||||
|
(instr_exec): replaced occurrences of renamed functions
|
||||||
|
|
||||||
|
2006-02-15 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* nips_asm.pl: collate flags for the same address instead of
|
||||||
|
emitting them individually. Happens, if the compiler generates
|
||||||
|
several labels for the same code address each of which has flags
|
||||||
|
set. I am not sure that was a real problem for the current VM
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
2006-02-11 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* state.c (global_state_to_str): output flags (accepting,
|
||||||
|
terminated) if monitor is present
|
||||||
|
|
||||||
|
2006-02-06 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* search.c (search_succ_cb): fixed type of succ_sz (size_t)
|
||||||
|
|
||||||
|
* state.c (global_state_to_str): fixed format arg mismatch for
|
||||||
|
64-bit systems.
|
||||||
|
|
||||||
|
2006-02-03 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* Released version 1.2.3
|
||||||
|
|
||||||
|
2006-02-02 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* search.c (t_search_context, search, search_succ_cb): count
|
||||||
|
transitions
|
||||||
|
|
||||||
|
* nipsvm.h (nipsvm_state_monitor_accepting)
|
||||||
|
(nipsvm_state_monitor_terminated)
|
||||||
|
(nipsvm_state_monitor_acc_or_term): added
|
||||||
|
|
||||||
|
* state.c, state.h (global_state_monitor_accepting)
|
||||||
|
(global_state_monitor_terminated)
|
||||||
|
(global_state_monitor_acc_or_term): deprecated
|
||||||
|
|
||||||
|
2006-02-01 Michael Weber <michaelw@foldr.org>
|
||||||
|
|
||||||
|
* hashtab.c: faster hash collision resolution using (very simple)
|
||||||
|
double hashing, speeding up almost-filled hash table insertions.
|
||||||
|
I measured a speedup of 1.35 when filling hash table to 93%.
|
||||||
|
|
||||||
|
API CHANGES AHEAD
|
||||||
|
|
||||||
|
Old API functions are still there, but will be be phased out
|
||||||
|
eventually.
|
||||||
|
|
||||||
|
* nipsvm.c, nipsvm.h : beginnings of a new interface: nipsvm_*
|
||||||
|
equivalents of the most used global_* methods
|
||||||
|
|
||||||
|
* simpler and less fragile callback interface, all extra
|
||||||
|
information is stashed away in
|
||||||
|
nipsvm_transition_information_t (can be extended without visibly
|
||||||
|
changing the API)
|
||||||
|
|
||||||
|
* converted some of the internals to the new API (work in
|
||||||
|
progress)
|
||||||
|
|
||||||
|
* some state handling functions have grown an extra size_t
|
||||||
|
argument, instead of calculating the state size themselves
|
||||||
|
|
||||||
|
* search.c (search): added initial state to hash table to
|
||||||
|
eliminate off-by-one difference between visited states and
|
||||||
|
states in table
|
||||||
|
|
||||||
|
* Makefile: added -g option by default, removed rt_err.o from
|
||||||
|
libnips_vm (not needed)
|
||||||
|
|
||||||
|
|
||||||
|
2005-10-11, 2005-10-12
|
||||||
|
----------------------
|
||||||
|
added range errors in assembler
|
||||||
|
changed maximum size of global variables to 65535
|
||||||
|
- access to global variables 256..65535 not possible using LDVA / STVA
|
||||||
|
use LDC <address> ; LDV / STV instead
|
||||||
|
added instructions
|
||||||
|
- GLOBSZX <size of global variables (0..65535)>
|
||||||
|
set size of global variables using 2 byte constant
|
||||||
|
- LDB [L|G]
|
||||||
|
load bit from local / global memory
|
||||||
|
stack:<addr>:<bit> ---> stack:<value>
|
||||||
|
only last 3 bits of <bit> are used
|
||||||
|
- STB [L|G]
|
||||||
|
store bit into local / global memory
|
||||||
|
stack:<value>:<addr>:<bit> ---> stack
|
||||||
|
<value> must be 0 or 1 (other values are treated as 1)
|
||||||
|
- LDV / STV [L|G] [2u|2s|4] LE
|
||||||
|
load / store variable in little endian format
|
||||||
|
works as version without LE at end (but in little endian format)
|
||||||
|
- BGET /BSET r_i, b for bit access to registers
|
||||||
|
behaviour is as FGET b / FSET b (but for r_i instead of r_F)
|
||||||
|
|
||||||
|
1.2.2 2005-09-30
|
||||||
|
----------------
|
||||||
|
tried to fix unalign errors on alpha
|
||||||
|
tried to fix left unalign errors on alpha
|
||||||
|
fixed byte order bug in LVAR instructions (remote ref)
|
||||||
|
added global_state_initial_size
|
||||||
|
added string output of states
|
||||||
|
|
||||||
|
1.2.1 2005-09-21
|
||||||
|
----------------
|
||||||
|
now forcing cycle in case of blocking system
|
||||||
|
- needed in most LTL model checkers to recognize
|
||||||
|
invalid states in which system blocks
|
||||||
|
- added INSTR_SUCC_CB_FLAG_SYS_BLOCK flag (successor callback)
|
||||||
|
|
||||||
|
1.2 2005-09-06
|
||||||
|
--------------
|
||||||
|
first public release
|
||||||
237
iface/nips/nips_vm/INSTALL
Normal file
237
iface/nips/nips_vm/INSTALL
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
Installation Instructions
|
||||||
|
*************************
|
||||||
|
|
||||||
|
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||||
|
2006, 2007 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free documentation; the Free Software Foundation gives
|
||||||
|
unlimited permission to copy, distribute and modify it.
|
||||||
|
|
||||||
|
Basic Installation
|
||||||
|
==================
|
||||||
|
|
||||||
|
Briefly, the shell commands `./configure; make; make install' should
|
||||||
|
configure, build, and install this package. The following
|
||||||
|
more-detailed instructions are generic; see the `README' file for
|
||||||
|
instructions specific to this package.
|
||||||
|
|
||||||
|
The `configure' shell script attempts to guess correct values for
|
||||||
|
various system-dependent variables used during compilation. It uses
|
||||||
|
those values to create a `Makefile' in each directory of the package.
|
||||||
|
It may also create one or more `.h' files containing system-dependent
|
||||||
|
definitions. Finally, it creates a shell script `config.status' that
|
||||||
|
you can run in the future to recreate the current configuration, and a
|
||||||
|
file `config.log' containing compiler output (useful mainly for
|
||||||
|
debugging `configure').
|
||||||
|
|
||||||
|
It can also use an optional file (typically called `config.cache'
|
||||||
|
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||||
|
the results of its tests to speed up reconfiguring. Caching is
|
||||||
|
disabled by default to prevent problems with accidental use of stale
|
||||||
|
cache files.
|
||||||
|
|
||||||
|
If you need to do unusual things to compile the package, please try
|
||||||
|
to figure out how `configure' could check whether to do them, and mail
|
||||||
|
diffs or instructions to the address given in the `README' so they can
|
||||||
|
be considered for the next release. If you are using the cache, and at
|
||||||
|
some point `config.cache' contains results you don't want to keep, you
|
||||||
|
may remove or edit it.
|
||||||
|
|
||||||
|
The file `configure.ac' (or `configure.in') is used to create
|
||||||
|
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||||
|
you want to change it or regenerate `configure' using a newer version
|
||||||
|
of `autoconf'.
|
||||||
|
|
||||||
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
|
1. `cd' to the directory containing the package's source code and type
|
||||||
|
`./configure' to configure the package for your system.
|
||||||
|
|
||||||
|
Running `configure' might take a while. While running, it prints
|
||||||
|
some messages telling which features it is checking for.
|
||||||
|
|
||||||
|
2. Type `make' to compile the package.
|
||||||
|
|
||||||
|
3. Optionally, type `make check' to run any self-tests that come with
|
||||||
|
the package.
|
||||||
|
|
||||||
|
4. Type `make install' to install the programs and any data files and
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
5. You can remove the program binaries and object files from the
|
||||||
|
source code directory by typing `make clean'. To also remove the
|
||||||
|
files that `configure' created (so you can compile the package for
|
||||||
|
a different kind of computer), type `make distclean'. There is
|
||||||
|
also a `make maintainer-clean' target, but that is intended mainly
|
||||||
|
for the package's developers. If you use it, you may have to get
|
||||||
|
all sorts of other programs in order to regenerate files that came
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
6. Often, you can also type `make uninstall' to remove the installed
|
||||||
|
files again.
|
||||||
|
|
||||||
|
Compilers and Options
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Some systems require unusual options for compilation or linking that the
|
||||||
|
`configure' script does not know about. Run `./configure --help' for
|
||||||
|
details on some of the pertinent environment variables.
|
||||||
|
|
||||||
|
You can give `configure' initial values for configuration parameters
|
||||||
|
by setting variables in the command line or in the environment. Here
|
||||||
|
is an example:
|
||||||
|
|
||||||
|
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||||
|
|
||||||
|
*Note Defining Variables::, for more details.
|
||||||
|
|
||||||
|
Compiling For Multiple Architectures
|
||||||
|
====================================
|
||||||
|
|
||||||
|
You can compile the package for more than one kind of computer at the
|
||||||
|
same time, by placing the object files for each architecture in their
|
||||||
|
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||||
|
directory where you want the object files and executables to go and run
|
||||||
|
the `configure' script. `configure' automatically checks for the
|
||||||
|
source code in the directory that `configure' is in and in `..'.
|
||||||
|
|
||||||
|
With a non-GNU `make', it is safer to compile the package for one
|
||||||
|
architecture at a time in the source code directory. After you have
|
||||||
|
installed the package for one architecture, use `make distclean' before
|
||||||
|
reconfiguring for another architecture.
|
||||||
|
|
||||||
|
Installation Names
|
||||||
|
==================
|
||||||
|
|
||||||
|
By default, `make install' installs the package's commands under
|
||||||
|
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||||
|
can specify an installation prefix other than `/usr/local' by giving
|
||||||
|
`configure' the option `--prefix=PREFIX'.
|
||||||
|
|
||||||
|
You can specify separate installation prefixes for
|
||||||
|
architecture-specific files and architecture-independent files. If you
|
||||||
|
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||||
|
PREFIX as the prefix for installing programs and libraries.
|
||||||
|
Documentation and other data files still use the regular prefix.
|
||||||
|
|
||||||
|
In addition, if you use an unusual directory layout you can give
|
||||||
|
options like `--bindir=DIR' to specify different values for particular
|
||||||
|
kinds of files. Run `configure --help' for a list of the directories
|
||||||
|
you can set and what kinds of files go in them.
|
||||||
|
|
||||||
|
If the package supports it, you can cause programs to be installed
|
||||||
|
with an extra prefix or suffix on their names by giving `configure' the
|
||||||
|
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||||
|
|
||||||
|
Optional Features
|
||||||
|
=================
|
||||||
|
|
||||||
|
Some packages pay attention to `--enable-FEATURE' options to
|
||||||
|
`configure', where FEATURE indicates an optional part of the package.
|
||||||
|
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||||
|
is something like `gnu-as' or `x' (for the X Window System). The
|
||||||
|
`README' should mention any `--enable-' and `--with-' options that the
|
||||||
|
package recognizes.
|
||||||
|
|
||||||
|
For packages that use the X Window System, `configure' can usually
|
||||||
|
find the X include and library files automatically, but if it doesn't,
|
||||||
|
you can use the `configure' options `--x-includes=DIR' and
|
||||||
|
`--x-libraries=DIR' to specify their locations.
|
||||||
|
|
||||||
|
Specifying the System Type
|
||||||
|
==========================
|
||||||
|
|
||||||
|
There may be some features `configure' cannot figure out automatically,
|
||||||
|
but needs to determine by the type of machine the package will run on.
|
||||||
|
Usually, assuming the package is built to be run on the _same_
|
||||||
|
architectures, `configure' can figure that out, but if it prints a
|
||||||
|
message saying it cannot guess the machine type, give it the
|
||||||
|
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||||
|
type, such as `sun4', or a canonical name which has the form:
|
||||||
|
|
||||||
|
CPU-COMPANY-SYSTEM
|
||||||
|
|
||||||
|
where SYSTEM can have one of these forms:
|
||||||
|
|
||||||
|
OS KERNEL-OS
|
||||||
|
|
||||||
|
See the file `config.sub' for the possible values of each field. If
|
||||||
|
`config.sub' isn't included in this package, then this package doesn't
|
||||||
|
need to know the machine type.
|
||||||
|
|
||||||
|
If you are _building_ compiler tools for cross-compiling, you should
|
||||||
|
use the option `--target=TYPE' to select the type of system they will
|
||||||
|
produce code for.
|
||||||
|
|
||||||
|
If you want to _use_ a cross compiler, that generates code for a
|
||||||
|
platform different from the build platform, you should specify the
|
||||||
|
"host" platform (i.e., that on which the generated programs will
|
||||||
|
eventually be run) with `--host=TYPE'.
|
||||||
|
|
||||||
|
Sharing Defaults
|
||||||
|
================
|
||||||
|
|
||||||
|
If you want to set default values for `configure' scripts to share, you
|
||||||
|
can create a site shell script called `config.site' that gives default
|
||||||
|
values for variables like `CC', `cache_file', and `prefix'.
|
||||||
|
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||||
|
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||||
|
`CONFIG_SITE' environment variable to the location of the site script.
|
||||||
|
A warning: not all `configure' scripts look for a site script.
|
||||||
|
|
||||||
|
Defining Variables
|
||||||
|
==================
|
||||||
|
|
||||||
|
Variables not defined in a site shell script can be set in the
|
||||||
|
environment passed to `configure'. However, some packages may run
|
||||||
|
configure again during the build, and the customized values of these
|
||||||
|
variables may be lost. In order to avoid this problem, you should set
|
||||||
|
them in the `configure' command line, using `VAR=value'. For example:
|
||||||
|
|
||||||
|
./configure CC=/usr/local2/bin/gcc
|
||||||
|
|
||||||
|
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||||
|
overridden in the site shell script).
|
||||||
|
|
||||||
|
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||||
|
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||||
|
|
||||||
|
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||||
|
|
||||||
|
`configure' Invocation
|
||||||
|
======================
|
||||||
|
|
||||||
|
`configure' recognizes the following options to control how it operates.
|
||||||
|
|
||||||
|
`--help'
|
||||||
|
`-h'
|
||||||
|
Print a summary of the options to `configure', and exit.
|
||||||
|
|
||||||
|
`--version'
|
||||||
|
`-V'
|
||||||
|
Print the version of Autoconf used to generate the `configure'
|
||||||
|
script, and exit.
|
||||||
|
|
||||||
|
`--cache-file=FILE'
|
||||||
|
Enable the cache: use and save the results of the tests in FILE,
|
||||||
|
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||||
|
disable caching.
|
||||||
|
|
||||||
|
`--config-cache'
|
||||||
|
`-C'
|
||||||
|
Alias for `--cache-file=config.cache'.
|
||||||
|
|
||||||
|
`--quiet'
|
||||||
|
`--silent'
|
||||||
|
`-q'
|
||||||
|
Do not print messages saying which checks are being made. To
|
||||||
|
suppress all normal output, redirect it to `/dev/null' (any error
|
||||||
|
messages will still be shown).
|
||||||
|
|
||||||
|
`--srcdir=DIR'
|
||||||
|
Look for the package's source code in directory DIR. Usually
|
||||||
|
`configure' can determine that directory automatically.
|
||||||
|
|
||||||
|
`configure' also accepts some other, not widely useful, options. Run
|
||||||
|
`configure --help' for more details.
|
||||||
|
|
||||||
41
iface/nips/nips_vm/Makefile.am
Normal file
41
iface/nips/nips_vm/Makefile.am
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
nipsvmdir = $(srcdir)
|
||||||
|
|
||||||
|
nipsvm_HEADERS = \
|
||||||
|
bytecode.h \
|
||||||
|
hashtab.h \
|
||||||
|
instr.h \
|
||||||
|
instr_step.h \
|
||||||
|
instr_tools.h \
|
||||||
|
instr_wrap.h \
|
||||||
|
interactive.h \
|
||||||
|
nipsvm.h \
|
||||||
|
rt_err.h \
|
||||||
|
search.h \
|
||||||
|
split.h \
|
||||||
|
state.h \
|
||||||
|
state_inline.h \
|
||||||
|
state_parts.h \
|
||||||
|
timeval.h \
|
||||||
|
tools.h
|
||||||
|
|
||||||
|
lib_LTLIBRARIES = libnipsvm.la
|
||||||
|
|
||||||
|
libnipsvm_la_SOURCES = \
|
||||||
|
bytecode.c \
|
||||||
|
hashtab.c \
|
||||||
|
instr.c \
|
||||||
|
instr_step.c \
|
||||||
|
instr_tools.c \
|
||||||
|
instr_wrap.c \
|
||||||
|
interactive.c \
|
||||||
|
nipsvm.c \
|
||||||
|
rt_err.c \
|
||||||
|
search.c \
|
||||||
|
split.c \
|
||||||
|
state.c \
|
||||||
|
state_parts.c
|
||||||
|
|
||||||
|
noinst_PROGRAMS = nipsvm
|
||||||
|
|
||||||
|
nipsvm_SOURCES = main.c
|
||||||
|
nipsvm_LDADD = libnipsvm.la
|
||||||
75
iface/nips/nips_vm/README
Normal file
75
iface/nips/nips_vm/README
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
|
||||||
|
very short description
|
||||||
|
======================
|
||||||
|
|
||||||
|
NIPS VM is a non-deterministic virtual machine
|
||||||
|
to be used for state space generation in model checkers.
|
||||||
|
|
||||||
|
For more information, see:
|
||||||
|
Stefan Schuermans, Ein Compiler und eine Virtuelle Maschine
|
||||||
|
zur Zustandsraumgenerierung, Dimplomarbeit, Lehrstuhl II fuer
|
||||||
|
Informatik RWTH Aachen, Oktober 2005
|
||||||
|
(available only in German)
|
||||||
|
|
||||||
|
For a description of the assembler and bytecode format, see:
|
||||||
|
assembler_format.txt
|
||||||
|
bytecode_format.txt
|
||||||
|
|
||||||
|
|
||||||
|
dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
GNU make 3.80
|
||||||
|
GNU C Compiler: gcc 3.3
|
||||||
|
C runtime library: libc 2.3 (at least libc 2.1)
|
||||||
|
perl 5.8.4
|
||||||
|
(NIPS C 1.2+)
|
||||||
|
|
||||||
|
versions given are known to work - other may work, too
|
||||||
|
|
||||||
|
getting started
|
||||||
|
===============
|
||||||
|
|
||||||
|
compilation
|
||||||
|
-----------
|
||||||
|
make
|
||||||
|
|
||||||
|
running an example
|
||||||
|
------------------
|
||||||
|
cd tests
|
||||||
|
make
|
||||||
|
make example
|
||||||
|
|
||||||
|
running some tests
|
||||||
|
------------------
|
||||||
|
make benchmark
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
assembling own files
|
||||||
|
--------------------
|
||||||
|
./nips_asm.pl mycode.s
|
||||||
|
|
||||||
|
running interactive / random simulations
|
||||||
|
----------------------------------------
|
||||||
|
./nips_vm [-R] mycode.b
|
||||||
|
|
||||||
|
generating full state space with breadth first / depth first search
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
./nips_vm {-B|-D 30} mycode.b
|
||||||
|
|
||||||
|
other features
|
||||||
|
--------------
|
||||||
|
./nips_vm --help
|
||||||
|
|
||||||
|
benchmarking against SPIN
|
||||||
|
-------------------------
|
||||||
|
# ensure that NIPS C is installed in ../nips_c/
|
||||||
|
cd tests/spin
|
||||||
|
./Benchmark
|
||||||
|
|
||||||
12
iface/nips/nips_vm/added_instructions.txt
Normal file
12
iface/nips/nips_vm/added_instructions.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
KILL
|
||||||
|
----
|
||||||
|
set process <pid> to terminated
|
||||||
|
stack before: [...] <pid>
|
||||||
|
stack after: [...]
|
||||||
|
|
||||||
|
POPX
|
||||||
|
----
|
||||||
|
discard topmost value from stack
|
||||||
|
stack before: [...] <value>
|
||||||
|
stack after: [...]
|
||||||
|
|
||||||
91
iface/nips/nips_vm/assembler_format.txt
Normal file
91
iface/nips/nips_vm/assembler_format.txt
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
NIPS - New Implementation of Promela Semantics
|
||||||
|
Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
specification of the assembler file format
|
||||||
|
|
||||||
|
|
||||||
|
The entire format is line based. A line can contain a label, an instruction,
|
||||||
|
a label and an instruction or a directive. An additional comment separated by
|
||||||
|
";" is allowed at the end of every line.
|
||||||
|
|
||||||
|
|
||||||
|
begin of new module
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
"!module" <name>
|
||||||
|
|
||||||
|
with <name> being enclosed in "
|
||||||
|
|
||||||
|
|
||||||
|
instruction lines
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
3 formats are allowed
|
||||||
|
|
||||||
|
<label>:
|
||||||
|
|
||||||
|
<instruction> <parameter 1> ... <parameter n>
|
||||||
|
|
||||||
|
<label>: <instruction> <parameter 1> ... <parameter n>
|
||||||
|
|
||||||
|
with <label> = "[A-Za-z][A-Za-Z0-9_]*"
|
||||||
|
|
||||||
|
For a list of instructions with their parameters, see "nips_asm_instr.pl".
|
||||||
|
The parameters may be fixed text or be of one of the following types:
|
||||||
|
|
||||||
|
!const?: a constant value, i.e. a number
|
||||||
|
!reg: some register "r0" ... "r7"
|
||||||
|
!addr: a relative address, i.e. a label name
|
||||||
|
!address: an absolute address, i.e. a label name
|
||||||
|
|
||||||
|
|
||||||
|
flags (of bytecode addresses)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
"!flags" "progress"? "accept"?
|
||||||
|
|
||||||
|
"!flags_addr" <address> "progress"? "accept"?
|
||||||
|
|
||||||
|
with <address> of format "0x[0-9A-Fa-f]+"
|
||||||
|
|
||||||
|
marks the current / the specified address with the specified flags
|
||||||
|
|
||||||
|
|
||||||
|
string (for the string table)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
"!string" <index> <text>
|
||||||
|
|
||||||
|
<index> is used in the PRINT* commands.
|
||||||
|
<text> must be enclosed in ".
|
||||||
|
|
||||||
|
source location information
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
"!srcloc" <line> <column>
|
||||||
|
|
||||||
|
"!srcloc_addr" <address> <line> <column>
|
||||||
|
|
||||||
|
with <address> of format "0x[0-9A-Fa-f]+"
|
||||||
|
with <line> and <column> being numbers
|
||||||
|
|
||||||
|
specifies the location in the source code
|
||||||
|
corresponding to the current / the specified address
|
||||||
|
|
||||||
|
|
||||||
|
structure information
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
"!strinf" "(begin|end)" <type> <name>?
|
||||||
|
|
||||||
|
"!strinf_addr" <address> "(begin|end)" <type> <name>?
|
||||||
|
|
||||||
|
with <address> of format "0x[0-9A-Fa-f]+"
|
||||||
|
with <type> and <name> of format "[A-Za-z]+"
|
||||||
|
|
||||||
|
specifies the begin / end of some structure of <type> in the source code
|
||||||
|
at the current / the specified address
|
||||||
|
|
||||||
610
iface/nips/nips_vm/bytecode.c
Normal file
610
iface/nips/nips_vm/bytecode.c
Normal file
|
|
@ -0,0 +1,610 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef EPROTO
|
||||||
|
# define E_BC_INV_FMT EPROTO
|
||||||
|
#else
|
||||||
|
# define E_BC_INV_FMT EINVAL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file - check module name
|
||||||
|
// returns -1 of error, 0 if not equal, 1 if equal
|
||||||
|
static int bytecode_load_from_file_check_module( FILE *file, const char *module )
|
||||||
|
{
|
||||||
|
// read size of module name
|
||||||
|
uint16_t mod_name_sz;
|
||||||
|
if( fread( &mod_name_sz, 1, sizeof( mod_name_sz ), file ) != sizeof( mod_name_sz ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mod_name_sz = be2h_16( mod_name_sz );
|
||||||
|
if( mod_name_sz == 0 )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read module name
|
||||||
|
char mod_name[mod_name_sz];
|
||||||
|
if( fread( mod_name, 1, mod_name_sz, file ) != mod_name_sz )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
mod_name[mod_name_sz - 1] = 0; // terminate string (should already be terminated there)
|
||||||
|
|
||||||
|
// compare module name (NULL matches any name)
|
||||||
|
return module == NULL || strcmp( mod_name, module ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file - read a string
|
||||||
|
static char * bytecode_load_from_file_string( FILE *file )
|
||||||
|
{
|
||||||
|
// read size of string
|
||||||
|
uint16_t str_sz;
|
||||||
|
if( fread( &str_sz, 1, sizeof( str_sz ), file ) != sizeof( str_sz ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
str_sz = be2h_16( str_sz );
|
||||||
|
if( str_sz == 0 )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate memory
|
||||||
|
char *str = (char *)malloc( str_sz );
|
||||||
|
if( str == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read string
|
||||||
|
if( fread( str, 1, str_sz, file ) != str_sz )
|
||||||
|
{
|
||||||
|
free( str );
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
str[str_sz - 1] = 0; // terminate string (should already be terminated there)
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file - process module
|
||||||
|
static st_bytecode * bytecode_load_from_file_module( FILE *file )
|
||||||
|
{
|
||||||
|
// read number of parts
|
||||||
|
uint16_t part_cnt;
|
||||||
|
if( fread( &part_cnt, 1, sizeof( part_cnt ), file ) != sizeof( part_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
part_cnt = be2h_16( part_cnt );
|
||||||
|
|
||||||
|
// allocate structure
|
||||||
|
st_bytecode *bytecode = (st_bytecode *)malloc( sizeof( st_bytecode ) );
|
||||||
|
if( bytecode == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
// initialize structure
|
||||||
|
bytecode->modflags = 0;
|
||||||
|
bytecode->size = 0;
|
||||||
|
bytecode->ptr = NULL;
|
||||||
|
bytecode->flag_cnt = 0;
|
||||||
|
bytecode->flags = NULL;
|
||||||
|
bytecode->string_cnt = 0;
|
||||||
|
bytecode->strings = NULL;
|
||||||
|
bytecode->src_loc_cnt = 0;
|
||||||
|
bytecode->src_locs = NULL;
|
||||||
|
bytecode->str_inf_cnt = 0;
|
||||||
|
bytecode->str_infs = NULL;
|
||||||
|
|
||||||
|
uint16_t part_no;
|
||||||
|
for( part_no = 0; part_no < part_cnt; part_no++ )
|
||||||
|
{
|
||||||
|
// read part type and part size
|
||||||
|
char part_type[4];
|
||||||
|
uint32_t part_sz;
|
||||||
|
if( fread( &part_type, 1, sizeof( part_type ), file ) != sizeof( part_type ) ||
|
||||||
|
fread( &part_sz, 1, sizeof( part_sz ), file ) != sizeof( part_sz ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
part_sz = be2h_32( part_sz );
|
||||||
|
|
||||||
|
// module flags
|
||||||
|
if( memcmp( part_type, "modf", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
uint32_t modflags;
|
||||||
|
if( fread( &modflags, 1, sizeof( modflags ), file ) != sizeof( modflags ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->modflags |= be2h_32( modflags );
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytecode
|
||||||
|
else if( memcmp( part_type, "bc ", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// two bytecodes in one module are invalid
|
||||||
|
if( bytecode->ptr != NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// allocate memory
|
||||||
|
bytecode->size = part_sz;
|
||||||
|
bytecode->ptr = (uint8_t *)malloc( bytecode->size == 0 ? 1 : bytecode->size );
|
||||||
|
if( bytecode->ptr == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// read bytecode
|
||||||
|
if( fread( bytecode->ptr, 1, bytecode->size, file ) != bytecode->size )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flag table
|
||||||
|
else if( memcmp( part_type, "flag", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// two flag tables in one module are invalid
|
||||||
|
if( bytecode->flags != NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// read flag count
|
||||||
|
uint16_t flag_cnt;
|
||||||
|
if( fread( &flag_cnt, 1, sizeof( flag_cnt ), file ) != sizeof( flag_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->flag_cnt = be2h_16( flag_cnt );
|
||||||
|
// allocate memory
|
||||||
|
bytecode->flags = (st_bc_flag *)malloc( bytecode->flag_cnt == 0 ? 1 : bytecode->flag_cnt * sizeof( st_bc_flag ) );
|
||||||
|
if( bytecode->flags == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read flag entries
|
||||||
|
uint16_t i;
|
||||||
|
for( i = 0; i < bytecode->flag_cnt; i++ )
|
||||||
|
{
|
||||||
|
uint32_t addr, flags;
|
||||||
|
if( fread( &addr, 1, sizeof( addr ), file ) != sizeof( addr ) ||
|
||||||
|
fread( &flags, 1, sizeof( flags ), file ) != sizeof( flags ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->flags[i].addr = be2h_32( addr );
|
||||||
|
bytecode->flags[i].flags = be2h_32( flags );
|
||||||
|
}
|
||||||
|
if( i < bytecode->flag_cnt )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string table
|
||||||
|
else if( memcmp( part_type, "str ", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// two string tables in one module are invalid
|
||||||
|
if( bytecode->strings != NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// read string count
|
||||||
|
uint16_t string_cnt;
|
||||||
|
if( fread( &string_cnt, 1, sizeof( string_cnt ), file ) != sizeof( string_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->string_cnt = be2h_16( string_cnt );
|
||||||
|
// allocate memory
|
||||||
|
bytecode->strings = (char **)malloc( bytecode->string_cnt == 0 ? 1 : bytecode->string_cnt * sizeof( char * ) );
|
||||||
|
if( bytecode->strings == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint16_t i;
|
||||||
|
for( i = 0; i < bytecode->string_cnt; i++ )
|
||||||
|
bytecode->strings[i] = NULL;
|
||||||
|
|
||||||
|
// read strings
|
||||||
|
for( i = 0; i < bytecode->string_cnt; i++ )
|
||||||
|
{
|
||||||
|
bytecode->strings[i] = bytecode_load_from_file_string( file );
|
||||||
|
if( bytecode->strings[i] == NULL )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( i < bytecode->string_cnt )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// source location table
|
||||||
|
else if( memcmp( part_type, "sloc", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// two source location tables in one module are invalid
|
||||||
|
if( bytecode->src_locs != NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// read source location count
|
||||||
|
uint16_t src_loc_cnt;
|
||||||
|
if( fread( &src_loc_cnt, 1, sizeof( src_loc_cnt ), file ) != sizeof( src_loc_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->src_loc_cnt = be2h_16( src_loc_cnt );
|
||||||
|
// allocate memory
|
||||||
|
bytecode->src_locs = (st_src_loc *)malloc( bytecode->src_loc_cnt == 0 ? 1 : bytecode->src_loc_cnt * sizeof( st_src_loc ) );
|
||||||
|
if( bytecode->src_locs == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read source locations
|
||||||
|
uint16_t i;
|
||||||
|
for( i = 0; i < bytecode->src_loc_cnt; i++ )
|
||||||
|
{
|
||||||
|
uint32_t addr, line, col;
|
||||||
|
if( fread( &addr, 1, sizeof( addr ), file ) != sizeof( addr ) ||
|
||||||
|
fread( &line, 1, sizeof( line ), file ) != sizeof( line ) ||
|
||||||
|
fread( &col, 1, sizeof( col ), file ) != sizeof( col ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->src_locs[i].addr = be2h_32( addr );
|
||||||
|
bytecode->src_locs[i].line = be2h_32( line );
|
||||||
|
bytecode->src_locs[i].col = be2h_32( col );
|
||||||
|
}
|
||||||
|
if( i < bytecode->src_loc_cnt )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// structure information table
|
||||||
|
else if( memcmp( part_type, "stin", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// two source location tables in one module are invalid
|
||||||
|
if( bytecode->str_infs != NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read structure information count
|
||||||
|
uint16_t str_inf_cnt;
|
||||||
|
if( fread( &str_inf_cnt, 1, sizeof( str_inf_cnt ), file ) != sizeof( str_inf_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytecode->str_inf_cnt = be2h_16( str_inf_cnt );
|
||||||
|
|
||||||
|
// allocate memory
|
||||||
|
bytecode->str_infs = (st_str_inf *)malloc( bytecode->str_inf_cnt == 0 ? 1 : bytecode->str_inf_cnt * sizeof( st_str_inf ) );
|
||||||
|
if( bytecode->src_locs == NULL )
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read structure information
|
||||||
|
uint16_t i;
|
||||||
|
for( i = 0; i < bytecode->str_inf_cnt; i++ )
|
||||||
|
{
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t code;
|
||||||
|
if ( fread( &addr, 1, sizeof( addr ), file ) != sizeof( addr ) ||
|
||||||
|
fread( &code, 1, sizeof( code ), file ) != sizeof( code ))
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read type
|
||||||
|
char *type = bytecode_load_from_file_string( file );
|
||||||
|
if( type == NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read name
|
||||||
|
char *name = bytecode_load_from_file_string( file );
|
||||||
|
if( name == NULL )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytecode->str_infs[i].addr = be2h_32( addr );
|
||||||
|
bytecode->str_infs[i].code = code;
|
||||||
|
bytecode->str_infs[i].type = type;
|
||||||
|
bytecode->str_infs[i].name = name;
|
||||||
|
}
|
||||||
|
if( i < bytecode->str_inf_cnt )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown part
|
||||||
|
else
|
||||||
|
fseek( file, part_sz, SEEK_CUR );
|
||||||
|
|
||||||
|
} // for( part_no ...
|
||||||
|
|
||||||
|
// no bytecode found
|
||||||
|
if( bytecode->ptr == NULL )
|
||||||
|
{
|
||||||
|
errno = ESRCH;
|
||||||
|
// mark as error
|
||||||
|
part_no = 0;
|
||||||
|
part_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// some error occured in loop
|
||||||
|
if( part_no < part_cnt || part_cnt == 0 )
|
||||||
|
{
|
||||||
|
// cleanup and return NULL (errno is already set)
|
||||||
|
if( bytecode->ptr != NULL )
|
||||||
|
free( bytecode->ptr );
|
||||||
|
if( bytecode->flags != NULL )
|
||||||
|
free( bytecode->flags );
|
||||||
|
if( bytecode->strings != NULL )
|
||||||
|
{
|
||||||
|
uint16_t i;
|
||||||
|
for( i = 0; i < bytecode->string_cnt; i++ )
|
||||||
|
if( bytecode->strings[i] != NULL )
|
||||||
|
free( bytecode->strings[i] );
|
||||||
|
free( bytecode->strings );
|
||||||
|
}
|
||||||
|
if( bytecode->src_locs != NULL )
|
||||||
|
free( bytecode->src_locs );
|
||||||
|
free( bytecode );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytecode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file - process sections
|
||||||
|
static st_bytecode * bytecode_load_from_file_sections( FILE *file, const char *module )
|
||||||
|
{
|
||||||
|
// get number of sections in file
|
||||||
|
uint16_t sec_cnt;
|
||||||
|
if( fread( &sec_cnt, 1, sizeof( sec_cnt ), file ) != sizeof( sec_cnt ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sec_cnt = be2h_16( sec_cnt );
|
||||||
|
|
||||||
|
// read sections
|
||||||
|
uint16_t sec_no;
|
||||||
|
for( sec_no = 0; sec_no < sec_cnt; sec_no++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
// read section type and section size
|
||||||
|
char sec_type[4];
|
||||||
|
uint32_t sec_sz;
|
||||||
|
if( fread( &sec_type, 1, sizeof( sec_type ), file ) != sizeof( sec_type ) ||
|
||||||
|
fread( &sec_sz, 1, sizeof( sec_sz ), file ) != sizeof( sec_sz ) )
|
||||||
|
{
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sec_sz = be2h_32( sec_sz );
|
||||||
|
|
||||||
|
// module section
|
||||||
|
if( memcmp( sec_type, "mod ", 4 ) == 0 )
|
||||||
|
{
|
||||||
|
// remember position in file
|
||||||
|
long pos = ftell( file );
|
||||||
|
|
||||||
|
// check if module name matches
|
||||||
|
int result = bytecode_load_from_file_check_module( file, module );
|
||||||
|
if( result < 0 ) // error
|
||||||
|
return NULL;
|
||||||
|
if( result > 0 ) // module name matches
|
||||||
|
return bytecode_load_from_file_module( file );
|
||||||
|
|
||||||
|
// skip module
|
||||||
|
fseek( file, pos + sec_sz, SEEK_SET );
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown section
|
||||||
|
else
|
||||||
|
fseek( file, sec_sz, SEEK_CUR );
|
||||||
|
|
||||||
|
} // for( sec_no ...
|
||||||
|
|
||||||
|
errno = ESRCH;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file
|
||||||
|
// if module == NULL the first module is loaded
|
||||||
|
// returns NULL on error (errno ist set in this case)
|
||||||
|
st_bytecode * bytecode_load_from_file( const char *filename, const char *module ) // extern
|
||||||
|
{
|
||||||
|
// open bytecode file for reading
|
||||||
|
FILE *file = fopen( filename, "rb" );
|
||||||
|
if( file == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// magic to check at beginning of bytecode
|
||||||
|
static char bc_magic[8] = "NIPS v2 ";
|
||||||
|
|
||||||
|
// read magic
|
||||||
|
char magic[sizeof( bc_magic )];
|
||||||
|
if( fread( magic, 1, sizeof( magic ), file ) != sizeof( magic ) )
|
||||||
|
{
|
||||||
|
fclose( file );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check magic
|
||||||
|
if( memcmp( bc_magic, magic, sizeof( bc_magic ) ) != 0 )
|
||||||
|
{
|
||||||
|
fclose( file );
|
||||||
|
errno = E_BC_INV_FMT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process sections
|
||||||
|
st_bytecode *bytecode = bytecode_load_from_file_sections( file, module );
|
||||||
|
fclose( file );
|
||||||
|
return bytecode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// unload bytecode
|
||||||
|
void bytecode_unload( st_bytecode *bytecode ) // extern
|
||||||
|
{
|
||||||
|
free( bytecode->ptr );
|
||||||
|
uint16_t i;
|
||||||
|
if( bytecode->flags != NULL )
|
||||||
|
free( bytecode->flags );
|
||||||
|
if( bytecode->strings != NULL )
|
||||||
|
{
|
||||||
|
for( i = 0; i < bytecode->string_cnt; i++ )
|
||||||
|
free( bytecode->strings[i] );
|
||||||
|
free( bytecode->strings );
|
||||||
|
}
|
||||||
|
if( bytecode->src_locs != NULL )
|
||||||
|
free( bytecode->src_locs );
|
||||||
|
if (bytecode->str_infs != NULL)
|
||||||
|
free(bytecode->str_infs);
|
||||||
|
free( bytecode );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if a monitor process exists in bytecode
|
||||||
|
int bytecode_monitor_present( st_bytecode *bytecode ) // extern
|
||||||
|
{
|
||||||
|
return (bytecode->modflags & BC_MODFLAG_MONITOR) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get flags at address (e.g. program counter)
|
||||||
|
uint32_t bytecode_flags( st_bytecode *bytecode, uint32_t addr ) // extern
|
||||||
|
{
|
||||||
|
int start, end, i;
|
||||||
|
|
||||||
|
start = 0;
|
||||||
|
end = bytecode->flag_cnt - 1;
|
||||||
|
while( start <= end )
|
||||||
|
{
|
||||||
|
i = (start + end) / 2;
|
||||||
|
if( addr < bytecode->flags[i].addr )
|
||||||
|
end = i - 1;
|
||||||
|
else if( addr > bytecode->flags[i].addr )
|
||||||
|
start = i + 1;
|
||||||
|
else
|
||||||
|
return bytecode->flags[i].flags;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get source location from address (e.g. program counter)
|
||||||
|
// TODO: change to same interface as bytecode_str_inf
|
||||||
|
st_src_loc bytecode_src_loc( st_bytecode *bytecode, uint32_t addr ) // extern
|
||||||
|
{
|
||||||
|
int start, end, i;
|
||||||
|
|
||||||
|
if( bytecode->src_loc_cnt < 1 )
|
||||||
|
return (st_src_loc){ .addr = addr, .line = -1, .col = -1 };
|
||||||
|
|
||||||
|
start = 0;
|
||||||
|
end = bytecode->src_loc_cnt - 1;
|
||||||
|
for( ; ; )
|
||||||
|
{
|
||||||
|
i = (start + end) / 2;
|
||||||
|
if( addr < bytecode->src_locs[i].addr )
|
||||||
|
{
|
||||||
|
if( i - 1 < start )
|
||||||
|
return bytecode->src_locs[i > 0 ? i - 1 : 0];
|
||||||
|
end = i - 1;
|
||||||
|
}
|
||||||
|
else if( addr > bytecode->src_locs[i].addr )
|
||||||
|
{
|
||||||
|
if( i + 1 > end )
|
||||||
|
return bytecode->src_locs[end];
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return bytecode->src_locs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get structure information from address (e.g. program counter), NULL if not found
|
||||||
|
|
||||||
|
// *start denotes where to start search, and if found, is modified to
|
||||||
|
// the next valid start position. Multiple records can be retrieved like this:
|
||||||
|
// unsigned int seq = 0;
|
||||||
|
// while ((s_inf = bytecode_str_inf (bc, addr, &seq)) != NULL) {
|
||||||
|
// /* stuff with *s_inf */
|
||||||
|
// }
|
||||||
|
|
||||||
|
// ASSUMES str_infs sorted by addr field
|
||||||
|
// TODO: replace linear search with binary search
|
||||||
|
extern st_str_inf *
|
||||||
|
bytecode_str_inf( st_bytecode *bytecode, uint32_t addr, unsigned int *start)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = *start; i < bytecode->str_inf_cnt; ++i)
|
||||||
|
{
|
||||||
|
if (bytecode->str_infs[i].addr == addr) {
|
||||||
|
*start = i+1;
|
||||||
|
return &bytecode->str_infs[i];
|
||||||
|
} else if (bytecode->str_infs[i].addr > addr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
93
iface/nips/nips_vm/bytecode.h
Normal file
93
iface/nips/nips_vm/bytecode.h
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_bytecode
|
||||||
|
#define INC_bytecode
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
// module flags
|
||||||
|
#define BC_MODFLAG_MONITOR 0x00000001 // if a monitor process exists in bytecode
|
||||||
|
|
||||||
|
|
||||||
|
// type for flags at some address
|
||||||
|
#define BC_FLAG_PROGRESS 0x00000001
|
||||||
|
#define BC_FLAG_ACCEPT 0x00000002
|
||||||
|
typedef struct t_bc_flag
|
||||||
|
{
|
||||||
|
uint32_t addr, flags;
|
||||||
|
} st_bc_flag;
|
||||||
|
|
||||||
|
// type for a source location (mapping of address to line and column in source)
|
||||||
|
typedef struct t_src_loc
|
||||||
|
{
|
||||||
|
uint32_t addr, line, col;
|
||||||
|
} st_src_loc;
|
||||||
|
|
||||||
|
// type for a structure inforamtion
|
||||||
|
typedef struct t_str_inf
|
||||||
|
{
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t code;
|
||||||
|
char *type, *name;
|
||||||
|
} st_str_inf;
|
||||||
|
|
||||||
|
// type for pointer to bytecode and its size
|
||||||
|
typedef struct t_bytecode
|
||||||
|
{
|
||||||
|
uint32_t modflags; // module flags
|
||||||
|
uint32_t size; // size of bytecode
|
||||||
|
uint8_t *ptr; // pointer to bytecode
|
||||||
|
uint16_t flag_cnt; // number of flag entries in table
|
||||||
|
st_bc_flag *flags; // flag table
|
||||||
|
uint16_t string_cnt; // number of strings in string table
|
||||||
|
char **strings; // string table
|
||||||
|
uint16_t src_loc_cnt; // number of source locations in table
|
||||||
|
st_src_loc *src_locs; // source location table
|
||||||
|
uint16_t str_inf_cnt; // number of structure information in table
|
||||||
|
st_str_inf *str_infs; // structure information table
|
||||||
|
} st_bytecode;
|
||||||
|
|
||||||
|
|
||||||
|
// load bytecode module from file
|
||||||
|
// if module == NULL the first module is loaded
|
||||||
|
// returns NULL on error (errno ist set in this case)
|
||||||
|
extern st_bytecode * bytecode_load_from_file( const char *filename, const char *module );
|
||||||
|
|
||||||
|
|
||||||
|
// unload bytecode
|
||||||
|
extern void bytecode_unload( st_bytecode *bytecode );
|
||||||
|
|
||||||
|
|
||||||
|
// check if a monitor process exists in bytecode
|
||||||
|
extern int bytecode_monitor_present( st_bytecode *bytecode );
|
||||||
|
|
||||||
|
|
||||||
|
// get flags at address (e.g. program counter)
|
||||||
|
extern uint32_t bytecode_flags( st_bytecode *bytecode, uint32_t addr );
|
||||||
|
|
||||||
|
|
||||||
|
// get source location from address (e.g. program counter)
|
||||||
|
extern st_src_loc bytecode_src_loc( st_bytecode *bytecode, uint32_t addr );
|
||||||
|
|
||||||
|
// get structure information from address (e.g. program counter)
|
||||||
|
extern st_str_inf *bytecode_str_inf( st_bytecode *bytecode, uint32_t addr, unsigned int *start );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_bytecode
|
||||||
103
iface/nips/nips_vm/bytecode_format.txt
Normal file
103
iface/nips/nips_vm/bytecode_format.txt
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
NIPS - New Implementation of Promela Semantics
|
||||||
|
Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
specification of the bytecode file format
|
||||||
|
|
||||||
|
bytecode file:
|
||||||
|
<file header>
|
||||||
|
<section 0>
|
||||||
|
...
|
||||||
|
<section sec_cnt-1>
|
||||||
|
|
||||||
|
file header:
|
||||||
|
"NIPS v1a"
|
||||||
|
sec_cnt: uint16_t, big-endian, number of sections in file
|
||||||
|
|
||||||
|
section:
|
||||||
|
sec_type: 4 uint8_t, ASCII, type of section
|
||||||
|
sec_sz: uint32_t, big-endian, size of section's content
|
||||||
|
section content: sec_sz uint8_t
|
||||||
|
|
||||||
|
section: module
|
||||||
|
sec_type: "mod "
|
||||||
|
sec_sz: uint32_t, big-endian, size of module section's content
|
||||||
|
<string module_name>
|
||||||
|
part_cnt: uint16_t, big-endian, number of parts in module
|
||||||
|
<part 0>
|
||||||
|
...
|
||||||
|
<part part_cnt-1>
|
||||||
|
|
||||||
|
part
|
||||||
|
part_type: 4 uint8_t, ASCII, type of part
|
||||||
|
part_sz: uint32_t, big-endian, size of part's content
|
||||||
|
part content: part_sz uint8_t
|
||||||
|
|
||||||
|
part: module flags
|
||||||
|
part_type: "modf"
|
||||||
|
part_sz: uint32_t, big-endian, always 4
|
||||||
|
mod_flags: uint32_t, big-endian, some flags describing properties of the module
|
||||||
|
0x00000001 = monitor exists
|
||||||
|
|
||||||
|
part: bytecode
|
||||||
|
part_type: "bc "
|
||||||
|
part_sz: uint32_t, big-endian, size of bytecode
|
||||||
|
bytecode: part_sz uint8_t, the bytecode
|
||||||
|
|
||||||
|
part: flag table
|
||||||
|
part_type: "flag"
|
||||||
|
part_sz: uint32_t, big-endian, size of entire flag table
|
||||||
|
flag_cnt: uint16_t, big-endian, number of flag entries in this table
|
||||||
|
the entries in this table have to be sorted ascending by their addresses
|
||||||
|
<flag 0>
|
||||||
|
...
|
||||||
|
<flag flag_cnt-1>
|
||||||
|
|
||||||
|
flag:
|
||||||
|
addr: uint32_t, big-endian, address for which flags are given
|
||||||
|
flags: uint32_t, the flags for this address
|
||||||
|
0x00000001 = progress state
|
||||||
|
0x00000002 = accept state
|
||||||
|
|
||||||
|
part: string table
|
||||||
|
part_type: "str "
|
||||||
|
part_sz: uint32_t, big-endian, size of entire string table
|
||||||
|
str_cnt: uint16_t, big-endian, number of strings in this table
|
||||||
|
<string 0>
|
||||||
|
...
|
||||||
|
<string str_cnt-1>
|
||||||
|
|
||||||
|
string:
|
||||||
|
str_sz: uint16_t, big-endian, size of string (including terminating zero)
|
||||||
|
str: str_sz uint8_t, ASCII, zero-terminated string
|
||||||
|
|
||||||
|
part: source location table
|
||||||
|
part_type: "sloc"
|
||||||
|
part_sz: uint32_t, big-endian, size of entire source location table
|
||||||
|
sloc_cnt: uint16_t, big-endian, number of source locations in this table
|
||||||
|
the entries in this table have to be sorted ascending by their addresses
|
||||||
|
<srcloc 0>
|
||||||
|
...
|
||||||
|
<srcloc sloc_cnt-1>
|
||||||
|
|
||||||
|
srcloc:
|
||||||
|
addr: uint32_t, big-endian, address whose source location is to be specified
|
||||||
|
line: uint32_t, big-endian, line number
|
||||||
|
col: uint32_t, big-endian, column number
|
||||||
|
|
||||||
|
part: structure information table
|
||||||
|
part_type: "stin"
|
||||||
|
part_sz: uint32_t, big-endian, size of entire structure information table
|
||||||
|
stin_cnt: uint16_t, big-endian, number of structure information entries in this table
|
||||||
|
the entries in this table have to be sorted ascending by their addresses
|
||||||
|
<strinf 0>
|
||||||
|
...
|
||||||
|
<strinf stin_cnt-1>
|
||||||
|
|
||||||
|
strinf:
|
||||||
|
addr: uint32_t, big-endian, address for which some structure information is given
|
||||||
|
code: uint8_t, 0x00 = start of some structure, 0x01 = end of some structure, 0x02 = middle in some structure
|
||||||
|
<string type>
|
||||||
|
<string name>
|
||||||
322
iface/nips/nips_vm/hashtab.c
Normal file
322
iface/nips/nips_vm/hashtab.c
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
#include "hashtab.h"
|
||||||
|
|
||||||
|
#define HASH_MIN_ENTRIES 65536 // 64k entries (because of calculation of hash_rest)
|
||||||
|
|
||||||
|
// type for hash values
|
||||||
|
typedef unsigned long t_hash;
|
||||||
|
|
||||||
|
typedef st_global_state_header *t_hashtab_value;
|
||||||
|
|
||||||
|
typedef struct t_hashtab_bucket
|
||||||
|
{
|
||||||
|
t_hashtab_value value;
|
||||||
|
unsigned short hash_rest; // part of hash value that is lost in "entry = hash_value % entries"
|
||||||
|
// ---> "hash_rest = hash_value / entries"
|
||||||
|
} PACKED st_hashtab_bucket;
|
||||||
|
|
||||||
|
|
||||||
|
// hashtable pointer type
|
||||||
|
typedef struct t_hashtab_header
|
||||||
|
{
|
||||||
|
unsigned long entries; // number of entries in the hash table
|
||||||
|
unsigned long retries; // maximum allowed number of retries by re-hashing
|
||||||
|
unsigned long memory_size; // size of entire hash table in bytes
|
||||||
|
unsigned int max_retry_count; // maximum number of retries needed so far
|
||||||
|
unsigned long conflict_count; // number of conflicts found so far
|
||||||
|
st_hashtab_bucket *bucket; // entries of hashtable
|
||||||
|
} st_hashtab_header;
|
||||||
|
|
||||||
|
|
||||||
|
// HASH FUNCTION TAKEN FROM http://burtleburtle.net/bob/hash/doobs.html - begin
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint32_t ub4; /* unsigned 4-byte quantities */
|
||||||
|
typedef uint8_t ub1; /* unsigned 1-byte quantities */
|
||||||
|
|
||||||
|
#define hashsize(n) ((ub4)1<<(n))
|
||||||
|
#define hashmask(n) (hashsize(n)-1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* mix -- mix 3 32-bit values reversibly.
|
||||||
|
* For every delta with one or two bits set, and the deltas of all three
|
||||||
|
* high bits or all three low bits, whether the original value of a,b,c
|
||||||
|
* is almost all zero or is uniformly distributed,
|
||||||
|
* * If mix() is run forward or backward, at least 32 bits in a,b,c
|
||||||
|
* have at least 1/4 probability of changing.
|
||||||
|
* * If mix() is run forward, every bit of c will change between 1/3 and
|
||||||
|
* 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
|
||||||
|
* mix() was built out of 36 single-cycle latency instructions in a
|
||||||
|
* structure that could supported 2x parallelism, like so:
|
||||||
|
* a -= b;
|
||||||
|
* a -= c; x = (c>>13);
|
||||||
|
* b -= c; a ^= x;
|
||||||
|
* b -= a; x = (a<<8);
|
||||||
|
* c -= a; b ^= x;
|
||||||
|
* c -= b; x = (b>>13);
|
||||||
|
* ...
|
||||||
|
* Unfortunately, superscalar Pentiums and Sparcs can't take advantage
|
||||||
|
* of that parallelism. They've also turned some of those single-cycle
|
||||||
|
* latency instructions into multi-cycle latency instructions. Still,
|
||||||
|
* this is the fastest good hash I could find. There were about 2^^68
|
||||||
|
* to choose from. I only looked at a billion or so.
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#define mix(a,b,c) \
|
||||||
|
{ \
|
||||||
|
a -= b; a -= c; a ^= (c>>13); \
|
||||||
|
b -= c; b -= a; b ^= (a<<8); \
|
||||||
|
c -= a; c -= b; c ^= (b>>13); \
|
||||||
|
a -= b; a -= c; a ^= (c>>12); \
|
||||||
|
b -= c; b -= a; b ^= (a<<16); \
|
||||||
|
c -= a; c -= b; c ^= (b>>5); \
|
||||||
|
a -= b; a -= c; a ^= (c>>3); \
|
||||||
|
b -= c; b -= a; b ^= (a<<10); \
|
||||||
|
c -= a; c -= b; c ^= (b>>15); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* hash() -- hash a variable-length key into a 32-bit value
|
||||||
|
* k : the key (the unaligned variable-length array of bytes)
|
||||||
|
* len : the length of the key, counting by bytes
|
||||||
|
* initval : can be any 4-byte value
|
||||||
|
* Returns a 32-bit value. Every bit of the key affects every bit of
|
||||||
|
* the return value. Every 1-bit and 2-bit delta achieves avalanche.
|
||||||
|
* About 6*len+35 instructions.
|
||||||
|
*
|
||||||
|
* The best hash table sizes are powers of 2. There is no need to do
|
||||||
|
* mod a prime (mod is sooo slow!). If you need less than 32 bits,
|
||||||
|
* use a bitmask. For example, if you need only 10 bits, do
|
||||||
|
* h = (h & hashmask(10));
|
||||||
|
* In which case, the hash table should have hashsize(10) elements.
|
||||||
|
*
|
||||||
|
* If you are hashing n strings (ub1 **)k, do it like this:
|
||||||
|
* for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
|
||||||
|
*
|
||||||
|
* By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
|
||||||
|
* code any way you wish, private, educational, or commercial. It's free.
|
||||||
|
*
|
||||||
|
* See http://burtleburtle.net/bob/hash/evahash.html
|
||||||
|
* Use for hash table lookup, or anything where one collision in 2^^32 is
|
||||||
|
* acceptable. Do NOT use for cryptographic purposes.
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline ub4 hash( k, length, initval)
|
||||||
|
register ub1 *k; /* the key */
|
||||||
|
register ub4 length; /* the length of the key */
|
||||||
|
register ub4 initval; /* the previous hash, or an arbitrary value */
|
||||||
|
{
|
||||||
|
register ub4 a,b,c,len;
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
len = length;
|
||||||
|
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
|
||||||
|
c = initval; /* the previous hash value */
|
||||||
|
|
||||||
|
/*---------------------------------------- handle most of the key */
|
||||||
|
while (len >= 12)
|
||||||
|
{
|
||||||
|
a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
|
||||||
|
b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
|
||||||
|
c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
|
||||||
|
mix(a,b,c);
|
||||||
|
k += 12; len -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------- handle the last 11 bytes */
|
||||||
|
c += length;
|
||||||
|
switch(len) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 11: c+=((ub4)k[10]<<24);
|
||||||
|
case 10: c+=((ub4)k[9]<<16);
|
||||||
|
case 9 : c+=((ub4)k[8]<<8);
|
||||||
|
/* the first byte of c is reserved for the length */
|
||||||
|
case 8 : b+=((ub4)k[7]<<24);
|
||||||
|
case 7 : b+=((ub4)k[6]<<16);
|
||||||
|
case 6 : b+=((ub4)k[5]<<8);
|
||||||
|
case 5 : b+=k[4];
|
||||||
|
case 4 : a+=((ub4)k[3]<<24);
|
||||||
|
case 3 : a+=((ub4)k[2]<<16);
|
||||||
|
case 2 : a+=((ub4)k[1]<<8);
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
/* case 0: nothing left to add */
|
||||||
|
}
|
||||||
|
mix(a,b,c);
|
||||||
|
/*-------------------------------------------- report the result */
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// HASH FUNCTION TAKEN FROM http://burtleburtle.net/bob/hash/doobs.html - end
|
||||||
|
|
||||||
|
|
||||||
|
// a hash function for binary data
|
||||||
|
static t_hash hashtab_hash( unsigned char * p_data, unsigned long size, unsigned long initval )
|
||||||
|
{
|
||||||
|
return hash( p_data, size, initval );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new hash table
|
||||||
|
t_hashtab hashtab_new( unsigned long entries, unsigned long retries ) // extern
|
||||||
|
{
|
||||||
|
unsigned long size;
|
||||||
|
t_hashtab hashtab;
|
||||||
|
char * ptr;
|
||||||
|
|
||||||
|
// correct parameters
|
||||||
|
entries = max( entries, HASH_MIN_ENTRIES );
|
||||||
|
retries = max( retries, 1 );
|
||||||
|
|
||||||
|
// calculate size
|
||||||
|
size = sizeof( st_hashtab_header ); // header
|
||||||
|
size += entries * sizeof( st_hashtab_bucket ); // entries
|
||||||
|
|
||||||
|
// allocate memory
|
||||||
|
hashtab = (t_hashtab)calloc( 1, size );
|
||||||
|
if( hashtab == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// initialize hashtab header
|
||||||
|
hashtab->entries = entries;
|
||||||
|
hashtab->retries = retries;
|
||||||
|
hashtab->memory_size = size;
|
||||||
|
|
||||||
|
// initialize hashtable
|
||||||
|
ptr = (char *)hashtab + sizeof( st_hashtab_header ); // pointer to array with entries
|
||||||
|
hashtab->bucket = (st_hashtab_bucket *)ptr;
|
||||||
|
|
||||||
|
return hashtab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// free a hash table
|
||||||
|
void hashtab_free( t_hashtab hashtab ) // extern
|
||||||
|
{
|
||||||
|
free( hashtab );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get index for/of an entry in a hash table
|
||||||
|
// - returns: 1 if state can be inserted into hash table
|
||||||
|
// 0 if state is already in hash table
|
||||||
|
// -1 if state did not fit into hash table (hash conflict that could not be resolved)
|
||||||
|
// - fills *p_pos with pointer to position for/of entry (not for return value -1)
|
||||||
|
extern int
|
||||||
|
hashtab_get_pos (t_hashtab hashtab, size_t size, nipsvm_state_t *state,
|
||||||
|
nipsvm_state_t ***p_pos)
|
||||||
|
{
|
||||||
|
unsigned long entry, i;
|
||||||
|
t_hash hash, k;
|
||||||
|
|
||||||
|
// get hashtable entry
|
||||||
|
hash = hashtab_hash( (unsigned char *)state, size, 0 );
|
||||||
|
k = 1 + (hash % (hashtab->entries - 1)); // naive double hashing
|
||||||
|
entry = hash % hashtab->entries;
|
||||||
|
for( i = 0; i < hashtab->retries; i++ )
|
||||||
|
{
|
||||||
|
if( hashtab->bucket[entry].value == NULL )
|
||||||
|
{
|
||||||
|
hashtab->bucket[entry].hash_rest = hash / hashtab->entries;
|
||||||
|
*p_pos = &hashtab->bucket[entry].value; // return pointer to position
|
||||||
|
return 1; // can be inserted into hash table
|
||||||
|
}
|
||||||
|
else if( hashtab->bucket[entry].hash_rest != hash / hashtab->entries )
|
||||||
|
{
|
||||||
|
// no match, try next
|
||||||
|
}
|
||||||
|
else if( nipsvm_state_compare( hashtab->bucket[entry].value, state, size ) == 0 )
|
||||||
|
{
|
||||||
|
*p_pos = &hashtab->bucket[entry].value; // return pointer to position
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
hashtab->conflict_count++;
|
||||||
|
hashtab->max_retry_count = max( hashtab->max_retry_count, i + 1 );
|
||||||
|
entry = (entry + k) % hashtab->entries; // considers indexes h, h + k, ..., h + i*k (mod entries)
|
||||||
|
} // for( i ...
|
||||||
|
|
||||||
|
// no more space ---> unresolvable hash conflict
|
||||||
|
*p_pos = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// put a state into a hash table
|
||||||
|
// - only the pointer is stored
|
||||||
|
// - returns: 1 if state was added to hash table
|
||||||
|
// 0 if state was already in hash table
|
||||||
|
// -1 if state did not fit into hash table (hash conflict that could not be resolved)
|
||||||
|
extern int
|
||||||
|
hashtab_insert( t_hashtab hashtab, size_t size, nipsvm_state_t *state )
|
||||||
|
{
|
||||||
|
unsigned long ret_val;
|
||||||
|
t_hashtab_value* pos;
|
||||||
|
|
||||||
|
// get indices where to place entry
|
||||||
|
ret_val = hashtab_get_pos( hashtab, size, state, &pos );
|
||||||
|
|
||||||
|
// put pointer to state into hash table if it is a new one
|
||||||
|
if( ret_val > 0 )
|
||||||
|
*pos = state;
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output statistical information about hashtable
|
||||||
|
void hashtab_print_statistics( FILE * stream, t_hashtab hashtab )
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int entries = 0;
|
||||||
|
|
||||||
|
// count entries in hash table
|
||||||
|
for( i = 0; i < hashtab->entries; i++ )
|
||||||
|
if( hashtab->bucket[i].value != NULL )
|
||||||
|
entries++;
|
||||||
|
|
||||||
|
double fill_ratio = 100.0 * (double)entries / (double)hashtab->entries;
|
||||||
|
|
||||||
|
fprintf( stream, "hashtable statistics:\n"
|
||||||
|
" memory usage: %0.2fMB\n", hashtab->memory_size / 1048576.0 );
|
||||||
|
fprintf( stream, " buckets used/available: %u/%lu (%0.1f%%)\n", entries, hashtab->entries, fill_ratio );
|
||||||
|
fprintf( stream, " max. no. of retries: %u\n", hashtab->max_retry_count );
|
||||||
|
fprintf( stream, " conflicts (resolved): %lu\n", hashtab->conflict_count );
|
||||||
|
}
|
||||||
|
|
||||||
|
// output statistical information about hashtable
|
||||||
|
extern void
|
||||||
|
table_statistics (t_hashtab table, table_statistics_t *stats)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int n_entries = 0;
|
||||||
|
|
||||||
|
assert (table != NULL);
|
||||||
|
assert (stats != NULL);
|
||||||
|
|
||||||
|
// count entries in hash table
|
||||||
|
for( i = 0; i < table->entries; i++ ) {
|
||||||
|
if (table->bucket[i].value != NULL) { n_entries++; }
|
||||||
|
}
|
||||||
|
|
||||||
|
memset (stats, sizeof stats, 0);
|
||||||
|
stats->memory_size = table->memory_size;
|
||||||
|
stats->entries_used = n_entries;
|
||||||
|
stats->entries_available = table->entries;
|
||||||
|
stats->conflicts = table->conflict_count;
|
||||||
|
stats->max_retries = table->max_retry_count;
|
||||||
|
}
|
||||||
70
iface/nips/nips_vm/hashtab.h
Normal file
70
iface/nips/nips_vm/hashtab.h
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_hashtab
|
||||||
|
#define INC_hashtab
|
||||||
|
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// hashtable pointer type
|
||||||
|
typedef struct t_hashtab_header *t_hashtab;
|
||||||
|
typedef struct table_statistics_t table_statistics_t;
|
||||||
|
|
||||||
|
struct table_statistics_t {
|
||||||
|
size_t memory_size;
|
||||||
|
unsigned long entries_used;
|
||||||
|
unsigned long entries_available;
|
||||||
|
unsigned long conflicts;
|
||||||
|
unsigned long max_retries;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// create a new hash table
|
||||||
|
extern t_hashtab hashtab_new( unsigned long entries, unsigned long retries );
|
||||||
|
|
||||||
|
|
||||||
|
// free a hash table
|
||||||
|
extern void hashtab_free( t_hashtab hashtab );
|
||||||
|
|
||||||
|
|
||||||
|
// get index for/of an entry in a hash table
|
||||||
|
// - returns: 1 if state can be inserted into hash table
|
||||||
|
// 0 if state is already in hash table
|
||||||
|
// -1 if state did not fit into hash table (hash conflict that could not be resolved)
|
||||||
|
// - fills *p_pos with pointer to position for/of entry (not for return value -1)
|
||||||
|
extern int
|
||||||
|
hashtab_get_pos (t_hashtab hashtab, size_t size, nipsvm_state_t *state, nipsvm_state_t ***p_pos);
|
||||||
|
|
||||||
|
|
||||||
|
// put a state into a hash table
|
||||||
|
// - only the pointer is stored
|
||||||
|
// - returns: 1 if state was added to hash table
|
||||||
|
// 0 if state was already in hash table
|
||||||
|
// -1 if state did not fit into hash table (hash conflict that could not be resolved)
|
||||||
|
extern int
|
||||||
|
hashtab_insert (t_hashtab hashtab, size_t size, nipsvm_state_t *state);
|
||||||
|
|
||||||
|
|
||||||
|
// retrieve statistical information about hashtable
|
||||||
|
extern void
|
||||||
|
table_statistics (t_hashtab hashtab, table_statistics_t *stats);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_hashtab
|
||||||
2151
iface/nips/nips_vm/instr.c
Normal file
2151
iface/nips/nips_vm/instr.c
Normal file
File diff suppressed because it is too large
Load diff
233
iface/nips/nips_vm/instr.h
Normal file
233
iface/nips/nips_vm/instr.h
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_instr
|
||||||
|
#define INC_instr
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
|
||||||
|
// return value of instruction callbacks
|
||||||
|
typedef enum t_ic_status
|
||||||
|
{
|
||||||
|
IC_CONTINUE, // continue (e.g. generate further successor states)
|
||||||
|
IC_STOP, // stop processing immediately and return
|
||||||
|
} et_ic_status;
|
||||||
|
|
||||||
|
|
||||||
|
// run time errors
|
||||||
|
typedef enum t_instr_err
|
||||||
|
{
|
||||||
|
IE_BYTECODE, // bytecode segmentation fault
|
||||||
|
IE_INVOP, // invalid opcode
|
||||||
|
IE_LOCAL, // invalid local memory access
|
||||||
|
IE_GLOBAL, // invalid global memory access
|
||||||
|
IE_STACKOV, // stack overflow
|
||||||
|
IE_STACKUN, // stack underflow
|
||||||
|
IE_DIV0, // division by zero
|
||||||
|
IE_OV, // overflow error (TRUNC instruction, must be enabled in instr.c)
|
||||||
|
IE_INDEX, // invalid array index
|
||||||
|
IE_ASSERT, // assertion violated
|
||||||
|
IE_INV_PROC_ID, // invalid process id
|
||||||
|
IE_NO_PROC, // no process with specified process id
|
||||||
|
IE_INV_CHAN_ID, // invalid channel id
|
||||||
|
IE_NO_CHAN, // no channel with specified channel id
|
||||||
|
IE_INV_CHAN_TYPE, // invalid channel type
|
||||||
|
IE_CHAN_OV, // channel overflow
|
||||||
|
IE_CHAN_UN, // channel underflow
|
||||||
|
IE_CHAN_EMPTY, // channel is empty, but message is needed here
|
||||||
|
IE_PROC_CNT, // too many processes
|
||||||
|
IE_CHAN_CNT, // too many channels
|
||||||
|
IE_PATH_CNT, // too many parallel execution paths
|
||||||
|
IE_INVIS_CNT, // too many invisible states
|
||||||
|
IE_SUCC_CNT, // too many possible successor states
|
||||||
|
IE_STATE_MEM, // out of temporary state memory
|
||||||
|
IE_NO_ACT_PROC, // no active process (this is most likely an internal error) (no pid or pc is passed to callback)
|
||||||
|
IE_EN_PROC_CNT, // too many enabled processes (no pid or pc is passed to callback)
|
||||||
|
IE_INVIS_MEM, // out of memory for invisible states
|
||||||
|
} et_instr_err;
|
||||||
|
|
||||||
|
|
||||||
|
// output of print instructions is stored in state buffer during instruction
|
||||||
|
// execution as linked list (pointing towards first output)
|
||||||
|
|
||||||
|
// an entry of the linked list of print instruction output
|
||||||
|
// - must be packed because of improper alignment in state buffer
|
||||||
|
typedef struct t_instr_output
|
||||||
|
{
|
||||||
|
struct t_instr_output *p_prev; // pointer to previous output or NULL
|
||||||
|
int8_t is_str; // if this is a string output or not (a value output)
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct // string output
|
||||||
|
{
|
||||||
|
uint16_t str; // number of string to print
|
||||||
|
} str;
|
||||||
|
struct // value output
|
||||||
|
{
|
||||||
|
uint8_t fmt; // format to print value in
|
||||||
|
t_val value; // value to print
|
||||||
|
} value;
|
||||||
|
} data;
|
||||||
|
} PACKED st_instr_output;
|
||||||
|
|
||||||
|
// output during successor state generation
|
||||||
|
typedef struct t_instr_succ_output
|
||||||
|
{
|
||||||
|
st_instr_output *p_out_sys1st; // output of system during 1st part of sync. comm.
|
||||||
|
st_instr_output *p_out_sys; // output of system
|
||||||
|
st_instr_output *p_out_monitor; // output of monitor
|
||||||
|
} st_instr_succ_output;
|
||||||
|
|
||||||
|
|
||||||
|
// types of callback functions
|
||||||
|
|
||||||
|
// report single single successor state to caller
|
||||||
|
// - memory pointed to by succ must not be modified or accessed outside of callback
|
||||||
|
#define INSTR_SUCC_CB_FLAG_SYNC 0x00000001 // sync. comm. took place
|
||||||
|
#define INSTR_SUCC_CB_FLAG_TIMEOUT 0x00000002 // timeout occured
|
||||||
|
#define INSTR_SUCC_CB_FLAG_SYS_BLOCK 0x00000004 // system is blocked
|
||||||
|
#define INSTR_SUCC_CB_FLAG_MONITOR_EXIST 0x00000010 // monitor process exists
|
||||||
|
#define INSTR_SUCC_CB_FLAG_MONITOR_EXEC 0x00000020 // monitor process executed
|
||||||
|
#define INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT 0x00000040 // monitor process is in accepting state
|
||||||
|
#define INSTR_SUCC_CB_FLAG_MONITOR_TERM 0x00000080 // monitor process is terminated
|
||||||
|
typedef et_ic_status (*instr_succ_callback_t)( st_global_state_header *succ, // the successor state
|
||||||
|
uint8_t label1st, // label of STEP command of 1st part of sync. comm. (unused if _SYNC flag is not set)
|
||||||
|
uint8_t label, // label of STEP command (of 2nd part of sync. comm. if _SYNC flag is set)
|
||||||
|
t_flag_reg flag_reg_1st, // flag register value returned by 1st part of sync. comm. (unused if _SYNC flag is not set)
|
||||||
|
t_flag_reg flag_reg, // flag register value returned (by 2nd part of sync. comm. if _SYNC flag is set)
|
||||||
|
unsigned int succ_cb_flags, // flags with boolean information
|
||||||
|
st_instr_succ_output *p_succ_out, // output during successor state generation
|
||||||
|
void *priv_context );
|
||||||
|
|
||||||
|
// report run time error to caller
|
||||||
|
typedef et_ic_status (*instr_err_callback_t)( et_instr_err err, // error code
|
||||||
|
t_pid pid, // pid of process causing error
|
||||||
|
t_pc pc, // program counter when error occured (might point into middle of instruction)
|
||||||
|
void *priv_context );
|
||||||
|
|
||||||
|
|
||||||
|
// context for successor state generation
|
||||||
|
typedef struct t_instr_succ_context
|
||||||
|
{
|
||||||
|
// maximum values (i.e. buffer sizes) used during successor state generation
|
||||||
|
uint8_t stack_max; // number of entries in the stack during execution of a step
|
||||||
|
// type is uint8_t because stack pointer is an uint8_t
|
||||||
|
// error IE_STACK_OV will occur if too small
|
||||||
|
unsigned int state_mem; // size of memory for temporary states within a step
|
||||||
|
// error IE_STATE_MEM will occur if too small
|
||||||
|
unsigned int enab_state_mem; // size of memory for temporary states within a step in ENAB instruction
|
||||||
|
// this can be smaller as above because execution stops after first state
|
||||||
|
// error IE_STATE_MEM will occur if too small
|
||||||
|
unsigned int invis_mem; // size of memory for invisible states stored for further processing
|
||||||
|
// error IE_INVIS_MEM will occur if too small
|
||||||
|
unsigned int path_max; // maximum number of states on stack during execution of a step
|
||||||
|
// maximum number of possible nondeterministic paths within a step
|
||||||
|
// e.g. maximum number of options in Promela's "do" statement
|
||||||
|
// error IE_PATH_CNT will happen if too small
|
||||||
|
unsigned int invis_max; // maximum number of invisible states that can be stored
|
||||||
|
// error IE_INVIS_CNT will happen if too small
|
||||||
|
unsigned int succ_max; // maximum number of possible successor states during execution of a step
|
||||||
|
// maximum number of executable nondeterministic paths within a step
|
||||||
|
// e.g. maximum number of executable options in Promela's "do" statement
|
||||||
|
// error IE_SUCC_CNT will happen if too small
|
||||||
|
// bytecode to execute
|
||||||
|
st_bytecode *bytecode;
|
||||||
|
// pointers to callback functions
|
||||||
|
instr_succ_callback_t succ_cb;
|
||||||
|
instr_err_callback_t err_cb;
|
||||||
|
// private context of caller
|
||||||
|
// - will be passed to every callback function being called
|
||||||
|
void *priv_context;
|
||||||
|
} st_instr_succ_context;
|
||||||
|
|
||||||
|
|
||||||
|
// context for execution of an instruction
|
||||||
|
#define INSTR_CONTEXT_MODE_INVALID 0 // context not initialized
|
||||||
|
#define INSTR_CONTEXT_MODE_ACTIVE 1 // a process is active, p_glob, p_gvar, gvar_sz, p_proc, p_lvar, lvar_sz, p_stack are valid
|
||||||
|
#define INSTR_CONTEXT_MODE_COMPLETED 2 // a step has been completed, p_glob is valid, invisible, label and flag_reg are set
|
||||||
|
#define INSTR_CONTEXT_MODE_STOP 3 // error callback requested stop - context not initialized
|
||||||
|
typedef struct t_instr_context_state
|
||||||
|
{
|
||||||
|
st_global_state_header *p_glob; // pointer to global state
|
||||||
|
st_instr_output *p_output; // pointer to last output list entry or NULL if none
|
||||||
|
unsigned int max_step_cnt; // maximum step_cnt in context
|
||||||
|
// - if step_cnt in context is greater than this, ignore this state
|
||||||
|
// - used in ELSE and UNLESS to ignore second path if some step has already been completed
|
||||||
|
} st_instr_context_state;
|
||||||
|
typedef struct t_instr_context
|
||||||
|
{
|
||||||
|
// current state
|
||||||
|
int mode; // current mode of context
|
||||||
|
int8_t invisible; // if the completed step is invisible
|
||||||
|
uint8_t label; // label of completed step
|
||||||
|
t_flag_reg flag_reg; // the flag register value before the step was completed
|
||||||
|
st_global_state_header *p_glob; // the global state the instruction shall be executed on
|
||||||
|
char *p_gvar; // the global variables within *p_glob
|
||||||
|
t_val gvar_sz; // the size of the global variables *p_gvar already converted to t_val
|
||||||
|
st_process_active_header *p_proc; // the active process within *p_glob
|
||||||
|
char *p_lvar; // the local variables within *p_proc
|
||||||
|
t_val lvar_sz; // the size of the local variables *p_lvar already converted to t_val
|
||||||
|
ua_t_val *p_stack; // the stack of the active process *p_proc
|
||||||
|
st_instr_output *p_output; // pointer to last output list entry or NULL if none
|
||||||
|
// additional states to process (must always be valid)
|
||||||
|
st_instr_context_state *p_states; // pointer to array with additonal states (stack)
|
||||||
|
unsigned int state_cnt_max; // maximum number of entries that fit into array
|
||||||
|
unsigned int state_cnt; // number of entries currently in array
|
||||||
|
// buffer with memory for new temporary states (must always be valid)
|
||||||
|
char **pp_buf;
|
||||||
|
unsigned long *p_buf_len;
|
||||||
|
// counter of completed steps
|
||||||
|
unsigned int step_cnt;
|
||||||
|
// other stuff
|
||||||
|
t_flag_reg init_flag_reg; // initial value of flag register (needed for ENAB)
|
||||||
|
int timeout; // boolean flag - Promela's timeout variable
|
||||||
|
t_pid last_pid; // pid of last process that executed a step (or 0 if not available)
|
||||||
|
st_instr_succ_context *p_succ_ctx; // context for successor state generation
|
||||||
|
} st_instr_context;
|
||||||
|
|
||||||
|
|
||||||
|
// type for a temporary successor
|
||||||
|
typedef struct t_instr_tmp_succ
|
||||||
|
{
|
||||||
|
st_global_state_header *p_glob; // the pointer to the state
|
||||||
|
int8_t invisible; // if the completed step is invisible
|
||||||
|
int8_t sync_comm; // if synchronous communication is taking place in the completed step
|
||||||
|
uint8_t label; // the label the step was completed with
|
||||||
|
t_flag_reg flag_reg; // value of flag register at end of step
|
||||||
|
st_instr_output *p_output; // output list at end of step
|
||||||
|
} st_instr_tmp_succ;
|
||||||
|
|
||||||
|
|
||||||
|
// execute instructions in executions paths
|
||||||
|
// - must be called with an active state
|
||||||
|
// - stops when all paths have reached inactive state
|
||||||
|
extern et_ic_status instr_exec_paths( st_instr_context *p_ctx,
|
||||||
|
int stop_on_first, // boolean flag if to stop when first temp. state is found
|
||||||
|
st_instr_tmp_succ *p_tmp_succs, // temp. states are returned here
|
||||||
|
unsigned int tmp_succ_cnt_max, // max. number of temp. states
|
||||||
|
unsigned int *p_tmp_succ_cnt // number of temp. states is returned here
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_instr
|
||||||
674
iface/nips/nips_vm/instr_step.c
Normal file
674
iface/nips/nips_vm/instr_step.c
Normal file
|
|
@ -0,0 +1,674 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "instr_step.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #define DEBUG_INVIS // print invisible states
|
||||||
|
|
||||||
|
|
||||||
|
// default maximum values (i.e. buffer sizes) for successor state generation
|
||||||
|
#define INSTR_DEF_STACK_MAX 64 // number of entries in the stack during execution of a step
|
||||||
|
// type is uint8_t because stack pointer is an uint8_t
|
||||||
|
#ifdef SMALLSTACK // (reduce sizes for windows, because default stack size is only 1MB)
|
||||||
|
# warning Building with reduced stack size demands.
|
||||||
|
# define INSTR_DEF_STATE_MEM 65536 // size of memory for temporary states within a step
|
||||||
|
# define INSTR_DEF_ENAB_STATE_MEM 8192 // size of memory for temporary states within a step in ENAB instruction
|
||||||
|
# define INSTR_DEF_INVIS_MEM 8192 // size of memory to store invisible states for further execution
|
||||||
|
#else
|
||||||
|
# define INSTR_DEF_STATE_MEM 262144 // size of memory for temporary states within a step
|
||||||
|
# define INSTR_DEF_ENAB_STATE_MEM 32768 // size of memory for temporary states within a step in ENAB instruction
|
||||||
|
# define INSTR_DEF_INVIS_MEM 32768 // size of memory to store invisible states for further execution
|
||||||
|
#endif
|
||||||
|
#define INSTR_DEF_PATH_MAX 256 // maximum number of states on stack during execution of a step
|
||||||
|
// maximum number of possible nondeterministic paths within a step
|
||||||
|
#define INSTR_DEF_INVIS_MAX 256 // maximum number of invisible states that can be stored
|
||||||
|
#define INSTR_DEF_SUCC_MAX 256 // maximum number of possible successor states during execution of a step
|
||||||
|
// maximum number of executable nondeterministic paths within a step
|
||||||
|
|
||||||
|
|
||||||
|
// type for numbers of successor states (of system and total)
|
||||||
|
typedef struct t_instr_succ_cnts
|
||||||
|
{
|
||||||
|
unsigned int sys; // successor count of system
|
||||||
|
unsigned int total; // total successor cnt
|
||||||
|
} st_instr_succ_cnts;
|
||||||
|
|
||||||
|
|
||||||
|
// type to save parameters of 1st part while executing 2nd part of sync. comm.
|
||||||
|
typedef struct t_instr_prm_save_sync
|
||||||
|
{
|
||||||
|
uint8_t label; // label returned by 1st part
|
||||||
|
t_flag_reg flag_reg; // flag register value returned by 1st part
|
||||||
|
st_instr_output *p_output; // output done by 1st part
|
||||||
|
} st_instr_prm_save_sync;
|
||||||
|
|
||||||
|
|
||||||
|
// type to save parameters of system while executing monitor process
|
||||||
|
typedef struct t_instr_prm_save_monitor
|
||||||
|
{
|
||||||
|
st_instr_prm_save_sync * p_prm_1st; // saved settings from 1st part of sync. comm.
|
||||||
|
uint8_t label; // label returned by step of normal system
|
||||||
|
t_flag_reg flag_reg; // flag register value returned by normal system
|
||||||
|
st_instr_output *p_output; // output done by normal system
|
||||||
|
} st_instr_prm_save_monitor;
|
||||||
|
|
||||||
|
|
||||||
|
// type for internal successor callback function
|
||||||
|
typedef et_ic_status (*instr_int_succ_cb_t)( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
|
||||||
|
t_pid pid, // pid of process that executed
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
unsigned int succ_cb_flags, // flags accumulated so far
|
||||||
|
st_instr_succ_context *p_succ_ctx, // context for successor state generation
|
||||||
|
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
|
||||||
|
void *p_int_ctx ); // private context
|
||||||
|
|
||||||
|
|
||||||
|
// execute a step in a process
|
||||||
|
// - callbacks in context are called for every event (e.g. errors)
|
||||||
|
// - returns instruction callback status
|
||||||
|
static et_ic_status instr_proc_step( st_global_state_header *p_glob, // state to start with
|
||||||
|
st_process_header *p_proc, // process to execute
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
t_pid monitor_last, // pid of process that did last step (0 if not executing monitor)
|
||||||
|
unsigned int succ_cb_flags, // flags already accumulated for successor callback
|
||||||
|
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
|
||||||
|
void *p_int_ctx, // private context for int_succ_cb
|
||||||
|
char **pp_invis_buf, unsigned long *p_invis_buf_len, // buffer for invisible states
|
||||||
|
st_instr_tmp_succ **pp_invis_tmp_succ, unsigned int *p_invis_tmp_succ_cnt, // array for invisible states
|
||||||
|
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts,
|
||||||
|
unsigned int *p_state_cnt ) // number of resulting states
|
||||||
|
{
|
||||||
|
// buffer for temporary states
|
||||||
|
char tmp_buf[p_succ_ctx->state_mem];
|
||||||
|
char *p_tmp_buf = tmp_buf;
|
||||||
|
unsigned long tmp_buf_len = sizeof( tmp_buf );
|
||||||
|
|
||||||
|
// activate process
|
||||||
|
st_process_active_header *p_proc_act;
|
||||||
|
st_global_state_header *p_glob_act = global_state_copy_activate( p_glob, p_proc,
|
||||||
|
p_succ_ctx->stack_max, flag_reg,
|
||||||
|
&p_tmp_buf, &tmp_buf_len,
|
||||||
|
&p_proc_act );
|
||||||
|
if( p_glob_act == NULL )
|
||||||
|
return p_succ_ctx->err_cb( IE_STATE_MEM, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
|
||||||
|
p_succ_ctx->priv_context );
|
||||||
|
|
||||||
|
// reset monitor accept flag in process header
|
||||||
|
p_proc_act->proc.flags &= ~PROCESS_FLAGS_MONITOR_ACCEPT;
|
||||||
|
|
||||||
|
// set up context to execute instructions
|
||||||
|
st_instr_context ctx;
|
||||||
|
st_instr_context_state states[p_succ_ctx->path_max]; // create stack of states to process
|
||||||
|
states[0].p_glob = p_glob_act;
|
||||||
|
states[0].p_output = NULL;
|
||||||
|
states[0].max_step_cnt = (unsigned int)-1; // process this state in any case
|
||||||
|
ctx.p_states = states;
|
||||||
|
ctx.state_cnt_max = count( states );
|
||||||
|
ctx.state_cnt = 1;
|
||||||
|
ctx.step_cnt = 0; // no step completed yet
|
||||||
|
ctx.pp_buf = &p_tmp_buf; // fill in pointers for buffer with memory for new temporary states
|
||||||
|
ctx.p_buf_len = &tmp_buf_len;
|
||||||
|
ctx.init_flag_reg = flag_reg;
|
||||||
|
ctx.timeout = timeout;
|
||||||
|
ctx.last_pid = monitor_last;
|
||||||
|
ctx.p_succ_ctx = p_succ_ctx;
|
||||||
|
|
||||||
|
// execute instructions until all paths are done
|
||||||
|
st_instr_tmp_succ tmp_succs[p_succ_ctx->succ_max];
|
||||||
|
unsigned int tmp_succ_cnt = 0;
|
||||||
|
if( instr_exec_paths( &ctx, 0, // do not stop on first state found
|
||||||
|
tmp_succs, count( tmp_succs ), &tmp_succ_cnt ) == IC_STOP )
|
||||||
|
return IC_STOP;
|
||||||
|
|
||||||
|
// process all completed states
|
||||||
|
unsigned int i;
|
||||||
|
for( i = 0; i < tmp_succ_cnt; i++ )
|
||||||
|
{
|
||||||
|
(*p_state_cnt)++;
|
||||||
|
// invisible state
|
||||||
|
if( tmp_succs[i].invisible && // state marked as invisible
|
||||||
|
! tmp_succs[i].sync_comm && // no synchronous communication in progress (sync. comm. forces visibility)
|
||||||
|
tmp_succs[i].p_output == NULL ) // no output done (outout forces visibility)
|
||||||
|
{
|
||||||
|
// put invisible state into buffer for invisible states
|
||||||
|
st_global_state_header * p_glb = global_state_copy( tmp_succs[i].p_glob, // copy state
|
||||||
|
pp_invis_buf, p_invis_buf_len );
|
||||||
|
if( p_glb == NULL )
|
||||||
|
return p_succ_ctx->err_cb( IE_INVIS_MEM, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
|
||||||
|
p_succ_ctx->priv_context );
|
||||||
|
if( *p_invis_tmp_succ_cnt == 0 ) // put copy of state into array
|
||||||
|
return p_succ_ctx->err_cb( IE_INVIS_CNT, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
|
||||||
|
p_succ_ctx->priv_context );
|
||||||
|
**pp_invis_tmp_succ = tmp_succs[i];
|
||||||
|
(**pp_invis_tmp_succ).p_glob = p_glb;
|
||||||
|
(*pp_invis_tmp_succ)++;
|
||||||
|
(*p_invis_tmp_succ_cnt)--;
|
||||||
|
}
|
||||||
|
// visible state
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// report state to caller
|
||||||
|
if( int_succ_cb( &tmp_succs[i], // successor state
|
||||||
|
be2h_pid( p_proc->pid ), // pid of process that executed
|
||||||
|
flag_reg, // initial value for flag register of process
|
||||||
|
timeout, // boolean flag if timeout
|
||||||
|
succ_cb_flags, // flags accumulated so far
|
||||||
|
p_succ_ctx, p_succ_cnts,
|
||||||
|
p_int_ctx ) == IC_STOP )
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
} // for( i ...
|
||||||
|
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// execute steps in a process
|
||||||
|
// - callbacks in context are called for every event (e.g. errors)
|
||||||
|
// - continues execution for invisible states are reached
|
||||||
|
// - returns instruction callback status
|
||||||
|
static et_ic_status instr_proc_steps( st_global_state_header *p_glob, // state to start with
|
||||||
|
st_process_header *p_proc, // process to execute
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
t_pid monitor_last, // pid of process that did last step (0 if not executing monitor)
|
||||||
|
unsigned int succ_cb_flags, // flags already accumulated for successor callback
|
||||||
|
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
|
||||||
|
void *p_int_ctx, // private context for int_succ_cb
|
||||||
|
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
|
||||||
|
{
|
||||||
|
// buffers for invisible states
|
||||||
|
char invis_bufs[2][p_succ_ctx->invis_mem];
|
||||||
|
st_instr_tmp_succ invis_tmp_succs[2][p_succ_ctx->invis_max];
|
||||||
|
int invis_buf_idx = 0; // active buffer
|
||||||
|
|
||||||
|
// save pid of process to execute
|
||||||
|
t_pid exec_pid = be2h_pid( p_proc->pid );
|
||||||
|
|
||||||
|
// initialize buffer for invisible states
|
||||||
|
char *p_invis_buf = invis_bufs[invis_buf_idx];
|
||||||
|
unsigned long invis_buf_len = sizeof( invis_bufs[invis_buf_idx] );
|
||||||
|
st_instr_tmp_succ *p_invis_tmp_succs = invis_tmp_succs[invis_buf_idx];
|
||||||
|
unsigned int invis_tmp_succ_cnt = count( invis_tmp_succs[invis_buf_idx] );
|
||||||
|
|
||||||
|
// process initial state
|
||||||
|
unsigned int state_cnt = 0;
|
||||||
|
if( instr_proc_step( p_glob, p_proc,
|
||||||
|
flag_reg, timeout, monitor_last,
|
||||||
|
succ_cb_flags, int_succ_cb, p_int_ctx,
|
||||||
|
&p_invis_buf, &invis_buf_len,
|
||||||
|
&p_invis_tmp_succs, &invis_tmp_succ_cnt,
|
||||||
|
p_succ_ctx, p_succ_cnts, &state_cnt ) == IC_STOP )
|
||||||
|
return IC_STOP;
|
||||||
|
|
||||||
|
// as long as there are states in buffer
|
||||||
|
for( ; ; )
|
||||||
|
{
|
||||||
|
// get pointer to and number of states in buffer
|
||||||
|
st_instr_tmp_succ *p_tmp_succs = invis_tmp_succs[invis_buf_idx];
|
||||||
|
unsigned int tmp_succ_cnt = count( invis_tmp_succs[invis_buf_idx] ) - invis_tmp_succ_cnt;
|
||||||
|
// no more states ---> exit loop
|
||||||
|
if( tmp_succ_cnt == 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// initialize buffer for new invisible states to use other buffer
|
||||||
|
p_invis_buf = invis_bufs[1 - invis_buf_idx];
|
||||||
|
invis_buf_len = sizeof( invis_bufs[1 - invis_buf_idx] );
|
||||||
|
p_invis_tmp_succs = invis_tmp_succs[1 - invis_buf_idx];
|
||||||
|
invis_tmp_succ_cnt = count( invis_tmp_succs[1 - invis_buf_idx] );
|
||||||
|
|
||||||
|
// process all states in buffer
|
||||||
|
for( ; tmp_succ_cnt > 0 ; tmp_succ_cnt--, p_tmp_succs++ )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_INVIS
|
||||||
|
printf( "DEBUG (invisible state): " );
|
||||||
|
global_state_print( p_tmp_succs->p_glob );
|
||||||
|
#endif
|
||||||
|
// get process to execute
|
||||||
|
st_process_header *p_prc = global_state_get_process( p_tmp_succs->p_glob, exec_pid );
|
||||||
|
if( p_prc != NULL )
|
||||||
|
{
|
||||||
|
unsigned int state_cnt = 0;
|
||||||
|
// if this process became the monitor or ceased to be the monitor
|
||||||
|
// while executing an invisible step
|
||||||
|
// then the next step is not executable according to the formal model
|
||||||
|
// so force this behaviour in this implementation
|
||||||
|
if( (p_glob->monitor_pid == p_proc->pid) == (p_tmp_succs->p_glob->monitor_pid == p_prc->pid) )
|
||||||
|
{
|
||||||
|
// process state
|
||||||
|
if( instr_proc_step( p_tmp_succs->p_glob, p_prc,
|
||||||
|
flag_reg, timeout, monitor_last,
|
||||||
|
succ_cb_flags, int_succ_cb, p_int_ctx,
|
||||||
|
&p_invis_buf, &invis_buf_len,
|
||||||
|
&p_invis_tmp_succs, &invis_tmp_succ_cnt,
|
||||||
|
p_succ_ctx, p_succ_cnts, &state_cnt ) == IC_STOP )
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
// no resulting states -> report original state to caller
|
||||||
|
if( state_cnt == 0 )
|
||||||
|
{
|
||||||
|
if( int_succ_cb( p_tmp_succs, // successor state
|
||||||
|
exec_pid, // pid of process that executed
|
||||||
|
flag_reg, // initial value for flag register of process
|
||||||
|
timeout, // boolean flag if timeout
|
||||||
|
succ_cb_flags, // flags accumulated so far
|
||||||
|
p_succ_ctx, p_succ_cnts,
|
||||||
|
p_int_ctx ) == IC_STOP )
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for( ; tmp_succ_cnt > 0; ...
|
||||||
|
|
||||||
|
// swap buffers
|
||||||
|
invis_buf_idx = 1 - invis_buf_idx;
|
||||||
|
|
||||||
|
} // for( ; ; )
|
||||||
|
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// execute a system step (and monitor step afterwards)
|
||||||
|
// - callbacks in context are called for every event (e.g. a successor state)
|
||||||
|
// - returns instruction callback status
|
||||||
|
static et_ic_status instr_sys_step( st_global_state_header *p_glob, // state to start with
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register
|
||||||
|
unsigned int succ_cb_flags, // flags already accumulated for successor callback
|
||||||
|
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
|
||||||
|
void *p_int_ctx, // private context for int_succ_cb
|
||||||
|
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
|
||||||
|
{
|
||||||
|
// get enabled processes
|
||||||
|
st_process_header *procs[PID_MAX]; // there cannot be more than PID_MAX processes
|
||||||
|
unsigned int proc_cnt = global_state_get_enabled_processes( p_glob, procs, count( procs ) );
|
||||||
|
if( proc_cnt == (unsigned int)-1 ) // too many enabled processes
|
||||||
|
return p_succ_ctx->err_cb( IE_EN_PROC_CNT, 0, 0, p_succ_ctx->priv_context );
|
||||||
|
|
||||||
|
// execute a step in every enabled process / in the process running exclusively
|
||||||
|
unsigned int sys_succ_cnt_start = p_succ_cnts->sys;
|
||||||
|
int timeout;
|
||||||
|
for( timeout = 0; timeout <= 1; timeout++ ) // first try timeout = 0, then try timeout = 1
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
// a process is running exclusively (and it is not the monitor)
|
||||||
|
if( p_glob->excl_pid != h2be_pid( 0 ) && p_glob->excl_pid != p_glob->monitor_pid )
|
||||||
|
{
|
||||||
|
for( i = 0; i < proc_cnt; i++ ) // search this process
|
||||||
|
if( procs[i]->pid == p_glob->excl_pid )
|
||||||
|
break;
|
||||||
|
if( i < proc_cnt ) // found this process
|
||||||
|
{
|
||||||
|
if( instr_proc_steps( p_glob, procs[i],
|
||||||
|
flag_reg, timeout,
|
||||||
|
0, // executing normal system (not monitor)
|
||||||
|
succ_cb_flags, int_succ_cb, p_int_ctx,
|
||||||
|
p_succ_ctx, p_succ_cnts ) == IC_STOP ) // execute this process
|
||||||
|
return IC_STOP; // some callback requested stop
|
||||||
|
if( p_succ_cnts->sys > sys_succ_cnt_start ) // process can do a step
|
||||||
|
return IC_CONTINUE; // ignore other processes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute every enabled process (except monitor)
|
||||||
|
for( i = 0; i < proc_cnt; i++ )
|
||||||
|
if( procs[i]->pid != p_glob->monitor_pid )
|
||||||
|
if( instr_proc_steps( p_glob, procs[i],
|
||||||
|
flag_reg, timeout,
|
||||||
|
0, // executing normal system (not monitor)
|
||||||
|
succ_cb_flags, int_succ_cb, p_int_ctx,
|
||||||
|
p_succ_ctx, p_succ_cnts ) == IC_STOP )
|
||||||
|
return IC_STOP; // some callback requested stop
|
||||||
|
if( p_succ_cnts->sys > sys_succ_cnt_start ) // at least one successor state
|
||||||
|
return IC_CONTINUE; // do not try again with timeout set
|
||||||
|
|
||||||
|
// set timeout flag
|
||||||
|
succ_cb_flags |= INSTR_SUCC_CB_FLAG_TIMEOUT;
|
||||||
|
}
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// execute a monitor step
|
||||||
|
// - callbacks in context are called for every event (e.g. a successor state)
|
||||||
|
// - returns instruction callback status
|
||||||
|
static et_ic_status instr_monitor_step( st_global_state_header *p_glob, // state to start with
|
||||||
|
uint8_t last_pid, // pid of process that executed last step
|
||||||
|
unsigned int succ_cb_flags, // flags already accumulated for successor callback
|
||||||
|
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
|
||||||
|
void *p_int_ctx, // private context for int_succ_cb
|
||||||
|
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
|
||||||
|
{
|
||||||
|
// get monitor process if available
|
||||||
|
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
|
||||||
|
st_process_header *p_monitor = NULL;
|
||||||
|
if( monitor_pid != 0 )
|
||||||
|
p_monitor = global_state_get_process( p_glob, monitor_pid );
|
||||||
|
|
||||||
|
// monitor process is not available or terminated
|
||||||
|
if( p_monitor == NULL ||
|
||||||
|
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// monitor process exists
|
||||||
|
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_EXIST;
|
||||||
|
|
||||||
|
// execute a step in the monitor process
|
||||||
|
unsigned int succ_cnt_start = p_succ_cnts->total;
|
||||||
|
int timeout;
|
||||||
|
for( timeout = 0; timeout <= 1; timeout++ ) // first try timeout = 0, then try timeout = 1
|
||||||
|
{
|
||||||
|
// execute monitor process
|
||||||
|
if( instr_proc_steps( p_glob, p_monitor,
|
||||||
|
0, timeout, // monitor starts always with flag_reg = 0
|
||||||
|
last_pid, // executing monitor
|
||||||
|
succ_cb_flags, int_succ_cb, p_int_ctx,
|
||||||
|
p_succ_ctx, p_succ_cnts ) == IC_STOP )
|
||||||
|
return IC_STOP; // some callback requested stop
|
||||||
|
if( p_succ_cnts->total > succ_cnt_start ) // at least one successor state
|
||||||
|
return IC_CONTINUE; // do not try again with timeout set
|
||||||
|
}
|
||||||
|
|
||||||
|
// when we get here, there was no successor state with timeout = 0 and none with timeout = 1
|
||||||
|
// ---> monitor process is blocked
|
||||||
|
// ---> no successor state
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal successor callback function for monitor successor states
|
||||||
|
et_ic_status instr_monitor_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
|
||||||
|
t_pid pid, // pid of process that executed
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
unsigned int succ_cb_flags, // flags accumulated so far
|
||||||
|
st_instr_succ_context *p_succ_ctx, // context for successor state generation
|
||||||
|
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
|
||||||
|
void *vp_prm_sys ) // private context: saved settings of system
|
||||||
|
{
|
||||||
|
st_instr_prm_save_monitor *p_prm_sys = (st_instr_prm_save_monitor *)vp_prm_sys;
|
||||||
|
|
||||||
|
// synchronous communication is still going on
|
||||||
|
if( p_succ->sync_comm )
|
||||||
|
// synchronous communication in monitor is not allowed -> invalid state
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// monitor executed a step
|
||||||
|
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_EXEC;
|
||||||
|
|
||||||
|
// set flags if monitor is in accepting state
|
||||||
|
st_process_header *p_monitor = global_state_get_process( p_succ->p_glob, pid );
|
||||||
|
if( p_monitor != NULL &&
|
||||||
|
bytecode_flags( p_succ_ctx->bytecode, be2h_pc( p_monitor->pc ) ) & BC_FLAG_ACCEPT )
|
||||||
|
{
|
||||||
|
p_monitor->flags |= PROCESS_FLAGS_MONITOR_ACCEPT; // set flag in process header of monitor process
|
||||||
|
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT; // set flag for successor callback
|
||||||
|
}
|
||||||
|
// set flag if monitor is terminated
|
||||||
|
if( p_monitor == NULL ||
|
||||||
|
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
|
||||||
|
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_TERM; // set flag for successor callback
|
||||||
|
|
||||||
|
// count state and report it to user
|
||||||
|
p_succ_cnts->total++;
|
||||||
|
st_instr_succ_output succ_out = // assemble structure with output
|
||||||
|
{
|
||||||
|
.p_out_sys1st = p_prm_sys->p_prm_1st->p_output, // output of system during 1st part of sync. comm.
|
||||||
|
.p_out_sys = p_prm_sys->p_output, // output of system
|
||||||
|
.p_out_monitor = p_succ->p_output // output of monitor
|
||||||
|
};
|
||||||
|
return p_succ_ctx->succ_cb( p_succ->p_glob, // report resulting state
|
||||||
|
p_prm_sys->p_prm_1st->label, p_prm_sys->label, // pass on saved settings of system
|
||||||
|
p_prm_sys->p_prm_1st->flag_reg, p_prm_sys->flag_reg,
|
||||||
|
succ_cb_flags, // pass on calulated flags
|
||||||
|
&succ_out,
|
||||||
|
p_succ_ctx->priv_context );
|
||||||
|
|
||||||
|
// keep compiler happy
|
||||||
|
flag_reg = 0;
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// execute monitor on system successor state
|
||||||
|
static et_ic_status instr_exec_monitor( st_instr_tmp_succ *p_sys_succ, // successor state of system (with label, flag_reg, ...)
|
||||||
|
st_instr_prm_save_sync *p_prm_1st, // saved parameters of 1st part of sync. comm. of system
|
||||||
|
uint8_t last_pid, // pid of process that executed last step
|
||||||
|
unsigned int succ_cb_flags, // flags already accumulated for successor callback
|
||||||
|
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
|
||||||
|
{
|
||||||
|
// count system's successor state
|
||||||
|
// - monitor is executed on every successor state of system
|
||||||
|
// - so system's successor states can be counted here
|
||||||
|
p_succ_cnts->sys++;
|
||||||
|
|
||||||
|
// save parameters returned by normal system
|
||||||
|
st_instr_prm_save_monitor prm_sys =
|
||||||
|
{
|
||||||
|
.p_prm_1st = p_prm_1st, // saved settings from 1st part of sync. comm.
|
||||||
|
.label = p_sys_succ->label, // label returned by normal system
|
||||||
|
.flag_reg = p_sys_succ->flag_reg, // flag register value returned by normal system
|
||||||
|
.p_output = p_sys_succ->p_output, // output done by normal system
|
||||||
|
};
|
||||||
|
|
||||||
|
// there is a monitor process (or at least a pid of some former monitor process)
|
||||||
|
if( p_sys_succ->p_glob->monitor_pid != h2be_pid( 0 ) )
|
||||||
|
{
|
||||||
|
// execute a monitor step
|
||||||
|
if( instr_monitor_step( p_sys_succ->p_glob, last_pid, succ_cb_flags,
|
||||||
|
instr_monitor_succ, (void *)&prm_sys, // monitor callback with saved settings of system as context
|
||||||
|
p_succ_ctx, p_succ_cnts ) == IC_STOP )
|
||||||
|
return IC_STOP; // some callback requested stop
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// when we get here, there is no monitor process
|
||||||
|
|
||||||
|
// count original system successor state and report it to user
|
||||||
|
p_succ_cnts->total++;
|
||||||
|
st_instr_succ_output succ_out = // assemble structure with output
|
||||||
|
{
|
||||||
|
.p_out_sys1st = p_prm_1st->p_output, // output of system during 1st part of sync. comm.
|
||||||
|
.p_out_sys = p_sys_succ->p_output, // output of system
|
||||||
|
.p_out_monitor = NULL // no output of monitor
|
||||||
|
};
|
||||||
|
return p_succ_ctx->succ_cb( p_sys_succ->p_glob, // report system state
|
||||||
|
p_prm_1st->label, p_sys_succ->label, // pass on settings of system
|
||||||
|
p_prm_1st->flag_reg, p_sys_succ->flag_reg,
|
||||||
|
succ_cb_flags, // pass on flags of system
|
||||||
|
&succ_out,
|
||||||
|
p_succ_ctx->priv_context );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal successor callback function for 2nd part of synchronous communication
|
||||||
|
et_ic_status instr_sync_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
|
||||||
|
t_pid pid, // pid of process that executed
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
unsigned int succ_cb_flags, // flags accumulated so far
|
||||||
|
st_instr_succ_context *p_succ_ctx, // context for successor state generation
|
||||||
|
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
|
||||||
|
void *vp_prm_1st ) // private context: saved settings of 1st part of sync. comm.
|
||||||
|
{
|
||||||
|
st_instr_prm_save_sync *p_prm_1st = (st_instr_prm_save_sync *)vp_prm_1st;
|
||||||
|
|
||||||
|
// synchronous communication is still going on
|
||||||
|
if( p_succ->sync_comm )
|
||||||
|
// this is not a valid state
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// execute monitor
|
||||||
|
return instr_exec_monitor( p_succ, // start from system successor state
|
||||||
|
p_prm_1st, // with saved setting from 1st part of sync. comm.
|
||||||
|
pid, // tell monitor process which process did the last step
|
||||||
|
succ_cb_flags, // pass on flags
|
||||||
|
p_succ_ctx, p_succ_cnts );
|
||||||
|
|
||||||
|
// keep compiler happy
|
||||||
|
flag_reg = 0;
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal successor callback function for system successor states
|
||||||
|
et_ic_status instr_sys_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
|
||||||
|
t_pid pid, // pid of process that executed
|
||||||
|
t_flag_reg flag_reg, // initial value for flag register of process
|
||||||
|
int timeout, // boolean flag if timeout
|
||||||
|
unsigned int succ_cb_flags, // flags accumulated so far
|
||||||
|
st_instr_succ_context *p_succ_ctx, // context for successor state generation
|
||||||
|
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
|
||||||
|
void *p_unused ) // private context
|
||||||
|
{
|
||||||
|
// no synchronous communication is going on
|
||||||
|
if( ! p_succ->sync_comm )
|
||||||
|
{
|
||||||
|
// create some dummy parameters to pass on
|
||||||
|
st_instr_prm_save_sync dummy_1st = { .label = 0, .flag_reg = 0, .p_output = NULL };
|
||||||
|
// execute monitor
|
||||||
|
return instr_exec_monitor( p_succ, // start from system successor state
|
||||||
|
&dummy_1st, // with saved setting from 1st part of sync. comm.
|
||||||
|
pid, // tell monitor process which process did the last step
|
||||||
|
succ_cb_flags, // pass on flags
|
||||||
|
p_succ_ctx, p_succ_cnts );
|
||||||
|
}
|
||||||
|
|
||||||
|
// save parameters of 1st part for 2nd part
|
||||||
|
st_instr_prm_save_sync prm_1st =
|
||||||
|
{
|
||||||
|
.label = p_succ->label, // label returned by 1st part
|
||||||
|
.flag_reg = p_succ->flag_reg, // flag register value returned by 1st part
|
||||||
|
.p_output = p_succ->p_output, // output done by 1st part
|
||||||
|
};
|
||||||
|
|
||||||
|
// get enabled processes
|
||||||
|
st_process_header *procs[PID_MAX]; // there cannot be more than PID_MAX processes
|
||||||
|
unsigned int proc_cnt = global_state_get_enabled_processes( p_succ->p_glob, procs, count( procs ) );
|
||||||
|
if( proc_cnt == (unsigned int)-1 ) // too many enabled processes
|
||||||
|
return p_succ_ctx->err_cb( IE_EN_PROC_CNT, 0, 0, p_succ_ctx->priv_context );
|
||||||
|
|
||||||
|
// let possible receivers receive message synchronously
|
||||||
|
unsigned int i;
|
||||||
|
for( i = 0; i < proc_cnt; i++ ) // execute every enabled process
|
||||||
|
if( procs[i]->pid != p_succ->p_glob->monitor_pid && // except monitor and sender
|
||||||
|
procs[i]->pid != h2be_pid( pid ) )
|
||||||
|
if( instr_proc_steps( p_succ->p_glob, procs[i],
|
||||||
|
flag_reg, timeout, // start with same flag_reg value and timeout setting as 1st part
|
||||||
|
0, // executing normal system (not monitor)
|
||||||
|
succ_cb_flags | INSTR_SUCC_CB_FLAG_SYNC, // add flag for synchronous communication
|
||||||
|
instr_sync_succ, (void *)&prm_1st, // sync. comm. callback with saved settings of 1st part as context
|
||||||
|
p_succ_ctx, p_succ_cnts ) == IC_STOP )
|
||||||
|
return IC_STOP; // some callback requested stop
|
||||||
|
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// keep compiler happy
|
||||||
|
p_unused = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** functions visible from outside ***
|
||||||
|
|
||||||
|
|
||||||
|
// initialize context with default maximum values
|
||||||
|
// only fills in maximum values and bytecode
|
||||||
|
// does not touch pointers to callback functions
|
||||||
|
void instr_succ_context_default( st_instr_succ_context *succ_ctx, st_bytecode *bytecode ) // extern
|
||||||
|
{
|
||||||
|
succ_ctx->stack_max = INSTR_DEF_STACK_MAX;
|
||||||
|
succ_ctx->state_mem = INSTR_DEF_STATE_MEM;
|
||||||
|
succ_ctx->enab_state_mem = INSTR_DEF_ENAB_STATE_MEM;
|
||||||
|
succ_ctx->invis_mem = INSTR_DEF_INVIS_MEM;
|
||||||
|
succ_ctx->path_max = INSTR_DEF_PATH_MAX;
|
||||||
|
succ_ctx->invis_max = INSTR_DEF_INVIS_MAX;
|
||||||
|
succ_ctx->succ_max = INSTR_DEF_SUCC_MAX;
|
||||||
|
succ_ctx->bytecode = bytecode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states
|
||||||
|
// callbacks in context are called for every event (e.g. a successor state)
|
||||||
|
// returns number of successor states that were reported to successor callback
|
||||||
|
unsigned int instr_succ( st_global_state_header *p_glob, // state to start with
|
||||||
|
t_flag_reg flag_reg, // value to put into flag register
|
||||||
|
st_instr_succ_context *succ_ctx ) // extern
|
||||||
|
{
|
||||||
|
// get monitor process in original state
|
||||||
|
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
|
||||||
|
st_process_header *p_monitor = NULL;
|
||||||
|
|
||||||
|
// there is a monitor process (or at least a pid of some former monitor process)
|
||||||
|
if( monitor_pid != 0 )
|
||||||
|
{
|
||||||
|
// get monitor process
|
||||||
|
p_monitor = global_state_get_process( p_glob, monitor_pid );
|
||||||
|
// monitor not available or terminated
|
||||||
|
if( p_monitor == NULL ||
|
||||||
|
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
|
||||||
|
{
|
||||||
|
// report original state as successor state to user
|
||||||
|
st_instr_succ_output succ_out = // structure with output: none
|
||||||
|
{
|
||||||
|
.p_out_sys1st = NULL, // output of system during 1st part of sync. comm.
|
||||||
|
.p_out_sys = NULL, // output of system
|
||||||
|
.p_out_monitor = NULL // output of monitor
|
||||||
|
};
|
||||||
|
succ_ctx->succ_cb( p_glob, // report original state
|
||||||
|
0, 0, 0, 0,
|
||||||
|
INSTR_SUCC_CB_FLAG_MONITOR_EXIST | INSTR_SUCC_CB_FLAG_MONITOR_TERM,
|
||||||
|
&succ_out,
|
||||||
|
succ_ctx->priv_context );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute a step in system (and monitor step afterwards)
|
||||||
|
st_instr_succ_cnts succ_cnts = { .sys = 0, .total = 0 };
|
||||||
|
instr_sys_step( p_glob, flag_reg,
|
||||||
|
0, // no successor callback flags yet
|
||||||
|
instr_sys_succ, NULL, // system successor callback and context
|
||||||
|
succ_ctx, &succ_cnts );
|
||||||
|
// done if at least one successor state of system
|
||||||
|
if( succ_cnts.sys > 0 )
|
||||||
|
return succ_cnts.total;
|
||||||
|
|
||||||
|
// when we get here, the system is blocked
|
||||||
|
|
||||||
|
// extension of finite paths only if monitor is present.
|
||||||
|
if (monitor_pid == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// report original state as successor state to user
|
||||||
|
st_instr_succ_output succ_out = // structure with output: none
|
||||||
|
{
|
||||||
|
.p_out_sys1st = NULL, // output of system during 1st part of sync. comm.
|
||||||
|
.p_out_sys = NULL, // output of system
|
||||||
|
.p_out_monitor = NULL // output of monitor
|
||||||
|
};
|
||||||
|
succ_ctx->succ_cb( p_glob, // report original state
|
||||||
|
0, 0, 0, 0,
|
||||||
|
INSTR_SUCC_CB_FLAG_SYS_BLOCK |
|
||||||
|
(p_monitor != NULL ? INSTR_SUCC_CB_FLAG_MONITOR_EXIST : 0) |
|
||||||
|
(p_monitor != NULL && (p_monitor->flags & PROCESS_FLAGS_MONITOR_ACCEPT) ? INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT : 0),
|
||||||
|
&succ_out,
|
||||||
|
succ_ctx->priv_context );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
44
iface/nips/nips_vm/instr_step.h
Normal file
44
iface/nips/nips_vm/instr_step.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_instr_step
|
||||||
|
#define INC_instr_step
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
|
||||||
|
// initialize context with default maximum values
|
||||||
|
// only fills in maximum values and bytecode
|
||||||
|
// does not touch pointers to callback functions
|
||||||
|
extern void instr_succ_context_default( st_instr_succ_context *succ_ctx, st_bytecode *bytecode );
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states
|
||||||
|
// callbacks in context are called for every event (e.g. a successor state)
|
||||||
|
// returns number of successor states that were reported to successor callback
|
||||||
|
extern unsigned int instr_succ( st_global_state_header *p_glob, // state to start with
|
||||||
|
t_flag_reg flag_reg, // value to put into flag register
|
||||||
|
st_instr_succ_context *succ_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_instr_step
|
||||||
168
iface/nips/nips_vm/instr_tools.c
Normal file
168
iface/nips/nips_vm/instr_tools.c
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "instr_tools.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
// convert runtime error to string
|
||||||
|
int
|
||||||
|
nipsvm_errorstring( char *str, size_t size, nipsvm_errorcode_t err,
|
||||||
|
nipsvm_pid_t pid, nipsvm_pc_t pc ) // extern
|
||||||
|
{
|
||||||
|
switch( err )
|
||||||
|
{
|
||||||
|
case IE_BYTECODE: return snprintf( str, size, "bytecode segmentation fault (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_INVOP: return snprintf( str, size, "invalid opcode (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_GLOBAL: return snprintf( str, size, "invalid global memory access (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_LOCAL: return snprintf( str, size, "invalid local memory access (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_STACKOV: return snprintf( str, size, "stack overflow (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_STACKUN: return snprintf( str, size, "stack underflow (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_DIV0: return snprintf( str, size, "division by zero (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_OV: return snprintf( str, size, "overflow error (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_INDEX: return snprintf( str, size, "invalid array index (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_ASSERT: return snprintf( str, size, "assertion violated (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_INV_PROC_ID: return snprintf( str, size, "invalid process id (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_NO_PROC: return snprintf( str, size, "no process with specified process id (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_INV_CHAN_ID: return snprintf( str, size, "invalid channel id (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_NO_CHAN: return snprintf( str, size, "no channel with specified channel id (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_INV_CHAN_TYPE: return snprintf( str, size, "invalid channel type (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_CHAN_OV: return snprintf( str, size, "channel overflow (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_CHAN_UN: return snprintf( str, size, "channel underflow (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_CHAN_EMPTY: return snprintf( str, size, "channel is empty, but message is needed here (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_PROC_CNT: return snprintf( str, size, "too many processes (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_CHAN_CNT: return snprintf( str, size, "too many channels (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_PATH_CNT: return snprintf( str, size, "too many parallel execution paths (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_SUCC_CNT: return snprintf( str, size, "too many possible successor states (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_STATE_MEM: return snprintf( str, size, "out of temporary state memory (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
case IE_NO_ACT_PROC: return snprintf( str, size, "INTERNAL ERROR: no active process" ); // no pid or pc here
|
||||||
|
case IE_EN_PROC_CNT: return snprintf( str, size, "too many enabled processes" ); // no pid or pc here
|
||||||
|
case IE_INVIS_MEM: return snprintf( str, size, "out of memory for invisible states (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
default: return snprintf( str, size, "unknown error (pid=%d, pc=0x%08X)", pid, pc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert output entries (recursively) to string (without terminating 0)
|
||||||
|
// *pp_buf: pointer into buffer, advanced by this function
|
||||||
|
// *p_buf_len: remaining length of buffer, decreased by this function
|
||||||
|
// returns -1 on error, 0 on success
|
||||||
|
static int instr_output_entry_to_str( st_bytecode *bytecode, st_instr_output *p_output,
|
||||||
|
char **p_buf, unsigned long *p_buf_len )
|
||||||
|
{
|
||||||
|
char *str, buf[32];
|
||||||
|
|
||||||
|
// nothing to print
|
||||||
|
if( p_output == NULL )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// process previous entries
|
||||||
|
if( instr_output_entry_to_str( bytecode, p_output->p_prev, p_buf, p_buf_len ) < 0 )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// string
|
||||||
|
if( p_output->is_str )
|
||||||
|
{
|
||||||
|
if( p_output->data.str.str < bytecode->string_cnt )
|
||||||
|
str = bytecode->strings[p_output->data.str.str];
|
||||||
|
else
|
||||||
|
sprintf( str = buf, "STRING(%d)", p_output->data.str.str );
|
||||||
|
}
|
||||||
|
|
||||||
|
// value
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch( p_output->data.value.fmt ) // print formatted value
|
||||||
|
{
|
||||||
|
case 'c': case 'C': sprintf( str = buf, "%c", p_output->data.value.value ); break;
|
||||||
|
case 'd': case 'D': sprintf( str = buf, "%d", p_output->data.value.value ); break;
|
||||||
|
case 'e': case 'E': if( p_output->data.value.value < bytecode->string_cnt )
|
||||||
|
str = bytecode->strings[p_output->data.value.value];
|
||||||
|
else
|
||||||
|
sprintf( str = buf, "STRING(%d)", p_output->data.value.value );
|
||||||
|
break;
|
||||||
|
case 'o': case 'O': sprintf( str = buf, "%o", p_output->data.value.value ); break;
|
||||||
|
case 'u': case 'U': sprintf( str = buf, "%u", p_output->data.value.value ); break;
|
||||||
|
case 'x': sprintf( str = buf, "%x", p_output->data.value.value ); break;
|
||||||
|
case 'X': sprintf( str = buf, "%X", p_output->data.value.value ); break;
|
||||||
|
default: sprintf( str = buf, "%d", p_output->data.value.value ); // default is decimal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy string into buffer
|
||||||
|
unsigned int len = strlen( str );
|
||||||
|
if( *p_buf_len < strlen( str ) )
|
||||||
|
return -1;
|
||||||
|
memcpy( *p_buf, str, len );
|
||||||
|
*p_buf += len;
|
||||||
|
*p_buf_len -= len;
|
||||||
|
|
||||||
|
// success
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// convert output list to string
|
||||||
|
// *pp_buf: pointer into buffer, advanced by this function
|
||||||
|
// *p_buf_len: remaining length of buffer, decreased by this function
|
||||||
|
// returns pointer to 0-terminated string in buffer or NULL in case of error
|
||||||
|
char * instr_output_to_str( st_bytecode *bytecode, st_instr_output *p_output,
|
||||||
|
char **p_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
// remember start of string
|
||||||
|
char *start = *p_buf;
|
||||||
|
|
||||||
|
// convert output list
|
||||||
|
if( instr_output_entry_to_str( bytecode, p_output, p_buf, p_buf_len ) < 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// add terminating 0
|
||||||
|
if( *p_buf_len < 1 )
|
||||||
|
return NULL;
|
||||||
|
**p_buf = 0;
|
||||||
|
(*p_buf)++;
|
||||||
|
(*p_buf_len)--;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// convert output during successor state generation to string
|
||||||
|
// *pp_buf: pointer into buffer, advanced by this function
|
||||||
|
// *p_buf_len: remaining length of buffer, decreased by this function
|
||||||
|
// returns pointer to 0-terminated string in buffer or NULL in case of error
|
||||||
|
char * instr_succ_output_to_str( st_bytecode *bytecode, st_instr_succ_output *p_succ_out,
|
||||||
|
char **p_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
// remember start of string
|
||||||
|
char *start = *p_buf;
|
||||||
|
|
||||||
|
// convert output of system during 1st part of sync. comm.
|
||||||
|
if( instr_output_entry_to_str( bytecode, p_succ_out->p_out_sys1st, p_buf, p_buf_len ) < 0 )
|
||||||
|
return NULL;
|
||||||
|
// convert output of system
|
||||||
|
if( instr_output_entry_to_str( bytecode, p_succ_out->p_out_sys, p_buf, p_buf_len ) < 0 )
|
||||||
|
return NULL;
|
||||||
|
// convert output of monitor
|
||||||
|
if( instr_output_entry_to_str( bytecode, p_succ_out->p_out_monitor, p_buf, p_buf_len ) < 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// add terminating 0
|
||||||
|
if( *p_buf_len < 1 )
|
||||||
|
return NULL;
|
||||||
|
**p_buf = 0;
|
||||||
|
(*p_buf)++;
|
||||||
|
(*p_buf_len)--;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
45
iface/nips/nips_vm/instr_tools.h
Normal file
45
iface/nips/nips_vm/instr_tools.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_instr_tools
|
||||||
|
#define INC_instr_tools
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
// convert output list to string
|
||||||
|
// *pp_buf: pointer into buffer, advanced by this function
|
||||||
|
// *p_buf_len: remaining length of buffer, decreased by this function
|
||||||
|
// returns pointer to 0-terminated string in buffer or NULL in case of error
|
||||||
|
extern char * instr_output_to_str( st_bytecode *bytecode, st_instr_output *p_output,
|
||||||
|
char **p_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// convert output during successor state generation to string
|
||||||
|
// *pp_buf: pointer into buffer, advanced by this function
|
||||||
|
// *p_buf_len: remaining length of buffer, decreased by this function
|
||||||
|
// returns pointer to 0-terminated string in buffer or NULL in case of error
|
||||||
|
extern char * instr_succ_output_to_str( st_bytecode *bytecode, st_instr_succ_output *p_succ_out,
|
||||||
|
char **p_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_instr_tools
|
||||||
215
iface/nips/nips_vm/instr_wrap.c
Normal file
215
iface/nips/nips_vm/instr_wrap.c
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "instr_step.h"
|
||||||
|
#include "instr_tools.h"
|
||||||
|
#include "instr_wrap.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
// *** helper functions ***
|
||||||
|
|
||||||
|
// private context for instr_succ_buf
|
||||||
|
typedef struct t_instr_succ_buf_ctx
|
||||||
|
{
|
||||||
|
unsigned long succ_cnt;
|
||||||
|
st_global_state_header **p_succ;
|
||||||
|
unsigned long succ_max;
|
||||||
|
char **pp_buf;
|
||||||
|
unsigned long *p_buf_len;
|
||||||
|
} st_instr_succ_buf_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
// successor callback function for instr_succ_buf
|
||||||
|
et_ic_status instr_succ_buf_succ_cb( st_global_state_header *succ,
|
||||||
|
uint8_t label_1st, uint8_t label,
|
||||||
|
t_flag_reg flag_reg_1st, t_flag_reg flag_reg,
|
||||||
|
unsigned int succ_cb_flags,
|
||||||
|
st_instr_succ_output *p_succ_out,
|
||||||
|
void *priv_context )
|
||||||
|
{
|
||||||
|
st_instr_succ_buf_ctx *p_ctx = (st_instr_succ_buf_ctx *)priv_context;
|
||||||
|
// copy successor state into buffer and save pointer to it
|
||||||
|
if( p_ctx->succ_cnt >= p_ctx->succ_max )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: too many successor states (try \"-s\")\n" );
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
p_ctx->p_succ[p_ctx->succ_cnt] = global_state_copy( succ, p_ctx->pp_buf, p_ctx->p_buf_len );
|
||||||
|
if( p_ctx->p_succ[p_ctx->succ_cnt] == NULL )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: out of state memory (try \"-b\")\n" );
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
p_ctx->succ_cnt++;
|
||||||
|
// go on finding successor states
|
||||||
|
return IC_CONTINUE;
|
||||||
|
// keep compiler happy
|
||||||
|
label_1st = 0;
|
||||||
|
label = 0;
|
||||||
|
flag_reg_1st = 0;
|
||||||
|
flag_reg = 0;
|
||||||
|
succ_cb_flags = 0;
|
||||||
|
p_succ_out = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private context for instr_succ_buf_ex
|
||||||
|
typedef struct t_instr_succ_buf_ex_ctx
|
||||||
|
{
|
||||||
|
unsigned long succ_cnt;
|
||||||
|
st_instr_succ_buf_ex_state *succ;
|
||||||
|
unsigned long succ_max;
|
||||||
|
char **pp_buf;
|
||||||
|
unsigned long *p_buf_len;
|
||||||
|
int process_output;
|
||||||
|
st_bytecode *bytecode;
|
||||||
|
} st_instr_succ_buf_ex_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
// successor callback function for instr_succ_buf_ex
|
||||||
|
et_ic_status instr_succ_buf_ex_succ_cb( st_global_state_header *succ,
|
||||||
|
uint8_t label_1st, uint8_t label,
|
||||||
|
t_flag_reg flag_reg_1st, t_flag_reg flag_reg,
|
||||||
|
unsigned int succ_cb_flags,
|
||||||
|
st_instr_succ_output *p_succ_out,
|
||||||
|
void *priv_context )
|
||||||
|
{
|
||||||
|
st_instr_succ_buf_ex_ctx *p_ctx = (st_instr_succ_buf_ex_ctx *)priv_context;
|
||||||
|
// copy successor state into buffer and save pointer to it
|
||||||
|
if( p_ctx->succ_cnt >= p_ctx->succ_max )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: too many successor states (try \"-s\")\n" );
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].p_state = global_state_copy( succ, p_ctx->pp_buf, p_ctx->p_buf_len ); // save successor state
|
||||||
|
if( p_ctx->succ[p_ctx->succ_cnt].p_state == NULL )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: out of state memory (try \"-b\")\n" );
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].label_1st = label_1st; // save additional information
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].label = label;
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].flag_reg_1st = flag_reg_1st;
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].flag_reg = flag_reg;
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].succ_cb_flags = succ_cb_flags;
|
||||||
|
if( p_ctx->process_output ) // save output string
|
||||||
|
{
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].p_output = instr_succ_output_to_str( p_ctx->bytecode, p_succ_out,
|
||||||
|
p_ctx->pp_buf, p_ctx->p_buf_len );
|
||||||
|
if( p_ctx->succ[p_ctx->succ_cnt].p_output == NULL )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: out of state memory (try \"-b\")\n" );
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // do not save output string
|
||||||
|
p_ctx->succ[p_ctx->succ_cnt].p_output = NULL;
|
||||||
|
p_ctx->succ_cnt++;
|
||||||
|
// go on finding successor states
|
||||||
|
return IC_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** functions visible from outside ***
|
||||||
|
|
||||||
|
|
||||||
|
// initialize successor state generation context for instr_succ_buf
|
||||||
|
// must be called before instr_succ_buf (only 1 time, not every time)
|
||||||
|
void instr_succ_buf_prepare( st_instr_succ_context *succ_ctx,
|
||||||
|
st_bytecode *bytecode ) // extern
|
||||||
|
{
|
||||||
|
// set default maximum values and bytecode
|
||||||
|
instr_succ_context_default( succ_ctx, bytecode );
|
||||||
|
|
||||||
|
// set callbacks
|
||||||
|
succ_ctx->succ_cb = instr_succ_buf_succ_cb;
|
||||||
|
succ_ctx->err_cb = nipsvm_default_error_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states in a buffer
|
||||||
|
// pointers to states are put into array pointed to by p_succ
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for successor states
|
||||||
|
// returns number of successor states
|
||||||
|
unsigned long instr_succ_buf( st_instr_succ_context *succ_ctx, // must be initialized with instr_succ_buf_prepare
|
||||||
|
st_global_state_header *p_glob, // state to start with
|
||||||
|
st_global_state_header **p_succ, unsigned long succ_max,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
// set up private context
|
||||||
|
st_instr_succ_buf_ctx ctx =
|
||||||
|
{
|
||||||
|
.succ_cnt = 0,
|
||||||
|
.p_succ = p_succ,
|
||||||
|
.succ_max = succ_max,
|
||||||
|
.pp_buf = pp_buf,
|
||||||
|
.p_buf_len = p_buf_len
|
||||||
|
};
|
||||||
|
succ_ctx->priv_context = &ctx; // put it into successor state generation context
|
||||||
|
|
||||||
|
// generate successor states - using normal successor function
|
||||||
|
instr_succ( p_glob, 0, succ_ctx );
|
||||||
|
|
||||||
|
// return number of successor states
|
||||||
|
return ctx.succ_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// initialize successor state generation context for instr_succ_buf_ex
|
||||||
|
// must be called before instr_succ_buf_ex (only 1 time, not every time)
|
||||||
|
void instr_succ_buf_ex_prepare( st_instr_succ_context *succ_ctx,
|
||||||
|
st_bytecode *bytecode ) // extern
|
||||||
|
{
|
||||||
|
// set default maximum values and bytecode
|
||||||
|
instr_succ_context_default( succ_ctx, bytecode );
|
||||||
|
|
||||||
|
// set callbacks
|
||||||
|
succ_ctx->succ_cb = instr_succ_buf_ex_succ_cb;
|
||||||
|
succ_ctx->err_cb = nipsvm_default_error_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states and extended information in a buffer
|
||||||
|
// state structure array succ is filled with results
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for successor states and output strings
|
||||||
|
// returns number of successor states
|
||||||
|
unsigned long instr_succ_buf_ex( st_instr_succ_context *succ_ctx, // must be initialized with instr_succ_buf_ex_prepare
|
||||||
|
st_global_state_header *p_glob, // state to start with
|
||||||
|
t_flag_reg flag_reg, // value to put into flag register
|
||||||
|
int process_output, // if to process output (from print instructions)
|
||||||
|
st_instr_succ_buf_ex_state *succ, unsigned long succ_max,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
// set up private context
|
||||||
|
st_instr_succ_buf_ex_ctx ctx =
|
||||||
|
{
|
||||||
|
.succ_cnt = 0,
|
||||||
|
.succ = succ,
|
||||||
|
.succ_max = succ_max,
|
||||||
|
.pp_buf = pp_buf,
|
||||||
|
.p_buf_len = p_buf_len,
|
||||||
|
.process_output = process_output,
|
||||||
|
.bytecode = succ_ctx->bytecode
|
||||||
|
};
|
||||||
|
succ_ctx->priv_context = &ctx; // put it into successor state generation context
|
||||||
|
|
||||||
|
// generate successor states - using normal successor function
|
||||||
|
instr_succ( p_glob, flag_reg, succ_ctx );
|
||||||
|
|
||||||
|
// return number of successor states
|
||||||
|
return ctx.succ_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
77
iface/nips/nips_vm/instr_wrap.h
Normal file
77
iface/nips/nips_vm/instr_wrap.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_instr_wrap
|
||||||
|
#define INC_instr_wrap
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
|
||||||
|
// successor state structure for instr_succ_buf_ex
|
||||||
|
typedef struct t_instr_succ_buf_ex_state
|
||||||
|
{
|
||||||
|
st_global_state_header *p_state; // the successor state
|
||||||
|
uint8_t label_1st; // label of STEP command of 1st part of sync. comm. (unused if ! sync)
|
||||||
|
uint8_t label; // label of STEP command (of 2nd part of sync. comm. if sync)
|
||||||
|
t_flag_reg flag_reg_1st; // flag register value returned by 1st part of sync. comm. (unused if ! sync)
|
||||||
|
t_flag_reg flag_reg; // flag register value returned (by 2nd part of sync. comm. if sync)
|
||||||
|
unsigned int succ_cb_flags; // boolean flags (if sync. comm. took place, if timeout occured, ...)
|
||||||
|
char *p_output; // pointer to 0-terminated output string (if process_output in instr_succ_buf_ex call was != 0)
|
||||||
|
} st_instr_succ_buf_ex_state;
|
||||||
|
|
||||||
|
|
||||||
|
// initialize successor state generation context for instr_succ_buf
|
||||||
|
// must be called before instr_succ_buf (only 1 time, not every time)
|
||||||
|
extern void instr_succ_buf_prepare( st_instr_succ_context *succ_ctx,
|
||||||
|
st_bytecode *bytecode );
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states in a buffer
|
||||||
|
// pointers to states are put into array pointed to by p_succ
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for successor states
|
||||||
|
// returns number of successor states
|
||||||
|
extern unsigned long instr_succ_buf( st_instr_succ_context *succ_ctx, // must be initialized with instr_succ_buf_prepare
|
||||||
|
st_global_state_header *p_glob, // state to start with
|
||||||
|
st_global_state_header **p_succ, unsigned long succ_max,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// initialize successor state generation context for instr_succ_buf_ex
|
||||||
|
// must be called before instr_succ_buf_ex (only 1 time, not every time)
|
||||||
|
extern void instr_succ_buf_ex_prepare( st_instr_succ_context *succ_ctx,
|
||||||
|
st_bytecode *bytecode );
|
||||||
|
|
||||||
|
|
||||||
|
// generate successor states and extended information in a buffer
|
||||||
|
// state structure array succ is filled with results
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for successor states and output strings
|
||||||
|
// returns number of successor states
|
||||||
|
extern unsigned long instr_succ_buf_ex( st_instr_succ_context *succ_ctx, // must be initialized with instr_succ_buf_ex_prepare
|
||||||
|
st_global_state_header *p_glob, // state to start with
|
||||||
|
t_flag_reg flag_reg, // value to put into flag register
|
||||||
|
int process_output, // if to process output (from print instructions)
|
||||||
|
st_instr_succ_buf_ex_state *succ, unsigned long succ_max,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_instr_wrap
|
||||||
207
iface/nips/nips_vm/interactive.c
Normal file
207
iface/nips/nips_vm/interactive.c
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 "bytecode.h"
|
||||||
|
//#include "instr.h"
|
||||||
|
//#include "instr_step.h"
|
||||||
|
#include "instr_wrap.h"
|
||||||
|
#include "rt_err.h"
|
||||||
|
#include "split.h"
|
||||||
|
//#include "state.h"
|
||||||
|
//#include "tools.h"
|
||||||
|
|
||||||
|
#include "interactive.h"
|
||||||
|
|
||||||
|
|
||||||
|
// do an interactive simulation stating from the initial state
|
||||||
|
// random: boolean flag if to replace interactivity by randomness
|
||||||
|
// rnd_quiet: if to suppress state output during random simulation
|
||||||
|
// print_hex: boolean flag if to print current states in hexadecimal
|
||||||
|
// split: boolean flag if to split up and reassemble states
|
||||||
|
// buffer_len: size of state buffer
|
||||||
|
// states_max: number of state pointer buffer entries
|
||||||
|
// ini_state: state to start simulation at (or NULL to use default)
|
||||||
|
void interactive_simulate( nipsvm_bytecode_t *bytecode,
|
||||||
|
int random, int rnd_quiet, int print_hex, int split,
|
||||||
|
unsigned long buffer_len, unsigned int states_max,
|
||||||
|
nipsvm_state_t *ini_state ) // extern
|
||||||
|
{
|
||||||
|
char *p_buffer, *p_buf;
|
||||||
|
nipsvm_state_t *p_cur;
|
||||||
|
t_flag_reg flag_reg;
|
||||||
|
st_instr_succ_buf_ex_state *states;
|
||||||
|
unsigned long buf_len, cnt, i, j, sel, len;
|
||||||
|
st_instr_succ_context succ_ctx;
|
||||||
|
|
||||||
|
// does monitor process exist?
|
||||||
|
if( bytecode_monitor_present( bytecode ) )
|
||||||
|
printf( "monitor process exists\n\n" );
|
||||||
|
|
||||||
|
// allocate buffer for states
|
||||||
|
p_buffer = (char *)malloc( buffer_len );
|
||||||
|
if( p_buffer == NULL )
|
||||||
|
rt_err( "out of memory (state buffer for interactive/random simulation)" );
|
||||||
|
// allocate buffer for successor state pointers
|
||||||
|
states = (st_instr_succ_buf_ex_state *)malloc( states_max * sizeof( st_instr_succ_buf_ex_state ) );
|
||||||
|
if( states == NULL )
|
||||||
|
rt_err( "out of memory (successor state pointer buffer for interactive/random simulation)" );
|
||||||
|
|
||||||
|
// get initial state
|
||||||
|
p_buf = p_buffer;
|
||||||
|
buf_len = buffer_len;
|
||||||
|
if( ini_state != NULL )
|
||||||
|
p_cur = global_state_copy( ini_state, &p_buf, &buf_len );
|
||||||
|
else
|
||||||
|
p_cur = global_state_initial( &p_buf, &buf_len );
|
||||||
|
if( p_cur == NULL )
|
||||||
|
rt_err( "state buffer too small for initial state" );
|
||||||
|
flag_reg = 0;
|
||||||
|
|
||||||
|
// initialize context for instr_succ_buf_ex
|
||||||
|
instr_succ_buf_ex_prepare( &succ_ctx, bytecode );
|
||||||
|
|
||||||
|
// scheduler loop
|
||||||
|
for( ; ; )
|
||||||
|
{
|
||||||
|
|
||||||
|
// show current state
|
||||||
|
if( ! random || ! rnd_quiet )
|
||||||
|
{
|
||||||
|
printf( "=== current state ===\n" );
|
||||||
|
global_state_print( p_cur );
|
||||||
|
printf( "ext info: flags=0x%X\n", flag_reg );
|
||||||
|
printf( "\n" );
|
||||||
|
|
||||||
|
// print current state in hexadecimal
|
||||||
|
if( print_hex )
|
||||||
|
{
|
||||||
|
len = nipsvm_state_size( p_cur );
|
||||||
|
for( i = 0, j = 0; i < len; )
|
||||||
|
{
|
||||||
|
printf( "%04lX:", i );
|
||||||
|
for( j = 0; i < len && j < 0x10; i++, j++ )
|
||||||
|
printf( " %02X", ((unsigned char *)p_cur)[i] );
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// split up and reassemble
|
||||||
|
if( split )
|
||||||
|
{
|
||||||
|
if( ! split_test( p_cur, stdout ) )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "split test failed\n" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate successor states
|
||||||
|
cnt = instr_succ_buf_ex( &succ_ctx, p_cur, flag_reg, 1 /* process output */,
|
||||||
|
states, states_max, &p_buf, &buf_len );
|
||||||
|
|
||||||
|
if( random )
|
||||||
|
{
|
||||||
|
|
||||||
|
// select a random state
|
||||||
|
if( cnt == 0 )
|
||||||
|
sel = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sel = rand( ) % cnt;
|
||||||
|
if( states[sel].p_output[0] != 0 ) // show output
|
||||||
|
{
|
||||||
|
if( rnd_quiet )
|
||||||
|
printf( "%s", states[sel].p_output );
|
||||||
|
else
|
||||||
|
printf( "output: \"%s\"\n\n", states[sel].p_output );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// show successor states
|
||||||
|
printf( "\n=== %ld successor state%s ===\n", cnt, cnt == 1 ? "" : "s" );
|
||||||
|
for( i = 0; i < cnt; i++ )
|
||||||
|
{
|
||||||
|
printf( "--- successor state %ld ---\n", i + 1 );
|
||||||
|
global_state_print( states[i].p_state );
|
||||||
|
printf( "ext info: " ); // show extended information
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_SYNC )
|
||||||
|
printf( "SYNC, label=%u flags=0x%X, label=%u flags=0x%X",
|
||||||
|
states[i].label_1st, states[i].flag_reg_1st,
|
||||||
|
states[i].label, states[i].flag_reg );
|
||||||
|
else
|
||||||
|
printf( "label=%u flags=0x%X",
|
||||||
|
states[i].label, states[i].flag_reg );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_TIMEOUT )
|
||||||
|
printf( ", TIMEOUT" );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_SYS_BLOCK )
|
||||||
|
printf( ", SYS_BLOCK" );
|
||||||
|
printf( "\n" );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_MONITOR_EXIST )
|
||||||
|
{
|
||||||
|
printf( "monitor: exists" );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_MONITOR_EXEC )
|
||||||
|
printf( ", executed" );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT )
|
||||||
|
printf( ", ACCEPT" );
|
||||||
|
if( states[i].succ_cb_flags & INSTR_SUCC_CB_FLAG_MONITOR_TERM )
|
||||||
|
printf( ", TERM" );
|
||||||
|
printf( "\n" );
|
||||||
|
}
|
||||||
|
if( states[i].p_output[0] != 0 ) // show output
|
||||||
|
printf( "output: \"%s\"\n", states[i].p_output );
|
||||||
|
}
|
||||||
|
printf( "\n" );
|
||||||
|
|
||||||
|
// let user select a state
|
||||||
|
if( cnt == 0 )
|
||||||
|
printf( "enter something to quit: " );
|
||||||
|
else if( cnt == 1 )
|
||||||
|
printf( "enter state number (1) or anything else to quit: " );
|
||||||
|
else
|
||||||
|
printf( "enter state number (1..%ld) or anything else to quit: ", cnt );
|
||||||
|
fflush( stdout );
|
||||||
|
scanf( "%lu", &sel );
|
||||||
|
printf( "\n" );
|
||||||
|
sel--; // convert to 0 based index
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// end requested
|
||||||
|
if( sel >= cnt )
|
||||||
|
break;
|
||||||
|
// system blocked in random mode -> end
|
||||||
|
if( random && states[sel].succ_cb_flags & INSTR_SUCC_CB_FLAG_SYS_BLOCK )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// keep flag register of selected state (just for testing)
|
||||||
|
flag_reg = states[sel].flag_reg;
|
||||||
|
|
||||||
|
// move selected state to beginning of buffer and use it as current state
|
||||||
|
len = nipsvm_state_size( states[sel].p_state );
|
||||||
|
memmove( p_buffer, states[sel].p_state, len );
|
||||||
|
p_buf = p_buffer + len;
|
||||||
|
buf_len = buffer_len - len;
|
||||||
|
p_cur = (nipsvm_state_t *)p_buffer;
|
||||||
|
|
||||||
|
} // for ( ; ; )
|
||||||
|
|
||||||
|
// free malloc-ed memory buffers
|
||||||
|
free( p_buffer );
|
||||||
|
free( states );
|
||||||
|
}
|
||||||
36
iface/nips/nips_vm/interactive.h
Normal file
36
iface/nips/nips_vm/interactive.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_interactive
|
||||||
|
#define INC_interactive
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// do an interactive simulation stating from the initial state
|
||||||
|
// random: boolean flag if to replace interactivity by randomness
|
||||||
|
// rnd_quiet: if to suppress state output during random simulation
|
||||||
|
// print_hex: boolean flag if to print current states in hexadecimal
|
||||||
|
// split: boolean flag if to split up and reassemble states
|
||||||
|
// buffer_len: size of state buffer
|
||||||
|
// states_max: number of state pointer buffer entries
|
||||||
|
// ini_state: state to start simulation at (or NULL to use default)
|
||||||
|
extern void interactive_simulate( st_bytecode *bytecode, int random, int rnd_quiet, int print_hex, int split,
|
||||||
|
unsigned long buffer_len, unsigned int states_max,
|
||||||
|
st_global_state_header *ini_state );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_interactive
|
||||||
367
iface/nips/nips_vm/main.c
Normal file
367
iface/nips/nips_vm/main.c
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
588
iface/nips/nips_vm/nips_asm.pl
Executable file
588
iface/nips/nips_vm/nips_asm.pl
Executable file
|
|
@ -0,0 +1,588 @@
|
||||||
|
#! /usr/bin/perl
|
||||||
|
# NIPS Asm - New Implementation of Promela Semantics Assembler
|
||||||
|
# Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# add directory of script to include directory
|
||||||
|
my $incdir=$0;
|
||||||
|
$incdir =~ s/[^\/]*$//;
|
||||||
|
$incdir = "./" if( $incdir eq "" );
|
||||||
|
push @INC, $incdir;
|
||||||
|
|
||||||
|
my $libprefix = $ENV{'NIPS_HOME'} || ".";
|
||||||
|
|
||||||
|
require $libprefix."/nips_asm_help.pl";
|
||||||
|
require $libprefix."/nips_asm_instr.pl";
|
||||||
|
my @instructions = get_instructions( );
|
||||||
|
|
||||||
|
print <<EOF;
|
||||||
|
|
||||||
|
NIPS Asm - New Implementation of Promela Semantics Assembler
|
||||||
|
Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# parse parameters
|
||||||
|
|
||||||
|
die "usage: perl nips_asm.pl <input.s> [<output.b> [<output.l>]]" if( @ARGV < 1 || @ARGV > 3 );
|
||||||
|
my ( $file_asm, $file_byte, $file_list ) = ( @ARGV[0], @ARGV[0], @ARGV[0] );
|
||||||
|
$file_byte =~ s/(\.s)?$/.b/;
|
||||||
|
$file_byte = @ARGV[1] if( @ARGV >= 2 );
|
||||||
|
$file_list =~ s/(\.s)?$/.l/;
|
||||||
|
$file_list = @ARGV[2] if( @ARGV >= 3 );
|
||||||
|
|
||||||
|
# parse input
|
||||||
|
|
||||||
|
print "parsing input file \"$file_asm\"...\n";
|
||||||
|
|
||||||
|
open ASM, "<".$file_asm or die "could not open input file \"$file_asm\"";
|
||||||
|
|
||||||
|
my ( $line_no, $line, $module );
|
||||||
|
my $modflags = 0;
|
||||||
|
my $addr = 0;
|
||||||
|
my @bytecodes = ( );
|
||||||
|
my @flags = ( );
|
||||||
|
my @strings = ( );
|
||||||
|
my @srclocs = ( );
|
||||||
|
my @strinfs = ( );
|
||||||
|
$module = "";
|
||||||
|
my @modules = ( );
|
||||||
|
for( $line_no = 1; $line = <ASM>; $line_no++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
# remove newline, whitespace, comment
|
||||||
|
|
||||||
|
chomp $line;
|
||||||
|
chomp $line;
|
||||||
|
$line =~ s/\t/ /g;
|
||||||
|
$line =~ s/^ *([^;]*)(;.*)?$/\1/;
|
||||||
|
|
||||||
|
# get label and split words
|
||||||
|
|
||||||
|
$line =~ /^(([A-Za-z][A-Za-z0-9_]*): *)?(.*)$/;
|
||||||
|
my $label = $2;
|
||||||
|
my @words = split /[ ,]+/, $3;
|
||||||
|
|
||||||
|
# get string possibly contained in line
|
||||||
|
|
||||||
|
my $str = undef;
|
||||||
|
$str = eval( $1 ) if( $line =~ /^[^"]*("([^"]|\\.)*").*$/ );
|
||||||
|
|
||||||
|
# empty line
|
||||||
|
|
||||||
|
if( @words <= 0 || (@words == 1 && @words[0] eq "") )
|
||||||
|
{
|
||||||
|
# save empty bytecode for this line if there is a label
|
||||||
|
push @bytecodes, [ $addr, $label, [ ], [ ] ] if( $label ne "" );
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# start of new module
|
||||||
|
|
||||||
|
if( @words[0] eq "!module" )
|
||||||
|
{
|
||||||
|
die "\"!module\" needs a string in line $line_no" if( $str eq undef );
|
||||||
|
push @modules, [ $module, $modflags, [ @bytecodes ], [ @strings ] ] if( @bytecodes > 0 or @strings > 0 );
|
||||||
|
$module = $str;
|
||||||
|
$modflags = 0;
|
||||||
|
$addr = 0;
|
||||||
|
@bytecodes = ( );
|
||||||
|
@flags = ( );
|
||||||
|
@strings = ( );
|
||||||
|
@srclocs = ( );
|
||||||
|
@strinfs = ( );
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# module flags
|
||||||
|
|
||||||
|
if( @words[0] eq "!modflags" )
|
||||||
|
{
|
||||||
|
my $flag;
|
||||||
|
foreach $flag (@words)
|
||||||
|
{
|
||||||
|
if( $flag eq "monitor" ) { $modflags |= 0x00000001; }
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# flags for address
|
||||||
|
|
||||||
|
if( @words[0] eq "!flags" || @words[0] eq "!flags_addr" )
|
||||||
|
{
|
||||||
|
my $ad = $addr;
|
||||||
|
my $i = 1;
|
||||||
|
if( @words[0] eq "!flags_addr" )
|
||||||
|
{
|
||||||
|
if( @words[1] =~ /^0*[xX]/ )
|
||||||
|
{ $ad = hex( @words[1] ); }
|
||||||
|
else
|
||||||
|
{ $ad = int( @words[1] ); }
|
||||||
|
$i = 2;
|
||||||
|
}
|
||||||
|
my $fl = 0;
|
||||||
|
for( ; $i < @words; $i++ )
|
||||||
|
{
|
||||||
|
if( @words[$i] eq "progress" )
|
||||||
|
{ $fl |= 0x00000001; }
|
||||||
|
elsif( @words[$i] eq "accept" )
|
||||||
|
{ $fl |= 0x00000002; }
|
||||||
|
else
|
||||||
|
{ die "unknown flag \"@words[$i]\" in line $line_no"; }
|
||||||
|
}
|
||||||
|
if( @flags > 0 && @{@flags[@flags-1]}[0] > $ad ) {
|
||||||
|
die "flags out of order in line $line_no"
|
||||||
|
} elsif (@flags > 0 && @{@flags[@flags-1]}[0] == $ad) {
|
||||||
|
# add more flags
|
||||||
|
@{@flags[@flags-1]}[1] |= $fl;
|
||||||
|
} else {
|
||||||
|
push @flags, [ $ad, $fl ] if( $fl != 0 );
|
||||||
|
}
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# string to put into string table
|
||||||
|
|
||||||
|
if( @words[0] eq "!string" )
|
||||||
|
{
|
||||||
|
die "\"!string\" needs a number in line $line_no" if( @words[1] !~ /^[0-9]+$/ );
|
||||||
|
die "\"!string\" needs a string in line $line_no" if( $str eq undef );
|
||||||
|
my $i = int( @words[1] );
|
||||||
|
die "duplicate definition of string $i in line $line_no" if( $i < @strings and @strings[$i] ne undef );
|
||||||
|
my $j;
|
||||||
|
for( $j = @strings; $j < $i; $j++ )
|
||||||
|
{ @strings[$j] = undef; }
|
||||||
|
@strings[$i] = $str;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# source location
|
||||||
|
|
||||||
|
if( @words[0] eq "!srcloc" || @words[0] eq "!srcloc_addr" )
|
||||||
|
{
|
||||||
|
my $ad = $addr;
|
||||||
|
my $i = 1;
|
||||||
|
if( @words[0] eq "!srcloc_addr" )
|
||||||
|
{
|
||||||
|
if( @words[1] =~ /^0*[xX]/ )
|
||||||
|
{ $ad = hex( @words[1] ); }
|
||||||
|
else
|
||||||
|
{ $ad = int( @words[1] ); }
|
||||||
|
$i = 2;
|
||||||
|
}
|
||||||
|
my $line = int( @words[$i] );
|
||||||
|
my $col = int( @words[$i+1] );
|
||||||
|
die "source location out of order in line $line_no" if( @srclocs > 0 && @{@srclocs[@srclocs-1]}[0] > $ad );
|
||||||
|
push @srclocs, [ $ad, $line, $col ];
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# structure information
|
||||||
|
|
||||||
|
if( @words[0] eq "!strinf" || @words[0] eq "!strinf_addr" )
|
||||||
|
{
|
||||||
|
my $ad = $addr;
|
||||||
|
my $i = 1;
|
||||||
|
if( @words[0] eq "!strinf_addr" )
|
||||||
|
{
|
||||||
|
if( @words[1] =~ /^0*[xX]/ )
|
||||||
|
{ $ad = hex( @words[1] ); }
|
||||||
|
else
|
||||||
|
{ $ad = int( @words[1] ); }
|
||||||
|
$i = 2;
|
||||||
|
}
|
||||||
|
my $code = 0xFF;
|
||||||
|
$code = 0x00 if( @words[$i] eq "begin" );
|
||||||
|
$code = 0x01 if( @words[$i] eq "end" );
|
||||||
|
$code = 0x02 if( @words[$i] eq "middle" );
|
||||||
|
my $type = @words[$i+1] . "";
|
||||||
|
die "invalid type \"$type\" in structure information in line $line_no" if( $type !~ /^[A-Za-z0-9_]+$/ );
|
||||||
|
my $name = @words[$i+2] . "";
|
||||||
|
die "invalid name \"$name\" in structure information in line $line_no" if( $name !~ /^[A-Za-z0-9_.]*$/ );
|
||||||
|
die "structure information out of order in line $line_no" if( @strinfs > 0 && @{@strinfs[@strinfs-1]}[0] > $ad );
|
||||||
|
push @strinfs, [ $ad, $code, $type, $name ];
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# find instruction in table
|
||||||
|
|
||||||
|
my $ok = 0;
|
||||||
|
my ( $opcode, $params );
|
||||||
|
for (@instructions)
|
||||||
|
{
|
||||||
|
( $opcode, $params ) = @{$_};
|
||||||
|
if( @words == @{$params} )
|
||||||
|
{
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < @{$params}; $i++ )
|
||||||
|
{
|
||||||
|
my $param = @{$params}[$i];
|
||||||
|
my $word = @words[$i];
|
||||||
|
last if( $param !~ /^\!/ and $param ne $word );
|
||||||
|
}
|
||||||
|
if( $i >= @{$params} )
|
||||||
|
{
|
||||||
|
$ok = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die "invalid instruction \"@words\" in line $line_no" if( ! $ok );
|
||||||
|
|
||||||
|
# process parameters and generate bytecode
|
||||||
|
|
||||||
|
my @bytecode = ( $opcode );
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < @{$params}; $i++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
# byte constant
|
||||||
|
|
||||||
|
if( @{$params}[$i] eq "!const1" )
|
||||||
|
{
|
||||||
|
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
|
||||||
|
my $val = int( @words[$i] );
|
||||||
|
die "1-byte constant \"".@words[$i]."\" in line $line_no is out of range" if( $val > 0xFF or $val < -0x80 );
|
||||||
|
push @bytecode, $val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
# word constant
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] eq "!const2" )
|
||||||
|
{
|
||||||
|
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
|
||||||
|
my $val = int( @words[$i] );
|
||||||
|
die "2-byte constant \"".@words[$i]."\" in line $line_no is out of range" if( $val > 0xFFFF or $val < -0x8000 );
|
||||||
|
push @bytecode, ($val >> 8) & 0xFF;
|
||||||
|
push @bytecode, $val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
# double-word constant
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] eq "!const4" )
|
||||||
|
{
|
||||||
|
die "invalid constant \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^-?[0-9]+$/ );
|
||||||
|
my $val = int( @words[$i] );
|
||||||
|
push @bytecode, ($val >> 24) & 0xFF;
|
||||||
|
push @bytecode, ($val >> 16) & 0xFF;
|
||||||
|
push @bytecode, ($val >> 8) & 0xFF;
|
||||||
|
push @bytecode, $val & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
# register
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] eq "!reg" )
|
||||||
|
{
|
||||||
|
die "invalid register \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^r([0-7])$/ );
|
||||||
|
push @bytecode, int( $1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
# relative address given by label
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] eq "!addr" )
|
||||||
|
{
|
||||||
|
die "invalid label \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^[A-Za-z][A-Za-z0-9_]*$/ );
|
||||||
|
push @bytecode, "addr1:".@words[$i]; # relative address of label takes 2 bytes
|
||||||
|
push @bytecode, "addr0:".@words[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
# absolute address given by label
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] eq "!address" )
|
||||||
|
{
|
||||||
|
die "invalid label \"".@words[$i]."\" in line $line_no" if( @words[$i] !~ /^[A-Za-z][A-Za-z0-9_]*$/ );
|
||||||
|
push @bytecode, "address3:".@words[$i]; # absolute address of label takes 4 bytes
|
||||||
|
push @bytecode, "address2:".@words[$i];
|
||||||
|
push @bytecode, "address1:".@words[$i];
|
||||||
|
push @bytecode, "address0:".@words[$i];
|
||||||
|
}
|
||||||
|
|
||||||
|
# other parmeter type
|
||||||
|
|
||||||
|
elsif( @{$params}[$i] =~ /^\!/ )
|
||||||
|
{
|
||||||
|
die "internal error: unknown parmeter type \"".@{$params}[$i]."\"\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save bytecode of this line
|
||||||
|
|
||||||
|
push @bytecodes, [ $addr, $label, [ @bytecode ], [ @words ] ];
|
||||||
|
$addr += @bytecode
|
||||||
|
}
|
||||||
|
push @modules, [ $module, $modflags, [ @bytecodes ], [ @flags ], [ @strings ], [ @srclocs], [ @strinfs ] ] if( @bytecodes > 0 or @strings > 0 );
|
||||||
|
die "no code found" if( @modules <= 0 );
|
||||||
|
|
||||||
|
# convert labels into addresses
|
||||||
|
|
||||||
|
print "converting labels to addresses...\n";
|
||||||
|
|
||||||
|
for (@modules)
|
||||||
|
{
|
||||||
|
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$_};
|
||||||
|
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w ) = @{$_};
|
||||||
|
for (@{$bc})
|
||||||
|
{
|
||||||
|
|
||||||
|
# byte in bytecode is a label
|
||||||
|
|
||||||
|
if( $_ =~ /^addr(ess)?([0123]):([A-Za-z][A-Za-z0-9_]*)$/ )
|
||||||
|
{
|
||||||
|
my $rel = $1 eq "";
|
||||||
|
my $byte = $2;
|
||||||
|
my $lab = $3;
|
||||||
|
|
||||||
|
# find declaration of this label
|
||||||
|
|
||||||
|
my $ok = 0;
|
||||||
|
my $ad = "";
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w ) = @{$_};
|
||||||
|
if( $label eq $lab )
|
||||||
|
{
|
||||||
|
$ad = $addr;
|
||||||
|
$ok = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die "label \"$lab\" is not declared in module \"$module\"" if( ! $ok );
|
||||||
|
|
||||||
|
# convert address into relative one
|
||||||
|
|
||||||
|
if( $rel )
|
||||||
|
{
|
||||||
|
$ad -= $addr + @{$bc};
|
||||||
|
die "destination label \"".$lab."\" in module \"$module\" is out of range" if( $ad > 0x7FFF or $ad < -0x8000 );
|
||||||
|
}
|
||||||
|
|
||||||
|
# put right byte address into bytecode
|
||||||
|
|
||||||
|
$_ = ($ad >> ($byte * 8)) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# update this line
|
||||||
|
|
||||||
|
$_ = [ $addr, $label, $bc, $w ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# output bytecode and listing
|
||||||
|
|
||||||
|
print "writing output files \"$file_byte\" and \"$file_list\"...\n";
|
||||||
|
|
||||||
|
open BYTE, ">".$file_byte or die "could not open bytecode output file \"$file_byte\"";
|
||||||
|
binmode BYTE;
|
||||||
|
open LIST, ">".$file_list or die "could not open list output file \"$file_list\"";
|
||||||
|
|
||||||
|
# file header
|
||||||
|
|
||||||
|
print BYTE "NIPS v2 ";
|
||||||
|
wr_word( \*BYTE, @modules + 0 );
|
||||||
|
print LIST "# this code was assembled according to \"NIPS v2 \"\n\n";
|
||||||
|
|
||||||
|
# modules
|
||||||
|
|
||||||
|
for (@modules)
|
||||||
|
{
|
||||||
|
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$_};
|
||||||
|
|
||||||
|
# module header
|
||||||
|
|
||||||
|
# sec_type
|
||||||
|
print BYTE "mod ";
|
||||||
|
# sec_sz (0 for now)
|
||||||
|
my $sec_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
print LIST "!module \"" . escape_str( $module ) . "\"\n\n";
|
||||||
|
|
||||||
|
# module_name
|
||||||
|
wr_string( \*BYTE, $module );
|
||||||
|
|
||||||
|
# part_cnt
|
||||||
|
wr_word( \*BYTE, 6 );
|
||||||
|
|
||||||
|
# module flags
|
||||||
|
|
||||||
|
print BYTE "modf";
|
||||||
|
wr_dword( \*BYTE, 4 );
|
||||||
|
wr_dword( \*BYTE, $modflags );
|
||||||
|
|
||||||
|
print LIST "!modflags";
|
||||||
|
print LIST " monitor" if( $modflags & 0x00000001 );
|
||||||
|
print LIST "\n\n";
|
||||||
|
|
||||||
|
# code
|
||||||
|
|
||||||
|
# part_type
|
||||||
|
print BYTE "bc ";
|
||||||
|
# part_sz (0 for now)
|
||||||
|
my $part_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w ) = @{$_};
|
||||||
|
|
||||||
|
# byte code
|
||||||
|
|
||||||
|
wr_byte( \*BYTE, $_ ) for (@{$bc});
|
||||||
|
|
||||||
|
# hex dump of bytecode
|
||||||
|
|
||||||
|
printf LIST "0x%08X:", $addr;
|
||||||
|
printf LIST " 0x%02X", $_ for (@{$bc});
|
||||||
|
|
||||||
|
# indentation
|
||||||
|
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < 48 - 7 - 5 * @{$bc}; $i++ ) { print LIST " "; }
|
||||||
|
|
||||||
|
# source code
|
||||||
|
|
||||||
|
print LIST " #";
|
||||||
|
print LIST " $label:" if( $label ne "" );
|
||||||
|
print LIST " $_" for (@{$w});
|
||||||
|
print LIST "\n";
|
||||||
|
}
|
||||||
|
print LIST "\n";
|
||||||
|
|
||||||
|
# part_sz
|
||||||
|
wr_size_fillin( \*BYTE, $part_sz_pos );
|
||||||
|
|
||||||
|
# flag table
|
||||||
|
|
||||||
|
# part_type
|
||||||
|
print BYTE "flag";
|
||||||
|
# part_sz
|
||||||
|
$part_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
# flag_cnt
|
||||||
|
wr_word( \*BYTE, @{$flags} + 0 );
|
||||||
|
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < @{$flags}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $fl) = @{@{$flags}[$i]};
|
||||||
|
# flag
|
||||||
|
wr_dword( \*BYTE, $addr );
|
||||||
|
wr_dword( \*BYTE, $fl );
|
||||||
|
|
||||||
|
printf LIST "!flags_addr 0x%08X", $addr;
|
||||||
|
print LIST " progress" if( $fl & 0x00000001 );
|
||||||
|
print LIST " accept" if( $fl & 0x00000002 );
|
||||||
|
print LIST "\n";
|
||||||
|
}
|
||||||
|
print LIST "\n";
|
||||||
|
|
||||||
|
# part_sz
|
||||||
|
wr_size_fillin( \*BYTE, $part_sz_pos );
|
||||||
|
|
||||||
|
# string table
|
||||||
|
|
||||||
|
# part_type
|
||||||
|
print BYTE "str ";
|
||||||
|
# part_sz
|
||||||
|
$part_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
# str_cnt
|
||||||
|
wr_word( \*BYTE, @{$strings} + 0 );
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$strings}; $i++ )
|
||||||
|
{
|
||||||
|
my $str = @{$strings}[$i];
|
||||||
|
if( $str ne undef )
|
||||||
|
{
|
||||||
|
wr_string( \*BYTE, $str );
|
||||||
|
print LIST "!string $i \"" . escape_str( $str ) . "\"\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# empty string
|
||||||
|
wr_string( \*BYTE, "" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print LIST "\n";
|
||||||
|
|
||||||
|
# part_sz
|
||||||
|
wr_size_fillin( \*BYTE, $part_sz_pos );
|
||||||
|
|
||||||
|
# source location table
|
||||||
|
|
||||||
|
# part_type
|
||||||
|
print BYTE "sloc";
|
||||||
|
# part_sz
|
||||||
|
$part_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
# sloc_cnt
|
||||||
|
wr_word( \*BYTE, @{$srclocs} + 0 );
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$srclocs}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $line, $col) = @{@{$srclocs}[$i]};
|
||||||
|
# srcloc
|
||||||
|
wr_dword( \*BYTE, $addr );
|
||||||
|
wr_dword( \*BYTE, $line );
|
||||||
|
wr_dword( \*BYTE, $col );
|
||||||
|
|
||||||
|
printf LIST "!srcloc_addr 0x%08X %d %d\n", $addr, $line, $col;
|
||||||
|
}
|
||||||
|
print LIST "\n";
|
||||||
|
|
||||||
|
# part_sz
|
||||||
|
wr_size_fillin( \*BYTE, $part_sz_pos );
|
||||||
|
|
||||||
|
# structure information table
|
||||||
|
|
||||||
|
# part_type
|
||||||
|
print BYTE "stin";
|
||||||
|
# part_sz
|
||||||
|
$part_sz_pos = wr_size_tmp( \*BYTE );
|
||||||
|
|
||||||
|
# stin_cnt
|
||||||
|
wr_word( \*BYTE, @{$strinfs} + 0 );
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$strinfs}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $code, $type, $name) = @{@{$strinfs}[$i]};
|
||||||
|
# strinf
|
||||||
|
wr_dword( \*BYTE, $addr );
|
||||||
|
wr_byte( \*BYTE, $code );
|
||||||
|
wr_string( \*BYTE, $type );
|
||||||
|
wr_string( \*BYTE, $name );
|
||||||
|
|
||||||
|
printf LIST "!strinf_addr 0x%08X", $addr;
|
||||||
|
if( $code == 0x00 )
|
||||||
|
{ print LIST " begin "; }
|
||||||
|
elsif( $code == 0x01 )
|
||||||
|
{ print LIST " end "; }
|
||||||
|
elsif( $code == 0x02 )
|
||||||
|
{ print LIST " middle "; }
|
||||||
|
else
|
||||||
|
{ print LIST " unknown "; }
|
||||||
|
print LIST $type;
|
||||||
|
print LIST " $name" if( $name ne "" );
|
||||||
|
print LIST "\n";
|
||||||
|
}
|
||||||
|
print LIST "\n";
|
||||||
|
|
||||||
|
# part_sz
|
||||||
|
wr_size_fillin( \*BYTE, $part_sz_pos );
|
||||||
|
|
||||||
|
# end of section
|
||||||
|
|
||||||
|
# sec_sz
|
||||||
|
wr_size_fillin( \*BYTE, $sec_sz_pos );
|
||||||
|
}
|
||||||
|
print "done...\n\n";
|
||||||
|
|
||||||
148
iface/nips/nips_vm/nips_asm_help.pl
Executable file
148
iface/nips/nips_vm/nips_asm_help.pl
Executable file
|
|
@ -0,0 +1,148 @@
|
||||||
|
# NIPS Asm - New Implementation of Promela Semantics Assembler
|
||||||
|
# Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# escape a string
|
||||||
|
sub escape_str
|
||||||
|
{
|
||||||
|
my $str = shift;
|
||||||
|
$str =~ s/\0/\\0/g;
|
||||||
|
$str =~ s/\r/\\r/g;
|
||||||
|
$str =~ s/\n/\\n/g;
|
||||||
|
$str =~ s/\t/\\t/g;
|
||||||
|
$str =~ s/"/\\"/g;
|
||||||
|
$str =~ s/'/\\'/g;
|
||||||
|
my $i;
|
||||||
|
for( $i = 1; $i < 32; $i++ )
|
||||||
|
{
|
||||||
|
my $c = pack( "C", $i );
|
||||||
|
my $h = sprintf( "%02X", $i );
|
||||||
|
$str =~ s/$c/\\x$h/g;
|
||||||
|
}
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
# convert a byte, a word, a dword to binary
|
||||||
|
sub byte2bin
|
||||||
|
{
|
||||||
|
my $value = shift;
|
||||||
|
return pack( "C", $value & 0xFF );
|
||||||
|
}
|
||||||
|
sub word2bin
|
||||||
|
{
|
||||||
|
my $value = shift;
|
||||||
|
return pack( "CC", ($value >> 8) & 0xFF,
|
||||||
|
$value & 0xFF );
|
||||||
|
}
|
||||||
|
sub dword2bin
|
||||||
|
{
|
||||||
|
my $value = shift;
|
||||||
|
return pack( "CCCC", ($value >> 24) & 0xFF,
|
||||||
|
($value >> 16) & 0xFF,
|
||||||
|
($value >> 8) & 0xFF,
|
||||||
|
$value & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
# convert a byte, a word, a dword from binary
|
||||||
|
sub bin2byte
|
||||||
|
{
|
||||||
|
my @data = unpack( "C", shift );
|
||||||
|
return @data[0];
|
||||||
|
}
|
||||||
|
sub bin2word
|
||||||
|
{
|
||||||
|
my @data = unpack( "CC", shift );
|
||||||
|
return @data[0] << 8 | @data[1];
|
||||||
|
}
|
||||||
|
sub bin2dword
|
||||||
|
{
|
||||||
|
my @data = unpack( "CCCC", shift );
|
||||||
|
return @data[0] << 24 | @data[1] << 16 | @data[2] << 8 | @data[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
# write a byte, a word, a dword to a binary file
|
||||||
|
sub wr_byte
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $byte = shift;
|
||||||
|
print $filehandle byte2bin( $byte );
|
||||||
|
}
|
||||||
|
sub wr_word
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $word = shift;
|
||||||
|
print $filehandle word2bin( $word );
|
||||||
|
}
|
||||||
|
sub wr_dword
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $dword = shift;
|
||||||
|
print $filehandle dword2bin( $dword );
|
||||||
|
}
|
||||||
|
|
||||||
|
# read a byte, a word, a dword from a binary file
|
||||||
|
sub rd_byte
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $data;
|
||||||
|
read $filehandle, $data, 1;
|
||||||
|
return bin2byte( $data );
|
||||||
|
}
|
||||||
|
sub rd_word
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $data;
|
||||||
|
read $filehandle, $data, 2;
|
||||||
|
return bin2word( $data );
|
||||||
|
}
|
||||||
|
sub rd_dword
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $data;
|
||||||
|
read $filehandle, $data, 4;
|
||||||
|
return bin2dword( $data );
|
||||||
|
}
|
||||||
|
|
||||||
|
# write a string to a binary file
|
||||||
|
sub wr_string
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $str = shift;
|
||||||
|
wr_word( $filehandle, length( $str ) + 1 );
|
||||||
|
print $filehandle $str . "\0";
|
||||||
|
}
|
||||||
|
|
||||||
|
# read a string from a binary file
|
||||||
|
sub rd_string
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $str_sz = rd_word( $filehandle );
|
||||||
|
my $str;
|
||||||
|
read $filehandle, $str, $str_sz;
|
||||||
|
$str =~ s/\0.*$//;
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
# write size to binary file
|
||||||
|
sub wr_size_tmp
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $pos = tell $filehandle;
|
||||||
|
wr_dword( $filehandle, 0 );
|
||||||
|
return $pos;
|
||||||
|
}
|
||||||
|
sub wr_size_fillin
|
||||||
|
{
|
||||||
|
my $filehandle = shift;
|
||||||
|
my $sz_pos = shift;
|
||||||
|
my $pos = tell $filehandle;
|
||||||
|
seek $filehandle, $sz_pos, 0;
|
||||||
|
wr_dword( $filehandle, $pos - $sz_pos - 4 );
|
||||||
|
seek $filehandle, $pos, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
187
iface/nips/nips_vm/nips_asm_instr.pl
Executable file
187
iface/nips/nips_vm/nips_asm_instr.pl
Executable file
|
|
@ -0,0 +1,187 @@
|
||||||
|
# NIPS (Dis)Asm - New Implementation of Promela Semantics (Dis-)Assembler
|
||||||
|
# Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# instructions
|
||||||
|
# - array with fixed words (variable number of strings)
|
||||||
|
# - e.g. instruction name
|
||||||
|
# - e.g. instruction variant
|
||||||
|
# - opcode
|
||||||
|
# - array with parameters
|
||||||
|
# - const1, const2, const4: constants with 1, 2, 4 bytes
|
||||||
|
# - addr: relative address expressed by a label
|
||||||
|
# - address: absolute address
|
||||||
|
# - reg: a register r0 .. r7
|
||||||
|
sub get_instructions
|
||||||
|
{
|
||||||
|
my ($cflow, $error) = (1, 1);
|
||||||
|
my @instructions = (
|
||||||
|
[ 0x00, [ "NOP" ] ],
|
||||||
|
[ 0x01, [ "LDC", "!const4" ] ],
|
||||||
|
[ 0x02, [ "LDV", "L", "1u" ] ],
|
||||||
|
[ 0x03, [ "LDV", "L", "1s" ] ],
|
||||||
|
[ 0x04, [ "LDV", "L", "2u" ] ],
|
||||||
|
[ 0x05, [ "LDV", "L", "2s" ] ],
|
||||||
|
[ 0x06, [ "LDV", "L", "4" ] ],
|
||||||
|
[ 0x07, [ "LDV", "G", "1u" ] ],
|
||||||
|
[ 0x08, [ "LDV", "G", "1s" ] ],
|
||||||
|
[ 0x09, [ "LDV", "G", "2u" ] ],
|
||||||
|
[ 0x0A, [ "LDV", "G", "2s" ] ],
|
||||||
|
[ 0x0B, [ "LDV", "G", "4" ] ],
|
||||||
|
[ 0x0C, [ "STV", "L", "1u" ] ],
|
||||||
|
[ 0x0D, [ "STV", "L", "1s" ] ],
|
||||||
|
[ 0x0E, [ "STV", "L", "2u" ] ],
|
||||||
|
[ 0x0F, [ "STV", "L", "2s" ] ],
|
||||||
|
[ 0x10, [ "STV", "L", "4" ] ],
|
||||||
|
[ 0x11, [ "STV", "G", "1u" ] ],
|
||||||
|
[ 0x12, [ "STV", "G", "1s" ] ],
|
||||||
|
[ 0x13, [ "STV", "G", "2u" ] ],
|
||||||
|
[ 0x14, [ "STV", "G", "2s" ] ],
|
||||||
|
[ 0x15, [ "STV", "G", "4" ] ],
|
||||||
|
[ 0x16, [ "TRUNC", "!const1" ] ],
|
||||||
|
[ 0x18, [ "LDS", "timeout" ] ],
|
||||||
|
[ 0x19, [ "LDS", "pid" ] ],
|
||||||
|
[ 0x1A, [ "LDS", "nrpr" ] ],
|
||||||
|
[ 0x1B, [ "LDS", "last" ] ],
|
||||||
|
[ 0x1C, [ "LDS", "np" ] ],
|
||||||
|
[ 0x20, [ "ADD" ] ],
|
||||||
|
[ 0x21, [ "SUB" ] ],
|
||||||
|
[ 0x22, [ "MUL" ] ],
|
||||||
|
[ 0x23, [ "DIV" ] ],
|
||||||
|
[ 0x24, [ "MOD" ] ],
|
||||||
|
[ 0x25, [ "NEG" ] ],
|
||||||
|
[ 0x26, [ "NOT" ] ],
|
||||||
|
[ 0x27, [ "AND" ] ],
|
||||||
|
[ 0x28, [ "OR" ] ],
|
||||||
|
[ 0x29, [ "XOR" ] ],
|
||||||
|
[ 0x2A, [ "SHL" ] ],
|
||||||
|
[ 0x2B, [ "SHR" ] ],
|
||||||
|
[ 0x2C, [ "EQ" ] ],
|
||||||
|
[ 0x2D, [ "NEQ" ] ],
|
||||||
|
[ 0x2E, [ "LT" ] ],
|
||||||
|
[ 0x2F, [ "LTE" ] ],
|
||||||
|
[ 0x30, [ "GT" ] ],
|
||||||
|
[ 0x31, [ "GTE" ] ],
|
||||||
|
[ 0x32, [ "BNOT" ] ],
|
||||||
|
[ 0x33, [ "BAND" ] ],
|
||||||
|
[ 0x34, [ "BOR" ] ],
|
||||||
|
[ 0x40, [ "ICHK", "!const1" ], $error ],
|
||||||
|
[ 0x41, [ "BCHK" ], $error ],
|
||||||
|
[ 0x48, [ "JMP", "!addr" ], $cflow ],
|
||||||
|
[ 0x49, [ "JMPZ", "!addr" ], $cflow ],
|
||||||
|
[ 0x4A, [ "JMPNZ", "!addr" ], $cflow ],
|
||||||
|
[ 0x4B, [ "LJMP", "!address" ], $cflow ],
|
||||||
|
[ 0x50, [ "TOP", "!reg" ] ],
|
||||||
|
[ 0x51, [ "POP", "!reg" ] ],
|
||||||
|
[ 0x52, [ "PUSH", "!reg" ] ],
|
||||||
|
[ 0x53, [ "POPX" ] ],
|
||||||
|
[ 0x54, [ "INC", "!reg" ] ],
|
||||||
|
[ 0x55, [ "DEC", "!reg" ] ],
|
||||||
|
[ 0x56, [ "LOOP", "!reg", "!addr" ], $cflow ],
|
||||||
|
[ 0x58, [ "CALL", "!addr" ], $cflow ],
|
||||||
|
[ 0x59, [ "RET" ], $cflow ],
|
||||||
|
[ 0x5A, [ "LCALL", "!address" ], $cflow ],
|
||||||
|
[ 0x60, [ "CHNEW", "!const1", "!const1" ] ],
|
||||||
|
[ 0x61, [ "CHMAX" ] ],
|
||||||
|
[ 0x62, [ "CHLEN" ] ],
|
||||||
|
[ 0x63, [ "CHFREE" ] ],
|
||||||
|
[ 0x64, [ "CHADD" ] ],
|
||||||
|
[ 0x65, [ "CHSET" ] ],
|
||||||
|
[ 0x66, [ "CHGET" ] ],
|
||||||
|
[ 0x67, [ "CHDEL" ] ],
|
||||||
|
[ 0x68, [ "CHSORT" ] ],
|
||||||
|
[ 0x6B, [ "CHROT" ] ],
|
||||||
|
[ 0x6C, [ "CHSETO", "!const1" ] ],
|
||||||
|
[ 0x6D, [ "CHGETO", "!const1" ] ],
|
||||||
|
[ 0x70, [ "NDET", "!addr" ] ],
|
||||||
|
[ 0x72, [ "ELSE", "!addr" ] ],
|
||||||
|
[ 0x73, [ "UNLESS", "!addr" ] ],
|
||||||
|
[ 0x74, [ "NEX" ], $cflow ],
|
||||||
|
[ 0x75, [ "NEXZ" ], $cflow ],
|
||||||
|
[ 0x76, [ "NEXNZ" ], $cflow ],
|
||||||
|
[ 0x78, [ "STEP", "N", "!const1" ], $cflow ],
|
||||||
|
[ 0x79, [ "STEP", "A", "!const1" ], $cflow ],
|
||||||
|
[ 0x7A, [ "STEP", "I", "!const1" ], $cflow ],
|
||||||
|
[ 0x7B, [ "STEP", "T", "!const1" ], $cflow ],
|
||||||
|
[ 0x80, [ "RUN", "!const1", "!const1", "!addr" ] ],
|
||||||
|
[ 0x81, [ "LRUN", "!const1", "!const1", "!address" ] ],
|
||||||
|
[ 0x84, [ "GLOBSZ", "!const1" ] ],
|
||||||
|
[ 0x85, [ "LOCSZ", "!const1" ] ],
|
||||||
|
[ 0x86, [ "GLOBSZX", "!const2" ] ],
|
||||||
|
[ 0x88, [ "FCLR" ] ],
|
||||||
|
[ 0x89, [ "FGET", "!const1" ] ],
|
||||||
|
[ 0x8A, [ "FSET", "!const1" ] ],
|
||||||
|
[ 0x8C, [ "BGET", "!reg", "!const1" ] ],
|
||||||
|
[ 0x8D, [ "BSET", "!reg", "!const1" ] ],
|
||||||
|
[ 0x90, [ "PRINTS", "!const2" ] ],
|
||||||
|
[ 0x91, [ "PRINTV", "!const1" ] ],
|
||||||
|
[ 0x92, [ "LDVA", "L", "1u", "!const1" ] ],
|
||||||
|
[ 0x93, [ "LDVA", "L", "1s", "!const1" ] ],
|
||||||
|
[ 0x94, [ "LDVA", "L", "2u", "!const1" ] ],
|
||||||
|
[ 0x95, [ "LDVA", "L", "2s", "!const1" ] ],
|
||||||
|
[ 0x96, [ "LDVA", "L", "4", "!const1" ] ],
|
||||||
|
[ 0x97, [ "LDVA", "G", "1u", "!const1" ] ],
|
||||||
|
[ 0x98, [ "LDVA", "G", "1s", "!const1" ] ],
|
||||||
|
[ 0x99, [ "LDVA", "G", "2u", "!const1" ] ],
|
||||||
|
[ 0x9A, [ "LDVA", "G", "2s", "!const1" ] ],
|
||||||
|
[ 0x9B, [ "LDVA", "G", "4", "!const1" ] ],
|
||||||
|
[ 0x9C, [ "STVA", "L", "1u", "!const1" ] ],
|
||||||
|
[ 0x9D, [ "STVA", "L", "1s", "!const1" ] ],
|
||||||
|
[ 0x9E, [ "STVA", "L", "2u", "!const1" ] ],
|
||||||
|
[ 0x9F, [ "STVA", "L", "2s", "!const1" ] ],
|
||||||
|
[ 0xA0, [ "STVA", "L", "4", "!const1" ] ],
|
||||||
|
[ 0xA1, [ "STVA", "G", "1u", "!const1" ] ],
|
||||||
|
[ 0xA2, [ "STVA", "G", "1s", "!const1" ] ],
|
||||||
|
[ 0xA3, [ "STVA", "G", "2u", "!const1" ] ],
|
||||||
|
[ 0xA4, [ "STVA", "G", "2s", "!const1" ] ],
|
||||||
|
[ 0xA5, [ "STVA", "G", "4", "!const1" ] ],
|
||||||
|
[ 0xB0, [ "LDA", "!address" ] ],
|
||||||
|
[ 0xB4, [ "PCVAL" ] ],
|
||||||
|
[ 0xB8, [ "LVAR", "1u" ] ],
|
||||||
|
[ 0xB9, [ "LVAR", "1s" ] ],
|
||||||
|
[ 0xBA, [ "LVAR", "2u" ] ],
|
||||||
|
[ 0xBB, [ "LVAR", "2s" ] ],
|
||||||
|
[ 0xBC, [ "LVAR", "4" ] ],
|
||||||
|
[ 0xBE, [ "ENAB" ] ],
|
||||||
|
[ 0xC0, [ "MONITOR" ] ],
|
||||||
|
[ 0xC4, [ "KILL" ] ],
|
||||||
|
[ 0xD0, [ "LDB", "L" ] ],
|
||||||
|
[ 0xD1, [ "LDB", "G" ] ],
|
||||||
|
[ 0xD2, [ "STB", "L" ] ],
|
||||||
|
[ 0xD3, [ "STB", "G" ] ],
|
||||||
|
[ 0xD4, [ "LDV", "L", "2u", "LE" ] ],
|
||||||
|
[ 0xD5, [ "LDV", "L", "2s", "LE" ] ],
|
||||||
|
[ 0xD6, [ "LDV", "L", "4", "LE" ] ],
|
||||||
|
[ 0xD7, [ "LDV", "G", "2u", "LE" ] ],
|
||||||
|
[ 0xD8, [ "LDV", "G", "2s", "LE" ] ],
|
||||||
|
[ 0xD9, [ "LDV", "G", "4", "LE" ] ],
|
||||||
|
[ 0xDA, [ "STV", "L", "2u", "LE" ] ],
|
||||||
|
[ 0xDB, [ "STV", "L", "2s", "LE" ] ],
|
||||||
|
[ 0xDC, [ "STV", "L", "4", "LE" ] ],
|
||||||
|
[ 0xDD, [ "STV", "G", "2u", "LE" ] ],
|
||||||
|
[ 0xDE, [ "STV", "G", "2s", "LE" ] ],
|
||||||
|
[ 0xDF, [ "STV", "G", "4", "LE" ] ],
|
||||||
|
);
|
||||||
|
return @instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub instruction_cfun {
|
||||||
|
my ($op, $params) = @_;
|
||||||
|
|
||||||
|
my $name = "instr";
|
||||||
|
for (@{$params}) {
|
||||||
|
next if /^!/;
|
||||||
|
if (/^[0-9]/) {
|
||||||
|
$name .= lc($_);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$name .= "_".lc($_);
|
||||||
|
}
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
513
iface/nips/nips_vm/nips_disasm.pl
Executable file
513
iface/nips/nips_vm/nips_disasm.pl
Executable file
|
|
@ -0,0 +1,513 @@
|
||||||
|
#! /usr/bin/perl
|
||||||
|
# NIPS DisAsm - New Implementation of Promela Semantics (Dis-)Assembler
|
||||||
|
# Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
# add directory of script to include directory
|
||||||
|
my $incdir=$0;
|
||||||
|
$incdir =~ s/[^\/]*$//;
|
||||||
|
$incdir = "./" if( $incdir eq "" );
|
||||||
|
push @INC, $incdir;
|
||||||
|
|
||||||
|
require "nips_asm_help.pl";
|
||||||
|
require "nips_asm_instr.pl";
|
||||||
|
my @instructions = get_instructions( );
|
||||||
|
|
||||||
|
print <<EOF;
|
||||||
|
NIPS DisAsm - New Implementation of Promela Semantics Dis-Assembler
|
||||||
|
Copyright (C) 2005: 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
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# parse parameters
|
||||||
|
|
||||||
|
die "usage: perl nips_disasm.pl <input.b> [<output.d.s>]" if( @ARGV < 1 || @ARGV > 2 );
|
||||||
|
my ( $file_byte, $file_asm, $file_c ) = ( @ARGV[0], @ARGV[0], @ARGV[0] );
|
||||||
|
$file_asm =~ s/(\.b)?$/.d.s/;
|
||||||
|
$file_asm = @ARGV[1] if( @ARGV >= 2 );
|
||||||
|
$file_c =~ s/(\.b)?$/.c_stub/;
|
||||||
|
|
||||||
|
# read input
|
||||||
|
|
||||||
|
print "reading input file \"$file_byte\"...\n";
|
||||||
|
|
||||||
|
open BYTE, "<".$file_byte or die "could not open input file \"$file_byte\"";
|
||||||
|
binmode BYTE;
|
||||||
|
|
||||||
|
my $m;
|
||||||
|
read BYTE, $m, 8;
|
||||||
|
die "input file \"$file_byte\" is not a valid bytecode file" if( $m ne "NIPS v2 " );
|
||||||
|
|
||||||
|
my $sec_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my @modules = ( );
|
||||||
|
|
||||||
|
my $sec_no;
|
||||||
|
for( $sec_no = 0; $sec_no < $sec_cnt; $sec_no++ )
|
||||||
|
{
|
||||||
|
# section header
|
||||||
|
|
||||||
|
my $sec_type;
|
||||||
|
read BYTE, $sec_type, 4;
|
||||||
|
my $sec_sz = rd_dword( \*BYTE );
|
||||||
|
my $sec_end = (tell BYTE) + $sec_sz;
|
||||||
|
|
||||||
|
# module
|
||||||
|
|
||||||
|
if( $sec_type eq "mod " )
|
||||||
|
{
|
||||||
|
# module name
|
||||||
|
|
||||||
|
my $mod_name = rd_string( \*BYTE );
|
||||||
|
|
||||||
|
my $modflags = 0;
|
||||||
|
my $bytecode = "";
|
||||||
|
my $flags = [];
|
||||||
|
my $strings = [];
|
||||||
|
my $srclocs = [];
|
||||||
|
my $strinfs = [];
|
||||||
|
|
||||||
|
my $part_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my $part_no;
|
||||||
|
for( $part_no = 0; $part_no < $part_cnt; $part_no++ )
|
||||||
|
{
|
||||||
|
# part header
|
||||||
|
|
||||||
|
my $part_type;
|
||||||
|
read BYTE, $part_type, 4;
|
||||||
|
my $part_sz = rd_dword( \*BYTE );
|
||||||
|
my $part_end = (tell BYTE) + $part_sz;
|
||||||
|
|
||||||
|
# module flags
|
||||||
|
|
||||||
|
if( $part_type eq "modf" )
|
||||||
|
{
|
||||||
|
$modflags |= rd_dword( \*BYTE );
|
||||||
|
}
|
||||||
|
|
||||||
|
# bytecode
|
||||||
|
|
||||||
|
elsif( $part_type eq "bc " )
|
||||||
|
{
|
||||||
|
read BYTE, $bytecode, $part_sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
# flag table
|
||||||
|
|
||||||
|
elsif( $part_type eq "flag" )
|
||||||
|
{
|
||||||
|
my $flag_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my $flag_no;
|
||||||
|
$flags = [];
|
||||||
|
for( $flag_no = 0; $flag_no < $flag_cnt; $flag_no++ )
|
||||||
|
{
|
||||||
|
# flag
|
||||||
|
my $addr = rd_dword( \*BYTE );
|
||||||
|
my $fl = rd_dword( \*BYTE );
|
||||||
|
push @{$flags}, [ $addr, $fl ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# string table
|
||||||
|
|
||||||
|
elsif( $part_type eq "str " )
|
||||||
|
{
|
||||||
|
my $str_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my $str_no;
|
||||||
|
$strings = [];
|
||||||
|
for( $str_no = 0; $str_no < $str_cnt; $str_no++ )
|
||||||
|
{
|
||||||
|
push @{$strings}, (rd_string( \*BYTE ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# source location table
|
||||||
|
|
||||||
|
elsif( $part_type eq "sloc" )
|
||||||
|
{
|
||||||
|
my $sloc_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my $sloc_no;
|
||||||
|
$srclocs = [];
|
||||||
|
for( $sloc_no = 0; $sloc_no < $sloc_cnt; $sloc_no++ )
|
||||||
|
{
|
||||||
|
# source location
|
||||||
|
my $addr = rd_dword( \*BYTE );
|
||||||
|
my $line = rd_dword( \*BYTE );
|
||||||
|
my $col = rd_dword( \*BYTE );
|
||||||
|
push @{$srclocs}, [ $addr, $line, $col ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# structure information table
|
||||||
|
|
||||||
|
elsif( $part_type eq "stin" )
|
||||||
|
{
|
||||||
|
my $stin_cnt = rd_word( \*BYTE );
|
||||||
|
|
||||||
|
my $stin_no;
|
||||||
|
$strinfs = [];
|
||||||
|
for( $stin_no = 0; $stin_no < $stin_cnt; $stin_no++ )
|
||||||
|
{
|
||||||
|
# structure information
|
||||||
|
my $addr = rd_dword( \*BYTE );
|
||||||
|
my $code = rd_byte( \*BYTE );
|
||||||
|
my $type = rd_string( \*BYTE );
|
||||||
|
my $name = rd_string( \*BYTE );
|
||||||
|
push @{$strinfs}, [ $addr, $code, $type, $name ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# unknown part
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seek BYTE, $part_sz, 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "part $part_no of section $sec_no of input file \"$file_byte\" is corrupt" if( $part_end != (tell BYTE) );
|
||||||
|
}
|
||||||
|
|
||||||
|
push @modules, [ $mod_name, $modflags, $bytecode, $flags, $strings, $srclocs, $strinfs ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# unknown section
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seek BYTE, $sec_sz, 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "section $sec_no of input file \"$file_byte\" is corrupt" if( $sec_end != (tell BYTE) );
|
||||||
|
}
|
||||||
|
|
||||||
|
my $mod;
|
||||||
|
for $mod (@modules)
|
||||||
|
{
|
||||||
|
my ($module, $modflags, $bytecode, $flags, $strings, $srclocs, $strinfs) = @{$mod};
|
||||||
|
|
||||||
|
my ( $op );
|
||||||
|
my $addr = 0;
|
||||||
|
my @bytecodes = ( );
|
||||||
|
my $pos = 0;
|
||||||
|
my $len = length( $bytecode );
|
||||||
|
while( $pos < $len )
|
||||||
|
{
|
||||||
|
|
||||||
|
$op = unpack( "C", substr( $bytecode, $pos, 1 ) );
|
||||||
|
$pos += 1;
|
||||||
|
|
||||||
|
# find instruction in table
|
||||||
|
|
||||||
|
my $ok = 0;
|
||||||
|
my ( $opcode, $params, $cflow );
|
||||||
|
for (@instructions)
|
||||||
|
{
|
||||||
|
( $opcode, $params, $cflow ) = @{$_};
|
||||||
|
if( $opcode == $op )
|
||||||
|
{
|
||||||
|
$ok = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
die "invalid opcode ".sprintf("0x%02X",$op)." at address ".sprintf("0x%08X",$addr) if( ! $ok );
|
||||||
|
|
||||||
|
# get parameters
|
||||||
|
|
||||||
|
my @bytecode = ( $opcode );
|
||||||
|
my @parameters = ( );
|
||||||
|
|
||||||
|
my $val;
|
||||||
|
my @values;
|
||||||
|
my $addr_tmp = $addr + 1;
|
||||||
|
for (@{$params} )
|
||||||
|
{
|
||||||
|
# byte constant
|
||||||
|
|
||||||
|
if( $_ eq "!const1" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 1 > $len );
|
||||||
|
@values = unpack( "C", substr( $bytecode, $pos, 1 ) );
|
||||||
|
$pos += 1;
|
||||||
|
push @bytecode, @values;
|
||||||
|
$val = @values[0];
|
||||||
|
$val -= 256 if( $val >= 128 );
|
||||||
|
push @parameters, $val;
|
||||||
|
$addr_tmp += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# word constant
|
||||||
|
|
||||||
|
elsif( $_ eq "!const2" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 2 > $len );
|
||||||
|
@values = unpack( "CC", substr( $bytecode, $pos, 2 ) );
|
||||||
|
$pos += 2;
|
||||||
|
push @bytecode, @values;
|
||||||
|
$val = @values[0] << 8 | @values[1];
|
||||||
|
$val -= 65536 if( $val >= 32768 );
|
||||||
|
push @parameters, $val;
|
||||||
|
$addr_tmp += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# double-word constant
|
||||||
|
|
||||||
|
elsif( $_ eq "!const4" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 4 > $len );
|
||||||
|
@values = unpack( "CCCC", substr( $bytecode, $pos, 4 ) );
|
||||||
|
$pos += 4;
|
||||||
|
push @bytecode, @values;
|
||||||
|
$val = @values[0] << 24 | @values[1] << 16 | @values[2] << 8 | @values[3];
|
||||||
|
$val -= 4294967296 if( $val >= 2147483648 );
|
||||||
|
push @parameters, $val;
|
||||||
|
$addr_tmp += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
# register
|
||||||
|
|
||||||
|
elsif( $_ eq "!reg" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 1 > $len );
|
||||||
|
@values = unpack( "C", substr( $bytecode, $pos, 1 ) );
|
||||||
|
$pos += 1;
|
||||||
|
die "invalid register number ".@values[0]." at address ".sprintf("0x%08X",$addr_tmp) if( @values[0] >= 8 );
|
||||||
|
push @bytecode, @values;
|
||||||
|
push @parameters, "r".@values[0];
|
||||||
|
$addr_tmp += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# relative address given by label
|
||||||
|
|
||||||
|
elsif( $_ eq "!addr" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 2 > $len );
|
||||||
|
@values = unpack( "CC", substr( $bytecode, $pos, 2 ) );
|
||||||
|
$pos += 2;
|
||||||
|
push @bytecode, @values;
|
||||||
|
$val = (@values[0] << 8 | @values[1]);
|
||||||
|
$val -= 65536 if( $val >= 32768 );
|
||||||
|
push @parameters, "addr:".$val;
|
||||||
|
$addr_tmp += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
# absolute address given by label
|
||||||
|
|
||||||
|
elsif( $_ eq "!address" )
|
||||||
|
{
|
||||||
|
die "truncated instruction at address ".sprintf("0x%08X",$addr_tmp) if( $pos + 4 > $len );
|
||||||
|
@values = unpack( "CCCC", substr( $bytecode, $pos, 4 ) );
|
||||||
|
$pos += 4;
|
||||||
|
push @bytecode, @values;
|
||||||
|
$val = (@values[0] << 24 | @values[1] << 16 | @values[2] << 8 | @values[3]);
|
||||||
|
push @parameters, "address:".$val;
|
||||||
|
$addr_tmp += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
# other parmeter type
|
||||||
|
|
||||||
|
elsif( $_ =~ /^\!/ )
|
||||||
|
{
|
||||||
|
die "internal error: unknown parmeter type \"$_\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# fixed word
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
push @parameters, $_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# save bytecode
|
||||||
|
|
||||||
|
push @bytecodes, [ $addr, "", [ @bytecode ], [ @parameters ], [ @{$params} ], $cflow ];
|
||||||
|
$addr = $addr_tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mod = [$module, $modflags, [@bytecodes], $flags, $strings, $srclocs, $strinfs];
|
||||||
|
}
|
||||||
|
|
||||||
|
# convert addresses into labels
|
||||||
|
|
||||||
|
print "converting addresses to labels...\n";
|
||||||
|
|
||||||
|
for $mod (@modules)
|
||||||
|
{
|
||||||
|
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$mod};
|
||||||
|
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w, $params, $cflow ) = @{$_};
|
||||||
|
for (@{$w})
|
||||||
|
{
|
||||||
|
|
||||||
|
# word is an address
|
||||||
|
|
||||||
|
if( $_ =~ /^addr(ess)?:(-?[0-9]+)$/ )
|
||||||
|
{
|
||||||
|
my $rel = $1 eq "";
|
||||||
|
my $ad = $2;
|
||||||
|
$ad += $addr + @{$bc} if( $rel ); # convert to absolute address
|
||||||
|
|
||||||
|
# find this address
|
||||||
|
|
||||||
|
my $wo = "";
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w, $params, $cflow ) = @{$_};
|
||||||
|
if( $ad >= $addr && $ad < $addr + @{$bc} )
|
||||||
|
{
|
||||||
|
$label = "L_" . sprintf( "%08X", $addr );
|
||||||
|
$_ = [ $addr, $label, $bc, $w, $params, $cflow ];
|
||||||
|
$wo = $label;
|
||||||
|
$wo .= "+" . ($ad - $addr) if( $ad != $addr );
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# update this word
|
||||||
|
|
||||||
|
$wo = sprintf( "0x%08X", $ad ) if( $wo eq "" );
|
||||||
|
$_ = $wo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# update this line
|
||||||
|
$_ = [ $addr, @{$_}[1], $bc, $w, $params, $cflow ]; # keep label (might have been updated in inner loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# output disassembled code
|
||||||
|
|
||||||
|
print "writing output file \"$file_asm\"...\n";
|
||||||
|
open ASM, ">".$file_asm or die "could not open output file \"$file_asm\"";
|
||||||
|
|
||||||
|
print "writing output file \"$file_c\"...\n";
|
||||||
|
open CCODE, ">".$file_c or die "could not open output file \"$file_c\"";
|
||||||
|
|
||||||
|
|
||||||
|
print CCODE <<INITIAL_CCODE;
|
||||||
|
static inline void instr_exec( st_instr_context *p_ctx )
|
||||||
|
{
|
||||||
|
t_pc pc_h = be2h_pc( p_ctx->p_proc->proc.pc );
|
||||||
|
#define INC_PC() p_ctx->p_proc->proc.pc = h2be_pc( pc_h = be2h_pc( p_ctx->p_proc->proc.pc ) + 1 )
|
||||||
|
|
||||||
|
// select instruction (and advance program counter)
|
||||||
|
#ifdef DEBUG_INSTR
|
||||||
|
printf( "DEBUG (before instr): " ); global_state_print( p_ctx->p_glob );
|
||||||
|
#endif
|
||||||
|
switch(pc_h) {
|
||||||
|
INITIAL_CCODE
|
||||||
|
|
||||||
|
for $mod (@modules)
|
||||||
|
{
|
||||||
|
my ($module, $modflags, $bytecodes, $flags, $strings, $srclocs, $strinfs) = @{$mod};
|
||||||
|
|
||||||
|
# module name
|
||||||
|
print ASM "!module \"" . escape_str( $module ) . "\"\n\n";
|
||||||
|
|
||||||
|
# module flags
|
||||||
|
|
||||||
|
print ASM "!modflags monitor\n\n" if( $modflags & 0x00000001 );
|
||||||
|
|
||||||
|
# byte code
|
||||||
|
|
||||||
|
my $old_cflow = 1;
|
||||||
|
for (@{$bytecodes})
|
||||||
|
{
|
||||||
|
my ( $addr, $label, $bc, $w, $params, $cflow ) = @{$_};
|
||||||
|
|
||||||
|
# source code
|
||||||
|
|
||||||
|
if( $label ne "" )
|
||||||
|
{
|
||||||
|
print ASM "$label:";
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < 11 - length( $label ) - 1; $i++ ) { print ASM " "; }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print ASM " ";
|
||||||
|
}
|
||||||
|
print ASM " $_" for (@{$w});
|
||||||
|
print ASM "\n";
|
||||||
|
|
||||||
|
printf CCODE " case 0x%x:\n", $addr if $old_cflow or @{$_}[1] ne "";
|
||||||
|
print CCODE "\tINC_PC();\t\t".instruction_cfun(0, $params)."(p_ctx);\n";
|
||||||
|
print CCODE "\tbreak;\n" if $cflow;
|
||||||
|
$old_cflow = $cflow;
|
||||||
|
}
|
||||||
|
print ASM "\n";
|
||||||
|
|
||||||
|
# flag table
|
||||||
|
|
||||||
|
my $i;
|
||||||
|
for( $i = 0; $i < @{$flags}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $fl) = @{@{$flags}[$i]};
|
||||||
|
|
||||||
|
printf ASM "!flags_addr 0x%08X", $addr;
|
||||||
|
print ASM " progress" if( $fl & 0x00000001 );
|
||||||
|
print ASM " accept" if( $fl & 0x00000002 );
|
||||||
|
print ASM "\n";
|
||||||
|
}
|
||||||
|
print ASM "\n";
|
||||||
|
|
||||||
|
# string table
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$strings}; $i++ )
|
||||||
|
{
|
||||||
|
my $str = @{$strings}[$i];
|
||||||
|
print ASM "!string $i \"" . escape_str( $str ) . "\"\n" if( $str ne undef );
|
||||||
|
}
|
||||||
|
print ASM "\n";
|
||||||
|
|
||||||
|
# source location table
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$srclocs}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $line, $col) = @{@{$srclocs}[$i]};
|
||||||
|
printf ASM "!srcloc_addr 0x%08X %d %d\n", $addr, $line, $col;
|
||||||
|
}
|
||||||
|
print ASM "\n";
|
||||||
|
|
||||||
|
# structure information table
|
||||||
|
|
||||||
|
for( $i = 0; $i < @{$strinfs}; $i++ )
|
||||||
|
{
|
||||||
|
my ($addr, $code, $type, $name) = @{@{$strinfs}[$i]};
|
||||||
|
printf ASM "!strinf_addr 0x%08X", $addr;
|
||||||
|
if( $code == 0x00 )
|
||||||
|
{ print ASM " begin "; }
|
||||||
|
elsif( $code == 0x01 )
|
||||||
|
{ print ASM " end "; }
|
||||||
|
elsif( $code == 0x02 )
|
||||||
|
{ print ASM " middle "; }
|
||||||
|
else
|
||||||
|
{ print ASM " unknown "; }
|
||||||
|
print ASM $type;
|
||||||
|
print ASM " $name" if( $name ne "" );
|
||||||
|
print ASM "\n";
|
||||||
|
}
|
||||||
|
print ASM "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
print CCODE <<FINAL_CCODE;
|
||||||
|
default:
|
||||||
|
instr_err( p_ctx, IE_BYTECODE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FINAL_CCODE
|
||||||
|
|
||||||
|
print "done...\n\n";
|
||||||
|
|
||||||
104
iface/nips/nips_vm/nipsvm.c
Normal file
104
iface/nips/nips_vm/nipsvm.c
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "bytecode.h"
|
||||||
|
#include "instr_step.h"
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
struct nipsvm_transition_information_t {
|
||||||
|
uint8_t label[2];
|
||||||
|
t_flag_reg flags[2];
|
||||||
|
unsigned int succ_cb_flags;
|
||||||
|
st_instr_succ_output *p_succ_out;
|
||||||
|
};
|
||||||
|
|
||||||
|
static et_ic_status
|
||||||
|
simple_scheduler_cb( st_global_state_header *succ,
|
||||||
|
uint8_t label_1st, uint8_t label,
|
||||||
|
t_flag_reg flag_reg_1st, t_flag_reg flag_reg,
|
||||||
|
unsigned int succ_cb_flags,
|
||||||
|
st_instr_succ_output *p_succ_out,
|
||||||
|
void *priv_context )
|
||||||
|
{
|
||||||
|
nipsvm_t *vm = (nipsvm_t *)priv_context;
|
||||||
|
|
||||||
|
nipsvm_transition_information_t transition_info = {
|
||||||
|
.label = { label_1st, label },
|
||||||
|
.flags = { flag_reg_1st, flag_reg },
|
||||||
|
.succ_cb_flags = succ_cb_flags,
|
||||||
|
.p_succ_out = p_succ_out,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (*vm->callback)(nipsvm_state_size (succ), succ,
|
||||||
|
&transition_info, vm->callback_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static et_ic_status
|
||||||
|
simple_error_cb (et_instr_err err, t_pid pid, t_pc pc, void *priv_context)
|
||||||
|
{
|
||||||
|
nipsvm_t *vm = (nipsvm_t *)priv_context;
|
||||||
|
return (*vm->error_callback)(err, pid, pc, vm->callback_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_module_init() { return 0; }
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_init (nipsvm_t *vm,
|
||||||
|
nipsvm_bytecode_t *bytecode,
|
||||||
|
nipsvm_scheduler_callback_t *s_callback,
|
||||||
|
nipsvm_error_callback_t *e_callback)
|
||||||
|
{
|
||||||
|
assert (vm != NULL);
|
||||||
|
|
||||||
|
vm->callback = s_callback;
|
||||||
|
vm->error_callback = e_callback != NULL ? e_callback : nipsvm_default_error_cb;
|
||||||
|
|
||||||
|
instr_succ_context_default (&vm->insn_context, bytecode);
|
||||||
|
vm->insn_context.priv_context = vm;
|
||||||
|
vm->insn_context.succ_cb = &simple_scheduler_cb;
|
||||||
|
vm->insn_context.err_cb = &simple_error_cb;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void *
|
||||||
|
nipsvm_finalize (nipsvm_t *vm)
|
||||||
|
{
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern unsigned int
|
||||||
|
nipsvm_scheduler_iter (nipsvm_t *vm,
|
||||||
|
nipsvm_state_t *state,
|
||||||
|
void *callback_context)
|
||||||
|
{
|
||||||
|
assert (vm != NULL);
|
||||||
|
vm->callback_context = callback_context;
|
||||||
|
return instr_succ (state, 0, &vm->insn_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern nipsvm_state_t *
|
||||||
|
nipsvm_initial_state (nipsvm_t *vm)
|
||||||
|
{
|
||||||
|
assert (vm != NULL);
|
||||||
|
static char initial_state_buf[NIPSVM_INITIAL_STATE_SIZE];
|
||||||
|
char *buf = initial_state_buf;
|
||||||
|
unsigned long sz = sizeof initial_state_buf;
|
||||||
|
return global_state_initial (&buf, &sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
// standard runtime error callback function
|
||||||
|
extern nipsvm_status_t
|
||||||
|
nipsvm_default_error_cb (nipsvm_errorcode_t err, nipsvm_pid_t pid,
|
||||||
|
nipsvm_pc_t pc, void *priv_context)
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
// print runtime error to stderr
|
||||||
|
nipsvm_errorstring (str, sizeof str, err, pid, pc);
|
||||||
|
fprintf (stderr, "RUNTIME ERROR: %s\n", str);
|
||||||
|
// do not try to find successor states
|
||||||
|
return IC_STOP;
|
||||||
|
// keep compiler happy
|
||||||
|
priv_context = NULL;
|
||||||
|
}
|
||||||
124
iface/nips/nips_vm/nipsvm.h
Normal file
124
iface/nips/nips_vm/nipsvm.h
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#ifndef NIPSVM_H
|
||||||
|
#define NIPSVM_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
#include "instr.h"
|
||||||
|
|
||||||
|
typedef struct nipsvm_t nipsvm_t;
|
||||||
|
//typedef st_global_state_header nipsvm_state_t; // state.h
|
||||||
|
typedef struct nipsvm_transition_information_t nipsvm_transition_information_t;
|
||||||
|
typedef st_bytecode nipsvm_bytecode_t;
|
||||||
|
typedef et_ic_status nipsvm_status_t;
|
||||||
|
typedef et_instr_err nipsvm_errorcode_t;
|
||||||
|
typedef t_pid nipsvm_pid_t;
|
||||||
|
typedef t_pc nipsvm_pc_t;
|
||||||
|
|
||||||
|
typedef nipsvm_status_t (nipsvm_scheduler_callback_t)(size_t, nipsvm_state_t *,
|
||||||
|
nipsvm_transition_information_t *,
|
||||||
|
void *context);
|
||||||
|
typedef nipsvm_status_t (nipsvm_error_callback_t)(nipsvm_errorcode_t, nipsvm_pid_t,
|
||||||
|
nipsvm_pc_t, void *context);
|
||||||
|
|
||||||
|
/* must be called once before using any other function of this
|
||||||
|
* module.
|
||||||
|
* Idempotent.
|
||||||
|
*/
|
||||||
|
extern int
|
||||||
|
nipsvm_module_init();
|
||||||
|
|
||||||
|
/* Initialize given VM structure (allocated elsewhere).
|
||||||
|
* Returns 0 on success.
|
||||||
|
*
|
||||||
|
* Usage pattern:
|
||||||
|
* { nipsvm_t vm;
|
||||||
|
* if (nipsvm_init (&vm, ...) != 0) error();
|
||||||
|
* ...
|
||||||
|
* nipsvm_finalize (&vm); }
|
||||||
|
*/
|
||||||
|
extern int
|
||||||
|
nipsvm_init (nipsvm_t *, nipsvm_bytecode_t *,
|
||||||
|
nipsvm_scheduler_callback_t *, nipsvm_error_callback_t *);
|
||||||
|
extern void *
|
||||||
|
nipsvm_finalize (nipsvm_t *);
|
||||||
|
|
||||||
|
|
||||||
|
/* returned initial state is transient, must be copied by caller */
|
||||||
|
extern nipsvm_state_t *
|
||||||
|
nipsvm_initial_state (nipsvm_t *);
|
||||||
|
|
||||||
|
/* calculates successor states of ``state'' and calls callback
|
||||||
|
* previously registered in ``vm'' for each.
|
||||||
|
* ``context'' is given to the callback verbatim.
|
||||||
|
*/
|
||||||
|
extern unsigned int
|
||||||
|
nipsvm_scheduler_iter (nipsvm_t *vm, nipsvm_state_t *state, void *context);
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
nipsvm_state_size (nipsvm_state_t *state) { return global_state_size (state); }
|
||||||
|
|
||||||
|
// Copy VM state into given buffer
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// Returns NULL in case of error
|
||||||
|
extern nipsvm_state_t *
|
||||||
|
nipsvm_state_copy (size_t sz, nipsvm_state_t *p_glob, char **pp_buf,
|
||||||
|
unsigned long *p_buf_len);
|
||||||
|
|
||||||
|
// Compare two states
|
||||||
|
// Returns 0 if equal, -1 or 1 if not equal
|
||||||
|
static inline int
|
||||||
|
nipsvm_state_compare (nipsvm_state_t *p_glob1, nipsvm_state_t *p_glob2, size_t size)
|
||||||
|
{
|
||||||
|
return memcmp (p_glob1, p_glob2, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the monitor process is in an accepting state
|
||||||
|
// Returns 0 if no monitor exists or it is not in an accepting state
|
||||||
|
// Returns 1 if a monitor exists and is in an accpeting state
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_accepting (nipsvm_state_t *);
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the monitor process is terminated
|
||||||
|
// Returns 0 if no monitor exists or it is not terminated
|
||||||
|
// Returns 1 if a monitor exists and is in terminated
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_terminated (nipsvm_state_t *);
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the monitor process is in an accepting state or terminated
|
||||||
|
// (This is the equivalent function of SPIN's accepting states in the never claim.)
|
||||||
|
// Returns 0 if no monitor exists or it is not in an accepting state and not terminated
|
||||||
|
// Returns 1 if a monitor exists and is in an accpeting state or terminated
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_acc_or_term (nipsvm_state_t *state);
|
||||||
|
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_errorstring (char *str, size_t size, nipsvm_errorcode_t err,
|
||||||
|
nipsvm_pid_t pid, nipsvm_pc_t pc);
|
||||||
|
|
||||||
|
extern nipsvm_error_callback_t nipsvm_default_error_cb;
|
||||||
|
|
||||||
|
/* Internal */
|
||||||
|
struct nipsvm_t {
|
||||||
|
nipsvm_scheduler_callback_t *callback;
|
||||||
|
nipsvm_error_callback_t *error_callback;
|
||||||
|
void *callback_context;
|
||||||
|
st_instr_succ_context insn_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline size_t
|
||||||
|
sizeof_nipsvm_t() { return sizeof (nipsvm_t); }
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
19
iface/nips/nips_vm/rt_err.c
Normal file
19
iface/nips/nips_vm/rt_err.c
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 "rt_err.h"
|
||||||
|
|
||||||
|
|
||||||
|
// generate a runtime error and abort program
|
||||||
|
void rt_err( char *err_msg ) // extern
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: %s\n", err_msg );
|
||||||
|
exit( -1 );
|
||||||
|
}
|
||||||
27
iface/nips/nips_vm/rt_err.h
Normal file
27
iface/nips/nips_vm/rt_err.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_rt_err
|
||||||
|
#define INC_rt_err
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// generate a runtime error and abort program
|
||||||
|
extern void rt_err( char *err_msg );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_rt_err
|
||||||
346
iface/nips/nips_vm/search.c
Normal file
346
iface/nips/nips_vm/search.c
Normal file
|
|
@ -0,0 +1,346 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <assert.h>
|
||||||
|
|
||||||
|
#include "timeval.h"
|
||||||
|
|
||||||
|
#include "rt_err.h"
|
||||||
|
#include "hashtab.h"
|
||||||
|
|
||||||
|
#include "search.h"
|
||||||
|
|
||||||
|
// context for depth-first search
|
||||||
|
typedef struct t_search_context
|
||||||
|
{
|
||||||
|
unsigned int depth_max; // maximum depth that may be reached (only for depth-first search)
|
||||||
|
unsigned int depth_reached; // maximum depth that was reached (only for depth-first search)
|
||||||
|
unsigned long state_cnt; // number of states visited
|
||||||
|
unsigned long transition_cnt; // number of transitions
|
||||||
|
unsigned long n_atomic_steps; // number of atomic steps
|
||||||
|
unsigned int max_state_size; // maximum state size seen
|
||||||
|
char *p_buf; // pointer to current position in state buffer
|
||||||
|
unsigned long buf_len; // number of bytes left in buffer
|
||||||
|
t_hashtab hashtab; // hash table to find duplicate states
|
||||||
|
int error; // set in case of an error
|
||||||
|
nipsvm_t nipsvm; // context for successor state generation
|
||||||
|
FILE *graph_out; // stream to output state graph to
|
||||||
|
nipsvm_state_t *graph_out_pred; // pointer to predecessor state (for graph output)
|
||||||
|
int print_hex; // if to print states in hex
|
||||||
|
} st_search_context;
|
||||||
|
|
||||||
|
|
||||||
|
// print a state in hex
|
||||||
|
static void search_print_hex( nipsvm_state_t *state )
|
||||||
|
{
|
||||||
|
int size = nipsvm_state_size( state );
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < size; i++ )
|
||||||
|
printf( "%02X", (unsigned char)((char *)state)[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// successor callback function
|
||||||
|
nipsvm_status_t
|
||||||
|
search_succ_cb (size_t succ_sz, nipsvm_state_t *succ,
|
||||||
|
nipsvm_transition_information_t *t_info,
|
||||||
|
void *priv_context)
|
||||||
|
{
|
||||||
|
st_search_context *ctx = (st_search_context *)priv_context;
|
||||||
|
nipsvm_state_t **pos, *state;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
++ctx->transition_cnt;
|
||||||
|
if (succ->excl_pid != 0) {
|
||||||
|
++ctx->n_atomic_steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// output edge of graph
|
||||||
|
if( ctx->graph_out != NULL )
|
||||||
|
{
|
||||||
|
fprintf( ctx->graph_out, "\"" );
|
||||||
|
global_state_print_ex( ctx->graph_out, ctx->graph_out_pred, 1 );
|
||||||
|
fprintf( ctx->graph_out, "\" -> \"" );
|
||||||
|
global_state_print_ex( ctx->graph_out, succ, 1 );
|
||||||
|
fprintf( ctx->graph_out, "\";\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//print state in hex
|
||||||
|
if( ctx->print_hex )
|
||||||
|
{
|
||||||
|
printf( " " );
|
||||||
|
search_print_hex( succ );
|
||||||
|
}
|
||||||
|
|
||||||
|
// get position for/of state in hash table
|
||||||
|
result = hashtab_get_pos( ctx->hashtab, succ_sz, succ, &pos );
|
||||||
|
|
||||||
|
if( result < 0 )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: unresolvable hash conflict (try \"-h\")\n" );
|
||||||
|
ctx->error = 1;
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// state already in hash table
|
||||||
|
if( result == 0 )
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// copy successor state into buffer
|
||||||
|
state = nipsvm_state_copy( succ_sz, succ, &ctx->p_buf, &ctx->buf_len );
|
||||||
|
if( state == NULL )
|
||||||
|
{
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: out of state memory (try \"-b\")\n" );
|
||||||
|
ctx->error = 1;
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put state into hash table
|
||||||
|
*pos = state;
|
||||||
|
|
||||||
|
// go on finding successor states
|
||||||
|
return IC_CONTINUE;
|
||||||
|
|
||||||
|
// keep compiler happy
|
||||||
|
t_info = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// runtime error callback function
|
||||||
|
nipsvm_status_t
|
||||||
|
search_err_cb (nipsvm_errorcode_t err, nipsvm_pid_t pid, nipsvm_pc_t pc, void *priv_context) // extern
|
||||||
|
{
|
||||||
|
st_search_context *ctx = (st_search_context *)priv_context;
|
||||||
|
char str[256];
|
||||||
|
|
||||||
|
// print runtime error to stderr
|
||||||
|
nipsvm_errorstring( str, sizeof str, err, pid, pc );
|
||||||
|
fprintf( stderr, "RUNTIME ERROR: %s\n", str );
|
||||||
|
|
||||||
|
// remember error and stop
|
||||||
|
ctx->error = 1;
|
||||||
|
return IC_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// depth-first search in state space
|
||||||
|
static void
|
||||||
|
search_internal_dfs_to_depth (nipsvm_state_t *state,
|
||||||
|
unsigned int depth_cur,
|
||||||
|
st_search_context *ctx)
|
||||||
|
{
|
||||||
|
char *start, *end;
|
||||||
|
unsigned int state_size;
|
||||||
|
|
||||||
|
// check maximum depth
|
||||||
|
if( depth_cur > ctx->depth_max )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// update reached depth
|
||||||
|
if( depth_cur > ctx->depth_reached )
|
||||||
|
ctx->depth_reached = depth_cur;
|
||||||
|
|
||||||
|
// count states
|
||||||
|
ctx->state_cnt++;
|
||||||
|
|
||||||
|
// generate successor states
|
||||||
|
start = ctx->p_buf; // remember pointer to start of successor states
|
||||||
|
if( ctx->print_hex )
|
||||||
|
{
|
||||||
|
search_print_hex( state );
|
||||||
|
printf( " ->" );
|
||||||
|
}
|
||||||
|
nipsvm_scheduler_iter (&ctx->nipsvm, state, ctx);
|
||||||
|
if( ctx->print_hex )
|
||||||
|
printf( "\n" );
|
||||||
|
end = ctx->p_buf; // remember pointer behind end of successor states
|
||||||
|
|
||||||
|
// continue with depth first search
|
||||||
|
while( start < end && ! ctx->error ) // abort on error
|
||||||
|
{
|
||||||
|
ctx->graph_out_pred = (nipsvm_state_t *)start;
|
||||||
|
search_internal_dfs_to_depth( (nipsvm_state_t *)start, depth_cur + 1, ctx );
|
||||||
|
state_size = nipsvm_state_size( (nipsvm_state_t *)start );
|
||||||
|
start += state_size;
|
||||||
|
|
||||||
|
// remember maximum state size
|
||||||
|
if( state_size > ctx->max_state_size )
|
||||||
|
ctx->max_state_size = state_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// breadth-first search in state space
|
||||||
|
static void
|
||||||
|
search_internal_bfs (nipsvm_state_t *state, st_search_context *ctx)
|
||||||
|
{
|
||||||
|
size_t state_size;
|
||||||
|
|
||||||
|
// as long as there is a state
|
||||||
|
while( (char *)state < ctx->p_buf && ! ctx->error ) // abort on error
|
||||||
|
{
|
||||||
|
// count states
|
||||||
|
ctx->state_cnt++;
|
||||||
|
|
||||||
|
// generate successor states
|
||||||
|
ctx->graph_out_pred = state;
|
||||||
|
if( ctx->print_hex )
|
||||||
|
{
|
||||||
|
search_print_hex( state );
|
||||||
|
printf( " ->" );
|
||||||
|
}
|
||||||
|
nipsvm_scheduler_iter (&ctx->nipsvm, state, ctx);
|
||||||
|
if( ctx->print_hex )
|
||||||
|
printf( "\n" );
|
||||||
|
|
||||||
|
// state is processed (jump over it)
|
||||||
|
state_size = nipsvm_state_size (state);
|
||||||
|
state = (nipsvm_state_t *)((char*)state + state_size);
|
||||||
|
|
||||||
|
// remember maximum state size
|
||||||
|
if( state_size > ctx->max_state_size )
|
||||||
|
ctx->max_state_size = state_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// do a depth-first or breadth-first search in state space up to specified depth
|
||||||
|
// bfs: boolean flag if to do a breadth-first seach (depth_max is ignored in this case)
|
||||||
|
// buffer_len: size of state buffer
|
||||||
|
// hash_entries, hash_retries: parameters of hash table to finf duplicate states
|
||||||
|
// graph_out: if != NULL state graph will be output to this tream in graphviz dot format
|
||||||
|
// print_hex: if to print states in hex
|
||||||
|
// ini_state: state to start simulation at (or NULL to use default)
|
||||||
|
void
|
||||||
|
search (nipsvm_bytecode_t *bytecode, int bfs, unsigned int depth_max, unsigned long buffer_len,
|
||||||
|
unsigned long hash_entries, unsigned long hash_retries, FILE *graph_out, int print_hex,
|
||||||
|
nipsvm_state_t *ini_state) // extern
|
||||||
|
{
|
||||||
|
char *p_buffer, *p_buf;
|
||||||
|
t_hashtab hashtab;
|
||||||
|
unsigned long buf_len;
|
||||||
|
nipsvm_state_t *state;
|
||||||
|
st_search_context ctx;
|
||||||
|
struct timeval time_start, time_end, time_diff;
|
||||||
|
double us_state;
|
||||||
|
|
||||||
|
// allocate buffer for states
|
||||||
|
p_buffer = (char *)malloc( buffer_len );
|
||||||
|
if( p_buffer == NULL )
|
||||||
|
rt_err( "out of memory (state buffer for search)" );
|
||||||
|
p_buf = p_buffer;
|
||||||
|
buf_len = buffer_len;
|
||||||
|
// allocate hash table
|
||||||
|
hashtab = hashtab_new( hash_entries, hash_retries );
|
||||||
|
if( hashtab == NULL )
|
||||||
|
rt_err( "out of memory (hash table)" );
|
||||||
|
|
||||||
|
// tell user to wait
|
||||||
|
if( bfs )
|
||||||
|
printf( "doing breadth-first search, please wait...\n" );
|
||||||
|
else
|
||||||
|
printf( "doing depth-first search up to depth %u, please wait...\n", depth_max );
|
||||||
|
|
||||||
|
// remember start time
|
||||||
|
gettimeofday( &time_start, NULL );
|
||||||
|
|
||||||
|
// set up context for successor state generation
|
||||||
|
nipsvm_init (&ctx.nipsvm, bytecode, &search_succ_cb, &search_err_cb);
|
||||||
|
|
||||||
|
// get initial state
|
||||||
|
if( ini_state == NULL ) {
|
||||||
|
ini_state = nipsvm_initial_state (&ctx.nipsvm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert initial state into table
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size (ini_state);
|
||||||
|
state = nipsvm_state_copy (sz, ini_state, &p_buf, &buf_len);
|
||||||
|
hashtab_insert (hashtab, sz, ini_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up rest of context for search
|
||||||
|
ctx.depth_max = depth_max;
|
||||||
|
ctx.depth_reached = 0;
|
||||||
|
ctx.state_cnt = 0;
|
||||||
|
ctx.transition_cnt = 0;
|
||||||
|
ctx.n_atomic_steps = 0;
|
||||||
|
ctx.max_state_size = 0;
|
||||||
|
ctx.p_buf = p_buf;
|
||||||
|
ctx.buf_len = buf_len;
|
||||||
|
ctx.hashtab = hashtab;
|
||||||
|
ctx.error = 0;
|
||||||
|
ctx.graph_out = graph_out;
|
||||||
|
ctx.graph_out_pred = state;
|
||||||
|
ctx.print_hex = print_hex;
|
||||||
|
|
||||||
|
// start search
|
||||||
|
if( bfs )
|
||||||
|
search_internal_bfs( state, &ctx );
|
||||||
|
else
|
||||||
|
search_internal_dfs_to_depth( state, 0, &ctx );
|
||||||
|
|
||||||
|
nipsvm_finalize (&ctx.nipsvm);
|
||||||
|
|
||||||
|
// update pointer and length of state buffer
|
||||||
|
p_buf = ctx.p_buf;
|
||||||
|
buf_len = ctx.buf_len;
|
||||||
|
|
||||||
|
// remember end time
|
||||||
|
gettimeofday( &time_end, NULL );
|
||||||
|
// get time difference
|
||||||
|
time_diff.tv_usec = time_end.tv_usec - time_start.tv_usec;
|
||||||
|
time_diff.tv_sec = time_end.tv_sec - time_start.tv_sec;
|
||||||
|
if( time_diff.tv_usec < 0 )
|
||||||
|
{
|
||||||
|
time_diff.tv_usec += 1000000;
|
||||||
|
time_diff.tv_sec--;
|
||||||
|
}
|
||||||
|
// get time per state (in microseconds)
|
||||||
|
us_state = ((double)time_diff.tv_sec * 1000000.0 + (double)time_diff.tv_usec)
|
||||||
|
/ (double)ctx.state_cnt;
|
||||||
|
|
||||||
|
// print statistics
|
||||||
|
table_statistics_t t_stats;
|
||||||
|
table_statistics (hashtab, &t_stats);
|
||||||
|
unsigned long used_buffer_space = buffer_len - buf_len;
|
||||||
|
double table_fill_ratio = 100.0 * (double)t_stats.entries_used / (double)t_stats.entries_available;
|
||||||
|
double state_memory_fill_ratio = 100.0 * (double)used_buffer_space / (double)buffer_len;
|
||||||
|
|
||||||
|
printf( "\n" );
|
||||||
|
if( bfs )
|
||||||
|
printf( "breadth-first search %s:\n", ctx.error ? "aborted" : "completed" );
|
||||||
|
else
|
||||||
|
printf( "depth-first search up to depth %u %s:\n", depth_max, ctx.error ? "aborted" : "completed" );
|
||||||
|
printf( " states visited: %lu\n", ctx.state_cnt );
|
||||||
|
printf( " transitions visited: %lu\n", ctx.transition_cnt );
|
||||||
|
printf( " atomic steps: %lu\n", ctx.n_atomic_steps );
|
||||||
|
printf( " maximum state size: %u\n", ctx.max_state_size );
|
||||||
|
if( ! bfs )
|
||||||
|
printf( " reached depth: %u\n", ctx.depth_reached );
|
||||||
|
printf( " total time: %lu.%06lu s\n"
|
||||||
|
" time per state: %f us\n", time_diff.tv_sec,
|
||||||
|
(unsigned long)time_diff.tv_usec, us_state );
|
||||||
|
printf( "\n" );
|
||||||
|
printf( "state memory statistics:\n" );
|
||||||
|
printf( " total: %0.2fMB\n", buffer_len / 1048576.0 );
|
||||||
|
printf( " used: %0.2fMB (%0.1f%%)\n", used_buffer_space / 1048576.0,
|
||||||
|
state_memory_fill_ratio );
|
||||||
|
printf( "\n" );
|
||||||
|
printf( "state table statistics:\n"
|
||||||
|
" memory usage: %0.2fMB\n", t_stats.memory_size / 1048576.0 );
|
||||||
|
printf( " buckets used/available: %lu/%lu (%0.1f%%)\n", t_stats.entries_used,
|
||||||
|
t_stats.entries_available, table_fill_ratio );
|
||||||
|
printf( " max. no. of retries: %lu\n", t_stats.max_retries );
|
||||||
|
printf( " conflicts (resolved): %lu\n", t_stats.conflicts );
|
||||||
|
|
||||||
|
// free state buffer and hash table
|
||||||
|
free( p_buffer );
|
||||||
|
hashtab_free( hashtab );
|
||||||
|
}
|
||||||
37
iface/nips/nips_vm/search.h
Normal file
37
iface/nips/nips_vm/search.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_search
|
||||||
|
#define INC_search
|
||||||
|
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// do a depth-first or breadth-first search in state space up to specified depth
|
||||||
|
// bfs: boolean flag if to do a breadth-first seach (depth_max is ignored in this case)
|
||||||
|
// buffer_len: size of state buffer
|
||||||
|
// hash_entries, hash_retries: parameters of hash table to finf duplicate states
|
||||||
|
// graph_out: if != NULL state graph will be output to this tream in graphviz dot format
|
||||||
|
// print_hex: if to print states in hex
|
||||||
|
// ini_state: state to start simulation at (or NULL to use default)
|
||||||
|
extern void search( nipsvm_bytecode_t *bytecode, int bfs, unsigned int depth_max, unsigned long buffer_len,
|
||||||
|
unsigned long hash_entries, unsigned long hash_retries, FILE *graph_out, int print_hex,
|
||||||
|
st_global_state_header *ini_state );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // #ifndef INC_search
|
||||||
105
iface/nips/nips_vm/split.c
Normal file
105
iface/nips/nips_vm/split.c
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <string.h>
|
||||||
|
|
||||||
|
#include "split.h"
|
||||||
|
#include "state_parts.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
// out context for splitting up the state and reassembling ist
|
||||||
|
typedef struct t_split_ctx
|
||||||
|
{
|
||||||
|
char *parts[512];
|
||||||
|
unsigned int part_cnt;
|
||||||
|
char *p_buf;
|
||||||
|
unsigned int buf_len;
|
||||||
|
unsigned int parts_size;
|
||||||
|
unsigned int restore_cnt;
|
||||||
|
} st_split_ctx;
|
||||||
|
|
||||||
|
|
||||||
|
// callback to save a part
|
||||||
|
void part_cb( char *p_part, unsigned int part_size, void *vp_ctx )
|
||||||
|
{
|
||||||
|
st_split_ctx *p_ctx = (st_split_ctx *)vp_ctx;
|
||||||
|
if( p_ctx->part_cnt < count( p_ctx->parts ) && // free pointer storage
|
||||||
|
part_size <= p_ctx->buf_len ) // free buffer space
|
||||||
|
{
|
||||||
|
memcpy( p_ctx->p_buf, p_part, part_size ); // copy part
|
||||||
|
p_ctx->parts[p_ctx->part_cnt] = p_ctx->p_buf; // save pointer
|
||||||
|
p_ctx->part_cnt++; // count pointers
|
||||||
|
p_ctx->p_buf += part_size; // reduce buffer space
|
||||||
|
p_ctx->buf_len -= part_size;
|
||||||
|
p_ctx->parts_size += part_size; // count total size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// callbacks to deliver parts for restoring state
|
||||||
|
unsigned int restore_cb( char *p_buf, unsigned int buf_len, void *vp_ctx, unsigned int (*part_size)( char * ) )
|
||||||
|
{
|
||||||
|
st_split_ctx *p_ctx = (st_split_ctx *)vp_ctx;
|
||||||
|
if( p_ctx->restore_cnt >= p_ctx->part_cnt ) // no more parts
|
||||||
|
return 0;
|
||||||
|
unsigned int sz = part_size( p_ctx->parts[p_ctx->restore_cnt] ); // get size
|
||||||
|
if( buf_len < sz ) // no more buffer space
|
||||||
|
return 0;
|
||||||
|
memcpy( p_buf, p_ctx->parts[p_ctx->restore_cnt], sz ); // copy part
|
||||||
|
p_ctx->restore_cnt++; // next part
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
unsigned int glob_cb( char *p_buf, unsigned int buf_len, void *vp_ctx )
|
||||||
|
{
|
||||||
|
return restore_cb( p_buf, buf_len, vp_ctx, glob_part_size );
|
||||||
|
}
|
||||||
|
unsigned int proc_cb( char *p_buf, unsigned int buf_len, void *vp_ctx )
|
||||||
|
{
|
||||||
|
return restore_cb( p_buf, buf_len, vp_ctx, proc_part_size );
|
||||||
|
}
|
||||||
|
unsigned int chan_cb( char *p_buf, unsigned int buf_len, void *vp_ctx )
|
||||||
|
{
|
||||||
|
return restore_cb( p_buf, buf_len, vp_ctx, chan_part_size );
|
||||||
|
}
|
||||||
|
|
||||||
|
// split a state and recreate it from its parts - then compare it
|
||||||
|
// - used to test state_parts
|
||||||
|
// - outputs some info if stream != NULL
|
||||||
|
// - returns boolean flag if success
|
||||||
|
int split_test( st_global_state_header * p_glob, FILE * stream ) // extern
|
||||||
|
{
|
||||||
|
char buffer[65536]; // some memory to store the parts of the state
|
||||||
|
st_split_ctx ctx;
|
||||||
|
ctx.part_cnt = 0;
|
||||||
|
ctx.p_buf = buffer;
|
||||||
|
ctx.buf_len = sizeof( buffer );
|
||||||
|
ctx.parts_size = 0;
|
||||||
|
ctx.restore_cnt = 0;
|
||||||
|
|
||||||
|
// split up state
|
||||||
|
state_parts( p_glob, part_cb, part_cb, part_cb, &ctx );
|
||||||
|
if( stream != NULL )
|
||||||
|
fprintf( stream, "splitted state into %d parts with total size %d\n",
|
||||||
|
ctx.part_cnt, ctx.parts_size );
|
||||||
|
|
||||||
|
// restore state
|
||||||
|
char restore[65536];
|
||||||
|
st_global_state_header *p_restored = state_restore( restore, sizeof( restore ), glob_cb, proc_cb, chan_cb, &ctx );
|
||||||
|
if( p_restored == NULL )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// compare
|
||||||
|
int ok = nipsvm_state_compare( p_glob, p_restored, nipsvm_state_size (p_glob) ) == 0;
|
||||||
|
if( stream != NULL )
|
||||||
|
fprintf( stream, "comparing restored state with original one: %s\n",
|
||||||
|
ok ? "identical" : "DIFFERENT" );
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
33
iface/nips/nips_vm/split.h
Normal file
33
iface/nips/nips_vm/split.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_split
|
||||||
|
#define INC_split
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
|
||||||
|
// split a state and recreate it from its parts - then compare it
|
||||||
|
// - used to test state_parts
|
||||||
|
// - outputs some info if stream != NULL
|
||||||
|
// - returns boolean flag if success
|
||||||
|
extern int split_test( st_global_state_header * p_glob, FILE * stream );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_split
|
||||||
646
iface/nips/nips_vm/state.c
Normal file
646
iface/nips/nips_vm/state.c
Normal file
|
|
@ -0,0 +1,646 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
#include "nipsvm.h"
|
||||||
|
|
||||||
|
#define STATE_OUT_DOTTY_LINE_END "\\l\\"
|
||||||
|
|
||||||
|
|
||||||
|
// import functions as "extern" for unoptimized compilation
|
||||||
|
#define STATE_INLINE extern
|
||||||
|
#include "state_inline.h"
|
||||||
|
#undef STATE_INLINE
|
||||||
|
|
||||||
|
// *** helper functions ***
|
||||||
|
|
||||||
|
// allocate memory of size sz in supplied buffer
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for allocation
|
||||||
|
// NULL is returned in case of insufficient memory
|
||||||
|
static inline char * state_alloc( unsigned int sz, char **pp_buf, unsigned long *p_buf_len )
|
||||||
|
{
|
||||||
|
if( *p_buf_len < sz ) return NULL;
|
||||||
|
char *p_new = *pp_buf;
|
||||||
|
*pp_buf += sz;
|
||||||
|
*p_buf_len -= sz;
|
||||||
|
memset( p_new, 0, sz ); // needed because of gaps in structures caused by alignment
|
||||||
|
return p_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** functions visible from outside ***
|
||||||
|
|
||||||
|
// generate initial state
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// NULL is returned in case of error
|
||||||
|
st_global_state_header * global_state_initial( char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
st_global_state_header *p_glob = (st_global_state_header *)state_alloc( global_state_initial_size, pp_buf, p_buf_len );
|
||||||
|
if( p_glob == NULL ) return NULL;
|
||||||
|
p_glob->gvar_sz = h2be_16( 0 ); // global header
|
||||||
|
p_glob->proc_cnt = 1;
|
||||||
|
p_glob->excl_pid = h2be_pid( 0 );
|
||||||
|
p_glob->monitor_pid = h2be_pid( 0 );
|
||||||
|
p_glob->chan_cnt = 0;
|
||||||
|
st_process_header *p_proc = (st_process_header *)((char *)p_glob + sizeof( st_global_state_header )); // process header
|
||||||
|
p_proc->pid = h2be_pid( 1 );
|
||||||
|
p_proc->flags = 0;
|
||||||
|
p_proc->lvar_sz = 0;
|
||||||
|
p_proc->pc = h2be_pc( 0 );
|
||||||
|
return p_glob;
|
||||||
|
}
|
||||||
|
|
||||||
|
nipsvm_state_t *
|
||||||
|
nipsvm_state_copy (size_t sz, nipsvm_state_t *p_glob, char **pp_buf,
|
||||||
|
unsigned long *p_buf_len)
|
||||||
|
{
|
||||||
|
nipsvm_state_t *p_glob_new = (nipsvm_state_t *)state_alloc (sz, pp_buf, p_buf_len);
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
memcpy (p_glob_new, p_glob, sz); // simply copy
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEPRECATED */
|
||||||
|
st_global_state_header * global_state_copy( st_global_state_header *p_glob,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size( p_glob );
|
||||||
|
return nipsvm_state_copy (sz, p_glob, pp_buf, p_buf_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with resized global variables
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
st_global_state_header * global_state_copy_gvar_sz( st_global_state_header *p_glob,
|
||||||
|
uint16_t gvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
unsigned int sz = nipsvm_state_size( p_glob ) - be2h_16( p_glob->gvar_sz ) + gvar_sz; // allocate
|
||||||
|
st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len );
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
char *src = (char *)p_glob;
|
||||||
|
char *dest = (char *)p_glob_new;
|
||||||
|
memcpy( dest, src, sizeof( st_global_state_header ) ); // header
|
||||||
|
p_glob_new->gvar_sz = h2be_16( gvar_sz );
|
||||||
|
dest += sizeof( st_global_state_header );
|
||||||
|
src += sizeof( st_global_state_header );
|
||||||
|
sz -= sizeof( st_global_state_header );
|
||||||
|
memset( dest, 0, gvar_sz ); // variables
|
||||||
|
memcpy( dest, src, min( gvar_sz, be2h_16( p_glob->gvar_sz ) ) );
|
||||||
|
dest += gvar_sz;
|
||||||
|
src += be2h_16( p_glob->gvar_sz );
|
||||||
|
sz -= gvar_sz;
|
||||||
|
memcpy( dest, src, sz ); // rest of state
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with resized local variables
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
st_global_state_header * global_state_copy_lvar_sz( st_global_state_header *p_glob,
|
||||||
|
st_process_header *p_proc, uint8_t lvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len ) // extern
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size( p_glob ) - p_proc->lvar_sz + lvar_sz; // allocate
|
||||||
|
st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len );
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
char *src = (char *)p_glob;
|
||||||
|
char *dest = (char *)p_glob_new;
|
||||||
|
unsigned int len = (char *)p_proc - (char *)p_glob; // size before process
|
||||||
|
st_process_header *p_proc_new = (st_process_header *)((char*)p_glob_new + len); // pointer to process in new state
|
||||||
|
if( p_proc->flags & PROCESS_FLAGS_ACTIVE ) // size of process header
|
||||||
|
len += sizeof( st_process_active_header );
|
||||||
|
else
|
||||||
|
len += sizeof( st_process_header );
|
||||||
|
memcpy( dest, src, len ); // part before process and process header
|
||||||
|
p_proc_new->lvar_sz = lvar_sz;
|
||||||
|
dest += len;
|
||||||
|
src += len;
|
||||||
|
sz -= len;
|
||||||
|
memset( dest, 0, lvar_sz ); // variables
|
||||||
|
memcpy( dest, src, min( lvar_sz, p_proc->lvar_sz ) );
|
||||||
|
dest += lvar_sz;
|
||||||
|
src += p_proc->lvar_sz;
|
||||||
|
sz -= lvar_sz;
|
||||||
|
memcpy( dest, src, sz ); // rest of state
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with selected process activated
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// *pp_proc is filled with the pointer to the activated process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
st_global_state_header * global_state_copy_activate( st_global_state_header *p_glob, st_process_header *p_proc,
|
||||||
|
uint8_t stack_max, t_flag_reg flag_reg,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_process_active_header **pp_proc ) // extern
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size( p_glob ) // allocate
|
||||||
|
- sizeof( st_process_header )
|
||||||
|
+ sizeof( st_process_active_header )
|
||||||
|
+ stack_max * sizeof( t_val );
|
||||||
|
st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len );
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
char *src = (char *)p_glob;
|
||||||
|
char *dest = (char *)p_glob_new;
|
||||||
|
unsigned int len = (char *)p_proc - (char *)p_glob; // part before process
|
||||||
|
memcpy( dest, src, len );
|
||||||
|
dest += len;
|
||||||
|
src += len;
|
||||||
|
sz -= len;
|
||||||
|
*pp_proc = (st_process_active_header *)dest; // return pointer to activated process
|
||||||
|
memcpy( dest, src, sizeof( st_process_header ) ); // process header
|
||||||
|
memset( ((st_process_active_header *)dest)->registers, 0, sizeof( ((st_process_active_header *)dest)->registers ) );
|
||||||
|
((st_process_active_header *)dest)->flag_reg = flag_reg;
|
||||||
|
((st_process_active_header *)dest)->proc.flags |= PROCESS_FLAGS_ACTIVE;
|
||||||
|
((st_process_active_header *)dest)->stack_cur = 0;
|
||||||
|
((st_process_active_header *)dest)->stack_max = stack_max;
|
||||||
|
dest += sizeof( st_process_active_header );
|
||||||
|
src += sizeof( st_process_header );
|
||||||
|
sz -= sizeof( st_process_active_header );
|
||||||
|
memcpy( dest, src, p_proc->lvar_sz ); // local variables
|
||||||
|
dest += p_proc->lvar_sz;
|
||||||
|
src += p_proc->lvar_sz;
|
||||||
|
sz -= p_proc->lvar_sz;
|
||||||
|
len = stack_max * sizeof( t_val ); // stack
|
||||||
|
memset( dest, 0, len );
|
||||||
|
dest += len;
|
||||||
|
sz -= len;
|
||||||
|
memcpy( dest, src, sz ); // rest of state
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with an additional process
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// *pp_proc is filled with the pointer to the new process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
st_global_state_header * global_state_copy_new_process( st_global_state_header *p_glob,
|
||||||
|
t_pid new_pid, uint8_t lvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_process_header **pp_proc ) // extern
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size( p_glob ) // allocate
|
||||||
|
+ sizeof( st_process_header )
|
||||||
|
+ lvar_sz;
|
||||||
|
st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len );
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
char *src = (char *)p_glob;
|
||||||
|
char *dest = (char *)p_glob_new;
|
||||||
|
unsigned int len = (char *)global_state_get_channels( p_glob ) - (char *)p_glob; // part to end of last process
|
||||||
|
memcpy( dest, src, len );
|
||||||
|
p_glob_new->proc_cnt++;
|
||||||
|
dest += len;
|
||||||
|
src += len;
|
||||||
|
sz -= len;
|
||||||
|
*pp_proc = (st_process_header *)dest; // new process
|
||||||
|
(*pp_proc)->pid = h2be_pid( new_pid );
|
||||||
|
(*pp_proc)->flags = 0;
|
||||||
|
(*pp_proc)->lvar_sz = lvar_sz;
|
||||||
|
(*pp_proc)->pc = h2be_pc( 0 );
|
||||||
|
dest += sizeof( st_process_header );
|
||||||
|
sz -= sizeof( st_process_header );
|
||||||
|
memset( dest, 0, lvar_sz );
|
||||||
|
dest += lvar_sz;
|
||||||
|
sz -= lvar_sz;
|
||||||
|
memcpy( dest, src, sz ); // rest of state
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with an additional channel
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// the new channel is inserted at the right place according to its channel id
|
||||||
|
// *pp_chan is filled with the pointer to the new process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
st_global_state_header * global_state_copy_new_channel( st_global_state_header *p_glob,
|
||||||
|
t_chid new_chid, uint8_t max_len, uint8_t type_len, uint8_t msg_len,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_channel_header **pp_chan ) // extern
|
||||||
|
{
|
||||||
|
size_t len = nipsvm_state_size( p_glob );
|
||||||
|
char * ptr = global_state_get_channels( p_glob ); // find place to insert new channel
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < (int)p_glob->chan_cnt; i++ )
|
||||||
|
{
|
||||||
|
if( be2h_chid( ((st_channel_header *)ptr)->chid ) == new_chid ) // duplicate chid -> error
|
||||||
|
return NULL;
|
||||||
|
if( be2h_chid( ((st_channel_header *)ptr)->chid ) > new_chid ) // place found
|
||||||
|
break;
|
||||||
|
ptr += channel_size( (st_channel_header *)ptr );
|
||||||
|
}
|
||||||
|
unsigned int len_before = ptr - (char *)p_glob; // get size of part before new channel
|
||||||
|
unsigned int len_chan = sizeof( st_channel_header ) // size of channel
|
||||||
|
+ type_len
|
||||||
|
+ max( 1, max_len ) * msg_len;
|
||||||
|
unsigned int sz = len + len_chan;
|
||||||
|
st_global_state_header *p_glob_new = (st_global_state_header *)state_alloc( sz, pp_buf, p_buf_len ); // allocate new state
|
||||||
|
if( p_glob_new == NULL ) return NULL;
|
||||||
|
char *src = (char *)p_glob;
|
||||||
|
char *dest = (char *)p_glob_new;
|
||||||
|
memcpy( dest, src, len_before ); // first part of old state
|
||||||
|
p_glob_new->chan_cnt++;
|
||||||
|
dest += len_before;
|
||||||
|
src += len_before;
|
||||||
|
sz -= len_before;
|
||||||
|
*pp_chan = (st_channel_header *)dest; // new channel
|
||||||
|
(*pp_chan)->chid = h2be_chid( new_chid );
|
||||||
|
(*pp_chan)->max_len = max_len;
|
||||||
|
(*pp_chan)->cur_len = 0;
|
||||||
|
(*pp_chan)->msg_len = msg_len;
|
||||||
|
(*pp_chan)->type_len = type_len;
|
||||||
|
dest += sizeof( st_channel_header );
|
||||||
|
sz -= sizeof( st_channel_header );
|
||||||
|
len_chan -= sizeof( st_channel_header );
|
||||||
|
memset( dest, 0, len_chan ); // types and content of new channel
|
||||||
|
dest += len_chan;
|
||||||
|
sz -= len_chan;
|
||||||
|
memcpy( dest, src, sz ); // rest of state
|
||||||
|
return p_glob_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// deactivate selected process in global state
|
||||||
|
void global_state_deactivate( st_global_state_header *p_glob, st_process_active_header *p_proc ) // extern
|
||||||
|
{
|
||||||
|
size_t sz = nipsvm_state_size( p_glob )
|
||||||
|
+ sizeof( st_process_header )
|
||||||
|
- sizeof( st_process_active_header )
|
||||||
|
- p_proc->stack_max * sizeof( t_val );
|
||||||
|
char *src = (char *)p_glob; // no new allocation must be done
|
||||||
|
char *dest = src; // because state becomes always smaller here
|
||||||
|
unsigned int len = (char *)p_proc - (char *)p_glob; // part before process
|
||||||
|
dest += len;
|
||||||
|
src += len;
|
||||||
|
sz -= len;
|
||||||
|
((st_process_header *)dest)->flags &= ~PROCESS_FLAGS_ACTIVE; // process header
|
||||||
|
dest += sizeof( st_process_header );
|
||||||
|
src += sizeof( st_process_active_header );
|
||||||
|
sz -= sizeof( st_process_header );
|
||||||
|
uint8_t lvar_sz = p_proc->proc.lvar_sz; // get size of local variables and stack
|
||||||
|
uint8_t stack_max = p_proc->stack_max;
|
||||||
|
memmove( dest, src, lvar_sz ); // local variables
|
||||||
|
dest += lvar_sz;
|
||||||
|
src += lvar_sz;
|
||||||
|
sz -= lvar_sz;
|
||||||
|
src += stack_max * sizeof( t_val ); // stack
|
||||||
|
memmove( dest, src, sz ); // rest of state
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remove selected process in global state
|
||||||
|
void global_state_remove( st_global_state_header *p_glob, st_process_header *p_proc ) // extern
|
||||||
|
{
|
||||||
|
unsigned int proc_sz = process_size( p_proc );
|
||||||
|
size_t sz = nipsvm_state_size( p_glob ) - proc_sz;
|
||||||
|
char *src = (char *)p_glob; // no new allocation must be done
|
||||||
|
char *dest = src; // because state becomes always smaller here
|
||||||
|
p_glob->proc_cnt--; // one process less
|
||||||
|
unsigned int len = (char *)p_proc - (char *)p_glob; // part before process
|
||||||
|
dest += len;
|
||||||
|
src += len;
|
||||||
|
sz -= len;
|
||||||
|
src += proc_sz; // remove process
|
||||||
|
memmove( dest, src, sz ); // rest of state
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// count enabled processes (i.e. processes that are not yet terminated)
|
||||||
|
// returns number of processes
|
||||||
|
unsigned int global_state_count_enabled_processes( st_global_state_header *p_glob ) // extern
|
||||||
|
{
|
||||||
|
char *ptr = global_state_get_processes( p_glob );
|
||||||
|
unsigned int i, cnt = 0;
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ )
|
||||||
|
{
|
||||||
|
if( (((st_process_header *)ptr)->flags & PROCESS_FLAGS_MODE) != PROCESS_FLAGS_MODE_TERMINATED )
|
||||||
|
cnt++;
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get enabled processes (i.e. processes that may be activated)
|
||||||
|
// returns number of processes or (unsigned int)-1 if there are too many enabled processes
|
||||||
|
unsigned int global_state_get_enabled_processes( st_global_state_header *p_glob, st_process_header **p_procs, unsigned int proc_max ) // extern
|
||||||
|
{
|
||||||
|
char *ptr = global_state_get_processes( p_glob );
|
||||||
|
unsigned int i, cnt = 0;
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ )
|
||||||
|
{
|
||||||
|
if( (((st_process_header *)ptr)->flags & PROCESS_FLAGS_MODE) != PROCESS_FLAGS_MODE_TERMINATED )
|
||||||
|
{
|
||||||
|
if( cnt >= proc_max ) return (unsigned int)-1;
|
||||||
|
p_procs[cnt++] = (st_process_header *)ptr;
|
||||||
|
}
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_accepting (nipsvm_state_t *p_glob)
|
||||||
|
{
|
||||||
|
st_process_header *p_monitor = global_state_get_process( p_glob, be2h_pid( p_glob->monitor_pid ) );
|
||||||
|
if (p_monitor == NULL)
|
||||||
|
return 0;
|
||||||
|
return (p_monitor->flags & PROCESS_FLAGS_MONITOR_ACCEPT) != 0; // force result 0 or 1
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_terminated (nipsvm_state_t *p_glob)
|
||||||
|
{
|
||||||
|
// check that there is a monitor process (or at least a pid of some former monitor process)
|
||||||
|
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
|
||||||
|
if( monitor_pid == 0 ) // no monitor
|
||||||
|
return 0;
|
||||||
|
// get monitor process
|
||||||
|
st_process_header *p_monitor = global_state_get_process( p_glob, monitor_pid );
|
||||||
|
// return if monitor not available or terminated
|
||||||
|
return p_monitor == NULL
|
||||||
|
|| (p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int
|
||||||
|
nipsvm_state_monitor_acc_or_term (nipsvm_state_t *p_glob)
|
||||||
|
{
|
||||||
|
// check that there is a monitor process (or at least a pid of some former monitor process)
|
||||||
|
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
|
||||||
|
if( monitor_pid == 0 ) // no monitor
|
||||||
|
return 0;
|
||||||
|
// get monitor process
|
||||||
|
st_process_header *p_monitor = global_state_get_process( p_glob, monitor_pid );
|
||||||
|
return p_monitor == NULL || // not availabale -> terminated
|
||||||
|
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED || // terminated
|
||||||
|
(p_monitor->flags & PROCESS_FLAGS_MONITOR_ACCEPT) != 0; // accepting state
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEPRECATED */
|
||||||
|
int global_state_monitor_accepting( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
return nipsvm_state_monitor_accepting (p_glob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEPRECATED */
|
||||||
|
int global_state_monitor_terminated( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
return nipsvm_state_monitor_terminated (p_glob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DEPRECATED */
|
||||||
|
int global_state_monitor_acc_or_term( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
return nipsvm_state_monitor_acc_or_term (p_glob);
|
||||||
|
}
|
||||||
|
|
||||||
|
// macro to shorten output to a string
|
||||||
|
// - p_buf: pointer to buffer to print string to
|
||||||
|
// - size: total size of buffer
|
||||||
|
// - pos: "unsigned int" variable containing current position in buffer
|
||||||
|
#define to_str( p_buf, size, pos, ... ) \
|
||||||
|
{ int cnt = snprintf( (p_buf) + pos, pos > (size) ? 0 : (size) - pos, __VA_ARGS__ ); \
|
||||||
|
pos += cnt < 0 ? 0 : cnt; }
|
||||||
|
|
||||||
|
|
||||||
|
// output a process to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
unsigned int process_to_str( st_process_header *p_proc, int dot_fmt, char *p_buf, unsigned int size ) // extern
|
||||||
|
{
|
||||||
|
unsigned int pos = 0;
|
||||||
|
int i;
|
||||||
|
char *ptr;
|
||||||
|
ua_t_val *val_ptr;
|
||||||
|
// dotty format?
|
||||||
|
char line_end[] = STATE_OUT_DOTTY_LINE_END;
|
||||||
|
if( ! dot_fmt )
|
||||||
|
line_end[0] = 0;
|
||||||
|
// header
|
||||||
|
to_str( p_buf, size, pos, " %sprocess pid=%u", p_proc->flags & PROCESS_FLAGS_ACTIVE ? "active " : "", be2h_pid( p_proc->pid ) );
|
||||||
|
switch( p_proc->flags & PROCESS_FLAGS_MODE )
|
||||||
|
{
|
||||||
|
case PROCESS_FLAGS_MODE_NORMAL: to_str( p_buf, size, pos, " mode=normal" ); break;
|
||||||
|
case PROCESS_FLAGS_MODE_ATOMIC: to_str( p_buf, size, pos, " mode=normal" ); break;
|
||||||
|
case PROCESS_FLAGS_MODE_INVISIBLE: to_str( p_buf, size, pos, " mode=invisible" ); break;
|
||||||
|
case PROCESS_FLAGS_MODE_TERMINATED: to_str( p_buf, size, pos, " mode=terminated" ); break;
|
||||||
|
default: to_str( p_buf, size, pos, " mode=?" );
|
||||||
|
}
|
||||||
|
to_str( p_buf, size, pos, " pc=0x%08X", be2h_pc( p_proc->pc ) );
|
||||||
|
to_str( p_buf, size, pos, " (size=%u)%s\n", process_size( p_proc ), line_end );
|
||||||
|
if( p_proc->flags & PROCESS_FLAGS_ACTIVE ) // process is active
|
||||||
|
{
|
||||||
|
to_str( p_buf, size, pos, " registers:" );
|
||||||
|
for( i = 0; i < 8; i++ )
|
||||||
|
to_str( p_buf, size, pos, " r%i=%d", i, ((st_process_active_header *)p_proc)->registers[i] );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
to_str( p_buf, size, pos, " flag register:" );
|
||||||
|
for( i = FLAG_REG_FLAG_CNT - 1; i >= 0; i-- )
|
||||||
|
to_str( p_buf, size, pos, "%s%d", (i & 7) == 7 ? " " : "",
|
||||||
|
((st_process_active_header *)p_proc)->flag_reg & 1 << i ? 1 : 0 );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
ptr = (char *)p_proc + sizeof( st_process_active_header );
|
||||||
|
}
|
||||||
|
else // process is not active
|
||||||
|
ptr = (char *)p_proc + sizeof( st_process_header );
|
||||||
|
// variables
|
||||||
|
to_str( p_buf, size, pos, " variables:" );
|
||||||
|
for( i = 0; i < (int)p_proc->lvar_sz; i++ )
|
||||||
|
to_str( p_buf, size, pos, " 0x%02X", (unsigned char)*(ptr++) );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
if( p_proc->flags & PROCESS_FLAGS_ACTIVE ) // process is active
|
||||||
|
{
|
||||||
|
// stack
|
||||||
|
to_str( p_buf, size, pos, " stack (max=%d):", ((st_process_active_header *)p_proc)->stack_max );
|
||||||
|
val_ptr = (ua_t_val *)ptr;
|
||||||
|
for( i = 0; i < (int)((st_process_active_header *)p_proc)->stack_cur; i++ )
|
||||||
|
to_str( p_buf, size, pos, " %d", (val_ptr++)->val );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output a channel to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
unsigned int channel_to_str( st_channel_header *p_chan, int dot_fmt, char *p_buf, unsigned int size ) // extern
|
||||||
|
{
|
||||||
|
unsigned int pos = 0;
|
||||||
|
int i, j;
|
||||||
|
// dotty format?
|
||||||
|
char line_end[] = STATE_OUT_DOTTY_LINE_END;
|
||||||
|
if( ! dot_fmt )
|
||||||
|
line_end[0] = 0;
|
||||||
|
// header
|
||||||
|
t_chid chid = be2h_chid( p_chan->chid );
|
||||||
|
to_str( p_buf, size, pos, " channel chid=0x%04X=%u-%u", chid, chid >> 8, chid & 0xFF );
|
||||||
|
to_str( p_buf, size, pos, " max_len=%u", p_chan->max_len );
|
||||||
|
to_str( p_buf, size, pos, " (size=%u)%s\n", channel_size( p_chan ), line_end );
|
||||||
|
// type
|
||||||
|
to_str( p_buf, size, pos, " type:" );
|
||||||
|
int8_t *p_type = (int8_t *)((char *)p_chan + sizeof( st_channel_header ));
|
||||||
|
for( i = 0; i < (int)p_chan->type_len; i++ )
|
||||||
|
to_str( p_buf, size, pos, " %d", p_type[i] );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
// messages
|
||||||
|
to_str( p_buf, size, pos, " messages:""%s\n", line_end );
|
||||||
|
char *ptr = (char *)p_type + p_chan->type_len;
|
||||||
|
for( i = 0; i < (int)p_chan->cur_len; i++ )
|
||||||
|
{
|
||||||
|
to_str( p_buf, size, pos, " %u) ", i + 1 );
|
||||||
|
for( j = 0; j < (int)p_chan->type_len; j++ )
|
||||||
|
{
|
||||||
|
if( p_type[j] < 0 ) // signed
|
||||||
|
{
|
||||||
|
if( p_type[j] >= -7 )
|
||||||
|
{ to_str( p_buf, size, pos, " %d", *(int8_t *)ptr ); ptr++; }
|
||||||
|
else if( p_type[j] >= -15 )
|
||||||
|
{ to_str( p_buf, size, pos, " %d", be2h_16( (int16_t)ua_rd_16( ptr ) ) ); ptr += 2; }
|
||||||
|
else
|
||||||
|
{ to_str( p_buf, size, pos, " %d", be2h_32( (int32_t)ua_rd_32( ptr ) ) ); ptr += 4; }
|
||||||
|
}
|
||||||
|
else // unsigned
|
||||||
|
{
|
||||||
|
if( p_type[j] <= 8 )
|
||||||
|
{ to_str( p_buf, size, pos, " %u", *(uint8_t *)ptr ); ptr++; }
|
||||||
|
else if( p_type[j] <= 16 )
|
||||||
|
{ to_str( p_buf, size, pos, " %u", be2h_16( (uint16_t)ua_rd_16( ptr ) ) ); ptr += 2; }
|
||||||
|
else
|
||||||
|
{ to_str( p_buf, size, pos, " %u", be2h_32( (uint32_t)ua_rd_32( ptr ) ) ); ptr += 4; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output a global state to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
unsigned int global_state_to_str( st_global_state_header *p_glob, int dot_fmt, char *p_buf, unsigned int size ) // extern
|
||||||
|
{
|
||||||
|
unsigned int pos = 0;
|
||||||
|
int i;
|
||||||
|
// dotty format?
|
||||||
|
char line_end[] = STATE_OUT_DOTTY_LINE_END;
|
||||||
|
if( ! dot_fmt )
|
||||||
|
line_end[0] = 0;
|
||||||
|
// header
|
||||||
|
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
|
||||||
|
to_str( p_buf, size, pos, "global state excl_pid=%u monitor_pid=%u",
|
||||||
|
be2h_pid( p_glob->excl_pid ),
|
||||||
|
monitor_pid );
|
||||||
|
to_str( p_buf, size, pos, " (size=%lu)%s\n", (unsigned long)nipsvm_state_size( p_glob ), line_end );
|
||||||
|
// variables
|
||||||
|
to_str( p_buf, size, pos, " variables:" );
|
||||||
|
char *ptr = (char *)p_glob + sizeof( st_global_state_header );
|
||||||
|
for( i = 0; i < (int)be2h_16( p_glob->gvar_sz ); i++ )
|
||||||
|
to_str( p_buf, size, pos, " 0x%02X", (unsigned char)*(ptr++) );
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
// processes
|
||||||
|
for( i = 0; i< (int)p_glob->proc_cnt; i++ )
|
||||||
|
{
|
||||||
|
int cnt = process_to_str( (st_process_header *)ptr, dot_fmt,
|
||||||
|
p_buf + pos, pos > size ? 0 : size - pos );
|
||||||
|
pos += cnt < 0 ? 0 : cnt;
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
}
|
||||||
|
// channels
|
||||||
|
for( i = 0; i< (int)p_glob->chan_cnt; i++ )
|
||||||
|
{
|
||||||
|
int cnt = channel_to_str( (st_channel_header *)ptr, dot_fmt,
|
||||||
|
p_buf + pos, pos > size ? 0 : size - pos );
|
||||||
|
pos += cnt < 0 ? 0 : cnt;
|
||||||
|
ptr += channel_size( (st_channel_header *)ptr );
|
||||||
|
}
|
||||||
|
// monitor flags
|
||||||
|
if (monitor_pid != 0) {
|
||||||
|
to_str (p_buf, size, pos, "Monitor:");
|
||||||
|
if (nipsvm_state_monitor_acc_or_term (p_glob)) {
|
||||||
|
to_str (p_buf, size, pos, " ACCEPTING");
|
||||||
|
}
|
||||||
|
if (nipsvm_state_monitor_terminated (p_glob)) {
|
||||||
|
to_str (p_buf, size, pos, " TERMINATED");
|
||||||
|
}
|
||||||
|
to_str( p_buf, size, pos, "%s\n", line_end );
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a process to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
void process_print_ex( FILE *out, st_process_header *p_proc, int dot_fmt ) // extern
|
||||||
|
{
|
||||||
|
unsigned int size = process_to_str( p_proc, dot_fmt, NULL, 0 ) + 1; // get needed buffer size
|
||||||
|
{
|
||||||
|
char buf[size]; // allocate buffer
|
||||||
|
process_to_str( p_proc, dot_fmt, buf, size ); // convert to string
|
||||||
|
fprintf( out, "%s", buf ); // output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a channel to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
void channel_print_ex( FILE *out, st_channel_header *p_chan, int dot_fmt ) // extern
|
||||||
|
{
|
||||||
|
unsigned int size = channel_to_str( p_chan, dot_fmt, NULL, 0 ) + 1; // get needed buffer size
|
||||||
|
{
|
||||||
|
char buf[size]; // allocate buffer
|
||||||
|
channel_to_str( p_chan, dot_fmt, buf, size ); // convert to string
|
||||||
|
fprintf( out, "%s", buf ); // output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a global state to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
void global_state_print_ex( FILE *out, st_global_state_header *p_glob, int dot_fmt ) // extern
|
||||||
|
{
|
||||||
|
unsigned int size = global_state_to_str( p_glob, dot_fmt, NULL, 0 ) + 1; // get needed buffer size
|
||||||
|
{
|
||||||
|
char buf[size]; // allocate buffer
|
||||||
|
global_state_to_str( p_glob, dot_fmt, buf, size ); // convert to string
|
||||||
|
fprintf( out, "%s", buf ); // output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a process to stdout
|
||||||
|
void process_print( st_process_header *p_proc ) // extern
|
||||||
|
{
|
||||||
|
process_print_ex( stdout, p_proc, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a channel to stdout
|
||||||
|
void channel_print( st_channel_header *p_chan ) // extern
|
||||||
|
{
|
||||||
|
channel_print_ex( stdout, p_chan, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// print a global state to stdout
|
||||||
|
void global_state_print( st_global_state_header *p_glob ) // extern
|
||||||
|
{
|
||||||
|
global_state_print_ex( stdout, p_glob, 0 );
|
||||||
|
}
|
||||||
274
iface/nips/nips_vm/state.h
Normal file
274
iface/nips/nips_vm/state.h
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_state
|
||||||
|
#define INC_state
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
// types for process and channel identifiers
|
||||||
|
typedef uint8_t t_pid;
|
||||||
|
#define PID_MAX ((t_pid)-1)
|
||||||
|
#define PID_OK( pid ) ((pid) > 0)
|
||||||
|
#define h2be_pid( x ) (x)
|
||||||
|
#define be2h_pid( x ) (x)
|
||||||
|
typedef uint16_t t_chid; // channel-id = <pid of creating process> <1 byte to make channel-id unique>
|
||||||
|
#define CHID_MAX ((t_chid)-1)
|
||||||
|
#define CHID_OK( chid ) ((chid) > 0)
|
||||||
|
#define h2be_chid( x ) h2be_16( x )
|
||||||
|
#define be2h_chid( x ) be2h_16( x )
|
||||||
|
|
||||||
|
// type for program counter
|
||||||
|
typedef uint32_t t_pc;
|
||||||
|
#define PC_MAX ((t_pc)-1)
|
||||||
|
#define h2be_pc( x ) h2be_32( x )
|
||||||
|
#define be2h_pc( x ) be2h_32( x )
|
||||||
|
|
||||||
|
// type of flag register
|
||||||
|
typedef uint32_t t_flag_reg;
|
||||||
|
#define FLAG_REG_FLAG_CNT 32
|
||||||
|
|
||||||
|
// type for internal values (type for data stack and normal registers)
|
||||||
|
typedef int32_t t_val;
|
||||||
|
typedef uint32_t t_u_val;
|
||||||
|
// unaligned version of internal value
|
||||||
|
// - realized as structure to be able to use PACKED
|
||||||
|
typedef struct { t_val val; } PACKED ua_t_val;
|
||||||
|
|
||||||
|
|
||||||
|
// process
|
||||||
|
typedef struct t_process_header
|
||||||
|
{
|
||||||
|
t_pid pid; // process identifier (never 0)
|
||||||
|
uint8_t flags; // flags (contain execution mode)
|
||||||
|
uint8_t lvar_sz; // size of local variables in bytes
|
||||||
|
t_pc pc; // program counter
|
||||||
|
} PACKED st_process_header;
|
||||||
|
// after header follows (if ! (flags & process_flags_active)):
|
||||||
|
// variables (lvar_sz bytes, multi-byte values in big-endian format),
|
||||||
|
|
||||||
|
// process flags
|
||||||
|
#define PROCESS_FLAGS_MODE 0x03 // execution modes
|
||||||
|
#define PROCESS_FLAGS_MODE_NORMAL 0x00
|
||||||
|
#define PROCESS_FLAGS_MODE_ATOMIC 0x01
|
||||||
|
#define PROCESS_FLAGS_MODE_INVISIBLE 0x02
|
||||||
|
#define PROCESS_FLAGS_MODE_TERMINATED 0x03
|
||||||
|
#define PROCESS_FLAGS_MONITOR_ACCEPT 0x10 // if monitor process is in accepting state (only valid for monitor process)
|
||||||
|
#define PROCESS_FLAGS_ACTIVE 0x80 // if process is currently active (i.e. executing)
|
||||||
|
|
||||||
|
// active process
|
||||||
|
typedef struct t_process_active_header
|
||||||
|
{
|
||||||
|
st_process_header proc; // normal process header (with flags & process_flags_active)
|
||||||
|
t_val registers[8]; // virtual machine registers (host byte order)
|
||||||
|
t_flag_reg flag_reg; // flag register (host byte order)
|
||||||
|
uint8_t stack_cur; // current size of stack in entries
|
||||||
|
uint8_t stack_max; // maximum size of stack in entries
|
||||||
|
} PACKED st_process_active_header;
|
||||||
|
// after header follows:
|
||||||
|
// variables (proc.lvar_sz bytes, multi-byte values in big-endian format),
|
||||||
|
// stack (stack_max ints in host byte order),
|
||||||
|
|
||||||
|
|
||||||
|
// channel
|
||||||
|
typedef struct t_channel_header
|
||||||
|
{
|
||||||
|
t_chid chid; // channel identifier (never 0)
|
||||||
|
uint8_t max_len; // maximum number of messages in channel (if 0, real max_len is 1)
|
||||||
|
uint8_t cur_len; // current number of messages in channel
|
||||||
|
uint8_t msg_len; // length of a single message in bytes
|
||||||
|
uint8_t type_len; // number of entries of flat type
|
||||||
|
} PACKED st_channel_header;
|
||||||
|
// after header follows:
|
||||||
|
// flat type of message (type_len bytes),
|
||||||
|
// - bytes contain number of bits the entries use
|
||||||
|
// (use -value+1 for negative values,
|
||||||
|
// round up to 8, 16 or 32 and divide by 8 to get number of bytes)
|
||||||
|
// messages (max( 1, max_len ) * msg_len bytes)
|
||||||
|
// (multi-byte values in big-endian format)
|
||||||
|
|
||||||
|
// global state
|
||||||
|
#define PROC_CNT_MAX 255 // maximum number of processes (must fit into uint8_t, see below)
|
||||||
|
#define CHAN_CNT_MAX 255 // maximum number of channels (must fit into uint8_t, see below)
|
||||||
|
typedef struct t_global_state_header
|
||||||
|
{
|
||||||
|
uint16_t gvar_sz; // size of global variables in bytes (big endian format)
|
||||||
|
uint8_t proc_cnt; // number of process currently active
|
||||||
|
t_pid excl_pid; // pid of the process executed exclusively or 0 if none
|
||||||
|
t_pid monitor_pid; // pid of the monitor process or 0 if none
|
||||||
|
uint8_t chan_cnt; // number of channels currently existing
|
||||||
|
} PACKED st_global_state_header;
|
||||||
|
// after header follows:
|
||||||
|
// variables (gvar_sz bytes, multi-byte values in big-endian format),
|
||||||
|
// processes (proc_cnt times a process),
|
||||||
|
// channels (chan_cnt times a channel)
|
||||||
|
|
||||||
|
typedef st_global_state_header nipsvm_state_t;
|
||||||
|
|
||||||
|
// inline functions as "extern inline" for optimized compilation
|
||||||
|
#define STATE_INLINE extern inline
|
||||||
|
#include "state_inline.h"
|
||||||
|
#undef STATE_INLINE
|
||||||
|
|
||||||
|
// size of initial state
|
||||||
|
#define NIPSVM_INITIAL_STATE_SIZE (sizeof( st_global_state_header ) \
|
||||||
|
+ sizeof( st_process_header ))
|
||||||
|
|
||||||
|
static const size_t global_state_initial_size = NIPSVM_INITIAL_STATE_SIZE;
|
||||||
|
|
||||||
|
// generate initial state
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_initial( char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// get a copy of global state
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy( st_global_state_header *p_glob,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with resized global variables
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy_gvar_sz( st_global_state_header *p_glob,
|
||||||
|
uint16_t gvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with resized local variables
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy_lvar_sz( st_global_state_header *p_glob,
|
||||||
|
st_process_header *p_proc, uint8_t lvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len );
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with selected process activated
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// *pp_proc is filled with the pointer to the activated process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy_activate( st_global_state_header *p_glob, st_process_header *p_proc,
|
||||||
|
uint8_t stack_max, t_flag_reg flag_reg,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_process_active_header **pp_proc );
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with an additional process
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// *pp_proc is filled with the pointer to the new process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy_new_process( st_global_state_header *p_glob,
|
||||||
|
t_pid new_pid, uint8_t lvar_sz,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_process_header **pp_proc );
|
||||||
|
|
||||||
|
|
||||||
|
// get copy of global state with an additional channel
|
||||||
|
// *pp_buf points to memory area of length *p_len to use for new state
|
||||||
|
// the new channel is inserted at the right place according to its channel id
|
||||||
|
// *pp_chan is filled with the pointer to the new process
|
||||||
|
// NULL is returned in case of error
|
||||||
|
extern st_global_state_header * global_state_copy_new_channel( st_global_state_header *p_glob,
|
||||||
|
t_chid new_chid, uint8_t max_len, uint8_t type_len, uint8_t msg_len,
|
||||||
|
char **pp_buf, unsigned long *p_buf_len,
|
||||||
|
st_channel_header **pp_chan );
|
||||||
|
|
||||||
|
|
||||||
|
// deactivate selected process in global state
|
||||||
|
extern void global_state_deactivate( st_global_state_header *p_glob, st_process_active_header *p_proc );
|
||||||
|
|
||||||
|
|
||||||
|
// remove selected process in global state
|
||||||
|
extern void global_state_remove( st_global_state_header *p_glob, st_process_header *p_proc );
|
||||||
|
|
||||||
|
|
||||||
|
// count enabled processes (i.e. processes that are not yet terminated)
|
||||||
|
// returns number of processes
|
||||||
|
extern unsigned int global_state_count_enabled_processes( st_global_state_header *p_glob );
|
||||||
|
|
||||||
|
|
||||||
|
// get enabled processes (i.e. processes that may be activated)
|
||||||
|
// returns number of processes or (unsigned int)-1 if there are too many enabled processes
|
||||||
|
extern unsigned int global_state_get_enabled_processes( st_global_state_header *p_glob, st_process_header **p_procs, unsigned int proc_max );
|
||||||
|
|
||||||
|
|
||||||
|
/* DEPRECATED */ extern int global_state_monitor_accepting( st_global_state_header *p_glob );
|
||||||
|
/* DEPRECATED */ extern int global_state_monitor_terminated( st_global_state_header *p_glob );
|
||||||
|
/* DEPRECATED */ extern int global_state_monitor_acc_or_term( st_global_state_header *p_glob );
|
||||||
|
|
||||||
|
// TIP: the following 3 functions can be called with ( ..., NULL, 0 )
|
||||||
|
// to obtain the needed buffer size
|
||||||
|
// (add 1 to return value for the terminating 0 character)
|
||||||
|
|
||||||
|
|
||||||
|
// output a process to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
extern unsigned int process_to_str( st_process_header *p_proc, int dot_fmt, char *p_buf, unsigned int size );
|
||||||
|
|
||||||
|
|
||||||
|
// output a channel to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
extern unsigned int channel_to_str( st_channel_header *p_chan, int dot_fmt, char *p_buf, unsigned int size );
|
||||||
|
|
||||||
|
|
||||||
|
// output a global state to a string
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
// - puts up to size charactes into *p_buf (including temintaing 0 character)
|
||||||
|
// - returns number of characters needed (e.g. size or more if string is truncated)
|
||||||
|
extern unsigned int global_state_to_str( st_global_state_header *p_glob, int dot_fmt, char *p_buf, unsigned int size );
|
||||||
|
|
||||||
|
|
||||||
|
// print a process to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
extern void process_print_ex( FILE *out, st_process_header *p_proc, int dot_fmt );
|
||||||
|
|
||||||
|
|
||||||
|
// print a channel to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
extern void channel_print_ex( FILE *out, st_channel_header *p_chan, int dot_fmt );
|
||||||
|
|
||||||
|
|
||||||
|
// print a global state to a stream
|
||||||
|
// - possibly to output in graphviz dot format
|
||||||
|
extern void global_state_print_ex( FILE *out, st_global_state_header *p_glob, int dot_fmt );
|
||||||
|
|
||||||
|
|
||||||
|
// print a process to stdout
|
||||||
|
extern void process_print( st_process_header *p_proc );
|
||||||
|
|
||||||
|
|
||||||
|
// print a channel to stdout
|
||||||
|
extern void channel_print( st_channel_header *p_chan );
|
||||||
|
|
||||||
|
|
||||||
|
// print a global state to stdout
|
||||||
|
extern void global_state_print( st_global_state_header *p_glob );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_state
|
||||||
280
iface/nips/nips_vm/state_inline.h
Normal file
280
iface/nips/nips_vm/state_inline.h
Normal file
|
|
@ -0,0 +1,280 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// DO NOT INCLUDE THIS FILE - IT IS FOR INTERNAL USE ONLY
|
||||||
|
#ifdef STATE_INLINE
|
||||||
|
|
||||||
|
|
||||||
|
// size of a process
|
||||||
|
STATE_INLINE unsigned int process_size( st_process_header *p_proc )
|
||||||
|
{
|
||||||
|
// active process
|
||||||
|
if( p_proc->flags & PROCESS_FLAGS_ACTIVE )
|
||||||
|
{
|
||||||
|
return sizeof( st_process_active_header ) // header
|
||||||
|
+ ((st_process_active_header *)p_proc)->proc.lvar_sz // variables
|
||||||
|
+ ((st_process_active_header *)p_proc)->stack_max * sizeof( t_val ); // stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal process
|
||||||
|
return sizeof( st_process_header ) // header
|
||||||
|
+ p_proc->lvar_sz; // variables
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to variables
|
||||||
|
STATE_INLINE char * process_get_variables( st_process_header *p_proc )
|
||||||
|
{
|
||||||
|
// active process
|
||||||
|
if( p_proc->flags & PROCESS_FLAGS_ACTIVE )
|
||||||
|
{
|
||||||
|
return (char *)p_proc
|
||||||
|
+ sizeof( st_process_active_header ); // header
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal process
|
||||||
|
return (char *)p_proc
|
||||||
|
+ sizeof( st_process_header ); // header
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to stack
|
||||||
|
STATE_INLINE ua_t_val * process_active_get_stack( st_process_active_header *p_proc )
|
||||||
|
{
|
||||||
|
return (ua_t_val *)((char *)p_proc
|
||||||
|
+ sizeof( st_process_active_header ) // header
|
||||||
|
+ p_proc->proc.lvar_sz); // variables
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// size of a channel
|
||||||
|
STATE_INLINE unsigned int channel_size( st_channel_header *p_chan )
|
||||||
|
{
|
||||||
|
return sizeof( st_channel_header ) // header
|
||||||
|
+ p_chan->type_len // type specification
|
||||||
|
+ max( 1, p_chan->max_len ) * p_chan->msg_len; // messages
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to type
|
||||||
|
STATE_INLINE int8_t * channel_get_type( st_channel_header *p_chan )
|
||||||
|
{
|
||||||
|
return (int8_t *)((char *)p_chan + sizeof( st_channel_header )); // header
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to message
|
||||||
|
STATE_INLINE char * channel_get_msg( st_channel_header *p_chan, uint8_t msg_no )
|
||||||
|
{
|
||||||
|
return (char *)p_chan + sizeof( st_channel_header ) // header
|
||||||
|
+ p_chan->type_len // type specification
|
||||||
|
+ msg_no * p_chan->msg_len; // messages before msg_no
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// size of a global state without processes and channels
|
||||||
|
STATE_INLINE unsigned int global_state_size_noproc_nochan( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
return sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
}
|
||||||
|
|
||||||
|
// size of a global state
|
||||||
|
STATE_INLINE size_t global_state_size( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
unsigned int sz, i;
|
||||||
|
|
||||||
|
sz = sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
sz += process_size( (st_process_header *)((char *)p_glob + sz) );
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ ) // channels
|
||||||
|
sz += channel_size( (st_channel_header *)((char *)p_glob + sz) );
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to variables
|
||||||
|
STATE_INLINE char * global_state_get_variables( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
return (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ); // header
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to processes
|
||||||
|
STATE_INLINE char * global_state_get_processes( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to active process
|
||||||
|
STATE_INLINE st_process_active_header * global_state_get_active_process( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // search process
|
||||||
|
{
|
||||||
|
if( ((st_process_header *)ptr)->flags & PROCESS_FLAGS_ACTIVE ) // active process found
|
||||||
|
return (st_process_active_header *)ptr;
|
||||||
|
ptr += process_size( (st_process_header *)ptr ); // next process
|
||||||
|
}
|
||||||
|
return NULL; // no active process found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to process
|
||||||
|
STATE_INLINE st_process_header * global_state_get_process( st_global_state_header *p_glob, t_pid pid )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // search process
|
||||||
|
{
|
||||||
|
if( ((st_process_header *)ptr)->pid == h2be_pid( pid ) ) // found
|
||||||
|
return (st_process_header *)ptr;
|
||||||
|
ptr += process_size( (st_process_header *)ptr ); // next process
|
||||||
|
}
|
||||||
|
return NULL; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get maximum process id
|
||||||
|
STATE_INLINE t_pid global_state_get_max_pid( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
t_pid max_pid;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
max_pid = 0;
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
{
|
||||||
|
max_pid = max( max_pid, be2h_pid( ((st_process_header *)ptr)->pid ) );
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
}
|
||||||
|
return max_pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to channels
|
||||||
|
STATE_INLINE char * global_state_get_channels( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get pointer to channel
|
||||||
|
STATE_INLINE st_channel_header * global_state_get_channel( st_global_state_header *p_glob, t_chid chid )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ ) // search channel
|
||||||
|
{
|
||||||
|
if( ((st_channel_header *)ptr)->chid == h2be_chid( chid ) ) // found
|
||||||
|
return (st_channel_header *)ptr;
|
||||||
|
ptr += channel_size( (st_channel_header *)ptr ); // next channel
|
||||||
|
}
|
||||||
|
return NULL; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get new channel id
|
||||||
|
STATE_INLINE t_chid global_state_get_new_chid( st_global_state_header *p_glob, t_pid pid )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
t_chid chid_begin, chid, chid_end_max, chid_end;
|
||||||
|
|
||||||
|
chid_begin = (t_chid)pid << 8;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
chid_end_max = 0;
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ ) // channels
|
||||||
|
{
|
||||||
|
chid = be2h_chid( ((st_channel_header *)ptr)->chid ); // get chid
|
||||||
|
if( (chid & 0xFF00) == chid_begin ) // compare begin of chid (pid)
|
||||||
|
chid_end_max = max( chid_end_max, chid & 0x00FF ); // save maximum end part
|
||||||
|
ptr += channel_size( (st_channel_header *)ptr );
|
||||||
|
}
|
||||||
|
|
||||||
|
chid_end = chid_end_max + 1; // generate new chid
|
||||||
|
if( chid_end > 0x00FF ) // all end parts used
|
||||||
|
return 0; // no chid
|
||||||
|
return chid_begin | chid_end; // return new chid
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// check if synchronous communication is occuring in at least one channel
|
||||||
|
STATE_INLINE int global_state_sync_comm( st_global_state_header *p_glob )
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
ptr = (char *)p_glob
|
||||||
|
+ sizeof( st_global_state_header ) // header
|
||||||
|
+ be2h_16( p_glob->gvar_sz ); // variables
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ ) // processes
|
||||||
|
ptr += process_size( (st_process_header *)ptr );
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ ) // channels
|
||||||
|
{
|
||||||
|
if( ((st_channel_header *)ptr)->cur_len > ((st_channel_header *)ptr)->max_len )
|
||||||
|
return 1; // found a channel that contains more messages than max_len
|
||||||
|
// ---> synchronous communication is occuring
|
||||||
|
ptr += channel_size( (st_channel_header *)ptr );
|
||||||
|
}
|
||||||
|
return 0; // all channels do not contain more than max_len messages
|
||||||
|
// ---> no synchronous communication
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* deprecated */ STATE_INLINE int
|
||||||
|
global_state_compare (void *p_glob1, void *p_glob2)
|
||||||
|
{
|
||||||
|
// see nipsvm_state_compare
|
||||||
|
return memcmp (p_glob1, p_glob2, global_state_size ((st_global_state_header *)p_glob1));
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef STATE_INLINE
|
||||||
|
|
||||||
|
#endif // #ifdef STATE_INLINE
|
||||||
|
|
||||||
103
iface/nips/nips_vm/state_parts.c
Normal file
103
iface/nips/nips_vm/state_parts.c
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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 "state.h"
|
||||||
|
#include "state_parts.h"
|
||||||
|
|
||||||
|
|
||||||
|
// get size of a global/process/channel part from pointer
|
||||||
|
unsigned int glob_part_size( char *p_glob_part ) // extern
|
||||||
|
{
|
||||||
|
return global_state_size_noproc_nochan( (st_global_state_header *)p_glob_part );
|
||||||
|
}
|
||||||
|
unsigned int proc_part_size( char *p_proc_part ) // extern
|
||||||
|
{
|
||||||
|
return process_size( (st_process_header *)p_proc_part );
|
||||||
|
}
|
||||||
|
unsigned int chan_part_size( char *p_chan_part ) // extern
|
||||||
|
{
|
||||||
|
return channel_size( (st_channel_header *)p_chan_part );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// split up a global state into its parts
|
||||||
|
// - callbacks are called with pointer to the different parts
|
||||||
|
// - 1x glob_cb, Nx proc_cb, Mx chan_cb
|
||||||
|
// - memory pointed to is read only and only valid within callback
|
||||||
|
void state_parts( st_global_state_header *p_glob, // the global state to split up
|
||||||
|
t_glob_part_cb glob_cb, t_proc_part_cb proc_cb, t_chan_part_cb chan_cb, // the callbacks to call
|
||||||
|
void *p_ctx ) // extern
|
||||||
|
{
|
||||||
|
char *ptr = (char *)p_glob;
|
||||||
|
unsigned int sz, i;
|
||||||
|
|
||||||
|
// report global part to callback
|
||||||
|
sz = global_state_size_noproc_nochan( (st_global_state_header *)ptr );
|
||||||
|
glob_cb( ptr, sz, p_ctx );
|
||||||
|
ptr += sz;
|
||||||
|
|
||||||
|
// report process parts to callback
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ )
|
||||||
|
{
|
||||||
|
sz = process_size( (st_process_header *)ptr );
|
||||||
|
proc_cb( ptr, sz, p_ctx );
|
||||||
|
ptr += sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// report channel parts to callback
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ )
|
||||||
|
{
|
||||||
|
sz = channel_size( (st_channel_header *)ptr );
|
||||||
|
chan_cb( ptr, sz, p_ctx );
|
||||||
|
ptr += sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// recreate a global state from its parts
|
||||||
|
// - callbacks are called to retrieve parts of state
|
||||||
|
// - 1x glob_cb, Nx proc_cb, Mx chan_cb
|
||||||
|
// - state is restored in buffer pointed to by p_buf of length buf_len
|
||||||
|
// - pointer to start of buffer is returned, or NULL if buffer too small
|
||||||
|
st_global_state_header * state_restore( char *p_buf, unsigned int buf_len,
|
||||||
|
t_glob_restore_cb glob_cb, t_proc_restore_cb proc_cb, t_chan_restore_cb chan_cb, // the callbacks to call
|
||||||
|
void *p_ctx ) // extern
|
||||||
|
{
|
||||||
|
st_global_state_header *p_glob = (st_global_state_header *)p_buf;
|
||||||
|
unsigned int sz, i;
|
||||||
|
|
||||||
|
// get global part
|
||||||
|
sz = glob_cb( p_buf, buf_len, p_ctx );
|
||||||
|
if( sz <= 0 || sz >= buf_len )
|
||||||
|
return NULL;
|
||||||
|
p_buf += sz;
|
||||||
|
buf_len -= sz;
|
||||||
|
|
||||||
|
// get processes
|
||||||
|
for( i = 0; i < p_glob->proc_cnt; i++ )
|
||||||
|
{
|
||||||
|
sz = proc_cb( p_buf, buf_len, p_ctx );
|
||||||
|
if( sz <= 0 || sz >= buf_len )
|
||||||
|
return NULL;
|
||||||
|
p_buf += sz;
|
||||||
|
buf_len -= sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get channels
|
||||||
|
for( i = 0; i < p_glob->chan_cnt; i++ )
|
||||||
|
{
|
||||||
|
sz = chan_cb( p_buf, buf_len, p_ctx );
|
||||||
|
if( sz <= 0 || sz >= buf_len )
|
||||||
|
return NULL;
|
||||||
|
p_buf += sz;
|
||||||
|
buf_len -= sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return assembled state
|
||||||
|
return p_glob;
|
||||||
|
}
|
||||||
67
iface/nips/nips_vm/state_parts.h
Normal file
67
iface/nips/nips_vm/state_parts.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_state_parts
|
||||||
|
#define INC_state_parts
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include "state.h"
|
||||||
|
|
||||||
|
|
||||||
|
// get size of a global/process/channel part from pointer
|
||||||
|
extern unsigned int glob_part_size( char *p_glob_part );
|
||||||
|
extern unsigned int proc_part_size( char *p_proc_part );
|
||||||
|
extern unsigned int chan_part_size( char *p_chan_part );
|
||||||
|
|
||||||
|
|
||||||
|
// types for callbacks to split up state
|
||||||
|
// - called for every part of the state
|
||||||
|
// - part is read only and only valid during callback
|
||||||
|
typedef void (*t_glob_part_cb)( char *p_glob_part, unsigned int glob_part_size, void *p_ctx );
|
||||||
|
typedef void (*t_proc_part_cb)( char *p_proc_part, unsigned int proc_part_size, void *p_ctx );
|
||||||
|
typedef void (*t_chan_part_cb)( char *p_chan_part, unsigned int chan_part_size, void *p_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
// split up a global state into its parts
|
||||||
|
// - callbacks are called with pointer to the different parts
|
||||||
|
// - 1x glob_cb, Nx proc_cb, Mx chan_cb
|
||||||
|
// - memory pointed to is read only and only valid within callback
|
||||||
|
extern void state_parts( st_global_state_header *p_glob, // the global state to split up
|
||||||
|
t_glob_part_cb glob_cb, t_proc_part_cb proc_cb, t_chan_part_cb chan_cb, // the callbacks to call
|
||||||
|
void *p_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
// types for callbacks to restore state
|
||||||
|
// - must copy the part into the memory pointed to by p_buf of length buf_len
|
||||||
|
// - must return number of bytes placed into buffer (0 in case of error)
|
||||||
|
typedef unsigned int (*t_glob_restore_cb)( char *p_buf, unsigned int buf_len, void *p_ctx );
|
||||||
|
typedef unsigned int (*t_proc_restore_cb)( char *p_buf, unsigned int buf_len, void *p_ctx );
|
||||||
|
typedef unsigned int (*t_chan_restore_cb)( char *p_buf, unsigned int buf_len, void *p_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
// recreate a global state from its parts
|
||||||
|
// - callbacks are called to retrieve parts of state
|
||||||
|
// - 1x glob_cb, Nx proc_cb, Mx chan_cb
|
||||||
|
// - state is restored in buffer pointed to by p_buf of length buf_len
|
||||||
|
// - pointer to start of buffer is returned, or NULL if buffer too small
|
||||||
|
extern st_global_state_header * state_restore( char *p_buf, unsigned int buf_len,
|
||||||
|
t_glob_restore_cb glob_cb, t_proc_restore_cb proc_cb, t_chan_restore_cb chan_cb, // the callbacks to call
|
||||||
|
void *p_ctx );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #ifndef INC_state_parts
|
||||||
76
iface/nips/nips_vm/timeval.h
Normal file
76
iface/nips/nips_vm/timeval.h
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* timeval.h 1.0 01/12/19
|
||||||
|
*
|
||||||
|
* Defines gettimeofday, timeval, etc. for Win32
|
||||||
|
*
|
||||||
|
* By Wu Yongwei
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TIMEVAL_H
|
||||||
|
#define _TIMEVAL_H
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#ifndef __GNUC__
|
||||||
|
#define EPOCHFILETIME (116444736000000000i64)
|
||||||
|
#else
|
||||||
|
#define EPOCHFILETIME (116444736000000000LL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//struct timeval {
|
||||||
|
// long tv_sec; /* seconds */
|
||||||
|
// long tv_usec; /* microseconds */
|
||||||
|
//};
|
||||||
|
|
||||||
|
struct timezone {
|
||||||
|
int tz_minuteswest; /* minutes W of Greenwich */
|
||||||
|
int tz_dsttime; /* type of dst correction */
|
||||||
|
};
|
||||||
|
|
||||||
|
__inline int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||||
|
{
|
||||||
|
FILETIME ft;
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
__int64 t;
|
||||||
|
static int tzflag;
|
||||||
|
|
||||||
|
if (tv)
|
||||||
|
{
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
li.LowPart = ft.dwLowDateTime;
|
||||||
|
li.HighPart = ft.dwHighDateTime;
|
||||||
|
t = li.QuadPart; /* In 100-nanosecond intervals */
|
||||||
|
t -= EPOCHFILETIME; /* Offset to the Epoch time */
|
||||||
|
t /= 10; /* In microseconds */
|
||||||
|
tv->tv_sec = (long)(t / 1000000);
|
||||||
|
tv->tv_usec = (long)(t % 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tz)
|
||||||
|
{
|
||||||
|
if (!tzflag)
|
||||||
|
{
|
||||||
|
_tzset();
|
||||||
|
tzflag++;
|
||||||
|
}
|
||||||
|
tz->tz_minuteswest = _timezone / 60;
|
||||||
|
tz->tz_dsttime = _daylight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* _WIN32 */
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
#endif /* _TIMEVAL_H */
|
||||||
60
iface/nips/nips_vm/tools.h
Normal file
60
iface/nips/nips_vm/tools.h
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
|
||||||
|
* Copyright (C) 2005: 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INC_tools
|
||||||
|
#define INC_tools
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef WIN32
|
||||||
|
# include <winsock2.h>
|
||||||
|
#else
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// minimum and maximum
|
||||||
|
#ifndef min
|
||||||
|
# define min( a, b ) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
#ifndef max
|
||||||
|
# define max( a, b ) ((a) > (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// number of entries in an array
|
||||||
|
#define count( array ) (sizeof( (array) ) / sizeof( (array)[0] ))
|
||||||
|
|
||||||
|
// packed (and unaligned) structures
|
||||||
|
#define PACKED __attribute__((packed))
|
||||||
|
|
||||||
|
// types to define macros for unaligned reads and writes
|
||||||
|
typedef struct { uint16_t u16; } PACKED ua_16;
|
||||||
|
typedef struct { uint32_t u32; } PACKED ua_32;
|
||||||
|
// unaligned reads
|
||||||
|
#define ua_rd_16( ptr ) (((ua_16 *)(ptr))->u16)
|
||||||
|
#define ua_rd_32( ptr ) (((ua_32 *)(ptr))->u32)
|
||||||
|
// unaligned writes
|
||||||
|
#define ua_wr_16( ptr, val ) (((ua_16 *)(ptr))->u16 = (uint16_t)(val))
|
||||||
|
#define ua_wr_32( ptr, val ) (((ua_32 *)(ptr))->u32 = (uint32_t)(val))
|
||||||
|
|
||||||
|
// byte order (big endian)
|
||||||
|
// we steal this code from netinet/in.h
|
||||||
|
#define h2be_16( x ) ((uint16_t)htons( (uint16_t)(x) ))
|
||||||
|
#define h2be_32( x ) ((uint32_t)htonl( (uint32_t)(x) ))
|
||||||
|
#define be2h_16( x ) ((uint16_t)ntohs( (uint16_t)(x) ))
|
||||||
|
#define be2h_32( x ) ((uint32_t)ntohl( (uint32_t)(x) ))
|
||||||
|
|
||||||
|
// byte oder (little endian)
|
||||||
|
// use big endian macros and swap bytes
|
||||||
|
// FIXME: there must be a better way
|
||||||
|
#define byteswap_16( x ) ((uint16_t)x << 8 | (uint16_t)x >> 8)
|
||||||
|
#define byteswap_32( x ) ((uint32_t)x << 24 | ((uint32_t)x << 8 & 0x00FF0000) | ((uint32_t)x >> 8 & 0x0000FF00) | (uint32_t)x >> 24)
|
||||||
|
#define h2le_16( x ) (byteswap_16( h2be_16( x ) ))
|
||||||
|
#define h2le_32( x ) (byteswap_32( h2be_32( x ) ))
|
||||||
|
#define le2h_16( x ) (be2h_16( byteswap_16( x ) ))
|
||||||
|
#define le2h_32( x ) (be2h_32( byteswap_32( x ) ))
|
||||||
|
|
||||||
|
#endif // #ifndef INC_tools
|
||||||
|
|
@ -47,3 +47,4 @@ libspot_la_LIBADD = \
|
||||||
|
|
||||||
# Dummy C++ source to cause C++ linking.
|
# Dummy C++ source to cause C++ linking.
|
||||||
nodist_EXTRA_libspot_la_SOURCES = _.cc
|
nodist_EXTRA_libspot_la_SOURCES = _.cc
|
||||||
|
_.cc:; touch $@
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue