Commit 66205b64 authored by Peter Collingbourne's avatar Peter Collingbourne Committed by Commit Bot

Only add runtime dependencies to the ordered libraries list.

We cannot find library dependencies to add to a target's ordered
libraries list by searching the build directory because the build
directory may contain libraries that appear to be dependencies but are
in fact unrelated libraries that share a name with a system library
that the target depends on. For example, we may be building a target
that depends on the system's libGLESv2.so, and the build directory may
contain a library named libGLESv2.so as a result of building ANGLE. The
resulting APK would try to load libGLESv2.so using the crazy linker,
which might fail to load the system's library.

The solution is to use GN's write_runtime_deps feature to export the
runtime dependency list from the build system and create an ordered
libraries list from that.

Bug: 742655
Change-Id: Ifdbf3de6b78b56af22dbfe0d12d80db5a48fe9db
Reviewed-on: https://chromium-review.googlesource.com/821600Reviewed-by: default avataragrieve <agrieve@chromium.org>
Commit-Queue: Peter Collingbourne <pcc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#523675}
parent a2e8edb8
...@@ -28,92 +28,65 @@ import sys ...@@ -28,92 +28,65 @@ import sys
from util import build_utils from util import build_utils
_readelf = None _readelf = None
_library_dirs = None
_library_re = re.compile( _library_re = re.compile(
'.*NEEDED.*Shared library: \[(?P<library_name>.+)\]') '.*NEEDED.*Shared library: \[(?P<library_name>.+)\]')
_library_path_map = {}
def SetReadelfPath(path): def SetReadelfPath(path):
global _readelf global _readelf
_readelf = path _readelf = path
def SetLibraryDirs(dirs):
global _library_dirs
_library_dirs = dirs
def FullLibraryPath(library_name):
assert _library_dirs is not None
for directory in _library_dirs:
path = '%s/%s' % (directory, library_name)
if os.path.exists(path):
return path
return library_name
def IsSystemLibrary(library_name):
# If the library doesn't exist in the libraries directory, assume that it is
# an Android system library.
return not os.path.exists(FullLibraryPath(library_name))
def CallReadElf(library_or_executable): def CallReadElf(library_or_executable):
assert _readelf is not None assert _readelf is not None
readelf_cmd = [_readelf, readelf_cmd = [_readelf, '-d', library_or_executable]
'-d',
FullLibraryPath(library_or_executable)]
return build_utils.CheckOutput(readelf_cmd) return build_utils.CheckOutput(readelf_cmd)
def GetDependencies(library_or_executable): def GetDependencies(library_or_executable):
elf = CallReadElf(library_or_executable) elf = CallReadElf(library_or_executable)
return set(_library_re.findall(elf)) deps = set()
for l in _library_re.findall(elf):
p = _library_path_map.get(l)
def GetNonSystemDependencies(library_name): if p is not None:
all_deps = GetDependencies(library_name) deps.add(p)
return set((lib for lib in all_deps if not IsSystemLibrary(lib))) return deps
def GetSortedTransitiveDependencies(libraries): def GetSortedTransitiveDependencies(libraries):
"""Returns all transitive library dependencies in dependency order.""" """Returns all transitive library dependencies in dependency order."""
return build_utils.GetSortedTransitiveDependencies( return build_utils.GetSortedTransitiveDependencies(
libraries, GetNonSystemDependencies) libraries, GetDependencies)
def GetSortedTransitiveDependenciesForBinaries(binaries):
if binaries[0].endswith('.so'):
libraries = [os.path.basename(lib) for lib in binaries]
else:
assert len(binaries) == 1
all_deps = GetDependencies(binaries[0])
libraries = [lib for lib in all_deps if not IsSystemLibrary(lib)]
return GetSortedTransitiveDependencies(libraries)
def main(): def main():
parser = optparse.OptionParser() parser = optparse.OptionParser()
build_utils.AddDepfileOption(parser) build_utils.AddDepfileOption(parser)
parser.add_option('--input-libraries',
help='A list of top-level input libraries.')
parser.add_option('--libraries-dir',
help='The directory which contains shared libraries.')
parser.add_option('--readelf', help='Path to the readelf binary.') parser.add_option('--readelf', help='Path to the readelf binary.')
parser.add_option('--runtime-deps',
help='A file created for the target using write_runtime_deps.')
parser.add_option('--output', help='Path to the generated .json file.') parser.add_option('--output', help='Path to the generated .json file.')
parser.add_option('--stamp', help='Path to touch on success.') parser.add_option('--stamp', help='Path to touch on success.')
options, _ = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:])) options, _ = parser.parse_args(build_utils.ExpandFileArgs(sys.argv[1:]))
SetReadelfPath(options.readelf) SetReadelfPath(options.readelf)
SetLibraryDirs(options.libraries_dir.split(','))
libraries = build_utils.ParseGnList(options.input_libraries) unsorted_lib_paths = []
if len(libraries): for f in open(options.runtime_deps):
libraries = GetSortedTransitiveDependenciesForBinaries(libraries) f = f[:-1]
if f.endswith('.so'):
p = f.replace('lib.unstripped/', '')
unsorted_lib_paths.append(p)
_library_path_map[os.path.basename(p)] = p
lib_paths = GetSortedTransitiveDependencies(unsorted_lib_paths)
libraries = [os.path.basename(l) for l in lib_paths]
# Convert to "base" library names: e.g. libfoo.so -> foo # Convert to "base" library names: e.g. libfoo.so -> foo
java_libraries_list = ( java_libraries_list = (
...@@ -121,7 +94,7 @@ def main(): ...@@ -121,7 +94,7 @@ def main():
out_json = { out_json = {
'libraries': libraries, 'libraries': libraries,
'lib_paths': [FullLibraryPath(l) for l in libraries], 'lib_paths': lib_paths,
'java_libraries_list': java_libraries_list 'java_libraries_list': java_libraries_list
} }
build_utils.WriteJson( build_utils.WriteJson(
......
...@@ -13,6 +13,11 @@ import("//build/toolchain/toolchain.gni") ...@@ -13,6 +13,11 @@ import("//build/toolchain/toolchain.gni")
assert(is_android) assert(is_android)
sanitizer_runtimes = []
if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) {
sanitizer_runtimes = [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-arm-android.so" ]
}
# Creates a dist directory for a native executable. # Creates a dist directory for a native executable.
# #
# Running a native executable on a device requires all the shared library # Running a native executable on a device requires all the shared library
...@@ -40,35 +45,34 @@ template("create_native_executable_dist") { ...@@ -40,35 +45,34 @@ template("create_native_executable_dist") {
_libraries_list = "${target_gen_dir}/${target_name}_library_dependencies.list" _libraries_list = "${target_gen_dir}/${target_name}_library_dependencies.list"
_runtime_deps_file = "$target_gen_dir/${target_name}.runtimedeps"
_runtime_deps_target_name = "${target_name}__runtime_deps"
group(_runtime_deps_target_name) {
forward_variables_from(invoker, [ "deps" ])
data = sanitizer_runtimes
write_runtime_deps = _runtime_deps_file
}
_find_deps_target_name = "${target_name}__find_library_dependencies" _find_deps_target_name = "${target_name}__find_library_dependencies"
# TODO(agrieve): Extract dependent libs from GN rather than readelf. # TODO(agrieve): Extract dependent libs from GN rather than readelf.
action(_find_deps_target_name) { action(_find_deps_target_name) {
forward_variables_from(invoker, [ "deps" ]) deps = invoker.deps + [ ":$_runtime_deps_target_name" ]
script = "//build/android/gyp/write_ordered_libraries.py" script = "//build/android/gyp/write_ordered_libraries.py"
depfile = "$target_gen_dir/$target_name.d" depfile = "$target_gen_dir/$target_name.d"
inputs = [ inputs = [
invoker.binary, invoker.binary,
_runtime_deps_file,
android_readelf, android_readelf,
] ]
outputs = [ outputs = [
_libraries_list, _libraries_list,
] ]
rebased_binaries = rebase_path([ invoker.binary ], root_build_dir)
_libraries_dir = rebase_path(root_shlib_dir, root_build_dir)
if (is_clang) {
_libraries_dir +=
"," +
rebase_path("$clang_base_path/lib/clang/$clang_version/lib/linux",
root_build_dir)
}
args = [ args = [
"--depfile", "--depfile",
rebase_path(depfile, root_build_dir), rebase_path(depfile, root_build_dir),
"--input-libraries=$rebased_binaries", "--runtime-deps",
"--libraries-dir", rebase_path(_runtime_deps_file, root_build_dir),
_libraries_dir,
"--output", "--output",
rebase_path(_libraries_list, root_build_dir), rebase_path(_libraries_list, root_build_dir),
"--readelf", "--readelf",
...@@ -1953,7 +1957,13 @@ if (enable_java_templates) { ...@@ -1953,7 +1957,13 @@ if (enable_java_templates) {
# not need this manual sorting step. # not need this manual sorting step.
action(_ordered_libraries_target) { action(_ordered_libraries_target) {
script = "//build/android/gyp/write_ordered_libraries.py" script = "//build/android/gyp/write_ordered_libraries.py"
deps = _native_libs_deps + [ ":$_build_config_target" ] deps = [
":${_template_name}__runtime_deps",
":$_build_config_target",
]
inputs = [
_runtime_deps_file,
]
outputs = [ outputs = [
_ordered_libraries_json, _ordered_libraries_json,
] ]
...@@ -1961,8 +1971,7 @@ if (enable_java_templates) { ...@@ -1961,8 +1971,7 @@ if (enable_java_templates) {
args = [ args = [
"--readelf=$_rebased_android_readelf", "--readelf=$_rebased_android_readelf",
"--output=$_rebased_ordered_libraries_json", "--output=$_rebased_ordered_libraries_json",
"--libraries-dir=.", "--runtime-deps=" + rebase_path(_runtime_deps_file, root_build_dir),
"--input-libraries=@FileArg($_rebased_build_config:native:libraries)",
] ]
} }
...@@ -2255,13 +2264,13 @@ if (enable_java_templates) { ...@@ -2255,13 +2264,13 @@ if (enable_java_templates) {
} }
} }
_extra_native_libs = [] _extra_native_libs = sanitizer_runtimes
_extra_native_libs_deps = [] _extra_native_libs_deps = []
assert(_extra_native_libs_deps == []) # Mark as used. assert(_extra_native_libs_deps == []) # Mark as used.
_extra_native_libs_even_when_incremental = [] _extra_native_libs_even_when_incremental = []
if (_native_libs_deps != []) { if (_native_libs_deps != []) {
if (_use_chromium_linker) { if (_use_chromium_linker) {
_extra_native_libs = _extra_native_libs +=
[ "$root_shlib_dir/libchromium_android_linker$shlib_extension" ] [ "$root_shlib_dir/libchromium_android_linker$shlib_extension" ]
_extra_native_libs_deps += _extra_native_libs_deps +=
[ "//base/android/linker:chromium_android_linker" ] [ "//base/android/linker:chromium_android_linker" ]
...@@ -2279,10 +2288,6 @@ if (enable_java_templates) { ...@@ -2279,10 +2288,6 @@ if (enable_java_templates) {
} }
} }
if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) {
_extra_native_libs += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-arm-android.so" ]
}
if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) { if (defined(invoker.loadable_modules) && invoker.loadable_modules != []) {
_extra_native_libs_even_when_incremental += invoker.loadable_modules _extra_native_libs_even_when_incremental += invoker.loadable_modules
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment