Просмотр исходного кода

Dpkg::Shlibs::Symbol/SymbolFile: introduce symver pattern, deprecate wildcards

Wildcards are still recognized. Their functionality is like of
(symver|optional). Also underline notations of all basic pattern names
in the man page.

Signed-off-by: Raphaël Hertzog <hertzog@debian.org>
Modestas Vainius лет назад: 16
Родитель
Сommit
3f593b5be3

+ 32 - 26
man/dpkg-gensymbols.1

@@ -162,6 +162,10 @@ some low level toolchain libraries like libgcc.
 Denotes \fIc++\fR symbol pattern. See \fBUsing symbol patterns\fR subsection
 Denotes \fIc++\fR symbol pattern. See \fBUsing symbol patterns\fR subsection
 below.
 below.
 .TP
 .TP
+.B symver
+Denotes \fIsymver\fR (symbol version) symbol pattern. See \fBUsing symbol
+patterns\fR subsection below.
+.TP
 .B regex
 .B regex
 Denotes \fIregex\fR symbol pattern. See \fBUsing symbol patterns\fR subsection
 Denotes \fIregex\fR symbol pattern. See \fBUsing symbol patterns\fR subsection
 below.
 below.
@@ -222,26 +226,29 @@ for them). However, as these collisions happen on the ABI level, they should
 not degrade quality of the symbol file.
 not degrade quality of the symbol file.
 .RE
 .RE
 .TP
 .TP
-.B wildcards
-Wildcard patterns are denoted by the string of the form \fI*@version\fR in the
-symbol name field, e.g. "*@GLIBC_2.0". Well maintained libraries have
+.B symver
+This pattern is denoted by the \fIsymver\fR tag. Well maintained libraries have
 versioned symbols where each version corresponds to the upstream version where
 versioned symbols where each version corresponds to the upstream version where
-the symbol got added. If that's the case, you can use wildcard patterns to
-match any symbol associated to the specific version. So "*@GLIBC_2.0" would
-match all symbols associated to the version GLIBC_2.0. For example:
+the symbol got added. If that's the case, you can use a \fIsymver\fR pattern to
+match any symbol associated to the specific version. For example:
 .RS
 .RS
 .PP
 .PP
 libc.so.6 libc6 #MINVER#
 libc.so.6 libc6 #MINVER#
- *@GLIBC_2.0 2.0
+ (symver)GLIBC_2.0 2.0
  [...]
  [...]
- *@GLIBC_2.7 2.7
+ (symver)GLIBC_2.7 2.7
  access@GLIBC_2.0 2.2
  access@GLIBC_2.0 2.2
 .PP
 .PP
 All symbols associated with versions GLIBC_2.0 and GLIBC_2.7 will lead to
 All symbols associated with versions GLIBC_2.0 and GLIBC_2.7 will lead to
 minimal version of 2.0 and 2.7 respectively with the exception of the symbol
 minimal version of 2.0 and 2.7 respectively with the exception of the symbol
 access@GLIBC_2.0. The latter will lead to a minimal dependency on libc6 version
 access@GLIBC_2.0. The latter will lead to a minimal dependency on libc6 version
-2.2 despite being in the scope of the wildcard "*@GLIBC_2.0" because specific
-symbols take precedence over patterns.
+2.2 despite being in the scope of the "(symver)GLIBC_2.0" pattern because
+specific symbols take precedence over patterns.
+.P
+Please note that while old style wildcard patterns (denoted by "*@version" in
+the symbol name field) are still supported, they have been deprecated by new
+style syntax "(symver|optional)version". For example, "*@GLIBC_2.0 2.0" should
+be written as "(symver|optional)GLIBC_2.0 2.0" if the same behaviour is needed.
 .RE
 .RE
 .TP
 .TP
 .B regex
 .B regex
@@ -263,34 +270,33 @@ names and matches will inherit \fIoptional\fR tag from the pattern.
 .RE
 .RE
 .P
 .P
 Basic patterns listed above can be combined where it makes sense. In that case,
 Basic patterns listed above can be combined where it makes sense. In that case,
