175ce41a5SAli Bahrami#!/usr/bin/perl -w 275ce41a5SAli Bahrami# 375ce41a5SAli Bahrami# CDDL HEADER START 475ce41a5SAli Bahrami# 575ce41a5SAli Bahrami# The contents of this file are subject to the terms of the 675ce41a5SAli Bahrami# Common Development and Distribution License (the "License"). 775ce41a5SAli Bahrami# You may not use this file except in compliance with the License. 875ce41a5SAli Bahrami# 975ce41a5SAli Bahrami# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 1075ce41a5SAli Bahrami# or http://www.opensolaris.org/os/licensing. 1175ce41a5SAli Bahrami# See the License for the specific language governing permissions 1275ce41a5SAli Bahrami# and limitations under the License. 1375ce41a5SAli Bahrami# 1475ce41a5SAli Bahrami# When distributing Covered Code, include this CDDL HEADER in each 1575ce41a5SAli Bahrami# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1675ce41a5SAli Bahrami# If applicable, add the following below this CDDL HEADER, with the 1775ce41a5SAli Bahrami# fields enclosed by brackets "[]" replaced with your own identifying 1875ce41a5SAli Bahrami# information: Portions Copyright [yyyy] [name of copyright owner] 1975ce41a5SAli Bahrami# 2075ce41a5SAli Bahrami# CDDL HEADER END 2175ce41a5SAli Bahrami# 2275ce41a5SAli Bahrami 2375ce41a5SAli Bahrami# 24*5253169eSAli Bahrami# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2575ce41a5SAli Bahrami# 2675ce41a5SAli Bahrami 2775ce41a5SAli Bahrami# 2875ce41a5SAli Bahrami# interface_cmp audits two interface definition files (as created by 2975ce41a5SAli Bahrami# interface_check) against one another, and confirms that: 3075ce41a5SAli Bahrami# 3175ce41a5SAli Bahrami# o All versioned libraries that were present in the previous interface 3275ce41a5SAli Bahrami# are present in the new interface 3375ce41a5SAli Bahrami# 3475ce41a5SAli Bahrami# o for each non-private interface in a library confirm that no symbols 3575ce41a5SAli Bahrami# have been removed and that no symbols have been added to it between 3675ce41a5SAli Bahrami# the two revisions 3775ce41a5SAli Bahrami# 3875ce41a5SAli Bahrami# Return codes: 3975ce41a5SAli Bahrami# 4075ce41a5SAli Bahrami# 0 All interfaces in the new release are identical in old release. 4175ce41a5SAli Bahrami# 1 Something is different refer to the error messages. 4275ce41a5SAli Bahrami 4375ce41a5SAli Bahrami 4475ce41a5SAli Bahramiuse strict; 4575ce41a5SAli Bahrami 4675ce41a5SAli Bahramiuse POSIX qw(getenv); 4775ce41a5SAli Bahramiuse Getopt::Std; 4875ce41a5SAli Bahramiuse File::Basename; 4975ce41a5SAli Bahrami 5075ce41a5SAli Bahrami#### Define all global variables (required for strict) 5175ce41a5SAli Bahramiuse vars qw($Prog); 5275ce41a5SAli Bahramiuse vars qw(%opt); 5375ce41a5SAli Bahramiuse vars qw(%old_hash %old_alias %new_hash %new_alias); 5475ce41a5SAli Bahrami 5575ce41a5SAli Bahrami# Exception Arrays: 5675ce41a5SAli Bahrami# 5775ce41a5SAli Bahrami# The ADDSYM and DELSYM exceptions are maintained on the @AddSymList 5875ce41a5SAli Bahrami# and @DelSymList arrays, respectively. Each array element is a reference 5975ce41a5SAli Bahrami# to a subarray of triples: 6075ce41a5SAli Bahrami# (sym_re, ver_re, obj_re) 6175ce41a5SAli Bahrami# where each item in the tripple is a regular expression, used to 6275ce41a5SAli Bahrami# match a particular symbol/version/object combination. 6375ce41a5SAli Bahrami# 6475ce41a5SAli Bahrami# The EMPTY_TOPVERSION exceptions are maintained on the @EmptyTopVerList 6575ce41a5SAli Bahrami# array. Each array element is a reference to a subarray of pairs: 6675ce41a5SAli Bahrami# (ver_re, obj_re) 6775ce41a5SAli Bahrami# where each item in the pair is a regular expression, used to 6875ce41a5SAli Bahrami# match a particular version/object combination. 6975ce41a5SAli Bahrami# 7075ce41a5SAli Bahramiuse vars qw(@AddSymList @DelSymList @EmptyTopVerList); 7175ce41a5SAli Bahrami 7275ce41a5SAli Bahrami 7375ce41a5SAli Bahrami## LoadExceptions 7475ce41a5SAli Bahrami# 7575ce41a5SAli Bahrami# Locate the exceptions file and process its contents. We can't use 7675ce41a5SAli Bahrami# onbld_elfmod::LoadExceptionsToEXRE() for this, because our exceptions 7775ce41a5SAli Bahrami# need to support more than a single regular expression. 7875ce41a5SAli Bahrami# 7975ce41a5SAli Bahrami# exit: 8075ce41a5SAli Bahrami# @AddSymList, @DelSymList, and @EmptyTopVerList have been updated 8175ce41a5SAli Bahrami# 8275ce41a5SAli Bahrami# note: 8375ce41a5SAli Bahrami# We expand strings of the form MACH(dir) to match the given 8475ce41a5SAli Bahrami# directory as well as any 64-bit architecture subdirectory that 8575ce41a5SAli Bahrami# might be present (i.e. amd64, sparcv9). 8675ce41a5SAli Bahrami# 8775ce41a5SAli Bahramisub LoadExceptions { 8875ce41a5SAli Bahrami my $file; 8975ce41a5SAli Bahrami my $Line; 9075ce41a5SAli Bahrami my $LineNum = 0; 9175ce41a5SAli Bahrami my $err = 0; 9275ce41a5SAli Bahrami 9375ce41a5SAli Bahrami # Locate the exception file 9475ce41a5SAli Bahrami FILE: { 9575ce41a5SAli Bahrami # If -e is specified, that file must be used 9675ce41a5SAli Bahrami if ($opt{e}) { 9775ce41a5SAli Bahrami $file = $opt{e}; 9875ce41a5SAli Bahrami last FILE; 9975ce41a5SAli Bahrami } 10075ce41a5SAli Bahrami 10175ce41a5SAli Bahrami # If this is an activated workspace, use the exception 10275ce41a5SAli Bahrami # file found in the exceptions_list directory. 10375ce41a5SAli Bahrami if (defined($ENV{CODEMGR_WS})) { 10475ce41a5SAli Bahrami $file = "$ENV{CODEMGR_WS}/exception_lists/interface_cmp"; 10575ce41a5SAli Bahrami last FILE if (-f $file); 10675ce41a5SAli Bahrami } 10775ce41a5SAli Bahrami 10875ce41a5SAli Bahrami # As a final backstop, the SUNWonbld package provides a 10975ce41a5SAli Bahrami # copy of the exception file. This can be useful if we 11075ce41a5SAli Bahrami # are being used with an older workspace. 11175ce41a5SAli Bahrami # 11275ce41a5SAli Bahrami # This script is installed in the SUNWonbld bin directory, 11375ce41a5SAli Bahrami # while the exception file is in etc/exception_lists. Find 11475ce41a5SAli Bahrami # it relative to the script location given by $0. 11575ce41a5SAli Bahrami $file = dirname($0) . "/../etc/exception_lists/interface_cmp"; 11675ce41a5SAli Bahrami last FILE if (-f $file); 11775ce41a5SAli Bahrami 11875ce41a5SAli Bahrami # No exception file was found. 11975ce41a5SAli Bahrami return; 12075ce41a5SAli Bahrami } 12175ce41a5SAli Bahrami 12275ce41a5SAli Bahrami open (EFILE, $file) || 12375ce41a5SAli Bahrami die "$Prog: unable to open exceptions file: $file"; 12475ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*EFILE, \$LineNum)) { 12575ce41a5SAli Bahrami 12675ce41a5SAli Bahrami # Expand MACH() 12775ce41a5SAli Bahrami $Line =~ s/MACH\(([^)]+)\)/$1(\/amd64|\/sparcv9)?/g; 12875ce41a5SAli Bahrami 12975ce41a5SAli Bahrami if ($Line =~ /^DELSYM\s+/) { 13075ce41a5SAli Bahrami my ($item, $sym_re, $ver_re, $obj_re) = 13175ce41a5SAli Bahrami split(/\s+/, $Line, 4); 13275ce41a5SAli Bahrami push @DelSymList, [ $sym_re, $ver_re, $obj_re ]; 13375ce41a5SAli Bahrami next; 13475ce41a5SAli Bahrami } 13575ce41a5SAli Bahrami 13675ce41a5SAli Bahrami if ($Line =~ /^ADDSYM\s+/) { 13775ce41a5SAli Bahrami my ($item, $sym_re, $ver_re, $obj_re) = 13875ce41a5SAli Bahrami split(/\s+/, $Line, 4); 13975ce41a5SAli Bahrami push @AddSymList, [ $sym_re, $ver_re, $obj_re ]; 14075ce41a5SAli Bahrami next; 14175ce41a5SAli Bahrami } 14275ce41a5SAli Bahrami 14375ce41a5SAli Bahrami if ($Line =~ /^EMPTY_TOPVERSION\s+/) { 14475ce41a5SAli Bahrami my ($item, $ver_re, $obj_re) = split(/\s+/, $Line, 3); 14575ce41a5SAli Bahrami push @EmptyTopVerList, [ $ver_re, $obj_re ]; 14675ce41a5SAli Bahrami next; 14775ce41a5SAli Bahrami } 14875ce41a5SAli Bahrami 14975ce41a5SAli Bahrami $err++; 15075ce41a5SAli Bahrami printf(STDERR "$file: Unrecognized option: ". 15175ce41a5SAli Bahrami "line $LineNum: $Line\n"); 15275ce41a5SAli Bahrami } 15375ce41a5SAli Bahrami close EFILE; 15475ce41a5SAli Bahrami 15575ce41a5SAli Bahrami exit 1 if ($err != 0); 15675ce41a5SAli Bahrami} 15775ce41a5SAli Bahrami 15875ce41a5SAli Bahrami## ExSym(SymList, sym, ver, obj) 15975ce41a5SAli Bahrami# 16075ce41a5SAli Bahrami# Compare a given symbol/version/object combination against the 16175ce41a5SAli Bahrami# exceptions found in the given list. 16275ce41a5SAli Bahrami# 16375ce41a5SAli Bahrami# entry: 16475ce41a5SAli Bahrami# SymList - Reference to @AddSymList, or @DelSymList. 16575ce41a5SAli Bahrami# sym, ver, obj - Combination to be compared against exception list 16675ce41a5SAli Bahrami# 16775ce41a5SAli Bahrami# exit: 16875ce41a5SAli Bahrami# Returns True (1) if there is a match, and False (0) otherwise. 16975ce41a5SAli Bahrami# 17075ce41a5SAli Bahramisub ExSym { 17175ce41a5SAli Bahrami my ($SymList, $sym, $ver, $obj) = @_; 17275ce41a5SAli Bahrami 17375ce41a5SAli Bahrami foreach my $ex (@$SymList) { 17475ce41a5SAli Bahrami return 1 if ($obj =~ /$$ex[2]/) && ($ver =~ /$$ex[1]/) && 17575ce41a5SAli Bahrami ($sym =~ /$$ex[0]/); 17675ce41a5SAli Bahrami } 17775ce41a5SAli Bahrami 17875ce41a5SAli Bahrami return 0; 17975ce41a5SAli Bahrami} 18075ce41a5SAli Bahrami 18175ce41a5SAli Bahrami## ExTopVer(ver, obj) 18275ce41a5SAli Bahrami# 18375ce41a5SAli Bahrami# Compare a given version/object combination against the pairs found 18475ce41a5SAli Bahrami# in @EmptyTopVerList. 18575ce41a5SAli Bahrami# 18675ce41a5SAli Bahrami# entry: 18775ce41a5SAli Bahrami# ver, obj - Combination to be compared against empty top version list 18875ce41a5SAli Bahrami# 18975ce41a5SAli Bahrami# exit: 19075ce41a5SAli Bahrami# Returns True (1) if there is a match, and False (0) otherwise. 19175ce41a5SAli Bahrami# 19275ce41a5SAli Bahramisub ExTopVer { 19375ce41a5SAli Bahrami my ($ver, $obj) = @_; 19475ce41a5SAli Bahrami 19575ce41a5SAli Bahrami foreach my $ex (@EmptyTopVerList) { 19675ce41a5SAli Bahrami return 1 if ($obj =~ /$$ex[1]/) && ($ver =~ /$$ex[0]/); 19775ce41a5SAli Bahrami } 19875ce41a5SAli Bahrami 19975ce41a5SAli Bahrami return 0; 20075ce41a5SAli Bahrami} 20175ce41a5SAli Bahrami 20275ce41a5SAli Bahrami## ExpandInheritance(objhashref) 20375ce41a5SAli Bahrami# 20475ce41a5SAli Bahrami# For each version contained in the specified object hash reference, 20575ce41a5SAli Bahrami# add the inherited symbols. 20675ce41a5SAli Bahrami# 20775ce41a5SAli Bahramisub ExpandInheritance { 20875ce41a5SAli Bahrami my $obj = $_[0]; 20975ce41a5SAli Bahrami 21075ce41a5SAli Bahrami # Versions to process. Typically, inheriting versions come before 21175ce41a5SAli Bahrami # the versions they inherit. Processing the list in reverse order 21275ce41a5SAli Bahrami # maximizes the odds that a needed sub-version will have already 21375ce41a5SAli Bahrami # have been processed. 21475ce41a5SAli Bahrami my @vers = reverse(@{$obj->{'VERSION_NAMES'}}); 21575ce41a5SAli Bahrami 21675ce41a5SAli Bahrami # Versions to process in the next pass 21775ce41a5SAli Bahrami my @next_vers = (); 21875ce41a5SAli Bahrami 21975ce41a5SAli Bahrami # Hash, indexed by version name, that reflects whether the version 22075ce41a5SAli Bahrami # has been expanded yet or not. 22175ce41a5SAli Bahrami my %done = (); 22275ce41a5SAli Bahrami 22375ce41a5SAli Bahrami while (scalar(@vers) > 0) { 22475ce41a5SAli Bahrami foreach my $name (@vers) { 22575ce41a5SAli Bahrami my $i; 22675ce41a5SAli Bahrami my $defer = 0; 22775ce41a5SAli Bahrami my $cur_version = $obj->{'VERSION_INFO'}{$name}; 22875ce41a5SAli Bahrami my ($top, $direct, $total, $symhash, $inheritarr) = 22975ce41a5SAli Bahrami @{$cur_version}; 23075ce41a5SAli Bahrami 23175ce41a5SAli Bahrami # In order to expand this version, all the inherited 23275ce41a5SAli Bahrami # versions must already have been done. If not, put 23375ce41a5SAli Bahrami # this version on @next_vers for the next pass. 23475ce41a5SAli Bahrami my $num = scalar(@$inheritarr); 23575ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 23675ce41a5SAli Bahrami if (!$done{$inheritarr->[$i]}) { 23775ce41a5SAli Bahrami $defer = 1; 23875ce41a5SAli Bahrami push @next_vers, $name; 23975ce41a5SAli Bahrami last; 24075ce41a5SAli Bahrami } 24175ce41a5SAli Bahrami } 24275ce41a5SAli Bahrami next if ($defer); 24375ce41a5SAli Bahrami 24475ce41a5SAli Bahrami # Add all the symbols from the inherited versions 24575ce41a5SAli Bahrami # to this one. 24675ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 24775ce41a5SAli Bahrami my $i_version = 24875ce41a5SAli Bahrami $obj->{'VERSION_INFO'}{$inheritarr->[$i]}; 24975ce41a5SAli Bahrami my $i_symhash = $i_version->[3]; 25075ce41a5SAli Bahrami 25175ce41a5SAli Bahrami foreach my $sym (keys %$i_symhash) { 25275ce41a5SAli Bahrami if (!defined($cur_version->[3]{$sym})) { 25375ce41a5SAli Bahrami $cur_version->[2]++; 25475ce41a5SAli Bahrami $cur_version->[3]{$sym} = 'INHERIT'; 25575ce41a5SAli Bahrami } 25675ce41a5SAli Bahrami } 25775ce41a5SAli Bahrami } 25875ce41a5SAli Bahrami 25975ce41a5SAli Bahrami $done{$name} = 1; 26075ce41a5SAli Bahrami } 26175ce41a5SAli Bahrami 26275ce41a5SAli Bahrami @vers = @next_vers; 26375ce41a5SAli Bahrami @next_vers = (); 26475ce41a5SAli Bahrami } 26575ce41a5SAli Bahrami} 26675ce41a5SAli Bahrami 26775ce41a5SAli Bahrami## ReadInterface(file, alias) 26875ce41a5SAli Bahrami# 26975ce41a5SAli Bahrami# Read the interface description file, as produced by interface_check, and 27075ce41a5SAli Bahrami# return a hash describing it. 27175ce41a5SAli Bahrami# 27275ce41a5SAli Bahrami# entry: 27375ce41a5SAli Bahrami# file - Interface file to read. 27475ce41a5SAli Bahrami# alias - Refence to hash to be filled in with any aliases 27575ce41a5SAli Bahrami# that are seen in the file. The alias name is the key, 27675ce41a5SAli Bahrami# and the object is the value. 27775ce41a5SAli Bahrami# 27875ce41a5SAli Bahrami# exit: 27975ce41a5SAli Bahrami# The hash referenced by alias has been updated. 28075ce41a5SAli Bahrami# 28175ce41a5SAli Bahrami# The return value is a hash that encapsulates the interface 28275ce41a5SAli Bahrami# information. This hash returned uses the object names as the 28375ce41a5SAli Bahrami# key. Each key references a sub-hash that contains information 28475ce41a5SAli Bahrami# for that object: 28575ce41a5SAli Bahrami# 28675ce41a5SAli Bahrami# CLASS -> ELFCLASS 28775ce41a5SAli Bahrami# TYPE -> ELF type 28875ce41a5SAli Bahrami# VERSION_NAMES -> Reference to array [1..n] of version names, in the 28975ce41a5SAli Bahrami# order they come from the input file. 29075ce41a5SAli Bahrami# VERSION_INFO -> Reference to hash indexed by version name, yielding 29175ce41a5SAli Bahrami# a reference to an array containing information about 29275ce41a5SAli Bahrami# that version. 29375ce41a5SAli Bahrami# 29475ce41a5SAli Bahrami# The arrays referenced via VERSION_INFO are of the form: 29575ce41a5SAli Bahrami# 29675ce41a5SAli Bahrami# (top, new, total, symhashref, inheritarrref) 29775ce41a5SAli Bahrami# 29875ce41a5SAli Bahrami# where: 29975ce41a5SAli Bahrami# top - 1 if version is a TOP_VERSION, 0 for a regular VERSION 30075ce41a5SAli Bahrami# new - Number of symbols defined explicitly by version 30175ce41a5SAli Bahrami# total - Number of symbols included in version, both new, 30275ce41a5SAli Bahrami# and via inheritance. 30375ce41a5SAli Bahrami# symhashref - Reference to hash indexed by symbol names, and 30475ce41a5SAli Bahrami# yielding true (1). 30575ce41a5SAli Bahrami# inheritarrref - Reference to array of names of versions 30675ce41a5SAli Bahrami# inherited by this one. 30775ce41a5SAli Bahrami# 30875ce41a5SAli Bahramisub ReadInterface { 30975ce41a5SAli Bahrami my ($file, $alias) = @_; 31075ce41a5SAli Bahrami my %main_hash = (); 31175ce41a5SAli Bahrami my $Line; 31275ce41a5SAli Bahrami my $LineNum = 0; 31375ce41a5SAli Bahrami my $obj_name; 31475ce41a5SAli Bahrami my $obj_hash; 31575ce41a5SAli Bahrami my $sym_ok = 0; 31675ce41a5SAli Bahrami my $cur_version; 31775ce41a5SAli Bahrami 31875ce41a5SAli Bahrami open(FILE, $file) || die "$Prog: Unable to open: $file"; 31975ce41a5SAli Bahrami 32075ce41a5SAli Bahrami # Until we see an OBJECT line, nothing else is valid. To 32175ce41a5SAli Bahrami # simplify the error handling, use a simple initial loop to 32275ce41a5SAli Bahrami # read the file up to that point 32375ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) { 32475ce41a5SAli Bahrami if ($Line =~ s/^OBJECT\s+//i) { 32575ce41a5SAli Bahrami $obj_name = $Line; 32675ce41a5SAli Bahrami $main_hash{$obj_name} = {}; 32775ce41a5SAli Bahrami $obj_hash = $main_hash{$obj_name}; 32875ce41a5SAli Bahrami last; 32975ce41a5SAli Bahrami } 33075ce41a5SAli Bahrami die "$file: OBJECT expected on line $LineNum: $Line\n"; 33175ce41a5SAli Bahrami } 33275ce41a5SAli Bahrami 33375ce41a5SAli Bahrami # Read the remainder of the file 33475ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) { 33575ce41a5SAli Bahrami # Items are parsed in order of decreasing frequency 33675ce41a5SAli Bahrami 33775ce41a5SAli Bahrami if ($Line =~ 33875ce41a5SAli Bahrami /^SYMBOL\s+([^\s]+)$/i) { 33975ce41a5SAli Bahrami my $sym = $1; 34075ce41a5SAli Bahrami 34175ce41a5SAli Bahrami die "$file: SYMBOL not expected on line $LineNum: $Line\n" 34275ce41a5SAli Bahrami if !$sym_ok; 34375ce41a5SAli Bahrami 34475ce41a5SAli Bahrami $cur_version->[1]++; 34575ce41a5SAli Bahrami $cur_version->[2]++; 34675ce41a5SAli Bahrami $cur_version->[3]{$sym} = 'NEW'; 34775ce41a5SAli Bahrami next; 34875ce41a5SAli Bahrami } 34975ce41a5SAli Bahrami 35075ce41a5SAli Bahrami if ($Line =~ /^((TOP_)?VERSION)\s+([^\s]+)(\s+\{(.*)\})?\s*$/i) { 35175ce41a5SAli Bahrami my ($top, $name, $inherit) = ($2, $3, $5); 35275ce41a5SAli Bahrami 35375ce41a5SAli Bahrami $top = defined($top) ? 1 : 0; 35475ce41a5SAli Bahrami 35575ce41a5SAli Bahrami my @inheritarr = defined($inherit) ? 35675ce41a5SAli Bahrami split /[,{\s]+/, $inherit : (); 35775ce41a5SAli Bahrami 35875ce41a5SAli Bahrami $cur_version = [ $top, 0, 0, {}, \@inheritarr ]; 35975ce41a5SAli Bahrami $obj_hash->{'VERSION_INFO'}{$name} = $cur_version; 36075ce41a5SAli Bahrami 36175ce41a5SAli Bahrami push @{$obj_hash->{'VERSION_NAMES'}}, $name; 36275ce41a5SAli Bahrami $sym_ok = 1; 36375ce41a5SAli Bahrami next; 36475ce41a5SAli Bahrami } 36575ce41a5SAli Bahrami 36675ce41a5SAli Bahrami if ($Line =~ /^OBJECT\s+([^\s]+)$/i) { 36775ce41a5SAli Bahrami my $prev_obj_hash = $obj_hash; 36875ce41a5SAli Bahrami $obj_name = $1; 36975ce41a5SAli Bahrami $main_hash{$obj_name} = {}; 37075ce41a5SAli Bahrami $obj_hash = $main_hash{$obj_name}; 37175ce41a5SAli Bahrami 37275ce41a5SAli Bahrami # Expand the versions for the object just processed 37375ce41a5SAli Bahrami ExpandInheritance($prev_obj_hash); 37475ce41a5SAli Bahrami next; 37575ce41a5SAli Bahrami } 37675ce41a5SAli Bahrami 37775ce41a5SAli Bahrami if ($Line =~ /^CLASS\s+([^\s]+)$/i) { 37875ce41a5SAli Bahrami $obj_hash->{'CLASS'} = $1; 37975ce41a5SAli Bahrami next; 38075ce41a5SAli Bahrami } 38175ce41a5SAli Bahrami 38275ce41a5SAli Bahrami if ($Line =~ /^TYPE\s+([^\s]+)$/i) { 38375ce41a5SAli Bahrami $obj_hash->{'TYPE'} = $1; 38475ce41a5SAli Bahrami next; 38575ce41a5SAli Bahrami } 38675ce41a5SAli Bahrami 38775ce41a5SAli Bahrami if ($Line =~ /^ALIAS\s+([^\s]+)$/i) { 38875ce41a5SAli Bahrami $$alias{$1} = $obj_name; 38975ce41a5SAli Bahrami next; 39075ce41a5SAli Bahrami } 39175ce41a5SAli Bahrami 39275ce41a5SAli Bahrami die "$file: unrecognized item on line $LineNum: $Line\n"; 39375ce41a5SAli Bahrami } 39475ce41a5SAli Bahrami close FILE; 39575ce41a5SAli Bahrami 39675ce41a5SAli Bahrami # Expand the versions for the final object from the file 39775ce41a5SAli Bahrami ExpandInheritance($obj_hash); 39875ce41a5SAli Bahrami 39975ce41a5SAli Bahrami return %main_hash; 40075ce41a5SAli Bahrami} 40175ce41a5SAli Bahrami 40275ce41a5SAli Bahrami## PrintInterface(main_hash, alias) 40375ce41a5SAli Bahrami# 40475ce41a5SAli Bahrami# Dump the contents of main_hash and alias to stdout in the same format 40575ce41a5SAli Bahrami# used by interface_check to produce the input interface file. This output 40675ce41a5SAli Bahrami# should diff cleanly against the original (ignoring the header comments). 40775ce41a5SAli Bahrami# 40875ce41a5SAli Bahramisub PrintInterface { 40975ce41a5SAli Bahrami my ($main_hash, $alias_hash) = @_; 41075ce41a5SAli Bahrami 41175ce41a5SAli Bahrami foreach my $obj (sort keys %$main_hash) { 41275ce41a5SAli Bahrami print "OBJECT\t$obj\n"; 41375ce41a5SAli Bahrami print "CLASS\t$main_hash->{$obj}{'CLASS'}\n"; 41475ce41a5SAli Bahrami print "TYPE\t$main_hash->{$obj}{'TYPE'}\n"; 41575ce41a5SAli Bahrami 41675ce41a5SAli Bahrami # This is inefficient, but good enough for debugging 41775ce41a5SAli Bahrami # Look at all the aliases and print those that belong 41875ce41a5SAli Bahrami # to this object. 41975ce41a5SAli Bahrami foreach my $alias (sort keys %$alias_hash) { 42075ce41a5SAli Bahrami print "ALIAS\t$alias\n" 42175ce41a5SAli Bahrami if ($obj eq $alias_hash->{$alias}); 42275ce41a5SAli Bahrami } 42375ce41a5SAli Bahrami 42475ce41a5SAli Bahrami next if !defined($main_hash->{$obj}{'VERSION_NAMES'}); 42575ce41a5SAli Bahrami 42675ce41a5SAli Bahrami my $num = scalar(@{$main_hash->{$obj}{'VERSION_NAMES'}}); 42775ce41a5SAli Bahrami my $i; 42875ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 42975ce41a5SAli Bahrami my $name = $main_hash->{$obj}{'VERSION_NAMES'}[$i]; 43075ce41a5SAli Bahrami my ($top, $direct, $total, $symhash, $inheritarr) = 43175ce41a5SAli Bahrami @{$main_hash->{$obj}{'VERSION_INFO'}{$name}}; 43275ce41a5SAli Bahrami 43375ce41a5SAli Bahrami $top = $top ? "TOP_" : ''; 43475ce41a5SAli Bahrami 43575ce41a5SAli Bahrami my $inherit = (scalar(@$inheritarr) > 0) ? 43675ce41a5SAli Bahrami "\t{" . join(', ', @{$inheritarr}) . "}" : ''; 43775ce41a5SAli Bahrami 43875ce41a5SAli Bahrami print "${top}VERSION\t$name$inherit\n"; 43975ce41a5SAli Bahrami 44075ce41a5SAli Bahrami foreach my $sym (sort keys %$symhash) { 44175ce41a5SAli Bahrami print "\t$symhash->{$sym}\t$sym\n"; 44275ce41a5SAli Bahrami } 44375ce41a5SAli Bahrami } 44475ce41a5SAli Bahrami } 44575ce41a5SAli Bahrami} 44675ce41a5SAli Bahrami 44775ce41a5SAli Bahrami## compare() 44875ce41a5SAli Bahrami# 44975ce41a5SAli Bahrami# Compare the old interface definition contained in (%old_hash, %old_alias) 45075ce41a5SAli Bahrami# with the new interface contained in (%new_hash, %new_alias). 45175ce41a5SAli Bahrami# 45275ce41a5SAli Bahramisub compare { 45375ce41a5SAli Bahrami foreach my $old_obj (sort keys %old_hash) { 45475ce41a5SAli Bahrami my $new_obj = $old_obj; 45575ce41a5SAli Bahrami my $Ttl = 0; 45675ce41a5SAli Bahrami 45775ce41a5SAli Bahrami # If the object does not exist in the new interface, 45875ce41a5SAli Bahrami # then see if there's an alias for it. Failing that, 45975ce41a5SAli Bahrami # we simply ignore the object. 46075ce41a5SAli Bahrami if (!defined($new_hash{$new_obj})) { 46175ce41a5SAli Bahrami next if !defined($new_alias{$new_obj}); 46275ce41a5SAli Bahrami $new_obj = $new_alias{$new_obj}; 46375ce41a5SAli Bahrami } 46475ce41a5SAli Bahrami 46575ce41a5SAli Bahrami my $old = $old_hash{$old_obj}; 46675ce41a5SAli Bahrami my $new = $new_hash{$new_obj}; 46775ce41a5SAli Bahrami 46875ce41a5SAli Bahrami # Every version in the old object must exist in the new object, 46975ce41a5SAli Bahrami # and there must be exactly the same symbols in each. 47075ce41a5SAli Bahrami my $num = scalar(@{$old->{'VERSION_NAMES'}}); 47175ce41a5SAli Bahrami for (my $i = 0; $i < $num; $i++) { 47275ce41a5SAli Bahrami my $name = $old->{'VERSION_NAMES'}[$i]; 47375ce41a5SAli Bahrami 47475ce41a5SAli Bahrami # New object must have this version 47575ce41a5SAli Bahrami if (!defined($new->{'VERSION_INFO'}{$name})) { 47675ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, \$Ttl, $old_obj, 47775ce41a5SAli Bahrami $new_obj, "$name: deleted version"); 47875ce41a5SAli Bahrami next; 47975ce41a5SAli Bahrami } 48075ce41a5SAli Bahrami 48175ce41a5SAli Bahrami my ($old_top, $old_direct, $old_total, $old_symhash) = 48275ce41a5SAli Bahrami @{$old->{'VERSION_INFO'}{$name}}; 48375ce41a5SAli Bahrami my ($new_top, $new_direct, $new_total, $new_symhash) = 48475ce41a5SAli Bahrami @{$new->{'VERSION_INFO'}{$name}}; 48575ce41a5SAli Bahrami 48675ce41a5SAli Bahrami # If this is an empty top version, and the old object 48775ce41a5SAli Bahrami # has the EMPTY_TOPVERSION exception set, then we 48875ce41a5SAli Bahrami # skip it as if it were not present. 48975ce41a5SAli Bahrami next if $old_top && ($old_direct == 0) && 49075ce41a5SAli Bahrami ExTopVer($name, $old_obj); 49175ce41a5SAli Bahrami 49275ce41a5SAli Bahrami # We check that every symbol in the old object is 49375ce41a5SAli Bahrami # in the new one to detect deleted symbols. We then 49475ce41a5SAli Bahrami # check that every symbol in the new object is also 49575ce41a5SAli Bahrami # in the old object, to find added symbols. If the 49675ce41a5SAli Bahrami # "deleted" check is clean, and the two objects have 49775ce41a5SAli Bahrami # the same number of symbols in their versions, then we 49875ce41a5SAli Bahrami # can skip the "added" test, because we know that 49975ce41a5SAli Bahrami # there is no room for an addition to have happened. 50075ce41a5SAli Bahrami # Since most objects satisfy these constraints, we 50175ce41a5SAli Bahrami # end up doing roughly half the number of comparisons 50275ce41a5SAli Bahrami # that would otherwise be needed. 50375ce41a5SAli Bahrami my $check_added_syms = 50475ce41a5SAli Bahrami ($old_total == $new_total) ? 0: 1; 50575ce41a5SAli Bahrami 50675ce41a5SAli Bahrami # Every symbol in the old version must be in the new one 50775ce41a5SAli Bahrami foreach my $sym (sort keys %$old_symhash) { 50875ce41a5SAli Bahrami if (!defined($new_symhash->{$sym})) { 50975ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 51075ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 51175ce41a5SAli Bahrami "$name: deleted interface: $sym") 51275ce41a5SAli Bahrami if !ExSym(\@DelSymList, 51375ce41a5SAli Bahrami $sym, $name, $new_obj); 51475ce41a5SAli Bahrami $check_added_syms = 1; 51575ce41a5SAli Bahrami } 51675ce41a5SAli Bahrami } 51775ce41a5SAli Bahrami 51875ce41a5SAli Bahrami # Do the "added" check, unless we can optimize it away. 51975ce41a5SAli Bahrami # Every symbol in the new version must be in the old one. 52075ce41a5SAli Bahrami if ($check_added_syms) { 52175ce41a5SAli Bahrami foreach my $sym (sort keys %$new_symhash) { 52275ce41a5SAli Bahrami if (!defined($old_symhash->{$sym})) { 52375ce41a5SAli Bahrami next if ExSym(\@AddSymList, 52475ce41a5SAli Bahrami $sym, $name, $new_obj); 52575ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 52675ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 52775ce41a5SAli Bahrami "$name: added interface: $sym"); 52875ce41a5SAli Bahrami } 52975ce41a5SAli Bahrami } 53075ce41a5SAli Bahrami } 53175ce41a5SAli Bahrami 53275ce41a5SAli Bahrami # We want to ensure that version numbers in an 53375ce41a5SAli Bahrami # inheritance chain don't go up by more than 1 in 53475ce41a5SAli Bahrami # any given release. If the version names are in the 535*5253169eSAli Bahrami # numbered <PREFIX>x.y[.z] format, we can compare the 53675ce41a5SAli Bahrami # two top versions and see if this has happened. 53775ce41a5SAli Bahrami # 538*5253169eSAli Bahrami # For a given <PREFIX>x.y[.z], valid sucessors would 539*5253169eSAli Bahrami # be <PREFIX>x.(y+1) or <PREFIX>x.y.(z+1), where z is 54075ce41a5SAli Bahrami # assumed to be 0 if not present. 54175ce41a5SAli Bahrami # 54275ce41a5SAli Bahrami # This check only makes sense when the new interface 54375ce41a5SAli Bahrami # is a direct decendent of the old one, as specified 54475ce41a5SAli Bahrami # via the -d option. If the two interfaces are more 54575ce41a5SAli Bahrami # than one release apart, we should not do this test. 546*5253169eSAli Bahrami next if !($opt{d} && $old_top && !$new_top); 547*5253169eSAli Bahrami 548*5253169eSAli Bahrami # Known numbered version? 549*5253169eSAli Bahrami # 550*5253169eSAli Bahrami # Key to @Cat contents: 551*5253169eSAli Bahrami # [0] 'NUMBERED' 552*5253169eSAli Bahrami # [1] number of dot separated numeric fields. 2 or 3. 553*5253169eSAli Bahrami # [2] prefix 554*5253169eSAli Bahrami # [3] major # 555*5253169eSAli Bahrami # [4] minor # 556*5253169eSAli Bahrami # [5] micro # (only if [1] is 3) 557*5253169eSAli Bahrami my @Cat = onbld_elfmod_vertype::Category($name, ''); 558*5253169eSAli Bahrami next if ($Cat[0] ne 'NUMBERED'); 559*5253169eSAli Bahrami 560*5253169eSAli Bahrami my $iname1 = "$Cat[2]$Cat[3]." . ($Cat[4] + 1); 56175ce41a5SAli Bahrami my $iname2; 562*5253169eSAli Bahrami if ($Cat[1] == 3) { 563*5253169eSAli Bahrami $iname2 = "$Cat[2]$Cat[3].$Cat[4]." . ($Cat[5] + 1); 56475ce41a5SAli Bahrami } else { 565*5253169eSAli Bahrami $iname2 = "$Cat[2]$Cat[3].$Cat[4].1"; 56675ce41a5SAli Bahrami } 56775ce41a5SAli Bahrami 56875ce41a5SAli Bahrami if (defined($new->{'VERSION_INFO'}{$iname1}) || 56975ce41a5SAli Bahrami defined($new->{'VERSION_INFO'}{$iname2})) { 57075ce41a5SAli Bahrami my $i_top = 57175ce41a5SAli Bahrami $new->{'VERSION_INFO'}{$iname1}[0] || 57275ce41a5SAli Bahrami $new->{'VERSION_INFO'}{$iname2}[0]; 57375ce41a5SAli Bahrami if (!$i_top) { 57475ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 57575ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 57675ce41a5SAli Bahrami "$name: inconsistant " . 57775ce41a5SAli Bahrami "version increment: " . 57875ce41a5SAli Bahrami "expect $iname1 or $iname2 ". 57975ce41a5SAli Bahrami "to replace top version"); 58075ce41a5SAli Bahrami } 58175ce41a5SAli Bahrami } else { 58275ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 58375ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 58475ce41a5SAli Bahrami "$name: expected superseding " . 58575ce41a5SAli Bahrami "top version to $name not " . 58675ce41a5SAli Bahrami "present: $iname1 or $iname2"); 58775ce41a5SAli Bahrami } 58875ce41a5SAli Bahrami } 58975ce41a5SAli Bahrami 59075ce41a5SAli Bahrami 59175ce41a5SAli Bahrami # Empty versions in the established interface description 59275ce41a5SAli Bahrami # are usually the result of fixing a versioning mistake 59375ce41a5SAli Bahrami # at some point in the past. These versions are part of 59475ce41a5SAli Bahrami # the public record, and cannot be changed now. However, if 59575ce41a5SAli Bahrami # comparing two interface descriptions from the same gate, 59675ce41a5SAli Bahrami # flag any empty versions in the new interface description 59775ce41a5SAli Bahrami # that are not present in the old one. These have yet to 59875ce41a5SAli Bahrami # become part of the official interface, and should be removed 59975ce41a5SAli Bahrami # before they do. 60075ce41a5SAli Bahrami next if !$opt{d}; 60175ce41a5SAli Bahrami 60275ce41a5SAli Bahrami $num = scalar(@{$new->{'VERSION_NAMES'}}); 60375ce41a5SAli Bahrami for (my $i = 0; $i < $num; $i++) { 60475ce41a5SAli Bahrami my $name = $new->{'VERSION_NAMES'}[$i]; 60575ce41a5SAli Bahrami 60675ce41a5SAli Bahrami # If old object has this version, skip it 60775ce41a5SAli Bahrami next if defined($old->{'VERSION_INFO'}{$name}); 60875ce41a5SAli Bahrami 60975ce41a5SAli Bahrami # If explicitly whitelisted, skip it 61075ce41a5SAli Bahrami next if ExTopVer($name, $new_obj); 61175ce41a5SAli Bahrami 61275ce41a5SAli Bahrami my ($new_top, $new_direct, $new_total, $new_symhash) = 61375ce41a5SAli Bahrami @{$new->{'VERSION_INFO'}{$name}}; 61475ce41a5SAli Bahrami 61575ce41a5SAli Bahrami if ($new_direct == 0) { 61675ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 61775ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 61875ce41a5SAli Bahrami "$name: invalid empty new version"); 61975ce41a5SAli Bahrami } 62075ce41a5SAli Bahrami } 62175ce41a5SAli Bahrami } 62275ce41a5SAli Bahrami 62375ce41a5SAli Bahrami} 62475ce41a5SAli Bahrami 62575ce41a5SAli Bahrami 62675ce41a5SAli Bahrami 62775ce41a5SAli Bahrami# ----------------------------------------------------------------------------- 62875ce41a5SAli Bahrami 62975ce41a5SAli Bahrami# Establish a program name for any error diagnostics. 63075ce41a5SAli Bahramichomp($Prog = `basename $0`); 63175ce41a5SAli Bahrami 63275ce41a5SAli Bahrami# Check that we have arguments. Normally, 2 plain arguments are required, 63375ce41a5SAli Bahrami# but if -t is present, only one is allowed. 634*5253169eSAli Bahramiif ((getopts('c:de:ot', \%opt) == 0) || (scalar(@ARGV) != ($opt{t} ? 1 : 2))) { 635*5253169eSAli Bahrami print "usage: $Prog [-dot] [-c vtype_mod] [-e exfile] old new\n"; 636*5253169eSAli Bahrami print "\t[-c vtype_mod]\tsupply alternative version category module\n"; 63775ce41a5SAli Bahrami print "\t[-d]\t\tnew is a direct decendent of old\n"; 63875ce41a5SAli Bahrami print "\t[-e exfile]\texceptions file\n"; 63975ce41a5SAli Bahrami print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n"; 64075ce41a5SAli Bahrami print "\t[-t]\tParse old, and recreate to stdout\n"; 64175ce41a5SAli Bahrami exit 1; 64275ce41a5SAli Bahrami} 64375ce41a5SAli Bahrami 644*5253169eSAli Bahrami# We depend on the onbld_elfmod and onbld_elfmod_vertype perl modules. 645*5253169eSAli Bahrami# Both modules are maintained in the same directory as this script, 646*5253169eSAli Bahrami# and are installed in ../lib/perl. Use the local one if present, 647*5253169eSAli Bahrami# and the installed one otherwise. 648*5253169eSAli Bahrami# 649*5253169eSAli Bahrami# The caller is allowed to supply an alternative implementation for 650*5253169eSAli Bahrami# onbld_elfmod_vertype via the -c option. In this case, the alternative 651*5253169eSAli Bahrami# implementation is expected to provide the same interface as the standard 652*5253169eSAli Bahrami# copy, and is loaded instead. 653*5253169eSAli Bahrami# 654*5253169eSAli Bahramimy $moddir = my $vermoddir = dirname($0); 655*5253169eSAli Bahrami$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm"; 656*5253169eSAli Bahramirequire "$moddir/onbld_elfmod.pm"; 657*5253169eSAli Bahramiif ($opt{c}) { 658*5253169eSAli Bahrami require "$opt{c}"; 659*5253169eSAli Bahrami} else { 660*5253169eSAli Bahrami $vermoddir = "$vermoddir/../lib/perl" 661*5253169eSAli Bahrami if ! -f "$vermoddir/onbld_elfmod_vertype.pm"; 662*5253169eSAli Bahrami require "$vermoddir/onbld_elfmod_vertype.pm"; 663*5253169eSAli Bahrami} 664*5253169eSAli Bahrami 66575ce41a5SAli Bahrami# Locate and process the exceptions file 66675ce41a5SAli BahramiLoadExceptions(); 66775ce41a5SAli Bahrami 66875ce41a5SAli Bahrami%old_alias = (); 66975ce41a5SAli Bahrami%old_hash = ReadInterface($ARGV[0], \%old_alias); 67075ce41a5SAli Bahrami 67175ce41a5SAli Bahrami# If -t is present, only one argument is allowed --- we parse it, and then 67275ce41a5SAli Bahrami# print the same information back to stderr in the same format as the original. 67375ce41a5SAli Bahrami# This is useful for debugging, to verify that the parsing is correct. 67475ce41a5SAli Bahramiif ($opt{t}) { 67575ce41a5SAli Bahrami PrintInterface(\%old_hash, \%old_alias); 67675ce41a5SAli Bahrami exit 0; 67775ce41a5SAli Bahrami} 67875ce41a5SAli Bahrami 67975ce41a5SAli Bahrami%new_alias = (); 68075ce41a5SAli Bahrami%new_hash = ReadInterface($ARGV[1], \%new_alias); 68175ce41a5SAli Bahrami 68275ce41a5SAli Bahramicompare(); 68375ce41a5SAli Bahrami 68475ce41a5SAli Bahramiexit 0; 685