#!/usr/bin/perl -w # # Quick Perl program to decode and display details about # tagged images created by mknbi # -e extracts directory to `nbidir' and segments to `segmentN' # N = 0, 1, 2, ... # # Added code to dump vendor tag in hex (for DOS disk parameters) # # Ken Yap, August 1999 # use strict; use vars qw($imagefile $data $curoffset $dirfile @seglengths $vendordata $extract $status $i); sub getvendordata ($) { my ($flags) = @_; my $vendordata = ''; my $vendorlen = ($flags & 0xff) >> 4; if ($vendorlen > 0) { $vendorlen *= 4; $vendordata = unpack("a$vendorlen", substr($data, $curoffset)); $curoffset += $vendorlen; } return ($vendordata); } sub decodesegmentflags ($) { my ($flags) = @_; my ($type); $flags >>= 24; $flags &= 0x3; ($flags == 0) and $type = "Absolute"; ($flags == 1) and $type = "Follows last segment"; ($flags == 2) and $type = "Below end of memory"; ($flags == 3) and $type = "Below last segment loaded"; return ($type); } sub one_nbi_segment ($) { my ($segnum) = @_; my ($type, $vendordata, @vdata, $i); my ($flags, $loadaddr, $imagelen, $memlength) = unpack('V4', substr($data, $curoffset)); $curoffset += 16; printf "Segment number %d\n", $segnum; printf "Load address:\t\t%08x\n", $loadaddr; printf "Image length:\t\t%d\n", $imagelen; printf "Memory length:\t\t%d\n", $memlength; $type = &decodesegmentflags($flags); print "Position:\t\t$type\n"; printf "Vendor tag:\t\t%d\n", ($flags >> 8) & 0xff; if (($vendordata = &getvendordata($flags)) ne '') { print "Vendor data:\t\t\"", $vendordata, "\"\n"; @vdata = unpack('C*', $vendordata); print "Vendor data in hex:\t"; foreach $i (0..$#vdata) { printf "%02x ", $vdata[$i]; } print "\n"; } print "\n"; push (@seglengths, $imagelen); return (($flags >> 26) & 1); } sub decode_nbi { my ($magic, $flags, $bx, $ds, $ip, $cs) = unpack('a4Vv4', substr($data, 0, 16)); $curoffset = 16; # Decode the header printf "Type: NBI\nHeader location:\t%04x:%04x\n", $ds, $bx; if (($flags >> 31) & 1) { printf "Start address:\t\t%04x%04x (flat)\n", $cs, $ip; } else { printf "Start address:\t\t%04x:%04x\n", $cs, $ip; } print "Flags:\n"; print "\tReturn to loader after execution (extension)\n" if (($flags >> 8) & 1); if (($vendordata = &getvendordata($flags)) ne '') { print "Vendor data:\t\t", $vendordata, "\n"; } print "\n"; # Now decode each segment record my $segnum = 0; do { $i = &one_nbi_segment($segnum); ++$segnum; } while (!$i); } sub one_elf_segment ($$) { my ($segnum, $curoffset) = @_; my ($offset, $vaddr, $paddr, $filesz, $memsz, $flags, $align) = unpack('@4V6', substr($data, $curoffset)); printf "Segment number %d\n", $segnum; printf "Load address:\t\t%08x\n", $vaddr; printf "Image length:\t\t%d\n", $filesz; printf "Memory length:\t\t%d\n", $memsz; print "\n"; push (@seglengths, $filesz); } sub decode_elf { my ($entry, $phoff, $shoff, $flags, $ehsize, $phentsize, $phnum) = unpack('@24V4v3', $data); printf "Type: ELF\nStart address:\t\t%08x\n", $entry; print "Flags:\n"; print "\tReturn to loader after execution (extension)\n" if ($flags & 0x8000000); print "\n"; $curoffset = $phoff; foreach $i (0..$phnum-1) { &one_elf_segment($i, $curoffset); $curoffset += $phentsize; } } $extract = 0; @seglengths = (); $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n"; if ($ARGV[0] eq '-e') { $extract = 1; shift } $#ARGV >= 0 or die "Usage: disnbi [-e] Etherboot-image-file\n"; $imagefile= $ARGV[0]; open(I, $ARGV[0]) or die "$imagefile: $!\n"; binmode(I); (defined($status = sysread(I, $data, 512)) and $status == 512) or die "$imagefile: Cannot read header\n"; my ($magic) = unpack('a4', substr($data, 0, 4)); if ($magic eq "\x36\x13\x03\x1B") { &decode_nbi(); $dirfile = 'nbidir'; } elsif ($magic eq "\x7FELF") { &decode_elf(); $dirfile = 'elfdir'; } else { die "$imagefile: Not a tagged or ELF image file\n"; } exit(0) if ($extract == 0); print "Dumping directory to `$dirfile'...\n"; open(O, ">$dirfile") or die "$dirfile: $!\n"; binmode(O); print O $data; close(O); $data = ''; foreach $i (0..$#seglengths) { print "Extracting segment $i to `segment$i'...\n"; open(O, ">segment$i") or die "segment$i: $!\n"; binmode(O); (defined($status = sysread(I, $data, $seglengths[$i])) and $status = $seglengths[$i]) or die "$imagefile: Cannot read data\n"; print O $data; close(O); } print "Done\n"; exit(0); __END__ =head1 NAME disnbi - display Etherboot image =head1 SYNOPSIS B [C<-e>] I =head1 DESCRIPTION B is a program that to display in symbolic form the contents of a Etherboot image created by mknbi or mkelf. Detection of image type is automatic. B<-e> Extract contents of image as well. The directory will be written to C or C and the segments to CI where I is 0, 1, 2, etc. =head1 BUGS Please report all bugs to the author. =head1 SEE ALSO Etherboot tutorial at C =head1 COPYRIGHT B is under the GNU Public License =head1 AUTHOR Ken Yap (C) =head1 DATE Version 1.4 December 2002