summaryrefslogtreecommitdiff
path: root/libstdc++-v3/scripts/extract_symvers.pl
blob: 59de89b8cf52a88f64c3269fc3950e874acabb7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/perl -w

# Copyright (C) 2010-2018 Free Software Foundation, Inc.
#
# This file is part of the GNU ISO C++ Library.  This library is free
# software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this library; see the file COPYING3.  If not see
# <http://www.gnu.org/licenses/>.

# Extract symbol version information on Solaris 2.
#
# Sun ld doesn't record symbol versions in .dynsym entries and they cannot
# easily be extracted from readelf --versions output, so use pvs instead.
# This way, we don't require GNU binutils in the native case.  Also ensures
# that baseline_symbols.txt is identical between native (pvs, elfdump) and
# cross (readelf) cases.

my $lib = shift;

open PVS, "pvs -dsvo $lib |" or die $!;
while (<PVS>) {
    chomp;

    # Remove trailing semicolon.
    s/;$//;

    # shared object, dash, version, symbol, [size]
    (undef, undef, $version, $symbol, $size) = split;

    # Remove colon separator from version field.
    $version =~ s/:$//;
    
    # Record base version.  The [BASE] field was only added in Solaris 11,
    # so simply use the first record instead.
    if ($. == 1) {
	$basever = $version;
      	next;
    }

    # Skip version declarations.
    next unless defined ($symbol);

    # Ignore version dependencies.
    next if ($symbol =~ /\{.*\}/);

    # Emit objects.
    if (defined ($size)) {
	# Strip parens from object size.
	$size =~ s/\((\d+)\)/$1/;

	$type{$symbol} = "OBJECT";
	$version{$symbol} = $version;
	$size{$symbol} = $size;
        next;
    }

    if ($version eq $symbol or $version eq $basever) {
	# Emit versions or symbols bound to base versions as objects.
	$type{$symbol} = "OBJECT";
	if ($version eq $basever) {
	    $version{$symbol} = $version;
	} else {
	    $version{$symbol} = $symbol;
	}
	$size{$symbol} = 0;
    } else {
	# Everything else without a size field is a function.
	$type{$symbol} = "FUNC";
	$version{$symbol} = $version;
    }
}
close PVS or die "pvs error";

# Only look at .dynsym table, like readelf in extract_symvers.
# Ignore error output to avoid getting confused by
# .gnu.version_r: zero sh_entsize information, expected 0x1
# warning with Solaris 11 elfdump on gld-produced shared objects.
open ELFDUMP, "/usr/ccs/bin/elfdump -s -N .dynsym $lib 2>/dev/null |" or die $!;
while (<ELFDUMP>) {
    chomp;

    # Ignore empty lines.
    next if (/^$/);

    # Ignore object name header.
    next if (/:$/);

    # Ignore table header lines.
    next if (/^Symbol Table Section:/);
    next if (/index.*value.*size/);

    # Split table.
    (undef, undef, undef, $type, $bind, $oth, undef, $shndx, $name) = split;

    # Error out for unknown input.
    die "unknown input line:\n$_" unless defined($bind);

    # Ignore local symbols.
    next if ($bind eq "LOCL");
    # Ignore hidden symbols.
    next if ($oth eq "H");
    # Ignore undefined symbols.
    next if ($shndx eq "UNDEF");
    # Error out for unhandled cases.   _GLOBAL_OFFSET_TABLE_ is P (protected).
    die "unhandled symbol:\n$_" if ($bind !~ /^(GLOB|WEAK)/ or $oth !~ /[DP]/);

    # Adapt to readelf type naming convention.
    $type = "NOTYPE" if ($type eq "NOTY");
    $type = "OBJECT" if ($type eq "OBJT");

    # Use correct symbol type.
    $type{$name} = $type if ($type{$name} ne $type);
}
close ELFDUMP or die "elfdump error";

foreach $symbol (keys %type) {
    if ($type{$symbol} eq "FUNC" || $type{$symbol} eq "NOTYPE") {
	push @lines, "$type{$symbol}:$symbol\@\@$version{$symbol}\n";
    } elsif ($type{$symbol} eq "OBJECT" and $size{$symbol} == 0) {
	# Omit symbols bound to base version; details can differ depending
	# on the toolchain used.
	next if $version{$symbol} eq $basever;

	push @lines, "$type{$symbol}:$size{$symbol}:$version{$symbol}\n";
    } else {
	push @lines, "$type{$symbol}:$size{$symbol}:$symbol\@\@$version{$symbol}\n";
    }
}
print sort @lines;