SymbolFile.pm 6.0 KB

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