diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/build/rust/std | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/build/rust/std')
-rw-r--r-- | third_party/libwebrtc/build/rust/std/BUILD.gn | 153 | ||||
-rwxr-xr-x | third_party/libwebrtc/build/rust/std/find_std_rlibs.py | 97 | ||||
-rw-r--r-- | third_party/libwebrtc/build/rust/std/immediate_crash.h | 170 | ||||
-rw-r--r-- | third_party/libwebrtc/build/rust/std/remap_alloc.c | 70 |
4 files changed, 490 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/rust/std/BUILD.gn b/third_party/libwebrtc/build/rust/std/BUILD.gn new file mode 100644 index 0000000000..7532439364 --- /dev/null +++ b/third_party/libwebrtc/build/rust/std/BUILD.gn @@ -0,0 +1,153 @@ +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This file provides the ability for our C++ toolchain to successfully +# link binaries containing arbitrary Rust code. +# +# By "arbitrary Rust code" I mean .rlib archives full of Rust code, which +# is actually a static archive. +# +# Those static libraries don't link as-is into a final executable because +# they're designed for downstream processing by further invocations of rustc +# which link into a final binary. That final invocation of rustc knows how +# to do two things: +# * Find the Rust standard library. +# * Remap some generic allocator symbols to the specific allocator symbols +# in use. +# This file does both those things. Any C++ target containing Rust .rlibs +# should simply depend on :std within this file and it will be taken care of. +# In practice, this will in future be taken care of by a standard template +# used for each Rust source set, so that a typical user of Rust need not +# think about it. +# +# This is obviously a bit fragile - rustc might do other magic in future. +# But, linking with a final C++ toolchain is something often needed, and +# https://github.com/rust-lang/rust/issues/64191 aims to make this +# officially possible. + +import("//build/config/compiler/compiler.gni") +import("//build/config/rust.gni") + +stdlib_files = [ + "std", # List first because it makes depfiles more debuggable (see below) + "addr2line", + "adler", + "alloc", + "cfg_if", + "compiler_builtins", + "core", + "getopts", + "gimli", + "hashbrown", + "libc", + "miniz_oxide", + "object", + "panic_abort", + "panic_unwind", + "proc_macro", + "rustc_demangle", + "std_detect", + "term", + "test", + "unicode_width", + "unwind", +] + +if (!use_unverified_rust_toolchain) { + # rlib files which are distributed alongside Rust's prebuilt stdlib, but we + # don't need to pass to the C++ linker because they're used for specialized + # purposes. + skip_stdlib_files = [ + "profiler_builtins", + "rustc_std_workspace_alloc", + "rustc_std_workspace_core", + "rustc_std_workspace_std", + ] +} + +if (toolchain_has_rust) { + action("find_stdlib") { + # Specifics of what we're doing here. + # + # We are using prebuilt Rust rlibs supplied along with the toolchain. + # The Rust standard library consists of rlibs with roughly all the names + # above. + # + # However, their filenames are not predictable, and therefore we can't + # have ninja rules which depend upon them. (gn offers a facility to + # build rules dynamically, but it's frowned upon because a script needs + # to run each time). + # + # Instead therefore we copy these unpredictable .rlib paths to apredictable + # location. That's what this script does. Furthermore, it generates a + # .d file in order to teach Ninja that it only needs to do this copying + # once, unless the source .rlibs change. + # + # The script accepts the list of known libraries and will raise an + # exception if the list on disk differs. (Either 'Found stdlib rlib + # that wasn't expected' or 'We failed to find all expected stdlib + # rlibs'). + script = "find_std_rlibs.py" + depfile = "$target_out_dir/stdlib.d" + out_libdir = rebase_path(target_out_dir, root_build_dir) + out_depfile = rebase_path(depfile, root_build_dir) + args = [ + "--rust-bin-dir", + rust_prefix, + "--output", + out_libdir, + "--depfile", + out_depfile, + + # Due to limitations in Ninja's handling of .d files, we have to pick + # *the first* of our outputs. To make diagnostics more obviously + # related to the Rust standard library, we ensure libstd.rlib is first. + "--depfile-target", + stdlib_files[0], + ] + if (!use_unverified_rust_toolchain) { + args += [ + "--stdlibs", + string_join(",", stdlib_files), + "--skip", + string_join(",", skip_stdlib_files), + ] + } + if (rust_abi_target != "") { + args += [ + "--target", + rust_abi_target, + ] + } + + outputs = [] + foreach(lib, stdlib_files) { + outputs += [ "$target_out_dir/lib$lib.rlib" ] + } + } + + config("rust_stdlib_config") { + ldflags = [] + out_libdir = rebase_path(target_out_dir, root_build_dir) + foreach(lib, stdlib_files) { + this_file = "$out_libdir/lib$lib.rlib" + ldflags += [ this_file ] + } + } + + source_set("remap_alloc") { + sources = [ + "immediate_crash.h", + "remap_alloc.c", + ] + } + + group("std") { + all_dependent_configs = [ ":rust_stdlib_config" ] + deps = [ + ":find_stdlib", + ":remap_alloc", + ] + } +} diff --git a/third_party/libwebrtc/build/rust/std/find_std_rlibs.py b/third_party/libwebrtc/build/rust/std/find_std_rlibs.py new file mode 100755 index 0000000000..b8f775e438 --- /dev/null +++ b/third_party/libwebrtc/build/rust/std/find_std_rlibs.py @@ -0,0 +1,97 @@ +#!/usr/bin/env/python3 + +# Copyright 2021 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# See BUILD.gn in this directory for an explanation of what this script is for. + +import argparse +import os +import sys +import shutil +import subprocess +import re + +REMOVE_METADATA_SUFFIX_RE = re.compile(b"-[0-9a-f]*", re.I) + + +def expand_name(concise_name): + return "lib%s.rlib" % concise_name + + +def main(): + parser = argparse.ArgumentParser("find_std_rlibs.py") + parser.add_argument("--rust-bin-dir", + help="Path to Rust binaries", + required=True), + parser.add_argument("--target", help="Rust target triple", required=False), + parser.add_argument("--output", + help="Path to rlibs without suffixes", + required=True) + parser.add_argument("--depfile", help="Path to write depfile", required=True) + parser.add_argument("--depfile-target", + help="Target to key depfile around", + required=True) + parser.add_argument("--stdlibs", + help="Expected list of standard library libraries") + parser.add_argument("--skip-stdlibs", + help="Standard library files to skip", + default="") + args = parser.parse_args() + # Ensure we handle each rlib in the expected list exactly once. + if args.stdlibs: + rlibs_expected = [expand_name(x) for x in args.stdlibs.split(',')] + else: + rlibs_expected = None + rlibs_to_skip = [expand_name(x) for x in args.skip_stdlibs.split(',')] + # Ask rustc where to find the stdlib for this target. + rustc = os.path.join(args.rust_bin_dir, "rustc") + rustc_args = [rustc, "--print", "target-libdir"] + if args.target: + rustc_args.extend(["--target", args.target]) + rustlib_dir = subprocess.check_output(rustc_args).rstrip() + # Copy the rlibs to a predictable location. Whilst we're doing so, + # also write a .d file so that ninja knows it doesn't need to do this + # again unless the source rlibs change. + # Format: + # <output path to>/lib<lib name.rlib>: <path to each Rust stlib rlib> + with open(args.depfile, 'w') as depfile: + # Ninja isn't versatile at understanding depfiles. We have to say that a + # single output depends on all the inputs. We choose any one of the + # output rlibs for that purpose. If any of the input rlibs change, ninja + # will run this script again and we'll copy them all afresh. + depfile.write("%s:" % + (os.path.join(args.output, expand_name(args.depfile_target)))) + for f in os.listdir(rustlib_dir): + if f.endswith(b'.rlib'): + # As standard Rust includes a hash on the end of each filename + # representing certain metadata, to ensure that clients will link + # against the correct version. As gn will be manually passing + # the correct file path to our linker invocations, we don't need + # that, and it would prevent us having the predictable filenames + # which we need for statically computable gn dependency rules. + (concise_name, count) = REMOVE_METADATA_SUFFIX_RE.subn(b"", f) + if count == 0: + raise Exception("Unable to remove suffix from %s" % f) + if concise_name.decode() in rlibs_to_skip: + continue + if rlibs_expected is not None: + if concise_name.decode() not in rlibs_expected: + raise Exception("Found stdlib rlib that wasn't expected: %s" % + concise_name) + rlibs_expected.remove(concise_name.decode()) + infile = os.path.join(rustlib_dir, f) + outfile = os.path.join(str.encode(args.output), concise_name) + depfile.write(" %s" % (infile.decode())) + if (not os.path.exists(outfile) + or os.stat(infile).st_mtime > os.stat(outfile).st_mtime): + shutil.copy(infile, outfile) + depfile.write("\n") + if rlibs_expected: + raise Exception("We failed to find all expected stdlib rlibs: %s" % + ','.join(rlibs_expected)) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/third_party/libwebrtc/build/rust/std/immediate_crash.h b/third_party/libwebrtc/build/rust/std/immediate_crash.h new file mode 100644 index 0000000000..9874bdcd48 --- /dev/null +++ b/third_party/libwebrtc/build/rust/std/immediate_crash.h @@ -0,0 +1,170 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is copied from //base/immediate_crash.h. + +#ifndef BUILD_RUST_STD_IMMEDIATE_CRASH_H_ +#define BUILD_RUST_STD_IMMEDIATE_CRASH_H_ + +#include "build/build_config.h" + +// Crashes in the fastest possible way with no attempt at logging. +// There are several constraints; see http://crbug.com/664209 for more context. +// +// - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the +// resulting exception or simply hit 'continue' to skip over it in a debugger. +// - Different instances of TRAP_SEQUENCE_() must not be folded together, to +// ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile +// blocks will not be folded together. +// Note: TRAP_SEQUENCE_() previously required an instruction with a unique +// nonce since unlike clang, GCC folds together identical asm volatile +// blocks. +// - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid +// memory access. +// - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions. +// __builtin_unreachable() is used to provide that hint here. clang also uses +// this as a heuristic to pack the instructions in the function epilogue to +// improve code density. +// +// Additional properties that are nice to have: +// - TRAP_SEQUENCE_() should be as compact as possible. +// - The first instruction of TRAP_SEQUENCE_() should not change, to avoid +// shifting crash reporting clusters. As a consequence of this, explicit +// assembly is preferred over intrinsics. +// Note: this last bullet point may no longer be true, and may be removed in +// the future. + +// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact +// that clang emits an actual instruction for __builtin_unreachable() on certain +// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will +// be removed in followups, so splitting it up like this now makes it easy to +// land the followups. + +#if defined(COMPILER_GCC) + +#if defined(OS_NACL) + +// Crash report accuracy is not guaranteed on NaCl. +#define TRAP_SEQUENCE1_() __builtin_trap() +#define TRAP_SEQUENCE2_() asm volatile("") + +#elif defined(ARCH_CPU_X86_FAMILY) + +// TODO(https://crbug.com/958675): In theory, it should be possible to use just +// int3. However, there are a number of crashes with SIGILL as the exception +// code, so it seems likely that there's a signal handler that allows execution +// to continue after SIGTRAP. +#define TRAP_SEQUENCE1_() asm volatile("int3") + +#if defined(OS_APPLE) +// Intentionally empty: __builtin_unreachable() is always part of the sequence +// (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac. +#define TRAP_SEQUENCE2_() asm volatile("") +#else +#define TRAP_SEQUENCE2_() asm volatile("ud2") +#endif // defined(OS_APPLE) + +#elif defined(ARCH_CPU_ARMEL) + +// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running +// as a 32 bit userspace app on arm64. There doesn't seem to be any way to +// cause a SIGTRAP from userspace without using a syscall (which would be a +// problem for sandboxing). +// TODO(https://crbug.com/958675): Remove bkpt from this sequence. +#define TRAP_SEQUENCE1_() asm volatile("bkpt #0") +#define TRAP_SEQUENCE2_() asm volatile("udf #0") + +#elif defined(ARCH_CPU_ARM64) + +// This will always generate a SIGTRAP on arm64. +// TODO(https://crbug.com/958675): Remove brk from this sequence. +#define TRAP_SEQUENCE1_() asm volatile("brk #0") +#define TRAP_SEQUENCE2_() asm volatile("hlt #0") + +#else + +// Crash report accuracy will not be guaranteed on other architectures, but at +// least this will crash as expected. +#define TRAP_SEQUENCE1_() __builtin_trap() +#define TRAP_SEQUENCE2_() asm volatile("") + +#endif // ARCH_CPU_* + +#elif defined(COMPILER_MSVC) + +#if !defined(__clang__) + +// MSVC x64 doesn't support inline asm, so use the MSVC intrinsic. +#define TRAP_SEQUENCE1_() __debugbreak() +#define TRAP_SEQUENCE2_() + +#elif defined(ARCH_CPU_ARM64) + +// Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and +// __debugbreak() generates that in both VC++ and clang. +#define TRAP_SEQUENCE1_() __debugbreak() +// Intentionally empty: __builtin_unreachable() is always part of the sequence +// (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64, +// https://crbug.com/958373 +#define TRAP_SEQUENCE2_() __asm volatile("") + +#else + +#define TRAP_SEQUENCE1_() asm volatile("int3") +#define TRAP_SEQUENCE2_() asm volatile("ud2") + +#endif // __clang__ + +#else + +#error No supported trap sequence! + +#endif // COMPILER_GCC + +#define TRAP_SEQUENCE_() \ + do { \ + TRAP_SEQUENCE1_(); \ + TRAP_SEQUENCE2_(); \ + } while (false) + +// CHECK() and the trap sequence can be invoked from a constexpr function. +// This could make compilation fail on GCC, as it forbids directly using inline +// asm inside a constexpr function. However, it allows calling a lambda +// expression including the same asm. +// The side effect is that the top of the stacktrace will not point to the +// calling function, but to this anonymous lambda. This is still useful as the +// full name of the lambda will typically include the name of the function that +// calls CHECK() and the debugger will still break at the right line of code. +#if !defined(COMPILER_GCC) + +#define WRAPPED_TRAP_SEQUENCE_() TRAP_SEQUENCE_() + +#else + +#define WRAPPED_TRAP_SEQUENCE_() \ + do { \ + [] { TRAP_SEQUENCE_(); }(); \ + } while (false) + +#endif // !defined(COMPILER_GCC) + +#if defined(__clang__) || defined(COMPILER_GCC) + +// __builtin_unreachable() hints to the compiler that this is noreturn and can +// be packed in the function epilogue. +#define IMMEDIATE_CRASH() \ + ({ \ + WRAPPED_TRAP_SEQUENCE_(); \ + __builtin_unreachable(); \ + }) + +#else + +// This is supporting non-chromium user of logging.h to build with MSVC, like +// pdfium. On MSVC there is no __builtin_unreachable(). +#define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE_() + +#endif // defined(__clang__) || defined(COMPILER_GCC) + +#endif // BUILD_RUST_STD_IMMEDIATE_CRASH_H_ diff --git a/third_party/libwebrtc/build/rust/std/remap_alloc.c b/third_party/libwebrtc/build/rust/std/remap_alloc.c new file mode 100644 index 0000000000..ba3b2b0671 --- /dev/null +++ b/third_party/libwebrtc/build/rust/std/remap_alloc.c @@ -0,0 +1,70 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> +#include <stdlib.h> + +#include "build/rust/std/immediate_crash.h" + +// When linking a final binary, rustc has to pick between either: +// * The default Rust allocator +// * Any #[global_allocator] defined in *any rlib in its dependency tree* +// (https://doc.rust-lang.org/edition-guide/rust-2018/platform-and-target-support/global-allocators.html) +// +// In this latter case, this fact will be recorded in some of the metadata +// within the .rlib file. (An .rlib file is just a .a file, but does have +// additional metadata for use by rustc. This is, as far as I know, the only +// such metadata we would ideally care about.) +// +// In all the linked rlibs, +// * If 0 crates define a #[global_allocator], rustc uses its default allocator +// * If 1 crate defines a #[global_allocator], rustc uses that +// * If >1 crates define a #[global_allocator], rustc bombs out. +// +// Because rustc does these checks, it doesn't just have the __rust_alloc +// symbols defined anywhere (neither in the stdlib nor in any of these +// crates which have a #[global_allocator] defined.) +// +// Instead: +// Rust's final linking stage invokes dynamic LLVM codegen to create symbols +// for the basic heap allocation operations. It literally creates a +// __rust_alloc symbol at link time. Unless any crate has specified a +// #[global_allocator], it simply calls from __rust_alloc into +// __rdl_alloc, which is the default Rust allocator. The same applies to a +// few other symbols. +// +// We're not (always) using rustc for final linking. For cases where we're not +// Rustc as the final linker, we'll define those symbols here instead. +// +// In future, we may wish to do something different from using the Rust +// default allocator (e.g. explicitly redirect to PartitionAlloc). We could +// do that here, or we could build a crate with a #[global_allocator] and +// redirect these symbols to that crate instead. The advantage of the latter +// is that it would work equally well for those cases where rustc is doing +// the final linking. + +void* __rdl_alloc(size_t, size_t); +void __rdl_dealloc(void*); +void* __rdl_realloc(void*, size_t, size_t, size_t); +void* __rdl_alloc_zeroed(size_t, size_t); + +void* __rust_alloc(size_t a, size_t b) { + return __rdl_alloc(a, b); +} + +void __rust_dealloc(void* a) { + __rdl_dealloc(a); +} + +void* __rust_realloc(void* a, size_t b, size_t c, size_t d) { + return __rdl_realloc(a, b, c, d); +} + +void* __rust_alloc_zeroed(size_t a, size_t b) { + return __rdl_alloc_zeroed(a, b); +} + +void __rust_alloc_error_handler(size_t a, size_t b) { + IMMEDIATE_CRASH(); +} |