File: | Dpkg/Shlibs/Cppfilt.pm |
Coverage: | 90.4% |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | # Copyright © 2009-2010 Modestas Vainius <modax@debian.org> | ||||||
2 | # Copyright © 2010, 2012-2015 Guillem Jover <guillem@debian.org> | ||||||
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 <https://www.gnu.org/licenses/>. | ||||||
16 | |||||||
17 | package Dpkg::Shlibs::Cppfilt; | ||||||
18 | |||||||
19 | 4 4 4 | 10 2 48 | use strict; | ||||
20 | 4 4 4 | 6 4 140 | use warnings; | ||||
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 4 | 8 4 44 | use Exporter qw(import); | ||||
31 | |||||||
32 | 4 4 4 | 254 2 122 | use Dpkg::ErrorHandling; | ||||
33 | 4 4 4 | 294 2 790 | use Dpkg::IPC; | ||||
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 | 0 | 464 | 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 | 309 | my $filt; | ||||
45 | 575 | 431 | if (exists $cppfilts{$type}) { | ||||
46 | 571 | 366 | $filt = $cppfilts{$type}; | ||||
47 | } else { | ||||||
48 | 4 | 20 | $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 | 52 | to_pipe => \$filt->{to}); | ||||
53 | syserr(g_('unable to execute %s'), 'c++filt') | ||||||
54 | 2 | 20 | unless defined $filt->{from}; | ||||
55 | 2 | 81 | $filt->{from}->autoflush(1); | ||||
56 | |||||||
57 | 2 | 207 | $cppfilts{$type} = $filt; | ||||
58 | } | ||||||
59 | 573 | 388 | 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 | 0 | 376 | my ($symbol, $type) = @_; | |||
68 | |||||||
69 | # Start or get c++filt 'object' for the requested type. | ||||||
70 | 575 | 406 | 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 | 484 | 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 | 306 306 | 158 886 | print { $filt->{from} } $symbol, "\n"; | ||||
78 | 306 | 1402276 | my $demangled = readline($filt->{to}); | ||||
79 | 306 | 265 | chop $demangled; | ||||
80 | |||||||
81 | # If the symbol was not demangled, return undef | ||||||
82 | 306 | 274 | $demangled = undef if $symbol eq $demangled; | ||||
83 | |||||||
84 | # Remember the last result | ||||||
85 | 306 | 205 | $filt->{last_symbol} = $symbol; | ||||
86 | 306 | 240 | $filt->{last_result} = $demangled; | ||||
87 | } | ||||||
88 | 573 | 841 | return $filt->{last_result}; | ||||
89 | } | ||||||
90 | |||||||
91 | sub cppfilt_demangle_cpp { | ||||||
92 | 575 | 0 | 340 | my $symbol = shift; | |||
93 | 575 | 432 | return cppfilt_demangle($symbol, 'auto'); | ||||
94 | } | ||||||
95 | |||||||
96 | sub terminate_cppfilts { | ||||||
97 | 2 | 0 | 6 | foreach my $type (keys %cppfilts) { | |||
98 | 2 | 3 | next if not defined $cppfilts{$type}{pid}; | ||||
99 | 2 | 14 | close $cppfilts{$type}{from}; | ||||
100 | 2 | 6 | close $cppfilts{$type}{to}; | ||||
101 | 2 | 5 | wait_child($cppfilts{$type}{pid}, cmdline => 'c++filt', | ||||
102 | nocheck => 1, | ||||||
103 | timeout => 5); | ||||||
104 | 2 | 16 | 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 | 6083 | my $exitcode = $?; | ||||
112 | 1 | 1 | terminate_cppfilts(); | ||||
113 | 1 | 209 | $? = $exitcode; | ||||
114 | } | ||||||
115 | |||||||
116 | 1; |