Skip to content

Instantly share code, notes, and snippets.

@jesboat
Created May 15, 2020 16:47
Show Gist options
  • Save jesboat/5b876169861d80588263dcb0bd772ea2 to your computer and use it in GitHub Desktop.
Save jesboat/5b876169861d80588263dcb0bd772ea2 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use IPC::Open2;
sub read_panic {
my ($in, $name) = @_;
my $lines = [ <$in> ];
chomp(@$lines);
return $lines;
}
sub parse_metadata {
my ($name, $lines) = @_;
my $vers;
my $slide;
for my $line (@$lines) {
if ($line =~ m{^(Darwin Kernel Version.*)$}) {
defined($vers) and die "Fatal: multiple version lines in $name\n";
$vers = $1;
} elsif ($line =~ m{^Kernel slide:\s+(0x[0-9a-f]+)$}) {
defined($slide) and die "Fatal: multiple slide lines in $name\n";
$slide = $1;
}
}
defined($vers) or die "Fatal: no version line in $name\n";
defined($slide) or die "Fatal: no slide line in $name\n";
return {vers => $vers, slide => $slide};
}
sub find_kernel {
my ($name, $metadata) = @_;
my @kernels = glob("/Library/Developer/KDKs/*/System/Library/Kernels/kernel*");
my @kernels_matching;
KERNEL:
for my $kernel (@kernels)
{
next if $kernel =~ /\.dSYM$/;
open my($strings), "-|", ("strings", $kernel);
while (<$strings>) {
chomp;
if ($_ eq $metadata->{vers}) {
push @kernels_matching, $kernel;
next KERNEL;
}
}
}
if (@kernels_matching > 1) {
die "Fatal: multiple kernels matched version ",
"'$metadata->{vers}' (found in $name): ",
"[@kernels_matching]\n";
} elsif (@kernels_matching == 0) {
die "Fatal: no kernels had version ",
"'$metadata->{vers}' (found in $name); ",
"tried [@kernels]\n";
} else {
return $kernels_matching[0];
}
}
sub symbolify_lines {
my ($name, $metadata, $kern, $lines) = @_;
for my $lineno (0 .. $#$lines) {
if ($lines->[$lineno] =~ m{^(0x[0-9a-f]+) \s* : \s* (0x[0-9a-f]+) \s*$}x) {
my $addr = $2;
my $atos_pid = open2(
my($from_atos), my($to_atos),
"atos", "-o", "$kern",#.dSYM/Contents/Resources/DWARF/kernel",
"-s", $metadata->{slide},
);
print {$to_atos} "$addr\n";
close($to_atos);
my $sym = <$from_atos>;
chomp($sym);
close($from_atos);
waitpid($atos_pid, 0); # ignore result
$lines->[$lineno] .= " ($sym)";
}
}
}
sub print_panic {
my ($out, $lines) = @_;
for my $line (@$lines) {
print {$out} $line, "\n";
}
}
sub symbolify {
my ($in, $out, $name) = @_;
my $lines = read_panic($in, $name);
my $metadata = parse_metadata($name, $lines);
my $kern = find_kernel($name, $metadata);
symbolify_lines($name, $metadata, $kern, $lines);
print_panic($out, $lines);
}
sub main {
my @args = @_;
if (@_ == 0) {
symbolify(\*STDIN, \*STDOUT, "standard input");
} else {
for my $file (@_) {
open my($in), "<", $file;
open my($out), ">", "$file.symbolified";
symbolify($in, $out, $file);
}
}
}
main(@ARGV) unless caller;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment