File: | Dpkg/Shlibs/Symbol.pm |
Coverage: | 80.4% |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | # Copyright © 2007 Raphaël Hertzog <hertzog@debian.org> | ||||||
2 | # Copyright © 2009-2010 Modestas Vainius <modax@debian.org> | ||||||
3 | # | ||||||
4 | # This program is free software; you can redistribute it and/or modify | ||||||
5 | # it under the terms of the GNU General Public License as published by | ||||||
6 | # the Free Software Foundation; either version 2 of the License, or | ||||||
7 | # (at your option) any later version. | ||||||
8 | # | ||||||
9 | # This program is distributed in the hope that it will be useful, | ||||||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||
12 | # GNU General Public License for more details. | ||||||
13 | # | ||||||
14 | # You should have received a copy of the GNU General Public License | ||||||
15 | # along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||||
16 | |||||||
17 | =encoding utf8 | ||||||
18 | |||||||
19 - 30 | =head1 NAME Dpkg::Shlibs::Symbol - represent an object file symbol =head1 DESCRIPTION This module provides a class to handle symbols from an executable or shared object file. B<Note>: This is a private module, its API can change at any time. =cut | ||||||
31 | |||||||
32 | package Dpkg::Shlibs::Symbol 0.01; | ||||||
33 | |||||||
34 | 6 6 6 | 22 10 158 | use strict; | ||||
35 | 6 6 6 | 18 12 242 | use warnings; | ||||
36 | |||||||
37 | 6 6 6 | 18 4 72 | use Storable (); | ||||
38 | 6 6 6 | 12 4 306 | use List::Util qw(any); | ||||
39 | |||||||
40 | 6 6 6 | 22 4 218 | use Dpkg::Gettext; | ||||
41 | 6 6 6 | 14 6 298 | use Dpkg::ErrorHandling; | ||||
42 | 6 6 6 | 16 12 236 | use Dpkg::Arch qw(debarch_is_concerned debarch_to_abiattrs); | ||||
43 | 6 6 6 | 18 6 244 | use Dpkg::Version; | ||||
44 | 6 6 6 | 6040 8 272 | use Dpkg::Shlibs::Cppfilt; | ||||
45 | |||||||
46 | # Supported alias types in the order of matching preference | ||||||
47 | 6 | 9292 | use constant ALIAS_TYPES => qw( | ||||
48 | c++ | ||||||
49 | symver | ||||||
50 | 6 6 | 28 6 | ); | ||||
51 | |||||||
52 | sub new { | ||||||
53 | 42813 | 0 | 53998 | my ($this, %args) = @_; | |||
54 | 42813 | 80189 | my $class = ref($this) || $this; | ||||
55 | 42813 | 126582 | my $self = bless { | ||||
56 | symbol => undef, | ||||||
57 | symbol_templ => undef, | ||||||
58 | minver => undef, | ||||||
59 | dep_id => 0, | ||||||
60 | deprecated => 0, | ||||||
61 | tags => {}, | ||||||
62 | tagorder => [], | ||||||
63 | }, $class; | ||||||
64 | 42813 | 70441 | $self->{$_} = $args{$_} foreach keys %args; | ||||
65 | 42813 | 56793 | return $self; | ||||
66 | } | ||||||
67 | |||||||
68 | # Deep clone | ||||||
69 | sub clone { | ||||||
70 | 711 | 0 | 1515 | my ($self, %args) = @_; | |||
71 | 711 | 32704 | my $clone = Storable::dclone($self); | ||||
72 | 711 | 2458 | $clone->{$_} = $args{$_} foreach keys %args; | ||||
73 | 711 | 1247 | return $clone; | ||||
74 | } | ||||||
75 | |||||||
76 | sub parse_tagspec { | ||||||
77 | 15753 | 0 | 13383 | my ($self, $tagspec) = @_; | |||
78 | |||||||
79 | 15753 | 23624 | if ($tagspec =~ /^\s*\((.*?)\)(.*)$/ && $1) { | ||||
80 | # (tag1=t1 value|tag2|...|tagN=tNp) | ||||||
81 | # Symbols ()|= cannot appear in the tag names and values | ||||||
82 | 699 | 858 | $tagspec = $1; | ||||
83 | 699 | 1212 | my $rest = ($2) ? $2 : ''; | ||||
84 | 699 | 1297 | my @tags = split(/\|/, $tagspec); | ||||
85 | |||||||
86 | # Parse each tag | ||||||
87 | 699 | 901 | for my $tag (@tags) { | ||||
88 | 1002 | 1615 | if ($tag =~ /^(.*)=(.*)$/) { | ||||
89 | # Tag with value | ||||||
90 | 522 | 704 | $self->add_tag($1, $2); | ||||
91 | } else { | ||||||
92 | # Tag without value | ||||||
93 | 480 | 753 | $self->add_tag($tag, undef); | ||||
94 | } | ||||||
95 | } | ||||||
96 | 699 | 1366 | return $rest; | ||||
97 | } | ||||||
98 | 15054 | 33250 | return; | ||||
99 | } | ||||||
100 | |||||||
101 | sub parse_symbolspec { | ||||||
102 | 15735 | 0 | 14249 | my ($self, $symbolspec, %opts) = @_; | |||
103 | 15735 | 20883 | my $symbol; | ||||
104 | my $symbol_templ; | ||||||
105 | 15735 | 0 | my $symbol_quoted; | ||||
106 | 15735 | 0 | my $rest; | ||||
107 | |||||||
108 | 15735 | 16269 | if (defined($symbol = $self->parse_tagspec($symbolspec))) { | ||||
109 | # (tag1=t1 value|tag2|...|tagN=tNp)"Foo::Bar::foobar()"@Base 1.0 1 | ||||||
110 | # Symbols ()|= cannot appear in the tag names and values | ||||||
111 | |||||||
112 | # If the tag specification exists symbol name template might be quoted too | ||||||
113 | 681 | 4723 | if ($symbol =~ /^(['"])/ && $symbol =~ /^($1)(.*?)$1(.*)$/) { | ||||
114 | 177 | 317 | $symbol_quoted = $1; | ||||
115 | 177 | 286 | $symbol_templ = $2; | ||||
116 | 177 | 204 | $symbol = $2; | ||||
117 | 177 | 327 | $rest = $3; | ||||
118 | } elsif ($symbol =~ m/^(\S+)(.*)$/) { | ||||||
119 | 504 | 622 | $symbol_templ = $1; | ||||
120 | 504 | 540 | $symbol = $1; | ||||
121 | 504 | 604 | $rest = $2; | ||||
122 | } | ||||||
123 | 681 | 1002 | error(g_('symbol name unspecified: %s'), $symbolspec) if (!$symbol); | ||||
124 | } elsif ($symbolspec =~ m/^(\S+)(.*)$/) { | ||||||
125 | # No tag specification. Symbol name is up to the first space | ||||||
126 | # foobarsymbol@Base 1.0 1 | ||||||
127 | 15054 | 13619 | $symbol = $1; | ||||
128 | 15054 | 13701 | $rest = $2; | ||||
129 | } else { | ||||||
130 | 0 | 0 | return 0; | ||||
131 | } | ||||||
132 | 15735 | 14006 | $self->{symbol} = $symbol; | ||||
133 | 15735 | 11312 | $self->{symbol_templ} = $symbol_templ; | ||||
134 | 15735 | 16020 | $self->{symbol_quoted} = $symbol_quoted if ($symbol_quoted); | ||||
135 | |||||||
136 | # Now parse "the rest" (minver and dep_id) | ||||||
137 | 15735 | 23459 | if ($rest =~ /^\s(\S+)(?:\s(\d+))?/) { | ||||
138 | 15732 | 15947 | $self->{minver} = $1; | ||||
139 | 15732 | 36086 | $self->{dep_id} = $2 // 0; | ||||
140 | } elsif (defined $opts{default_minver}) { | ||||||
141 | 3 | 11 | $self->{minver} = $opts{default_minver}; | ||||
142 | 3 | 7 | $self->{dep_id} = 0; | ||||
143 | } else { | ||||||
144 | 0 | 0 | return 0; | ||||
145 | } | ||||||
146 | 15735 | 17030 | return 1; | ||||
147 | } | ||||||
148 | |||||||
149 | # A hook for symbol initialization (typically processing of tags). The code | ||||||
150 | # here may even change symbol name. Called from | ||||||
151 | # Dpkg::Shlibs::SymbolFile::create_symbol(). | ||||||
152 | sub initialize { | ||||||
153 | 15735 | 0 | 11145 | my $self = shift; | |||
154 | |||||||
155 | # Look for tags marking symbol patterns. The pattern may match multiple | ||||||
156 | # real symbols. | ||||||
157 | 15735 | 10908 | my $type; | ||||
158 | 15735 | 16771 | if ($self->has_tag('c++')) { | ||||
159 | # Raw symbol name is always demangled to the same alias while demangled | ||||||
160 | # symbol name cannot be reliably converted back to raw symbol name. | ||||||
161 | # Therefore, we can use hash for mapping. | ||||||
162 | 213 | 235 | $type = 'alias-c++'; | ||||
163 | } | ||||||
164 | |||||||
165 | # Support old style wildcard syntax. That's basically a symver | ||||||
166 | # with an optional tag. | ||||||
167 | 15735 | 16868 | if ($self->get_symbolname() =~ /^\*@(.*)$/) { | ||||
168 | 9 | 16 | $self->add_tag('symver') unless $self->has_tag('symver'); | ||||
169 | 9 | 15 | $self->add_tag('optional') unless $self->has_tag('optional'); | ||||
170 | 9 | 12 | $self->{symbol} = $1; | ||||
171 | } | ||||||
172 | |||||||
173 | 15735 | 15606 | if ($self->has_tag('symver')) { | ||||
174 | # Each symbol is matched against its version rather than full | ||||||
175 | # name@version string. | ||||||
176 | 81 | 150 | $type = (defined $type) ? 'generic' : 'alias-symver'; | ||||
177 | 81 | 117 | if ($self->get_symbolname() =~ /@/) { | ||||
178 | 0 | 0 | warning(g_('symver tag with versioned symbol will not match: %s'), | ||||
179 | $self->get_symbolspec(1)); | ||||||
180 | } | ||||||
181 | 81 | 97 | if ($self->get_symbolname() eq 'Base') { | ||||
182 | 0 | 0 | error(g_("you can't use symver tag to catch unversioned symbols: %s"), | ||||
183 | $self->get_symbolspec(1)); | ||||||
184 | } | ||||||
185 | } | ||||||
186 | |||||||
187 | # As soon as regex is involved, we need to match each real | ||||||
188 | # symbol against each pattern (aka 'generic' pattern). | ||||||
189 | 15735 | 14803 | if ($self->has_tag('regex')) { | ||||
190 | 75 | 76 | $type = 'generic'; | ||||
191 | # Pre-compile regular expression for better performance. | ||||||
192 | 75 | 85 | my $regex = $self->get_symbolname(); | ||||
193 | 75 | 1722 | $self->{pattern}{regex} = qr/$regex/; | ||||
194 | } | ||||||
195 | 15735 | 19955 | if (defined $type) { | ||||
196 | 258 | 403 | $self->init_pattern($type); | ||||
197 | } | ||||||
198 | } | ||||||
199 | |||||||
200 | sub get_symbolname { | ||||||
201 | 185154 | 0 | 116546 | my $self = shift; | |||
202 | |||||||
203 | 185154 | 248946 | return $self->{symbol}; | ||||
204 | } | ||||||
205 | |||||||
206 | sub get_symboltempl { | ||||||
207 | 814758 | 0 | 461778 | my $self = shift; | |||
208 | |||||||
209 | 814758 | 1306101 | return $self->{symbol_templ} || $self->{symbol}; | ||||
210 | } | ||||||
211 | |||||||
212 | sub set_symbolname { | ||||||
213 | 585 | 0 | 861 | my ($self, $name, $templ, $quoted) = @_; | |||
214 | |||||||
215 | 585 | 2184 | $name //= $self->{symbol}; | ||||
216 | 585 | 2184 | if (!defined $templ && $name =~ /\s/) { | ||||
217 | 0 | 0 | $templ = $name; | ||||
218 | } | ||||||
219 | 585 | 1648 | if (!defined $quoted && defined $templ && $templ =~ /\s/) { | ||||
220 | 0 | 0 | $quoted = '"'; | ||||
221 | } | ||||||
222 | 585 | 700 | $self->{symbol} = $name; | ||||
223 | 585 | 657 | $self->{symbol_templ} = $templ; | ||||
224 | 585 | 730 | if ($quoted) { | ||||
225 | 0 | 0 | $self->{symbol_quoted} = $quoted; | ||||
226 | } else { | ||||||
227 | 585 | 861 | delete $self->{symbol_quoted}; | ||||
228 | } | ||||||
229 | } | ||||||
230 | |||||||
231 | sub has_tags { | ||||||
232 | 486 | 0 | 330 | my $self = shift; | |||
233 | 486 486 | 361 745 | return scalar (@{$self->{tagorder}}); | ||||
234 | } | ||||||
235 | |||||||
236 | sub add_tag { | ||||||
237 | 1020 | 0 | 1936 | my ($self, $tagname, $tagval) = @_; | |||
238 | 1020 | 1467 | if (exists $self->{tags}{$tagname}) { | ||||
239 | 18 | 24 | $self->{tags}{$tagname} = $tagval; | ||||
240 | 18 | 28 | return 0; | ||||
241 | } else { | ||||||
242 | 1002 | 1529 | $self->{tags}{$tagname} = $tagval; | ||||
243 | 1002 1002 | 893 1412 | push @{$self->{tagorder}}, $tagname; | ||||
244 | } | ||||||
245 | 1002 | 1152 | return 1; | ||||
246 | } | ||||||
247 | |||||||
248 | sub delete_tag { | ||||||
249 | 18 | 0 | 38 | my ($self, $tagname) = @_; | |||
250 | 18 | 30 | if (exists $self->{tags}{$tagname}) { | ||||
251 | 6 | 14 | delete $self->{tags}{$tagname}; | ||||
252 | 6 6 6 | 8 12 12 | $self->{tagorder} = [ grep { $_ ne $tagname } @{$self->{tagorder}} ]; | ||||
253 | 6 | 10 | return 1; | ||||
254 | } | ||||||
255 | 12 | 20 | return 0; | ||||
256 | } | ||||||
257 | |||||||
258 | sub has_tag { | ||||||
259 | 75918 | 0 | 55898 | my ($self, $tag) = @_; | |||
260 | 75918 | 130041 | return exists $self->{tags}{$tag}; | ||||
261 | } | ||||||
262 | |||||||
263 | sub get_tag_value { | ||||||
264 | 0 | 0 | 0 | my ($self, $tag) = @_; | |||
265 | 0 | 0 | return $self->{tags}{$tag}; | ||||
266 | } | ||||||
267 | |||||||
268 | # Checks if the symbol is equal to another one (by name and optionally, | ||||||
269 | # tag sets, versioning info (minver and depid)) | ||||||
270 | sub equals { | ||||||
271 | 348 | 0 | 440 | my ($self, $other, %opts) = @_; | |||
272 | 348 | 393 | $opts{versioning} //= 1; | ||||
273 | 348 | 818 | $opts{tags} //= 1; | ||||
274 | |||||||
275 | 348 | 736 | return 0 if $self->{symbol} ne $other->{symbol}; | ||||
276 | |||||||
277 | 144 | 209 | if ($opts{versioning}) { | ||||
278 | 3 | 9 | return 0 if $self->{minver} ne $other->{minver}; | ||||
279 | 3 | 7 | return 0 if $self->{dep_id} ne $other->{dep_id}; | ||||
280 | } | ||||||
281 | |||||||
282 | 144 | 176 | if ($opts{tags}) { | ||||
283 | 144 144 144 | 117 169 186 | return 0 if scalar(@{$self->{tagorder}}) != scalar(@{$other->{tagorder}}); | ||||
284 | |||||||
285 | 144 144 | 134 234 | for my $i (0 .. scalar(@{$self->{tagorder}}) - 1) { | ||||
286 | 297 | 293 | my $tag = $self->{tagorder}->[$i]; | ||||
287 | 297 | 357 | return 0 if $tag ne $other->{tagorder}->[$i]; | ||||
288 | 297 | 1093 | if (defined $self->{tags}{$tag} && defined $other->{tags}{$tag}) { | ||||
289 | 0 | 0 | return 0 if $self->{tags}{$tag} ne $other->{tags}{$tag}; | ||||
290 | } elsif (defined $self->{tags}{$tag} || defined $other->{tags}{$tag}) { | ||||||
291 | 0 | 0 | return 0; | ||||
292 | } | ||||||
293 | } | ||||||
294 | } | ||||||
295 | |||||||
296 | 144 | 333 | return 1; | ||||
297 | } | ||||||
298 | |||||||
299 | |||||||
300 | sub is_optional { | ||||||
301 | 28623 | 0 | 18104 | my $self = shift; | |||
302 | 28623 | 24414 | return $self->has_tag('optional'); | ||||
303 | } | ||||||
304 | |||||||
305 | sub is_arch_specific { | ||||||
306 | 0 | 0 | 0 | my $self = shift; | |||
307 | 0 | 0 | return $self->has_tag('arch'); | ||||
308 | } | ||||||
309 | |||||||
310 | sub arch_is_concerned { | ||||||
311 | 124280 | 0 | 102028 | my ($self, $arch) = @_; | |||
312 | 124280 | 102963 | my $arches = $self->{tags}{arch}; | ||||
313 | |||||||
314 | 124280 | 264083 | return 0 if defined $arch && defined $arches && | ||||
315 | !debarch_is_concerned($arch, split /[\s,]+/, $arches); | ||||||
316 | |||||||
317 | 123974 | 141418 | my ($bits, $endian) = debarch_to_abiattrs($arch); | ||||
318 | return 0 if defined $bits && defined $self->{tags}{'arch-bits'} && | ||||||
319 | 123974 | 276635 | $bits ne $self->{tags}{'arch-bits'}; | ||||
320 | return 0 if defined $endian && defined $self->{tags}{'arch-endian'} && | ||||||
321 | 123848 | 252241 | $endian ne $self->{tags}{'arch-endian'}; | ||||
322 | |||||||
323 | 123734 | 253443 | return 1; | ||||
324 | } | ||||||
325 | |||||||
326 | # Get reference to the pattern the symbol matches (if any) | ||||||
327 | sub get_pattern { | ||||||
328 | 1878 | 0 | 1399 | my $self = shift; | |||
329 | |||||||
330 | 1878 | 5154 | return $self->{matching_pattern}; | ||||
331 | } | ||||||
332 | |||||||
333 | ### NOTE: subroutines below require (or initialize) $self to be a pattern ### | ||||||
334 | |||||||
335 | # Initializes this symbol as a pattern of the specified type. | ||||||
336 | sub init_pattern { | ||||||
337 | 258 | 0 | 296 | my ($self, $type) = @_; | |||
338 | |||||||
339 | 258 | 448 | $self->{pattern}{type} = $type; | ||||
340 | # To be filled with references to symbols matching this pattern. | ||||||
341 | 258 | 433 | $self->{pattern}{matches} = []; | ||||
342 | } | ||||||
343 | |||||||
344 | # Is this symbol a pattern or not? | ||||||
345 | sub is_pattern { | ||||||
346 | 72035 | 0 | 51753 | my $self = shift; | |||
347 | |||||||
348 | 72035 | 90751 | return exists $self->{pattern}; | ||||
349 | } | ||||||
350 | |||||||
351 | # Get pattern type if this symbol is a pattern. | ||||||
352 | sub get_pattern_type { | ||||||
353 | 2280 | 0 | 2195 | my $self = shift; | |||
354 | |||||||
355 | 2280 | 18860 | return $self->{pattern}{type} // ''; | ||||
356 | } | ||||||
357 | |||||||
358 | # Get (sub)type of the alias pattern. Returns empty string if current | ||||||
359 | # pattern is not alias. | ||||||
360 | sub get_alias_type { | ||||||
361 | 2139 | 0 | 2183 | my $self = shift; | |||
362 | |||||||
363 | 2139 | 2795 | return ($self->get_pattern_type() =~ /^alias-(.+)/ && $1) || ''; | ||||
364 | } | ||||||
365 | |||||||
366 | # Get a list of symbols matching this pattern if this symbol is a pattern | ||||||
367 | sub get_pattern_matches { | ||||||
368 | 159 | 0 | 140 | my $self = shift; | |||
369 | |||||||
370 | 159 159 | 124 2536 | return @{$self->{pattern}{matches}}; | ||||
371 | } | ||||||
372 | |||||||
373 | # Create a new symbol based on the pattern (i.e. $self) | ||||||
374 | # and add it to the pattern matches list. | ||||||
375 | sub create_pattern_match { | ||||||
376 | 585 | 0 | 601 | my $self = shift; | |||
377 | 585 | 766 | return unless $self->is_pattern(); | ||||
378 | |||||||
379 | # Leave out 'pattern' subfield while deep-cloning | ||||||
380 | 585 | 702 | my $pattern_stuff = $self->{pattern}; | ||||
381 | 585 | 994 | delete $self->{pattern}; | ||||
382 | 585 | 1255 | my $newsym = $self->clone(@_); | ||||
383 | 585 | 814 | $self->{pattern} = $pattern_stuff; | ||||
384 | |||||||
385 | # Clean up symbol name related internal fields | ||||||
386 | 585 | 1153 | $newsym->set_symbolname(); | ||||
387 | |||||||
388 | # Set newsym pattern reference, add to pattern matches list | ||||||
389 | 585 | 694 | $newsym->{matching_pattern} = $self; | ||||
390 | 585 585 | 537 1150 | push @{$self->{pattern}{matches}}, $newsym; | ||||
391 | 585 | 1000 | return $newsym; | ||||
392 | } | ||||||
393 | |||||||
394 | ### END of pattern subroutines ### | ||||||
395 | |||||||
396 | # Given a raw symbol name the call returns its alias according to the rules of | ||||||
397 | # the current pattern ($self). Returns undef if the supplied raw name is not | ||||||
398 | # transformable to alias. | ||||||
399 | sub convert_to_alias { | ||||||
400 | 2688 | 0 | 3498 | my ($self, $rawname, $type) = @_; | |||
401 | 2688 | 4626 | $type = $self->get_alias_type() unless $type; | ||||
402 | |||||||
403 | 2688 | 3224 | if ($type) { | ||||
404 | 2688 | 7267 | if ($type eq 'symver') { | ||||
405 | # In case of symver, alias is symbol version. Extract it from the | ||||||
406 | # rawname. | ||||||
407 | 1335 | 5999 | return "$1" if ($rawname =~ /\@([^@]+)$/); | ||||
408 | } elsif ($rawname =~ /^_Z/ && $type eq 'c++') { | ||||||
409 | 1353 | 2570 | return cppfilt_demangle_cpp($rawname); | ||||
410 | } | ||||||
411 | } | ||||||
412 | 0 | 0 | return; | ||||
413 | } | ||||||
414 | |||||||
415 | sub get_tagspec { | ||||||
416 | 120 | 0 | 103 | my $self = shift; | |||
417 | 120 | 126 | if ($self->has_tags()) { | ||||
418 | 120 | 109 | my @tags; | ||||
419 | 120 120 | 106 165 | for my $tagname (@{$self->{tagorder}}) { | ||||
420 | 168 | 271 | my $tagval = $self->{tags}{$tagname}; | ||||
421 | 168 | 166 | if (defined $tagval) { | ||||
422 | 84 | 138 | push @tags, $tagname . '=' . $tagval; | ||||
423 | } else { | ||||||
424 | 84 | 120 | push @tags, $tagname; | ||||
425 | } | ||||||
426 | } | ||||||
427 | 120 | 304 | return '(' . join('|', @tags) . ')'; | ||||
428 | } | ||||||
429 | 0 | 0 | return ''; | ||||
430 | } | ||||||
431 | |||||||
432 | sub get_symbolspec { | ||||||
433 | 41700 | 0 | 29603 | my $self = shift; | |||
434 | 41700 | 25611 | my $template_mode = shift; | ||||
435 | 41700 | 26517 | my $spec = ''; | ||||
436 | 41700 | 37851 | $spec .= "#MISSING: $self->{deprecated}#" if $self->{deprecated}; | ||||
437 | 41700 | 31556 | $spec .= ' '; | ||||
438 | 41700 | 32587 | if ($template_mode) { | ||||
439 | 366 | 465 | if ($self->has_tags()) { | ||||
440 | $spec .= sprintf('%s%3$s%s%3$s', $self->get_tagspec(), | ||||||
441 | 120 | 179 | $self->get_symboltempl(), $self->{symbol_quoted} // ''); | ||||
442 | } else { | ||||||
443 | 246 | 264 | $spec .= $self->get_symboltempl(); | ||||
444 | } | ||||||
445 | } else { | ||||||
446 | 41334 | 37274 | $spec .= $self->get_symbolname(); | ||||
447 | } | ||||||
448 | 41700 | 39965 | $spec .= " $self->{minver}"; | ||||
449 | 41700 | 36527 | $spec .= " $self->{dep_id}" if $self->{dep_id}; | ||||
450 | 41700 | 47711 | return $spec; | ||||
451 | } | ||||||
452 | |||||||
453 | # Sanitize the symbol when it is confirmed to be found in | ||||||
454 | # the respective library. | ||||||
455 | sub mark_found_in_library { | ||||||
456 | 27086 | 0 | 28585 | my ($self, $minver, $arch) = @_; | |||
457 | |||||||
458 | 27086 | 59608 | if ($self->{deprecated}) { | ||||
459 | # Symbol reappeared somehow | ||||||
460 | 9 | 19 | $self->{deprecated} = 0; | ||||
461 | 9 | 26 | $self->{minver} = $minver if (not $self->is_optional()); | ||||
462 | } elsif (version_compare($minver, $self->{minver}) < 0) { | ||||||
463 | # We assume that the right dependency information is already | ||||||
464 | # there. | ||||||
465 | 0 | 0 | $self->{minver} = $minver; | ||||
466 | } | ||||||
467 | # Never remove arch tags from patterns | ||||||
468 | 27086 | 43229 | if (not $self->is_pattern()) { | ||||
469 | 26501 | 35712 | if (not $self->arch_is_concerned($arch)) { | ||||
470 | # Remove arch tags because they are incorrect. | ||||||
471 | 6 | 34 | $self->delete_tag('arch'); | ||||
472 | 6 | 8 | $self->delete_tag('arch-bits'); | ||||
473 | 6 | 12 | $self->delete_tag('arch-endian'); | ||||
474 | } | ||||||
475 | } | ||||||
476 | } | ||||||
477 | |||||||
478 | # Sanitize the symbol when it is confirmed to be NOT found in | ||||||
479 | # the respective library. | ||||||
480 | # Mark as deprecated those that are no more provided (only if the | ||||||
481 | # minver is later than the version where the symbol was introduced) | ||||||
482 | sub mark_not_found_in_library { | ||||||
483 | 510 | 0 | 693 | my ($self, $minver, $arch) = @_; | |||
484 | |||||||
485 | # Ignore symbols from foreign arch | ||||||
486 | 510 | 821 | return if not $self->arch_is_concerned($arch); | ||||
487 | |||||||
488 | 342 | 911 | if ($self->{deprecated}) { | ||||
489 | # Bump deprecated if the symbol is optional so that it | ||||||
490 | # keeps reappearing in the diff while it's missing | ||||||
491 | 6 | 16 | $self->{deprecated} = $minver if $self->is_optional(); | ||||
492 | } elsif (version_compare($minver, $self->{minver}) > 0) { | ||||||
493 | 336 | 1378 | $self->{deprecated} = $minver; | ||||
494 | } | ||||||
495 | } | ||||||
496 | |||||||
497 | # Checks if the symbol (or pattern) is legitimate as a real symbol for the | ||||||
498 | # specified architecture. | ||||||
499 | sub is_legitimate { | ||||||
500 | 54954 | 0 | 41340 | my ($self, $arch) = @_; | |||
501 | return ! $self->{deprecated} && | ||||||
502 | 54954 | 86956 | $self->arch_is_concerned($arch); | ||||
503 | } | ||||||
504 | |||||||
505 | # Determine whether a supplied raw symbol name matches against current ($self) | ||||||
506 | # symbol or pattern. | ||||||
507 | sub matches_rawname { | ||||||
508 | 801 | 0 | 1065 | my ($self, $rawname) = @_; | |||
509 | 801 | 844 | my $target = $rawname; | ||||
510 | 801 | 767 | my $ok = 1; | ||||
511 | 801 | 722 | my $do_eq_match = 1; | ||||
512 | |||||||
513 | 801 | 1129 | if ($self->is_pattern()) { | ||||
514 | # Process pattern tags in the order they were specified. | ||||||
515 | 801 801 | 658 1309 | for my $tag (@{$self->{tagorder}}) { | ||||
516 | 1719 2637 | 4522 3515 | if (any { $tag eq $_ } ALIAS_TYPES) { | ||||
517 | 1053 | 1395 | $ok = not not ($target = $self->convert_to_alias($target, $tag)); | ||||
518 | } elsif ($tag eq 'regex') { | ||||||
519 | # Symbol name is a regex. Match it against the target | ||||||
520 | 549 | 577 | $do_eq_match = 0; | ||||
521 | 549 | 3064 | $ok = ($target =~ $self->{pattern}{regex}); | ||||
522 | } | ||||||
523 | 1719 | 3625 | last if not $ok; | ||||
524 | } | ||||||
525 | } | ||||||
526 | |||||||
527 | # Equality match by default | ||||||
528 | 801 | 2197 | if ($ok && $do_eq_match) { | ||||
529 | 252 | 591 | $ok = $target eq $self->get_symbolname(); | ||||
530 | } | ||||||
531 | 801 | 2621 | return $ok; | ||||
532 | } | ||||||
533 | |||||||
534 - 540 | =head1 CHANGES =head2 Version 0.xx This is a private module. =cut | ||||||
541 | |||||||
542 | 1; |