#!/usr/bin/perl -w ## scd-addresses.pl ## by Mike Melanson (mike at multimedia.cx) ## Perl script to automatically determine the function boundaries from a ## scd disassembly listing; scd = Sang Cho's Disassembler, available here: ## http://www.geocities.com/siliconvalley/foothills/4078/disasm.html ## ## Usage: ## scd-addresses.pl < disassembly-file > function-file ## use strict; # parse lines from "ASSEMBLY CODE LISTING" to "Cross Reference Listing" my $parse = 0; my $current_start = 0; my $call_line; my $address; my $next_line; my $function; my $previous_address; my %master_function_table; while (($_ = ) && ($_ !~ /Cross Reference Listing/)) { chomp; # build a list of the public, exported, top-level functions if (/EXPORTED FUNCTIONS/) { # eat 3 lines $_ = ; $_ = ; $_ = ; while (($_ = ) && ($_ =~ /^Addr:/)) { $_ = s/^Addr:(.{8}).*Name: (.*)$//; $address = $1; $function = $2; $master_function_table{$address}->{'function'} = $function; $master_function_table{$current_start}->{'call_list'} = ""; } } if (($parse == 0) && (/ASSEMBLY CODE LISTING/)) { $parse = 1; } if ($parse == 1) { if (/^=+/) { $next_line = ; chomp $next_line; if ($next_line !~ /^:/) { ; # another line of '=' chars $next_line = ; } $next_line =~ s/^:([0-9A-Fa-f]{8})//; $current_start = $1; if (!defined $master_function_table{$current_start}) { $master_function_table{$current_start}->{'function'} = "(no name)"; $master_function_table{$current_start}->{'call_list'} = ""; } } if (/ call /) { $call_line = $_; $call_line =~ s/call (.*$)//; $call_line = $1; $master_function_table{$current_start}->{'call_list'} .= "$call_line|"; } } } # fill in the last addresses by assuming that the last address for a given # function is 1 less than the first address for the next function print "Full function list:\n"; $previous_address = "FFFFFFFF"; foreach $address(sort keys %master_function_table) { if ($previous_address ne "FFFFFFFF") { $master_function_table{$previous_address}->{'last_address'} = sprintf "%08X", hex($address) - 1; print "function: $previous_address -> $master_function_table{$previous_address}->{'last_address'}: $master_function_table{$previous_address}->{'function'}\n"; } $previous_address = $address; } # assume that the last address goes on forever (small hole in the logic) $master_function_table{$previous_address}->{'last_address'} = "FFFFFFFF"; print "function: $previous_address -> $master_function_table{$previous_address}->{'last_address'}: $master_function_table{$previous_address}->{'function'}\n";