File Coverage

blib/lib/Dpkg/Shlibs/Cppfilt.pm
Criterion Covered Total %
statement 47 47 100.0
branch 8 10 80.0
condition 1 2 50.0
subroutine 10 10 100.0
pod 0 4 0.0
total 66 73 90.4


line stmt bran cond sub pod time code
1             # Copyright © 2009-2010 Modestas Vainius
2             # Copyright © 2010, 2012-2015 Guillem Jover
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 .
16              
17             package Dpkg::Shlibs::Cppfilt;
18              
19 4     4   232500 use strict;
  4         10  
  4         150  
20 4     4   26 use warnings;
  4         6  
  4         388  
21              
22             our $VERSION = '0.01';
23             our @EXPORT = qw(
24             cppfilt_demangle_cpp
25             );
26             our @EXPORT_OK = qw(
27             cppfilt_demangle
28             );
29              
30 4     4   28 use Exporter qw(import);
  4         8  
  4         148  
31              
32 4     4   920 use Dpkg::ErrorHandling;
  4         10  
  4         398  
33 4     4   962 use Dpkg::IPC;
  4         8  
  4         2110  
34              
35             # A hash of 'objects' referring to preforked c++filt processes for the distinct
36             # demangling types.
37             my %cppfilts;
38              
39             sub get_cppfilt {
40 575   50 575 0 1240 my $type = shift || 'auto';
41              
42             # Fork c++filt process for demangling $type unless it is forked already.
43             # Keeping c++filt running improves performance a lot.
44 575         762 my $filt;
45 575 100       1399 if (exists $cppfilts{$type}) {
46 571         899 $filt = $cppfilts{$type};
47             } else {
48 4         68 $filt = { from => undef, to => undef,
49             last_symbol => '', last_result => '' };
50             $filt->{pid} = spawn(exec => [ 'c++filt', "--format=$type" ],
51             from_pipe => \$filt->{from},
52 4         90 to_pipe => \$filt->{to});
53             syserr(g_('unable to execute %s'), 'c++filt')
54 2 50       68 unless defined $filt->{from};
55 2         221 $filt->{from}->autoflush(1);
56              
57 2         630 $cppfilts{$type} = $filt;
58             }
59 573         1099 return $filt;
60             }
61              
62             # Demangle the given $symbol using demangler for the specified $type (defaults
63             # to 'auto') . Extraneous characters trailing after a mangled name are kept
64             # intact. If neither whole $symbol nor portion of it could be demangled, undef
65             # is returned.
66             sub cppfilt_demangle {
67 575     575 0 1171 my ($symbol, $type) = @_;
68              
69             # Start or get c++filt 'object' for the requested type.
70 575         1088 my $filt = get_cppfilt($type);
71              
72             # Remember the last result. Such a local optimization is cheap and useful
73             # when sequential pattern matching is performed.
74 573 100       1457 if ($filt->{last_symbol} ne $symbol) {
75             # This write/read operation should not deadlock because c++filt flushes
76             # output buffer on LF or each invalid character.
77 305         453 print { $filt->{from} } $symbol, "\n";
  305         11200  
78 305         3146136 my $demangled = readline($filt->{to});
79 305         1152 chop $demangled;
80              
81             # If the symbol was not demangled, return undef
82 305 100       897 $demangled = undef if $symbol eq $demangled;
83              
84             # Remember the last result
85 305         756 $filt->{last_symbol} = $symbol;
86 305         759 $filt->{last_result} = $demangled;
87             }
88 573         2869 return $filt->{last_result};
89             }
90              
91             sub cppfilt_demangle_cpp {
92 575     575 0 68428 my $symbol = shift;
93 575         1218 return cppfilt_demangle($symbol, 'auto');
94             }
95              
96             sub terminate_cppfilts {
97 2     2 0 21 foreach my $type (keys %cppfilts) {
98 2 50       16 next if not defined $cppfilts{$type}{pid};
99 2         97 close $cppfilts{$type}{from};
100 2         30 close $cppfilts{$type}{to};
101 2         31 wait_child($cppfilts{$type}{pid}, cmdline => 'c++filt',
102             nocheck => 1,
103             timeout => 5);
104 2         43 delete $cppfilts{$type};
105             }
106             }
107              
108             # Close/terminate running c++filt process(es)
109             END {
110             # Make sure exitcode is not changed (by wait_child)
111 1     1   18224 my $exitcode = $?;
112 1         6 terminate_cppfilts();
113 1         50 $? = $exitcode;
114             }
115              
116             1;