-they are processed in the order in which the tags are specified. Since wildcard
-pattern does not have a specific tag, it is processed last if the symbol
-specification looks like a wildcard. For example, both
+they are processed in the order in which the tags are specified. For example,
+both
 .PP
 .PP
  (c++|regex)"^NSA::ClassA::Private::privmethod\\d\\(int\\)@Base" 1.0
  (c++|regex)"^NSA::ClassA::Private::privmethod\\d\\(int\\)@Base" 1.0
  (regex|c++)N3NSA6ClassA7Private11privmethod\\dEi@Base 1.0
  (regex|c++)N3NSA6ClassA7Private11privmethod\\dEi@Base 1.0
 .P
 .P
 will match symbols "_ZN3NSA6ClassA7Private11privmethod1Ei@Base" and
 will match symbols "_ZN3NSA6ClassA7Private11privmethod1Ei@Base" and
 "_ZN3NSA6ClassA7Private11privmethod2Ei@Base". When matching the first pattern,
 "_ZN3NSA6ClassA7Private11privmethod2Ei@Base". When matching the first pattern,
-the raw symbol is first demangled as c++ symbol, then the demangled name is
+the raw symbol is first demangled as C++ symbol, then the demangled name is
 matched against the regular expression. On the other hand, when matching the
 matched against the regular expression. On the other hand, when matching the
 second pattern, regular expression is matched against the raw symbol name, then
 second pattern, regular expression is matched against the raw symbol name, then
-the symbol is tested if it is c++ one by attempting to demangle it. A failure
+the symbol is tested if it is C++ one by attempting to demangle it. A failure
 of any basic pattern will result in the failure of the whole pattern.
 of any basic pattern will result in the failure of the whole pattern.
 Therefore, for example, "__N3NSA6ClassA7Private11privmethod\\dEi@Base" will not
 Therefore, for example, "__N3NSA6ClassA7Private11privmethod\\dEi@Base" will not
-match either of the patterns because it is not a valid c++ symbol.
+match either of the patterns because it is not a valid C++ symbol.
 .P
 .P
-In general, all patterns are divided into two groups: aliases (basic c++ and
-wildcards) and generic patterns (regex, all combinations of multiple basic
-patterns). Matching of basic alias-based patterns is fast (O(1)) while generic
-patterns are O(N) (N - generic pattern count) for each symbol.  Therefore, it
-is recommended not to overuse generic patterns.
+In general, all patterns are divided into two groups: aliases (basic \fIc++\fR
+and \fIsymver\fR) and generic patterns (\fIregex\fR, all combinations of
+multiple basic patterns). Matching of basic alias-based patterns is fast (O(1))
+while generic patterns are O(N) (N - generic pattern count) for each symbol.
+Therefore, it is recommended not to overuse generic patterns.
 .P
 .P
-When multiple patterns match the same real symbol, aliases (first c++, then
-wildcards) are preferred over generic patterns. Generic patterns are matched in
-the order they are found in the symbol file template until the first success.
-Please note, however, that manual reordering of template file entries is not
-recommended because \fBdpkg-gensymbols\fR generates diffs based on the
+When multiple patterns match the same real symbol, aliases (first \fIc++\fR,
+then \fIsymver\fR) are preferred over generic patterns. Generic patterns are
+matched in the order they are found in the symbol file template until the first
+success.  Please note, however, that manual reordering of template file entries
+is not recommended because \fBdpkg-gensymbols\fR generates diffs based on the
 alphanumerical order of their names.
 alphanumerical order of their names.
 .SS Using includes
 .SS Using includes
 .P
 .P

+ 43 - 33
scripts/Dpkg/Shlibs/Symbol.pm

@@ -25,6 +25,9 @@ use Dpkg::Version;
 use Storable qw();
 use Storable qw();
 use Dpkg::Shlibs::Cppfilt;
 use Dpkg::Shlibs::Cppfilt;
 
 
