def gen_list(output, lib): libpaths = [os.path.join(substs['DIST'], 'bin')] binary_type = get_type(lib) if binary_type == ELF: func = dependentlibs_readelf elif binary_type == MACHO: func = dependentlibs_otool else: ext = os.path.splitext(lib)[1] assert(ext == '.dll') func = dependentlibs_dumpbin deps = dependentlibs(lib, libpaths, func) deps[lib] = mozpath.join(libpaths[0], lib) output.write('\n'.join(deps.keys()) + '\n') return set(deps.values())
def main(): parser = OptionParser() parser.add_option("-L", dest="libpaths", action="append", metavar="PATH", help="Add the given path to the library search path") parser.add_option("-p", dest="toolchain_prefix", metavar="PREFIX", help="Use the given prefix to readelf") (options, args) = parser.parse_args() if options.toolchain_prefix: global TOOLCHAIN_PREFIX TOOLCHAIN_PREFIX = options.toolchain_prefix lib = args[0] binary_type = get_type(lib) if binary_type == ELF: func = dependentlibs_readelf elif binary_type == MACHO: func = dependentlibs_otool else: ext = os.path.splitext(lib)[1] assert(ext == '.dll') func = dependentlibs_dumpbin if not options.libpaths: options.libpaths = [os.path.dirname(lib)] print '\n'.join(dependentlibs(lib, options.libpaths, func) + [lib])
def iter_symbols(binary): ty = get_type(binary) # XXX: Static libraries on ELF, MACHO and COFF/PE systems are all # ar archives. So technically speaking, the following is wrong # but is enough for now. llvm-objdump -t can actually be used on all # platforms for static libraries, but its format is different for # Windows .obj files, so the following won't work for them, but # it currently doesn't matter. if ty == UNKNOWN and open(binary).read(8) == '!<arch>\n': ty = ELF if ty in (ELF, MACHO): for line in get_output(buildconfig.substs['LLVM_OBJDUMP'], '-t', binary): m = ADDR_RE.match(line) if not m: continue addr = int(m.group(0), 16) # The second "column" is 7 one-character items that can be # whitespaces. We don't have use for their value, so just skip # those. rest = line[m.end() + 9:].split() # The number of remaining colums will vary between ELF and MACHO. # On ELF, we have: # Section Size .hidden? Name # On Macho, the size is skipped. # In every case, the symbol name is last. name = rest[-1] if '@' in name: name, ver = name.rsplit('@', 1) while name.endswith('@'): name = name[:-1] else: ver = None yield { 'addr': addr, 'size': int(rest[1], 16) if ty == ELF else 0, 'name': name, 'version': ver or None, } else: export_table = False for line in get_output(buildconfig.substs['LLVM_OBJDUMP'], '-p', binary): if line.strip() == 'Export Table:': export_table = True continue elif not export_table: continue cols = line.split() # The data we're interested in comes in 3 columns, and the first # column is a number. if len(cols) != 3 or not cols[0].isdigit(): continue _, rva, name = cols # - The MSVC mangling has some type info following `@@` # - Any namespacing that can happen on the symbol appears as a # suffix, after a `@`. # - Mangled symbols are prefixed with `?`. name = name.split('@@')[0].split('@')[0].lstrip('?') yield { 'addr': int(rva, 16), 'size': 0, 'name': name, 'version': None, }
def check_nsmodules(target, binary): if target is HOST or not is_libxul(binary): raise Skip() symbols = [] if buildconfig.substs.get('_MSC_VER'): for line in get_output('dumpbin', '-exports', binary): data = line.split(None, 3) if data and len(data) == 4 and data[0].isdigit() and \ ishex(data[1]) and ishex(data[2]): # - Some symbols in the table can be aliases, and appear as # `foo = bar`. # - The MSVC mangling has some type info following `@@` # - Any namespacing that can happen on the symbol appears as a # suffix, after a `@`. # - Mangled symbols are prefixed with `?`. name = data[3].split(' = ')[0].split('@@')[0].split('@')[0] \ .lstrip('?') if name.endswith('_NSModule') or name in ( '__start_kPStaticModules', '__stop_kPStaticModules'): symbols.append((int(data[2], 16), GUESSED_NSMODULE_SIZE, name)) else: for line in get_output(target['nm'], '-P', binary): data = line.split() # Some symbols may not have a size listed at all. if len(data) == 3: data.append('0') if len(data) == 4: sym, _, addr, size = data # NSModules symbols end with _NSModule or _NSModuleE when # C++-mangled. if sym.endswith(('_NSModule', '_NSModuleE')): # On mac, nm doesn't actually print anything other than 0 # for the size. So take our best guess. size = int(size, 16) or GUESSED_NSMODULE_SIZE symbols.append((int(addr, 16), size, sym)) elif sym.endswith( ('__start_kPStaticModules', '__stop_kPStaticModules')): # On ELF and mac systems, these symbols have no size, such # that the first actual NSModule has the same address as # the start symbol. symbols.append((int(addr, 16), 0, sym)) if not symbols: raise RuntimeError('Could not find NSModules') def print_symbols(symbols): for addr, size, sym in symbols: print('%x %d %s' % (addr, size, sym)) symbols = sorted(symbols) next_addr = None # MSVC linker, when doing incremental linking, adds padding when # merging sections. Allow there to be more space between the NSModule # symbols, as long as they are in the right order. if buildconfig.substs.get('_MSC_VER') and \ buildconfig.substs.get('DEVELOPER_OPTIONS'): sym_cmp = lambda guessed, actual: guessed <= actual else: sym_cmp = lambda guessed, actual: guessed == actual for addr, size, sym in symbols: if next_addr is not None and not sym_cmp(next_addr, addr): print_symbols(symbols) raise RuntimeError('NSModules are not adjacent') next_addr = addr + size # The mac linker doesn't emit the start/stop symbols in the symbol table. # We'll just assume it did the job correctly. if get_type(binary) == MACHO: return first = symbols[0][2] last = symbols[-1][2] # On some platforms, there are extra underscores on symbol names. if first.lstrip('_') != 'start_kPStaticModules' or \ last.lstrip('_') != 'stop_kPStaticModules': print_symbols(symbols) syms = set(sym for add, size, sym in symbols) if 'start_kPStaticModules' not in syms: raise RuntimeError('Could not find start_kPStaticModules symbol') if 'stop_kPStaticModules' not in syms: raise RuntimeError('Could not find stop_kPStaticModules symbol') raise RuntimeError('NSModules are not ordered appropriately')
def check_nsmodules(target, binary): if target is HOST or not is_libxul(binary): raise Skip() symbols = [] for sym in iter_symbols(binary): if sym['addr'] == 0: continue name = sym['name'] # NSModules symbols end with _NSModule or _NSModuleE when C++-mangled. if name.endswith(('_NSModule', '_NSModuleE')): # We don't have a valid size in the symbol list for macho and coff. # Use our guesstimate. size = sym['size'] or GUESSED_NSMODULE_SIZE symbols.append((sym['addr'], size, name)) elif name in ('__start_kPStaticModules', '__stop_kPStaticModules'): # For coff, these symbols have a size. if get_type(binary) not in (ELF, MACHO): size = GUESSED_NSMODULE_SIZE else: size = 0 symbols.append((sym['addr'], size, name)) if not symbols: raise RuntimeError('Could not find NSModules') def print_symbols(symbols): for addr, size, sym in symbols: print('%x %d %s' % (addr, size, sym)) symbols = sorted(symbols) next_addr = None # MSVC linker, when doing incremental linking, adds padding when # merging sections. Allow there to be more space between the NSModule # symbols, as long as they are in the right order. test_msvc = (buildconfig.substs.get('CC_TYPE') in ('msvc', 'clang-cl') and \ buildconfig.substs.get('DEVELOPER_OPTIONS')) test_clang = (buildconfig.substs.get('CC_TYPE') == 'clang' and \ buildconfig.substs.get('OS_ARCH') == 'WINNT') if test_msvc or test_clang: sym_cmp = lambda guessed, actual: guessed <= actual else: sym_cmp = lambda guessed, actual: guessed == actual for addr, size, sym in symbols: if next_addr is not None and not sym_cmp(next_addr, addr): print_symbols(symbols) raise RuntimeError('NSModules are not adjacent') next_addr = addr + size # The mac linker doesn't emit the start/stop symbols in the symbol table. # We'll just assume it did the job correctly. if get_type(binary) == MACHO: return first = symbols[0][2] last = symbols[-1][2] # On some platforms, there are extra underscores on symbol names. if first.lstrip('_') != 'start_kPStaticModules' or \ last.lstrip('_') != 'stop_kPStaticModules': print_symbols(symbols) syms = set(sym for add, size, sym in symbols) if 'start_kPStaticModules' not in syms: raise RuntimeError('Could not find start_kPStaticModules symbol') if 'stop_kPStaticModules' not in syms: raise RuntimeError('Could not find stop_kPStaticModules symbol') raise RuntimeError('NSModules are not ordered appropriately')