#!/usr/bin/perl -w

#
# Copyright (c) 2002 David Eriksson <david@2good.com>
# 
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the
# following conditions:
# 
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
# USE OR OTHER DEALINGS IN THE SOFTWARE.
# 
# Rewritten in perl by Bosse - May 2003

use strict;
no strict "vars";
$, = ' ';
$\ = "\n";

$hex = '';

@ARGV == 1 || die("Syntax: $0 file.o > file.pat\n");
$object = $ARGV[0];

open(FH, "nm -n $object|");
while(<FH>) {
# address type name
  my @line = split(' ');
  next unless($#line >= 1);
  if($line[1] =~ /^[WT]$/o) {
	 push @{$pubhash{$line[2]}}, $line[0];
  } elsif ($line[0] =~ /^U$/o) {
	 $undefhash{$line[1]} = 1;
  }
}
close(FH);

open(FH, "objdump -s -j .text $object|");
while(<FH>) {
  next unless(/^\s*[0-9a-f]+\s+((([0-9a-f]){1,8}\s){1,4})/io);
  $hex .= $1;
}
close(FH);

$hex =~ s/\s//g;

$modlen = length($hex) / 2;

open(FH, "objdump -r -j .text $object|");
while(<FH>) {
  my ($offset, $type, $name) = split(/\s+/);
  next if(!($offset =~ /^[0-9a-f]+$/io && $type && $name));
  if(!($type =~ /R_386_32/o || $type =~ /R_386_PC32/o)) {
    print STDERR "Unknown relocation type on this line:\n$_";
    next;
  }
  $offset = hex($offset);
  if($offset >= $modlen) {
    print STDERR "Too little data at this line:\n$_";
    exit(1);
  }
  push @{$relochash{$name}}, $offset;
  substr($hex, $offset * 2, 8) = "........";
}
close(FH);

if($modlen < 32) {
  $hex .= "." x (64 - length($hex));
}

$pattern = substr($hex, 0, 64);
$remaining = substr($hex, 64);

$asum = 0;
$alen = 0;

printf("%s %02x %04x %04x", $pattern, $alen, $asum, $modlen);

while(my $name = each %pubhash){
  foreach my $i (0 .. $#{$pubhash{$name}}) {
	 printf(" :%04x %s", hex($pubhash{$name}[$i]), $name);
  }
}

while(my $name = each %undefhash) {
  foreach my $i (0 .. $#{$relochash{$name}}) {
    printf(" ^%04x %s", $relochash{$name}[$i], $name);
  }
}

print " $remaining\n---";
