diff options
-rw-r--r-- | rules/apex/BUILD | 2 | ||||
-rw-r--r-- | rules/apex/apex.bzl | 62 | ||||
-rw-r--r-- | rules/apex/apex_test.bzl | 33 | ||||
-rw-r--r-- | rules/apex/toolchain.bzl | 6 | ||||
-rw-r--r-- | rules/cc/cc_stub_library.bzl | 14 | ||||
-rw-r--r-- | rules/partitions/partition.bzl | 7 | ||||
-rw-r--r-- | rules/staging_dir_builder.py | 137 | ||||
-rwxr-xr-x | rules/staging_dir_builder_test.sh | 6 | ||||
-rw-r--r-- | tests/apex/BUILD | 23 | ||||
-rw-r--r-- | tests/apex/minimal_apex_using.txt.golden | 151 |
10 files changed, 362 insertions, 79 deletions
diff --git a/rules/apex/BUILD b/rules/apex/BUILD index cf64c03e..2f1b4834 100644 --- a/rules/apex/BUILD +++ b/rules/apex/BUILD @@ -104,9 +104,11 @@ apex_toolchain( avbtool = "//external/avb:avbtool", conv_apex_manifest = "//system/apex/apexer:conv_apex_manifest", e2fsdroid = "//external/e2fsprogs/contrib/android:e2fsdroid", + gen_ndk_usedby_apex = "//build/soong/scripts:gen_ndk_usedby_apex.sh", jsonmodify = "//build/soong/scripts:jsonmodify", manifest_fixer = "//build/soong/scripts:manifest_fixer", mke2fs = "//external/e2fsprogs/misc:mke2fs", + readelf = "//prebuilts/clang/host/linux-x86:llvm-readelf", resize2fs = "//external/e2fsprogs/resize:resize2fs", sefcontext_compile = "//external/selinux/libselinux:sefcontext_compile", soong_zip = "//build/soong/zip/cmd:soong_zip", diff --git a/rules/apex/apex.bzl b/rules/apex/apex.bzl index be67933e..40733adc 100644 --- a/rules/apex/apex.bzl +++ b/rules/apex/apex.bzl @@ -39,6 +39,7 @@ ApexInfo = provider( "container_key_info": "Info of the container key provided as AndroidAppCertificateInfo.", "package_name": "APEX package name.", "backing_libs": "File containing libraries used by the APEX.", + "symbols_used_by_apex": "Symbol list used by this APEX.", }, ) @@ -302,6 +303,15 @@ def _run_apexer(ctx, apex_toolchain): # Arguments args = ctx.actions.args() args.add(file_mapping_file.path) + + # NOTE: When used as inputs to another sandboxed action, this directory + # artifact's inner files will be made up of symlinks. Ensure that the + # aforementioned action handles symlinks correctly (e.g. following + # symlinks). + staging_dir = ctx.actions.declare_directory(ctx.attr.name + "_staging_dir") + args.add(staging_dir.path) + + # start of apexer cmd args.add(apexer_files.executable.path) if ctx.attr._apexer_verbose[BuildSettingInfo].value: args.add("--verbose") @@ -358,7 +368,7 @@ def _run_apexer(ctx, apex_toolchain): elif ctx.attr.testonly: args.add("--test_only") - args.add("STAGING_DIR_PLACEHOLDER") + args.add(staging_dir.path) args.add(apex_output_file) inputs = [ @@ -387,17 +397,18 @@ def _run_apexer(ctx, apex_toolchain): ctx.actions.run( inputs = inputs, tools = tools, - outputs = [apex_output_file], + outputs = [apex_output_file, staging_dir], executable = ctx.executable._staging_dir_builder, arguments = [args], mnemonic = "Apexer", ) - return ( - apex_output_file, - requires_native_libs, - provides_native_libs, - _generate_apex_backing_file(ctx, backing_libs), + return struct( + unsigned_apex = apex_output_file, + requires_native_libs = requires_native_libs, + provides_native_libs = provides_native_libs, + backing_libs = _generate_apex_backing_file(ctx, backing_libs), + symbols_used_by_apex = _generate_symbols_used_by_apex(ctx, apex_toolchain, staging_dir), ) # Sign a file with signapk. @@ -454,11 +465,35 @@ def _run_apex_compression_tool(ctx, apex_toolchain, input_file, output_file_name ) return compressed_file +# Generate <module>_using.txt, which contains a list of versioned NDK symbols +# dynamically linked to by this APEX's contents. This is used for coverage +# checks. +def _generate_symbols_used_by_apex(ctx, apex_toolchain, staging_dir): + symbols_used_by_apex = ctx.actions.declare_file(ctx.attr.name + "_using.txt") + ctx.actions.run( + outputs = [symbols_used_by_apex], + inputs = [staging_dir], + tools = [ + apex_toolchain.readelf.files_to_run, + apex_toolchain.gen_ndk_usedby_apex.files_to_run, + ], + executable = apex_toolchain.gen_ndk_usedby_apex.files_to_run, + arguments = [ + staging_dir.path, + apex_toolchain.readelf.files_to_run.executable.path, + symbols_used_by_apex.path, + ], + progress_message = "Generating dynamic NDK symbol list used by the %s apex" % ctx.attr.name, + mnemonic = "ApexUsingNDKSymbolsForCoverage", + ) + return symbols_used_by_apex + # See the APEX section in the README on how to use this rule. def _apex_rule_impl(ctx): apex_toolchain = ctx.toolchains["//build/bazel/rules/apex:apex_toolchain_type"].toolchain_info - unsigned_apex, requires_native_libs, provides_native_libs, backing_file = _run_apexer(ctx, apex_toolchain) + apexer_outputs = _run_apexer(ctx, apex_toolchain) + unsigned_apex = apexer_outputs.unsigned_apex apex_cert_info = ctx.attr.certificate[AndroidAppCertificateInfo] private_key = apex_cert_info.pk8 @@ -473,17 +508,22 @@ def _apex_rule_impl(ctx): _run_signapk(ctx, compressed_apex_output_file, signed_capex, private_key, public_key, "BazelCompressedApexSigning") apex_key_info = ctx.attr.key[ApexKeyInfo] + return [ DefaultInfo(files = depset([signed_apex])), ApexInfo( signed_output = signed_apex, unsigned_output = unsigned_apex, - requires_native_libs = requires_native_libs, - provides_native_libs = provides_native_libs, + requires_native_libs = apexer_outputs.requires_native_libs, + provides_native_libs = apexer_outputs.provides_native_libs, bundle_key_info = apex_key_info, container_key_info = apex_cert_info, package_name = ctx.attr.package_name, - backing_libs = backing_file, + backing_libs = apexer_outputs.backing_libs, + symbols_used_by_apex = apexer_outputs.symbols_used_by_apex, + ), + OutputGroupInfo( + coverage_files = [apexer_outputs.symbols_used_by_apex], ), ] diff --git a/rules/apex/apex_test.bzl b/rules/apex/apex_test.bzl index 755c741f..33e25a59 100644 --- a/rules/apex/apex_test.bzl +++ b/rules/apex/apex_test.bzl @@ -1412,6 +1412,38 @@ def _test_apex_backing_file(): return test_name +def _apex_symbols_used_by_apex_test(ctx): + env = analysistest.begin(ctx) + target_under_test = analysistest.target_under_test(env) + actual = target_under_test[ApexInfo].symbols_used_by_apex + + asserts.equals(env, ctx.attr.expected_path, actual.short_path) + + return analysistest.end(env) + +apex_symbols_used_by_apex_test = analysistest.make( + _apex_symbols_used_by_apex_test, + attrs = { + "expected_path": attr.string(), + }, +) + +def _test_apex_symbols_used_by_apex(): + name = "apex_with_symbols_used_by_apex" + test_name = name + "_test" + + test_apex( + name = name, + ) + + apex_symbols_used_by_apex_test( + name = test_name, + target_under_test = name, + expected_path = "build/bazel/rules/apex/apex_with_symbols_used_by_apex_using.txt", + ) + + return test_name + def apex_test_suite(name): native.test_suite( name = name, @@ -1445,5 +1477,6 @@ def apex_test_suite(name): _test_apex_testonly_with_manifest(), _test_apex_testonly_without_manifest(), _test_apex_backing_file(), + _test_apex_symbols_used_by_apex(), ], ) diff --git a/rules/apex/toolchain.bzl b/rules/apex/toolchain.bzl index 747089f4..756357d2 100644 --- a/rules/apex/toolchain.bzl +++ b/rules/apex/toolchain.bzl @@ -30,6 +30,8 @@ ApexToolchainInfo = provider( "soong_zip", "jsonmodify", "manifest_fixer", + "gen_ndk_usedby_apex", + "readelf", ], ) @@ -49,6 +51,8 @@ def _apex_toolchain_impl(ctx): soong_zip = ctx.file.soong_zip, jsonmodify = ctx.attr.jsonmodify, manifest_fixer = ctx.attr.manifest_fixer, + gen_ndk_usedby_apex = ctx.attr.gen_ndk_usedby_apex, + readelf = ctx.attr.readelf, ), ) return [toolchain_info] @@ -72,5 +76,7 @@ apex_toolchain = rule( # and has been added to apex toolchain previously. "soong_zip": attr.label(allow_single_file = True, cfg = "exec", executable = True, mandatory = True), "manifest_fixer": attr.label(cfg = "exec", executable = True, mandatory = True), + "gen_ndk_usedby_apex": attr.label(cfg = "exec", executable = True, mandatory = True, allow_single_file = [".sh"]), + "readelf": attr.label(cfg = "exec", executable = True, mandatory = True, allow_single_file = True), }, ) diff --git a/rules/cc/cc_stub_library.bzl b/rules/cc/cc_stub_library.bzl index ecb6dbad..2f579cbb 100644 --- a/rules/cc/cc_stub_library.bzl +++ b/rules/cc/cc_stub_library.bzl @@ -69,6 +69,9 @@ def _cc_stub_gen_impl(ctx): abi_symbol_list = out_abi_symbol_list, version = ctx.attr.version, ), + OutputGroupInfo( + stub_map = [out_stub_map], + ), ] cc_stub_gen = rule( @@ -142,9 +145,18 @@ def cc_stub_library_shared(name, stubs_symbol_file, version, export_includes, so if len(soname) == 0: fail("For stub libraries 'soname' is mandatory and must be same as the soname of its source library.") soname_flag = "-Wl,-soname," + soname + stub_map = name + "_stub_map" + native.filegroup( + name = stub_map, + srcs = [name + "_files"], + output_group = "stub_map", + tags = ["manual"], + ) + version_script_flag = "-Wl,--version-script,$(location %s)" % stub_map native.cc_shared_library( name = name + "_so", - user_link_flags = [soname_flag], + additional_linker_inputs = [stub_map], + user_link_flags = [soname_flag, version_script_flag], roots = [name + "_root"], features = disable_crt_link(features), target_compatible_with = target_compatible_with, diff --git a/rules/partitions/partition.bzl b/rules/partitions/partition.bzl index 6bf0acaf..0e455aa8 100644 --- a/rules/partitions/partition.bzl +++ b/rules/partitions/partition.bzl @@ -312,6 +312,8 @@ def _partition_impl(ctx): # It seems build_image will prepend /system to the paths when building_system_image=true ctx.actions.write(file_mapping_file, json.encode({k.removeprefix("/system"): v.path for k, v in files.items()})) + staging_dir = ctx.actions.declare_directory(ctx.attr.name + "_staging_dir") + ctx.actions.run( inputs = [ image_info, @@ -326,11 +328,12 @@ def _partition_impl(ctx): executable = ctx.executable._staging_dir_builder, arguments = [ file_mapping_file.path, + staging_dir.path, toolchain.build_image.path, - "STAGING_DIR_PLACEHOLDER", + staging_dir.path, image_info.path, output_image.path, - "STAGING_DIR_PLACEHOLDER", + staging_dir.path, ], mnemonic = "BuildPartition", # TODO: the /usr/bin addition is because build_image uses the du command diff --git a/rules/staging_dir_builder.py b/rules/staging_dir_builder.py index 6961c760..a5bcee9e 100644 --- a/rules/staging_dir_builder.py +++ b/rules/staging_dir_builder.py @@ -19,32 +19,26 @@ import os import shutil import subprocess import sys -import tempfile +import argparse -def main(argv): - '''Build a staging directory, and then call a custom command. +def build_staging_dir(file_mapping_path, staging_dir_path, command_argv): + '''Create a staging dir with provided file mapping and apply the command in the dir. - The first argument to this script must be the path to a file containing a json - dictionary mapping paths in the staging directory to paths to files that should - be copied there. The rest of the arguments will be run as a separate command. - At least one other argument must be "STAGING_DIR_PLACEHOLDER", which will be - replaced with the path to the staging directory. + At least - Example: - staging_dir_builder file_mapping.json path/to/apexer --various-apexer-flags STAGING_DIR_PLACEHOLDER path/to/out.apex.unsigned + Args: + file_mapping_path (str): path to the file mapping json + staging_dir_path (str): path to the staging directory + command_argv (str list): the command to be executed, with the first arg as the executable ''' - if len(argv) < 2: - sys.exit('usage: staging_dir_builder MAPPING_FILE COMMAND...') - if "STAGING_DIR_PLACEHOLDER" not in argv[1:]: - sys.exit('At least one argument must be "STAGING_DIR_PLACEHOLDER"') try: - with open(argv[0], 'r') as f: + with open(file_mapping_path, 'r') as f: file_mapping = json.load(f) except OSError as e: sys.exit(str(e)) except json.JSONDecodeError as e: - sys.exit(argv[0] + ": JSON decode error: " + str(e)) + sys.exit(file_mapping_path + ": JSON decode error: " + str(e)) # Validate and clean the file_mapping. This consists of: # - Making sure it's a dict[str, str] @@ -53,10 +47,10 @@ def main(argv): # - Making sure no paths use .. to break out of the staging dir cleaned_file_mapping = {} if not isinstance(file_mapping, dict): - sys.exit(argv[0] + ": expected a JSON dict[str, str]") + sys.exit(file_mapping_path + ": expected a JSON dict[str, str]") for path_in_staging_dir, path_in_bazel in file_mapping.items(): if not isinstance(path_in_staging_dir, str) or not isinstance(path_in_bazel, str): - sys.exit(argv[0] + ": expected a JSON dict[str, str]") + sys.exit(file_mapping_path + ": expected a JSON dict[str, str]") path_in_staging_dir = os.path.normpath(path_in_staging_dir).lstrip('/') if path_in_staging_dir in cleaned_file_mapping: sys.exit("Staging dir path repeated twice: " + path_in_staging_dir) @@ -65,57 +59,72 @@ def main(argv): cleaned_file_mapping[path_in_staging_dir] = path_in_bazel file_mapping = cleaned_file_mapping - argv = argv[1:] - - with tempfile.TemporaryDirectory() as staging_dir: - for path_in_staging_dir, path_in_bazel in file_mapping.items(): - path_in_staging_dir = os.path.join(staging_dir, path_in_staging_dir) - - # Because Bazel execution root is a symlink forest, all the input files are symlinks, these - # include the dependency files declared in the BUILD files as well as the files declared - # and created in the bzl files. For sandbox runs the former are two or more level symlinks and - # latter are one level symlinks. For non-sandbox runs, the former are one level symlinks - # and the latter are actual files. Here are some examples: - # - # Two level symlinks: - # system/timezone/output_data/version/tz_version -> - # /usr/local/google/home/...out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ - # execroot/__main__/system/timezone/output_data/version/tz_version -> - # /usr/local/google/home/.../system/timezone/output_data/version/tz_version - # - # Three level symlinks: - # bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so -> - # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ - # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so -> - # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ - # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/ - # liblibcrypto_stripped.so -> - # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ - # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/ - # liblibcrypto_unstripped.so - # - # One level symlinks: - # bazel-out/android_target-fastbuild/bin/system/timezone/apex/apex_manifest.pb -> - # /usr/local/google/home/.../out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ - # execroot/__main__/bazel-out/android_target-fastbuild/bin/system/timezone/apex/ - # apex_manifest.pb - if os.path.islink(path_in_bazel): - path_in_bazel = os.readlink(path_in_bazel) + for path_in_staging_dir, path_in_bazel in file_mapping.items(): + path_in_staging_dir = os.path.join(staging_dir_path, path_in_staging_dir) - # For sandbox run these are the 2nd level symlinks and we need to resolve - while os.path.islink(path_in_bazel) and 'execroot/__main__' in path_in_bazel: - path_in_bazel = os.readlink(path_in_bazel) + # Because Bazel execution root is a symlink forest, all the input files are symlinks, these + # include the dependency files declared in the BUILD files as well as the files declared + # and created in the bzl files. For sandbox runs the former are two or more level symlinks and + # latter are one level symlinks. For non-sandbox runs, the former are one level symlinks + # and the latter are actual files. Here are some examples: + # + # Two level symlinks: + # system/timezone/output_data/version/tz_version -> + # /usr/local/google/home/...out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ + # execroot/__main__/system/timezone/output_data/version/tz_version -> + # /usr/local/google/home/.../system/timezone/output_data/version/tz_version + # + # Three level symlinks: + # bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so -> + # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ + # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/libcrypto.so -> + # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ + # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/ + # liblibcrypto_stripped.so -> + # /usr/local/google/home/yudiliu/android/aosp/master/out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ + # execroot/__main__/bazel-out/android_x86_64-fastbuild-ST-4ecd5e98bfdd/bin/external/boringssl/ + # liblibcrypto_unstripped.so + # + # One level symlinks: + # bazel-out/android_target-fastbuild/bin/system/timezone/apex/apex_manifest.pb -> + # /usr/local/google/home/.../out/bazel/output_user_root/b1ed7e1e9af3ebbd1403e9cf794e4884/ + # execroot/__main__/bazel-out/android_target-fastbuild/bin/system/timezone/apex/ + # apex_manifest.pb + if os.path.islink(path_in_bazel): + path_in_bazel = os.readlink(path_in_bazel) - os.makedirs(os.path.dirname(path_in_staging_dir), exist_ok=True) - shutil.copyfile(path_in_bazel, path_in_staging_dir, follow_symlinks=False) + # For sandbox run these are the 2nd level symlinks and we need to resolve + while os.path.islink(path_in_bazel) and 'execroot/__main__' in path_in_bazel: + path_in_bazel = os.readlink(path_in_bazel) - for i in range(len(argv)): - if argv[i] == 'STAGING_DIR_PLACEHOLDER': - argv[i] = staging_dir + os.makedirs(os.path.dirname(path_in_staging_dir), exist_ok=True) + shutil.copyfile(path_in_bazel, path_in_staging_dir, follow_symlinks=False) - result = subprocess.run(argv) + result = subprocess.run(command_argv) sys.exit(result.returncode) +def main(): + '''Build a staging directory, and then call a custom command. + + The first argument to this script must be the path to a file containing a json + dictionary mapping paths in the staging directory to paths to files that should + be copied there. The rest of the arguments will be run as a separate command. + + Example: + staging_dir_builder file_mapping.json path/to/staging_dir path/to/apexer --various-apexer-flags path/to/out.apex.unsigned + ''' + parser = argparse.ArgumentParser() + parser.add_argument( + "file_mapping_path", + help="Path to the <staging dir path>:<bazel input path> file mapping JSON.", + ) + parser.add_argument( + "staging_dir_path", + help="Path to a directory to store the staging directory content.", + ) + args, command_argv = parser.parse_known_args() + build_staging_dir(args.file_mapping_path, args.staging_dir_path, command_argv) + if __name__ == '__main__': - main(sys.argv[1:]) + main() diff --git a/rules/staging_dir_builder_test.sh b/rules/staging_dir_builder_test.sh index 148e79d3..27d3505d 100755 --- a/rules/staging_dir_builder_test.sh +++ b/rules/staging_dir_builder_test.sh @@ -104,11 +104,15 @@ echo "/ 0 2000 0755 apexer_tool_paths=${avb_tool_path}:${avb_tool_path}:${e2fsdroid_path}:${mke2fs_path}:${resize2fs_path}:${debugfs_path}:${soong_zip_path}:${aapt2_path}:${sefcontext_compile_path} +staging_dir=$(mktemp -d /tmp/temporary-dir.XXXXXXXX) +trap 'rm -rf -- "${staging_dir}"' EXIT + ############################################# # run staging_dir_builder ############################################# "${RUNFILES_DIR}/__main__/build/bazel/rules/staging_dir_builder" \ ${staging_dir_builder_manifest_file} \ + ${staging_dir} \ ${apexer_tool_path} \ --manifest ${manifest_file} \ --file_contexts ${file_contexts_file} \ @@ -116,7 +120,7 @@ apexer_tool_paths=${avb_tool_path}:${avb_tool_path}:${e2fsdroid_path}:${mke2fs_p --apexer_tool_path "${apexer_tool_paths}" \ --android_jar_path ${android_jar} \ --canned_fs_config ${canned_fs_config} \ - STAGING_DIR_PLACEHOLDER \ + ${staging_dir} \ ${output_file} ############################################# diff --git a/tests/apex/BUILD b/tests/apex/BUILD index 3f295f34..c31445d7 100644 --- a/tests/apex/BUILD +++ b/tests/apex/BUILD @@ -62,3 +62,26 @@ diff_test( file2 = "com.android.adbd.apex_manifest.json.golden", target_compatible_with = ["//build/bazel/platforms/os:linux"], ) + +filegroup( + name = "minimal_apex_coverage_files", + srcs = ["//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal"], + output_group = "coverage_files", +) + +genrule( + name = "minimal_apex_using_txt", + srcs = [":minimal_apex_coverage_files"], + outs = ["minimal_apex_using.txt"], + cmd = "cat $(location :minimal_apex_coverage_files) | sort > $@", +) + +diff_test( + name = "minimal_apex_symbols_used_by_apex_diff_test", + file1 = ":minimal_apex_using.txt", + file2 = ":minimal_apex_using.txt.golden", + target_compatible_with = [ + "//build/bazel/platforms/os:android", + "//build/bazel/platforms/arch:arm64", + ], +) diff --git a/tests/apex/minimal_apex_using.txt.golden b/tests/apex/minimal_apex_using.txt.golden new file mode 100644 index 00000000..c3a1d94d --- /dev/null +++ b/tests/apex/minimal_apex_using.txt.golden @@ -0,0 +1,151 @@ + +_Unwind_DeleteException@LIBC_R +_Unwind_GetIP@LIBC_R +_Unwind_GetLanguageSpecificData@LIBC_R +_Unwind_GetRegionStart@LIBC_R +_Unwind_RaiseException@LIBC_R +_Unwind_Resume@LIBC_R +_Unwind_SetGR@LIBC_R +_Unwind_SetIP@LIBC_R +__ctype_get_mb_cur_max@LIBC +__cxa_atexit@LIBC +__cxa_finalize@LIBC +__cxa_finalize@LIBC +__cxa_finalize@LIBC +__cxa_finalize@LIBC +__cxa_thread_atexit_impl@LIBC +__errno@LIBC +__fwrite_chk@LIBC_N +__gnu_strerror_r@LIBC +__libc_init@LIBC +__open_2@LIBC +__read_chk@LIBC +__stack_chk_fail@LIBC +__stack_chk_fail@LIBC +__stack_chk_fail@LIBC +__stack_chk_fail@LIBC +__stack_chk_fail@LIBC +__strlen_chk@LIBC +__system_property_get@LIBC +__vsnprintf_chk@LIBC +abort@LIBC +android_set_abort_message@LIBC +btowc@LIBC +calloc@LIBC +clock_gettime@LIBC +close@LIBC +closelog@LIBC +fflush@LIBC +fprintf@LIBC +fputc@LIBC +free@LIBC +freelocale@LIBC +fwrite@LIBC +getauxval@LIBC +getc@LIBC +iswalpha@LIBC +iswblank@LIBC +iswcntrl@LIBC +iswdigit@LIBC +iswlower@LIBC +iswprint@LIBC +iswpunct@LIBC +iswspace@LIBC +iswupper@LIBC +iswxdigit@LIBC +localeconv@LIBC +malloc@LIBC +mbrlen@LIBC +mbrtowc@LIBC +mbsnrtowcs@LIBC +mbsrtowcs@LIBC +mbtowc@LIBC +memchr@LIBC +memcmp@LIBC +memcpy@LIBC +memmove@LIBC +memset@LIBC +memset@LIBC +memset@LIBC +memset@LIBC +memset@LIBC +nanosleep@LIBC +newlocale@LIBC +openlog@LIBC +posix_memalign@LIBC +pthread_cond_broadcast@LIBC +pthread_cond_destroy@LIBC +pthread_cond_signal@LIBC +pthread_cond_timedwait@LIBC +pthread_cond_wait@LIBC +pthread_detach@LIBC +pthread_equal@LIBC +pthread_getspecific@LIBC +pthread_join@LIBC +pthread_key_create@LIBC +pthread_mutex_destroy@LIBC +pthread_mutex_init@LIBC +pthread_mutex_lock@LIBC +pthread_mutex_trylock@LIBC +pthread_mutex_unlock@LIBC +pthread_mutexattr_destroy@LIBC +pthread_mutexattr_init@LIBC +pthread_mutexattr_settype@LIBC +pthread_once@LIBC +pthread_self@LIBC +pthread_setspecific@LIBC +realloc@LIBC +sched_yield@LIBC +setlocale@LIBC +snprintf@LIBC +sscanf@LIBC +strcmp@LIBC +strcoll@LIBC +strftime@LIBC +strlen@LIBC +strlen@LIBC +strlen@LIBC +strlen@LIBC +strncmp@LIBC +strtod@LIBC +strtod_l@LIBC_O +strtof@LIBC +strtof_l@LIBC_O +strtol@LIBC +strtold@LIBC +strtold_l@LIBC +strtoll@LIBC +strtoll_l@LIBC +strtoul@LIBC +strtoull@LIBC +strtoull_l@LIBC +strxfrm@LIBC +swprintf@LIBC +sysconf@LIBC +syslog@LIBC +towlower@LIBC +towupper@LIBC +ungetc@LIBC +uselocale@LIBC +vasprintf@LIBC +vfprintf@LIBC +vsnprintf@LIBC +vsscanf@LIBC +wcrtomb@LIBC +wcscoll@LIBC +wcslen@LIBC +wcsnrtombs@LIBC +wcstod@LIBC +wcstof@LIBC +wcstol@LIBC +wcstold@LIBC +wcstoll@LIBC +wcstoul@LIBC +wcstoull@LIBC +wcsxfrm@LIBC +wctob@LIBC +wmemchr@LIBC +wmemcmp@LIBC +wmemcpy@LIBC +wmemmove@LIBC +wmemset@LIBC |