Ignore:
Timestamp:
Nov 24, 2016, 1:14:11 PM (9 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to version 4.4.3

File:
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/buildtools/wafsamba/symbols.py

    r740 r988  
    22# using nm, producing a set of exposed defined/undefined symbols
    33
    4 import Utils, Build, subprocess, Logs
    5 from samba_wildcard import fake_build_environment
    6 from samba_utils import *
     4import os, re, subprocess
     5import Utils, Build, Options, Logs
     6from Logs import debug
     7from samba_utils import TO_LIST, LOCAL_CACHE, get_tgt_list, os_path_relpath
    78
    89# these are the data structures used in symbols.py:
     
    1819# bld.env.syslib_symbols: dictionary mapping system library name to set of symbols
    1920#                         for that library
     21# bld.env.library_dict  : dictionary mapping built library paths to subsystem names
    2022#
    2123# LOCAL_CACHE(bld, 'TARGET_TYPE') : dictionary mapping subsystem name to target type
    2224
    23 def symbols_extract(objfiles, dynamic=False):
     25
     26def symbols_extract(bld, objfiles, dynamic=False):
    2427    '''extract symbols from objfile, returning a dictionary containing
    2528       the set of undefined and public symbols for each file'''
    2629
    2730    ret = {}
     31
     32    # see if we can get some results from the nm cache
     33    if not bld.env.nm_cache:
     34        bld.env.nm_cache = {}
     35
     36    objfiles = set(objfiles).copy()
     37
     38    remaining = set()
     39    for obj in objfiles:
     40        if obj in bld.env.nm_cache:
     41            ret[obj] = bld.env.nm_cache[obj].copy()
     42        else:
     43            remaining.add(obj)
     44    objfiles = remaining
     45
     46    if len(objfiles) == 0:
     47        return ret
    2848
    2949    cmd = ["nm"]
     
    3151        # needed for some .so files
    3252        cmd.append("-D")
    33     cmd.extend(objfiles)
     53    cmd.extend(list(objfiles))
    3454
    3555    nmpipe = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
    3656    if len(objfiles) == 1:
    37         filename = objfiles[0]
     57        filename = list(objfiles)[0]
    3858        ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set()}
    3959
     
    6080            ret[filename]["UNDEFINED"].add(symbol)
    6181
     82    # add to the cache
     83    for obj in objfiles:
     84        if obj in ret:
     85            bld.env.nm_cache[obj] = ret[obj].copy()
     86        else:
     87            bld.env.nm_cache[obj] = { "PUBLIC": set(), "UNDEFINED" : set() }
     88
    6289    return ret
    6390
     
    6996
    7097
    71 def find_syslib_path(bld, libname, deps):
     98def find_ldd_path(bld, libname, binary):
    7299    '''find the path to the syslib we will link against'''
    73     # the strategy is to use the targets that depend on the library, and run ldd
    74     # on it to find the real location of the library that is used
    75 
    76     linkpath = deps[0].link_task.outputs[0].abspath(bld.env)
    77 
    78     if libname == "python":
    79         libname += bld.env.PYTHON_VERSION
    80 
    81100    ret = None
    82 
    83     lddpipe = subprocess.Popen(['ldd', linkpath], stdout=subprocess.PIPE).stdout
     101    if not bld.env.syslib_paths:
     102        bld.env.syslib_paths = {}
     103    if libname in bld.env.syslib_paths:
     104        return bld.env.syslib_paths[libname]
     105
     106    lddpipe = subprocess.Popen(['ldd', binary], stdout=subprocess.PIPE).stdout
    84107    for line in lddpipe:
    85108        line = line.strip()
     
    87110        if len(cols) < 3 or cols[1] != "=>":
    88111            continue
    89         if cols[0].startswith("lib%s." % libname.lower()):
    90             ret = cols[2]
    91112        if cols[0].startswith("libc."):
    92113            # save this one too
    93114            bld.env.libc_path = cols[2]
     115        if cols[0].startswith(libname):
     116            ret = cols[2]
     117    bld.env.syslib_paths[libname] = ret
    94118    return ret
     119
     120
     121# some regular expressions for parsing readelf output
     122re_sharedlib = re.compile('Shared library: \[(.*)\]')
     123re_rpath     = re.compile('Library rpath: \[(.*)\]')
     124
     125def get_libs(bld, binname):
     126    '''find the list of linked libraries for any binary or library
     127    binname is the path to the binary/library on disk
     128
     129    We do this using readelf instead of ldd as we need to avoid recursing
     130    into system libraries
     131    '''
     132
     133    # see if we can get the result from the ldd cache
     134    if not bld.env.lib_cache:
     135        bld.env.lib_cache = {}
     136    if binname in bld.env.lib_cache:
     137        return bld.env.lib_cache[binname].copy()
     138
     139    rpath = []
     140    libs = set()
     141
     142    elfpipe = subprocess.Popen(['readelf', '--dynamic', binname], stdout=subprocess.PIPE).stdout
     143    for line in elfpipe:
     144        m = re_sharedlib.search(line)
     145        if m:
     146            libs.add(m.group(1))
     147        m = re_rpath.search(line)
     148        if m:
     149            rpath.extend(m.group(1).split(":"))
     150
     151    ret = set()
     152    for lib in libs:
     153        found = False
     154        for r in rpath:
     155            path = os.path.join(r, lib)
     156            if os.path.exists(path):
     157                ret.add(os.path.realpath(path))
     158                found = True
     159                break
     160        if not found:
     161            # we didn't find this lib using rpath. It is probably a system
     162            # library, so to find the path to it we either need to use ldd
     163            # or we need to start parsing /etc/ld.so.conf* ourselves. We'll
     164            # use ldd for now, even though it is slow
     165            path = find_ldd_path(bld, lib, binname)
     166            if path:
     167                ret.add(os.path.realpath(path))
     168
     169    bld.env.lib_cache[binname] = ret.copy()
     170
     171    return ret
     172
     173
     174def get_libs_recursive(bld, binname, seen):
     175    '''find the recursive list of linked libraries for any binary or library
     176    binname is the path to the binary/library on disk. seen is a set used
     177    to prevent loops
     178    '''
     179    if binname in seen:
     180        return set()
     181    ret = get_libs(bld, binname)
     182    seen.add(binname)
     183    for lib in ret:
     184        # we don't want to recurse into system libraries. If a system
     185        # library that we use (eg. libcups) happens to use another library
     186        # (such as libkrb5) which contains common symbols with our own
     187        # libraries, then that is not an error
     188        if lib in bld.env.library_dict:
     189            ret = ret.union(get_libs_recursive(bld, lib, seen))
     190    return ret
     191
     192
     193
     194def find_syslib_path(bld, libname, deps):
     195    '''find the path to the syslib we will link against'''
     196    # the strategy is to use the targets that depend on the library, and run ldd
     197    # on it to find the real location of the library that is used
     198
     199    linkpath = deps[0].link_task.outputs[0].abspath(bld.env)
     200
     201    if libname == "python":
     202        libname += bld.env.PYTHON_VERSION
     203
     204    return find_ldd_path(bld, "lib%s" % libname.lower(), linkpath)
    95205
    96206
     
    114224                objmap[objpath] = t
    115225
    116     symbols = symbols_extract(objlist)
     226    symbols = symbols_extract(bld, objlist)
    117227    for obj in objlist:
    118228        t = objmap[obj]
     
    143253        if t.samba_type == 'LIBRARY':
    144254            for dep in t.add_objects:
    145                 t2 = bld.name_to_obj(dep, bld.env)
     255                t2 = bld.get_tgen_by_name(dep)
    146256                bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
    147257                bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t2.public_symbols)
     
    156266        if t.samba_type == 'LIBRARY':
    157267            for dep in t.add_objects:
    158                 t2 = bld.name_to_obj(dep, bld.env)
     268                t2 = bld.get_tgen_by_name(dep)
    159269                bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep))
    160270                bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols)
     271
     272
     273def build_library_dict(bld, tgt_list):
     274    '''build the library_dict dictionary'''
     275
     276    if bld.env.library_dict:
     277        return
     278
     279    bld.env.library_dict = {}
     280
     281    for t in tgt_list:
     282        if t.samba_type in [ 'LIBRARY', 'PYTHON' ]:
     283            linkpath = os.path.realpath(t.link_task.outputs[0].abspath(bld.env))
     284            bld.env.library_dict[linkpath] = t.sname
    161285
    162286
     
    193317    objmap[bld.env.libc_path] = 'c'
    194318
    195     symbols = symbols_extract(syslib_paths, dynamic=True)
     319    symbols = symbols_extract(bld, syslib_paths, dynamic=True)
    196320
    197321    # keep a map of syslib names to public symbols
     
    240364                deps.add(depname[0])
    241365                continue
    242             t2 = bld.name_to_obj(depname[0], bld.env)
     366            t2 = bld.get_tgen_by_name(depname[0])
    243367            if len(t2.in_library) != 1:
    244368                deps.add(depname[0])
     
    263387        if t.samba_type in [ 'LIBRARY' ]:
    264388            for obj in t.samba_deps_extended:
    265                 t2 = bld.name_to_obj(obj, bld.env)
     389                t2 = bld.get_tgen_by_name(obj)
    266390                if t2 and t2.samba_type in [ 'SUBSYSTEM', 'ASN1' ]:
    267391                    if not t.sname in t2.in_library:
     
    280404
    281405    for dep in t.autodeps:
    282         t2 = bld.name_to_obj(dep, bld.env)
     406        t2 = bld.get_tgen_by_name(dep)
    283407        if t2 is None:
    284408            continue
     
    313437    '''check for depenencies that should be changed'''
    314438
    315     if bld.name_to_obj(t.sname + ".objlist", bld.env):
     439    if bld.get_tgen_by_name(t.sname + ".objlist"):
    316440        return
    317441
     
    325449    deps = set(t.samba_deps)
    326450    for d in t.samba_deps:
    327         if targets[d] in [ 'EMPTY', 'DISABLED', 'SYSLIB' ]:
     451        if targets[d] in [ 'EMPTY', 'DISABLED', 'SYSLIB', 'GENERATOR' ]:
    328452            continue
    329453        bld.ASSERT(d in bld.env.public_symbols, "Failed to find symbol list for dependency '%s'" % d)
     
    353477    '''check for syslib depenencies'''
    354478
    355     if bld.name_to_obj(t.sname + ".objlist", bld.env):
     479    if bld.get_tgen_by_name(t.sname + ".objlist"):
    356480        return
    357481
     
    362486    features = TO_LIST(t.features)
    363487    if 'pyembed' in features or 'pyext' in features:
    364         t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python'])
     488        if 'python' in bld.env.public_symbols:
     489            t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python'])
    365490
    366491    needed = {}
     
    444569
    445570
    446 
    447 def symbols_dupcheck(task):
     571def report_duplicate(bld, binname, sym, libs, fail_on_error):
     572    '''report duplicated symbols'''
     573    if sym in ['_init', '_fini', '_edata', '_end', '__bss_start']:
     574        return
     575    libnames = []
     576    for lib in libs:
     577        if lib in bld.env.library_dict:
     578            libnames.append(bld.env.library_dict[lib])
     579        else:
     580            libnames.append(lib)
     581    if fail_on_error:
     582        raise Utils.WafError("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
     583    else:
     584        print("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
     585
     586
     587def symbols_dupcheck_binary(bld, binname, fail_on_error):
     588    '''check for duplicated symbols in one binary'''
     589
     590    libs = get_libs_recursive(bld, binname, set())
     591    symlist = symbols_extract(bld, libs, dynamic=True)
     592
     593    symmap = {}
     594    for libpath in symlist:
     595        for sym in symlist[libpath]['PUBLIC']:
     596            if sym == '_GLOBAL_OFFSET_TABLE_':
     597                continue
     598            if not sym in symmap:
     599                symmap[sym] = set()
     600            symmap[sym].add(libpath)
     601    for sym in symmap:
     602        if len(symmap[sym]) > 1:
     603            for libpath in symmap[sym]:
     604                if libpath in bld.env.library_dict:
     605                    report_duplicate(bld, binname, sym, symmap[sym], fail_on_error)
     606                    break
     607
     608def symbols_dupcheck(task, fail_on_error=False):
    448609    '''check for symbols defined in two different subsystems'''
    449610    bld = task.env.bld
     
    452613    targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
    453614
    454     Logs.info("Checking for duplicate symbols")
    455     for sym in bld.env.symbol_map:
    456         subsystems = set(bld.env.symbol_map[sym])
    457         if len(subsystems) == 1:
    458             continue
    459 
    460         if sym in ['main', '_init', '_fini', 'init_samba_module', 'samba_init_module', 'ldb_init_module' ]:
    461             # these are expected to be in many subsystems
    462             continue
    463 
    464         # if all of them are in system libraries, we can ignore them. This copes
    465         # with the duplication between libc, libpthread and libattr
    466         all_syslib = True
    467         for s in subsystems:
    468             if s != 'c' and (not s in targets or targets[s] != 'SYSLIB'):
    469                 all_syslib = False
    470         if all_syslib:
    471             continue
    472         Logs.info("symbol %s appears in %s" % (sym, subsystems))
     615    build_library_dict(bld, tgt_list)
     616    for t in tgt_list:
     617        if t.samba_type == 'BINARY':
     618            binname = os_path_relpath(t.link_task.outputs[0].abspath(bld.env), os.getcwd())
     619            symbols_dupcheck_binary(bld, binname, fail_on_error)
     620
     621
     622def symbols_dupcheck_fatal(task):
     623    '''check for symbols defined in two different subsystems (and fail if duplicates are found)'''
     624    symbols_dupcheck(task, fail_on_error=True)
    473625
    474626
     
    495647
    496648Build.BuildContext.SYMBOL_CHECK = SYMBOL_CHECK
     649
     650def DUP_SYMBOL_CHECK(bld):
     651    if Options.options.DUP_SYMBOLCHECK and bld.env.DEVELOPER:
     652        '''check for duplicate symbols'''
     653        bld.SET_BUILD_GROUP('syslibcheck')
     654        task = bld(rule=symbols_dupcheck_fatal, always=True, name='symbol duplicate checking')
     655        task.env.bld = bld
     656
     657Build.BuildContext.DUP_SYMBOL_CHECK = DUP_SYMBOL_CHECK
Note: See TracChangeset for help on using the changeset viewer.