blob: 263ec937eaa70b4fd00bff18599db7f22671753c [file] [log] [blame]
#!/usr/bin/env perl
# ----------------------------------------------------------------------
# knlinfo by Phil Elwell for Raspberry Pi
#
# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
#
# Licensed under the terms of the GNU General Public License.
# ----------------------------------------------------------------------
use strict;
use integer;
use Fcntl ":seek";
my $trailer_magic = 'RPTL';
my %atom_formats =
(
'DDTK' => \&format_bool,
'DTOK' => \&format_bool,
'KVer' => \&format_string,
'270X' => \&format_bool,
'283X' => \&format_bool,
'283x' => \&format_bool,
);
if (@ARGV != 1)
{
print ("Usage: knlinfo <kernel image>\n");
exit(1);
}
my $kernel_file = $ARGV[0];
my ($atoms, $pos) = read_trailer($kernel_file);
exit(1) if (!$atoms);
printf("Kernel trailer found at %d/0x%x:\n", $pos, $pos);
foreach my $atom (@$atoms)
{
printf(" %s: %s\n", $atom->[0], format_atom($atom));
}
exit(0);
sub read_trailer
{
my ($kernel_file) = @_;
my $fh;
if (!open($fh, '<', $kernel_file))
{
print ("* Failed to open '$kernel_file'\n");
return undef;
}
if (!seek($fh, -12, SEEK_END))
{
print ("* seek error in '$kernel_file'\n");
return undef;
}
my $last_bytes;
sysread($fh, $last_bytes, 12);
my ($trailer_len, $data_len, $magic) = unpack('VVa4', $last_bytes);
if (($magic ne $trailer_magic) || ($data_len != 4))
{
print ("* no trailer\n");
return undef;
}
if (!seek($fh, -12, SEEK_END))
{
print ("* seek error in '$kernel_file'\n");
return undef;
}
$trailer_len -= 12;
while ($trailer_len > 0)
{
if ($trailer_len < 8)
{
print ("* truncated atom header in trailer\n");
return undef;
}
if (!seek($fh, -8, SEEK_CUR))
{
print ("* seek error in '$kernel_file'\n");
return undef;
}
$trailer_len -= 8;
my $atom_hdr;
sysread($fh, $atom_hdr, 8);
my ($atom_len, $atom_type) = unpack('Va4', $atom_hdr);
if ($trailer_len < $atom_len)
{
print ("* truncated atom data in trailer\n");
return undef;
}
my $rounded_len = (($atom_len + 3) & ~3);
if (!seek($fh, -(8 + $rounded_len), SEEK_CUR))
{
print ("* seek error in '$kernel_file'\n");
return undef;
}
$trailer_len -= $rounded_len;
my $atom_data;
sysread($fh, $atom_data, $atom_len);
if (!seek($fh, -$atom_len, SEEK_CUR))
{
print ("* seek error in '$kernel_file'\n");
return undef;
}
push @$atoms, [ $atom_type, $atom_data ];
}
if (($$atoms[-1][0] eq "\x00\x00\x00\x00") &&
($$atoms[-1][1] eq ""))
{
pop @$atoms;
}
else
{
print ("* end marker missing from trailer\n");
}
return ($atoms, tell($fh));
}
sub format_atom
{
my ($atom) = @_;
my $format_func = $atom_formats{$atom->[0]} || \&format_hex;
return $format_func->($atom->[1]);
}
sub format_bool
{
my ($data) = @_;
return unpack('V', $data) ? 'y' : 'n';
}
sub format_int
{
my ($data) = @_;
return unpack('V', $data);
}
sub format_string
{
my ($data) = @_;
return '"'.$data.'"';
}
sub format_hex
{
my ($data) = @_;
return unpack('H*', $data);
}