#!/usr/bin/perl

# 
# cyg-resolve.pl - CygProfiler resolver
# 
# Michal Ludvig <michal@logix.cz>
# http://www.logix.cz/michal/devel
# 
# Use this script to parse the output of the CygProfile suite.
# 

use strict;
use warnings;
no warnings 'portable';
use diagnostics;
use English;

my %symtab;
my ($binfile, $textfile, $levelcorr);

$OUTPUT_AUTOFLUSH=1;

&help() if($#ARGV < 1);
$binfile=$ARGV[0];
&help() if($binfile =~ /--help/);
$textfile=($#ARGV > 0 ? $ARGV[1] : "cygprof.log");
$levelcorr=($#ARGV > 1 ? $ARGV[2] : -1);

&main();

# ==== Subs

sub help()
{
	printf("CygProgile parser, Michal Ludvig <michal\@logix.cz>, 2002-2003\n");
	printf("Usage: %s <bin-file> <log-file> [<correction>]\n", $0);
	printf("\t<bin-file>   Program that generated the logfile.\n");
	printf("\t<log-file>   Logfile generated by the profiled program.\n");
	printf("\t<correction> Correction of the nesting level.\n");
	exit;
}

sub main()
{
	my($offset, $type, $function);
	my($nsym, $nfunc);
	
	$nsym=0;
	$nfunc=0;
	
	open(NM, "nm $binfile|") or die("Unable to run 'nm $binfile': $!\n");
	printf("Loading symbols from $binfile ... ");
	
	while(<NM>)
	{
		$nsym++;
		next if(!/^([0-9A-F]+) (.) (.+)$/i);
		$offset=hex($1); $type=$2; $function=$3;
		next if($type !~ /[tT]/);
		$nfunc++;
		$symtab{$offset}=$function;
	}
	printf("OK\nSeen %d symbols, stored %d function offsets\n", $nsym, $nfunc);
	close(NM);

	open(TEXT, "$textfile")
		or die("Unable to open '$textfile': $!\n");
	
	if ($levelcorr == -1)
	{
		$levelcorr = 0;
		while(<TEXT>)
		{
			if ((/^.*[+-] (-*\d+)/) && ($1 < -$levelcorr))
				{ $levelcorr = -$1; }
		}
		printf("Level correction set to %d\n", $levelcorr);
		seek(TEXT, 0, 0);
	}

	while(<TEXT>)
	{
		# Change the pattern if the output format 
		# of __cyg_...() functions has changed.
		if(!/(.*)([+-]) (-*\d+) 0x([[:xdigit:]]+) 0x([[:xdigit:]]+)\s*(\d*)/)
			{ print $_; next; }
		else
		{
			my $prolog=$1;
			my $type=$2;

			my $level=$3 + $levelcorr;
			my $off1=hex($4);
			my $off2=hex($5);
			my $pid=$6;

			printf("$prolog\n") if ($prolog);

			# Don't print exits
			next if($type eq "-");
			my $sym=(defined($symtab{$off1})?$symtab{$off1}:"???");

			printf("\t%s %2d 0x%x (from 0x%x) %*s%s\n",
				$type, $level, $off1, $off2,
				$level+1, " ", "$sym()");
		}
	}
	close(TEXT);

	printf("done\n");
}
