summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@chromium.org>2014-07-30 00:36:12 -0400
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-07-31 19:43:53 +0000
commitdd21e507911a373d11ed8714385f637572f4f430 (patch)
tree341e21f0f49674452cddf1b46226bcadd495d2cf
parent51d742d9728d498f2044d9e9f9f921562e274667 (diff)
downloadchromite-dd21e507911a373d11ed8714385f637572f4f430.tar.gz
lddtree: sync with Gentoo
This doesn't have any fixes we need really, but it syncs up so we can grab fixes we do care about afterwards. BUG=chromium:398098 BUG=chromium:393018 TEST=`cbuildbot arm-generic-full` works Change-Id: I16b3f2d9b273d2ef58dc39b12a8aa5fe55ee5a86 Reviewed-on: https://chromium-review.googlesource.com/210352 Reviewed-by: Yunlian Jiang <yunlian@chromium.org> Tested-by: Mike Frysinger <vapier@chromium.org> Commit-Queue: Mike Frysinger <vapier@chromium.org>
-rw-r--r--third_party/lddtree.py87
1 files changed, 60 insertions, 27 deletions
diff --git a/third_party/lddtree.py b/third_party/lddtree.py
index 438659a96..41776988e 100644
--- a/third_party/lddtree.py
+++ b/third_party/lddtree.py
@@ -1,9 +1,10 @@
#!/usr/bin/python
-# Copyright 2012-2013 Gentoo Foundation
-# Copyright 2012-2013 Mike Frysinger <vapier@gentoo.org>
+# Copyright 2012-2014 Gentoo Foundation
+# Copyright 2012-2014 Mike Frysinger <vapier@gentoo.org>
+# Copyright 2012-2014 The Chromium OS Authors
# Use of this source code is governed by a BSD-style license (BSD-3)
# pylint: disable=C0301
-# $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.py,v 1.41 2013/04/22 22:02:43 vapier Exp $
+# $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.py,v 1.48 2014/07/30 04:28:41 vapier Exp $
# TODO: Handle symlinks.
@@ -28,7 +29,7 @@ from elftools.common import exceptions
def warn(msg, prefix='warning'):
"""Write |msg| to stderr with a |prefix| before it"""
- print('%s: %s: %s' % (sys.argv[0], prefix, msg), file=sys.stderr)
+ print('%s: %s: %s' % (os.path.basename(sys.argv[0]), prefix, msg), file=sys.stderr)
def err(msg, status=1):
@@ -37,6 +38,12 @@ def err(msg, status=1):
sys.exit(status)
+def dbg(debug, *args, **kwargs):
+ """Pass |args| and |kwargs| to print() when |debug| is True"""
+ if debug:
+ print(*args, **kwargs)
+
+
def bstr(buf):
"""Decode the byte string into a string"""
return buf.decode('utf-8')
@@ -109,7 +116,7 @@ exec \
os.rename(wrappath, wrappath + '.elf')
with open(wrappath, 'w') as f:
f.write(wrapper % replacements)
- os.chmod(wrappath, 0o755)
+ os.chmod(wrappath, 0o0755)
def ParseLdPaths(str_ldpaths, root='', path=None):
@@ -121,8 +128,10 @@ def ParseLdPaths(str_ldpaths, root='', path=None):
- (TODO) $LIB and friends
Args:
- str_ldpath: A colon-delimited string of paths
+ str_ldpaths: A colon-delimited string of paths
root: The path to prepend to all paths found
+ path: The object actively being parsed (used for $ORIGIN)
+
Returns:
list of processed paths
"""
@@ -148,6 +157,7 @@ def ParseLdSoConf(ldso_conf, root='/', _first=True):
ldso_conf: The file to scan
root: The path to prepend to all paths found
_first: Recursive use only; is this the first ELF ?
+
Returns:
list of paths found
"""
@@ -181,13 +191,15 @@ def ParseLdSoConf(ldso_conf, root='/', _first=True):
return paths
-def LoadLdpaths(root='/'):
+def LoadLdpaths(root='/', prefix=''):
"""Load linker paths from common locations
This parses the ld.so.conf and LD_LIBRARY_PATH env var.
Args:
root: The root tree to prepend to paths
+ prefix: The path under |root| to search
+
Returns:
dict containing library paths to search
"""
@@ -209,7 +221,7 @@ def LoadLdpaths(root='/'):
ldpaths['env'] = ParseLdPaths(env_ldpath, path='')
# Load up /etc/ld.so.conf.
- ldpaths['conf'] = ParseLdSoConf(root + 'etc/ld.so.conf', root=root)
+ ldpaths['conf'] = ParseLdSoConf(root + prefix + '/etc/ld.so.conf', root=root)
return ldpaths
@@ -223,6 +235,7 @@ def CompatibleELFs(elf1, elf2):
Args:
elf1: an ELFFile object
elf2: an ELFFile object
+
Returns:
True if compatible, False otherwise
"""
@@ -236,18 +249,22 @@ def CompatibleELFs(elf1, elf2):
elf1.header['e_machine'] == elf2.header['e_machine'])
-def FindLib(elf, lib, ldpaths):
+def FindLib(elf, lib, ldpaths, debug=False):
"""Try to locate a |lib| that is compatible to |elf| in the given |ldpaths|
Args:
- elf: the elf which the library should be compatible with (ELF wise)
- lib: the library (basename) to search for
- ldpaths: a list of paths to search
+ elf: The elf which the library should be compatible with (ELF wise)
+ lib: The library (basename) to search for
+ ldpaths: A list of paths to search
+ debug: Enable debug output
+
Returns:
the full path to the desired library
"""
+ dbg(debug, ' FindLib(%s)' % lib)
for ldpath in ldpaths:
path = os.path.join(ldpath, lib)
+ dbg(debug, ' checking:', path)
if os.path.exists(path):
with open(path, 'rb') as f:
libelf = ELFFile(f)
@@ -256,18 +273,21 @@ def FindLib(elf, lib, ldpaths):
return None
-def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
- _first=True, _all_libs={}):
+def ParseELF(path, root='/', prefix='', ldpaths={'conf':[], 'env':[], 'interp':[]},
+ debug=False, _first=True, _all_libs={}):
"""Parse the ELF dependency tree of the specified file
Args:
path: The ELF to scan
root: The root tree to prepend to paths; this applies to interp and rpaths
only as |path| and |ldpaths| are expected to be prefixed already
+ prefix: The path under |root| to search
ldpaths: dict containing library paths to search; should have the keys:
conf, env, interp
+ debug: Enable debug output
_first: Recursive use only; is this the first ELF ?
_all_libs: Recursive use only; dict of all libs we've seen
+
Returns:
a dict containing information about all the ELFs; e.g.
{
@@ -297,6 +317,8 @@ def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
'libs': _all_libs,
}
+ dbg(debug, 'ParseELF(%s)' % path)
+
with open(path, 'rb') as f:
elf = ELFFile(f)
@@ -307,6 +329,7 @@ def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
continue
interp = bstr(segment.get_interp_name())
+ dbg(debug, ' interp =', interp)
ret['interp'] = normpath(root + interp)
ret['libs'][os.path.basename(interp)] = {
'path': ret['interp'],
@@ -315,8 +338,9 @@ def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
# XXX: Should read it and scan for /lib paths.
ldpaths['interp'] = [
normpath(root + os.path.dirname(interp)),
- normpath(root + '/usr' + os.path.dirname(interp)),
+ normpath(root + prefix + '/usr' + os.path.dirname(interp).lstrip(prefix)),
]
+ dbg(debug, ' ldpaths[interp] =', ldpaths['interp'])
break
# Parse the ELF's dynamic tags.
@@ -346,6 +370,8 @@ def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
# used at runtime to locate things.
ldpaths['rpath'] = rpaths
ldpaths['runpath'] = runpaths
+ dbg(debug, ' ldpaths[rpath] =', rpaths)
+ dbg(debug, ' ldpaths[runpath] =', runpaths)
ret['rpath'] = rpaths
ret['runpath'] = runpaths
ret['needed'] = libs
@@ -357,13 +383,13 @@ def ParseELF(path, root='/', ldpaths={'conf':[], 'env':[], 'interp':[]},
continue
if all_ldpaths is None:
all_ldpaths = rpaths + ldpaths['rpath'] + ldpaths['env'] + runpaths + ldpaths['runpath'] + ldpaths['conf'] + ldpaths['interp']
- fullpath = FindLib(elf, lib, all_ldpaths)
+ fullpath = FindLib(elf, lib, all_ldpaths, debug=debug)
_all_libs[lib] = {
'path': fullpath,
'needed': [],
}
if fullpath:
- lret = ParseELF(fullpath, root, ldpaths, False, _all_libs)
+ lret = ParseELF(fullpath, root, prefix, ldpaths, debug, False, _all_libs)
_all_libs[lib]['needed'] = lret['needed']
del elf
@@ -376,7 +402,7 @@ def _NormalizePath(option, _opt, value, parser):
def _ShowVersion(_option, _opt, _value, _parser):
- d = '$Id: lddtree.py,v 1.41 2013/04/22 22:02:43 vapier Exp $'.split()
+ d = '$Id: lddtree.py,v 1.48 2014/07/30 04:28:41 vapier Exp $'.split()
print('%s-%s %s %s' % (d[1].split('.')[0], d[2], d[3], d[4]))
sys.exit(0)
@@ -543,6 +569,10 @@ they need will be placed into /foo/lib/ only.""")
default=os.environ.get('ROOT', ''), type='string',
action='callback', callback=_NormalizePath,
help='Search for all files/dependencies in ROOT')
+ parser.add_option('-P', '--prefix',
+ default=os.environ.get('EPREFIX', '@GENTOO_PORTAGE_EPREFIX@'), type='string',
+ action='callback', callback=_NormalizePath,
+ help='Specify EPREFIX for binaries (for Gentoo Prefix)')
parser.add_option('--no-auto-root',
dest='auto_root', action='store_false', default=True,
help='Do not automatically prefix input ELFs with ROOT')
@@ -587,6 +617,8 @@ they need will be placed into /foo/lib/ only.""")
if options.root != '/':
options.root += '/'
+ if options.prefix == '@''GENTOO_PORTAGE_EPREFIX''@':
+ options.prefix = ''
if options.bindir and options.bindir[0] != '/':
parser.error('--bindir accepts absolute paths only')
@@ -596,32 +628,33 @@ they need will be placed into /foo/lib/ only.""")
if options.skip_non_elfs and options.copy_non_elfs:
parser.error('pick one handler for non-ELFs: skip or copy')
- if options.debug:
- print('root =', options.root)
- if options.dest:
- print('dest =', options.dest)
+ dbg(options.debug, 'root =', options.root)
+ if options.dest:
+ dbg(options.debug, 'dest =', options.dest)
if not paths:
err('missing ELF files to scan')
- ldpaths = LoadLdpaths(options.root)
- if options.debug:
- print('ldpaths[conf] =', ldpaths['conf'])
- print('ldpaths[env] =', ldpaths['env'])
+ ldpaths = LoadLdpaths(options.root, options.prefix)
+ dbg(options.debug, 'ldpaths[conf] =', ldpaths['conf'])
+ dbg(options.debug, 'ldpaths[env] =', ldpaths['env'])
# Process all the files specified.
ret = 0
for path in paths:
+ dbg(options.debug, 'argv[x] =', path)
# Only auto-prefix the path if the ELF is absolute.
# If it's a relative path, the user most likely wants
# the local path.
if options.auto_root and path.startswith('/'):
path = options.root + path.lstrip('/')
+ dbg(options.debug, ' +auto-root =', path)
matched = False
for p in glob.iglob(path):
matched = True
try:
- elf = ParseELF(p, options.root, ldpaths)
+ elf = ParseELF(p, options.root, options.prefix, ldpaths,
+ debug=options.debug)
except exceptions.ELFError as e:
if options.skip_non_elfs:
continue