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: |