#!/usr/bin/perl

#############################################################
#                                                           #
# COPYRIGHT (C) HITACHI,LTD. 2002 ALL RIGHTS RESERVED.      #
#                                                           #
# Created by K.SERIZAWA <serizawa@sdl.hitachi.co.jp>        #
#                                                           #
#############################################################

require "getopts.pl";

my	$uname_r = `uname -r`;
my	@symtable = ();
my	$dump_file = "lkstbuf read |";
my	$ksyms_file = "/proc/ksyms";
my	$systemmap_file = "/boot/System.map-$uname_r";
#my	$systemmap_file = "/boot/System.map";

$usage = "usage: $0 [-s System.map]  [-k ksyms]  [-d dump_filename] \n";

Getopts('d:k:s:') || $usage;

if ($opt_d) {
	$dump_file = $opt_d;
}

if ($opt_k) {
	$ksyms_file = $opt_k;
}

if ($opt_s) {
	$systemmap_file = $opt_s;
}


sub symname_print
{
	my ($addr) = @_;
	my ($addr_n) = oct ($addr);
	my ($entry, $entry_prev);
	my ($offs);

	$entry_prev = [0xc0000000,"0xc0000000"];
	foreach $entry (@symtable) {
		if ($addr_n < @{$entry}[0]) {
			$offs = $addr_n - @{$entry_prev}[0];
			print "<@{$entry_prev}[1]+$offs>";
			return;
		}
		$entry_prev = $entry;
	}
}

# lkst_mod_stacktrace_getsym.sh
# (cut -d ' ' -f 1,3 /boot/System.map-2.4.16-Ev020213 ; cut -f 1 /proc/ksyms ) | sort | uniq 

				# Read System.map
open(SYSTEMMAP, $systemmap_file)
	|| die("SYSTEMMAP $systemmap_file ");
while (<SYSTEMMAP>) {
	my ($addr,$symtype, $symname);
	($addr,$symtype, $symname) = split(" ",$_,3);
	chomp($symname);
	push(@symtable, [oct ("0x$addr"), $symname]);
}
close SYSTEMMAP;

				# Read ksyms
				# TODO: ksymoops
open(KSYMS, "$ksyms_file")
	|| die("KSYMS");
while (<KSYMS>) {
	my ($addr,$symname, $modname);
	($addr,$symname,$modname) = split(" ",$_,3);
	chomp($symname);
	push(@symtable, [oct ("0x$addr"), $symname]);
}
close SYSTEMMAP;

push(@symtable, [0xc0000000,"0xc0000000"]);
push(@symtable, [0xffffffff,"0xffffffff"]);

@symtable = sort  {@{$a}[0] <=>
		   @{$b}[0]     } @symtable;

# TODO: uniq

if ($dump_file eq '-') {
	*LKSTBUF = *STDIN;
}
else {
	open(LKSTBUF, $dump_file)
		|| die("Open error: dump_file: $dump_file");
}

while (<LKSTBUF>) {
	if (/^0x[0-9A-Fa-f]{8}: [0-9]{16,18} \[mc\], \\/) {
		$line1 = $_;
		$_ = <LKSTBUF>;
		if (/\(0x0ff[cd]\)/) {
			print "    ";
			$_ = <LKSTBUF>;
			chomp;
			@addrs = split (" ", $_, 4);
			foreach $addr (@addrs) {
				print symname_print ($addr) ." "
			}
			$_ = <LKSTBUF>;
			chomp;
			@addrs = split (" ", $_, 4);
			foreach $addr (@addrs) {
				print symname_print ($addr) ." "
			}
			print "\n";
		}
		else {
			print "\n$line1";
			print $_;
			$_ = <LKSTBUF>;
			print $_;
			$_ = <LKSTBUF>;
			print $_;
			$_ = <LKSTBUF>;
		}
	}
}

#  END
