SymbolFile.pm 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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 <http://www.gnu.org/licenses/>.
  16. package Dpkg::Shlibs::SymbolFile;
  17. use strict;
  18. use warnings;
  19. our $VERSION = '0.01';
  20. use Dpkg::Gettext;
  21. use Dpkg::ErrorHandling;
  22. use Dpkg::Version;
  23. use Dpkg::Control::Fields;
  24. use Dpkg::Shlibs::Symbol;
  25. use Dpkg::Arch qw(get_host_arch);
  26. use base qw(Dpkg::Interface::Storable);
  27. my %blacklist = (
  28. __bss_end__ => 1, # arm
  29. __bss_end => 1, # arm
  30. _bss_end__ => 1, # arm
  31. __bss_start => 1, # ALL
  32. __bss_start__ => 1, # arm
  33. __data_start => 1, # arm
  34. __do_global_ctors_aux => 1, # ia64
  35. __do_global_dtors_aux => 1, # ia64
  36. __do_jv_register_classes => 1, # ia64
  37. _DYNAMIC => 1, # ALL
  38. _edata => 1, # ALL
  39. _end => 1, # ALL
  40. __end__ => 1, # arm
  41. __exidx_end => 1, # armel
  42. __exidx_start => 1, # armel
  43. _fbss => 1, # mips, mipsel
  44. _fdata => 1, # mips, mipsel
  45. _fini => 1, # ALL
  46. _ftext => 1, # mips, mipsel
  47. _GLOBAL_OFFSET_TABLE_ => 1, # hppa, mips, mipsel
  48. __gmon_start__ => 1, # hppa
  49. __gnu_local_gp => 1, # mips, mipsel
  50. _gp => 1, # mips, mipsel
  51. _init => 1, # ALL
  52. _PROCEDURE_LINKAGE_TABLE_ => 1, # sparc, alpha
  53. _SDA2_BASE_ => 1, # powerpc
  54. _SDA_BASE_ => 1, # powerpc
  55. );
  56. for my $i (14 .. 31) {
  57. # Many powerpc specific symbols
  58. $blacklist{"_restfpr_$i"} = 1;
  59. $blacklist{"_restfpr_$i\_x"} = 1;
  60. $blacklist{"_restgpr_$i"} = 1;
  61. $blacklist{"_restgpr_$i\_x"} = 1;
  62. $blacklist{"_savefpr_$i"} = 1;
  63. $blacklist{"_savegpr_$i"} = 1;
  64. }
  65. # Many armel-specific symbols
  66. $blacklist{"__aeabi_$_"} = 1 foreach (qw(cdcmpeq cdcmple cdrcmple cfcmpeq
  67. cfcmple cfrcmple d2f d2iz d2lz d2uiz d2ulz dadd dcmpeq dcmpge dcmpgt
  68. dcmple dcmplt dcmpun ddiv dmul dneg drsub dsub f2d f2iz f2lz f2uiz f2ulz
  69. fadd fcmpeq fcmpge fcmpgt fcmple fcmplt fcmpun fdiv fmul fneg frsub fsub
  70. i2d i2f idiv idivmod l2d l2f lasr lcmp ldivmod llsl llsr lmul ui2d ui2f
  71. uidiv uidivmod ul2d ul2f ulcmp uldivmod unwind_cpp_pr0 unwind_cpp_pr1
  72. unwind_cpp_pr2 uread4 uread8 uwrite4 uwrite8));
  73. sub new {
  74. my $this = shift;
  75. my %opts=@_;
  76. my $class = ref($this) || $this;
  77. my $self = \%opts;
  78. bless $self, $class;
  79. $self->{arch} //= get_host_arch();
  80. $self->clear();
  81. if (exists $self->{file}) {
  82. $self->load($self->{file}) if -e $self->{file};
  83. }
  84. return $self;
  85. }
  86. sub get_arch {
  87. my ($self) = @_;
  88. return $self->{arch};
  89. }
  90. sub clear {
  91. my ($self) = @_;
  92. $self->{objects} = {};
  93. }
  94. sub clear_except {
  95. my ($self, @ids) = @_;
  96. my %has;
  97. $has{$_} = 1 foreach (@ids);
  98. foreach my $objid (keys %{$self->{objects}}) {
  99. delete $self->{objects}{$objid} unless exists $has{$objid};
  100. }
  101. }
  102. sub get_sonames {
  103. my ($self) = @_;
  104. return keys %{$self->{objects}};
  105. }
  106. sub get_symbols {
  107. my ($self, $soname) = @_;
  108. if (defined $soname) {
  109. my $obj = $self->get_object($soname);
  110. return (defined $obj) ? values %{$obj->{syms}} : ();
  111. } else {
  112. my @syms;
  113. foreach my $soname ($self->get_sonames()) {
  114. push @syms, $self->get_symbols($soname);
  115. }
  116. return @syms;
  117. }
  118. }
  119. sub get_patterns {
  120. my ($self, $soname) = @_;
  121. my @patterns;
  122. if (defined $soname) {
  123. my $obj = $self->get_object($soname);
  124. foreach my $alias (values %{$obj->{patterns}{aliases}}) {
  125. push @patterns, values %$alias;
  126. }
  127. return (@patterns, @{$obj->{patterns}{generic}});
  128. } else {
  129. foreach my $soname ($self->get_sonames()) {
  130. push @patterns, $self->get_patterns($soname);
  131. }
  132. return @patterns;
  133. }
  134. }
  135. # Create a symbol from the supplied string specification.
  136. sub create_symbol {
  137. my ($self, $spec, %opts) = @_;
  138. my $symbol = (exists $opts{base}) ? $opts{base} :
  139. Dpkg::Shlibs::Symbol->new();
  140. my $ret = $opts{dummy} ? $symbol->parse_symbolspec($spec, default_minver => 0) :
  141. $symbol->parse_symbolspec($spec);
  142. if ($ret) {
  143. $symbol->initialize(arch => $self->get_arch());
  144. return $symbol;
  145. }
  146. return;
  147. }
  148. sub add_symbol {
  149. my ($self, $symbol, $soname) = @_;
  150. my $object = $self->get_object($soname);
  151. if ($symbol->is_pattern()) {
  152. if (my $alias_type = $symbol->get_alias_type()) {
  153. unless (exists $object->{patterns}{aliases}{$alias_type}) {
  154. $object->{patterns}{aliases}{$alias_type} = {};
  155. }
  156. # Alias hash for matching.
  157. my $aliases = $object->{patterns}{aliases}{$alias_type};
  158. $aliases->{$symbol->get_symbolname()} = $symbol;
  159. } else {
  160. # Otherwise assume this is a generic sequential pattern. This
  161. # should be always safe.
  162. push @{$object->{patterns}{generic}}, $symbol;
  163. }
  164. return 'pattern';
  165. } else {
  166. # invalidate the minimum version cache
  167. $object->{minver_cache} = [];
  168. $object->{syms}{$symbol->get_symbolname()} = $symbol;
  169. return 'sym';
  170. }
  171. }
  172. sub _new_symbol {
  173. my $base = shift || 'Dpkg::Shlibs::Symbol';
  174. return (ref $base) ? $base->clone(@_) : $base->new(@_);
  175. }
  176. # Parameter seen is only used for recursive calls
  177. sub parse {
  178. my ($self, $fh, $file, $seen, $obj_ref, $base_symbol) = @_;
  179. if (defined($seen)) {
  180. return if exists $seen->{$file}; # Avoid include loops
  181. } else {
  182. $self->{file} = $file;
  183. $seen = {};
  184. }
  185. $seen->{$file} = 1;
  186. if (not ref($obj_ref)) { # Init ref to name of current object/lib
  187. $$obj_ref = undef;
  188. }
  189. while (defined($_ = <$fh>)) {
  190. chomp($_);
  191. if (/^(?:\s+|#(?:DEPRECATED|MISSING): ([^#]+)#\s*)(.*)/) {
  192. if (not defined ($$obj_ref)) {
  193. error(_g('symbol information must be preceded by a header (file %s, line %s)'), $file, $.);
  194. }
  195. # Symbol specification
  196. my $deprecated = ($1) ? $1 : 0;
  197. my $sym = _new_symbol($base_symbol, deprecated => $deprecated);
  198. if ($self->create_symbol($2, base => $sym)) {
  199. $self->add_symbol($sym, $$obj_ref);
  200. } else {
  201. warning(_g('Failed to parse line in %s: %s'), $file, $_);
  202. }
  203. } elsif (/^(\(.*\))?#include\s+"([^"]+)"/) {
  204. my $tagspec = $1;
  205. my $filename = $2;
  206. my $dir = $file;
  207. my $new_base_symbol;
  208. if (defined $tagspec) {
  209. $new_base_symbol = _new_symbol($base_symbol);
  210. $new_base_symbol->parse_tagspec($tagspec);
  211. }
  212. $dir =~ s{[^/]+$}{}; # Strip filename
  213. $self->load("$dir$filename", $seen, $obj_ref, $new_base_symbol);
  214. } elsif (/^#|^$/) {
  215. # Skip possible comments and empty lines
  216. } elsif (/^\|\s*(.*)$/) {
  217. # Alternative dependency template
  218. push @{$self->{objects}{$$obj_ref}{deps}}, "$1";
  219. } elsif (/^\*\s*([^:]+):\s*(.*\S)\s*$/) {
  220. # Add meta-fields
  221. $self->{objects}{$$obj_ref}{fields}{field_capitalize($1)} = $2;
  222. } elsif (/^(\S+)\s+(.*)$/) {
  223. # New object and dependency template
  224. $$obj_ref = $1;
  225. if (exists $self->{objects}{$$obj_ref}) {
  226. # Update/override infos only
  227. $self->{objects}{$$obj_ref}{deps} = [ "$2" ];
  228. } else {
  229. # Create a new object
  230. $self->create_object($$obj_ref, "$2");
  231. }
  232. } else {
  233. warning(_g('Failed to parse a line in %s: %s'), $file, $_);
  234. }
  235. }
  236. delete $seen->{$file};
  237. }
  238. # Beware: we reuse the data structure of the provided symfile so make
  239. # sure to not modify them after having called this function
  240. sub merge_object_from_symfile {
  241. my ($self, $src, $objid) = @_;
  242. if (not $self->has_object($objid)) {
  243. $self->{objects}{$objid} = $src->get_object($objid);
  244. } else {
  245. warning(_g('tried to merge the same object (%s) twice in a symfile'), $objid);
  246. }
  247. }
  248. sub output {
  249. my ($self, $fh, %opts) = @_;
  250. $opts{template_mode} = 0 unless exists $opts{template_mode};
  251. $opts{with_deprecated} = 1 unless exists $opts{with_deprecated};
  252. $opts{with_pattern_matches} = 0 unless exists $opts{with_pattern_matches};
  253. my $res = '';
  254. foreach my $soname (sort $self->get_sonames()) {
  255. my @deps = $self->get_dependencies($soname);
  256. my $dep = shift @deps;
  257. $dep =~ s/#PACKAGE#/$opts{package}/g if exists $opts{package};
  258. print $fh "$soname $dep\n" if defined $fh;
  259. $res .= "$soname $dep\n" if defined wantarray;
  260. foreach $dep (@deps) {
  261. $dep =~ s/#PACKAGE#/$opts{package}/g if exists $opts{package};
  262. print $fh "| $dep\n" if defined $fh;
  263. $res .= "| $dep\n" if defined wantarray;
  264. }
  265. my $f = $self->{objects}{$soname}{fields};
  266. foreach my $field (sort keys %{$f}) {
  267. my $value = $f->{$field};
  268. $value =~ s/#PACKAGE#/$opts{package}/g if exists $opts{package};
  269. print $fh "* $field: $value\n" if defined $fh;
  270. $res .= "* $field: $value\n" if defined wantarray;
  271. }
  272. my @symbols;
  273. if ($opts{template_mode}) {
  274. # Exclude symbols matching a pattern, but include patterns themselves
  275. @symbols = grep { not $_->get_pattern() } $self->get_symbols($soname);
  276. push @symbols, $self->get_patterns($soname);
  277. } else {
  278. @symbols = $self->get_symbols($soname);
  279. }
  280. foreach my $sym (sort { $a->get_symboltempl() cmp
  281. $b->get_symboltempl() } @symbols) {
  282. next if $sym->{deprecated} and not $opts{with_deprecated};
  283. # Do not dump symbols from foreign arch unless dumping a template.
  284. next if not $opts{template_mode} and
  285. not $sym->arch_is_concerned($self->get_arch());
  286. # Dump symbol specification. Dump symbol tags only in template mode.
  287. print $fh $sym->get_symbolspec($opts{template_mode}), "\n" if defined $fh;
  288. $res .= $sym->get_symbolspec($opts{template_mode}) . "\n" if defined wantarray;
  289. # Dump pattern matches as comments (if requested)
  290. if ($opts{with_pattern_matches} && $sym->is_pattern()) {
  291. for my $match (sort { $a->get_symboltempl() cmp
  292. $b->get_symboltempl() } $sym->get_pattern_matches())
  293. {
  294. print $fh '#MATCH:', $match->get_symbolspec(0), "\n" if defined $fh;
  295. $res .= '#MATCH:' . $match->get_symbolspec(0) . "\n" if defined wantarray;
  296. }
  297. }
  298. }
  299. }
  300. return $res;
  301. }
  302. # Tries to match a symbol name and/or version against the patterns defined.
  303. # Returns a pattern which matches (if any).
  304. sub find_matching_pattern {
  305. my ($self, $refsym, $sonames, $inc_deprecated) = @_;
  306. $inc_deprecated //= 0;
  307. my $name = (ref $refsym) ? $refsym->get_symbolname() : $refsym;
  308. my $pattern_ok = sub {
  309. my $p = shift;
  310. return defined $p && ($inc_deprecated || !$p->{deprecated}) &&
  311. $p->arch_is_concerned($self->get_arch());
  312. };
  313. foreach my $soname ((ref($sonames) eq 'ARRAY') ? @$sonames : $sonames) {
  314. my $obj = $self->get_object($soname);
  315. my ($type, $pattern);
  316. next unless defined $obj;
  317. my $all_aliases = $obj->{patterns}{aliases};
  318. for my $type (Dpkg::Shlibs::Symbol::ALIAS_TYPES) {
  319. if (exists $all_aliases->{$type} && keys(%{$all_aliases->{$type}})) {
  320. my $aliases = $all_aliases->{$type};
  321. my $converter = $aliases->{(keys %$aliases)[0]};
  322. if (my $alias = $converter->convert_to_alias($name)) {
  323. if ($alias && exists $aliases->{$alias}) {
  324. $pattern = $aliases->{$alias};
  325. last if &$pattern_ok($pattern);
  326. $pattern = undef; # otherwise not found yet
  327. }
  328. }
  329. }
  330. }
  331. # Now try generic patterns and use the first that matches
  332. if (not defined $pattern) {
  333. for my $p (@{$obj->{patterns}{generic}}) {
  334. if (&$pattern_ok($p) && $p->matches_rawname($name)) {
  335. $pattern = $p;
  336. last;
  337. }
  338. }
  339. }
  340. if (defined $pattern) {
  341. return (wantarray) ?
  342. ( symbol => $pattern, soname => $soname ) : $pattern;
  343. }
  344. }
  345. return;
  346. }
  347. # merge_symbols($object, $minver)
  348. # Needs $Objdump->get_object($soname) as parameter
  349. # Don't merge blacklisted symbols related to the internal (arch-specific)
  350. # machinery
  351. sub merge_symbols {
  352. my ($self, $object, $minver) = @_;
  353. my $soname = $object->{SONAME} || error(_g('cannot merge symbols from objects without SONAME'));
  354. my %dynsyms;
  355. foreach my $sym ($object->get_exported_dynamic_symbols()) {
  356. my $name = $sym->{name} . '@' .
  357. ($sym->{version} ? $sym->{version} : 'Base');
  358. my $symobj = $self->lookup_symbol($name, $soname);
  359. if (exists $blacklist{$sym->{name}}) {
  360. next unless (defined $symobj and $symobj->has_tag('ignore-blacklist'));
  361. }
  362. $dynsyms{$name} = $sym;
  363. }
  364. unless ($self->has_object($soname)) {
  365. $self->create_object($soname, '');
  366. }
  367. # Scan all symbols provided by the objects
  368. my $obj = $self->get_object($soname);
  369. # invalidate the minimum version cache - it is not sufficient to
  370. # invalidate in add_symbol, since we might change a minimum
  371. # version for a particular symbol without adding it
  372. $obj->{minver_cache} = [];
  373. foreach my $name (keys %dynsyms) {
  374. my $sym;
  375. if ($sym = $self->lookup_symbol($name, $obj, 1)) {
  376. # If the symbol is already listed in the file
  377. $sym->mark_found_in_library($minver, $self->get_arch());
  378. } else {
  379. # The exact symbol is not present in the file, but it might match a
  380. # pattern.
  381. my $pattern = $self->find_matching_pattern($name, $obj, 1);
  382. if (defined $pattern) {
  383. $pattern->mark_found_in_library($minver, $self->get_arch());
  384. $sym = $pattern->create_pattern_match(symbol => $name);
  385. } else {
  386. # Symbol without any special info as no pattern matched
  387. $sym = Dpkg::Shlibs::Symbol->new(symbol => $name,
  388. minver => $minver);
  389. }
  390. $self->add_symbol($sym, $obj);
  391. }
  392. }
  393. # Process all symbols which could not be found in the library.
  394. foreach my $sym ($self->get_symbols($soname)) {
  395. if (not exists $dynsyms{$sym->get_symbolname()}) {
  396. $sym->mark_not_found_in_library($minver, $self->get_arch());
  397. }
  398. }
  399. # Deprecate patterns which didn't match anything
  400. for my $pattern (grep { $_->get_pattern_matches() == 0 }
  401. $self->get_patterns($soname)) {
  402. $pattern->mark_not_found_in_library($minver, $self->get_arch());
  403. }
  404. }
  405. sub is_empty {
  406. my ($self) = @_;
  407. return scalar(keys %{$self->{objects}}) ? 0 : 1;
  408. }
  409. sub has_object {
  410. my ($self, $soname) = @_;
  411. return exists $self->{objects}{$soname};
  412. }
  413. sub get_object {
  414. my ($self, $soname) = @_;
  415. return ref($soname) ? $soname : $self->{objects}{$soname};
  416. }
  417. sub create_object {
  418. my ($self, $soname, @deps) = @_;
  419. $self->{objects}{$soname} = {
  420. syms => {},
  421. fields => {},
  422. patterns => {
  423. aliases => {},
  424. generic => [],
  425. },
  426. deps => [ @deps ],
  427. minver_cache => []
  428. };
  429. }
  430. sub get_dependency {
  431. my ($self, $soname, $dep_id) = @_;
  432. $dep_id //= 0;
  433. return $self->get_object($soname)->{deps}[$dep_id];
  434. }
  435. sub get_smallest_version {
  436. my ($self, $soname, $dep_id) = @_;
  437. $dep_id //= 0;
  438. my $so_object = $self->get_object($soname);
  439. return $so_object->{minver_cache}[$dep_id] if(defined($so_object->{minver_cache}[$dep_id]));
  440. my $minver;
  441. foreach my $sym ($self->get_symbols($so_object)) {
  442. next if $dep_id != $sym->{dep_id};
  443. $minver //= $sym->{minver};
  444. if (version_compare($minver, $sym->{minver}) > 0) {
  445. $minver = $sym->{minver};
  446. }
  447. }
  448. $so_object->{minver_cache}[$dep_id] = $minver;
  449. return $minver;
  450. }
  451. sub get_dependencies {
  452. my ($self, $soname) = @_;
  453. return @{$self->get_object($soname)->{deps}};
  454. }
  455. sub get_field {
  456. my ($self, $soname, $name) = @_;
  457. if (my $obj = $self->get_object($soname)) {
  458. if (exists $obj->{fields}{$name}) {
  459. return $obj->{fields}{$name};
  460. }
  461. }
  462. return;
  463. }
  464. # Tries to find a symbol like the $refsym and returns its descriptor.
  465. # $refsym may also be a symbol name.
  466. sub lookup_symbol {
  467. my ($self, $refsym, $sonames, $inc_deprecated) = @_;
  468. $inc_deprecated //= 0;
  469. my $name = (ref $refsym) ? $refsym->get_symbolname() : $refsym;
  470. foreach my $so ((ref($sonames) eq 'ARRAY') ? @$sonames : $sonames) {
  471. if (my $obj = $self->get_object($so)) {
  472. my $sym = $obj->{syms}{$name};
  473. if ($sym and ($inc_deprecated or not $sym->{deprecated}))
  474. {
  475. return (wantarray) ?
  476. ( symbol => $sym, soname => $so ) : $sym;
  477. }
  478. }
  479. }
  480. return;
  481. }
  482. # Tries to find a pattern like the $refpat and returns its descriptor.
  483. # $refpat may also be a pattern spec.
  484. sub lookup_pattern {
  485. my ($self, $refpat, $sonames, $inc_deprecated) = @_;
  486. $inc_deprecated //= 0;
  487. # If $refsym is a string, we need to create a dummy ref symbol.
  488. $refpat = $self->create_symbol($refpat, dummy => 1) if ! ref($refpat);
  489. if ($refpat && $refpat->is_pattern()) {
  490. foreach my $soname ((ref($sonames) eq 'ARRAY') ? @$sonames : $sonames) {
  491. if (my $obj = $self->get_object($soname)) {
  492. my $pat;
  493. if (my $type = $refpat->get_alias_type()) {
  494. if (exists $obj->{patterns}{aliases}{$type}) {
  495. $pat = $obj->{patterns}{aliases}{$type}{$refpat->get_symbolname()};
  496. }
  497. } elsif ($refpat->get_pattern_type() eq 'generic') {
  498. for my $p (@{$obj->{patterns}{generic}}) {
  499. if (($inc_deprecated || !$p->{deprecated}) &&
  500. $p->equals($refpat, versioning => 0))
  501. {
  502. $pat = $p;
  503. last;
  504. }
  505. }
  506. }
  507. if ($pat && ($inc_deprecated || !$pat->{deprecated})) {
  508. return (wantarray) ?
  509. (symbol => $pat, soname => $soname) : $pat;
  510. }
  511. }
  512. }
  513. }
  514. return;
  515. }
  516. # Get symbol object reference either by symbol name or by a reference object.
  517. sub get_symbol_object {
  518. my ($self, $refsym, $soname) = @_;
  519. my $sym = $self->lookup_symbol($refsym, $soname, 1);
  520. if (! defined $sym) {
  521. $sym = $self->lookup_pattern($refsym, $soname, 1);
  522. }
  523. return $sym;
  524. }
  525. sub get_new_symbols {
  526. my ($self, $ref, %opts) = @_;
  527. my $with_optional = (exists $opts{with_optional}) ?
  528. $opts{with_optional} : 0;
  529. my @res;
  530. foreach my $soname ($self->get_sonames()) {
  531. next if not $ref->has_object($soname);
  532. # Scan raw symbols first.
  533. foreach my $sym (grep { ($with_optional || ! $_->is_optional())
  534. && $_->is_legitimate($self->get_arch()) }
  535. $self->get_symbols($soname))
  536. {
  537. my $refsym = $ref->lookup_symbol($sym, $soname, 1);
  538. my $isnew;
  539. if (defined $refsym) {
  540. # If the symbol exists in the $ref symbol file, it might
  541. # still be new if $refsym is not legitimate.
  542. $isnew = not $refsym->is_legitimate($self->get_arch());
  543. } else {
  544. # If the symbol does not exist in the $ref symbol file, it does
  545. # not mean that it's new. It might still match a pattern in the
  546. # symbol file. However, due to performance reasons, first check
  547. # if the pattern that the symbol matches (if any) exists in the
  548. # ref symbol file as well.
  549. $isnew = not (
  550. ($sym->get_pattern() and $ref->lookup_pattern($sym->get_pattern(), $soname, 1)) or
  551. $ref->find_matching_pattern($sym, $soname, 1)
  552. );
  553. }
  554. push @res, { symbol => $sym, soname => $soname } if $isnew;
  555. }
  556. # Now scan patterns
  557. foreach my $p (grep { ($with_optional || ! $_->is_optional())
  558. && $_->is_legitimate($self->get_arch()) }
  559. $self->get_patterns($soname))
  560. {
  561. my $refpat = $ref->lookup_pattern($p, $soname, 0);
  562. # If reference pattern was not found or it is not legitimate,
  563. # considering current one as new.
  564. if (not defined $refpat or
  565. not $refpat->is_legitimate($self->get_arch()))
  566. {
  567. push @res, { symbol => $p , soname => $soname };
  568. }
  569. }
  570. }
  571. return @res;
  572. }
  573. sub get_lost_symbols {
  574. my ($self, $ref, %opts) = @_;
  575. return $ref->get_new_symbols($self, %opts);
  576. }
  577. sub get_new_libs {
  578. my ($self, $ref) = @_;
  579. my @res;
  580. foreach my $soname ($self->get_sonames()) {
  581. push @res, $soname if not $ref->get_object($soname);
  582. }
  583. return @res;
  584. }
  585. sub get_lost_libs {
  586. my ($self, $ref) = @_;
  587. return $ref->get_new_libs($self);
  588. }
  589. 1;