# a waf tool to extract symbols from object files or libraries
# using nm, producing a set of exposed defined/undefined symbols
-import Utils, Build, subprocess, Logs, re
-from samba_wildcard import fake_build_environment
-from samba_utils import *
+import os, re, subprocess
+from waflib import Utils, Build, Options, Logs, Errors
+from waflib.Logs import debug
+from samba_utils import TO_LIST, LOCAL_CACHE, get_tgt_list, os_path_relpath
# these are the data structures used in symbols.py:
#
for line in nmpipe:
line = line.strip()
- if line.endswith(':'):
+ if line.endswith(b':'):
filename = line[:-1]
ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set() }
continue
- cols = line.split(" ")
- if cols == ['']:
+ cols = line.split(b" ")
+ if cols == [b'']:
continue
# see if the line starts with an address
if len(cols) == 3:
else:
symbol_type = cols[0]
symbol = cols[1]
- if symbol_type in "BDGTRVWSi":
+ if symbol_type in b"BDGTRVWSi":
# its a public symbol
ret[filename]["PUBLIC"].add(symbol)
- elif symbol_type in "U":
+ elif symbol_type in b"U":
ret[filename]["UNDEFINED"].add(symbol)
# add to the cache
lddpipe = subprocess.Popen(['ldd', binary], stdout=subprocess.PIPE).stdout
for line in lddpipe:
line = line.strip()
- cols = line.split(" ")
- if len(cols) < 3 or cols[1] != "=>":
+ cols = line.split(b" ")
+ if len(cols) < 3 or cols[1] != b"=>":
continue
- if cols[0].startswith("libc."):
+ if cols[0].startswith(b"libc."):
# save this one too
bld.env.libc_path = cols[2]
if cols[0].startswith(libname):
# some regular expressions for parsing readelf output
-re_sharedlib = re.compile('Shared library: \[(.*)\]')
-re_rpath = re.compile('Library rpath: \[(.*)\]')
+re_sharedlib = re.compile(b'Shared library: \[(.*)\]')
+# output from readelf could be `Library rpath` or `Libray runpath`
+re_rpath = re.compile(b'Library (rpath|runpath): \[(.*)\]')
def get_libs(bld, binname):
'''find the list of linked libraries for any binary or library
libs.add(m.group(1))
m = re_rpath.search(line)
if m:
- rpath.extend(m.group(1).split(":"))
+ # output from Popen is always bytestr even in py3
+ rpath.extend(m.group(2).split(b":"))
ret = set()
for lib in libs:
bld.env.public_symbols[name] = t.public_symbols
if t.samba_type == 'LIBRARY':
for dep in t.add_objects:
- t2 = bld.name_to_obj(dep, bld.env)
+ t2 = bld.get_tgen_by_name(dep)
bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t2.public_symbols)
bld.env.used_symbols[name] = t.used_symbols
if t.samba_type == 'LIBRARY':
for dep in t.add_objects:
- t2 = bld.name_to_obj(dep, bld.env)
+ t2 = bld.get_tgen_by_name(dep)
bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols)
if targets[depname[0]] in [ 'SYSLIB' ]:
deps.add(depname[0])
continue
- t2 = bld.name_to_obj(depname[0], bld.env)
+ t2 = bld.get_tgen_by_name(depname[0])
if len(t2.in_library) != 1:
deps.add(depname[0])
continue
for t in tgt_list:
if t.samba_type in [ 'LIBRARY' ]:
for obj in t.samba_deps_extended:
- t2 = bld.name_to_obj(obj, bld.env)
+ t2 = bld.get_tgen_by_name(obj)
if t2 and t2.samba_type in [ 'SUBSYSTEM', 'ASN1' ]:
if not t.sname in t2.in_library:
t2.in_library.append(t.sname)
Logs.warn("WARNING: Target '%s' in multiple libraries: %s" % (t.sname, t.in_library))
for dep in t.autodeps:
- t2 = bld.name_to_obj(dep, bld.env)
+ t2 = bld.get_tgen_by_name(dep)
if t2 is None:
continue
for dep2 in t2.autodeps:
if dep2 == name and t.in_library != t2.in_library:
Logs.warn("WARNING: mutual dependency %s <=> %s" % (name, real_name(t2.sname)))
Logs.warn("Libraries should match. %s != %s" % (t.in_library, t2.in_library))
- # raise Utils.WafError("illegal mutual dependency")
+ # raise Errors.WafError("illegal mutual dependency")
def check_syslib_collisions(bld, tgt_list):
Logs.error("ERROR: Target '%s' has symbols '%s' which is also in syslib '%s'" % (t.sname, common, lib))
has_error = True
if has_error:
- raise Utils.WafError("symbols in common with system libraries")
+ raise Errors.WafError("symbols in common with system libraries")
def check_dependencies(bld, t):
'''check for depenencies that should be changed'''
- if bld.name_to_obj(t.sname + ".objlist", bld.env):
+ if bld.get_tgen_by_name(t.sname + ".objlist"):
return
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
def check_syslib_dependencies(bld, t):
'''check for syslib depenencies'''
- if bld.name_to_obj(t.sname + ".objlist", bld.env):
+ if bld.get_tgen_by_name(t.sname + ".objlist"):
return
sname = real_name(t.sname)
why = Options.options.WHYNEEDED.split(":")
if len(why) != 2:
- raise Utils.WafError("usage: WHYNEEDED=TARGET:DEPENDENCY")
+ raise Errors.WafError("usage: WHYNEEDED=TARGET:DEPENDENCY")
target = why[0]
subsystem = why[1]
Logs.info("target '%s' uses symbols %s from '%s'" % (target, overlap, subsystem))
-def report_duplicate(bld, binname, sym, libs):
+def report_duplicate(bld, binname, sym, libs, fail_on_error):
'''report duplicated symbols'''
- if sym in ['_init', '_fini']:
+ if sym in ['_init', '_fini', '_edata', '_end', '__bss_start']:
return
libnames = []
for lib in libs:
libnames.append(bld.env.library_dict[lib])
else:
libnames.append(lib)
- print("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
+ if fail_on_error:
+ raise Errors.WafError("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
+ else:
+ print("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
-def symbols_dupcheck_binary(bld, binname):
+def symbols_dupcheck_binary(bld, binname, fail_on_error):
'''check for duplicated symbols in one binary'''
libs = get_libs_recursive(bld, binname, set())
symmap = {}
for libpath in symlist:
for sym in symlist[libpath]['PUBLIC']:
+ if sym == '_GLOBAL_OFFSET_TABLE_':
+ continue
if not sym in symmap:
symmap[sym] = set()
symmap[sym].add(libpath)
if len(symmap[sym]) > 1:
for libpath in symmap[sym]:
if libpath in bld.env.library_dict:
- report_duplicate(bld, binname, sym, symmap[sym])
+ report_duplicate(bld, binname, sym, symmap[sym], fail_on_error)
break
-def symbols_dupcheck(task):
+def symbols_dupcheck(task, fail_on_error=False):
'''check for symbols defined in two different subsystems'''
bld = task.env.bld
tgt_list = get_tgt_list(bld)
for t in tgt_list:
if t.samba_type == 'BINARY':
binname = os_path_relpath(t.link_task.outputs[0].abspath(bld.env), os.getcwd())
- symbols_dupcheck_binary(bld, binname)
+ symbols_dupcheck_binary(bld, binname, fail_on_error)
+def symbols_dupcheck_fatal(task):
+ '''check for symbols defined in two different subsystems (and fail if duplicates are found)'''
+ symbols_dupcheck(task, fail_on_error=True)
+
def SYMBOL_CHECK(bld):
'''check our dependency lists'''
Build.BuildContext.SYMBOL_CHECK = SYMBOL_CHECK
+
+def DUP_SYMBOL_CHECK(bld):
+ if Options.options.DUP_SYMBOLCHECK and bld.env.DEVELOPER:
+ '''check for duplicate symbols'''
+ bld.SET_BUILD_GROUP('syslibcheck')
+ task = bld(rule=symbols_dupcheck_fatal, always=True, name='symbol duplicate checking')
+ task.env.bld = bld
+
+Build.BuildContext.DUP_SYMBOL_CHECK = DUP_SYMBOL_CHECK