Gentoo Archives: gentoo-commits

From: "Anthony G. Basile" <blueness@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/elfix:master commit in: misc/
Date: Wed, 26 Dec 2012 21:23:34
Message-Id: 1356556989.beacfc74b3af09d5a87ea60edba019a8d7f51f6a.blueness@gentoo
1 commit: beacfc74b3af09d5a87ea60edba019a8d7f51f6a
2 Author: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
3 AuthorDate: Wed Dec 26 21:23:09 2012 +0000
4 Commit: Anthony G. Basile <blueness <AT> gentoo <DOT> org>
5 CommitDate: Wed Dec 26 21:23:09 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/elfix.git;a=commit;h=beacfc74
7
8 misc/link_maps: encapsulate all logic in class LinkMap
9
10 ---
11 misc/link_maps | 302 +++++++++++++++++++++++++++++---------------------------
12 1 files changed, 156 insertions(+), 146 deletions(-)
13
14 diff --git a/misc/link_maps b/misc/link_maps
15 index 3707298..508af24 100755
16 --- a/misc/link_maps
17 +++ b/misc/link_maps
18 @@ -1,14 +1,5 @@
19 #!/usr/bin/env python
20
21 -#
22 -# Note: This alternative way of doing revdep-pax only
23 -# works on Gentoo systems where NEEDED.ELF.2 all the
24 -# information we need generated by scanelf during emerge.
25 -#
26 -# See /usr/lib/portage/bin/misc-functions.sh ~line 520
27 -# echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
28 -#
29 -
30 import os
31 import sys
32 import re
33 @@ -16,147 +7,181 @@ import pax
34 import portage
35
36
37 -def get_object_needed():
38 - """ Return object_needed dictionary which has structure
39 +class LinkMap:
40
41 - {
42 - abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
43 - abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
44 - ....
45 - }
46 + def __init__(self):
47 + """ Put all the NEEDED.ELF.2 files for all installed packages
48 + into a dictionary of the form
49
50 - Here the sonames were obtained from the ELF object by scanelf -nm
51 - (like readelf -d) during emerge.
52 - """
53 + { pkg : line_from_NEEDED.ELF.2, ... }
54
55 - vardb = portage.db[portage.root]["vartree"].dbapi
56 + where the line has the following form:
57
58 - object_needed = {}
59 + echo "${arch:3};${obj};${soname};${rpath};${needed}" >> \
60 + "${PORTAGE_BUILDDIR}"/build-info/NEEDED.ELF.2
61
62 - for pkg in vardb.cpv_all():
63 - needs = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
64 - if not needs: #skip empty lines
65 - continue
66 - lines = re.split('\n', needs)
67 - for line in lines:
68 - link = re.split(';', line)
69 - abi = link[0]
70 - elf = link[1]
71 - sonames = re.split(',', link[4])
72 - object_needed.setdefault(abi,{}).update({elf:sonames})
73 + See /usr/lib/portage/bin/misc-functions.sh ~line 520
74 + """
75 + vardb = portage.db[portage.root]["vartree"].dbapi
76
77 - return object_needed
78 + self.pkgs = []
79 + self.pkgs_needed = {}
80
81 + for pkg in vardb.cpv_all():
82 + needed = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
83 + if needed: # Some packages have no NEEDED.ELF.2
84 + self.pkgs.append(pkg)
85 + for line in re.split('\n', needed):
86 + self.pkgs_needed.setdefault(pkg,[]).append(re.split(';', line))
87
88 -def get_libraries():
89 - """ Return library2soname dictionary which has structure
90
91 - { full_path_to_library : (soname, abi), ... }
92 + def get_object_needed(self):
93 + """ Return object_needed dictionary which has structure
94
95 - and its inverse which has structure
96 + {
97 + abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
98 + abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
99 + ....
100 + }
101
102 - { (soname, abi) : full_path_to_library, ... }
103 - """
104 + Here the sonames were obtained from the ELF object by scanelf -nm
105 + (like readelf -d) during emerge.
106 + """
107 + object_needed = {}
108
109 - vardb = portage.db[portage.root]["vartree"].dbapi
110 + for pkg in self.pkgs:
111 + for link in self.pkgs_needed[pkg]:
112 + abi = link[0]
113 + elf = link[1]
114 + sonames = re.split(',', link[4])
115 + object_needed.setdefault(abi,{}).update({elf:sonames})
116
117 - library2soname = {}
118 - soname2library = {}
119 + return object_needed
120
121 - for pkg in vardb.cpv_all():
122 - needs = vardb.aux_get(pkg, ['NEEDED.ELF.2'])[0].strip()
123 - if not needs: #skip empty lines
124 - continue
125 - lines = re.split('\n', needs)
126 - for line in lines:
127 - link = re.split(';', line)
128 - abi = link[0]
129 - elf = link[1]
130 - soname = link[2]
131 - if soname: #no soname => executable
132 - library2soname[elf] = (soname,abi)
133 - soname2library[(soname,abi)] = elf
134
135 - return ( library2soname, soname2library )
136 + def get_libraries(self):
137 + """ Return library2soname dictionary which has structure
138
139 + { full_path_to_library : (soname, abi), ... }
140
141 -def get_soname_needed( object_needed, library2soname ):
142 - """ Return soname_needed dictionary which has structure:
143 + and its inverse which has structure
144
145 - {
146 - abi1: { soname: [ soname1, soname2, ... ], .... },
147 - abi2: { soname: [ soname1, soname2, ... ], .... },
148 - }
149 + { (soname, abi) : full_path_to_library, ... }
150 + """
151 + library2soname = {}
152 + soname2library = {}
153
154 - Here the soname1, soname2,... were obtained from soname's corresponding
155 - ELF object by scanelf -n during emerge.
156 - """
157 + for pkg in self.pkgs:
158 + for link in self.pkgs_needed[pkg]:
159 + abi = link[0]
160 + elf = link[1]
161 + soname = link[2]
162 + if soname: #no soname => executable
163 + library2soname[elf] = (soname,abi)
164 + soname2library[(soname,abi)] = elf
165
166 - soname_needed = {}
167 + return ( library2soname, soname2library )
168
169 - for abi in object_needed:
170 - for elf in object_needed[abi]:
171 - try:
172 - (soname, abi_check) = library2soname[elf]
173 - if abi != abi_check:
174 - print('This should never happen!')
175 - sys.exit(1)
176 - soname_needed.setdefault(abi,{}).update({soname:object_needed[abi][elf]})
177 - except KeyError:
178 - continue # no soname, its probably an executable
179 -
180 - return soname_needed
181 -
182 -
183 -def expand_linkings( object_needed, soname2library ):
184 - """ Expands the object_needed dictionary which has structure
185 -
186 - {
187 - abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
188 - abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
189 - ....
190 - }
191 -
192 - such that the soname's are traced all the way to the end of
193 - the link chain. Here the sonames should be the same as those
194 - obtained from the ELF object by ldd.
195 - """
196 -
197 - for abi in object_needed:
198 - for elf in object_needed[abi]:
199 - while True:
200 - found_new_soname = False
201 - for so in object_needed[abi][elf]: # For all the first links ...
202 - try:
203 - for sn in object_needed[abi][soname2library[(so,abi)]]: # go to the next links ...
204 - if sn in object_needed[abi][elf]: # skip if already included ...
205 - continue
206 - if not (sn,abi) in soname2library: # skip if vdso ...
207 - continue
208 - # This appends to the object_needed
209 - # and soname_needed lists. No copy
210 - # was done so its the same lists in
211 - # memory for both, and its modified
212 - # for both.
213 - object_needed[abi][elf].append(sn) # otherwise collapse it back into
214 - found_new_soname = True # first links of the chain.
215 -
216 - except KeyError: # Not all nodes in the chain have a next node
217 - continue
218 -
219 - if not found_new_soname: # We're done, that last iteration found
220 - break # no new nodes
221 -
222 -
223 -def get_object_reverse_linkings( object_linkings ):
224 - object_reverse_linkings = {}
225
226 - for abi in object_linkings:
227 - for elf in object_linkings[abi]:
228 - for soname in object_linkings[abi][elf]:
229 - object_reverse_linkings.setdefault(abi,{}).setdefault(soname,[]).append(elf)
230 + def get_soname_needed(self, object_needed, library2soname ):
231 + """ Return soname_needed dictionary which has structure:
232 +
233 + {
234 + abi1: { soname: [ soname1, soname2, ... ], .... },
235 + abi2: { soname: [ soname1, soname2, ... ], .... },
236 + }
237 +
238 + Here the soname1, soname2,... were obtained from soname's corresponding
239 + ELF object by scanelf -n during emerge.
240 + """
241 + soname_needed = {}
242 +
243 + for abi in object_needed:
244 + for elf in object_needed[abi]:
245 + try:
246 + (soname, abi_check) = library2soname[elf]
247 + assert abi == abi_check # We should get the same abi associated with the soname
248 + soname_needed.setdefault(abi,{}).update({soname:object_needed[abi][elf]})
249 + except KeyError:
250 + continue # no soname, its probably an executable
251 +
252 + return soname_needed
253 +
254 +
255 + def expand_linkings(self, object_needed, soname2library):
256 + """ Expands the object_needed dictionary which has structure
257 +
258 + {
259 + abi1 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
260 + abi2 : { full_path_to_ELF_object : [ soname1, soname2, ... ], ... },
261 + ....
262 + }
263 +
264 + such that the soname's are traced all the way to the end of
265 + the link chain. Here the sonames should be the same as those
266 + obtained from the ELF object by ldd.
267 + """
268 + for abi in object_needed:
269 + for elf in object_needed[abi]:
270 + while True:
271 + found_new_soname = False
272 + for so in object_needed[abi][elf]: # For all the first links ...
273 + try:
274 + for sn in object_needed[abi][soname2library[(so,abi)]]: # go to the next links ...
275 + if sn in object_needed[abi][elf]: # skip if already included ...
276 + continue
277 + if not (sn,abi) in soname2library: # skip if vdso ...
278 + continue
279 +
280 + # This appends to the object_needed and soname_needed lists. No copy was
281 + # done so its the same lists in memory for both, and its modified for both.
282 +
283 + object_needed[abi][elf].append(sn) # otherwise collapse it back into
284 + found_new_soname = True # first links of the chain.
285
286 - return object_reverse_linkings
287 + except KeyError: # Not all nodes in the chain have a next node
288 + continue
289 +
290 + if not found_new_soname: # We're done, that last iteration found
291 + break # no new nodes
292 +
293 +
294 + def get_object_reverse_linkings(self, object_linkings):
295 + """ Return object_reverse_linkings dictionary which has structure
296 +
297 + {
298 + abi1 : { soname : [ path_to_elf1, path_to_elf2, ... ], ... },
299 + abi2 : { soname : [ path_to_elf3, path_to_elf4, ... ], ... },
300 + ....
301 + }
302 + """
303 + object_reverse_linkings = {}
304 +
305 + for abi in object_linkings:
306 + for elf in object_linkings[abi]:
307 + for soname in object_linkings[abi][elf]:
308 + object_reverse_linkings.setdefault(abi,{}).setdefault(soname,[]).append(elf)
309 +
310 + return object_reverse_linkings
311 +
312 +
313 + def get_maps(self):
314 + """ Generate the full forward and reverse links using the above functions """
315 +
316 + # After get_object_needed() and get_soname_needed(), both object_linkings and
317 + # soname_linkings are only one step into the entire link chain.
318 +
319 + object_linkings = self.get_object_needed()
320 + ( library2soname, soname2library ) = self.get_libraries()
321 + soname_linkings = self.get_soname_needed( object_linkings, library2soname )
322 +
323 + # After the appending in expand_linkings(), forward_linkings and soname_linkings
324 + # have been extended through the entire chain of linking. expand_linkings() is
325 + # a "side-effect" function, so we note it here.
326 + self.expand_linkings( soname_linkings, soname2library )
327 + object_reverse_linkings = self.get_object_reverse_linkings( object_linkings )
328 +
329 + return ( object_linkings, object_reverse_linkings, library2soname, soname2library )
330
331
332 def main():
333 @@ -167,27 +192,12 @@ def main():
334 print('RUN AS ROOT: cannot read all flags')
335 sys.exit(0)
336
337 - object_needed = get_object_needed()
338 - ( library2soname, soname2library ) = get_libraries()
339 - soname_needed = get_soname_needed( object_needed, library2soname )
340 -
341 - # After the appending to needed in expand_linkings(), forward_needed
342 - # and soname_needed have been extended through the entire chain of linking.
343 - # If we want to keep only the object_needed and soname_needed, then do
344 - # a copy before calling expand_linkings().
345 - expand_linkings( soname_needed, soname2library )
346 -
347 - object_linkings = object_needed
348 - object_needed = None
349 -
350 - soname_linkings = soname_needed
351 - soname_needed = None
352 -
353 - object_reverse_linkings = get_object_reverse_linkings( object_linkings )
354 + link_maps = LinkMap()
355 + ( object_linkings, object_reverse_linkings, library2soname, soname2library ) = link_maps.get_maps()
356
357 layout = "{0:<30} => {1:<30}"
358
359 - """ Print out all ELF objects and the NEEDED sonames and full library paths """
360 + #Print out all ELF objects and the NEEDED sonames and full library paths
361 for abi in object_linkings:
362 for elf in object_linkings[abi]:
363 sonames = object_linkings[abi][elf]
364 @@ -199,7 +209,7 @@ def main():
365 print('\t%s' % layout.format(soname, '***' ))
366 print('')
367
368 - """ Print out all ELF objects and the NEEDED sonames and full library paths """
369 + # Print out all ELF objects and the NEEDED sonames and full library paths
370 for abi in object_linkings:
371 for soname in object_reverse_linkings[abi]:
372 try: