SymbolFile.pm 12 KB

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