]>
Commit | Line | Data |
---|---|---|
7dc2f14b FW |
1 | #!/usr/bin/python3 |
2 | # Move symbols from other shared objects into libc.so. | |
6d7e8eda | 3 | # Copyright (C) 2020-2023 Free Software Foundation, Inc. |
7dc2f14b FW |
4 | # This file is part of the GNU C Library. |
5 | # | |
6 | # The GNU C Library is free software; you can redistribute it and/or | |
7 | # modify it under the terms of the GNU Lesser General Public | |
8 | # License as published by the Free Software Foundation; either | |
9 | # version 2.1 of the License, or (at your option) any later version. | |
10 | # | |
11 | # The GNU C Library is distributed in the hope that it will be useful, | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | # Lesser General Public License for more details. | |
15 | # | |
16 | # You should have received a copy of the GNU Lesser General Public | |
17 | # License along with the GNU C Library; if not, see | |
18 | # <https://www.gnu.org/licenses/>. | |
19 | ||
20 | """Move symbols from other shared objects into libc.so. | |
21 | ||
22 | This script moves ABI symbols from non-libc abilists in to | |
23 | libc.abilist. Symbol versions are preserved. The script must be | |
24 | called from the top of the glibc source tree. | |
25 | ||
26 | """ | |
27 | ||
28 | import argparse | |
29 | import os.path | |
30 | import sys | |
31 | ||
b9e29037 FW |
32 | # Make available glibc Python modules. |
33 | sys.path.append(os.path.dirname(os.path.realpath(__file__))) | |
7dc2f14b | 34 | |
b9e29037 | 35 | import glibcsymbols |
7dc2f14b FW |
36 | |
37 | def add_to_libc_path(path, new_symbols): | |
38 | """Add SYMBOLS to the abilist file PATH. | |
39 | ||
b9e29037 FW |
40 | NEW_SYMBOLS is a dictionary from glibcsymbols.VersionedSymbol |
41 | objects to their flags. | |
7dc2f14b FW |
42 | |
43 | """ | |
b9e29037 | 44 | original_symbols = glibcsymbols.read_abilist(path) |
7dc2f14b FW |
45 | updated_symbols = original_symbols.copy() |
46 | updated_symbols.update(new_symbols) | |
47 | if updated_symbols != original_symbols: | |
48 | sys.stdout.write('updating libc abilist {}\n'.format(path)) | |
b9e29037 FW |
49 | glibcsymbols.replace_file( |
50 | path, glibcsymbols.abilist_lines(updated_symbols)) | |
7dc2f14b FW |
51 | |
52 | # The name of the libc.so abilist file. | |
53 | libc_abilist = 'libc.abilist' | |
54 | ||
55 | def add_to_libc_fallback(directory, subdirs, symbol_lines): | |
56 | """Add SYMBOL_LINES to the libc.abilist files in SUBDIRS in DIRECTORY. | |
57 | ||
58 | All subdirectories must exist. If they do, return True. If not, | |
59 | skip processing and return False. | |
60 | ||
61 | """ | |
62 | abilists = [os.path.join(directory, subdir, libc_abilist) | |
63 | for subdir in subdirs] | |
64 | for abilist in abilists: | |
65 | if not os.path.exists(abilist): | |
66 | return False | |
67 | for abilist in abilists: | |
68 | add_to_libc_path(abilist, symbol_lines) | |
69 | return True | |
70 | ||
71 | def add_to_libc(directory, symbol_lines): | |
72 | ||
73 | """Add SYMBOL_LINES (a list of strings) to libc.abilist in DIRECTORY. | |
74 | ||
75 | Try specific subdirectories as well if libc.abilist is not found | |
76 | in DIRECTORY. | |
77 | ||
78 | """ | |
79 | libc_path = os.path.join(directory, libc_abilist) | |
80 | if os.path.exists(libc_path): | |
81 | add_to_libc_path(libc_path, symbol_lines) | |
82 | return | |
83 | ||
84 | # Special case for powerpc32 and mips32 variants. | |
85 | if add_to_libc_fallback(directory, ('fpu', 'nofpu'), symbol_lines): | |
86 | return | |
87 | ||
88 | # Special case for mips64. | |
89 | if add_to_libc_fallback(directory, ('n32', 'n64'), symbol_lines): | |
90 | return | |
91 | ||
92 | raise IOError('No libc.abilist found for: {}'.format(directory)) | |
93 | ||
94 | def move_symbols_1(path, to_move, moved_symbols): | |
95 | """Move SYMBOLS from the abilist file PATH to MOVED_SYMBOLS. | |
96 | ||
97 | TO_MOVE must be a set of strings. MOVED_SYMBOLS is a dictionary. | |
98 | ||
99 | """ | |
100 | suffix = '.abilist' | |
101 | assert path.endswith('.abilist') | |
102 | library = os.path.basename(path)[:-len(suffix)] | |
103 | placeholder = '__{}_version_placeholder'.format(library) | |
104 | ||
105 | new_lines = [] | |
106 | changed = False | |
107 | ||
b9e29037 | 108 | old_symbols = glibcsymbols.read_abilist(path) |
7dc2f14b FW |
109 | old_versions = set(versym.version for versym in old_symbols.keys()) |
110 | matching_symbols = dict(e for e in old_symbols.items() | |
111 | if e[0].symbol in to_move) | |
112 | if matching_symbols: | |
113 | sys.stdout.write('updating {} abilist {}\n'.format(library, path)) | |
114 | new_symbols = dict(e for e in old_symbols.items() | |
115 | if e[0].symbol not in to_move) | |
116 | ||
117 | # Add placeholder symbols to prevent symbol versions from | |
118 | # going away completely. | |
119 | new_versions = set(versym.version for versym in new_symbols.keys()) | |
120 | for missing_version in old_versions - new_versions: | |
b9e29037 FW |
121 | new_symbols[glibcsymbols.VersionedSymbol( |
122 | placeholder, missing_version)] = 'F' | |
7dc2f14b | 123 | |
b9e29037 FW |
124 | glibcsymbols.replace_file( |
125 | path, glibcsymbols.abilist_lines(new_symbols)) | |
7dc2f14b FW |
126 | |
127 | moved_symbols.update(matching_symbols) | |
128 | ||
129 | def move_symbols(directory, files, symbols): | |
130 | """Move SYMBOLS from FILES (a list of abilist file names) in DIRECTORY. | |
131 | ||
132 | SYMBOLS must be a set of strings. | |
133 | ||
134 | """ | |
135 | moved_symbols = {} | |
136 | for filename in files: | |
137 | move_symbols_1(os.path.join(directory, filename), symbols, | |
138 | moved_symbols) | |
139 | if moved_symbols: | |
140 | add_to_libc(directory, moved_symbols) | |
141 | ||
142 | def get_parser(): | |
143 | """Return an argument parser for this module.""" | |
144 | parser = argparse.ArgumentParser(description=__doc__) | |
145 | parser.add_argument('--only-linux', action='store_true', | |
146 | help='Restrict the operation to Linux abilists') | |
147 | parser.add_argument('symbols', help='name of the symbol to move', | |
148 | nargs='+') | |
149 | return parser | |
150 | ||
151 | def main(argv): | |
152 | """The main entry point.""" | |
153 | parser = get_parser() | |
154 | opts = parser.parse_args(argv) | |
155 | if opts.only_linux: | |
156 | sysdeps = 'sysdeps/unix/sysv/linux' | |
157 | else: | |
158 | sysdeps = 'sysdeps' | |
159 | ||
160 | symbols = frozenset(opts.symbols) | |
161 | ||
162 | for directory, dirs, files in os.walk(sysdeps): | |
163 | move_symbols(directory, [name for name in files | |
164 | if name != 'libc.abilist' | |
165 | and name.endswith('.abilist')], symbols) | |
166 | ||
167 | if __name__ == '__main__': | |
168 | main(sys.argv[1:]) |