Commit | Line | Data |
---|---|---|
1479465f GJ |
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 | use strict; | |
20 | 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 | use Exporter qw(import); | |
31 | ||
32 | use Dpkg::ErrorHandling; | |
33 | 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 | 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 | my $filt; | |
45 | if (exists $cppfilts{$type}) { | |
46 | $filt = $cppfilts{$type}; | |
47 | } else { | |
48 | $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 | to_pipe => \$filt->{to}); | |
53 | syserr(g_('unable to execute %s'), 'c++filt') | |
54 | unless defined $filt->{from}; | |
55 | $filt->{from}->autoflush(1); | |
56 | ||
57 | $cppfilts{$type} = $filt; | |
58 | } | |
59 | 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 | my ($symbol, $type) = @_; | |
68 | ||
69 | # Start or get c++filt 'object' for the requested type. | |
70 | 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 | 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 | print { $filt->{from} } $symbol, "\n"; | |
78 | my $demangled = readline($filt->{to}); | |
79 | chop $demangled; | |
80 | ||
81 | # If the symbol was not demangled, return undef | |
82 | $demangled = undef if $symbol eq $demangled; | |
83 | ||
84 | # Remember the last result | |
85 | $filt->{last_symbol} = $symbol; | |
86 | $filt->{last_result} = $demangled; | |
87 | } | |
88 | return $filt->{last_result}; | |
89 | } | |
90 | ||
91 | sub cppfilt_demangle_cpp { | |
92 | my $symbol = shift; | |
93 | return cppfilt_demangle($symbol, 'auto'); | |
94 | } | |
95 | ||
96 | sub terminate_cppfilts { | |
97 | foreach my $type (keys %cppfilts) { | |
98 | next if not defined $cppfilts{$type}{pid}; | |
99 | close $cppfilts{$type}{from}; | |
100 | close $cppfilts{$type}{to}; | |
101 | wait_child($cppfilts{$type}{pid}, cmdline => 'c++filt', | |
102 | nocheck => 1, | |
103 | timeout => 5); | |
104 | 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 | my $exitcode = $?; | |
112 | terminate_cppfilts(); | |
113 | $? = $exitcode; | |
114 | } | |
115 | ||
116 | 1; |