about summary refs log tree commit diff stats
path: root/apps/ex12.subx
blob: 0c0d4315f0a8877496896b6c090ffa5fb9591474 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Example showing mmap syscall.
# Create a new segment using mmap, save the address, write to it.
#
# To run:
#   $ ./bootstrap translate init.linux apps/ex12.subx -o apps/ex12
#   $ ./bootstrap run apps/ex12
# You shouldn't get a segmentation fault.

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

Entry:
    # mmap(Mmap-new-segment->len)
    bb/copy-to-ebx  Mmap-new-segment/imm32
    e8/call  syscall_mmap/disp32

    # write to *eax to check that we have access to the newly-allocated segment
    c7          0/subop/copy        0/mod/direct    0/rm32/eax    .           .             .           .           .               0x34/imm32        # copy to *eax

    # exit(eax)
    89/copy                         3/mod/direct    3/rm32/ebx    .           .             .           0/r32/eax   .               .                 # copy eax to ebx
    e8/call  syscall_exit/disp32

== data

# various constants used here were found in the Linux sources (search for file mman-common.h)
Mmap-new-segment:  # type mmap_arg_struct
    # addr
    0/imm32
    # len
    0x100/imm32
    # protection flags
    3/imm32  # PROT_READ | PROT_WRITE
    # sharing flags
    0x22/imm32  # MAP_PRIVATE | MAP_ANONYMOUS
    # fd
    -1/imm32  # since MAP_ANONYMOUS is specified
    # offset
    0/imm32  # since MAP_ANONYMOUS is specified

# . . vim:nowrap:textwidth=0
a id='n242' href='#n242'>242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364











































































































































































































































































































































































                                                                                                                          
#!/usr/bin/perl -w
# $LynxId: tbl2html.pl,v 1.5 2011/05/21 15:18:16 tom Exp $
#
# Translate one or more ".tbl" files into ".html" files which can be used to
# test the charset support in lynx.  Each of the ".html" files will use the
# charset that corresponds to the input ".tbl" file.

use strict;

use Getopt::Std;
use File::Basename;
use POSIX qw(strtod);

sub field($$) {
	my $value = $_[0];
	my $count = $_[1];

	while ( $count > 0 ) {
		$count -= 1;
		$value =~ s/^\S*\s*//;
	}
	$value =~ s/\s.*//;
	return $value;
}

