File Coverage

File:Dpkg/Shlibs/Cppfilt.pm
Coverage:90.7%

linestmtbrancondsubpodtimecode
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=encoding utf8
18
19 - 30
=head1 NAME

Dpkg::Shlibs::Cppfilt - C++ symbol mangling support via c++filt

=head1 DESCRIPTION

This module provides functions that wrap over c++filt for its easy and
fast usage.

B<Note>: This is a private module, its API can change at any time.

=cut
31
32package Dpkg::Shlibs::Cppfilt 0.01;
33
34
12
12
12
66
10
512
use strict;
35
12
12
12
44
12
674
use warnings;
36
37our @EXPORT = qw(
38    cppfilt_demangle_cpp
39);
40our @EXPORT_OK = qw(
41    cppfilt_demangle
42);
43
44
12
12
12
76
10
230
use Exporter qw(import);
45
46
12
12
12
1200
26
690
use Dpkg::ErrorHandling;
47
12
12
12
1338
14
3844
use Dpkg::IPC;
48
49# A hash of 'objects' referring to preforked c++filt processes for the distinct
50# demangling types.
51my %cppfilts;
52
53sub get_cppfilt {
54
1725
0
2428
    my $type = shift || 'auto';
55
56    # Fork c++filt process for demangling $type unless it is forked already.
57    # Keeping c++filt running improves performance a lot.
58
1725
1448
    my $filt;
59
1725
2835
    if (exists $cppfilts{$type}) {
60
1713
1939
        $filt = $cppfilts{$type};
61    } else {
62
12
62
        $filt = {
63            from => undef,
64            to => undef,
65            last_symbol => '',
66            last_result => '',
67        };
68        $filt->{pid} = spawn(exec => [ 'c++filt', "--format=$type" ],
69                             from_pipe => \$filt->{from},
70
12
102
                             to_pipe => \$filt->{to});
71        syserr(g_('unable to execute %s'), 'c++filt')
72
6
69
            unless defined $filt->{from};
73
6
241
        $filt->{from}->autoflush(1);
74
75
6
790
        $cppfilts{$type} = $filt;
76    }
77
1719
2022
    return $filt;
78}
79
80# Demangle the given $symbol using demangler for the specified $type (defaults
81# to 'auto') . Extraneous characters trailing after a mangled name are kept
82# intact. If neither whole $symbol nor portion of it could be demangled, undef
83# is returned.
84sub cppfilt_demangle {
85
1725
0
2138
    my ($symbol, $type) = @_;
86
87    # Start or get c++filt 'object' for the requested type.
88
1725
2554
    my $filt = get_cppfilt($type);
89
90    # Remember the last result. Such a local optimization is cheap and useful
91    # when sequential pattern matching is performed.
92
1719
2951
    if ($filt->{last_symbol} ne $symbol) {
93        # This write/read operation should not deadlock because c++filt flushes
94        # output buffer on LF or each invalid character.
95
917
917
978
6071
        print { $filt->{from} } $symbol, "\n";
96
917
10043669
        my $demangled = readline($filt->{to});
97
917
1662
        chop $demangled;
98
99        # If the symbol was not demangled, return undef. Otherwise normalize
100        # it as llvm packs ending angle brackets with no intermediate spaces
101        # as allowed by C++11, contrary to GNU binutils.
102
917
1638
        if ($symbol eq $demangled) {
103
150
163
            $demangled = undef;
104        } else {
105
767
5928
            $demangled =~ s{(?<=>)(?=>)}{ }g;
106        }
107
108        # Remember the last result
109
917
1355
        $filt->{last_symbol} = $symbol;
110
917
1250
        $filt->{last_result} = $demangled;
111    }
112
1719
5243
    return $filt->{last_result};
113}
114
115sub cppfilt_demangle_cpp {
116
1725
0
1664
    my $symbol = shift;
117
1725
2580
    return cppfilt_demangle($symbol, 'auto');
118}
119
120sub terminate_cppfilts {
121
6
0
25
    foreach my $type (keys %cppfilts) {
122
6
26
        next if not defined $cppfilts{$type}{pid};
123
6
82
        close $cppfilts{$type}{from};
124
6
20
        close $cppfilts{$type}{to};
125
6
25
        wait_child($cppfilts{$type}{pid}, cmdline => 'c++filt',
126                                          nocheck => 1,
127                                          timeout => 5);
128
6
48
        delete $cppfilts{$type};
129    }
130}
131
132# Close/terminate running c++filt process(es)
133END {
134    # Make sure exitcode is not changed (by wait_child)
135
3
26214
    my $exitcode = $?;
136
3
7
    terminate_cppfilts();
137
3
87
    $? = $exitcode;
138}
139
140 - 146
=head1 CHANGES

=head2 Version 0.xx

This is a private module.

=cut
147
1481;