+# Supported alias types in the order of matching preference
+use constant 'ALIAS_TYPES' => qw(c++ symver);
+
 sub new {
 sub new {
     my $this = shift;
     my $this = shift;
     my $class = ref($this) || $this;
     my $class = ref($this) || $this;
@@ -146,27 +149,44 @@ sub initialize {
 
 
     # Look for tags marking symbol patterns. The pattern may match multiple
     # Look for tags marking symbol patterns. The pattern may match multiple
     # real symbols.
     # real symbols.
+    my $type;
     if ($self->has_tag('c++')) {
     if ($self->has_tag('c++')) {
 	# Raw symbol name is always demangled to the same alias while demangled
 	# Raw symbol name is always demangled to the same alias while demangled
 	# symbol name cannot be reliably converted back to raw symbol name.
 	# symbol name cannot be reliably converted back to raw symbol name.
 	# Therefore, we can use hash for mapping.
 	# Therefore, we can use hash for mapping.
-	$self->init_pattern('alias-c++'); # Alias subtype is c++.
+	$type = 'alias-c++';
+    }
+
+    if ($self->has_tag('symver')) {
+	# Each symbol is matched against its version rather than full
+	# name@version string.
+	$type = (defined $type) ? 'generic' : 'alias-symver';
     }
     }
-    # Wildcard is an alias based pattern. It gets recognized here even if it is
-    # not specially tagged.
-    if (my $ver = $self->get_wildcard_version()) {
-	error(_g("you can't use wildcards on unversioned symbols: %s"), $_) if $ver eq "Base";
-	$self->init_pattern(($self->is_pattern()) ? 'generic' : 'alias-wildcard');
-	$self->{pattern}{wildcard} = 1;
+    # Support old style wildcard syntax as well. That's basically a symver
+    # with implicit optional tag.
+    if ($self->get_symbolname() =~ /^\*@(.*)$/) {
+	error(_g("you can't use wildcards on unversioned symbols: %s"), $_) if $1 eq "Base";
+	# symver pattern needs symbol name to be its version. However, keeping
+	# dumping this as old style wildcard in the output.
+	unless (defined $self->{symbol_templ}) {
+	    $self->{symbol_templ} = $self->get_symbolname();
+	}
+	$type = (defined $type) ? 'generic' : 'alias-symver';
+	$self->{symbol} = $1;
+	$self->{pattern}{old_wildcard} = 1;
     }
     }
+
     # As soon as regex is involved, we need to match each real
     # As soon as regex is involved, we need to match each real
     # symbol against each pattern (aka 'generic' pattern).
     # symbol against each pattern (aka 'generic' pattern).
     if ($self->has_tag('regex')) {
     if ($self->has_tag('regex')) {
-	$self->init_pattern('generic');
+	$type = 'generic';
 	# Pre-compile regular expression for better performance.
 	# Pre-compile regular expression for better performance.
 	my $regex = $self->get_symbolname();
 	my $regex = $self->get_symbolname();
 	$self->{pattern}{regex} = qr/$regex/;
 	$self->{pattern}{regex} = qr/$regex/;
     }
     }
+    if (defined $type) {
+	$self->init_pattern($type);
+    }
 }
 }
 
 
 sub get_symbolname {
 sub get_symbolname {
@@ -190,14 +210,6 @@ sub set_symbolname {
     }
     }
 }
 }
 
 
