#!/usr/bin/perl
#
# checkov.pl
#
# Check NASM map output for overflow
#
# This assumes that a section for which start != vstart, both
# ranges need to be checked for overflow (true for SYSLINUX)
#

($in, $target) = @ARGV;

sub overlap($$$$) {
    my($s1,$e1,$s2,$e2) = @_;

    return 1 if ( $s2 < $e1 && $e2 > $s1 );
    return 1 if ( $s1 < $e2 && $e1 > $s2 );

    return 0;
}

open(IN, '<', $in) or die "$0: Cannot open input file: $in\n";

$section = undef;
while ( $line = <IN> ) {
    if ( $line =~ /^-/ ) {
	if ( $line =~ /^\-\-\-\- Section (\S+) / ) {
	    $section = $1;
	} else {
	    $section = undef;
	}
    } elsif ( defined($section) ) {
	if ( $line =~ /^length\:\s*(\S+)/ ) {
	    $length{$section} = hex $1;
	} elsif ( $line =~ /^start\:\s*(\S+)/ ) {
	    $start{$section} = hex $1;
	} elsif ( $line =~ /^vstart\:\s*(\S+)/ ) {
	    $vstart{$section} = hex $1;
	}
    }
}
close(IN);

$err = 0;

foreach $s ( keys(%start) ) {
    $sstart  = $start{$s};
    $svstart = $vstart{$s};
    $send    = $sstart + $length{$s};
    $svend   = $svstart + $length{$s};

    if ( $send > 0x10000 || $svend > 0x10000 ) {
	print STDERR "$target: 16-bit overflow on section $s\n";
	$err++;
    }

    foreach $o ( keys(%start) ) {
	next if ( $s ge $o );

	$ostart  = $start{$o};
	$ovstart = $vstart{$o};
	$oend    = $ostart + $length{$o};
	$ovend   = $ovstart + $length{$o};

	if ( overlap($sstart, $send, $ostart, $oend) ||
	     overlap($svstart, $svend, $ostart, $oend) ||
	     overlap($sstart, $send, $ovstart, $ovend) ||
	     overlap($svstart, $svend, $ovstart, $ovend) ) {
	    print STDERR "$target: section $s overlaps section $o\n";
	    $err++;
	}
    }
}

if ( $err ) {
    unlink($target);
    exit(1);
} else {
    exit(0);
}