sub notes($) {
	my $value = $_[0];

	$value =~ s/^[^#]*//;
	$value =~ s/^#//;
	$value =~ s/^\s+//;

	return $value;
}

sub make_header($$$) {
	my $source   = $_[0];
	my $charset  = $_[1];
	my $official = $_[2];

	printf FP "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
	printf FP "<HTML>\n";
	printf FP "<HEAD>\n";
	printf FP "<!-- $source -->\n";
	printf FP "<TITLE>%s table</TITLE>\n", &escaped($official);
	printf FP "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=%s\">\n", &escaped($charset);
	printf FP "</HEAD>\n";
	printf FP "\n";
	printf FP "<BODY> \n";
	printf FP "\n";
	printf FP "<H1 ALIGN=center>%s table</H1> \n", &escaped($charset);
	printf FP "\n";
	printf FP "<PRE>\n";
	printf FP "Code  Char  Entity   Render          Description\n";
}

sub make_mark() {
	printf FP "----  ----  ------   ------          -----------------------------------\n";
}

sub escaped($) {
	my $result = $_[0];
	$result =~ s/&/&amp;/g;
	$result =~ s/</&lt;/g;
	$result =~ s/>/&gt;/g;
	return $result;
}

sub make_row($$$) {
	my $old_code = $_[0];
	my $new_code = $_[1];
	my $comments = $_[2];

	# printf "# make_row %d %d %s\n", $old_code, $new_code, $comments;
	my $visible = sprintf("&amp;#%d;      ", $new_code);
	if ($old_code < 256) {
		printf FP "%4x    %c   %.13s  &#%d;             %s\n",
			$old_code, $old_code,
			$visible, $new_code,
			&escaped($comments);
	} else {
		printf FP "%4x    .   %.13s  &#%d;             %s\n",
			$old_code,
			$visible, $new_code,
			&escaped($comments);
	}
}

sub null_row($$) {
	my $old_code = $_[0];
	my $comments = $_[1];

	if ($old_code < 256) {
		printf FP "%4x    %c                     %s\n",
			$old_code, $old_code,
			&escaped($comments);
	} else {
		printf FP "%4x    .                     %s\n",
			$old_code,
			&escaped($comments);
	}
}

sub make_footer() {
	printf FP "</PRE>\n";
	printf FP "</BODY>\n";
	printf FP "</HTML>\n";
}

# return true if the string describes a range
sub is_range($) {
	return ($_[0] =~ /.*-.*/);
}

# convert the U+'s to 0x's so strtod() can convert them.
sub zeroxes($) {
	my $result = $_[0];
	$result =~ s/^U\+/0x/;
	$result =~ s/-U\+/-0x/;
	return $result;
}

# convert a string to a number (-1's are outside the range of Unicode).
sub value_of($) {
	my ($result, $oops) = strtod($_[0]);
	$result = -1 if ($oops ne 0);
	return $result;
}

# return the first number in a range
sub first_of($) {
	my $range = &zeroxes($_[0]);
	$range =~ s/-.*//;
	return &value_of($range);
}

# return the last number in a range
sub last_of($) {
	my $range = &zeroxes($_[0]);
	$range =~ s/^.*-//;
	return &value_of($range);
}

sub one_many($$$) {
	my $oldcode = $_[0];
	my $newcode = &zeroxes($_[1]);
	my $comment = $_[2];

	my $old_code = &value_of($oldcode);
	if ( $old_code lt 0 ) {
		printf "? Problem with number \"%s\"\n", $oldcode;
	} else {
		&make_mark if (( $old_code % 8 ) == 0 );

		if ( $newcode =~ /^#.*/ ) {
			&null_row($old_code, $comment);
		} elsif ( &is_range($newcode) ) {
			my $first_item = &first_of($newcode);
			my $last_item  = &last_of($newcode);
			my $item;

			if ( $first_item lt 0 or $last_item lt 0 ) {
				printf "? Problem with one:many numbers \"%s\"\n", $newcode;
			} else {
				if ( $comment =~ /^$/ ) {
					$comment = sprintf("mapped: %#x to %#x..%#x", $old_code, $first_item, $last_item);
				} else {
					$comment = $comment . " (range)";
				}
				for $item ( $first_item..$last_item) {
					&make_row($old_code, $item, $comment);
				}
			}
		} else {
			my $new_code = &value_of($newcode);
			if ( $new_code lt 0 ) {
				printf "? Problem with number \"%s\"\n", $newcode;
			} else {
				if ( $comment =~ /^$/ ) {
					$comment = sprintf("mapped: %#x to %#x", $old_code, $new_code);
				}
				&make_row($old_code, $new_code, $comment);
			}
		}
	}
}

sub many_many($$$) {
	my $oldcode = $_[0];
	my $newcode = $_[1];
	my $comment = $_[2];

	my $first_old = &first_of($oldcode);
	my $last_old  = &last_of($oldcode);
	my $item;

	if (&is_range($newcode)) {
		my $first_new = &first_of($newcode);
		my $last_new  = &last_of($newcode);
		for $item ( $first_old..$last_old) {
			&one_many($item, $first_new, $comment);
			$first_new += 1;
		}
	} else {
		for $item ( $first_old..$last_old) {
			&one_many($item, $newcode, $comment);
		}
	}
}

sub approximate($$$) {
	my $values = $_[0];
	my $expect = sprintf("%-8s", $_[1]);
	my $comment = $_[2];
	my $escaped = &escaped($expect);
	my $left;
	my $this;
	my $next;

	$escaped =~ s/\\134/\\/g;
	$escaped =~ s/\\015/\&#13\;/g;
	$escaped =~ s/\\012/\&#10\;/g;

	while ( $escaped =~ /^.*\\[0-7]{3}.*$/ ) {
		$left = $escaped;
		$left =~ s/\\[0-7]{3}.*//;
		$this = substr $escaped,length($left)+1,3;
		$next = substr $escaped,length($left)+4;
		$escaped = sprintf("%s&#%d;%s", $left, oct $this, $next);
	}

	my $visible = sprintf("&amp;#%d;      ", $values);
	if ($values < 256) {
		printf FP "%4x    %c   %.13s  &#%d;             approx: %s\n",
			$values, $values,
			$visible,
			$values,
			$escaped;
	} else {
		printf FP "%4x    .   %.13s  &#%d;             approx: %s\n",
			$values,
			$visible,
			$values,
			$escaped;
	}
}

sub doit($) {
	my $source = $_[0];

	printf "** %s\n", $source;

	my $target = basename($source, ".tbl");

	# Read the file into an array in memory.
	open(FP,$source) || do {
		print STDERR "Can't open input $source: $!\n";
		return;
	};
	my (@input) = <FP>;
	chomp @input;
	close(FP);

	my $n;
	my $charset = "";
	my $official = "";
	my $empty = 1;

	for $n (0..$#input) {
		$input[$n] =~ s/\s*$//; # trim trailing blanks
		$input[$n] =~ s/^\s*//; # trim leading blanks
		$input[$n] =~ s/^#0x/0x/; # uncomment redundant stuff

		next if $input[$n] =~ /^$/;
		next if $input[$n] =~ /^#.*$/;

		if ( $empty 
		  and ( $input[$n] =~ /^\d/
		     or $input[$n] =~ /^U\+/ ) ) {
			$target = $charset . ".html";
			printf "=> %s\n", $target;
			open(FP,">$target") || do {
				print STDERR "Can't open output $target: $!\n";
				return;
			};
			&make_header($source, $charset, $official);
			$empty = 0;
		}

		if ( $input[$n] =~ /^M.*/ ) {
			$charset = $input[$n];
			$charset =~ s/^.//;
		} elsif ( $input[$n] =~ /^O.*/ ) {
			$official = $input[$n];
			$official =~ s/^.//;
		} elsif ( $input[$n] =~ /^\d/ ) {

			my $newcode = &field($input[$n], 1);

			next if ( $newcode eq "idem" );
			next if ( $newcode eq "" );

			my $oldcode = &field($input[$n], 0);
			if ( &is_range($oldcode) ) {
				&many_many($oldcode, $newcode, &notes($input[$n]));
			} else {
				&one_many($oldcode, $newcode, &notes($input[$n]));
			}
		} elsif ( $input[$n] =~ /^U\+/ ) {
			if ( $input[$n] =~ /^U\+\w+:/ ) {
				my $values = $input[$n];
				my $expect = $input[$n];

				$values =~ s/:.*//;
				$values = &zeroxes($values);
				$expect =~ s/^[^:]+://;

				if ( &is_range($values) ) {
					printf "fixme:%s(%s)(%s)\n", $input[$n], $values, $expect;
				} else {
					&approximate(&value_of($values), $expect, &notes($input[$n]));
				}
			} else {
				my $value = $input[$n];
				$value =~ s/\s*".*//;
				$value = &value_of(&zeroxes($value));
				if ($value gt 0) {
					my $quote = $input[$n];
					my $comment = &notes($input[$n]);
					$quote =~ s/^[^"]*"//;
					$quote =~ s/".*//;
					&approximate($value, $quote, $comment);
				} else {
					printf "fixme:%d(%s)\n", $n, $input[$n];
				}
			}
		} else {
			# printf "skipping line %d:%s\n", $n + 1, $input[$n];
		}
	}
	if ( ! $empty ) {
		&make_footer();
	}
	close FP;
}

sub usage() {
	print <<USAGE;
Usage: $0 [tbl-files]

The script writes a new ".html" file for each input, using
the same name as the input, stripping the ".tbl" suffix.
USAGE
	exit(1);
}

if ( $#ARGV < 0 ) {
	usage();
} else {
	while ( $#ARGV >= 0 ) {
		&doit ( shift @ARGV );
	}
}
exit (0);