SymbolFile.pm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # Copyright (C) 2007 Raphael Hertzog
  2. # This program is free software; you can redistribute it and/or modify
  3. # it under the terms of the GNU General Public License as published by
  4. # the Free Software Foundation; either version 2 of the License, or
  5. # (at your option) any later version.
  6. # This program is distributed in the hope that it will be useful,
  7. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. # GNU General Public License for more details.
  10. # You should have received a copy of the GNU General Public License along
  11. # with this program; if not, write to the Free Software Foundation, Inc.,
  12. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  13. package Dpkg::Shlibs::SymbolFile;
  14. use Dpkg::Gettext;
  15. use Dpkg::ErrorHandling qw(syserr warning error);
  16. use Dpkg::Version qw(vercmp);
  17. textdomain("dpkg-dev");
  18. sub new {
  19. my $this = shift;
  20. my $file = shift;
  21. my $class = ref($this) || $this;
  22. my $self = { };
  23. bless $self, $class;
  24. if (defined($file) ) {
  25. $self->{file} = $file;
  26. $self->load($file) if -e $file;
  27. }
  28. return $self;
  29. }
  30. sub clear {
  31. my ($self) = @_;
  32. $self->{objects} = {};
  33. }
  34. sub clear_except {
  35. my ($self, @ids) = @_;
  36. my %has;
  37. $has{$_} = 1 foreach (@ids);
  38. foreach my $objid (keys %{$self->{objects}}) {
  39. delete $self->{objects}{$objid} unless exists $has{$objid};
  40. }
  41. }
  42. sub load {
  43. my ($self, $file) = @_;
  44. $self->{file} = $file;
  45. open(SYM_FILE, "<", $file)
  46. || syserr(sprintf(_g("Can't open %s: %s"), $file));
  47. my ($object);
  48. while (defined($_ = <SYM_FILE>)) {
  49. chomp($_);
  50. if (/^\s+(\S+)\s(\S+)(?:\s(\d+))?/) {
  51. # New symbol
  52. my $sym = {
  53. minver => $2,
  54. dep_id => defined($3) ? $3 : 0,
  55. deprecated => 0
  56. };
  57. $self->{objects}{$object}{syms}{$1} = $sym;
  58. } elsif (/^#DEPRECATED: ([^#]+)#\s*(\S+)\s(\S+)(?:\s(\d+))?/) {
  59. my $sym = {
  60. minver => $3,
  61. dep_id => defined($4) ? $4 : 0,
  62. deprecated => $1
  63. };
  64. $self->{objects}{$object}{syms}{$2} = $sym;
  65. } elsif (/^\|\s*(.*)$/) {
  66. # Alternative dependency template
  67. push @{$self->{objects}{$object}{deps}}, "$1";
  68. } elsif (/^(\S+)\s+(.*)$/) {
  69. # New object and dependency template
  70. $object = $1;
  71. $self->{objects}{$object} = {
  72. syms => {},
  73. deps => [ "$2" ]
  74. };
  75. } else {
  76. warning(sprintf(_g("Failed to parse a line in %s: %s"), $file, $_));
  77. }
  78. }
  79. close(SYM_FILE);
  80. }
  81. sub save {
  82. my ($self, $file) = @_;
  83. $file = $self->{file} unless defined($file);
  84. my $fh;
  85. if ($file eq "-") {
  86. $fh = \*STDOUT;
  87. } else {
  88. open($fh, ">", $file)
  89. || syserr(sprintf(_g("Can't open %s for writing: %s"), $file, $!));
  90. }
  91. $self->dump($fh);
  92. close($fh) if ($file ne "-");
  93. }
  94. sub dump {
  95. my ($self, $fh) = @_;
  96. foreach my $soname (sort keys %{$self->{objects}}) {
  97. print $fh "$soname $self->{objects}{$soname}{deps}[0]\n";
  98. print $fh "| $_" foreach (@{$self->{objects}{$soname}{deps}}[ 1 .. -1 ]);
  99. foreach my $sym (sort keys %{$self->{objects}{$soname}{syms}}) {
  100. my $info = $self->{objects}{$soname}{syms}{$sym};
  101. print $fh "#DEPRECATED: $info->{deprecated}#" if $info->{deprecated};
  102. print $fh " $sym $info->{minver}";
  103. print $fh " $info->{dep_id}" if $info->{dep_id};
  104. print $fh "\n";
  105. }
  106. }
  107. }
  108. # merge_symbols($object, $minver)
  109. # Needs $Objdump->get_object($soname) as parameter
  110. sub merge_symbols {
  111. my ($self, $object, $minver) = @_;
  112. my $soname = $object->{SONAME} || error(_g("Can't merge symbols from objects without SONAME."));
  113. my %dynsyms = map { $_ => $object->{dynsyms}{$_} }
  114. grep { local $a = $object->{dynsyms}{$_}; $a->{dynamic} && $a->{defined} }
  115. keys %{$object->{dynsyms}};
  116. # Scan all symbols provided by the objects
  117. foreach my $sym (keys %dynsyms) {
  118. if (exists $self->{objects}{$soname}{syms}{$sym}) {
  119. # If the symbol is already listed in the file
  120. my $info = $self->{objects}{$soname}{syms}{$sym};
  121. if ($info->{deprecated}) {
  122. # Symbol reappeared somehow
  123. $info->{deprecated} = 0;
  124. $info->{minver} = $minver;
  125. next;
  126. }
  127. # We assume that the right dependency information is already
  128. # there.
  129. if (vercmp($minver, $info->{minver}) < 0) {
  130. $info->{minver} = $minver;
  131. }
  132. } else {
  133. # The symbol is new and not present in the file
  134. my $info = {
  135. minver => $minver,
  136. deprecated => 0,
  137. dep_id => 0
  138. };
  139. $self->{objects}{$soname}{syms}{$sym} = $info;
  140. }
  141. }
  142. # Scan all symbols in the file and mark as deprecated those that are
  143. # no more provided
  144. foreach my $sym (keys %{$self->{objects}{$soname}{syms}}) {
  145. if (! exists $dynsyms{$sym}) {
  146. $self->{objects}{$soname}{syms}{$sym}{deprecated} = $minver;
  147. }
  148. }
  149. }
  150. sub has_object {
  151. my ($self, $soname) = @_;
  152. return exists $self->{objects}{$soname};
  153. }
  154. sub create_object {
  155. my ($self, $soname, @deps) = @_;
  156. $self->{objects}{$soname} = {
  157. syms => {},
  158. deps => [ @deps ]
  159. };
  160. }
  161. sub get_dependency {
  162. my ($self, $soname, $dep_id) = @_;
  163. $dep_id = 0 unless defined($dep_id);
  164. return $self->{objects}{$soname}{deps}[$dep_id];
  165. }
  166. sub lookup_symbol {
  167. my ($self, $name, $sonames) = @_;
  168. foreach my $so (@{$sonames}) {
  169. next if (! exists $self->{objects}{$so});
  170. if (exists $self->{objects}{$so}{syms}{$name} and
  171. not $self->{objects}{$so}{syms}{$name}{deprecated})
  172. {
  173. my $dep_id = $self->{objects}{$so}{syms}{$name}{dep_id};
  174. return {
  175. 'depends' => $self->{objects}{$so}{deps}[$dep_id],
  176. 'soname' => $so,
  177. %{$self->{objects}{$so}{syms}{$name}}
  178. };
  179. }
  180. }
  181. return undef;
  182. }
  183. sub has_lost_symbols {
  184. my ($self, $ref) = @_;
  185. foreach my $soname (keys %{$self->{objects}}) {
  186. my $mysyms = $self->{objects}{$soname}{syms};
  187. next if not exists $ref->{objects}{$soname};
  188. my $refsyms = $ref->{objects}{$soname}{syms};
  189. foreach my $sym (grep { not $refsyms->{$_}{deprecated} }
  190. keys %{$refsyms})
  191. {
  192. if ((not exists $mysyms->{$sym}) or
  193. $mysyms->{$sym}{deprecated})
  194. {
  195. return 1;
  196. }
  197. }
  198. }
  199. return 0;
  200. }
  201. sub has_new_symbols {
  202. my ($self, $ref) = @_;
  203. foreach my $soname (keys %{$self->{objects}}) {
  204. my $mysyms = $self->{objects}{$soname}{syms};
  205. next if not exists $ref->{objects}{$soname};
  206. my $refsyms = $ref->{objects}{$soname}{syms};
  207. foreach my $sym (grep { not $mysyms->{$_}{deprecated} }
  208. keys %{$mysyms})
  209. {
  210. if ((not exists $refsyms->{$sym}) or
  211. $refsyms->{$sym}{deprecated})
  212. {
  213. return 1;
  214. }
  215. }
  216. }
  217. return 0;
  218. }
  219. sub has_new_libs {
  220. my ($self, $ref) = @_;
  221. foreach my $soname (keys %{$self->{objects}}) {
  222. return 1 if not exists $ref->{objects}{$soname};
  223. }
  224. return 0;
  225. }
  226. sub has_lost_libs {
  227. my ($self, $ref) = @_;
  228. foreach my $soname (keys %{$ref->{objects}}) {
  229. return 1 if not exists $self->{objects}{$soname};
  230. }
  231. return 0;
  232. }
  233. 1;