1*75ce41a5SAli Bahrami#!/usr/bin/perl -w 2*75ce41a5SAli Bahrami# 3*75ce41a5SAli Bahrami# CDDL HEADER START 4*75ce41a5SAli Bahrami# 5*75ce41a5SAli Bahrami# The contents of this file are subject to the terms of the 6*75ce41a5SAli Bahrami# Common Development and Distribution License (the "License"). 7*75ce41a5SAli Bahrami# You may not use this file except in compliance with the License. 8*75ce41a5SAli Bahrami# 9*75ce41a5SAli Bahrami# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*75ce41a5SAli Bahrami# or http://www.opensolaris.org/os/licensing. 11*75ce41a5SAli Bahrami# See the License for the specific language governing permissions 12*75ce41a5SAli Bahrami# and limitations under the License. 13*75ce41a5SAli Bahrami# 14*75ce41a5SAli Bahrami# When distributing Covered Code, include this CDDL HEADER in each 15*75ce41a5SAli Bahrami# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*75ce41a5SAli Bahrami# If applicable, add the following below this CDDL HEADER, with the 17*75ce41a5SAli Bahrami# fields enclosed by brackets "[]" replaced with your own identifying 18*75ce41a5SAli Bahrami# information: Portions Copyright [yyyy] [name of copyright owner] 19*75ce41a5SAli Bahrami# 20*75ce41a5SAli Bahrami# CDDL HEADER END 21*75ce41a5SAli Bahrami# 22*75ce41a5SAli Bahrami 23*75ce41a5SAli Bahrami# 24*75ce41a5SAli Bahrami# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25*75ce41a5SAli Bahrami# Use is subject to license terms. 26*75ce41a5SAli Bahrami# 27*75ce41a5SAli Bahrami 28*75ce41a5SAli Bahrami# 29*75ce41a5SAli Bahrami# interface_cmp audits two interface definition files (as created by 30*75ce41a5SAli Bahrami# interface_check) against one another, and confirms that: 31*75ce41a5SAli Bahrami# 32*75ce41a5SAli Bahrami# o All versioned libraries that were present in the previous interface 33*75ce41a5SAli Bahrami# are present in the new interface 34*75ce41a5SAli Bahrami# 35*75ce41a5SAli Bahrami# o for each non-private interface in a library confirm that no symbols 36*75ce41a5SAli Bahrami# have been removed and that no symbols have been added to it between 37*75ce41a5SAli Bahrami# the two revisions 38*75ce41a5SAli Bahrami# 39*75ce41a5SAli Bahrami# Return codes: 40*75ce41a5SAli Bahrami# 41*75ce41a5SAli Bahrami# 0 All interfaces in the new release are identical in old release. 42*75ce41a5SAli Bahrami# 1 Something is different refer to the error messages. 43*75ce41a5SAli Bahrami 44*75ce41a5SAli Bahrami 45*75ce41a5SAli Bahramiuse strict; 46*75ce41a5SAli Bahrami 47*75ce41a5SAli Bahramiuse POSIX qw(getenv); 48*75ce41a5SAli Bahramiuse Getopt::Std; 49*75ce41a5SAli Bahramiuse File::Basename; 50*75ce41a5SAli Bahrami 51*75ce41a5SAli Bahrami#### Define all global variables (required for strict) 52*75ce41a5SAli Bahramiuse vars qw($Prog); 53*75ce41a5SAli Bahramiuse vars qw(%opt); 54*75ce41a5SAli Bahramiuse vars qw(%old_hash %old_alias %new_hash %new_alias); 55*75ce41a5SAli Bahrami 56*75ce41a5SAli Bahrami# Exception Arrays: 57*75ce41a5SAli Bahrami# 58*75ce41a5SAli Bahrami# The ADDSYM and DELSYM exceptions are maintained on the @AddSymList 59*75ce41a5SAli Bahrami# and @DelSymList arrays, respectively. Each array element is a reference 60*75ce41a5SAli Bahrami# to a subarray of triples: 61*75ce41a5SAli Bahrami# (sym_re, ver_re, obj_re) 62*75ce41a5SAli Bahrami# where each item in the tripple is a regular expression, used to 63*75ce41a5SAli Bahrami# match a particular symbol/version/object combination. 64*75ce41a5SAli Bahrami# 65*75ce41a5SAli Bahrami# The EMPTY_TOPVERSION exceptions are maintained on the @EmptyTopVerList 66*75ce41a5SAli Bahrami# array. Each array element is a reference to a subarray of pairs: 67*75ce41a5SAli Bahrami# (ver_re, obj_re) 68*75ce41a5SAli Bahrami# where each item in the pair is a regular expression, used to 69*75ce41a5SAli Bahrami# match a particular version/object combination. 70*75ce41a5SAli Bahrami# 71*75ce41a5SAli Bahramiuse vars qw(@AddSymList @DelSymList @EmptyTopVerList); 72*75ce41a5SAli Bahrami 73*75ce41a5SAli Bahrami 74*75ce41a5SAli Bahrami## LoadExceptions 75*75ce41a5SAli Bahrami# 76*75ce41a5SAli Bahrami# Locate the exceptions file and process its contents. We can't use 77*75ce41a5SAli Bahrami# onbld_elfmod::LoadExceptionsToEXRE() for this, because our exceptions 78*75ce41a5SAli Bahrami# need to support more than a single regular expression. 79*75ce41a5SAli Bahrami# 80*75ce41a5SAli Bahrami# exit: 81*75ce41a5SAli Bahrami# @AddSymList, @DelSymList, and @EmptyTopVerList have been updated 82*75ce41a5SAli Bahrami# 83*75ce41a5SAli Bahrami# note: 84*75ce41a5SAli Bahrami# We expand strings of the form MACH(dir) to match the given 85*75ce41a5SAli Bahrami# directory as well as any 64-bit architecture subdirectory that 86*75ce41a5SAli Bahrami# might be present (i.e. amd64, sparcv9). 87*75ce41a5SAli Bahrami# 88*75ce41a5SAli Bahramisub LoadExceptions { 89*75ce41a5SAli Bahrami my $file; 90*75ce41a5SAli Bahrami my $Line; 91*75ce41a5SAli Bahrami my $LineNum = 0; 92*75ce41a5SAli Bahrami my $err = 0; 93*75ce41a5SAli Bahrami 94*75ce41a5SAli Bahrami # Locate the exception file 95*75ce41a5SAli Bahrami FILE: { 96*75ce41a5SAli Bahrami # If -e is specified, that file must be used 97*75ce41a5SAli Bahrami if ($opt{e}) { 98*75ce41a5SAli Bahrami $file = $opt{e}; 99*75ce41a5SAli Bahrami last FILE; 100*75ce41a5SAli Bahrami } 101*75ce41a5SAli Bahrami 102*75ce41a5SAli Bahrami # If this is an activated workspace, use the exception 103*75ce41a5SAli Bahrami # file found in the exceptions_list directory. 104*75ce41a5SAli Bahrami if (defined($ENV{CODEMGR_WS})) { 105*75ce41a5SAli Bahrami $file = "$ENV{CODEMGR_WS}/exception_lists/interface_cmp"; 106*75ce41a5SAli Bahrami last FILE if (-f $file); 107*75ce41a5SAli Bahrami } 108*75ce41a5SAli Bahrami 109*75ce41a5SAli Bahrami # As a final backstop, the SUNWonbld package provides a 110*75ce41a5SAli Bahrami # copy of the exception file. This can be useful if we 111*75ce41a5SAli Bahrami # are being used with an older workspace. 112*75ce41a5SAli Bahrami # 113*75ce41a5SAli Bahrami # This script is installed in the SUNWonbld bin directory, 114*75ce41a5SAli Bahrami # while the exception file is in etc/exception_lists. Find 115*75ce41a5SAli Bahrami # it relative to the script location given by $0. 116*75ce41a5SAli Bahrami $file = dirname($0) . "/../etc/exception_lists/interface_cmp"; 117*75ce41a5SAli Bahrami last FILE if (-f $file); 118*75ce41a5SAli Bahrami 119*75ce41a5SAli Bahrami # No exception file was found. 120*75ce41a5SAli Bahrami return; 121*75ce41a5SAli Bahrami } 122*75ce41a5SAli Bahrami 123*75ce41a5SAli Bahrami open (EFILE, $file) || 124*75ce41a5SAli Bahrami die "$Prog: unable to open exceptions file: $file"; 125*75ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*EFILE, \$LineNum)) { 126*75ce41a5SAli Bahrami 127*75ce41a5SAli Bahrami # Expand MACH() 128*75ce41a5SAli Bahrami $Line =~ s/MACH\(([^)]+)\)/$1(\/amd64|\/sparcv9)?/g; 129*75ce41a5SAli Bahrami 130*75ce41a5SAli Bahrami if ($Line =~ /^DELSYM\s+/) { 131*75ce41a5SAli Bahrami my ($item, $sym_re, $ver_re, $obj_re) = 132*75ce41a5SAli Bahrami split(/\s+/, $Line, 4); 133*75ce41a5SAli Bahrami push @DelSymList, [ $sym_re, $ver_re, $obj_re ]; 134*75ce41a5SAli Bahrami next; 135*75ce41a5SAli Bahrami } 136*75ce41a5SAli Bahrami 137*75ce41a5SAli Bahrami if ($Line =~ /^ADDSYM\s+/) { 138*75ce41a5SAli Bahrami my ($item, $sym_re, $ver_re, $obj_re) = 139*75ce41a5SAli Bahrami split(/\s+/, $Line, 4); 140*75ce41a5SAli Bahrami push @AddSymList, [ $sym_re, $ver_re, $obj_re ]; 141*75ce41a5SAli Bahrami next; 142*75ce41a5SAli Bahrami } 143*75ce41a5SAli Bahrami 144*75ce41a5SAli Bahrami if ($Line =~ /^EMPTY_TOPVERSION\s+/) { 145*75ce41a5SAli Bahrami my ($item, $ver_re, $obj_re) = split(/\s+/, $Line, 3); 146*75ce41a5SAli Bahrami push @EmptyTopVerList, [ $ver_re, $obj_re ]; 147*75ce41a5SAli Bahrami next; 148*75ce41a5SAli Bahrami } 149*75ce41a5SAli Bahrami 150*75ce41a5SAli Bahrami $err++; 151*75ce41a5SAli Bahrami printf(STDERR "$file: Unrecognized option: ". 152*75ce41a5SAli Bahrami "line $LineNum: $Line\n"); 153*75ce41a5SAli Bahrami } 154*75ce41a5SAli Bahrami close EFILE; 155*75ce41a5SAli Bahrami 156*75ce41a5SAli Bahrami exit 1 if ($err != 0); 157*75ce41a5SAli Bahrami} 158*75ce41a5SAli Bahrami 159*75ce41a5SAli Bahrami## ExSym(SymList, sym, ver, obj) 160*75ce41a5SAli Bahrami# 161*75ce41a5SAli Bahrami# Compare a given symbol/version/object combination against the 162*75ce41a5SAli Bahrami# exceptions found in the given list. 163*75ce41a5SAli Bahrami# 164*75ce41a5SAli Bahrami# entry: 165*75ce41a5SAli Bahrami# SymList - Reference to @AddSymList, or @DelSymList. 166*75ce41a5SAli Bahrami# sym, ver, obj - Combination to be compared against exception list 167*75ce41a5SAli Bahrami# 168*75ce41a5SAli Bahrami# exit: 169*75ce41a5SAli Bahrami# Returns True (1) if there is a match, and False (0) otherwise. 170*75ce41a5SAli Bahrami# 171*75ce41a5SAli Bahramisub ExSym { 172*75ce41a5SAli Bahrami my ($SymList, $sym, $ver, $obj) = @_; 173*75ce41a5SAli Bahrami 174*75ce41a5SAli Bahrami foreach my $ex (@$SymList) { 175*75ce41a5SAli Bahrami return 1 if ($obj =~ /$$ex[2]/) && ($ver =~ /$$ex[1]/) && 176*75ce41a5SAli Bahrami ($sym =~ /$$ex[0]/); 177*75ce41a5SAli Bahrami } 178*75ce41a5SAli Bahrami 179*75ce41a5SAli Bahrami return 0; 180*75ce41a5SAli Bahrami} 181*75ce41a5SAli Bahrami 182*75ce41a5SAli Bahrami## ExTopVer(ver, obj) 183*75ce41a5SAli Bahrami# 184*75ce41a5SAli Bahrami# Compare a given version/object combination against the pairs found 185*75ce41a5SAli Bahrami# in @EmptyTopVerList. 186*75ce41a5SAli Bahrami# 187*75ce41a5SAli Bahrami# entry: 188*75ce41a5SAli Bahrami# ver, obj - Combination to be compared against empty top version list 189*75ce41a5SAli Bahrami# 190*75ce41a5SAli Bahrami# exit: 191*75ce41a5SAli Bahrami# Returns True (1) if there is a match, and False (0) otherwise. 192*75ce41a5SAli Bahrami# 193*75ce41a5SAli Bahramisub ExTopVer { 194*75ce41a5SAli Bahrami my ($ver, $obj) = @_; 195*75ce41a5SAli Bahrami 196*75ce41a5SAli Bahrami foreach my $ex (@EmptyTopVerList) { 197*75ce41a5SAli Bahrami return 1 if ($obj =~ /$$ex[1]/) && ($ver =~ /$$ex[0]/); 198*75ce41a5SAli Bahrami } 199*75ce41a5SAli Bahrami 200*75ce41a5SAli Bahrami return 0; 201*75ce41a5SAli Bahrami} 202*75ce41a5SAli Bahrami 203*75ce41a5SAli Bahrami## ExpandInheritance(objhashref) 204*75ce41a5SAli Bahrami# 205*75ce41a5SAli Bahrami# For each version contained in the specified object hash reference, 206*75ce41a5SAli Bahrami# add the inherited symbols. 207*75ce41a5SAli Bahrami# 208*75ce41a5SAli Bahramisub ExpandInheritance { 209*75ce41a5SAli Bahrami my $obj = $_[0]; 210*75ce41a5SAli Bahrami 211*75ce41a5SAli Bahrami # Versions to process. Typically, inheriting versions come before 212*75ce41a5SAli Bahrami # the versions they inherit. Processing the list in reverse order 213*75ce41a5SAli Bahrami # maximizes the odds that a needed sub-version will have already 214*75ce41a5SAli Bahrami # have been processed. 215*75ce41a5SAli Bahrami my @vers = reverse(@{$obj->{'VERSION_NAMES'}}); 216*75ce41a5SAli Bahrami 217*75ce41a5SAli Bahrami # Versions to process in the next pass 218*75ce41a5SAli Bahrami my @next_vers = (); 219*75ce41a5SAli Bahrami 220*75ce41a5SAli Bahrami # Hash, indexed by version name, that reflects whether the version 221*75ce41a5SAli Bahrami # has been expanded yet or not. 222*75ce41a5SAli Bahrami my %done = (); 223*75ce41a5SAli Bahrami 224*75ce41a5SAli Bahrami while (scalar(@vers) > 0) { 225*75ce41a5SAli Bahrami foreach my $name (@vers) { 226*75ce41a5SAli Bahrami my $i; 227*75ce41a5SAli Bahrami my $defer = 0; 228*75ce41a5SAli Bahrami my $cur_version = $obj->{'VERSION_INFO'}{$name}; 229*75ce41a5SAli Bahrami my ($top, $direct, $total, $symhash, $inheritarr) = 230*75ce41a5SAli Bahrami @{$cur_version}; 231*75ce41a5SAli Bahrami 232*75ce41a5SAli Bahrami # In order to expand this version, all the inherited 233*75ce41a5SAli Bahrami # versions must already have been done. If not, put 234*75ce41a5SAli Bahrami # this version on @next_vers for the next pass. 235*75ce41a5SAli Bahrami my $num = scalar(@$inheritarr); 236*75ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 237*75ce41a5SAli Bahrami if (!$done{$inheritarr->[$i]}) { 238*75ce41a5SAli Bahrami $defer = 1; 239*75ce41a5SAli Bahrami push @next_vers, $name; 240*75ce41a5SAli Bahrami last; 241*75ce41a5SAli Bahrami } 242*75ce41a5SAli Bahrami } 243*75ce41a5SAli Bahrami next if ($defer); 244*75ce41a5SAli Bahrami 245*75ce41a5SAli Bahrami # Add all the symbols from the inherited versions 246*75ce41a5SAli Bahrami # to this one. 247*75ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 248*75ce41a5SAli Bahrami my $i_version = 249*75ce41a5SAli Bahrami $obj->{'VERSION_INFO'}{$inheritarr->[$i]}; 250*75ce41a5SAli Bahrami my $i_symhash = $i_version->[3]; 251*75ce41a5SAli Bahrami 252*75ce41a5SAli Bahrami foreach my $sym (keys %$i_symhash) { 253*75ce41a5SAli Bahrami if (!defined($cur_version->[3]{$sym})) { 254*75ce41a5SAli Bahrami $cur_version->[2]++; 255*75ce41a5SAli Bahrami $cur_version->[3]{$sym} = 'INHERIT'; 256*75ce41a5SAli Bahrami } 257*75ce41a5SAli Bahrami } 258*75ce41a5SAli Bahrami } 259*75ce41a5SAli Bahrami 260*75ce41a5SAli Bahrami $done{$name} = 1; 261*75ce41a5SAli Bahrami } 262*75ce41a5SAli Bahrami 263*75ce41a5SAli Bahrami @vers = @next_vers; 264*75ce41a5SAli Bahrami @next_vers = (); 265*75ce41a5SAli Bahrami } 266*75ce41a5SAli Bahrami} 267*75ce41a5SAli Bahrami 268*75ce41a5SAli Bahrami## ReadInterface(file, alias) 269*75ce41a5SAli Bahrami# 270*75ce41a5SAli Bahrami# Read the interface description file, as produced by interface_check, and 271*75ce41a5SAli Bahrami# return a hash describing it. 272*75ce41a5SAli Bahrami# 273*75ce41a5SAli Bahrami# entry: 274*75ce41a5SAli Bahrami# file - Interface file to read. 275*75ce41a5SAli Bahrami# alias - Refence to hash to be filled in with any aliases 276*75ce41a5SAli Bahrami# that are seen in the file. The alias name is the key, 277*75ce41a5SAli Bahrami# and the object is the value. 278*75ce41a5SAli Bahrami# 279*75ce41a5SAli Bahrami# exit: 280*75ce41a5SAli Bahrami# The hash referenced by alias has been updated. 281*75ce41a5SAli Bahrami# 282*75ce41a5SAli Bahrami# The return value is a hash that encapsulates the interface 283*75ce41a5SAli Bahrami# information. This hash returned uses the object names as the 284*75ce41a5SAli Bahrami# key. Each key references a sub-hash that contains information 285*75ce41a5SAli Bahrami# for that object: 286*75ce41a5SAli Bahrami# 287*75ce41a5SAli Bahrami# CLASS -> ELFCLASS 288*75ce41a5SAli Bahrami# TYPE -> ELF type 289*75ce41a5SAli Bahrami# VERSION_NAMES -> Reference to array [1..n] of version names, in the 290*75ce41a5SAli Bahrami# order they come from the input file. 291*75ce41a5SAli Bahrami# VERSION_INFO -> Reference to hash indexed by version name, yielding 292*75ce41a5SAli Bahrami# a reference to an array containing information about 293*75ce41a5SAli Bahrami# that version. 294*75ce41a5SAli Bahrami# 295*75ce41a5SAli Bahrami# The arrays referenced via VERSION_INFO are of the form: 296*75ce41a5SAli Bahrami# 297*75ce41a5SAli Bahrami# (top, new, total, symhashref, inheritarrref) 298*75ce41a5SAli Bahrami# 299*75ce41a5SAli Bahrami# where: 300*75ce41a5SAli Bahrami# top - 1 if version is a TOP_VERSION, 0 for a regular VERSION 301*75ce41a5SAli Bahrami# new - Number of symbols defined explicitly by version 302*75ce41a5SAli Bahrami# total - Number of symbols included in version, both new, 303*75ce41a5SAli Bahrami# and via inheritance. 304*75ce41a5SAli Bahrami# symhashref - Reference to hash indexed by symbol names, and 305*75ce41a5SAli Bahrami# yielding true (1). 306*75ce41a5SAli Bahrami# inheritarrref - Reference to array of names of versions 307*75ce41a5SAli Bahrami# inherited by this one. 308*75ce41a5SAli Bahrami# 309*75ce41a5SAli Bahramisub ReadInterface { 310*75ce41a5SAli Bahrami my ($file, $alias) = @_; 311*75ce41a5SAli Bahrami my %main_hash = (); 312*75ce41a5SAli Bahrami my $Line; 313*75ce41a5SAli Bahrami my $LineNum = 0; 314*75ce41a5SAli Bahrami my $obj_name; 315*75ce41a5SAli Bahrami my $obj_hash; 316*75ce41a5SAli Bahrami my $sym_ok = 0; 317*75ce41a5SAli Bahrami my $cur_version; 318*75ce41a5SAli Bahrami 319*75ce41a5SAli Bahrami open(FILE, $file) || die "$Prog: Unable to open: $file"; 320*75ce41a5SAli Bahrami 321*75ce41a5SAli Bahrami # Until we see an OBJECT line, nothing else is valid. To 322*75ce41a5SAli Bahrami # simplify the error handling, use a simple initial loop to 323*75ce41a5SAli Bahrami # read the file up to that point 324*75ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) { 325*75ce41a5SAli Bahrami if ($Line =~ s/^OBJECT\s+//i) { 326*75ce41a5SAli Bahrami $obj_name = $Line; 327*75ce41a5SAli Bahrami $main_hash{$obj_name} = {}; 328*75ce41a5SAli Bahrami $obj_hash = $main_hash{$obj_name}; 329*75ce41a5SAli Bahrami last; 330*75ce41a5SAli Bahrami } 331*75ce41a5SAli Bahrami die "$file: OBJECT expected on line $LineNum: $Line\n"; 332*75ce41a5SAli Bahrami } 333*75ce41a5SAli Bahrami 334*75ce41a5SAli Bahrami # Read the remainder of the file 335*75ce41a5SAli Bahrami while ($Line = onbld_elfmod::GetLine(\*FILE, \$LineNum)) { 336*75ce41a5SAli Bahrami # Items are parsed in order of decreasing frequency 337*75ce41a5SAli Bahrami 338*75ce41a5SAli Bahrami if ($Line =~ 339*75ce41a5SAli Bahrami /^SYMBOL\s+([^\s]+)$/i) { 340*75ce41a5SAli Bahrami my $sym = $1; 341*75ce41a5SAli Bahrami 342*75ce41a5SAli Bahrami die "$file: SYMBOL not expected on line $LineNum: $Line\n" 343*75ce41a5SAli Bahrami if !$sym_ok; 344*75ce41a5SAli Bahrami 345*75ce41a5SAli Bahrami $cur_version->[1]++; 346*75ce41a5SAli Bahrami $cur_version->[2]++; 347*75ce41a5SAli Bahrami $cur_version->[3]{$sym} = 'NEW'; 348*75ce41a5SAli Bahrami next; 349*75ce41a5SAli Bahrami } 350*75ce41a5SAli Bahrami 351*75ce41a5SAli Bahrami if ($Line =~ /^((TOP_)?VERSION)\s+([^\s]+)(\s+\{(.*)\})?\s*$/i) { 352*75ce41a5SAli Bahrami my ($top, $name, $inherit) = ($2, $3, $5); 353*75ce41a5SAli Bahrami 354*75ce41a5SAli Bahrami $top = defined($top) ? 1 : 0; 355*75ce41a5SAli Bahrami 356*75ce41a5SAli Bahrami my @inheritarr = defined($inherit) ? 357*75ce41a5SAli Bahrami split /[,{\s]+/, $inherit : (); 358*75ce41a5SAli Bahrami 359*75ce41a5SAli Bahrami $cur_version = [ $top, 0, 0, {}, \@inheritarr ]; 360*75ce41a5SAli Bahrami $obj_hash->{'VERSION_INFO'}{$name} = $cur_version; 361*75ce41a5SAli Bahrami 362*75ce41a5SAli Bahrami push @{$obj_hash->{'VERSION_NAMES'}}, $name; 363*75ce41a5SAli Bahrami $sym_ok = 1; 364*75ce41a5SAli Bahrami next; 365*75ce41a5SAli Bahrami } 366*75ce41a5SAli Bahrami 367*75ce41a5SAli Bahrami if ($Line =~ /^OBJECT\s+([^\s]+)$/i) { 368*75ce41a5SAli Bahrami my $prev_obj_hash = $obj_hash; 369*75ce41a5SAli Bahrami $obj_name = $1; 370*75ce41a5SAli Bahrami $main_hash{$obj_name} = {}; 371*75ce41a5SAli Bahrami $obj_hash = $main_hash{$obj_name}; 372*75ce41a5SAli Bahrami 373*75ce41a5SAli Bahrami # Expand the versions for the object just processed 374*75ce41a5SAli Bahrami ExpandInheritance($prev_obj_hash); 375*75ce41a5SAli Bahrami next; 376*75ce41a5SAli Bahrami } 377*75ce41a5SAli Bahrami 378*75ce41a5SAli Bahrami if ($Line =~ /^CLASS\s+([^\s]+)$/i) { 379*75ce41a5SAli Bahrami $obj_hash->{'CLASS'} = $1; 380*75ce41a5SAli Bahrami next; 381*75ce41a5SAli Bahrami } 382*75ce41a5SAli Bahrami 383*75ce41a5SAli Bahrami if ($Line =~ /^TYPE\s+([^\s]+)$/i) { 384*75ce41a5SAli Bahrami $obj_hash->{'TYPE'} = $1; 385*75ce41a5SAli Bahrami next; 386*75ce41a5SAli Bahrami } 387*75ce41a5SAli Bahrami 388*75ce41a5SAli Bahrami if ($Line =~ /^ALIAS\s+([^\s]+)$/i) { 389*75ce41a5SAli Bahrami $$alias{$1} = $obj_name; 390*75ce41a5SAli Bahrami next; 391*75ce41a5SAli Bahrami } 392*75ce41a5SAli Bahrami 393*75ce41a5SAli Bahrami die "$file: unrecognized item on line $LineNum: $Line\n"; 394*75ce41a5SAli Bahrami } 395*75ce41a5SAli Bahrami close FILE; 396*75ce41a5SAli Bahrami 397*75ce41a5SAli Bahrami # Expand the versions for the final object from the file 398*75ce41a5SAli Bahrami ExpandInheritance($obj_hash); 399*75ce41a5SAli Bahrami 400*75ce41a5SAli Bahrami return %main_hash; 401*75ce41a5SAli Bahrami} 402*75ce41a5SAli Bahrami 403*75ce41a5SAli Bahrami## PrintInterface(main_hash, alias) 404*75ce41a5SAli Bahrami# 405*75ce41a5SAli Bahrami# Dump the contents of main_hash and alias to stdout in the same format 406*75ce41a5SAli Bahrami# used by interface_check to produce the input interface file. This output 407*75ce41a5SAli Bahrami# should diff cleanly against the original (ignoring the header comments). 408*75ce41a5SAli Bahrami# 409*75ce41a5SAli Bahramisub PrintInterface { 410*75ce41a5SAli Bahrami my ($main_hash, $alias_hash) = @_; 411*75ce41a5SAli Bahrami 412*75ce41a5SAli Bahrami foreach my $obj (sort keys %$main_hash) { 413*75ce41a5SAli Bahrami print "OBJECT\t$obj\n"; 414*75ce41a5SAli Bahrami print "CLASS\t$main_hash->{$obj}{'CLASS'}\n"; 415*75ce41a5SAli Bahrami print "TYPE\t$main_hash->{$obj}{'TYPE'}\n"; 416*75ce41a5SAli Bahrami 417*75ce41a5SAli Bahrami # This is inefficient, but good enough for debugging 418*75ce41a5SAli Bahrami # Look at all the aliases and print those that belong 419*75ce41a5SAli Bahrami # to this object. 420*75ce41a5SAli Bahrami foreach my $alias (sort keys %$alias_hash) { 421*75ce41a5SAli Bahrami print "ALIAS\t$alias\n" 422*75ce41a5SAli Bahrami if ($obj eq $alias_hash->{$alias}); 423*75ce41a5SAli Bahrami } 424*75ce41a5SAli Bahrami 425*75ce41a5SAli Bahrami next if !defined($main_hash->{$obj}{'VERSION_NAMES'}); 426*75ce41a5SAli Bahrami 427*75ce41a5SAli Bahrami my $num = scalar(@{$main_hash->{$obj}{'VERSION_NAMES'}}); 428*75ce41a5SAli Bahrami my $i; 429*75ce41a5SAli Bahrami for ($i = 0; $i < $num; $i++) { 430*75ce41a5SAli Bahrami my $name = $main_hash->{$obj}{'VERSION_NAMES'}[$i]; 431*75ce41a5SAli Bahrami my ($top, $direct, $total, $symhash, $inheritarr) = 432*75ce41a5SAli Bahrami @{$main_hash->{$obj}{'VERSION_INFO'}{$name}}; 433*75ce41a5SAli Bahrami 434*75ce41a5SAli Bahrami $top = $top ? "TOP_" : ''; 435*75ce41a5SAli Bahrami 436*75ce41a5SAli Bahrami my $inherit = (scalar(@$inheritarr) > 0) ? 437*75ce41a5SAli Bahrami "\t{" . join(', ', @{$inheritarr}) . "}" : ''; 438*75ce41a5SAli Bahrami 439*75ce41a5SAli Bahrami print "${top}VERSION\t$name$inherit\n"; 440*75ce41a5SAli Bahrami 441*75ce41a5SAli Bahrami foreach my $sym (sort keys %$symhash) { 442*75ce41a5SAli Bahrami print "\t$symhash->{$sym}\t$sym\n"; 443*75ce41a5SAli Bahrami } 444*75ce41a5SAli Bahrami } 445*75ce41a5SAli Bahrami } 446*75ce41a5SAli Bahrami} 447*75ce41a5SAli Bahrami 448*75ce41a5SAli Bahrami## compare() 449*75ce41a5SAli Bahrami# 450*75ce41a5SAli Bahrami# Compare the old interface definition contained in (%old_hash, %old_alias) 451*75ce41a5SAli Bahrami# with the new interface contained in (%new_hash, %new_alias). 452*75ce41a5SAli Bahrami# 453*75ce41a5SAli Bahramisub compare { 454*75ce41a5SAli Bahrami foreach my $old_obj (sort keys %old_hash) { 455*75ce41a5SAli Bahrami my $new_obj = $old_obj; 456*75ce41a5SAli Bahrami my $Ttl = 0; 457*75ce41a5SAli Bahrami 458*75ce41a5SAli Bahrami # If the object does not exist in the new interface, 459*75ce41a5SAli Bahrami # then see if there's an alias for it. Failing that, 460*75ce41a5SAli Bahrami # we simply ignore the object. 461*75ce41a5SAli Bahrami if (!defined($new_hash{$new_obj})) { 462*75ce41a5SAli Bahrami next if !defined($new_alias{$new_obj}); 463*75ce41a5SAli Bahrami $new_obj = $new_alias{$new_obj}; 464*75ce41a5SAli Bahrami } 465*75ce41a5SAli Bahrami 466*75ce41a5SAli Bahrami my $old = $old_hash{$old_obj}; 467*75ce41a5SAli Bahrami my $new = $new_hash{$new_obj}; 468*75ce41a5SAli Bahrami 469*75ce41a5SAli Bahrami # Every version in the old object must exist in the new object, 470*75ce41a5SAli Bahrami # and there must be exactly the same symbols in each. 471*75ce41a5SAli Bahrami my $num = scalar(@{$old->{'VERSION_NAMES'}}); 472*75ce41a5SAli Bahrami for (my $i = 0; $i < $num; $i++) { 473*75ce41a5SAli Bahrami my $name = $old->{'VERSION_NAMES'}[$i]; 474*75ce41a5SAli Bahrami 475*75ce41a5SAli Bahrami # New object must have this version 476*75ce41a5SAli Bahrami if (!defined($new->{'VERSION_INFO'}{$name})) { 477*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, \$Ttl, $old_obj, 478*75ce41a5SAli Bahrami $new_obj, "$name: deleted version"); 479*75ce41a5SAli Bahrami next; 480*75ce41a5SAli Bahrami } 481*75ce41a5SAli Bahrami 482*75ce41a5SAli Bahrami my ($old_top, $old_direct, $old_total, $old_symhash) = 483*75ce41a5SAli Bahrami @{$old->{'VERSION_INFO'}{$name}}; 484*75ce41a5SAli Bahrami my ($new_top, $new_direct, $new_total, $new_symhash) = 485*75ce41a5SAli Bahrami @{$new->{'VERSION_INFO'}{$name}}; 486*75ce41a5SAli Bahrami 487*75ce41a5SAli Bahrami # If this is an empty top version, and the old object 488*75ce41a5SAli Bahrami # has the EMPTY_TOPVERSION exception set, then we 489*75ce41a5SAli Bahrami # skip it as if it were not present. 490*75ce41a5SAli Bahrami next if $old_top && ($old_direct == 0) && 491*75ce41a5SAli Bahrami ExTopVer($name, $old_obj); 492*75ce41a5SAli Bahrami 493*75ce41a5SAli Bahrami # We check that every symbol in the old object is 494*75ce41a5SAli Bahrami # in the new one to detect deleted symbols. We then 495*75ce41a5SAli Bahrami # check that every symbol in the new object is also 496*75ce41a5SAli Bahrami # in the old object, to find added symbols. If the 497*75ce41a5SAli Bahrami # "deleted" check is clean, and the two objects have 498*75ce41a5SAli Bahrami # the same number of symbols in their versions, then we 499*75ce41a5SAli Bahrami # can skip the "added" test, because we know that 500*75ce41a5SAli Bahrami # there is no room for an addition to have happened. 501*75ce41a5SAli Bahrami # Since most objects satisfy these constraints, we 502*75ce41a5SAli Bahrami # end up doing roughly half the number of comparisons 503*75ce41a5SAli Bahrami # that would otherwise be needed. 504*75ce41a5SAli Bahrami my $check_added_syms = 505*75ce41a5SAli Bahrami ($old_total == $new_total) ? 0: 1; 506*75ce41a5SAli Bahrami 507*75ce41a5SAli Bahrami # Every symbol in the old version must be in the new one 508*75ce41a5SAli Bahrami foreach my $sym (sort keys %$old_symhash) { 509*75ce41a5SAli Bahrami if (!defined($new_symhash->{$sym})) { 510*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 511*75ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 512*75ce41a5SAli Bahrami "$name: deleted interface: $sym") 513*75ce41a5SAli Bahrami if !ExSym(\@DelSymList, 514*75ce41a5SAli Bahrami $sym, $name, $new_obj); 515*75ce41a5SAli Bahrami $check_added_syms = 1; 516*75ce41a5SAli Bahrami } 517*75ce41a5SAli Bahrami } 518*75ce41a5SAli Bahrami 519*75ce41a5SAli Bahrami # Do the "added" check, unless we can optimize it away. 520*75ce41a5SAli Bahrami # Every symbol in the new version must be in the old one. 521*75ce41a5SAli Bahrami if ($check_added_syms) { 522*75ce41a5SAli Bahrami foreach my $sym (sort keys %$new_symhash) { 523*75ce41a5SAli Bahrami if (!defined($old_symhash->{$sym})) { 524*75ce41a5SAli Bahrami next if ExSym(\@AddSymList, 525*75ce41a5SAli Bahrami $sym, $name, $new_obj); 526*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 527*75ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 528*75ce41a5SAli Bahrami "$name: added interface: $sym"); 529*75ce41a5SAli Bahrami } 530*75ce41a5SAli Bahrami } 531*75ce41a5SAli Bahrami } 532*75ce41a5SAli Bahrami 533*75ce41a5SAli Bahrami # We want to ensure that version numbers in an 534*75ce41a5SAli Bahrami # inheritance chain don't go up by more than 1 in 535*75ce41a5SAli Bahrami # any given release. If the version names are in the 536*75ce41a5SAli Bahrami # standard SUNW_x.y[.z] format, we can compare the 537*75ce41a5SAli Bahrami # two top versions and see if this has happened. 538*75ce41a5SAli Bahrami # 539*75ce41a5SAli Bahrami # For a given SUNW_x.y[.z], valid sucessors would 540*75ce41a5SAli Bahrami # be SUNW_x.(y+1) or SUNW_x.y.(z+1), where z is 541*75ce41a5SAli Bahrami # assumed to be 0 if not present. 542*75ce41a5SAli Bahrami # 543*75ce41a5SAli Bahrami # This check only makes sense when the new interface 544*75ce41a5SAli Bahrami # is a direct decendent of the old one, as specified 545*75ce41a5SAli Bahrami # via the -d option. If the two interfaces are more 546*75ce41a5SAli Bahrami # than one release apart, we should not do this test. 547*75ce41a5SAli Bahrami if ($opt{d} && $old_top && !$new_top && 548*75ce41a5SAli Bahrami ($name =~ /^SUNW_(\d+)\.(\d+)(\.(\d+))?/)) { 549*75ce41a5SAli Bahrami my $iname1 = "SUNW_$1." . ($2 + 1); 550*75ce41a5SAli Bahrami my $iname2; 551*75ce41a5SAli Bahrami if (defined($4)) { 552*75ce41a5SAli Bahrami $iname2 = "SUNW_$1.$2." . ($4 + 1); 553*75ce41a5SAli Bahrami } else { 554*75ce41a5SAli Bahrami $iname2 = "SUNW_$1.$2.1"; 555*75ce41a5SAli Bahrami } 556*75ce41a5SAli Bahrami 557*75ce41a5SAli Bahrami if (defined($new->{'VERSION_INFO'}{$iname1}) || 558*75ce41a5SAli Bahrami defined($new->{'VERSION_INFO'}{$iname2})) { 559*75ce41a5SAli Bahrami my $i_top = 560*75ce41a5SAli Bahrami $new->{'VERSION_INFO'}{$iname1}[0] || 561*75ce41a5SAli Bahrami $new->{'VERSION_INFO'}{$iname2}[0]; 562*75ce41a5SAli Bahrami if (!$i_top) { 563*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 564*75ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 565*75ce41a5SAli Bahrami "$name: inconsistant " . 566*75ce41a5SAli Bahrami "version increment: " . 567*75ce41a5SAli Bahrami "expect $iname1 or $iname2 ". 568*75ce41a5SAli Bahrami "to replace top version"); 569*75ce41a5SAli Bahrami } 570*75ce41a5SAli Bahrami } else { 571*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 572*75ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 573*75ce41a5SAli Bahrami "$name: expected superseding " . 574*75ce41a5SAli Bahrami "top version to $name not " . 575*75ce41a5SAli Bahrami "present: $iname1 or $iname2"); 576*75ce41a5SAli Bahrami } 577*75ce41a5SAli Bahrami } 578*75ce41a5SAli Bahrami } 579*75ce41a5SAli Bahrami 580*75ce41a5SAli Bahrami 581*75ce41a5SAli Bahrami # Empty versions in the established interface description 582*75ce41a5SAli Bahrami # are usually the result of fixing a versioning mistake 583*75ce41a5SAli Bahrami # at some point in the past. These versions are part of 584*75ce41a5SAli Bahrami # the public record, and cannot be changed now. However, if 585*75ce41a5SAli Bahrami # comparing two interface descriptions from the same gate, 586*75ce41a5SAli Bahrami # flag any empty versions in the new interface description 587*75ce41a5SAli Bahrami # that are not present in the old one. These have yet to 588*75ce41a5SAli Bahrami # become part of the official interface, and should be removed 589*75ce41a5SAli Bahrami # before they do. 590*75ce41a5SAli Bahrami next if !$opt{d}; 591*75ce41a5SAli Bahrami 592*75ce41a5SAli Bahrami $num = scalar(@{$new->{'VERSION_NAMES'}}); 593*75ce41a5SAli Bahrami for (my $i = 0; $i < $num; $i++) { 594*75ce41a5SAli Bahrami my $name = $new->{'VERSION_NAMES'}[$i]; 595*75ce41a5SAli Bahrami 596*75ce41a5SAli Bahrami # If old object has this version, skip it 597*75ce41a5SAli Bahrami next if defined($old->{'VERSION_INFO'}{$name}); 598*75ce41a5SAli Bahrami 599*75ce41a5SAli Bahrami # If explicitly whitelisted, skip it 600*75ce41a5SAli Bahrami next if ExTopVer($name, $new_obj); 601*75ce41a5SAli Bahrami 602*75ce41a5SAli Bahrami my ($new_top, $new_direct, $new_total, $new_symhash) = 603*75ce41a5SAli Bahrami @{$new->{'VERSION_INFO'}{$name}}; 604*75ce41a5SAli Bahrami 605*75ce41a5SAli Bahrami if ($new_direct == 0) { 606*75ce41a5SAli Bahrami onbld_elfmod::OutMsg2(\*STDOUT, 607*75ce41a5SAli Bahrami \$Ttl, $old_obj, $new_obj, 608*75ce41a5SAli Bahrami "$name: invalid empty new version"); 609*75ce41a5SAli Bahrami } 610*75ce41a5SAli Bahrami } 611*75ce41a5SAli Bahrami } 612*75ce41a5SAli Bahrami 613*75ce41a5SAli Bahrami} 614*75ce41a5SAli Bahrami 615*75ce41a5SAli Bahrami 616*75ce41a5SAli Bahrami 617*75ce41a5SAli Bahrami# ----------------------------------------------------------------------------- 618*75ce41a5SAli Bahrami 619*75ce41a5SAli Bahrami# Establish a program name for any error diagnostics. 620*75ce41a5SAli Bahramichomp($Prog = `basename $0`); 621*75ce41a5SAli Bahrami 622*75ce41a5SAli Bahrami# The onbld_elfmod package is maintained in the same directory as this 623*75ce41a5SAli Bahrami# script, and is installed in ../lib/perl. Use the local one if present, 624*75ce41a5SAli Bahrami# and the installed one otherwise. 625*75ce41a5SAli Bahramimy $moddir = dirname($0); 626*75ce41a5SAli Bahrami$moddir = "$moddir/../lib/perl" if ! -f "$moddir/onbld_elfmod.pm"; 627*75ce41a5SAli Bahramirequire "$moddir/onbld_elfmod.pm"; 628*75ce41a5SAli Bahrami 629*75ce41a5SAli Bahrami# Check that we have arguments. Normally, 2 plain arguments are required, 630*75ce41a5SAli Bahrami# but if -t is present, only one is allowed. 631*75ce41a5SAli Bahramiif ((getopts('de:ot', \%opt) == 0) || (scalar(@ARGV) != ($opt{t} ? 1 : 2))) { 632*75ce41a5SAli Bahrami print "usage: $Prog [-dot] [-e exfile] old new\n"; 633*75ce41a5SAli Bahrami print "\t[-d]\t\tnew is a direct decendent of old\n"; 634*75ce41a5SAli Bahrami print "\t[-e exfile]\texceptions file\n"; 635*75ce41a5SAli Bahrami print "\t[-o]\t\tproduce one-liner output (prefixed with pathname)\n"; 636*75ce41a5SAli Bahrami print "\t[-t]\tParse old, and recreate to stdout\n"; 637*75ce41a5SAli Bahrami exit 1; 638*75ce41a5SAli Bahrami} 639*75ce41a5SAli Bahrami 640*75ce41a5SAli Bahrami# Locate and process the exceptions file 641*75ce41a5SAli BahramiLoadExceptions(); 642*75ce41a5SAli Bahrami 643*75ce41a5SAli Bahrami%old_alias = (); 644*75ce41a5SAli Bahrami%old_hash = ReadInterface($ARGV[0], \%old_alias); 645*75ce41a5SAli Bahrami 646*75ce41a5SAli Bahrami# If -t is present, only one argument is allowed --- we parse it, and then 647*75ce41a5SAli Bahrami# print the same information back to stderr in the same format as the original. 648*75ce41a5SAli Bahrami# This is useful for debugging, to verify that the parsing is correct. 649*75ce41a5SAli Bahramiif ($opt{t}) { 650*75ce41a5SAli Bahrami PrintInterface(\%old_hash, \%old_alias); 651*75ce41a5SAli Bahrami exit 0; 652*75ce41a5SAli Bahrami} 653*75ce41a5SAli Bahrami 654*75ce41a5SAli Bahrami%new_alias = (); 655*75ce41a5SAli Bahrami%new_hash = ReadInterface($ARGV[1], \%new_alias); 656*75ce41a5SAli Bahrami 657*75ce41a5SAli Bahramicompare(); 658*75ce41a5SAli Bahrami 659*75ce41a5SAli Bahramiexit 0; 660