-sub get_wildcard_version {
-    my $self = shift;
-    if ($self->get_symbolname() =~ /^\*@(.*)$/) {
-	return $1;
-    }
-    return undef;
-}
-
 sub has_tags {
 sub has_tags {
     my $self = shift;
     my $self = shift;
     return scalar (@{$self->{tagorder}});
     return scalar (@{$self->{tagorder}});
@@ -258,7 +270,8 @@ sub equals {
 
 
 sub is_optional {
 sub is_optional {
     my $self = shift;
     my $self = shift;
-    return $self->has_tag("optional");
+    return $self->has_tag("optional") ||
+           (exists $self->{pattern} && exists $self->{pattern}{old_wildcard});
 }
 }
 
 
 sub is_arch_specific {
 sub is_arch_specific {
@@ -349,10 +362,10 @@ sub convert_to_alias {
     $type = $self->get_alias_type() unless $type;
     $type = $self->get_alias_type() unless $type;
 
 
     if ($type) {
     if ($type) {
-	if ($type eq 'wildcard') {
-	    # In case of wildcard, alias is like "*@SYMBOL_VERSION". Extract
-	    # symbol version from the rawname.
-	    return "*\@$1" if ($rawname =~ /\@([^@]+)$/);
+	if ($type eq 'symver') {
+	    # In case of symver, alias is symbol version. Extract it from the
+	    # rawname.
+	    return "$1" if ($rawname =~ /\@([^@]+)$/);
 	} elsif ($rawname =~ /^_Z/ && $type eq "c++") {
 	} elsif ($rawname =~ /^_Z/ && $type eq "c++") {
 	    return cppfilt_demangle($rawname, "auto");
 	    return cppfilt_demangle($rawname, "auto");
 	}
 	}
@@ -383,9 +396,13 @@ sub get_symbolspec {
     my $spec = "";
     my $spec = "";
     $spec .= "#MISSING: $self->{deprecated}#" if $self->{deprecated};
     $spec .= "#MISSING: $self->{deprecated}#" if $self->{deprecated};
     $spec .= " ";
     $spec .= " ";
-    if ($template_mode && $self->has_tags()) {
-	$spec .= sprintf('%s%3$s%s%3$s', $self->get_tagspec(),
-	    $self->get_symboltempl(), $self->{symbol_quoted} || "");
+    if ($template_mode) {
+	if ($self->has_tags()) {
+	    $spec .= sprintf('%s%3$s%s%3$s', $self->get_tagspec(),
+		$self->get_symboltempl(), $self->{symbol_quoted} || "");
+	} else {
+	    $spec .= $self->get_symboltempl();
+	}
     } else {
     } else {
 	$spec .= $self->get_symbolname();
 	$spec .= $self->get_symbolname();
     }
     }
@@ -458,9 +475,8 @@ sub matches_rawname {
     if ($self->is_pattern()) {
     if ($self->is_pattern()) {
 	# Process pattern tags in the order they were specified.
 	# Process pattern tags in the order they were specified.
 	for my $tag (@{$self->{tagorder}}) {
 	for my $tag (@{$self->{tagorder}}) {
-	    if ($tag eq "c++") {
-		# Demangle it.
-		$ok = not not ($target = $self->convert_to_alias($target, "c++"));
+	    if (grep { $tag eq $_ } ALIAS_TYPES) {
+		$ok = not not ($target = $self->convert_to_alias($target, $tag));
 	    } elsif ($tag eq "regex") {
 	    } elsif ($tag eq "regex") {
 		# Symbol name is a regex. Match it against the target
 		# Symbol name is a regex. Match it against the target
 		$do_eq_match = 0;
 		$do_eq_match = 0;
@@ -468,12 +484,6 @@ sub matches_rawname {
 	    }
 	    }
 	    last if not $ok;
 	    last if not $ok;
 	}
 	}
-	if ($ok) {
-	    # Wildcards are checked last
-	    if ($self->{pattern}{wildcard}) {
-		$target = $self->convert_to_alias($target, "wildcard");
-	    }
-	}
     }
     }
 
 
     # Equality match by default
     # Equality match by default

+ 1 - 5
scripts/Dpkg/Shlibs/SymbolFile.pm

@@ -25,10 +25,6 @@ use Dpkg::Control::Fields;
 use Dpkg::Shlibs::Symbol;
 use Dpkg::Shlibs::Symbol;
 use Dpkg::Arch qw(get_host_arch);
 use Dpkg::Arch qw(get_host_arch);
 
 
-# Supported alias types in the order of matching preference
-# See: find_matching_pattern().
-use constant 'ALIAS_TYPES' => qw(c++ wildcard);
-
 my %blacklist = (
 my %blacklist = (
     '__bss_end__' => 1,		# arm
     '__bss_end__' => 1,		# arm
     '__bss_end' => 1,		# arm
     '__bss_end' => 1,		# arm
@@ -318,7 +314,7 @@ sub find_matching_pattern {
 	next unless defined $obj;
 	next unless defined $obj;
 
 
 	my $all_aliases = $obj->{patterns}{aliases};
 	my $all_aliases = $obj->{patterns}{aliases};
-	for my $type (ALIAS_TYPES) {
+	for my $type (Dpkg::Shlibs::Symbol::ALIAS_TYPES) {
 	    if (exists $all_aliases->{$type}) {
 	    if (exists $all_aliases->{$type}) {
 		my $aliases = $all_aliases->{$type};
 		my $aliases = $all_aliases->{$type};
 		if (my $alias = $aliases->{converter}->convert_to_alias($name)) {
 		if (my $alias = $aliases->{converter}->convert_to_alias($name)) {

+ 36 - 10
scripts/t/200_Dpkg_Shlibs.t

@@ -13,7 +13,7 @@
 # You should have received a copy of the GNU General Public License
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
-use Test::More tests => 97;
+use Test::More tests => 104;
 use Cwd;
 use Cwd;
 use IO::String;
 use IO::String;
 
 
@@ -440,20 +440,46 @@ is_deeply( \@tmp, [], "no LOST symbols if all patterns matched." );
 @tmp = map { $_->get_symbolname() } $sym_file->get_new_symbols($sym_file_dup);
 @tmp = map { $_->get_symbolname() } $sym_file->get_new_symbols($sym_file_dup);
 is_deeply( \@tmp, [], "no NEW symbols if all patterns matched." );
 is_deeply( \@tmp, [], "no NEW symbols if all patterns matched." );
 
 
-# Pattern resolution order: aliases (c++, wildcard), generic
-$sym = $sym_file->lookup_symbol('VERSION_1@VERSION_1',['libpatterns.so.1']);
-is ( $sym->{minver}, '1', "specific VERSION_1 symbol" );
+# Pattern resolution order: aliases (c++, symver), generic
+$sym = $sym_file->lookup_symbol('SYMVER_1@SYMVER_1',['libpatterns.so.1']);
+is ( $sym->{minver}, '1', "specific SYMVER_1 symbol" );
 
 
-$sym = $sym_file->lookup_symbol('_ZN3NSB8Wildcard16wildcard_method1Ev@VERSION_1', ['libpatterns.so.1']);
+$sym = $sym_file->lookup_symbol('_ZN3NSB6Symver14symver_method1Ev@SYMVER_1', ['libpatterns.so.1']);
 is ( $sym->{minver}, '1.method1', "specific symbol prefered over pattern" );
 is ( $sym->{minver}, '1.method1', "specific symbol prefered over pattern" );
 
 
-$sym = $sym_file->lookup_symbol('_ZN3NSB8Wildcard16wildcard_method2Ev@VERSION_1', ['libpatterns.so.1']);
+$sym = $sym_file->lookup_symbol('_ZN3NSB6Symver14symver_method2Ev@SYMVER_1', ['libpatterns.so.1']);
 is ( $sym->{minver}, '1.method2', "c++ alias pattern preferred over generic pattern" );
 is ( $sym->{minver}, '1.method2', "c++ alias pattern preferred over generic pattern" );
-is ( $sym->get_pattern()->get_symbolname(), 'NSB::Wildcard::wildcard_method2()@VERSION_1' );
+is ( $sym->get_pattern()->get_symbolname(), 'NSB::Symver::symver_method2()@SYMVER_1' );
 
 
-$sym = $sym_file->lookup_symbol('_ZN3NSB8WildcardD1Ev@VERSION_1', ['libpatterns.so.1']);
-is ( $sym->{minver}, '1.generic', 'generic (wildcard & c++) pattern covers the rest (destructor)' );
-is ( $sym->get_pattern()->get_symbolname(), '*@VERSION_1' );
+$sym = $sym_file->lookup_symbol('_ZN3NSB6SymverD1Ev@SYMVER_1', ['libpatterns.so.1']);
+is ( $sym->{minver}, '1.generic', 'generic (c++ & symver) pattern covers the rest (destructor)' );
+ok ( $sym->get_pattern()->equals($sym_file->create_symbol('(c++|symver)SYMVER_1 1.generic')) );
+
+# Test old style wildcard support
+load_patterns_symbols();
+$pat = $sym_file->lookup_pattern($sym_file->create_symbol('*@SYMVEROPT_2 2'), ['libpatterns.so.1']);
+ok ( $pat->is_optional(), "Old style wildcard is optional");
+is ( $pat->get_alias_type(), "symver", "old style wildcard is a symver pattern" );
+
+# Get rid of all SymverOptional symbols
+foreach my $tmp (keys %{$obj->{dynsyms}}) {
+    delete $obj->{dynsyms}{$tmp} if ($tmp =~ /SymverOptional/);
+}
+$sym_file->merge_symbols($obj, '100.MISSING');
+is_deeply ( [ map { $_->get_symbolname() } $pat->get_pattern_matches() ],
+    [], "old style wildcard matches nothing.");
+is ( $pat->{deprecated}, '100.MISSING', "old style wildcard gets deprecated." );
+@tmp = map { $_->get_symbolname() } $sym_file->get_lost_symbols($sym_file_dup);
+is_deeply( \@tmp, [], "but old style wildcard is not LOST." );
+
+# 'Internal' pattern covers all internal symbols
+load_patterns_obj();
+@tmp = grep { $_->get_symbolname() =~ /Internal/ } values %{$sym_file->{objects}{'libpatterns.so.1'}{syms}};
+$sym = $sym_file->create_symbol('(regex|c++)^_Z(T[ISV])?N3NSA6ClassA8Internal.*@Base$ 1.internal'),
+$pat = $sym_file->lookup_pattern($sym, ['libpatterns.so.1']);
+is_deeply ([ sort $pat->get_pattern_matches() ], [ sort @tmp ],
+    "Pattern covers all internal symbols");
+is ( $tmp[0]->{minver}, '1.internal' );
 
 
 # Lookup private pattern
 # Lookup private pattern
 my @private_symnames = sort qw(
 my @private_symnames = sort qw(

+ 18 - 9
scripts/t/200_Dpkg_Shlibs/patterns.cpp

@@ -82,17 +82,26 @@ namespace NSB
     EXPORT(ClassD::~ClassD());
     EXPORT(ClassD::~ClassD());
     EXPORT(void ClassD::generate_vt(const char*) const);
     EXPORT(void ClassD::generate_vt(const char*) const);
 
 
-    class Wildcard {
+    class Symver {
 	public:
 	public:
-	    Wildcard();
-	    ~Wildcard();
+	    Symver();
+	    ~Symver();
 
 
-	    void wildcard_method1();
-	    void wildcard_method2();
+	    void symver_method1();
+	    void symver_method2();
     };
     };
 
 
-    EXPORT(Wildcard::Wildcard());
-    EXPORT(Wildcard::~Wildcard());
-    EXPORT(void Wildcard::wildcard_method1());
-    EXPORT(void Wildcard::wildcard_method2());
+    EXPORT(Symver::Symver());
+    EXPORT(Symver::~Symver());
+    EXPORT(void Symver::symver_method1());
+    EXPORT(void Symver::symver_method2());
+
+    class SymverOptional {
+	public:
+	    SymverOptional();
+	    ~SymverOptional();
+    };
+
+    EXPORT(SymverOptional::SymverOptional());
+    EXPORT(SymverOptional::~SymverOptional());
 };
 };

+ 7 - 2
scripts/t/200_Dpkg_Shlibs/patterns.map

@@ -1,4 +1,9 @@
-VERSION_1 {
+SYMVER_1 {
 	global:
 	global:
-		_ZN3NSB8Wildcard*;
+		_ZN3NSB6Symver*;
+};
+
+SYMVEROPT_2 {
+	global:
+		_ZN3NSB14SymverOptional*;
 };
 };

+ 6 - 4
scripts/t/200_Dpkg_Shlibs/patterns.symbols

@@ -1,8 +1,10 @@
 libpatterns.so.1 libpatterns1 #MINVER#
 libpatterns.so.1 libpatterns1 #MINVER#
- (c++)*@VERSION_1 1.generic
+ *@SYMVEROPT_2 2
  (c++|regex|optional)NSA::ClassA::Private(::.*)?@Base 1.private
  (c++|regex|optional)NSA::ClassA::Private(::.*)?@Base 1.private
- (c++)NSB::Wildcard::wildcard_method2()@VERSION_1 1.method2
- VERSION_1@VERSION_1 1
+ (c++)NSB::Symver::symver_method2()@SYMVER_1 1.method2
+ SYMVEROPT_2@SYMVEROPT_2 2
+ (c++|symver)SYMVER_1 1.generic
+ SYMVER_1@SYMVER_1 1
  (regex|c++)^_Z(T[ISV])?N3NSA6ClassA8Internal.*@Base$ 1.internal
  (regex|c++)^_Z(T[ISV])?N3NSA6ClassA8Internal.*@Base$ 1.internal
  _ZN3NSA6ClassAC1Ev@Base 1
  _ZN3NSA6ClassAC1Ev@Base 1
  _ZN3NSA6ClassAC2Ev@Base 1
  _ZN3NSA6ClassAC2Ev@Base 1
@@ -14,7 +16,7 @@ libpatterns.so.1 libpatterns1 #MINVER#
  _ZN3NSB6ClassDD0Ev@Base 1
  _ZN3NSB6ClassDD0Ev@Base 1
  _ZN3NSB6ClassDD1Ev@Base 1
  _ZN3NSB6ClassDD1Ev@Base 1
  _ZN3NSB6ClassDD2Ev@Base 1
  _ZN3NSB6ClassDD2Ev@Base 1
- _ZN3NSB8Wildcard16wildcard_method1Ev@VERSION_1 1.method1
+ _ZN3NSB6Symver14symver_method1Ev@SYMVER_1 1.method1
  _ZN6ClassBC1Ev@Base 1
  _ZN6ClassBC1Ev@Base 1
  _ZN6ClassBC2Ev@Base 1
  _ZN6ClassBC2Ev@Base 1
  _ZN6ClassBD0Ev@Base 1
  _ZN6ClassBD0Ev@Base 1