spot/iface/nips/nips_vm/nips_disasm.pl
Guillaume Sadegh bc5f13bb4e NIPS VM added to the SPOT distribution.
2008-05-29  Guillaume SADEGH  <sadegh@lrde.epita.fr>

	* iface/nips/nips.cc, iface/nips/nips.hh, iface/nips/common.cc,
	iface/nips/common.hh, iface/nips/Makefile.am: TGBA implementation
	with the NIPS library.
	* iface/nips/emptiness_check.cc: Emptiness check on a Promela
	interface.
	* iface/nips/dottynips.cc: Dot printer on the NIPS interface.
	* iface/nips/compile.sh: Add. Wrapper around nips compiler to
	compile Promela to NIPS bytecode.
	* iface/nips/nips_vm,iface/nips/nips_vm/bytecode.h,
	iface/nips/nips_vm/ChangeLog, iface/nips/nips_vm/COPYING,
	iface/nips/nips_vm/hashtab.c, iface/nips/nips_vm/hashtab.h,
	iface/nips/nips_vm/INSTALL, iface/nips/nips_vm/instr.c,
	iface/nips/nips_vm/instr.h, iface/nips/nips_vm/instr_step.c,
	iface/nips/nips_vm/instr_step.h,
	iface/nips/nips_vm/instr_tools.c,
	iface/nips/nips_vm/instr_tools.h,
	iface/nips/nips_vm/instr_wrap.c,
	iface/nips/nips_vm/instr_wrap.h,
	iface/nips/nips_vm/interactive.c,
	iface/nips/nips_vm/interactive.h, iface/nips/nips_vm/main.c,
	iface/nips/nips_vm/Makefile, iface/nips/nips_vm/Makefile.am,
	iface/nips/nips_vm/nips_asm_help.pl,
	iface/nips/nips_vm/nips_asm_instr.pl,
	iface/nips/nips_vm/nips_asm.pl,
	iface/nips/nips_vm/nips_disasm.pl, iface/nips/nips_vm/nipsvm.c,
	iface/nips/nips_vm/nipsvm.h, iface/nips/nips_vm/README,
	iface/nips/nips_vm/rt_err.c, iface/nips/nips_vm/rt_err.h,
	iface/nips/nips_vm/search.c, iface/nips/nips_vm/search.h,
	iface/nips/nips_vm/split.c, iface/nips/nips_vm/split.h,
	iface/nips/nips_vm/state.c, iface/nips/nips_vm/state.h,
	iface/nips/nips_vm/state_inline.h,
	iface/nips/nips_vm/state_parts.c,
	iface/nips/nips_vm/state_parts.h, iface/nips/nips_vm/timeval.h,
	iface/nips/nips_vm/tools.h: NIPS VM added to the SPOT
	distribution.
	* configure.ac, iface/Makefile.am: Build system updated for the
	NIPS front-end.
2008-05-30 13:22:00 +02:00

513 lines
12 KiB
Perl
Executable file

#! /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";