Remove the Nips interface.
* NEWS: Mention it. * configure.ac, README: Remove it. * iface/Makefile.am (SUBDIRS): Remove nips. * iface/nips/: Delete this directory.
This commit is contained in:
parent
8256ae9bfb
commit
6d213e5e4c
67 changed files with 11 additions and 11617 deletions
|
|
@ -1,3 +1,12 @@
|
||||||
|
2011-03-07 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
||||||
|
|
||||||
|
Remove the Nips interface.
|
||||||
|
|
||||||
|
* NEWS: Mention it.
|
||||||
|
* configure.ac, README: Remove it.
|
||||||
|
* iface/Makefile.am (SUBDIRS): Remove nips.
|
||||||
|
* iface/nips/: Delete this directory.
|
||||||
|
|
||||||
2011-03-07 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
2011-03-07 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
||||||
|
|
||||||
Accept "P_0 == CS" as synonym for "P_0.CS" in the dve2 interface.
|
Accept "P_0 == CS" as synonym for "P_0.CS" in the dve2 interface.
|
||||||
|
|
|
||||||
1
NEWS
1
NEWS
|
|
@ -1,6 +1,7 @@
|
||||||
New in spot 0.7.1a:
|
New in spot 0.7.1a:
|
||||||
|
|
||||||
* Spot can read DiVinE models. See iface/dve2/README for details.
|
* Spot can read DiVinE models. See iface/dve2/README for details.
|
||||||
|
* The experimental Nips interface has been removed.
|
||||||
|
|
||||||
New in spot 0.7.1 (2001-02-07):
|
New in spot 0.7.1 (2001-02-07):
|
||||||
|
|
||||||
|
|
|
||||||
7
README
7
README
|
|
@ -148,8 +148,6 @@ iface/ Interfaces to other libraries.
|
||||||
dve2/ Interface with DiVinE2.
|
dve2/ Interface with DiVinE2.
|
||||||
gspn/ GreatSPN interface.
|
gspn/ GreatSPN interface.
|
||||||
examples/ Supporting models used by the test cases.
|
examples/ Supporting models used by the test cases.
|
||||||
nips/ NIPS interface (to use Promela models).
|
|
||||||
nipstest/ Tests for NIPS.
|
|
||||||
|
|
||||||
Third party software
|
Third party software
|
||||||
--------------------
|
--------------------
|
||||||
|
|
@ -157,10 +155,6 @@ Third party software
|
||||||
buddy/ A patched version of BuDDy 2.3 (a BDD library).
|
buddy/ A patched version of BuDDy 2.3 (a BDD library).
|
||||||
lbtt/ lbtt 1.2.1 (an LTL to Büchi automata test bench).
|
lbtt/ lbtt 1.2.1 (an LTL to Büchi automata test bench).
|
||||||
ltdl/ Libtool's portable dlopen() wrapper library.
|
ltdl/ Libtool's portable dlopen() wrapper library.
|
||||||
iface/ Interfaces to other libraries.
|
|
||||||
nips/ NIPS interface (to use Promela models).
|
|
||||||
nips_vm/ NIPS VM 1.2.7 (New Implementation of Promela Semantics
|
|
||||||
Virtual Machine).
|
|
||||||
|
|
||||||
Build-system stuff
|
Build-system stuff
|
||||||
------------------
|
------------------
|
||||||
|
|
@ -179,4 +173,3 @@ End:
|
||||||
LocalWords: gtec Tarjan tgbaparse tgbatest doc html PDF spotref pdf cgi ELTL
|
LocalWords: gtec Tarjan tgbaparse tgbatest doc html PDF spotref pdf cgi ELTL
|
||||||
LocalWords: CGI ltl iface BDD Couvreur's evtgba emptchk kripke Kripke saba vm
|
LocalWords: CGI ltl iface BDD Couvreur's evtgba emptchk kripke Kripke saba vm
|
||||||
LocalWords: eltlparse eltltest SABA sabaalgos sabatest ssp ltlcouter scc SCC
|
LocalWords: eltlparse eltltest SABA sabaalgos sabatest ssp ltlcouter scc SCC
|
||||||
LocalWords: Promela nipstest VM
|
|
||||||
|
|
|
||||||
|
|
@ -103,10 +103,6 @@ AC_CONFIG_FILES([
|
||||||
iface/gspn/defs
|
iface/gspn/defs
|
||||||
iface/gspn/Makefile
|
iface/gspn/Makefile
|
||||||
iface/Makefile
|
iface/Makefile
|
||||||
iface/nips/Makefile
|
|
||||||
iface/nips/nipstest/defs
|
|
||||||
iface/nips/nipstest/Makefile
|
|
||||||
iface/nips/nips_vm/Makefile
|
|
||||||
src/eltlparse/Makefile
|
src/eltlparse/Makefile
|
||||||
src/eltltest/defs
|
src/eltltest/defs
|
||||||
src/eltltest/Makefile
|
src/eltltest/Makefile
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
## 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 dve2
|
SUBDIRS = dve2
|
||||||
|
|
||||||
if WITH_GSPN
|
if WITH_GSPN
|
||||||
SUBDIRS += gspn
|
SUBDIRS += gspn
|
||||||
|
|
|
||||||
3
iface/nips/.gitignore
vendored
3
iface/nips/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
TAGS
|
|
||||||
dottynips
|
|
||||||
empt_check
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
## Copyright (C) 2008 Laboratoire de Recherche et Développement
|
|
||||||
## de l'Epita (LRDE).
|
|
||||||
##
|
|
||||||
## 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)/iface/nips
|
|
||||||
|
|
||||||
nips_HEADERS = \
|
|
||||||
common.hh \
|
|
||||||
nips.hh
|
|
||||||
|
|
||||||
lib_LTLIBRARIES = libspotnips.la
|
|
||||||
libspotnips_la_LIBADD = $(top_builddir)/src/libspot.la $(builddir)/nips_vm/libnipsvm.la
|
|
||||||
libspotnips_la_SOURCES = \
|
|
||||||
common.cc \
|
|
||||||
nips.cc
|
|
||||||
|
|
||||||
noinst_PROGRAMS = \
|
|
||||||
dottynips empt_check
|
|
||||||
|
|
||||||
dottynips_SOURCES = dottynips.cc
|
|
||||||
dottynips_LDADD = libspotnips.la
|
|
||||||
|
|
||||||
empt_check_SOURCES = emptiness_check.cc
|
|
||||||
empt_check_LDADD = libspotnips.la
|
|
||||||
|
|
||||||
SUBDIRS = nips_vm nipstest
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
// Copyright (C) 2008 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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() << " with exit value: " << e.get_err();
|
|
||||||
else
|
|
||||||
os << e.get_where();
|
|
||||||
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
// Copyright (C) 2008 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
#! /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
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (C) 2008 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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 <cstdlib>
|
|
||||||
#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;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
// 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 <cstdlib>
|
|
||||||
#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;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
@ -1,419 +0,0 @@
|
||||||
// Copyright (C) 2008, 2010, 2011 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
#include "nipsvm.h"
|
|
||||||
|
|
||||||
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)
|
|
||||||
: 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);
|
|
||||||
hash_comp();
|
|
||||||
}
|
|
||||||
|
|
||||||
state_nips(const state* other)
|
|
||||||
{
|
|
||||||
const state_nips* o = dynamic_cast<const state_nips*>(other);
|
|
||||||
assert(o);
|
|
||||||
ref_ = o->ref_;
|
|
||||||
++(*ref_);
|
|
||||||
state_ = o->state_;
|
|
||||||
hash_ = o->hash_;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 nipsvm_state_compare(get_state(), o->get_state(),
|
|
||||||
min(nipsvm_state_size(get_state()),
|
|
||||||
nipsvm_state_size(o->get_state())));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual size_t
|
|
||||||
hash() const
|
|
||||||
{
|
|
||||||
return hash_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual state_nips* clone() const
|
|
||||||
{
|
|
||||||
return new state_nips(get_state());
|
|
||||||
}
|
|
||||||
|
|
||||||
nipsvm_state_t*
|
|
||||||
get_state() const
|
|
||||||
{
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned* ref_;
|
|
||||||
nipsvm_state_t* state_;
|
|
||||||
size_t hash_;
|
|
||||||
}; // 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()
|
|
||||||
{
|
|
||||||
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 = new char[size];
|
|
||||||
|
|
||||||
global_state_to_str(s->get_state(), 0, buf, size);
|
|
||||||
|
|
||||||
std::string res(buf);
|
|
||||||
delete buf;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
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("Unable to open `" + filename +
|
|
||||||
"' as a NIPS bytecode.");
|
|
||||||
|
|
||||||
nipsvm_ = new nipsvm_t();
|
|
||||||
int res = nipsvm_init(nipsvm_, bytecode_, successor_state_callback,
|
|
||||||
search_error_callback);
|
|
||||||
|
|
||||||
if (res != 0)
|
|
||||||
throw nips_exception("Error while initializing the NIPS VM", res);
|
|
||||||
}
|
|
||||||
|
|
||||||
nips_interface::~nips_interface()
|
|
||||||
{
|
|
||||||
nipsvm_finalize(nipsvm_);
|
|
||||||
bytecode_unload(bytecode_);
|
|
||||||
delete nipsvm_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nips_interface::has_monitor() const
|
|
||||||
{
|
|
||||||
if (bytecode_ == 0)
|
|
||||||
throw nips_exception("The bytecode isn't loaded");
|
|
||||||
|
|
||||||
return bytecode_monitor_present(bytecode_);
|
|
||||||
}
|
|
||||||
|
|
||||||
tgba* nips_interface::automaton()
|
|
||||||
{
|
|
||||||
return new tgba_nips(dict_, nipsvm_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
// Copyright (C) 2008 Laboratoire de Recherche et Développement
|
|
||||||
// de l'Epita (LRDE).
|
|
||||||
//
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
|
|
||||||
// Fwd declarations.
|
|
||||||
typedef struct nipsvm_t nipsvm_t;
|
|
||||||
typedef struct t_bytecode nipsvm_bytecode_t;
|
|
||||||
|
|
||||||
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();
|
|
||||||
bool has_monitor() const;
|
|
||||||
tgba* automaton();
|
|
||||||
private:
|
|
||||||
bdd_dict* dict_;
|
|
||||||
nipsvm_t* nipsvm_;
|
|
||||||
nipsvm_bytecode_t* bytecode_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SPOT_IFACE_NIPS_NIPS_HH
|
|
||||||
1
iface/nips/nips_vm/.gitignore
vendored
1
iface/nips/nips_vm/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
nipsvm
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
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)."
|
|
||||||
|
|
@ -1,674 +0,0 @@
|
||||||
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>.
|
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
2010-11-27 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
|
||||||
|
|
||||||
Fix compilation with Clang.
|
|
||||||
|
|
||||||
* state.c: Do not include state_inline.h twice with different
|
|
||||||
value of STATE_INLINE. It was included once via state.h with
|
|
||||||
STATE_INLINE = "extern inline", and another time directly with
|
|
||||||
STATE_INLINE = "extern". Now...
|
|
||||||
* state.h: ... only include it once here with STATE_INLINE =
|
|
||||||
"static inline".
|
|
||||||
|
|
||||||
2010-01-21 Alexandre Duret-Lutz <adl@lrde.epita.fr>
|
|
||||||
|
|
||||||
Kill a warning on Ubuntu.
|
|
||||||
|
|
||||||
* interactive.c (interactive_simulate): Explicitly ignore the
|
|
||||||
return of scanf to kill a warning.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
noinst_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
|
|
||||||
|
|
||||||
noinst_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
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
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
|
|
||||||
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
KILL
|
|
||||||
----
|
|
||||||
set process <pid> to terminated
|
|
||||||
stack before: [...] <pid>
|
|
||||||
stack after: [...]
|
|
||||||
|
|
||||||
POPX
|
|
||||||
----
|
|
||||||
discard topmost value from stack
|
|
||||||
stack before: [...] <value>
|
|
||||||
stack after: [...]
|
|
||||||
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
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
|
|
||||||
|
|
||||||
|
|
@ -1,610 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
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>
|
|
||||||
|
|
@ -1,322 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/* 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
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,233 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,674 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,215 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
/* 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 );
|
|
||||||
(void) 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 );
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,367 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,588 +0,0 @@
|
||||||
#! /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";
|
|
||||||
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
# 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;
|
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
# 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;
|
|
||||||
|
|
@ -1,513 +0,0 @@
|
||||||
#! /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";
|
|
||||||
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
/* 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 );
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,346 +0,0 @@
|
||||||
/* 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 );
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,640 +0,0 @@
|
||||||
/* 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\\"
|
|
||||||
|
|
||||||
// *** 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 );
|
|
||||||
}
|
|
||||||
|
|
@ -1,274 +0,0 @@
|
||||||
/* 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 static 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
|
|
||||||
|
|
@ -1,280 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
/* 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
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 */
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
/* 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
|
|
||||||
1
iface/nips/nipstest/.gitignore
vendored
1
iface/nips/nipstest/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
defs
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
## Copyright (C) 2003, 2004, 2005, 2006, 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.
|
|
||||||
|
|
||||||
|
|
||||||
check_SCRIPTS = defs
|
|
||||||
|
|
||||||
BYTECODES = dinner.pr.nips.b never.pr.b peterson.pm.b regbit.b
|
|
||||||
EXTRA_DIST = $(TESTS) $(BYTECODES)
|
|
||||||
|
|
||||||
# Ordered by strength of the test. Test basic features first.
|
|
||||||
TESTS = \
|
|
||||||
dotty.test \
|
|
||||||
emptiness.test
|
|
||||||
|
|
||||||
CLEANFILES = \
|
|
||||||
dotty
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
# -*- shell-script -*-
|
|
||||||
# Copyright (C) 2003, 2004, 2006, 2011 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.
|
|
||||||
|
|
||||||
# Ensure we are running from the right directory.
|
|
||||||
test -f ./defs || {
|
|
||||||
echo "defs: not found in current directory" 1>&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# If srcdir is not set, then we are not running from `make check'.
|
|
||||||
if test -z "$srcdir"; then
|
|
||||||
# compute $srcdir.
|
|
||||||
srcdir=`echo "$0" | sed -e 's,/[^\\/]*$,,'`
|
|
||||||
test $srcdir = $0 && srcdir=.
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure $srcdir is set correctly.
|
|
||||||
test -f $srcdir/defs.in || {
|
|
||||||
echo "$srcdir/defs.in not found, check \$srcdir" 1>&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# User can set VERBOSE to see all output.
|
|
||||||
test -z "$VERBOSE" && exec >/dev/null 2>&1
|
|
||||||
|
|
||||||
echo "== Running test $0"
|
|
||||||
|
|
||||||
DOT='@DOT@'
|
|
||||||
top_builddir='@builddir@/..'
|
|
||||||
VALGRIND='@VALGRIND@'
|
|
||||||
|
|
||||||
run()
|
|
||||||
{
|
|
||||||
expected_exitcode=$1
|
|
||||||
shift
|
|
||||||
exitcode=0
|
|
||||||
if test -n "$VALGRIND"; then
|
|
||||||
exec 6>valgrind.err
|
|
||||||
GLIBCPP_FORCE_NEW=1 \
|
|
||||||
$VALGRIND --tool=memcheck --leak-check=yes --log-fd=6 -q "$@" ||
|
|
||||||
exitcode=$?
|
|
||||||
cat valgrind.err 1>&2
|
|
||||||
test -z "`sed 1q valgrind.err`" || exit 50
|
|
||||||
rm -f valgrind.err
|
|
||||||
else
|
|
||||||
"$@" || exitcode=$?
|
|
||||||
fi
|
|
||||||
test $exitcode = $expected_exitcode || exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Turn on shell traces when VERBOSE=x.
|
|
||||||
if test "x$VERBOSE" = xx; then
|
|
||||||
set -x
|
|
||||||
else
|
|
||||||
:
|
|
||||||
fi
|
|
||||||
Binary file not shown.
|
|
@ -1,31 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Copyright (C) 2008, 2011 Laboratoire de Recherche et Développement de
|
|
||||||
# l'Epita (LRDE)
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
. ./defs || exit 1
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
BYTECODE="never.pr.b regbit.b"
|
|
||||||
for bytecode in $BYTECODE; do
|
|
||||||
run 0 "$top_builddir/dottynips" "$srcdir/$bytecode" > dotty || exit 1
|
|
||||||
test -z "$DOT" || "$DOT" -Tps dotty > /dev/null || exit 1
|
|
||||||
rm -f dotty
|
|
||||||
done
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# Copyright (C) 2008 Laboratoire de Recherche et Développement de
|
|
||||||
# l'Epita (LRDE)
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
. ./defs || exit 1
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
ALGO="Cou99 CVWY90 GV04 SE05 Tau03 Tau03"
|
|
||||||
|
|
||||||
# Non empty.
|
|
||||||
BYTECODE="dinner.pr.nips.b never.pr.b"
|
|
||||||
for algo in $ALGO; do
|
|
||||||
for bytecode in $BYTECODE; do
|
|
||||||
run 0 "$top_builddir/empt_check" -c -e$algo "$srcdir/$bytecode" |
|
|
||||||
grep '^non empty$' > /dev/null || exit 1
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Empty
|
|
||||||
BYTECODE="peterson.pm.b"
|
|
||||||
for algo in $ALGO; do
|
|
||||||
for bytecode in $BYTECODE; do
|
|
||||||
run 0 "$top_builddir/empt_check" -c -e$algo "$srcdir/$bytecode" |
|
|
||||||
grep '^empty$' > /dev/null || exit 1
|
|
||||||
done
|
|
||||||
done
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue