SymbolFile.pm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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. use Dpkg::Fields qw(capit);
  18. my %blacklist = (
  19. '__bss_end__' => 1, # arm
  20. '__bss_end' => 1, # arm
  21. '_bss_end__' => 1, # arm
  22. '__bss_start' => 1, # ALL
  23. '__bss_start__' => 1, # arm
  24. '__data_start' => 1, # arm
  25. '__do_global_ctors_aux' => 1, # ia64
  26. '__do_global_dtors_aux' => 1, # ia64
  27. '__do_jv_register_classes' => 1,# ia64
  28. '_DYNAMIC' => 1, # ALL
  29. '_edata' => 1, # ALL
  30. '_end' => 1, # ALL
  31. '__end__' => 1, # arm
  32. '__exidx_end' => 1, # armel
  33. '__exidx_start' => 1, # armel
  34. '_fbss' => 1, # mips, mipsel
  35. '_fdata' => 1, # mips, mipsel
  36. '_fini' => 1, # ALL
  37. '_ftext' => 1, # mips, mipsel
  38. '_GLOBAL_OFFSET_TABLE_' => 1, # hppa, mips, mipsel
  39. '__gmon_start__' => 1, # hppa
  40. '_gp' => 1, # mips, mipsel
  41. '_init' => 1, # ALL
  42. '_PROCEDURE_LINKAGE_TABLE_' => 1, # sparc, alpha
  43. '_SDA2_BASE_' => 1, # powerpc
  44. '_SDA_BASE_' => 1, # powerpc
  45. );
  46. for (my $i = 14; $i <= 31; $i++) {
  47. # Many powerpc specific symbols
  48. $blacklist{"_restfpr_$i"} = 1;
  49. $blacklist{"_restfpr_$i\_x"} = 1;
  50. $blacklist{"_restgpr_$i"} = 1;
  51. $blacklist{"_restgpr_$i\_x"} = 1;
  52. $blacklist{"_savefpr_$i"} = 1;
  53. $blacklist{"_savegpr_$i"} = 1;
  54. }
  55. # Many armel-specific symbols
  56. $blacklist{"__aeabi_$_"} = 1 foreach (qw(cdcmpeq cdcmple cdrcmple cfcmpeq
  57. cfcmple cfrcmple d2f d2iz d2lz d2uiz d2ulz dadd dcmpeq dcmpge dcmpgt
  58. dcmple dcmplt dcmpun ddiv dmul dneg drsub dsub f2d f2iz f2lz f2uiz f2ulz
  59. fadd fcmpeq fcmpge fcmpgt fcmple fcmplt fcmpun fdiv fmul fneg frsub fsub
  60. i2d i2f idiv idivmod l2d l2f lasr lcmp ldivmod llsl llsr lmul ui2d ui2f
  61. uidiv uidivmod ul2d ul2f ulcmp uldivmod unwind_cpp_pr0 unwind_cpp_pr1
  62. unwind_cpp_pr2 uread4 uread8 uwrite4 uwrite8));
  63. sub new {
  64. my $this = shift;
  65. my $file = shift;
  66. my $class = ref($this) || $this;
  67. my $self = { };
  68. bless $self, $class;
  69. $self->clear();
  70. if (defined($file) ) {
  71. $self->{file} = $file;
  72. $self->load($file) if -e $file;
  73. }
  74. return $self;
  75. }
  76. sub clear {
  77. my ($self) = @_;
  78. $self->{objects} = {};
  79. $self->{used_wildcards} = 0;
  80. }
  81. sub clear_except {
  82. my ($self, @ids) = @_;
  83. my %has;
  84. $has{$_} = 1 foreach (@ids);
  85. foreach my $objid (keys %{$self->{objects}}) {
  86. delete $self->{objects}{$objid} unless exists $has{$objid};
  87. }
  88. }
  89. # Parameter seen is only used for recursive calls
  90. sub load {
  91. my ($self, $file, $seen, $current_object) = @_;
  92. if (defined($seen)) {
  93. return if exists $seen->{$file}; # Avoid include loops
  94. } else {
  95. $self->{file} = $file;
  96. $seen = {};
  97. }
  98. $seen->{$file} = 1;
  99. open(my $sym_file, "<", $file)
  100. || syserr(_g("cannot open %s"), $file);
  101. my $object = $current_object;
  102. while (defined($_ = <$sym_file>)) {
  103. chomp($_);
  104. if (/^\s+(\S+)\s(\S+)(?:\s(\d+))?/) {
  105. if (not defined ($object)) {
  106. error(_g("Symbol information must be preceded by a header (file %s, line %s)."), $file, $.);
  107. }
  108. my $name = $1;
  109. # New symbol
  110. my $sym = {
  111. minver => $2,
  112. dep_id => defined($3) ? $3 : 0,
  113. deprecated => 0
  114. };
  115. if ($name =~ /^\*@(.*)$/) {
  116. error(_g("you can't use wildcards on unversioned symbols: %s"), $_) if $1 eq "Base";
  117. $self->{objects}{$object}{wildcards}{$1} = $sym;
  118. } else {
  119. $self->{objects}{$object}{syms}{$name} = $sym;
  120. }
  121. } elsif (/^#include\s+"([^"]+)"/) {
  122. my $filename = $1;
  123. my $dir = $file;
  124. $dir =~ s{[^/]+$}{}; # Strip filename
  125. $self->load("$dir$filename", $seen, $object);
  126. } elsif (/^#(?:DEPRECATED|MISSING): ([^#]+)#\s*(\S+)\s(\S+)(?:\s(\d+))?/) {
  127. my $sym = {
  128. minver => $3,
  129. dep_id => defined($4) ? $4 : 0,
  130. deprecated => $1
  131. };
  132. $self->{objects}{$object}{syms}{$2} = $sym;
  133. } elsif (/^#/) {
  134. # Skip possible comments
  135. } elsif (/^\|\s*(.*)$/) {
  136. # Alternative dependency template
  137. push @{$self->{objects}{$object}{deps}}, "$1";
  138. } elsif (/^\*\s*([^:]+):\s*(.*\S)\s*$/) {
  139. # Add meta-fields
  140. $self->{objects}{$object}{fields}{capit($1)} = $2;
  141. } elsif (/^(\S+)\s+(.*)$/) {
  142. # New object and dependency template
  143. $object = $1;
  144. if (exists $self->{objects}{$object}) {
  145. # Update/override infos only
  146. $self->{objects}{$object}{deps} = [ "$2" ];
  147. } else {
  148. # Create a new object
  149. $self->create_object($object, "$2");
  150. }
  151. } else {
  152. warning(_g("Failed to parse a line in %s: %s"), $file, $_);
  153. }
  154. }
  155. close($sym_file);
  156. delete $seen->{$file};
  157. }
  158. sub save {
  159. my ($self, $file, $with_deprecated) = @_;
  160. $file = $self->{file} unless defined($file);
  161. my $fh;
  162. if ($file eq "-") {
  163. $fh = \*STDOUT;
  164. } else {
  165. open($fh, ">", $file)
  166. || syserr(_g("cannot write %s"), $file);
  167. }
  168. $self->dump($fh, $with_deprecated);
  169. close($fh) if ($file ne "-");
  170. }
  171. sub dump {
  172. my ($self, $fh, $with_deprecated) = @_;
  173. $with_deprecated = 1 unless defined($with_deprecated);
  174. foreach my $soname (sort keys %{$self->{objects}}) {
  175. my @deps = @{$self->{objects}{$soname}{deps}};
  176. print $fh "$soname $deps[0]\n";
  177. shift @deps;
  178. print $fh "| $_\n" foreach (@deps);
  179. my $f = $self->{objects}{$soname}{fields};
  180. print $fh "* $_: $f->{$_}\n" foreach (sort keys %{$f});
  181. foreach my $sym (sort keys %{$self->{objects}{$soname}{syms}}) {
  182. my $info = $self->{objects}{$soname}{syms}{$sym};
  183. next if $info->{deprecated} and not $with_deprecated;
  184. print $fh "#MISSING: $info->{deprecated}#" if $info->{deprecated};
  185. print $fh " $sym $info->{minver}";
  186. print $fh " $info->{dep_id}" if $info->{dep_id};
  187. print $fh "\n";
  188. }
  189. }
  190. }
  191. # merge_symbols($object, $minver)
  192. # Needs $Objdump->get_object($soname) as parameter
  193. # Don't merge blacklisted symbols related to the internal (arch-specific)
  194. # machinery
  195. sub merge_symbols {
  196. my ($self, $object, $minver) = @_;
  197. my $soname = $object->{SONAME} || error(_g("Can't merge symbols from objects without SONAME."));
  198. my %dynsyms;
  199. foreach my $sym ($object->get_exported_dynamic_symbols()) {
  200. next if exists $blacklist{$sym->{name}};
  201. if ($sym->{version}) {
  202. $dynsyms{$sym->{name} . '@' . $sym->{version}} = $sym;
  203. } else {
  204. $dynsyms{$sym->{name}} = $sym;
  205. }
  206. }
  207. unless ($self->{objects}{$soname}) {
  208. $self->create_object($soname, '');
  209. }
  210. # Scan all symbols provided by the objects
  211. foreach my $sym (keys %dynsyms) {
  212. my $obj = $self->{objects}{$soname};
  213. if (exists $obj->{syms}{$sym}) {
  214. # If the symbol is already listed in the file
  215. my $info = $obj->{syms}{$sym};
  216. if ($info->{deprecated}) {
  217. # Symbol reappeared somehow
  218. $info->{deprecated} = 0;
  219. $info->{minver} = $minver;
  220. next;
  221. }
  222. # We assume that the right dependency information is already
  223. # there.
  224. if (vercmp($minver, $info->{minver}) < 0) {
  225. $info->{minver} = $minver;
  226. }
  227. } else {
  228. # The symbol is new and not present in the file
  229. my $info;
  230. my $symobj = $dynsyms{$sym};
  231. if ($symobj->{version} and exists $obj->{wildcards}{$symobj->{version}}) {
  232. # Get the info from wildcards
  233. $info = $obj->{wildcards}{$symobj->{version}};
  234. $self->{used_wildcards}++;
  235. } else {
  236. # New symbol provided by the current release
  237. $info = {
  238. minver => $minver,
  239. deprecated => 0,
  240. dep_id => 0
  241. };
  242. }
  243. $obj->{syms}{$sym} = $info;
  244. }
  245. }
  246. # Scan all symbols in the file and mark as deprecated those that are
  247. # no more provided (only if the minver is bigger than the version where
  248. # the symbol was introduced)
  249. foreach my $sym (keys %{$self->{objects}{$soname}{syms}}) {
  250. if (! exists $dynsyms{$sym}) {
  251. # Do nothing if already deprecated
  252. next if $self->{objects}{$soname}{syms}{$sym}{deprecated};
  253. my $info = $self->{objects}{$soname}{syms}{$sym};
  254. if (vercmp($minver, $info->{minver}) > 0) {
  255. $self->{objects}{$soname}{syms}{$sym}{deprecated} = $minver;
  256. }
  257. }
  258. }
  259. }
  260. sub is_empty {
  261. my ($self) = @_;
  262. return scalar(keys %{$self->{objects}}) ? 0 : 1;
  263. }
  264. sub has_object {
  265. my ($self, $soname) = @_;
  266. return exists $self->{objects}{$soname};
  267. }
  268. sub create_object {
  269. my ($self, $soname, @deps) = @_;
  270. $self->{objects}{$soname} = {
  271. syms => {},
  272. fields => {},
  273. wildcards => {},
  274. deps => [ @deps ]
  275. };
  276. }
  277. sub get_dependency {
  278. my ($self, $soname, $dep_id) = @_;
  279. $dep_id = 0 unless defined($dep_id);
  280. return $self->{objects}{$soname}{deps}[$dep_id];
  281. }
  282. sub get_dependencies {
  283. my ($self, $soname) = @_;
  284. return @{$self->{objects}{$soname}{deps}};
  285. }
  286. sub get_field {
  287. my ($self, $soname, $name) = @_;
  288. if (exists $self->{objects}{$soname}{fields}{$name}) {
  289. return $self->{objects}{$soname}{fields}{$name};
  290. }
  291. return undef;
  292. }
  293. sub contains_wildcards {
  294. my ($self) = @_;
  295. my $res = 0;
  296. foreach my $soname (sort keys %{$self->{objects}}) {
  297. if (scalar keys %{$self->{objects}{$soname}{wildcards}}) {
  298. $res = 1;
  299. }
  300. }
  301. return $res;
  302. }
  303. sub used_wildcards {
  304. my ($self) = @_;
  305. return $self->{used_wildcards};
  306. }
  307. sub lookup_symbol {
  308. my ($self, $name, $sonames, $inc_deprecated) = @_;
  309. $inc_deprecated = 0 unless defined($inc_deprecated);
  310. foreach my $so (@{$sonames}) {
  311. next if (! exists $self->{objects}{$so});
  312. if (exists $self->{objects}{$so}{syms}{$name} and
  313. ($inc_deprecated or not
  314. $self->{objects}{$so}{syms}{$name}{deprecated}))
  315. {
  316. my $dep_id = $self->{objects}{$so}{syms}{$name}{dep_id};
  317. return {
  318. 'depends' => $self->{objects}{$so}{deps}[$dep_id],
  319. 'soname' => $so,
  320. %{$self->{objects}{$so}{syms}{$name}}
  321. };
  322. }
  323. }
  324. return undef;
  325. }
  326. sub get_new_symbols {
  327. my ($self, $ref) = @_;
  328. my @res;
  329. foreach my $soname (keys %{$self->{objects}}) {
  330. my $mysyms = $self->{objects}{$soname}{syms};
  331. next if not exists $ref->{objects}{$soname};
  332. my $refsyms = $ref->{objects}{$soname}{syms};
  333. foreach my $sym (grep { not $mysyms->{$_}{deprecated} }
  334. keys %{$mysyms})
  335. {
  336. if ((not exists $refsyms->{$sym}) or
  337. $refsyms->{$sym}{deprecated})
  338. {
  339. push @res, {
  340. 'soname' => $soname,
  341. 'name' => $sym,
  342. %{$mysyms->{$sym}}
  343. };
  344. }
  345. }
  346. }
  347. return @res;
  348. }
  349. sub get_lost_symbols {
  350. my ($self, $ref) = @_;
  351. return $ref->get_new_symbols($self);
  352. }
  353. sub get_new_libs {
  354. my ($self, $ref) = @_;
  355. my @res;
  356. foreach my $soname (keys %{$self->{objects}}) {
  357. push @res, $soname if not exists $ref->{objects}{$soname};
  358. }
  359. return @res;
  360. }
  361. sub get_lost_libs {
  362. my ($self, $ref) = @_;
  363. return $ref->get_new_libs($self);
  364. }
  365. 1;