From 27a8c441852d8b0e30c3eb8c3d299ef9b5b29a80 Mon Sep 17 00:00:00 2001 From: Chris Martin Date: Mon, 10 Mar 2025 17:05:06 +0000 Subject: [PATCH] Bug 1950364 - Update and vendor minidump-writer r=glandium,supply-chain-reviewers,gsvelto,nika Differential Revision: https://phabricator.services.mozilla.com/D239530 --- Cargo.lock | 70 +- build/rust/goblin/Cargo.toml | 4 +- supply-chain/audits.toml | 36 + supply-chain/imports.lock | 26 +- .../breakpad-symbols/.cargo-checksum.json | 2 +- third_party/rust/breakpad-symbols/Cargo.toml | 9 +- third_party/rust/breakpad-symbols/src/lib.rs | 1 - .../rust/error-graph/.cargo-checksum.json | 1 + third_party/rust/error-graph/Cargo.toml | 52 + third_party/rust/error-graph/LICENSE | 23 + third_party/rust/error-graph/README.md | 145 ++ third_party/rust/error-graph/src/lib.rs | 386 ++++++ third_party/rust/error-graph/src/strategy.rs | 166 +++ .../rust/error-graph/tests/error_graph.rs | 147 ++ .../rust/failspot/.cargo-checksum.json | 1 + third_party/rust/failspot/Cargo.toml | 46 + third_party/rust/failspot/LICENSE | 5 + third_party/rust/failspot/README.md | 11 + third_party/rust/failspot/src/lib.rs | 327 +++++ third_party/rust/failspot/src/testing.rs | 172 +++ third_party/rust/failspot/tests/failspot.rs | 152 +++ .../rust/framehop/.cargo-checksum.json | 2 +- third_party/rust/framehop/Cargo.toml | 10 +- third_party/rust/framehop/src/unwinder.rs | 45 - third_party/rust/gimli/.cargo-checksum.json | 2 +- third_party/rust/gimli/CHANGELOG.md | 54 + third_party/rust/gimli/Cargo.toml | 4 +- third_party/rust/gimli/README.md | 2 +- third_party/rust/gimli/src/common.rs | 2 - third_party/rust/gimli/src/constants.rs | 3 + third_party/rust/gimli/src/leb128.rs | 4 +- third_party/rust/gimli/src/lib.rs | 10 +- third_party/rust/gimli/src/read/aranges.rs | 193 ++- third_party/rust/gimli/src/read/cfi.rs | 445 ++++--- third_party/rust/gimli/src/read/dwarf.rs | 6 +- .../rust/gimli/src/read/endian_reader.rs | 14 +- third_party/rust/gimli/src/read/index.rs | 14 +- third_party/rust/gimli/src/read/line.rs | 269 ++-- third_party/rust/gimli/src/read/lists.rs | 2 +- third_party/rust/gimli/src/read/loclists.rs | 15 +- third_party/rust/gimli/src/read/mod.rs | 37 +- third_party/rust/gimli/src/read/op.rs | 1 - third_party/rust/gimli/src/read/reader.rs | 52 + third_party/rust/gimli/src/read/rnglists.rs | 18 +- third_party/rust/gimli/src/read/unit.rs | 25 +- third_party/rust/gimli/src/write/cfi.rs | 3 +- third_party/rust/gimli/src/write/line.rs | 75 +- third_party/rust/gimli/src/write/mod.rs | 4 +- third_party/rust/gimli/src/write/unit.rs | 2 +- third_party/rust/gimli/src/write/writer.rs | 1 - third_party/rust/goblin/.cargo-checksum.json | 2 +- third_party/rust/goblin/CHANGELOG.md | 25 +- third_party/rust/goblin/Cargo.lock | 2 +- third_party/rust/goblin/Cargo.toml | 18 +- third_party/rust/goblin/README.md | 7 +- third_party/rust/goblin/src/lib.rs | 7 +- third_party/rust/goblin/src/pe/debug.rs | 77 +- third_party/rust/goblin/src/pe/header.rs | 172 ++- third_party/rust/goblin/src/pe/mod.rs | 120 ++ third_party/rust/goblin/src/pe/tls.rs | 247 ++++ third_party/rust/goblin/src/pe/utils.rs | 2 + .../rust/goblin/tests/bins/te/README.md | 24 + .../rust/minidump-common/.cargo-checksum.json | 2 +- third_party/rust/minidump-common/Cargo.toml | 3 +- .../rust/minidump-common/src/format.rs | 11 +- .../rust/minidump-common/src/traits.rs | 2 +- .../rust/minidump-unwind/.cargo-checksum.json | 2 +- third_party/rust/minidump-unwind/Cargo.toml | 11 +- .../minidump-unwind/src/symbols/debuginfo.rs | 2 +- .../rust/minidump-writer/.cargo-checksum.json | 2 +- third_party/rust/minidump-writer/CHANGELOG.md | 12 +- third_party/rust/minidump-writer/Cargo.lock | 1180 +++++++++++------ third_party/rust/minidump-writer/Cargo.toml | 50 +- third_party/rust/minidump-writer/deny.toml | 3 +- .../rust/minidump-writer/src/bin/test.rs | 135 +- .../rust/minidump-writer/src/dir_section.rs | 19 +- third_party/rust/minidump-writer/src/lib.rs | 15 +- third_party/rust/minidump-writer/src/linux.rs | 1 + .../minidump-writer/src/linux/auxv/mod.rs | 40 +- .../src/linux/dumper_cpu_info/x86_mips.rs | 17 +- .../rust/minidump-writer/src/linux/errors.rs | 279 +++- .../minidump-writer/src/linux/maps_reader.rs | 42 +- .../minidump-writer/src/linux/mem_reader.rs | 6 +- .../src/linux/minidump_writer.rs | 166 ++- .../src/linux/module_reader.rs | 8 +- .../src/linux/ptrace_dumper.rs | 330 +++-- .../src/linux/sections/systeminfo_stream.rs | 15 +- .../minidump-writer/src/linux/serializers.rs | 40 + .../rust/minidump-writer/src/mem_writer.rs | 29 +- .../rust/minidump-writer/src/serializers.rs | 30 + .../rust/minidump-writer/tests/common/mod.rs | 35 + .../tests/linux_minidump_writer.rs | 53 +- .../tests/linux_minidump_writer_soft_error.rs | 92 ++ .../tests/mac_minidump_writer.rs | 148 +-- .../minidump-writer/tests/ptrace_dumper.rs | 66 +- .../rust/minidump/.cargo-checksum.json | 2 +- third_party/rust/minidump/Cargo.toml | 7 +- third_party/rust/minidump/src/context.rs | 2 +- third_party/rust/minidump/src/minidump.rs | 32 +- .../rust/procfs-core/.cargo-checksum.json | 2 +- third_party/rust/procfs-core/COPYRIGHT.txt | 483 +++++++ third_party/rust/procfs-core/Cargo.toml | 11 +- third_party/rust/procfs-core/LICENSE-APACHE | 202 +++ third_party/rust/procfs-core/LICENSE-MIT | 19 + third_party/rust/procfs-core/src/cgroups.rs | 1 + third_party/rust/procfs-core/src/cpuinfo.rs | 6 +- third_party/rust/procfs-core/src/crypto.rs | 597 +++++++++ third_party/rust/procfs-core/src/devices.rs | 192 +++ .../rust/procfs-core/src/kpageflags.rs | 90 ++ third_party/rust/procfs-core/src/lib.rs | 9 + third_party/rust/procfs-core/src/meminfo.rs | 2 +- third_party/rust/procfs-core/src/net.rs | 334 +++-- .../rust/procfs-core/src/partitions.rs | 9 +- .../rust/procfs-core/src/process/mount.rs | 7 + .../rust/procfs-core/src/process/pagemap.rs | 1 + .../minidump-analyzer/Cargo.toml | 6 +- .../crashreporter/process_reader/Cargo.toml | 2 +- .../rust_minidump_writer_linux/Cargo.toml | 2 +- 118 files changed, 7005 insertions(+), 1658 deletions(-) create mode 100644 third_party/rust/error-graph/.cargo-checksum.json create mode 100644 third_party/rust/error-graph/Cargo.toml create mode 100644 third_party/rust/error-graph/LICENSE create mode 100644 third_party/rust/error-graph/README.md create mode 100644 third_party/rust/error-graph/src/lib.rs create mode 100644 third_party/rust/error-graph/src/strategy.rs create mode 100644 third_party/rust/error-graph/tests/error_graph.rs create mode 100644 third_party/rust/failspot/.cargo-checksum.json create mode 100644 third_party/rust/failspot/Cargo.toml create mode 100644 third_party/rust/failspot/LICENSE create mode 100644 third_party/rust/failspot/README.md create mode 100644 third_party/rust/failspot/src/lib.rs create mode 100644 third_party/rust/failspot/src/testing.rs create mode 100644 third_party/rust/failspot/tests/failspot.rs create mode 100644 third_party/rust/goblin/src/pe/tls.rs create mode 100644 third_party/rust/goblin/tests/bins/te/README.md create mode 100644 third_party/rust/minidump-writer/src/linux/serializers.rs create mode 100644 third_party/rust/minidump-writer/src/serializers.rs create mode 100644 third_party/rust/minidump-writer/tests/linux_minidump_writer_soft_error.rs create mode 100644 third_party/rust/procfs-core/COPYRIGHT.txt create mode 100644 third_party/rust/procfs-core/LICENSE-APACHE create mode 100644 third_party/rust/procfs-core/LICENSE-MIT create mode 100644 third_party/rust/procfs-core/src/crypto.rs create mode 100644 third_party/rust/procfs-core/src/devices.rs create mode 100644 third_party/rust/procfs-core/src/kpageflags.rs diff --git a/Cargo.lock b/Cargo.lock index 3f6a6cc01575..3a2a2dae1ffe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -581,9 +581,9 @@ dependencies = [ [[package]] name = "breakpad-symbols" -version = "0.22.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeaa2a7f839cbb61c2f59ad6e51cc3fd2c24aa2103cb24e6be143bcc114aa24" +checksum = "05cc04995b4f6f26dc9cc5989e93e42c373def047b4b057aaf8f48400b971d1e" dependencies = [ "async-trait", "cachemap2", @@ -612,7 +612,7 @@ dependencies = [ name = "buildid_reader" version = "0.1.0" dependencies = [ - "goblin 0.8.2", + "goblin 0.8.999", "libc", "log", "scroll", @@ -1792,6 +1792,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "error-graph" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b920e777967421aa5f9bf34f842c0ab6ba19b3bdb4a082946093860f5858879" +dependencies = [ + "serde", +] + [[package]] name = "error-support" version = "0.1.0" @@ -1846,6 +1855,12 @@ dependencies = [ "syn", ] +[[package]] +name = "failspot" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c942e64b20ecd39933d5ff938ca4fdb6ef0d298cc3855b231179a5ef0b24948d" + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -2119,9 +2134,9 @@ dependencies = [ [[package]] name = "framehop" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd28d2036d4fd99e3629487baca659e5af1c5d554e320168613be79028610fc" +checksum = "33e8ad8f843eb89b4ec8270be4d5840dc6b81ca1a1c1e036b17e94076f36eed4" dependencies = [ "arrayvec", "cfg-if", @@ -2369,9 +2384,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" dependencies = [ "fallible-iterator", "stable_deref_trait", @@ -2649,16 +2664,16 @@ dependencies = [ [[package]] name = "goblin" -version = "0.7.999" +version = "0.8.999" dependencies = [ - "goblin 0.8.2", + "goblin 0.9.2", ] [[package]] name = "goblin" -version = "0.8.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +checksum = "53ab3f32d1d77146981dea5d6b1e8fe31eedcb7013e5e00d6ccd1259a4b4d923" dependencies = [ "log", "plain", @@ -3900,9 +3915,9 @@ dependencies = [ [[package]] name = "minidump" -version = "0.22.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee91aa51259518a08a12c18b5754e45135f89f1d9d7d6aae76ce93b92686698" +checksum = "e03e301d414a75655d4ce80e6e3690fbfe70814b67c496c64c826ba558d18ec9" dependencies = [ "debugid", "encoding_rs", @@ -3945,9 +3960,9 @@ dependencies = [ [[package]] name = "minidump-common" -version = "0.22.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd8a9fb054833d2f402e82e256aeef544e595e45fe8fca2de6d03ed605f6647" +checksum = "5273687f49325b3977f7d372a1bbe2e528694d18128de8dcac78d134448e83b4" dependencies = [ "bitflags 2.8.0", "debugid", @@ -3960,9 +3975,9 @@ dependencies = [ [[package]] name = "minidump-unwind" -version = "0.22.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efde3c09258c297c0f6761f04d97771ef82a59a6734e7ba0e6e2ef961fb3cbb3" +checksum = "c30454f5703c77433b4059bf5e196266b800b14223c55793ee636e49c8f9160e" dependencies = [ "async-trait", "breakpad-symbols", @@ -3978,15 +3993,17 @@ dependencies = [ [[package]] name = "minidump-writer" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c75ff36a030d76801ed7ec3ea4ae45f12c0f1297f3447790288194274e9aa98" +checksum = "6e9370e1f326cb4385f78355d8a0f68f429e9002fd3ca53fff9b43fded234473" dependencies = [ "bitflags 2.8.0", "byteorder", "cfg-if", "crash-context", - "goblin 0.8.2", + "error-graph", + "failspot", + "goblin 0.9.2", "libc", "log", "mach2", @@ -3996,8 +4013,10 @@ dependencies = [ "nix 0.29.0", "procfs-core", "scroll", + "serde", + "serde_json", "tempfile", - "thiserror 1.999.999", + "thiserror 2.0.9", ] [[package]] @@ -5128,7 +5147,7 @@ dependencies = [ name = "process_reader" version = "0.1.0" dependencies = [ - "goblin 0.7.999", + "goblin 0.9.2", "libc", "mach2", "memoffset 0.9.0", @@ -5151,12 +5170,13 @@ dependencies = [ [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ "bitflags 2.8.0", "hex", + "serde", ] [[package]] @@ -6855,7 +6875,7 @@ dependencies = [ "cargo_metadata", "fs-err", "glob", - "goblin 0.8.2", + "goblin 0.8.999", "heck", "once_cell", "paste", diff --git a/build/rust/goblin/Cargo.toml b/build/rust/goblin/Cargo.toml index 1b442d66e1fc..6a82d980ca86 100644 --- a/build/rust/goblin/Cargo.toml +++ b/build/rust/goblin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "goblin" -version = "0.7.999" +version = "0.8.999" edition = "2018" license = "MIT OR Apache-2.0" @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" path = "lib.rs" [dependencies.goblin] -version = "0.8.0" +version = "0.9.0" default-features = false diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 87c0c80a17fe..eba12d55e21f 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2023,6 +2023,12 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "0.3.1 -> 0.3.3" +[[audits.error-graph]] +who = "Chris Martin " +criteria = "safe-to-deploy" +version = "0.1.1" +notes = "This code was written and reviewed by Mozilla employees" + [[audits.extend]] who = "Ben Dean-Kawamura " criteria = "safe-to-deploy" @@ -2034,6 +2040,12 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "1.1.2 -> 1.2.0" +[[audits.failspot]] +who = "Chris Martin " +criteria = "safe-to-deploy" +version = "0.2.0" +notes = "This code was written and reviewed by Mozilla employees" + [[audits.fallible_collections]] who = "Mike Hommey " criteria = "safe-to-deploy" @@ -2445,6 +2457,12 @@ Unsafe code blocks are sound. Minimal dependencies used. No use of side-effectful std functions. """ +[[audits.gimli]] +who = "Chris Martin " +criteria = "safe-to-deploy" +delta = "0.30.0 -> 0.29.0" +notes = "No unsafe code, mostly algorithms and parsing. Very unlikely to cause security issues." + [[audits.gleam]] who = "Jamie Nicol " criteria = "safe-to-deploy" @@ -2496,6 +2514,12 @@ criteria = "safe-to-deploy" delta = "0.8.1 -> 0.8.2" notes = "Removes the TE feature/functionality, otherwise no meaningful changes." +[[audits.goblin]] +who = "Chris Martin " +criteria = "safe-to-deploy" +delta = "0.8.2 -> 0.9.2" +notes = "Doesn't use any unsafe code, mostly parsing and arithmetic." + [[audits.gpu-alloc]] who = "Teodor Tanasoaia " criteria = "safe-to-deploy" @@ -3351,6 +3375,12 @@ criteria = "safe-to-deploy" delta = "0.8.9 -> 0.10.1" notes = "Crate written and reviewed by mozilla employees." +[[audits.minidump-writer]] +who = "Chris Martin " +criteria = "safe-to-deploy" +delta = "0.10.1 -> 0.10.2" +notes = "This patch was written and reviewed by Mozilla employees" + [[audits.miniz_oxide]] who = "Mike Hommey " criteria = "safe-to-deploy" @@ -4097,6 +4127,12 @@ who = "Gabriele Svelto " criteria = "safe-to-deploy" delta = "0.16.0-RC1 -> 0.16.0" +[[audits.procfs-core]] +who = "Chris Martin " +criteria = "safe-to-deploy" +delta = "0.16.0 -> 0.17.0" +notes = "Lots of code, but nothing unsafe and mostly parsing various text formats output by /proc files" + [[audits.profiling]] who = "Mike Hommey " criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index d8707e379920..4936a275854a 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -62,8 +62,8 @@ user-login = "martinthomson" user-name = "Martin Thomson" [[publisher.breakpad-symbols]] -version = "0.22.1" -when = "2024-09-05" +version = "0.24.0" +when = "2025-01-06" user-id = 72814 user-login = "gabrielesvelto" user-name = "Gabriele Svelto" @@ -237,8 +237,8 @@ user-login = "joshtriplett" user-name = "Josh Triplett" [[publisher.framehop]] -version = "0.12.1" -when = "2024-06-04" +version = "0.13.0" +when = "2024-07-24" user-id = 20227 user-login = "mstange" user-name = "Markus Stange" @@ -391,22 +391,22 @@ user-login = "seanmonstar" user-name = "Sean McArthur" [[publisher.minidump]] -version = "0.22.1" -when = "2024-09-05" +version = "0.24.0" +when = "2025-01-06" user-id = 72814 user-login = "gabrielesvelto" user-name = "Gabriele Svelto" [[publisher.minidump-common]] -version = "0.22.1" -when = "2024-09-05" +version = "0.24.0" +when = "2025-01-06" user-id = 72814 user-login = "gabrielesvelto" user-name = "Gabriele Svelto" [[publisher.minidump-unwind]] -version = "0.22.1" -when = "2024-09-05" +version = "0.24.0" +when = "2025-01-06" user-id = 72814 user-login = "gabrielesvelto" user-name = "Gabriele Svelto" @@ -1169,6 +1169,12 @@ who = "Pat Hickey " criteria = "safe-to-deploy" version = "0.3.27" +[[audits.bytecode-alliance.audits.gimli]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +delta = "0.29.0 -> 0.31.0" +notes = "Various updates here and there, nothing too major, what you'd expect from a DWARF parsing crate." + [[audits.bytecode-alliance.audits.heck]] who = "Alex Crichton " criteria = "safe-to-deploy" diff --git a/third_party/rust/breakpad-symbols/.cargo-checksum.json b/third_party/rust/breakpad-symbols/.cargo-checksum.json index 95de59d60655..98f2d42bad08 100644 --- a/third_party/rust/breakpad-symbols/.cargo-checksum.json +++ b/third_party/rust/breakpad-symbols/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2dfb12c51f860b95f13b937e550dc7579bfe122854861717b8aed2c25fe51fe3","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"b0b97fcaf1d9eb5a3f3ca1fc0b0b1f593f7a116465ddcb8158541a40ff98660a","src/http.rs":"025a542391b2464fb6bdc769786b7c3d7ab697d932ee198360bc926e5e2b5cb6","src/lib.rs":"dd9a6cf9a140e5132db87e072550afa2418e2bb75cc0c652d929047e69850f6f","src/sym_file/mod.rs":"bb1c42d9b8823eabca753a7eff11533fdf403bcb0e0c91b298fdf07bcfde023e","src/sym_file/parser.rs":"6fbfd6805e8ef2cdadfd6c171d6ad40647a481760e7296f0ac093cb767fdf8dc","src/sym_file/types.rs":"c23a928bf092cbc9302316777ea00e416706bda6879ce7866a118ba18dbb718c","src/sym_file/walker.rs":"05f31914eb04186cdb292d68eb2f5bc5f2be9112e853867e49cc26eee1518a0a"},"package":"6aeaa2a7f839cbb61c2f59ad6e51cc3fd2c24aa2103cb24e6be143bcc114aa24"} \ No newline at end of file +{"files":{"Cargo.toml":"a7debd586eea67b4edf0b792d50d43eb5a13976f83696573252aa127cf495bfd","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"b0b97fcaf1d9eb5a3f3ca1fc0b0b1f593f7a116465ddcb8158541a40ff98660a","src/http.rs":"025a542391b2464fb6bdc769786b7c3d7ab697d932ee198360bc926e5e2b5cb6","src/lib.rs":"9b75eb5e197a9b5cd1a62050d2355a1694688ee29828096c9624638f02045cb4","src/sym_file/mod.rs":"bb1c42d9b8823eabca753a7eff11533fdf403bcb0e0c91b298fdf07bcfde023e","src/sym_file/parser.rs":"6fbfd6805e8ef2cdadfd6c171d6ad40647a481760e7296f0ac093cb767fdf8dc","src/sym_file/types.rs":"c23a928bf092cbc9302316777ea00e416706bda6879ce7866a118ba18dbb718c","src/sym_file/walker.rs":"05f31914eb04186cdb292d68eb2f5bc5f2be9112e853867e49cc26eee1518a0a"},"package":"05cc04995b4f6f26dc9cc5989e93e42c373def047b4b057aaf8f48400b971d1e"} \ No newline at end of file diff --git a/third_party/rust/breakpad-symbols/Cargo.toml b/third_party/rust/breakpad-symbols/Cargo.toml index 33ec19dac4ac..98f1dada1972 100644 --- a/third_party/rust/breakpad-symbols/Cargo.toml +++ b/third_party/rust/breakpad-symbols/Cargo.toml @@ -12,10 +12,11 @@ [package] edition = "2018" name = "breakpad-symbols" -version = "0.22.1" +version = "0.24.0" authors = ["Ted Mielczarek "] build = false exclude = ["testdata/*"] +autolib = false autobins = false autoexamples = false autotests = false @@ -35,7 +36,7 @@ path = "src/lib.rs" version = "0.1.52" [dependencies.cab] -version = "0.5.0" +version = "0.6.0" optional = true [dependencies.cachemap2] @@ -51,7 +52,7 @@ version = "0.8.0" version = "0.3" [dependencies.minidump-common] -version = "0.22.1" +version = "0.24.0" [dependencies.nom] version = "7" @@ -60,7 +61,7 @@ version = "7" version = "0.2" [dependencies.reqwest] -version = "0.11.6" +version = "0.12" features = [ "gzip", "rustls-tls", diff --git a/third_party/rust/breakpad-symbols/src/lib.rs b/third_party/rust/breakpad-symbols/src/lib.rs index 95bcd3765df6..4e0198bc21f4 100644 --- a/third_party/rust/breakpad-symbols/src/lib.rs +++ b/third_party/rust/breakpad-symbols/src/lib.rs @@ -715,7 +715,6 @@ impl CachedAsyncResult { /// [simple]: struct.SimpleSymbolSupplier.html /// [get_symbol]: struct.Symbolizer.html#method.get_symbol_at_address /// [fill_symbol]: struct.Symbolizer.html#method.fill_symbol - pub struct Symbolizer { /// Symbol supplier for locating symbols. supplier: Box, diff --git a/third_party/rust/error-graph/.cargo-checksum.json b/third_party/rust/error-graph/.cargo-checksum.json new file mode 100644 index 000000000000..c7859ff04afd --- /dev/null +++ b/third_party/rust/error-graph/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"bfef4a4465ffe3fb3ca6e123b115e0c77f4b2bb9612935e45b032353f7ff32c6","LICENSE":"30fefc3a7d6a0041541858293bcbea2dde4caa4c0a5802f996a7f7e8c0085652","README.md":"8e867e8b78902382d2f9c91dcb3b4f9e23bd1690f7f6f62c5d02751ac58ec048","src/lib.rs":"bfdeade34ed8d16378fc2e777bc5952c9d453acec0aabdaee634e35801e1afb4","src/strategy.rs":"c6d243c72b8f61ffb9d240f177d10bd9798cdebe5a9004ce48e0defb15b7a991","tests/error_graph.rs":"4db68c13fcb1e7809a72407e225e8b70ff2ce2a602cb7978bf6bde4ef7fa2fd4"},"package":"9b920e777967421aa5f9bf34f842c0ab6ba19b3bdb4a082946093860f5858879"} \ No newline at end of file diff --git a/third_party/rust/error-graph/Cargo.toml b/third_party/rust/error-graph/Cargo.toml new file mode 100644 index 000000000000..cafd8fbceb76 --- /dev/null +++ b/third_party/rust/error-graph/Cargo.toml @@ -0,0 +1,52 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "error-graph" +version = "0.1.1" +authors = ["Chris Martin "] +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Allows non-fatal errors in a tree of subfunctions to easily be collected by a caller" +readme = "README.md" +keywords = [ + "error", + "error-handling", +] +categories = ["rust-patterns"] +license = "MIT" +repository = "https://github.com/marti4d/error-graph" + +[lib] +name = "error_graph" +path = "src/lib.rs" + +[[test]] +name = "error_graph" +path = "tests/error_graph.rs" + +[dependencies.serde] +version = "1" +optional = true + +[dev-dependencies.serde] +version = "1" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1" + +[features] +serde = ["dep:serde"] diff --git a/third_party/rust/error-graph/LICENSE b/third_party/rust/error-graph/LICENSE new file mode 100644 index 000000000000..468cd79a8f6e --- /dev/null +++ b/third_party/rust/error-graph/LICENSE @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/third_party/rust/error-graph/README.md b/third_party/rust/error-graph/README.md new file mode 100644 index 000000000000..8be0cdd11500 --- /dev/null +++ b/third_party/rust/error-graph/README.md @@ -0,0 +1,145 @@ +# error-graph + +Allows non-fatal errors in a tree of subfunctions to easily be collected by a caller + +Provides the `error_graph::ErrorList` type to hold a list of non-fatal errors +that occurred while a function was running. + +It has a `subwriter()` method that can be passed as a parameter to +a subfunction and allows that subfunction to record all the non-fatal errors it encounters. +When the subfunction is done running, its error list will be mapped to the caller's error type +and added to the caller's `ErrorList` automatically. + +Since subfunctions may in-turn also use the `subwriter()` +function on the writter given to them by their caller, this creates a tree of non-fatal errors +that occurred during the execution of an entire call graph. + +# Usage + +``` +# use error_graph::{ErrorList, WriteErrorList, strategy::{DontCare, ErrorOccurred}}; +enum UpperError { + Upper, + Middle(ErrorList), +} +enum MiddleError { + Middle, + Lower(ErrorList), +} +enum LowerError { + Lower, +} +fn upper() { + let mut errors = ErrorList::default(); + errors.push(UpperError::Upper); + // Map the ErrorList to our UpperError::Middle variant + middle(errors.subwriter(UpperError::Middle)); + errors.push(UpperError::Upper); + + // Some callers just don't want to know if things went wrong or not + middle(DontCare); + + // Some callers are only interested in whether an error occurred or not + let mut error_occurred = ErrorOccurred::default(); + middle(&mut error_occurred); + if error_occurred.as_bool() { + errors.push(UpperError::Upper); + } +} +fn middle(mut errors: impl WriteErrorList) { + // We can pass a sublist by mutable reference if we need to manipulate it before and after + let mut sublist = errors.sublist(MiddleError::Lower); + lower(&mut sublist); + let num_errors = sublist.len(); + sublist.finish(); + if num_errors > 10 { + errors.push(MiddleError::Middle); + } + // We can pass a reference directly to our error list for peer functions + middle_2(&mut errors); +} +fn middle_2(mut errors: impl WriteErrorList) { + errors.push(MiddleError::Middle); +} +fn lower(mut errors: impl WriteErrorList) { + errors.push(LowerError::Lower); +} +``` + +# Motivation + +In most call graphs, a function that encounters an error will early-return and pass an +error type to its caller. The caller will often respond by passing that error further up the +call stack up to its own caller (possibly after wrapping it in its own error type). That +continues so-on-and-so-forth until some caller finally handles the error, returns from `main`, +or panics. Ultimately, the result is that some interested caller will receive a linear chain of +errors that led to the failure. + +But, not all errors are fatal -- Sometimes, a function might be able to continue working after +it encounters an error and still be able to at-least-partially achieve its goals. Calling it +again - or calling other functions in the same API - is still permissible and may also result +in full or partial functionality. + +In that case, the function may still choose to return `Result::Ok`; however, that leaves the +function with a dilemma -- How can it report the non-fatal errors to the caller? + +1. **Return a tuple in its `Result::Ok` type**: that wouldn't capture the non-fatal errors in + the case that a fatal error occurs, so it would also have to be added to the `Result::Err` + type as well. + + That adds a bunch of boilerplate, as the function needs to allocate the list and map it + into the return type for every error return and good return. It also makes the function + signature much more noisy. + +2. **Take a list as a mutable reference?**: Better, but now the caller has to allocate the + list, and there's no way for it to opt out if it doesn't care about the non-fatal errors. + +3. **Maybe add an `Option` to it?** Okay, so a parameter like `errors: Option<&mut Vec>`? + Getting warmer, but now the child has to do a bunch of + `if let Some(v) = errors { v.push(error); }` all over the place. + +And what about the caller side of it? For a simple caller, the last point isn't too bad: The +caller just has to allocate the list, pass `Some(&mut errors)` to the child, and check it upon +return. + +But often, the caller itself is keeping its own list of non-fatal errors and may also be a +subfunction to some other caller, and so-on-and-so-forth. In this case, we no longer have +a simple chain of errors, but instead we have a tree of errors -- Each level in the tree +contains all the non-fatal errors that occurred during execution of a function and all +subfunctions in its call graph. + +# Solution + +The main behavior we want is captured by the `WriteErrorList` trait in this crate. It can be +passed as a parameter to any function that wants to be able to report non-fatal errors to its +caller, and it gives the caller flexibility to decide what it wants to do with that +information. + +The main concrete type in this crate is `ErrorList`, which stores a list of a single type of +error. Any time a list of errors needs to be stored in memory, this is the type to use. It will +usually be created by the top-level caller using `ErrorList::default`, and any subfunction will +give an `ErrorList` of its own error type to the `map_fn` that was passed in by its caller upon +return. + +However, `ErrorList` should rarely be passed as a parameter to a function, as that wouldn't +provide the caller with the flexiblity to decide what strategy it actually wants +to use when collecting its subfunction's non-fatal errors. The caller may want to pass direct +reference to its own error list, it may want to pass a `Sublist` type that automatically +pushes the subfunction's error list to its own error list after mapping, or it may want to +pass the `DontCare` type if it doesn't want to know anything about the +subfunction's non-fatal errors. + +Instead, subfunctions should take `impl WriteErrorList` as a parameter. +This allows any of those types above, as well as mutable references to those types, to be +passed in by the caller. This also allows future caller strategies to be implemented, like +a caller that only cares how many non-fatal errors occurred but doesn't care about the details. + +# Serde + +(This section only applies if the `serde` feature is enabled) + +`ErrorList` implements the `Serialize` trait if the errors it contains do, and +likewise with the `Deserialize` trait. This means that if every error type in the tree +implements these traits then the entire tree can be sent over the wire and recreated elsewhere. +Very useful if the errors are to be examined remotely! + diff --git a/third_party/rust/error-graph/src/lib.rs b/third_party/rust/error-graph/src/lib.rs new file mode 100644 index 000000000000..7b2335d2c8a3 --- /dev/null +++ b/third_party/rust/error-graph/src/lib.rs @@ -0,0 +1,386 @@ +//! Allows non-fatal errors in a tree of subfunctions to easily be collected by a caller +//! +//! Provides the [`error_graph::ErrorList`][ErrorList] type to hold a list of non-fatal errors +//! that occurred while a function was running. +//! +//! It has a [`subwriter()`][WriteErrorList::subwriter] method that can be passed as a parameter to +//! a subfunction and allows that subfunction to record all the non-fatal errors it encounters. +//! When the subfunction is done running, its error list will be mapped to the caller's error type +//! and added to the caller's [ErrorList] automatically. +//! +//! Since subfunctions may in-turn also use the [`subwriter()`][WriteErrorList::subwriter] +//! function on the writter given to them by their caller, this creates a tree of non-fatal errors +//! that occurred during the execution of an entire call graph. +//! +//! # Usage +//! +//! ``` +//! # use error_graph::{ErrorList, WriteErrorList, strategy::{DontCare, ErrorOccurred}}; +//! enum UpperError { +//! Upper, +//! Middle(ErrorList), +//! } +//! enum MiddleError { +//! Middle, +//! Lower(ErrorList), +//! } +//! enum LowerError { +//! Lower, +//! } +//! fn upper() { +//! let mut errors = ErrorList::default(); +//! errors.push(UpperError::Upper); +//! // Map the ErrorList to our UpperError::Middle variant +//! middle(errors.subwriter(UpperError::Middle)); +//! errors.push(UpperError::Upper); +//! +//! // Some callers just don't want to know if things went wrong or not +//! middle(DontCare); +//! +//! // Some callers are only interested in whether an error occurred or not +//! let mut error_occurred = ErrorOccurred::default(); +//! middle(&mut error_occurred); +//! if error_occurred.as_bool() { +//! errors.push(UpperError::Upper); +//! } +//! } +//! fn middle(mut errors: impl WriteErrorList) { +//! // We can pass a sublist by mutable reference if we need to manipulate it before and after +//! let mut sublist = errors.sublist(MiddleError::Lower); +//! lower(&mut sublist); +//! let num_errors = sublist.len(); +//! sublist.finish(); +//! if num_errors > 10 { +//! errors.push(MiddleError::Middle); +//! } +//! // We can pass a reference directly to our error list for peer functions +//! middle_2(&mut errors); +//! } +//! fn middle_2(mut errors: impl WriteErrorList) { +//! errors.push(MiddleError::Middle); +//! } +//! fn lower(mut errors: impl WriteErrorList) { +//! errors.push(LowerError::Lower); +//! } +//! ``` +//! +//! # Motivation +//! +//! In most call graphs, a function that encounters an error will early-return and pass an +//! error type to its caller. The caller will often respond by passing that error further up the +//! call stack up to its own caller (possibly after wrapping it in its own error type). That +//! continues so-on-and-so-forth until some caller finally handles the error, returns from `main`, +//! or panics. Ultimately, the result is that some interested caller will receive a linear chain of +//! errors that led to the failure. +//! +//! But, not all errors are fatal -- Sometimes, a function might be able to continue working after +//! it encounters an error and still be able to at-least-partially achieve its goals. Calling it +//! again - or calling other functions in the same API - is still permissible and may also result +//! in full or partial functionality. +//! +//! In that case, the function may still choose to return `Result::Ok`; however, that leaves the +//! function with a dilemma -- How can it report the non-fatal errors to the caller? +//! +//! 1. **Return a tuple in its `Result::Ok` type**: that wouldn't capture the non-fatal errors in +//! the case that a fatal error occurs, so it would also have to be added to the `Result::Err` +//! type as well. +//! +//! That adds a bunch of boilerplate, as the function needs to allocate the list and map it +//! into the return type for every error return and good return. It also makes the function +//! signature much more noisy. +//! +//! 2. **Take a list as a mutable reference?**: Better, but now the caller has to allocate the +//! list, and there's no way for it to opt out if it doesn't care about the non-fatal errors. +//! +//! 3. **Maybe add an `Option` to it?** Okay, so a parameter like `errors: Option<&mut Vec>`? +//! Getting warmer, but now the child has to do a bunch of +//! `if let Some(v) = errors { v.push(error); }` all over the place. +//! +//! And what about the caller side of it? For a simple caller, the last point isn't too bad: The +//! caller just has to allocate the list, pass `Some(&mut errors)` to the child, and check it upon +//! return. +//! +//! But often, the caller itself is keeping its own list of non-fatal errors and may also be a +//! subfunction to some other caller, and so-on-and-so-forth. In this case, we no longer have +//! a simple chain of errors, but instead we have a tree of errors -- Each level in the tree +//! contains all the non-fatal errors that occurred during execution of a function and all +//! subfunctions in its call graph. +//! +//! # Solution +//! +//! The main behavior we want is captured by the [WriteErrorList] trait in this crate. It can be +//! passed as a parameter to any function that wants to be able to report non-fatal errors to its +//! caller, and it gives the caller flexibility to decide what it wants to do with that +//! information. +//! +//! The main concrete type in this crate is [ErrorList], which stores a list of a single type of +//! error. Any time a list of errors needs to be stored in memory, this is the type to use. It will +//! usually be created by the top-level caller using [ErrorList::default], and any subfunction will +//! give an [ErrorList] of its own error type to the `map_fn` that was passed in by its caller upon +//! return. +//! +//! However, [ErrorList] should rarely be passed as a parameter to a function, as that wouldn't +//! provide the caller with the flexiblity to decide what strategy it actually wants +//! to use when collecting its subfunction's non-fatal errors. The caller may want to pass direct +//! reference to its own error list, it may want to pass a [Sublist] type that automatically +//! pushes the subfunction's error list to its own error list after mapping, or it may want to +//! pass the [DontCare] type if it doesn't want to know anything about the +//! subfunction's non-fatal errors. +//! +//! Instead, subfunctions should take `impl WriteErrorList` as a parameter. +//! This allows any of those types above, as well as mutable references to those types, to be +//! passed in by the caller. This also allows future caller strategies to be implemented, like +//! a caller that only cares how many non-fatal errors occurred but doesn't care about the details. +//! +//! # Serde +//! +//! (This section only applies if the `serde` feature is enabled) +//! +//! [ErrorList] implements the `Serialize` trait if the errors it contains do, and +//! likewise with the `Deserialize` trait. This means that if every error type in the tree +//! implements these traits then the entire tree can be sent over the wire and recreated elsewhere. +//! Very useful if the errors are to be examined remotely! + +use { + std::{ + error::Error, + fmt::{self, Debug, Display, Formatter}, + }, + strategy::*, +}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +pub mod strategy; + +/// Types that are capable of having errors and sublists of errors pushed onto them +/// +/// This is the main trait that allows a function to record a list of non-fatal errors it +/// encounters during its execution. Generally, the [WriteErrorList::push] method will be used when +/// such an error occurs to record the error and any relevant information. +/// +/// Often, a function will want to call a subfunction and add any non-fatal errors encountered +/// to its own list of errors. There are 2 strategies it could use: +/// +/// 1. **Let the subfunction directly push onto its error list** For functions that are at the same +/// level of abstraction and use the same error type, it might make the most sense for them +/// to just share an error list. In this case, simply pass a mutable reference to the error +/// list. For any type that implements this trait, a mutable reference to it implements the +/// trait too. This allows a single function to be a composition of a bunch of functions that +/// each share a single flat error list. +/// +/// 2. **Map the subfunction's error list to the caller** For a subfunction that is at a different +/// level of abstraction than the caller and uses its own error type, this makes the most sense; +/// consume the subfunction's entire error list and store it as a single error of the +/// caller's higher-level error type. Of course, those subfunctions may implement this same +/// strategy for subfunctions they call, creating a hierarchy of errors. +/// +/// In this case, call the [WriteErrorList::subwriter()] function as a parameter to +/// the subfunction. If you need to manipulate the list after the subfunction has returned, +/// instead call [WriteErrorList::sublist] and pass a mutable reference as a parameter. +/// +/// Function parameters should always prefer to take an object by this trait, and should rarely +/// take parameters as concrete types like [ErrorList] or [Sublist]. +/// Doing so would prevent callers from being able to decide what strategy they want to use +/// to merge the subfunction's errors with its own, and would also prevent them from using the +/// [DontCare] call if they want to opt out of receiving non-fatal error information. +/// +/// Passing by this trait may also help prevent logic errors: Directly passing a [Sublist] allows +/// the subfunction to query the contents of the list it's passed. Functions may incorrectly rely on +/// the fact that they are always passed an empty list, and will suddenly break if that assumption +/// doesn't hold. +pub trait WriteErrorList: Sized + private::Sealed { + /// Add an error to the list of errors + fn push(&mut self, error: E); + /// Create a new mapping error writer with this as its parent + /// + /// Creates a error writer for use by a subfunction. When the subfunction is finished, + /// either by explicitly calling [WriteErrorList::finish] or by letting it drop, the list + /// of errors it has written using [WriteErrorList::push] will be passed as an + /// [`ErrorList`][ErrorList] to the given `map_fn`, which is expected to map it to + /// our error type, `E`. + /// + /// Use of this function should always be preferred to [WriteErrorList::sublist] when the + /// caller does not need to inspect or manipulate the list returned by the subfunction and + /// simply wants to pass it upward to its own caller, as this function will pass forward + /// alternate strategies for collecting the errors, like [DontCare] (which turns + /// [WriteErrorList::push] into a no-op). In constrast, [WriteErrorList::sublist] actually + /// materializes a list that will collect all the errors of all the lists below it, even + /// if the caller above it passed in a [DontCare]. + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub; + /// Start a new error list with this error list as its parent + /// + /// This works in a very similar manner to [WriteErrorList::subwriter], but it materializes + /// an actual concrete [Sublist] type. This function + /// should only be used if the function needs to be able to inspect or manipulate the errors + /// returned by the subfunction, as it always collects all errors written by the subfunction's + /// call graph. Otherwise, [WriteErrorList::subwriter] should be used. + fn sublist( + &mut self, + map_fn: SubMapFn, + ) -> Sublist<'_, SubErr, SubMapFn, Self, E> + where + SubMapFn: FnOnce(ErrorList) -> E, + { + Sublist::new(map_fn, self) + } + /// Finish this error list + /// + /// This doesn't normally need to be called, as the [Drop] implementation will take care of + /// all the details of cleaning up and ensuring that sublists are mapped up to their parent. + /// + /// This is mostly useful when a caller maintains a binding to a subfunction's error list + /// and passes it by mutable reference instead of by value. Before the caller can continue + /// to use its own error list, the sublist must release its exclusive reference. + /// + /// This function simply calls [drop()], but it's just a bit more clear about the intent. + fn finish(self) { + drop(self) + } +} + +impl> private::Sealed for &mut T {} + +impl> WriteErrorList for &mut T { + fn push(&mut self, error: E) { + WriteErrorList::push(*self, error) + } + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub, + { + WriteErrorList::subwriter(*self, map_fn) + } +} + +/// The main type that holds a list of errors. +/// +/// See the module-level docs and the docs for [WriteErrorList]. +#[derive(Debug, Eq, Hash, PartialEq)] +pub struct ErrorList { + errors: Vec, +} + +#[cfg(feature = "serde")] +impl Serialize for ErrorList { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + Serialize::serialize(&self.errors, serializer) + } +} + +#[cfg(feature = "serde")] +impl<'de, E: Deserialize<'de>> Deserialize<'de> for ErrorList { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Ok(ErrorList { + errors: Deserialize::deserialize(deserializer)?, + }) + } +} + +impl ErrorList { + /// Returns whether the error list is empty + pub fn is_empty(&self) -> bool { + self.errors.is_empty() + } + /// Return the length of the error list + pub fn len(&self) -> usize { + self.errors.len() + } + /// Iterate the error list, returning immutable references + pub fn iter<'a>(&'a self) -> impl Iterator + where + E: 'a, + { + self.errors.iter() + } + /// Iterate the error list, returning mutable references + pub fn iter_mut<'a>(&'a mut self) -> impl Iterator + where + E: 'a, + { + self.errors.iter_mut() + } +} + +impl private::Sealed for ErrorList {} + +impl WriteErrorList for ErrorList { + fn push(&mut self, error: E) { + self.errors.push(error); + } + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub, + { + self.sublist(map_fn) + } +} + +impl Default for ErrorList { + fn default() -> Self { + Self { errors: Vec::new() } + } +} + +impl Display for ErrorList { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + writeln!(f, "one or more errors occurred:")?; + writeln!(f)?; + for (i, e) in self.errors.iter().enumerate() { + writeln!(f, " {i}:")?; + + for line in e.to_string().lines() { + writeln!(f, " {line}")?; + } + + writeln!(f)?; + + let mut source = e.source(); + while let Some(e) = source { + writeln!(f, " caused by:")?; + + for line in e.to_string().lines() { + writeln!(f, " {line}")?; + } + + writeln!(f)?; + + source = e.source(); + } + } + Ok(()) + } +} + +impl Error for ErrorList {} + +impl IntoIterator for ErrorList { + type Item = as IntoIterator>::Item; + type IntoIter = as IntoIterator>::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self.errors.into_iter() + } +} + +mod private { + /// Prevent users of this crate from implementing traits for their own types + pub trait Sealed {} +} diff --git a/third_party/rust/error-graph/src/strategy.rs b/third_party/rust/error-graph/src/strategy.rs new file mode 100644 index 000000000000..a607eb7b42df --- /dev/null +++ b/third_party/rust/error-graph/src/strategy.rs @@ -0,0 +1,166 @@ +//! Strategies a caller may use to collect errors from subfunctions +//! +//! Currently, the strategies contained in this module are: +//! +//! - [DontCare]: The caller will ignore any non-fatal errors in subfunction. +//! [WriteErrorList::push] is effectively a no-op. +//! +//! - [ErrorOccurred]: Keeps track of a single boolean about whether an error occurred or not. +//! [WriteErrorList::push] essentially just sets a flag. +//! +//! - [Sublist]: A full-fledged list of all non-fatal errors in subfunction. Will be mapped to +//! the caller's error type with a map function and pushed into the caller's error list. +use { + crate::{private, ErrorList, WriteErrorList}, + std::ops::{Deref, DerefMut}, +}; + +/// A sublist that maps a list of errors into a parent error type +/// +/// When an object of this type is dropped, it will call the given `MapFn` object with a +/// [`ErrorList`][ErrorList] containing all the errors that were pushed into it. The map +/// function will be used to map that error list to a single `ParentErr` object which will then +/// be pushed onto the parent's error list. +/// +/// This type implements [DerefMut] to an [ErrorList], so it can basically be thought of as +/// an [ErrorList] with a fancy destructor. +pub struct Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + list: ErrorList, + map_fn_and_parent: Option<(MapFn, &'a mut Parent)>, +} + +impl<'a, E, MapFn, Parent, ParentErr> Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + /// Create a new sublist that maps a list of subfunction errors to the parent error + /// + /// `map_fn` is a function that accepts an `ErrorList` and returns a `ParentErr`, which + /// is then pushed into the parent's error list. + /// + /// It is recommended use [WriteErrorList::sublist] instead of this. + pub fn new(map_fn: MapFn, parent: &'a mut Parent) -> Self { + Self { + list: ErrorList::default(), + map_fn_and_parent: Some((map_fn, parent)), + } + } +} + +impl<'a, E, MapFn, Parent, ParentErr> Drop for Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + fn drop(&mut self) { + if !self.list.is_empty() { + let list = std::mem::take(&mut self.list); + let (map_fn, parent) = self.map_fn_and_parent.take().unwrap(); + let parent_error = map_fn(list); + parent.push(parent_error); + } + } +} + +impl<'a, E, MapFn, Parent, ParentErr> Deref for Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + type Target = ErrorList; + fn deref(&self) -> &Self::Target { + &self.list + } +} + +impl<'a, E, MapFn, Parent, ParentErr> DerefMut for Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.list + } +} + +impl<'a, E, MapFn, Parent, ParentErr> private::Sealed + for Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ +} + +impl<'a, E, MapFn, Parent, ParentErr> WriteErrorList for Sublist<'a, E, MapFn, Parent, ParentErr> +where + MapFn: FnOnce(ErrorList) -> ParentErr, + Parent: WriteErrorList, +{ + fn push(&mut self, error: E) { + self.list.push(error) + } + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub, + { + self.sublist(map_fn) + } +} + +/// An error list writer that ignores errors +/// +/// Any call to [WriteErrorList::push] does nothing but drop the given error. +pub struct DontCare; + +impl private::Sealed for DontCare {} + +impl WriteErrorList for DontCare { + fn push(&mut self, _error: E) {} + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + _map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub, + { + DontCare + } +} + +/// An error list writer that only notes that an error occurred +/// +/// [ErrorOccurred::as_bool] will return `true` if the subfunction encountered a non-fatal error +/// `false` otherwise +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub struct ErrorOccurred(bool); + +impl ErrorOccurred { + pub fn as_bool(&self) -> bool { + self.0 + } +} + +impl private::Sealed for ErrorOccurred {} + +impl WriteErrorList for ErrorOccurred { + fn push(&mut self, _error: E) { + self.0 = true; + } + fn subwriter<'sub, SubMapFn, SubErr: 'sub>( + &'sub mut self, + _map_fn: SubMapFn, + ) -> impl WriteErrorList + 'sub + where + SubMapFn: FnOnce(ErrorList) -> E + 'sub, + { + self + } +} diff --git a/third_party/rust/error-graph/tests/error_graph.rs b/third_party/rust/error-graph/tests/error_graph.rs new file mode 100644 index 000000000000..e761ed71cfed --- /dev/null +++ b/third_party/rust/error-graph/tests/error_graph.rs @@ -0,0 +1,147 @@ +use error_graph::{ErrorList, WriteErrorList}; + +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +enum UpperError { + Upper, + Middle(ErrorList), +} + +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +enum MiddleError { + Middle, + Lower(ErrorList), +} + +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +enum LowerError { + Lower, +} + +fn upper(mut errors: impl WriteErrorList) { + errors.push(UpperError::Upper); + middle(errors.subwriter(UpperError::Middle)); + errors.push(UpperError::Upper); +} + +fn middle(mut errors: impl WriteErrorList) { + errors.push(MiddleError::Middle); + lower(errors.subwriter(MiddleError::Lower)); + errors.push(MiddleError::Middle); +} + +fn lower(mut errors: impl WriteErrorList) { + errors.push(LowerError::Lower); +} + +fn lower_errors_only(mut errors: impl WriteErrorList) { + lower(errors.subwriter(MiddleError::Lower)); +} + +fn no_errors(mut errors: impl WriteErrorList) { + no_errors_middle(errors.subwriter(UpperError::Middle)); +} + +fn no_errors_middle(mut errors: impl WriteErrorList) { + no_errors_lower(errors.subwriter(MiddleError::Lower)); +} + +fn no_errors_lower(mut _errors: impl WriteErrorList) {} + +#[test] +fn empty() { + let mut errors = ErrorList::default(); + errors.push(UpperError::Upper); + no_errors_middle(errors.subwriter(UpperError::Middle)); + assert_eq!(errors.len(), 1); +} + +#[test] +fn basic() { + let mut errors = ErrorList::default(); + upper(&mut errors); + + let mut upper_it = errors.into_iter(); + assert!(matches!(upper_it.next(), Some(UpperError::Upper))); + let Some(UpperError::Middle(middle)) = upper_it.next() else { + panic!(); + }; + assert!(matches!(upper_it.next(), Some(UpperError::Upper))); + + let mut middle_it = middle.into_iter(); + assert!(matches!(middle_it.next(), Some(MiddleError::Middle))); + let Some(MiddleError::Lower(lower)) = middle_it.next() else { + panic!(); + }; + assert!(matches!(middle_it.next(), Some(MiddleError::Middle))); + + let mut lower_it = lower.into_iter(); + assert!(matches!(lower_it.next(), Some(LowerError::Lower))); +} + +#[test] +fn sublist() { + let mut errors = ErrorList::default(); + errors.push(UpperError::Upper); + let mut sublist = errors.sublist(UpperError::Middle); + middle(&mut sublist); + assert_eq!(sublist.len(), 3); + drop(sublist); + assert_eq!(errors.len(), 2); +} + +#[test] +fn dont_care() { + let mut errors = error_graph::strategy::DontCare; + errors.push(UpperError::Upper); + let mut sublist = errors.sublist(UpperError::Middle); + middle(&mut sublist); + assert_eq!(sublist.len(), 3); + sublist.finish(); + middle(errors.subwriter(UpperError::Middle)); +} + +#[test] +fn error_occurred() { + let mut error_occurred = error_graph::strategy::ErrorOccurred::default(); + no_errors(&mut error_occurred); + assert!(!error_occurred.as_bool()); + lower_errors_only(&mut error_occurred); + assert!(error_occurred.as_bool()); + let mut error_occurred = error_graph::strategy::ErrorOccurred::default(); + middle(&mut error_occurred); + assert!(error_occurred.as_bool()); +} + +#[cfg(feature = "serde")] +#[test] +fn serde() { + const EXPECTED_JSON: &str = r#"[ + "Upper", + { + "Middle": [ + "Middle", + { + "Lower": [ + "Lower" + ] + }, + "Middle" + ] + }, + "Upper" +]"#; + + let mut errors = ErrorList::default(); + upper(&mut errors); + let json = serde_json::to_string_pretty(&errors).unwrap(); + assert_eq!(json.as_str(), EXPECTED_JSON); + + let recreated_errors: ErrorList = serde_json::from_str(&json).unwrap(); + + for (left, right) in errors.iter().zip(recreated_errors.iter()) { + assert_eq!(left, right); + } +} diff --git a/third_party/rust/failspot/.cargo-checksum.json b/third_party/rust/failspot/.cargo-checksum.json new file mode 100644 index 000000000000..d4e3982e85ca --- /dev/null +++ b/third_party/rust/failspot/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"050c2c16aa21b10b00a5e5943d22bcf4adbe79fc3c728a188f2558f456a54ff8","LICENSE":"748c15c2a285ef74aec280f2e72bd98482b96bd0e2da0d8f0fde934fa88e2e16","README.md":"4574640bf1b6b6f24b9b70a159d2e291d2dc89621bd4ec378d7ec7ab69fde597","src/lib.rs":"c8a28569145d36e3097407b8c2bef6e96e2d3196f2efb5304055ce2ceafb93ec","src/testing.rs":"abc7299e60c076de162dd5da66fc958780d4a30278db911a54b7867a34b25c1c","tests/failspot.rs":"e7793c44c7113a51312c67d02b1a174c84f5543385fdb07f0e671f27851ea0b2"},"package":"c942e64b20ecd39933d5ff938ca4fdb6ef0d298cc3855b231179a5ef0b24948d"} \ No newline at end of file diff --git a/third_party/rust/failspot/Cargo.toml b/third_party/rust/failspot/Cargo.toml new file mode 100644 index 000000000000..5a74df5df533 --- /dev/null +++ b/third_party/rust/failspot/Cargo.toml @@ -0,0 +1,46 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "failspot" +version = "0.2.0" +authors = ["Chris Martin "] +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "A testing library that makes it easy(ish) to add intentional errors to a program" +readme = "README.md" +keywords = [ + "error", + "error-handling", + "testing", +] +categories = ["development-tools::testing"] +license = "MIT" +repository = "https://github.com/marti4d/failspot" + +[lib] +name = "failspot" +path = "src/lib.rs" + +[[test]] +name = "failspot" +path = "tests/failspot.rs" + +[dependencies.flagset] +version = "0.4.6" +optional = true + +[features] +enabled = ["dep:flagset"] diff --git a/third_party/rust/failspot/LICENSE b/third_party/rust/failspot/LICENSE new file mode 100644 index 000000000000..0e77b64a4bb8 --- /dev/null +++ b/third_party/rust/failspot/LICENSE @@ -0,0 +1,5 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/failspot/README.md b/third_party/rust/failspot/README.md new file mode 100644 index 000000000000..537c61e97b9c --- /dev/null +++ b/third_party/rust/failspot/README.md @@ -0,0 +1,11 @@ +# failspot + +[![crates.io](https://img.shields.io/crates/v/failspot?style=for-the-badge&logo=rust)](https://crates.io/crates/failspot) +[![docs.rs](https://img.shields.io/docsrs/failspot?style=for-the-badge&logo=docs.rs&label=docs.rs)](https://docs.rs/failspot) +![license](https://img.shields.io/crates/l/failspot?style=for-the-badge) + +A testing library that makes it easy(ish) to add intentional errors to a program + +When testing error-handling codepaths, it is often useful to programmatically tell parts of the code to fail. This +crate provides the `failspot!()` macro, which can be used to mark a spot in the codepath where an intentional failure +can be toggled on and off from testing code. diff --git a/third_party/rust/failspot/src/lib.rs b/third_party/rust/failspot/src/lib.rs new file mode 100644 index 000000000000..ebbddd8c3bc1 --- /dev/null +++ b/third_party/rust/failspot/src/lib.rs @@ -0,0 +1,327 @@ +//! A testing library that makes it easy(ish) to add intentional errors to a program +//! +//! When testing error-handling codepaths, it is often useful to programmatically tell parts of the +//! code to fail. This crate provides the [`failspot!()`][failspot] macro, which can be used +//! to mark a spot in the codepath where an intentional failure can be toggled on and off +//! from testing code. +//! +//! Adding it to code is fairly simple: +//! +//! ```no_run +//! # use {failspot::failspot, std::{error::Error, fs, io, path::Path}}; +//! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } +//! # fn main() { +//! # read_data_file("/tmp/foo".as_ref()); +//! # } +//! fn read_data_file(path: &Path) -> Result, Box> { +//! // `FailDataRead` is a variant of an enum that was declared in our crate +//! // `bail` returns `Err` and does type conversion on the error type +//! failspot!(FailDataRead bail(io::Error::other("failed due to test config"))); +//! Ok(fs::read(path)?) +//! } +//! ``` +//! +//! The [`failspot_name!()`][failspot_name] macro is used to declare an enum that can be used +//! to name a failspot. Its syntax is identical to a regular enum declaration: +//! +//! ```no_run +//! # use failspot::failspot_name; +//! failspot_name! { +//! pub enum FailSpotName { +//! StuffWentWrong, +//! } +//! } +//! ``` +//! +//! # Syntaxes +//! +//! The [`failspot!()`][failspot] macro has **four main syntaxes**. Each takes either a +//! **long form** or a **short form**. +//! +//! The **long form** explicitly contains the path to the enum containing the failspot names. This +//! is useful if there are multiple enums with different failspot names, or if the enum is only +//! accessible at a non-standard name or path. +//! +//! If the enum can be reached at the name `crate::FailSpotName` (either because it was declared in +//! the crate root or re-exported there), the **short form** versions of these macros +//! can be used. The examples below make this clear: +//! +//! ## "if-else" syntax (long form) +//! +//! Useful when standard if-else behavior is desired: +//! +//! ``` +//! # use {failspot::failspot}; +//! # pub mod my_module { +//! # failspot::failspot_name! { pub enum MyFailName { FailDataRead } } +//! # } +//! # fn main() { +//! // In "long form", the entire path to the enum must be spelled out +//! let _enabled = failspot!(if ::FailDataRead { +//! println!("Data read failure enabled"); +//! true +//! } else { +//! println!("Data read failure disabled"); +//! false +//! }); +//! # } +//! ``` +//! +//! When the `enabled` feature is not on, the compiler will see the second block verbatim. +//! +//! ### The same code with the short-form +//! +//! If an enum named `FailSpotName` is reachable at the crate root, like this: +//! +//! ``` +//! # use failspot::failspot_name; +//! // lib.rs +//! failspot_name! { +//! pub enum FailSpotName { +//! FailDataRead, +//! } +//! } +//! ``` +//! +//! The short form can be used, like this: +//! +//! ``` +//! # use failspot::{failspot, failspot_name}; +//! # failspot_name! { pub enum FailSpotName { FailDataRead } } +//! # fn main() { +//! let _enabled = failspot!(if FailDataRead { +//! println!("Data read failure enabled"); +//! true +//! } else { +//! println!("Data read failure disabled"); +//! false +//! }); +//! # } +//! ``` +//! +//! ## "quick expression" syntax +//! +//! Useful when a short block of syntax should be evaluated when the failspot is enabled: +//! +//! ``` +//! # use {failspot::failspot}; +//! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } +//! # fn main() { +//! failspot!(FailDataRead println!("Data read failure enabled")); +//! +//! // Also good for panicking +//! failspot!(FailDataRead panic!()); +//! +//! // Or for just early returning +//! failspot!(FailDataRead return); +//! +//! // Multiple statements can be run, but use sparingly as things start to get ugly. +//! failspot!(FailDataRead println!("Data read failure enabled"); return); +//! # } +//! ``` +//! +//! When the `enabled` feature is not on, the macro will evaluate to the empty block, `{}`. +//! +//! ## "bail" syntax +//! +//! Useful for returning an `Err` with error-type conversion: +//! +//! ``` +//! # use {failspot::failspot, std::error::Error}; +//! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } +//! fn main() -> Result<(), Box> { +//! failspot!(FailDataRead bail(std::io::Error::other("Data read failure enabled"))); +//! Ok(()) +//! } +//! ``` +//! +//! When the `enabled` feature is not on, the macro will evaluate to the empty block, `{}`. +//! +//! ## "bool" syntax +//! +//! Useful to just evaluate whether the failspot is enabled or not: +//! +//! ``` +//! # use {failspot::failspot, std::error::Error}; +//! # failspot::failspot_name! { pub enum FailSpotName { FailDataRead } } +//! # fn main() { +//! # let bytes_to_read = 5; +//! let fail_the_read = bytes_to_read > 5000 || failspot!(FailDataRead); +//! # } +//! ``` +//! +//! When the `enabled` feature is not on, the macro will evaluate to the token `false`. + +#![cfg_attr( + feature = "enabled", + doc = r#" +# Testing code + +Testing code should see the documentation for the [testing] module."# +)] +#![forbid(missing_docs)] + +#[cfg(feature = "enabled")] +pub mod testing; + +/// Declares a spot that can trigger intentional failures +/// +/// See the [crate-level docs][crate] for details. +#[cfg(feature = "enabled")] +#[allow(clippy::crate_in_macro_def)] +#[macro_export] +macro_rules! failspot { +( + if <$e: ty>::$n: ident { + $($enabled: tt)* + } $(else { + $($disabled: tt)* + })? +) => {{ + if $crate::failspot!(<$e>::$n) { + $($enabled)* + } $(else { + $($disabled)* + })? +}}; + +( + if $n: ident { + $($enabled: tt)* + } $(else { + $($disabled: tt)* + })? +) => { + $crate::failspot!( + if ::$n { + $($enabled)* + } $(else { + $($disabled)* + })? + ) +}; + +(<$e: ty>::$n: ident bail($err: expr)) => {{ + if $crate::failspot!(<$e>::$n) { + return Err($err.into()); + } +}}; +($n: ident bail($err: expr)) => { + $crate::failspot!(::$n bail($err)) +}; +(<$e: ty>::$n: ident) => {{ + <$e>::enabled(<$e>::$n) +}}; +($n: ident) => { + $crate::failspot!(::$n) +}; +(<$e: ty>::$n: ident $($enabled: tt)+) => {{ + if $crate::failspot!(<$e>::$n) { + $($enabled)+ + } +}}; +($n: ident $($enabled: tt)+) => { + $crate::failspot!(::$n $($enabled)+) +}} + +/// Declares a spot that can trigger intentional failures +/// +/// See the [crate-level docs][crate] for details. +#[cfg(not(feature = "enabled"))] +#[allow(clippy::crate_in_macro_def)] +#[macro_export] +macro_rules! failspot { +( + if <$e: ty>::$n: ident { + $($enabled: tt)* + } $(else { + $($disabled: tt)* + })? +) => {{$($($disabled)*)?}}; + +( + if $n: ident { + $($enabled: tt)* + } $(else { + $($disabled: tt)* + })? +) => { + $crate::failspot!( + if ::$n { + $($enabled)* + } $(else { + $($disabled)* + })? + ) +}; +(<$e: ty>::$n: ident bail($err: expr)) => {{}}; +($n: ident bail($err: expr)) => { + $crate::failspot!(::$n bail($err)) +}; +(<$e: ty>::$n: ident) => {false}; +($n: ident) => { + $crate::failspot!(::$n) +}; +(<$e: ty>::$n: ident $($enabled: tt)+) => {{}}; +($n: ident $($enabled: tt)+) => { + $crate::failspot!(::$n $($enabled)+) +}} + +/// Declares an enum that can be used as a name for a [failspot] +/// +/// When feature `enabled` is off, this macro does nothing. +/// +/// See the [crate-level docs][crate] for details. +#[cfg(feature = "enabled")] +#[macro_export] +macro_rules! failspot_name {{ + $(#[$m:meta])* + $p:vis enum $n:ident { + $( + $(#[$a:meta])* + $k:ident + ),+ $(,)* + } +} => { + $crate::flagset::flags! { + $(#[$m])* + $p enum $n: usize { + $( + $(#[$a])* + $k + ),+ + } + } + $crate::failspot_global!($n); +}} + +/// Declares an enum that can be used as a name for a [failspot] +/// +/// When feature `enabled` is off, this macro does nothing. +/// +/// See the [crate-level docs][crate] for details. +#[cfg(not(feature = "enabled"))] +#[macro_export] +macro_rules! failspot_name(($($t: tt)*) => ()); + +#[doc(hidden)] +#[macro_export] +macro_rules! failspot_global(($n: ident) => { + impl $n { + pub fn enabled(name: Self) -> bool { + Self::global_config().enabled(name) + } + pub fn testing_client() -> $crate::testing::Client<'static, $n> { + Self::global_config().client() + } + fn global_config() -> &'static $crate::testing::Config<$n> { + static GLOBAL: std::sync::LazyLock<$crate::testing::Config<$n>> = + std::sync::LazyLock::new($crate::testing::Config::default); + &GLOBAL + } + } +}); + +#[cfg(feature = "enabled")] +#[doc(hidden)] +pub use flagset; diff --git a/third_party/rust/failspot/src/testing.rs b/third_party/rust/failspot/src/testing.rs new file mode 100644 index 000000000000..0d40af9fcd32 --- /dev/null +++ b/third_party/rust/failspot/src/testing.rs @@ -0,0 +1,172 @@ +//! Allows testing code to enable and disable failspots +//! +//! When testing a crate, failspots can be enabled through a [Client] object. This can be retrieved +//! by using the `fn testing_client() -> Client<'static, Self>` method that exists as part of +//! every enum that was declared using the [`failspot_name!()`][crate::failspot_name] macro. +//! +//! The [`Client::set_enabled()`][Client::set_enabled] method can be used to set or unset a +//! failspot. [`Client::reset()`][Client::reset] will unset all failspots. +//! +//! Example usage: +//! +//! ``` +//! # failspot::failspot_name! { pub enum FailSpotName { Name1 } } +//! # fn run_tests() {} +//! let mut client = FailSpotName::testing_client(); +//! client.set_enabled(FailSpotName::Name1, true); +//! // When the `Client` object drops, all the failspots will be reset to disabled +//! // Must ensure it stays alive while tests are running. +//! run_tests(); +//! ``` +//! +//! # Concurrency -- Important!!! +//! +//! **TL;DR -- Put all your integration tests that use failspot in a separate source file!** +//! +//! ## The problem +//! +//! In Rust, **tests are run concurrently by default**. Since the configuration for the failspots +//! is a global variable that will be shared by all threads, that would create a problem -- Tests +//! that don't use failspots will suddenly start failing because another concurrent test enabled +//! them, and tests that do use failspots would clobber each other's configuration. +//! +//! To prevent this, the [Client] returned by `testing_client()` is **protected by a mutex** -- +//! Only one test at a time can configure the failspots through the `Client` methods. When the +//! client is dropped, all the failspots are reset to disabled state and the mutex is released so +//! the next test can start with a fresh state. +//! +//! This means **every test that may run concurrently with a failspot test must hold the [Client] +//! object the entire time the test is running**, even if that test doesn't actually use failspots. +//! If there are multiple enums declared with [`failspot_name!()`][crate::failspot_name] then a +//! [Client] object for each enum must be held by every test that may run concurrently. +//! +//! For tests that use failspots, this is intuitive -- Most tests that use failspots will create a +//! [Client] as part of their setup. +//! +//! ## Stopping regular tests from breaking +//! +//! For tests that don't use failspots, there are 2 choices: +//! +//! 1. **Put failspot tests in their own source file (recommended)** Integration tests in +//! different source files are run in different processes, so separating failspot and non +//! failspot tests eliminates the concurrency issue. +//! +//! 2. **Force tests to run serially** By setting `RUST_TEST_THREADS=1` in the enviroment, the +//! tests will run one-at-a-time and there will be no interference. +//! +//! Obviously, the first one should be preferred unless there is a good reason not to. + +use { + flagset::FlagSet, + std::{ + ops::{Deref, DerefMut}, + sync::{Mutex, MutexGuard, RwLock}, + }, +}; + +/// Config object for an enum declared with [`failspot_name!()`][crate::failspot_name] +/// +/// Every failspot enum has one of these attached. It tracks which failspots are currently +/// enabled for that enum, and contains the mutex that ensures that only one [Client] at a time +/// is running. It is not normally used directly by user code, but is instead used by the +/// [`failspot!()`][crate::failspot] macro for testing failpoints, and by the `testing_client()` +/// method to obtain a [Client] for testing code. +#[derive(Debug)] +pub struct Config { + inner: RwLock>, + client_mutex: Mutex<()>, +} + +#[derive(Debug, Eq, PartialEq)] +struct ConfigInner { + enabled_spots: FlagSet, +} + +impl Default for Config { + fn default() -> Self { + Self { + inner: Default::default(), + client_mutex: Default::default(), + } + } +} + +impl Default for ConfigInner { + fn default() -> Self { + Self { + enabled_spots: Default::default(), + } + } +} + +impl Config { + /// Returns whether or not the given failspot is enabled + pub fn enabled(&self, spot: T) -> bool { + self.inner().enabled_spots.contains(spot) + } + /// Returns a client for this failspot config + pub fn client(&self) -> Client<'_, T> { + Client::new(self) + } + fn inner(&self) -> impl Deref> + '_ { + self.inner.read().unwrap() + } + fn inner_mut(&self) -> impl DerefMut> + '_ { + self.inner.write().unwrap() + } +} + +/// Client for testing code +/// +/// See [module-level docs][self], especially the part about concurrency. +#[derive(Debug)] +pub struct Client<'a, T: flagset::Flags> { + config: &'a Config, + _guard: MutexGuard<'a, ()>, +} + +impl<'a, T: flagset::Flags> Client<'a, T> { + /// Create a new [Client]. + /// + /// Normally not used directly -- Use `EnumName::testing_client()` instead + pub fn new(config: &'a Config) -> Self { + let _guard = config + .client_mutex + .lock() + .unwrap_or_else(|e| e.into_inner()); + + assert_eq!( + *config.inner(), + ConfigInner::default(), + "somehow failed to reset config to default after last client" + ); + + Client { config, _guard } + } + /// Set whether the given failspot is enabled or disabled + pub fn set_enabled(&mut self, spot: T, enabled: bool) -> &mut Self { + if enabled { + self.config.inner_mut().enabled_spots |= spot; + } else { + self.config.inner_mut().enabled_spots -= spot; + } + self + } + /// Reset all failspots to disabled + pub fn reset(&mut self) -> &mut Self { + *self.config.inner_mut() = ConfigInner::default(); + self + } + /// Finish with a [Client], resetting all failspots to disabled and releasing the mutex + /// + /// Identical to dropping the [Client], but a bit more explicit about intent. + pub fn finish(self) { + drop(self) + } +} + +impl<'a, T: flagset::Flags> Drop for Client<'a, T> { + fn drop(&mut self) { + self.reset(); + } +} diff --git a/third_party/rust/failspot/tests/failspot.rs b/third_party/rust/failspot/tests/failspot.rs new file mode 100644 index 000000000000..770e328e483b --- /dev/null +++ b/third_party/rust/failspot/tests/failspot.rs @@ -0,0 +1,152 @@ +#![cfg_attr(not(feature = "enabled"), allow(dead_code))] + +failspot::failspot_name! { + pub enum FailSpotName { + One, + Two, + Three, + Four, + } +} + +mod inner { + failspot::failspot_name! { + pub enum FailSpotName2 { + Four, + Five, + Six, + Seven, + } + } +} + +fn stop_process_or_fail() -> Result<(), Box> { + failspot::failspot!(One bail(std::io::Error::other("fail"))); + failspot::failspot!(::Four bail(std::io::Error::other("fail"))); + Ok(()) +} + +fn fill_missing_auxv_or_panic() { + failspot::failspot!(Two panic!()); + failspot::failspot!(::Five panic!()); +} + +fn get_thread_name_or_none() -> Option { + if failspot::failspot!(Three) { + return None; + } + if failspot::failspot!(::Six) { + return None; + } + Some("mythread".to_string()) +} + +fn common() -> Result, Box> { + stop_process_or_fail()?; + fill_missing_auxv_or_panic(); + let name = get_thread_name_or_none(); + + let name = failspot::failspot!(if Four { + name.map(|_| "deleted".to_string()) + } else { + name + }); + + let name = name.map(|name| { + failspot::failspot!(if ::Seven { + "deleted".to_string() + } else { + name + }) + }); + + Ok(name) +} + +#[cfg(feature = "enabled")] +#[test] +fn no_fails() -> Result<(), Box> { + let _client = FailSpotName::testing_client(); + let _client2 = inner::FailSpotName2::testing_client(); + let thread_name = common()?; + assert_eq!(thread_name.as_deref(), Some("mythread")); + Ok(()) +} + +#[cfg(feature = "enabled")] +#[test] +#[should_panic] +fn panic_fail() { + let mut client = FailSpotName::testing_client(); + let _client2 = inner::FailSpotName2::testing_client(); + client.set_enabled(FailSpotName::Two, true); + let _ = common(); +} + +#[cfg(feature = "enabled")] +#[test] +#[should_panic] +fn panic_fail2() { + let mut _client = FailSpotName::testing_client(); + let mut client2 = inner::FailSpotName2::testing_client(); + client2.set_enabled(inner::FailSpotName2::Five, true); + let _ = common(); +} + +#[cfg(feature = "enabled")] +#[test] +fn test_error() { + let mut client = FailSpotName::testing_client(); + let mut _client2 = inner::FailSpotName2::testing_client(); + client.set_enabled(FailSpotName::One, true); + common().unwrap_err(); +} + +#[cfg(feature = "enabled")] +#[test] +fn test_error2() { + let mut _client = FailSpotName::testing_client(); + let mut client2 = inner::FailSpotName2::testing_client(); + client2.set_enabled(inner::FailSpotName2::Four, true); + common().unwrap_err(); +} + +#[cfg(feature = "enabled")] +#[test] +fn expression_fail() { + let mut client = FailSpotName::testing_client(); + let mut _client2 = inner::FailSpotName2::testing_client(); + client.set_enabled(FailSpotName::Three, true); + let thread_name = common().unwrap(); + assert!(thread_name.is_none()); +} + +#[cfg(feature = "enabled")] +#[test] +fn expression_fail2() { + let mut _client = FailSpotName::testing_client(); + let mut client2 = inner::FailSpotName2::testing_client(); + client2.set_enabled(inner::FailSpotName2::Six, true); + let thread_name = common().unwrap(); + assert!(thread_name.is_none()); +} + +#[cfg(feature = "enabled")] +#[test] +fn if_statement_fail() { + let mut client = FailSpotName::testing_client(); + let mut _client2 = inner::FailSpotName2::testing_client(); + client.set_enabled(FailSpotName::Four, true); + let thread_name = common().unwrap(); + assert!(thread_name.as_deref() == Some("deleted")); +} + +#[cfg(feature = "enabled")] +#[test] +fn if_statement_fail2() { + let mut _client = FailSpotName::testing_client(); + let mut client2 = inner::FailSpotName2::testing_client(); + client2.set_enabled(inner::FailSpotName2::Seven, true); + let thread_name = common().unwrap(); + assert!(thread_name.as_deref() == Some("deleted")); +} diff --git a/third_party/rust/framehop/.cargo-checksum.json b/third_party/rust/framehop/.cargo-checksum.json index 7c7cc70ada49..e31e5e8d04bd 100644 --- a/third_party/rust/framehop/.cargo-checksum.json +++ b/third_party/rust/framehop/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"6b9b3906662b434710edcd87739806a1b4d1312794f969b50e50705025c9d611","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"9ec2734f45b0d65192b9fee2307e05176b805a19efa994a553dcc5b2d3219a1e","Readme.md":"f1c7d3ed5b9ec8dbc9f87d742b213573d0667ca4b4d148cf1e72681115093e67","src/aarch64/arch.rs":"894d1d66ba487363cdf5f2dd66c20ff6560e3906e7c6ecd80e5fc11a682fa5d9","src/aarch64/cache.rs":"88bfc7ee6d38bd0a0fb5532f29fbcec88fd6a222db0e1a3398e0168d7c05d82c","src/aarch64/dwarf.rs":"800bb304e8d746fb1857c2da5486f278242103ea7eac45b1cdc135b1eb3b92f1","src/aarch64/instruction_analysis/epilogue.rs":"fe45d3fbb92dc7224526fb1e613019ebf36a9f2aa3f8fb52217d20744fbda3ae","src/aarch64/instruction_analysis/mod.rs":"6298b1c5b96a5ac8b1ca39a9764b1b71af8ca4a60b6a435e7404e0b02e700f6a","src/aarch64/instruction_analysis/prologue.rs":"065172ee6e2cb868c76dad0d704f0da15397e94424cb0c5522e4bffcae1b0f19","src/aarch64/macho.rs":"ec88fb0c02707d3d96a41f22bb2f698909af26b41ac9cca6b0244e837e240504","src/aarch64/mod.rs":"a94c4c0b1d3e08bce5b0baf9a6ba1b59f42da2809ce970b8a9050b9c3c46e00a","src/aarch64/pe.rs":"6800dfee18cb8eb96d8802c4a175cfca511d9503a7b6c09d0ce7e84c28d8a1a8","src/aarch64/unwind_rule.rs":"1119387590f16f4582672095f6c9462a94e3d4eaf448baa19c432c5e57fa055d","src/aarch64/unwinder.rs":"1dd24b21a49cf1b2fdcb5fada2afb54b2df269d3560be1e1f0063604593f26f1","src/aarch64/unwindregs.rs":"19e5fd82d62eac135c9075e75c0b031f3037a4b670060b3bc6746ef6d71685f8","src/add_signed.rs":"8c52b1d7c7dfc5cbdd477ff9dcce2e888f663a19e8ef6b89c209c06f7a532203","src/arch.rs":"f7dff12cdc2cf91986a5cb3c8d492f608264bd789841a0cfab1c7042233f0488","src/cache.rs":"90569eba164d72c3d20a0465d05a92bc35ceba38c21b944ced3c759f61be3268","src/code_address.rs":"1e2bd03a5813c0100171c7020dc05d8457e2670c7ef58c0c4e3627bf1d82f1b1","src/display_utils.rs":"2f874fd4778e7e304365d8b65d60dc4a5a8fa5ee2715740dc64e334989a1276d","src/dwarf.rs":"79689d0d16a5ccdb5a6c90d690602d1b9bb0100543c2922b47a4c5715004c581","src/error.rs":"bbcaa2ede65b465bff515e19c50f4a8b76c4fcb481297a50427fd21689121294","src/instruction_analysis.rs":"1023577c008a71805338cd45b8582774dd8c69c7bb349990992733297761743e","src/lib.rs":"f57770c147c5de29b4a3600675b459ce26925ad8c5be19ab0c9545883a7a9320","src/macho.rs":"472cd64d0ef4c4d7b91f3d19307875f61db67de52273fef186da9ede89016982","src/pe.rs":"d50f13dd153d124c3b76df7930295e2310381e7490d45563382775422a858bfe","src/rule_cache.rs":"d764fe5e9202314b77e536a7ebe7cb4d574494eeaeb76d2e7a13ff6b0770cf3b","src/unwind_result.rs":"ec6898d9e66b455978880884199d5570fd220c7d3d1101c6b854b9a2b6cea88d","src/unwind_rule.rs":"3335e0d2af34961ba4eff2d89db6bdde5950909f352539e96852c42b3ca16139","src/unwinder.rs":"1ccd6b02770ed54f8837615cd0da02be75e92da9db304e17a14b6cf8f36dd3e0","src/x86_64/arch.rs":"12ea62c70058eac1c2aa698594cc83fafc5d8ec7205596c4b6f6ff325bd1ed8d","src/x86_64/cache.rs":"57eecbc7a0eea21269ba87e80efd985b13d420b2546722ae1b7c73e2e1731169","src/x86_64/dwarf.rs":"6643cc16ac524c325c02ae3a980dd95da38f660328d7b75c1081454b85e24925","src/x86_64/instruction_analysis/epilogue.rs":"21b98f794ec11d501497904b352017d678ea57a2a1f1617a625b1044de1c79c5","src/x86_64/instruction_analysis/mod.rs":"df9089f73861574607dab07fda68b8c5bf1ff426401840a6c35503bda9996143","src/x86_64/instruction_analysis/prologue.rs":"57f2a9376a70ca708c0d9c85bd324edff8062f73102aa57a9c6319627d8189ad","src/x86_64/macho.rs":"1b8eb6622d36115ac664c54d2a8768cbadd17bdcf252e368cf5ea8a35339d5b9","src/x86_64/mod.rs":"160ad03cce68b6263028fa9eaf460a89fee57795a81adac8bed9c7d4fdf0ebad","src/x86_64/pe.rs":"25d850fc896e635831c90c1e4073900b32b02fff88858aa579a986aa4052d54e","src/x86_64/register_ordering.rs":"e4e01b5506eaf1d448874e10930035d4a67b8077803e2ceee305d9c5aa88cd2f","src/x86_64/unwind_rule.rs":"f5be036172ac469cbc8248047411cbd43931a1def52cc9fcacce54210abc9824","src/x86_64/unwinder.rs":"2d7228655cc427266e31f1405f44b9e81bb119b9eb0f4abb9a29b39697db2b44","src/x86_64/unwindregs.rs":"63b358fe31b613d456982360ff659927d540b502f9c1a3145c4ba66beb4afdfc"},"package":"0fd28d2036d4fd99e3629487baca659e5af1c5d554e320168613be79028610fc"} \ No newline at end of file +{"files":{"Cargo.toml":"9899c522be4b56e17638b19aa8ee37132f5654b32cba8bfe73e3f6929975ffad","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"9ec2734f45b0d65192b9fee2307e05176b805a19efa994a553dcc5b2d3219a1e","Readme.md":"f1c7d3ed5b9ec8dbc9f87d742b213573d0667ca4b4d148cf1e72681115093e67","src/aarch64/arch.rs":"894d1d66ba487363cdf5f2dd66c20ff6560e3906e7c6ecd80e5fc11a682fa5d9","src/aarch64/cache.rs":"88bfc7ee6d38bd0a0fb5532f29fbcec88fd6a222db0e1a3398e0168d7c05d82c","src/aarch64/dwarf.rs":"800bb304e8d746fb1857c2da5486f278242103ea7eac45b1cdc135b1eb3b92f1","src/aarch64/instruction_analysis/epilogue.rs":"fe45d3fbb92dc7224526fb1e613019ebf36a9f2aa3f8fb52217d20744fbda3ae","src/aarch64/instruction_analysis/mod.rs":"6298b1c5b96a5ac8b1ca39a9764b1b71af8ca4a60b6a435e7404e0b02e700f6a","src/aarch64/instruction_analysis/prologue.rs":"065172ee6e2cb868c76dad0d704f0da15397e94424cb0c5522e4bffcae1b0f19","src/aarch64/macho.rs":"ec88fb0c02707d3d96a41f22bb2f698909af26b41ac9cca6b0244e837e240504","src/aarch64/mod.rs":"a94c4c0b1d3e08bce5b0baf9a6ba1b59f42da2809ce970b8a9050b9c3c46e00a","src/aarch64/pe.rs":"6800dfee18cb8eb96d8802c4a175cfca511d9503a7b6c09d0ce7e84c28d8a1a8","src/aarch64/unwind_rule.rs":"1119387590f16f4582672095f6c9462a94e3d4eaf448baa19c432c5e57fa055d","src/aarch64/unwinder.rs":"1dd24b21a49cf1b2fdcb5fada2afb54b2df269d3560be1e1f0063604593f26f1","src/aarch64/unwindregs.rs":"19e5fd82d62eac135c9075e75c0b031f3037a4b670060b3bc6746ef6d71685f8","src/add_signed.rs":"8c52b1d7c7dfc5cbdd477ff9dcce2e888f663a19e8ef6b89c209c06f7a532203","src/arch.rs":"f7dff12cdc2cf91986a5cb3c8d492f608264bd789841a0cfab1c7042233f0488","src/cache.rs":"90569eba164d72c3d20a0465d05a92bc35ceba38c21b944ced3c759f61be3268","src/code_address.rs":"1e2bd03a5813c0100171c7020dc05d8457e2670c7ef58c0c4e3627bf1d82f1b1","src/display_utils.rs":"2f874fd4778e7e304365d8b65d60dc4a5a8fa5ee2715740dc64e334989a1276d","src/dwarf.rs":"79689d0d16a5ccdb5a6c90d690602d1b9bb0100543c2922b47a4c5715004c581","src/error.rs":"bbcaa2ede65b465bff515e19c50f4a8b76c4fcb481297a50427fd21689121294","src/instruction_analysis.rs":"1023577c008a71805338cd45b8582774dd8c69c7bb349990992733297761743e","src/lib.rs":"f57770c147c5de29b4a3600675b459ce26925ad8c5be19ab0c9545883a7a9320","src/macho.rs":"472cd64d0ef4c4d7b91f3d19307875f61db67de52273fef186da9ede89016982","src/pe.rs":"d50f13dd153d124c3b76df7930295e2310381e7490d45563382775422a858bfe","src/rule_cache.rs":"d764fe5e9202314b77e536a7ebe7cb4d574494eeaeb76d2e7a13ff6b0770cf3b","src/unwind_result.rs":"ec6898d9e66b455978880884199d5570fd220c7d3d1101c6b854b9a2b6cea88d","src/unwind_rule.rs":"3335e0d2af34961ba4eff2d89db6bdde5950909f352539e96852c42b3ca16139","src/unwinder.rs":"72874a341338b3d536b1ab4602cffe8d05fd7f59063d2f55985a5d3843203ef7","src/x86_64/arch.rs":"12ea62c70058eac1c2aa698594cc83fafc5d8ec7205596c4b6f6ff325bd1ed8d","src/x86_64/cache.rs":"57eecbc7a0eea21269ba87e80efd985b13d420b2546722ae1b7c73e2e1731169","src/x86_64/dwarf.rs":"6643cc16ac524c325c02ae3a980dd95da38f660328d7b75c1081454b85e24925","src/x86_64/instruction_analysis/epilogue.rs":"21b98f794ec11d501497904b352017d678ea57a2a1f1617a625b1044de1c79c5","src/x86_64/instruction_analysis/mod.rs":"df9089f73861574607dab07fda68b8c5bf1ff426401840a6c35503bda9996143","src/x86_64/instruction_analysis/prologue.rs":"57f2a9376a70ca708c0d9c85bd324edff8062f73102aa57a9c6319627d8189ad","src/x86_64/macho.rs":"1b8eb6622d36115ac664c54d2a8768cbadd17bdcf252e368cf5ea8a35339d5b9","src/x86_64/mod.rs":"160ad03cce68b6263028fa9eaf460a89fee57795a81adac8bed9c7d4fdf0ebad","src/x86_64/pe.rs":"25d850fc896e635831c90c1e4073900b32b02fff88858aa579a986aa4052d54e","src/x86_64/register_ordering.rs":"e4e01b5506eaf1d448874e10930035d4a67b8077803e2ceee305d9c5aa88cd2f","src/x86_64/unwind_rule.rs":"f5be036172ac469cbc8248047411cbd43931a1def52cc9fcacce54210abc9824","src/x86_64/unwinder.rs":"2d7228655cc427266e31f1405f44b9e81bb119b9eb0f4abb9a29b39697db2b44","src/x86_64/unwindregs.rs":"63b358fe31b613d456982360ff659927d540b502f9c1a3145c4ba66beb4afdfc"},"package":"33e8ad8f843eb89b4ec8270be4d5840dc6b81ca1a1c1e036b17e94076f36eed4"} \ No newline at end of file diff --git a/third_party/rust/framehop/Cargo.toml b/third_party/rust/framehop/Cargo.toml index 0901d8bbe0d7..f605c7891865 100644 --- a/third_party/rust/framehop/Cargo.toml +++ b/third_party/rust/framehop/Cargo.toml @@ -12,7 +12,7 @@ [package] edition = "2021" name = "framehop" -version = "0.12.1" +version = "0.13.0" authors = ["Markus Stange "] exclude = [ "/.github", @@ -48,7 +48,7 @@ version = "1.0.0" version = "0.3.0" [dependencies.gimli] -version = "0.30" +version = "0.31" features = ["read"] default-features = false @@ -56,12 +56,6 @@ default-features = false version = "0.4.0" optional = true -[dependencies.object] -version = "0.36" -features = ["read_core"] -optional = true -default-features = false - [dependencies.pe-unwind-info] version = "0.2.1" optional = true diff --git a/third_party/rust/framehop/src/unwinder.rs b/third_party/rust/framehop/src/unwinder.rs index 49c7cda1cb12..fd3dc31c4e8d 100644 --- a/third_party/rust/framehop/src/unwinder.rs +++ b/third_party/rust/framehop/src/unwinder.rs @@ -936,51 +936,6 @@ where } } -#[cfg(feature = "object")] -mod object { - use super::{ModuleSectionInfo, Range}; - use object::read::{Object, ObjectSection, ObjectSegment}; - - impl<'data: 'file, 'file, O, D> ModuleSectionInfo for &'file O - where - O: Object<'data>, - D: From<&'data [u8]>, - { - fn base_svma(&self) -> u64 { - if let Some(text_segment) = self.segments().find(|s| s.name() == Ok(Some("__TEXT"))) { - // This is a mach-O image. "Relative addresses" are relative to the - // vmaddr of the __TEXT segment. - return text_segment.address(); - } - - // For PE binaries, relative_address_base() returns the image base address. - // Otherwise it returns zero. This gives regular ELF images a base address of zero, - // which is what we want. - self.relative_address_base() - } - - fn section_svma_range(&mut self, name: &[u8]) -> Option> { - let section = self.section_by_name_bytes(name)?; - Some(section.address()..section.address() + section.size()) - } - - fn section_data(&mut self, name: &[u8]) -> Option { - let section = self.section_by_name_bytes(name)?; - section.data().ok().map(|data| data.into()) - } - - fn segment_svma_range(&mut self, name: &[u8]) -> Option> { - let segment = self.segments().find(|s| s.name_bytes() == Ok(Some(name)))?; - Some(segment.address()..segment.address() + segment.size()) - } - - fn segment_data(&mut self, name: &[u8]) -> Option { - let segment = self.segments().find(|s| s.name_bytes() == Ok(Some(name)))?; - segment.data().ok().map(|data| data.into()) - } - } -} - impl> Module { pub fn new( name: String, diff --git a/third_party/rust/gimli/.cargo-checksum.json b/third_party/rust/gimli/.cargo-checksum.json index 0e8c64a55b24..ab8b822a28b8 100644 --- a/third_party/rust/gimli/.cargo-checksum.json +++ b/third_party/rust/gimli/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"39644968fcea2bf6cf14f94047cc8b5e9785797631c0cd8033e4e2cdbcf27969","Cargo.toml":"1ecca3db954f8885686c1e3ca6b7222d500bc26926a46438eabd519569109c32","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"6b55025491f62ca7dd19a7a6cdb9154b06db33c85247c88a19804ab1c1ba2b5e","src/arch.rs":"735a8e871479263ad2dd86c38cc68167da320800ca70b8b1d25a224e5f3d0bd8","src/common.rs":"92bb5bc1eebe0a1906389a75096288773bb86b8895b827851bfb082a3c4999f8","src/constants.rs":"33b74f752fc11aefa1f5ef36a08c2fac19453e6d16f8e490d15b2eabcd63a55c","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"996d5c79d027f97c010ca487bc4ff5f8265f4b9e63d62b4e4fa291383c259ee9","src/lib.rs":"538a8080f33a0641f831e883085425c36cbce2ae39e0cd5e0b6c7c062bca7712","src/read/abbrev.rs":"f937e45d151ac5073f2c526b792e86e5ba96d3d36cb0377682a596c272be589a","src/read/addr.rs":"a6a535b690793e4c8ec85127d558e796cb8f6272533cd0418886bbc44289039e","src/read/aranges.rs":"fd3ff965cfd23c8b425c555f8f34a190764ae993433f32c63f9452c6604806cd","src/read/cfi.rs":"93e7572e44d97d10977833cedab78d68b6f0fec643edda4a613ad8ae845a93ce","src/read/dwarf.rs":"0f30d814dfe067aa6fbd0b80dac8e1a2532e2c5cd5e584c151a8915356b6b2d7","src/read/endian_reader.rs":"25752b609d74ad7dc85df84d044d0e931024a95af72a760cd51f834016775b3e","src/read/endian_slice.rs":"5b44661714967780b8c9f52fdaf655a53e309c38cbd3daf11bf6b1d5f6d067bb","src/read/index.rs":"2a28d032bc3bc5235545ac526b367512ac0aa7807909b6c02c8d3f84f5beff87","src/read/line.rs":"463fedce39895af793cdce413d9593cfd3470939f9f944fd7814ded5946d5b7e","src/read/lists.rs":"67ca9e1a36a91feb4996d035211de845205212bfda02163685d217818567ff93","src/read/loclists.rs":"a05933e752d44c1d26e83c321dbc1b8a3616b1d76ad15f488858f7f74fd3aece","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"1154168832c544acd31f467668fb86536232138c84e5918ba3b1cc66d1554d05","src/read/op.rs":"8782f09332eea1a218aa524a67c9c1cc2e73a8210b30402519dbe8fcf21dcf6e","src/read/pubnames.rs":"ed752ee1a7017e6d3be42d81e4ddaaac960ef08081463a19106c9f041526d4a3","src/read/pubtypes.rs":"5e75b32c0923e827aff0bb2db456797a0e8d38ba46be992558a7990b3196bcf5","src/read/reader.rs":"afc9c2cfbfe0fce5b1825d029f8e841100f48b04b86181950a213fbb82e6ad63","src/read/relocate.rs":"6844b113eb8218152e29912accc54b26bc2498e97bfe4af824472ddb69b8601c","src/read/rnglists.rs":"d1afeb1779d145493a1fc665fa32820c63c539e40b10ecd5b5f343836da188e6","src/read/str.rs":"4dd98cc8d93ce6f06c194eae034bfe0a3d45a9f06fbeaca38d8f29a9c7cf15a5","src/read/unit.rs":"bcff85e55148bf141984a4cb20eb5983cfd85de6e8a4535cef2ab19e8e0f5103","src/read/util.rs":"61e41212f1c8336988c9a7a1523c2913af8c8a66d2dd59d3631ba179e801e3bd","src/read/value.rs":"1c0db3759c65ffda3520fcecd36118367dfb46845035d5d97fcba2f0ea780380","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"323ab703251a41fe83172d749c8afec7d869c5d52e8edd85d7b87450102e6e3a","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"80f7626f15467d69fb73a9d9fda7863fe343f236d5fcdbc353bdf2a2a4b1bb42","src/write/loc.rs":"2a58b0f57ab344f23de81e459f6fefa153e29e0384af31bbcbc80095af0fa703","src/write/mod.rs":"6e43a028baf73bf50ee276a3f08f31adc69cacdde25d56b55f14c0d48ca6f3aa","src/write/op.rs":"e599fa116366f273ca33da3428132f2b9da21c0cc50a0c0ccfd0f524ccb4e82e","src/write/range.rs":"28033849e7912f60d137c2f2e0065c5169a7f16896b179178c8e3674d7c2785e","src/write/relocate.rs":"117b97eae3ca2aad9d5b242652ebbdb333440e877be37873a7ef5ba1a39ced43","src/write/section.rs":"126a0202d606ea94d5b7ee4853afefb05f2546710210954fd0cc18af8674a511","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"35419f917bd759ab026c9701ac0aef9a945ffb95a10f1c9c72608020206edf44","src/write/writer.rs":"7d5dd07b82ec3becebb060c106d4ea697cbd8b9b64a5de78403511a5244e08b1"},"package":"e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9"} \ No newline at end of file +{"files":{"CHANGELOG.md":"3947775ed524a59bfbe1e9bb695ff03629da07f12e8a15df600d2a79a8a5f8fa","Cargo.toml":"a59608f272a0c354fd03374fa94556d7858281e516a4bea82c05e42e15eb7c81","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7b63ecd5f1902af1b63729947373683c32745c16a10e8e6292e2e2dcd7e90ae0","README.md":"004c3170ee488dd64b91927a99024a884463d0dfebf98bdb9a3526d08895e0c0","src/arch.rs":"735a8e871479263ad2dd86c38cc68167da320800ca70b8b1d25a224e5f3d0bd8","src/common.rs":"f3ba70eaf7f9a5978bdcbdf20fab5f7c2bfa5d4816e765d59f064500231938da","src/constants.rs":"d28ab78922d0cb49b1cd0897b4fa46e337f3af99492f9715349807ac962c3147","src/endianity.rs":"1f7e62ae34f540c06bedf1e7948739211556eea7dd83731a5ca52c7d687ed0fc","src/leb128.rs":"81a0ca0e8ba56e749af4588fe76179611234062f79be1e9fb8ea8a27516b372f","src/lib.rs":"7c2640854e32a8b974f4e577b4a30e29f3d682e72203ce1d2a657e87752477ff","src/read/abbrev.rs":"f937e45d151ac5073f2c526b792e86e5ba96d3d36cb0377682a596c272be589a","src/read/addr.rs":"a6a535b690793e4c8ec85127d558e796cb8f6272533cd0418886bbc44289039e","src/read/aranges.rs":"464bd2deb2b7510a53c9068cc236c588aef3cad640868a4cae6fed6a0303c6af","src/read/cfi.rs":"298066749e66065b451f4ad9bbec9d959211fb2a90b0d93bb39297b1eec5f6cd","src/read/dwarf.rs":"708b821ec5c8e73530ef5b5adec092296b7e78b9187958336154840ed275fbd2","src/read/endian_reader.rs":"6e7bf5b26719b1a5e396159387bb10666b218c10e603a4552882ec9d4d5cb8be","src/read/endian_slice.rs":"5b44661714967780b8c9f52fdaf655a53e309c38cbd3daf11bf6b1d5f6d067bb","src/read/index.rs":"42c9aae82e87cf7451d4434f68cd5d84e6bb482e51742af213a711b053633085","src/read/line.rs":"46c8a779d19533e7aac4edb035ab86839a5173e3418b37d45c0a2a6bfeb6d5fc","src/read/lists.rs":"5a4e33038ceedb48a8332a7713ee67a1be9b7a4031881a2ccb9b9259ba29356b","src/read/loclists.rs":"8276b94599cc2fdbf25cee1cfd13236e1b00c12897268cd164b58f2515dab52b","src/read/lookup.rs":"0cf89ba12b9d48b1fe035dd3a497730323acb9427a9457abbc2f7c58c4c71165","src/read/mod.rs":"89b718ead26a4bda49d6185dee081c9b42a8839397fb3337c9a0ffa18105f5b5","src/read/op.rs":"0a24a7ab1de6e9799da6cce4b838c2264f88c3fd8936fd0601e3a7ac44c5a72d","src/read/pubnames.rs":"ed752ee1a7017e6d3be42d81e4ddaaac960ef08081463a19106c9f041526d4a3","src/read/pubtypes.rs":"5e75b32c0923e827aff0bb2db456797a0e8d38ba46be992558a7990b3196bcf5","src/read/reader.rs":"502b303d33e2cb93fba54c97b487bf3f2216d645ab1c6eae8f4cad9c2e8f27e2","src/read/relocate.rs":"6844b113eb8218152e29912accc54b26bc2498e97bfe4af824472ddb69b8601c","src/read/rnglists.rs":"2f4259326078b5dd7e2643265cd3c9bcfb74f938188c5adac96c8ae0ea2a99bf","src/read/str.rs":"4dd98cc8d93ce6f06c194eae034bfe0a3d45a9f06fbeaca38d8f29a9c7cf15a5","src/read/unit.rs":"f2fc760be1337a6a0351e9921e6e2e6290b17b6cfada6db96e0ebb3fdee68c90","src/read/util.rs":"61e41212f1c8336988c9a7a1523c2913af8c8a66d2dd59d3631ba179e801e3bd","src/read/value.rs":"1c0db3759c65ffda3520fcecd36118367dfb46845035d5d97fcba2f0ea780380","src/test_util.rs":"291eefa6b51c6d934ba2f4a4c9bc7c403046fc1cccf4d43487820f0154bb89e2","src/write/abbrev.rs":"fa02163389e92e804d139cf84f833ab6af932083f0eb2d74464b4a70bd3237ff","src/write/cfi.rs":"22e93c21552d8d6329f5d9ea1c515fbe3820a23e89fff1b38d9478fa2bbab723","src/write/dwarf.rs":"8a1a0893e31134ad68993994594f3024ad0c8af7c1188b29e0ffc26b42edef21","src/write/endian_vec.rs":"1d5811986648816a677580b22630f5059757a381487d73e9adbb3008c9ae0c58","src/write/line.rs":"a8686164701dc2b19954a1f17da635c6f162fe9eec3fa66b2a368ae1940e6703","src/write/loc.rs":"2a58b0f57ab344f23de81e459f6fefa153e29e0384af31bbcbc80095af0fa703","src/write/mod.rs":"7ebf0af9d4b558e1c24c7e6b84ae9c75b7e75c83d09a03ef8608973052d31913","src/write/op.rs":"e599fa116366f273ca33da3428132f2b9da21c0cc50a0c0ccfd0f524ccb4e82e","src/write/range.rs":"28033849e7912f60d137c2f2e0065c5169a7f16896b179178c8e3674d7c2785e","src/write/relocate.rs":"117b97eae3ca2aad9d5b242652ebbdb333440e877be37873a7ef5ba1a39ced43","src/write/section.rs":"126a0202d606ea94d5b7ee4853afefb05f2546710210954fd0cc18af8674a511","src/write/str.rs":"4850cc2fee55980f9cbb6b4169f9861ab9d05c2b28a85c2b790480b83a66f514","src/write/unit.rs":"e0552266b0b39b74ab4676ca5cebed333fc34e9fb0b735f3509943058926f7e3","src/write/writer.rs":"c7696a3c2cff032ad6ada696132e4bbef92c4af76c7370c9ce82dedf2cf3716b"},"package":"32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"} \ No newline at end of file diff --git a/third_party/rust/gimli/CHANGELOG.md b/third_party/rust/gimli/CHANGELOG.md index 18a269194854..f1fe8bd535e9 100644 --- a/third_party/rust/gimli/CHANGELOG.md +++ b/third_party/rust/gimli/CHANGELOG.md @@ -2,6 +2,60 @@ -------------------------------------------------------------------------------- +## 0.31.0 + +Released 2024/07/16. + +### Breaking changes + +* Deleted support for segment selectors. + [#720](https://github.com/gimli-rs/gimli/pull/720) + +* Added `read::FileEntry::source` and deleted `Copy` implementation. + [#728](https://github.com/gimli-rs/gimli/pull/728) + +* Changed `read::LineRow::execute` to return a `Result`. + [#731](https://github.com/gimli-rs/gimli/pull/731) + +* Deleted `Display` implementation for `read::LineInstruction`. + [#734](https://github.com/gimli-rs/gimli/pull/734) + +* Changed `read::Error` to be non-exhaustive. + +### Changed + +* Fixed `Hash` implementation for `read::EndianReader`. + [#723](https://github.com/gimli-rs/gimli/pull/723) + +* Changed `read::EhFrameHdr::parse` to validate the FDE count encoding. + [#725](https://github.com/gimli-rs/gimli/pull/725) + +* Changed address overflow to be an error for `read::UnwindTableRow`, + `read::LineRow`, and `read::ArangeEntry`. + [#730](https://github.com/gimli-rs/gimli/pull/730) + [#731](https://github.com/gimli-rs/gimli/pull/731) + [#732](https://github.com/gimli-rs/gimli/pull/732) + +* Changed wrapping addition for 32-bit addresses to wrap at 32 bits instead of + at 64 bits. + [#733](https://github.com/gimli-rs/gimli/pull/733) + +* Added earlier validation of address sizes. + [#733](https://github.com/gimli-rs/gimli/pull/733) + +### Added + +* Added `read::IndexSectionId::section_id`. + [#719](https://github.com/gimli-rs/gimli/pull/719) + +* Added `read::FrameDescriptionEntry::end_address`. + [#727](https://github.com/gimli-rs/gimli/pull/727) + +* Added support for `DW_LNCT_LLVM_source`. + [#728](https://github.com/gimli-rs/gimli/pull/728) + +-------------------------------------------------------------------------------- + ## 0.30.0 Released 2024/05/26. diff --git a/third_party/rust/gimli/Cargo.toml b/third_party/rust/gimli/Cargo.toml index 4a0be3a4b8c0..7723e7ed5636 100644 --- a/third_party/rust/gimli/Cargo.toml +++ b/third_party/rust/gimli/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" rust-version = "1.60" name = "gimli" -version = "0.30.0" +version = "0.31.0" include = [ "/CHANGELOG.md", "/Cargo.toml", @@ -24,7 +24,7 @@ include = [ ] description = "A library for reading and writing the DWARF debugging format." documentation = "https://docs.rs/gimli" -readme = "./README.md" +readme = "README.md" keywords = [ "DWARF", "debug", diff --git a/third_party/rust/gimli/README.md b/third_party/rust/gimli/README.md index 991e185d0868..a5c52b9f9ea6 100644 --- a/third_party/rust/gimli/README.md +++ b/third_party/rust/gimli/README.md @@ -30,7 +30,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -gimli = "0.30.0" +gimli = "0.31.0" ``` The minimum supported Rust version is: diff --git a/third_party/rust/gimli/src/common.rs b/third_party/rust/gimli/src/common.rs index cad9568af79b..515718f3c930 100644 --- a/third_party/rust/gimli/src/common.rs +++ b/third_party/rust/gimli/src/common.rs @@ -48,8 +48,6 @@ pub struct Encoding { /// The size of an address. pub address_size: u8, - // The size of a segment selector. - // TODO: pub segment_size: u8, /// Whether the DWARF format is 32- or 64-bit. pub format: Format, diff --git a/third_party/rust/gimli/src/constants.rs b/third_party/rust/gimli/src/constants.rs index 4bb43ec951b0..8d39288dc1de 100644 --- a/third_party/rust/gimli/src/constants.rs +++ b/third_party/rust/gimli/src/constants.rs @@ -1052,7 +1052,10 @@ DwLnct(u16) { DW_LNCT_timestamp = 0x3, DW_LNCT_size = 0x4, DW_LNCT_MD5 = 0x5, + // DW_LNCT_source = 0x6, DW_LNCT_lo_user = 0x2000, + // We currently only implement the LLVM embedded source code extension for DWARF v5. + DW_LNCT_LLVM_source = 0x2001, DW_LNCT_hi_user = 0x3fff, }); diff --git a/third_party/rust/gimli/src/leb128.rs b/third_party/rust/gimli/src/leb128.rs index de81cfdcf1e2..c0ee303ae54d 100644 --- a/third_party/rust/gimli/src/leb128.rs +++ b/third_party/rust/gimli/src/leb128.rs @@ -56,7 +56,7 @@ fn low_bits_of_byte(byte: u8) -> u8 { #[inline] #[allow(dead_code)] fn low_bits_of_u64(val: u64) -> u8 { - let byte = val & u64::from(core::u8::MAX); + let byte = val & u64::from(u8::MAX); low_bits_of_byte(byte as u8) } @@ -465,7 +465,7 @@ mod tests { for i in -513..513 { inner(i); } - inner(core::i64::MIN); + inner(i64::MIN); } #[test] diff --git a/third_party/rust/gimli/src/lib.rs b/third_party/rust/gimli/src/lib.rs index 213e2cbddc95..c69823c2ff2e 100644 --- a/third_party/rust/gimli/src/lib.rs +++ b/third_party/rust/gimli/src/lib.rs @@ -9,15 +9,15 @@ //! Cargo features that can be enabled with `gimli`: //! //! * `std`: Enabled by default. Use the `std` library. Disabling this feature -//! allows using `gimli` in embedded environments that do not have access to -//! `std`. Note that even when `std` is disabled, `gimli` still requires an -//! implementation of the `alloc` crate. +//! allows using `gimli` in embedded environments that do not have access to +//! `std`. Note that even when `std` is disabled, `gimli` still requires an +//! implementation of the `alloc` crate. //! //! * `read`: Enabled by default. Enables the `read` module. Use of `std` is -//! optional. +//! optional. //! //! * `write`: Enabled by default. Enables the `write` module. Always uses -//! the `std` library. +//! the `std` library. #![deny(missing_docs)] #![deny(missing_debug_implementations)] // Selectively enable rust 2018 warnings diff --git a/third_party/rust/gimli/src/read/aranges.rs b/third_party/rust/gimli/src/read/aranges.rs index 12bcec7e61e3..fd9f8353e11d 100644 --- a/third_party/rust/gimli/src/read/aranges.rs +++ b/third_party/rust/gimli/src/read/aranges.rs @@ -1,6 +1,8 @@ use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId}; use crate::endianity::Endianity; -use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section}; +use crate::read::{ + EndianSlice, Error, Range, Reader, ReaderAddress, ReaderOffset, Result, Section, +}; /// The `DebugAranges` struct represents the DWARF address range information /// found in the `.debug_aranges` section. @@ -135,7 +137,6 @@ where encoding: Encoding, length: Offset, debug_info_offset: DebugInfoOffset, - segment_size: u8, entries: R, } @@ -158,21 +159,22 @@ where } let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?; - let address_size = rest.read_u8()?; + let address_size = rest.read_address_size()?; let segment_size = rest.read_u8()?; + if segment_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } // unit_length + version + offset + address_size + segment_size let header_length = format.initial_length_size() + 2 + format.word_size() + 1 + 1; // The first tuple following the header in each set begins at an offset that is - // a multiple of the size of a single tuple (that is, the size of a segment selector - // plus twice the size of an address). + // a multiple of the size of a single tuple (that is, twice the size of an address). let tuple_length = address_size .checked_mul(2) - .and_then(|x| x.checked_add(segment_size)) - .ok_or(Error::InvalidAddressRange)?; + .ok_or(Error::UnsupportedAddressSize(address_size))?; if tuple_length == 0 { - return Err(Error::InvalidAddressRange); + return Err(Error::UnsupportedAddressSize(address_size)); } let padding = if header_length % tuple_length == 0 { 0 @@ -185,14 +187,12 @@ where format, version, address_size, - // TODO: segment_size }; Ok(ArangeHeader { offset, encoding, length, debug_info_offset, - segment_size, entries: rest, }) } @@ -215,12 +215,6 @@ where self.encoding } - /// Return the segment size for this set of entries. - #[inline] - pub fn segment_size(&self) -> u8 { - self.segment_size - } - /// Return the offset into the .debug_info section for this set of arange entries. #[inline] pub fn debug_info_offset(&self) -> DebugInfoOffset { @@ -233,7 +227,6 @@ where ArangeEntryIter { input: self.entries.clone(), encoding: self.encoding, - segment_size: self.segment_size, } } } @@ -246,7 +239,6 @@ where pub struct ArangeEntryIter { input: R, encoding: Encoding, - segment_size: u8, } impl ArangeEntryIter { @@ -261,7 +253,7 @@ impl ArangeEntryIter { return Ok(None); } - match ArangeEntry::parse(&mut self.input, self.encoding, self.segment_size) { + match ArangeEntry::parse(&mut self.input, self.encoding) { Ok(Some(entry)) => Ok(Some(entry)), Ok(None) => { self.input.empty(); @@ -288,61 +280,40 @@ impl fallible_iterator::FallibleIterator for ArangeEntryIter { /// A single parsed arange. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct ArangeEntry { - segment: Option, - address: u64, + range: Range, length: u64, } impl ArangeEntry { /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange. - fn parse( - input: &mut R, - encoding: Encoding, - segment_size: u8, - ) -> Result> { + fn parse(input: &mut R, encoding: Encoding) -> Result> { let address_size = encoding.address_size; - let tuple_length = R::Offset::from_u8(2 * address_size + segment_size); + let tuple_length = R::Offset::from_u8(2 * address_size); if tuple_length > input.len() { input.empty(); return Ok(None); } - let segment = if segment_size != 0 { - input.read_address(segment_size)? - } else { - 0 - }; - let address = input.read_address(address_size)?; + let begin = input.read_address(address_size)?; let length = input.read_address(address_size)?; + // Calculate end now so that we can handle overflow. + let end = begin.add_sized(length, address_size)?; + let range = Range { begin, end }; - match (segment, address, length) { + match (begin, length) { // This is meant to be a null terminator, but in practice it can occur // before the end, possibly due to a linker omitting a function and // leaving an unrelocated entry. - (0, 0, 0) => Self::parse(input, encoding, segment_size), - _ => Ok(Some(ArangeEntry { - segment: if segment_size != 0 { - Some(segment) - } else { - None - }, - address, - length, - })), + (0, 0) => Self::parse(input, encoding), + _ => Ok(Some(ArangeEntry { range, length })), } } - /// Return the segment selector of this arange. - #[inline] - pub fn segment(&self) -> Option { - self.segment - } - /// Return the beginning address of this arange. #[inline] pub fn address(&self) -> u64 { - self.address + self.range.begin } /// Return the length of this arange. @@ -354,10 +325,7 @@ impl ArangeEntry { /// Return the range. #[inline] pub fn range(&self) -> Range { - Range { - begin: self.address, - end: self.address.wrapping_add(self.length), - } + self.range } } @@ -426,8 +394,8 @@ mod tests { fn test_parse_header_ok() { #[rustfmt::skip] let buf = [ - // 32-bit length = 32. - 0x20, 0x00, 0x00, 0x00, + // 32-bit length = 28 (8 bytes header, 4 bytes padding, 16 bytes tuple data). + 0x1c, 0x00, 0x00, 0x00, // Version. 0x02, 0x00, // Offset. @@ -435,11 +403,10 @@ mod tests { // Address size. 0x08, // Segment size. - 0x04, - // Length to here = 12, tuple length = 20. + 0x00, + // Length to here = 12, tuple length = 16. // Padding to tuple length multiple = 4. 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // Dummy arange tuple data. 0x20, 0x00, 0x00, 0x00, @@ -472,9 +439,8 @@ mod tests { version: 2, address_size: 8, }, - length: 0x20, + length: 0x1c, debug_info_offset: DebugInfoOffset(0x0403_0201), - segment_size: 4, entries: EndianSlice::new(&buf[buf.len() - 32..buf.len() - 16], LittleEndian), } ); @@ -493,7 +459,7 @@ mod tests { // Address size. 0xff, // Segment size. - 0xff, + 0x00, // Length to here = 12, tuple length = 20. // Padding to tuple length multiple = 4. 0x10, 0x00, 0x00, 0x00, @@ -516,7 +482,7 @@ mod tests { let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) .expect_err("should fail to parse header"); - assert_eq!(error, Error::InvalidAddressRange); + assert_eq!(error, Error::UnsupportedAddressSize(0xff)); } #[test] @@ -556,7 +522,7 @@ mod tests { let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10)) .expect_err("should fail to parse header"); - assert_eq!(error, Error::InvalidAddressRange); + assert_eq!(error, Error::UnsupportedAddressSize(0)); } #[test] @@ -566,50 +532,17 @@ mod tests { version: 2, address_size: 4, }; - let segment_size = 0; let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]; let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); + let entry = ArangeEntry::parse(rest, encoding).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, Some(ArangeEntry { - segment: None, - address: 0x0403_0201, - length: 0x0807_0605, - }) - ); - } - - #[test] - fn test_parse_entry_segment() { - let encoding = Encoding { - format: Format::Dwarf32, - version: 2, - address_size: 4, - }; - let segment_size = 8; - #[rustfmt::skip] - let buf = [ - // Segment. - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - // Address. - 0x01, 0x02, 0x03, 0x04, - // Length. - 0x05, 0x06, 0x07, 0x08, - // Next tuple. - 0x09 - ]; - let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); - assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); - assert_eq!( - entry, - Some(ArangeEntry { - segment: Some(0x1817_1615_1413_1211), - address: 0x0403_0201, + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, length: 0x0807_0605, }) ); @@ -622,7 +555,6 @@ mod tests { version: 2, address_size: 4, }; - let segment_size = 0; #[rustfmt::skip] let buf = [ // Zero tuple. @@ -635,16 +567,61 @@ mod tests { 0x09 ]; let rest = &mut EndianSlice::new(&buf, LittleEndian); - let entry = - ArangeEntry::parse(rest, encoding, segment_size).expect("should parse entry ok"); + let entry = ArangeEntry::parse(rest, encoding).expect("should parse entry ok"); assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); assert_eq!( entry, Some(ArangeEntry { - segment: None, - address: 0x0403_0201, + range: Range { + begin: 0x0403_0201, + end: 0x0403_0201 + 0x0807_0605, + }, length: 0x0807_0605, }) ); } + + #[test] + fn test_parse_entry_overflow_32() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 4, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0x01, 0x02, 0x03, 0x84, + // Length. + 0x05, 0x06, 0x07, 0x88, + // Next tuple. + 0x09 + ]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let entry = ArangeEntry::parse(rest, encoding); + assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); + assert_eq!(entry, Err(Error::AddressOverflow)); + } + + #[test] + fn test_parse_entry_overflow_64() { + let encoding = Encoding { + format: Format::Dwarf32, + version: 2, + address_size: 8, + }; + #[rustfmt::skip] + let buf = [ + // Address. + 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x80, + // Length. + 0x05, 0x06, 0x07, 0x08, 0x00, 0x00, 0x00, 0x80, + // Next tuple. + 0x09 + ]; + let rest = &mut EndianSlice::new(&buf, LittleEndian); + let entry = ArangeEntry::parse(rest, encoding); + assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian)); + assert_eq!(entry, Err(Error::AddressOverflow)); + } } diff --git a/third_party/rust/gimli/src/read/cfi.rs b/third_party/rust/gimli/src/read/cfi.rs index 5aa88468cf05..9941f72c8e8f 100644 --- a/third_party/rust/gimli/src/read/cfi.rs +++ b/third_party/rust/gimli/src/read/cfi.rs @@ -14,7 +14,8 @@ use crate::common::{ use crate::constants::{self, DwEhPe}; use crate::endianity::Endianity; use crate::read::{ - EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, StoreOnHeap, + EndianSlice, Error, Expression, Reader, ReaderAddress, ReaderOffset, Result, Section, + StoreOnHeap, }; /// `DebugFrame` contains the `.debug_frame` section's frame unwinding @@ -35,7 +36,6 @@ use crate::read::{ pub struct DebugFrame { section: R, address_size: u8, - segment_size: u8, vendor: Vendor, } @@ -48,14 +48,6 @@ impl DebugFrame { self.address_size = address_size } - /// Set the size of a segment selector in bytes. - /// - /// This defaults to 0. - /// This is only used if the CIE version is less than 4. - pub fn set_segment_size(&mut self, segment_size: u8) { - self.segment_size = segment_size - } - /// Set the vendor extensions to use. /// /// This defaults to `Vendor::Default`. @@ -100,11 +92,10 @@ impl Section for DebugFrame { impl From for DebugFrame { fn from(section: R) -> Self { - // Default to no segments and native word size. + // Default to native word size. DebugFrame { section, address_size: mem::size_of::() as u8, - segment_size: 0, vendor: Vendor::Default, } } @@ -169,7 +160,10 @@ impl EhFrameHdr { if fde_count_enc == constants::DW_EH_PE_omit || table_enc == constants::DW_EH_PE_omit { fde_count = 0 } else { - fde_count = parse_encoded_pointer(fde_count_enc, ¶meters, &mut reader)?.direct()?; + if fde_count_enc != fde_count_enc.format() { + return Err(Error::UnsupportedPointerEncoding); + } + fde_count = parse_encoded_value(fde_count_enc, ¶meters, &mut reader)?; } Ok(ParsedEhFrameHdr { @@ -459,20 +453,21 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> { /// /// You must provide a function to get the associated CIE. See /// `PartialFrameDescriptionEntry::parse` for more information. - pub fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage>( + pub fn unwind_info_for_address<'ctx, F, S>( &self, frame: &EhFrame, bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, address: u64, get_cie: F, - ) -> Result<&'ctx UnwindTableRow> + ) -> Result<&'ctx UnwindTableRow> where F: FnMut( &EhFrame, &BaseAddresses, EhFrameOffset, ) -> Result>, + S: UnwindContextStorage, { let fde = self.fde_for_address(frame, bases, address, get_cie)?; fde.unwind_info_for_address(frame, bases, ctx, address) @@ -631,9 +626,6 @@ pub trait _UnwindSectionPrivate { /// The address size to use if `has_address_and_segment_sizes` returns false. fn address_size(&self) -> u8; - /// The segment size to use if `has_address_and_segment_sizes` returns false. - fn segment_size(&self) -> u8; - /// The vendor extensions to use. fn vendor(&self) -> Vendor; } @@ -778,15 +770,16 @@ pub trait UnwindSection: Clone + Debug + _UnwindSectionPrivate { /// # } /// ``` #[inline] - fn unwind_info_for_address<'ctx, F, A: UnwindContextStorage>( + fn unwind_info_for_address<'ctx, F, S>( &self, bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, address: u64, get_cie: F, - ) -> Result<&'ctx UnwindTableRow> + ) -> Result<&'ctx UnwindTableRow> where F: FnMut(&Self, &BaseAddresses, Self::Offset) -> Result>, + S: UnwindContextStorage, { let fde = self.fde_for_address(bases, address, get_cie)?; fde.unwind_info_for_address(self, bases, ctx, address) @@ -828,10 +821,6 @@ impl _UnwindSectionPrivate for DebugFrame { self.address_size } - fn segment_size(&self) -> u8 { - self.segment_size - } - fn vendor(&self) -> Vendor { self.vendor } @@ -872,10 +861,6 @@ impl _UnwindSectionPrivate for EhFrame { self.address_size } - fn segment_size(&self) -> u8 { - 0 - } - fn vendor(&self) -> Vendor { self.vendor } @@ -1297,10 +1282,6 @@ where /// > must match the address size here. address_size: u8, - /// "The size of a segment selector in this CIE and any FDEs that use it, in - /// bytes." - segment_size: u8, - /// "A constant that is factored out of all advance location instructions /// (see Section 6.4.2.1)." code_alignment_factor: u64, @@ -1360,12 +1341,15 @@ impl CommonInformationEntry { let mut augmentation_string = rest.read_null_terminated_slice()?; - let (address_size, segment_size) = if Section::has_address_and_segment_sizes(version) { - let address_size = rest.read_u8()?; + let address_size = if Section::has_address_and_segment_sizes(version) { + let address_size = rest.read_address_size()?; let segment_size = rest.read_u8()?; - (address_size, segment_size) + if segment_size != 0 { + return Err(Error::UnsupportedSegmentSize); + } + address_size } else { - (section.address_size(), section.segment_size()) + section.address_size() }; let code_alignment_factor = rest.read_uleb128()?; @@ -1396,7 +1380,6 @@ impl CommonInformationEntry { version, augmentation, address_size, - segment_size, code_alignment_factor, data_alignment_factor, return_address_register, @@ -1635,7 +1618,6 @@ where /// > The address of the first location associated with this table entry. If /// > the segment_size field of this FDE's CIE is non-zero, the initial /// > location is preceded by a segment selector of the given length. - initial_segment: u64, initial_address: u64, /// "The number of bytes of program instructions described by this entry." @@ -1668,12 +1650,6 @@ impl FrameDescriptionEntry { { let cie = get_cie(section, bases, cie_pointer)?; - let initial_segment = if cie.segment_size > 0 { - rest.read_address(cie.segment_size)? - } else { - 0 - }; - let mut parameters = PointerEncodingParameters { bases: &bases.eh_frame, func_base: None, @@ -1699,7 +1675,6 @@ impl FrameDescriptionEntry { length, format, cie, - initial_segment, initial_address, address_range, augmentation: aug_data, @@ -1716,15 +1691,10 @@ impl FrameDescriptionEntry { ) -> Result<(u64, u64)> { let encoding = cie.augmentation().and_then(|a| a.fde_address_encoding); if let Some(encoding) = encoding { - let initial_address = parse_encoded_pointer(encoding, parameters, input)?; - // Ignore indirection. - let initial_address = initial_address.pointer(); - - // Address ranges cannot be relative to anything, so just grab the - // data format bits from the encoding. - let address_range = parse_encoded_pointer(encoding.format(), parameters, input)?; - Ok((initial_address, address_range.pointer())) + let initial_address = parse_encoded_pointer(encoding, parameters, input)?.pointer(); + let address_range = parse_encoded_value(encoding, parameters, input)?; + Ok((initial_address, address_range)) } else { let initial_address = input.read_address(cie.address_size)?; let address_range = input.read_address(cie.address_size)?; @@ -1734,12 +1704,16 @@ impl FrameDescriptionEntry { /// Return the table of unwind information for this FDE. #[inline] - pub fn rows<'a, 'ctx, Section: UnwindSection, A: UnwindContextStorage>( + pub fn rows<'a, 'ctx, Section, S>( &self, section: &'a Section, bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, - ) -> Result> { + ctx: &'ctx mut UnwindContext, + ) -> Result> + where + Section: UnwindSection, + S: UnwindContextStorage, + { UnwindTable::new(section, bases, ctx, self) } @@ -1749,17 +1723,17 @@ impl FrameDescriptionEntry { /// context in the form `Ok((unwind_info, context))`. If not found, /// `Err(gimli::Error::NoUnwindInfoForAddress)` is returned. If parsing or /// CFI evaluation fails, the error is returned. - pub fn unwind_info_for_address< - 'ctx, - Section: UnwindSection, - A: UnwindContextStorage, - >( + pub fn unwind_info_for_address<'ctx, Section, S>( &self, section: &Section, bases: &BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, address: u64, - ) -> Result<&'ctx UnwindTableRow> { + ) -> Result<&'ctx UnwindTableRow> + where + Section: UnwindSection, + S: UnwindContextStorage, + { let mut table = self.rows(section, bases, ctx)?; while let Some(row) = table.next_row()? { if row.contains(address) { @@ -1827,6 +1801,15 @@ impl FrameDescriptionEntry { self.initial_address } + /// One more than the last address that this entry has unwind information for. + /// + /// This uses wrapping arithmetic, so the result may be less than + /// `initial_address`. + pub fn end_address(&self) -> u64 { + self.initial_address + .wrapping_add_sized(self.address_range, self.cie.address_size) + } + /// The number of bytes of instructions that this entry has unwind /// information for. pub fn len(&self) -> u64 { @@ -1839,9 +1822,7 @@ impl FrameDescriptionEntry { /// This is equivalent to `entry.initial_address() <= address < /// entry.initial_address() + entry.len()`. pub fn contains(&self, address: u64) -> bool { - let start = self.initial_address(); - let end = start + self.len(); - start <= address && address < end + self.initial_address() <= address && address < self.end_address() } /// The address of this FDE's language-specific data area (LSDA), if it has @@ -1970,11 +1951,15 @@ impl UnwindContextStorage for StoreOnHeap { /// # } /// ``` #[derive(Clone, PartialEq, Eq)] -pub struct UnwindContext = StoreOnHeap> { +pub struct UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ // Stack of rows. The last row is the row currently being built by the // program. There is always at least one row. The vast majority of CFI // programs will only ever have one row on the stack. - stack: ArrayVec, + stack: ArrayVec, // If we are evaluating an FDE's instructions, then `is_initialized` will be // `true`. If `initial_rule` is `Some`, then the initial register rules are either @@ -1989,7 +1974,11 @@ pub struct UnwindContext = StoreOnHe is_initialized: bool, } -impl> Debug for UnwindContext { +impl Debug for UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("UnwindContext") .field("stack", &self.stack) @@ -1999,7 +1988,11 @@ impl> Debug for UnwindContext } } -impl> Default for UnwindContext { +impl Default for UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn default() -> Self { Self::new_in() } @@ -2017,7 +2010,11 @@ impl UnwindContext { /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations, if an non-allocating storage is used. -impl> UnwindContext { +impl UnwindContext +where + T: ReaderOffset, + S: UnwindContextStorage, +{ /// Construct a new call frame unwinding context. pub fn new_in() -> Self { let mut ctx = UnwindContext { @@ -2058,11 +2055,11 @@ impl> UnwindContext { self.is_initialized = false; } - fn row(&self) -> &UnwindTableRow { + fn row(&self) -> &UnwindTableRow { self.stack.last().unwrap() } - fn row_mut(&mut self) -> &mut UnwindTableRow { + fn row_mut(&mut self) -> &mut UnwindTableRow { self.stack.last_mut().unwrap() } @@ -2196,28 +2193,37 @@ impl> UnwindContext { /// > recording just the differences starting at the beginning address of each /// > subroutine in the program. #[derive(Debug)] -pub struct UnwindTable<'a, 'ctx, R: Reader, A: UnwindContextStorage = StoreOnHeap> { +pub struct UnwindTable<'a, 'ctx, R, S = StoreOnHeap> +where + R: Reader, + S: UnwindContextStorage, +{ code_alignment_factor: Wrapping, data_alignment_factor: Wrapping, + address_size: u8, next_start_address: u64, last_end_address: u64, returned_last_row: bool, current_row_valid: bool, instructions: CallFrameInstructionIter<'a, R>, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, } /// # Signal Safe Methods /// /// These methods are guaranteed not to allocate, acquire locks, or perform any /// other signal-unsafe operations. -impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'ctx, R, A> { +impl<'a, 'ctx, R, S> UnwindTable<'a, 'ctx, R, S> +where + R: Reader, + S: UnwindContextStorage, +{ /// Construct a new `UnwindTable` for the given /// `FrameDescriptionEntry`'s CFI unwinding program. pub fn new>( section: &'a Section, bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, fde: &FrameDescriptionEntry, ) -> Result { ctx.initialize(section, bases, fde.cie())?; @@ -2227,15 +2233,16 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c fn new_for_fde>( section: &'a Section, bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, fde: &FrameDescriptionEntry, ) -> Self { assert!(ctx.stack.len() >= 1); UnwindTable { code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()), data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()), + address_size: fde.cie().address_size, next_start_address: fde.initial_address(), - last_end_address: fde.initial_address().wrapping_add(fde.len()), + last_end_address: fde.end_address(), returned_last_row: false, current_row_valid: false, instructions: fde.instructions(section, bases), @@ -2246,13 +2253,14 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c fn new_for_cie>( section: &'a Section, bases: &'a BaseAddresses, - ctx: &'ctx mut UnwindContext, + ctx: &'ctx mut UnwindContext, cie: &CommonInformationEntry, ) -> Self { assert!(ctx.stack.len() >= 1); UnwindTable { code_alignment_factor: Wrapping(cie.code_alignment_factor()), data_alignment_factor: Wrapping(cie.data_alignment_factor()), + address_size: cie.address_size, next_start_address: 0, last_end_address: 0, returned_last_row: false, @@ -2267,7 +2275,7 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c /// /// Unfortunately, this cannot be used with `FallibleIterator` because of /// the restricted lifetime of the yielded item. - pub fn next_row(&mut self) -> Result>> { + pub fn next_row(&mut self) -> Result>> { assert!(self.ctx.stack.len() >= 1); self.ctx.set_start_address(self.next_start_address); self.current_row_valid = false; @@ -2300,7 +2308,7 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c } /// Returns the current row with the lifetime of the context. - pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow> { + pub fn into_current_row(self) -> Option<&'ctx UnwindTableRow> { if self.current_row_valid { Some(self.ctx.row()) } else { @@ -2327,7 +2335,10 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c } AdvanceLoc { delta } => { let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor; - self.next_start_address = (Wrapping(self.ctx.start_address()) + delta).0; + self.next_start_address = self + .ctx + .start_address() + .add_sized(delta.0, self.address_size)?; self.ctx.row_mut().end_address = self.next_start_address; return Ok(true); } @@ -2519,11 +2530,19 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage> UnwindTable<'a, 'c // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32 // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31 // - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31 -struct RegisterRuleMap = StoreOnHeap> { +struct RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ rules: ArrayVec, } -impl> Debug for RegisterRuleMap { +impl Debug for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RegisterRuleMap") .field("rules", &self.rules) @@ -2531,7 +2550,11 @@ impl> Debug for RegisterRuleMap> Clone for RegisterRuleMap { +impl Clone for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn clone(&self) -> Self { Self { rules: self.rules.clone(), @@ -2539,7 +2562,11 @@ impl> Clone for RegisterRuleMap> Default for RegisterRuleMap { +impl Default for RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn default() -> Self { RegisterRuleMap { rules: Default::default(), @@ -2551,7 +2578,11 @@ impl> Default for RegisterRuleMap> RegisterRuleMap { +impl RegisterRuleMap +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn is_default(&self) -> bool { self.rules.is_empty() } @@ -2599,10 +2630,10 @@ impl> RegisterRuleMap { } } -impl<'a, R, S: UnwindContextStorage> FromIterator<&'a (Register, RegisterRule)> - for RegisterRuleMap +impl<'a, R, S> FromIterator<&'a (Register, RegisterRule)> for RegisterRuleMap where R: 'a + ReaderOffset, + S: UnwindContextStorage, { fn from_iter(iter: T) -> Self where @@ -2620,9 +2651,10 @@ where } } -impl> PartialEq for RegisterRuleMap +impl PartialEq for RegisterRuleMap where T: ReaderOffset + PartialEq, + S: UnwindContextStorage, { fn eq(&self, rhs: &Self) -> bool { for &(reg, ref rule) in &*self.rules { @@ -2643,7 +2675,12 @@ where } } -impl> Eq for RegisterRuleMap where T: ReaderOffset + Eq {} +impl Eq for RegisterRuleMap +where + T: ReaderOffset + Eq, + S: UnwindContextStorage, +{ +} /// An unordered iterator for register rules. #[derive(Debug, Clone)] @@ -2662,7 +2699,11 @@ impl<'iter, T: ReaderOffset> Iterator for RegisterRuleIter<'iter, T> { /// A row in the virtual unwind table that describes how to find the values of /// the registers in the *previous* frame for a range of PC addresses. #[derive(PartialEq, Eq)] -pub struct UnwindTableRow = StoreOnHeap> { +pub struct UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ start_address: u64, end_address: u64, saved_args_size: u64, @@ -2670,7 +2711,11 @@ pub struct UnwindTableRow = StoreOnH registers: RegisterRuleMap, } -impl> Debug for UnwindTableRow { +impl Debug for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("UnwindTableRow") .field("start_address", &self.start_address) @@ -2682,7 +2727,11 @@ impl> Debug for UnwindTableRow } } -impl> Clone for UnwindTableRow { +impl Clone for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn clone(&self) -> Self { Self { start_address: self.start_address, @@ -2694,7 +2743,11 @@ impl> Clone for UnwindTableRow } } -impl> Default for UnwindTableRow { +impl Default for UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn default() -> Self { UnwindTableRow { start_address: 0, @@ -2706,7 +2759,11 @@ impl> Default for UnwindTableRow> UnwindTableRow { +impl UnwindTableRow +where + T: ReaderOffset, + S: UnwindContextStorage, +{ fn is_default(&self) -> bool { self.start_address == 0 && self.end_address == 0 @@ -2827,8 +2884,7 @@ pub enum CfaRule { /// The offset from the register's base value. offset: i64, }, - /// The CFA is obtained by evaluating this `Reader` as a DWARF expression - /// program. + /// The CFA is obtained by evaluating a DWARF expression program. Expression(UnwindExpression), } @@ -3459,6 +3515,28 @@ impl<'a, R: Reader> fallible_iterator::FallibleIterator for CallFrameInstruction /// /// This is stored as an offset and length within the section instead of as a /// `Reader` to avoid lifetime issues when reusing [`UnwindContext`]. +/// +/// # Example +/// ``` +/// # use gimli::{EhFrame, EndianSlice, NativeEndian, Error, FrameDescriptionEntry, UnwindExpression, EvaluationResult}; +/// # fn foo() -> Result<(), Error> { +/// # let eh_frame: EhFrame> = unreachable!(); +/// # let fde: FrameDescriptionEntry> = unimplemented!(); +/// # let unwind_expression: UnwindExpression<_> = unimplemented!(); +/// let expression = unwind_expression.get(&eh_frame)?; +/// let mut evaluation = expression.evaluation(fde.cie().encoding()); +/// let mut result = evaluation.evaluate()?; +/// loop { +/// match result { +/// EvaluationResult::Complete => break, +/// // Provide information to the evaluation. +/// _ => { unimplemented!()} +/// } +/// } +/// let value = evaluation.value_result(); +/// # Ok(()) +/// # } +/// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct UnwindExpression { /// The offset of the expression within the section. @@ -3472,10 +3550,11 @@ impl UnwindExpression { /// /// The offset and length were previously validated when the /// `UnwindExpression` was created, so this should not fail. - pub fn get, S: UnwindSection>( - &self, - section: &S, - ) -> Result> { + pub fn get(&self, section: &S) -> Result> + where + R: Reader, + S: UnwindSection, + { let input = &mut section.section().clone(); input.skip(self.offset)?; let data = input.split(self.length)?; @@ -3574,7 +3653,8 @@ fn parse_encoded_pointer( constants::DW_EH_PE_pcrel => { if let Some(section_base) = parameters.bases.section { let offset_from_section = input.offset_from(parameters.section); - section_base.wrapping_add(offset_from_section.into_u64()) + section_base + .wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size) } else { return Err(Error::PcRelativePointerButSectionBaseIsUndefined); } @@ -3604,7 +3684,19 @@ fn parse_encoded_pointer( _ => unreachable!(), }; - let offset = match encoding.format() { + let offset = parse_encoded_value(encoding, parameters, input)?; + Ok(Pointer::new( + encoding, + base.wrapping_add_sized(offset, parameters.address_size), + )) +} + +fn parse_encoded_value( + encoding: constants::DwEhPe, + parameters: &PointerEncodingParameters<'_, R>, + input: &mut R, +) -> Result { + match encoding.format() { // Unsigned variants. constants::DW_EH_PE_absptr => input.read_address(parameters.address_size), constants::DW_EH_PE_uleb128 => input.read_uleb128(), @@ -3623,9 +3715,7 @@ fn parse_encoded_pointer( // That was all of the valid encoding formats. _ => unreachable!(), - }?; - - Ok(Pointer::new(encoding, base.wrapping_add(offset))) + } } #[cfg(test)] @@ -3643,7 +3733,6 @@ mod tests { use alloc::vec::Vec; use core::marker::PhantomData; use core::mem; - use core::u64; use test_assembler::{Endian, Label, LabelMaker, LabelOrNum, Section, ToLabelOrNum}; // Ensure each test tries to read the same section kind that it wrote. @@ -3766,7 +3855,7 @@ mod tests { let section = section.D8(0); let section = if T::has_address_and_segment_sizes(cie.version) { - section.D8(cie.address_size).D8(cie.segment_size) + section.D8(cie.address_size).D8(0) } else { section }; @@ -3817,13 +3906,6 @@ mod tests { } }; - let section = match fde.cie.segment_size { - 0 => section, - 4 => section.D32(fde.initial_segment as u32), - 8 => section.D64(fde.initial_segment), - x => panic!("Unsupported test segment size: {}", x), - }; - let section = match fde.cie.address_size { 4 => section .D32(fde.initial_address() as u32) @@ -3977,7 +4059,6 @@ mod tests { version: 99, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 2, return_address_register: Register(3), @@ -4038,7 +4119,6 @@ mod tests { version, augmentation: None, address_size, - segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), @@ -4085,7 +4165,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 0, data_alignment_factor: 0, return_address_register: Register(3), @@ -4174,7 +4253,6 @@ mod tests { augmentation: None, // DWARF32 with a 64 bit address size! Holy moly! address_size: 8, - segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), @@ -4186,7 +4264,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, @@ -4211,56 +4288,6 @@ mod tests { assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } - #[test] - fn test_parse_fde_32_with_segment_ok() { - let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let cie_offset = 0xbad0_bad1; - let expected_instrs: Vec<_> = (0..92).map(|_| constants::DW_CFA_nop.0).collect(); - - let cie = CommonInformationEntry { - offset: 0, - length: 100, - format: Format::Dwarf32, - version: 4, - augmentation: None, - address_size: 4, - segment_size: 4, - code_alignment_factor: 3, - data_alignment_factor: 2, - return_address_register: Register(1), - initial_instructions: EndianSlice::new(&[], LittleEndian), - }; - - let mut fde = FrameDescriptionEntry { - offset: 0, - length: 0, - format: Format::Dwarf32, - cie: cie.clone(), - initial_segment: 0xbadb_ad11, - initial_address: 0xfeed_beef, - address_range: 999, - augmentation: None, - instructions: EndianSlice::new(&expected_instrs, LittleEndian), - }; - - let kind = debug_frame_le(); - let section = Section::with_endian(kind.endian()) - .fde(kind, cie_offset, &mut fde) - .append_bytes(&expected_rest); - - let section = section.get_contents().unwrap(); - let debug_frame = kind.section(§ion); - let rest = &mut EndianSlice::new(§ion, LittleEndian); - - let get_cie = |_: &_, _: &_, offset| { - assert_eq!(offset, DebugFrameOffset(cie_offset as usize)); - Ok(cie.clone()) - }; - - assert_eq!(parse_fde(debug_frame, rest, get_cie), Ok(fde)); - assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); - } - #[test] fn test_parse_fde_64_ok() { let expected_rest = [1, 2, 3, 4, 5, 6, 7, 8, 9]; @@ -4274,7 +4301,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), @@ -4286,7 +4312,6 @@ mod tests { length: 0, format: Format::Dwarf64, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, @@ -4323,7 +4348,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), @@ -4359,7 +4383,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 16, data_alignment_factor: 32, return_address_register: Register(1), @@ -4371,7 +4394,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, @@ -4424,7 +4446,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 2, return_address_register: Register(3), @@ -4438,7 +4459,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 3, data_alignment_factor: 2, return_address_register: Register(1), @@ -4463,7 +4483,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie1.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, @@ -4475,7 +4494,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie2.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, @@ -4546,7 +4564,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 4, data_alignment_factor: 8, return_address_register: Register(12), @@ -5328,7 +5345,6 @@ mod tests { address_size: mem::size_of::() as u8, initial_instructions: EndianSlice::new(&[], LittleEndian), augmentation: None, - segment_size: 0, data_alignment_factor: 2, code_alignment_factor: 3, } @@ -5369,13 +5385,30 @@ mod tests { } #[test] - fn test_eval_advance_loc_overflow() { - let cie = make_test_cie(); + fn test_eval_advance_loc_overflow_32() { + let mut cie = make_test_cie(); + cie.address_size = 4; + let mut ctx = UnwindContext::new(); + ctx.row_mut().start_address = u32::MAX.into(); + let expected = ctx.clone(); + let instructions = [( + Err(Error::AddressOverflow), + CallFrameInstruction::AdvanceLoc { delta: 42 }, + )]; + assert_eval(ctx, expected, cie, None, instructions); + } + + #[test] + fn test_eval_advance_loc_overflow_64() { + let mut cie = make_test_cie(); + cie.address_size = 8; let mut ctx = UnwindContext::new(); ctx.row_mut().start_address = u64::MAX; - let mut expected = ctx.clone(); - expected.row_mut().end_address = 42 * cie.code_alignment_factor - 1; - let instructions = [(Ok(true), CallFrameInstruction::AdvanceLoc { delta: 42 })]; + let expected = ctx.clone(); + let instructions = [( + Err(Error::AddressOverflow), + CallFrameInstruction::AdvanceLoc { delta: 42 }, + )]; assert_eval(ctx, expected, cie, None, instructions); } @@ -5679,7 +5712,6 @@ mod tests { address_range: 0, augmentation: None, initial_address: 0, - initial_segment: 0, cie: cie.clone(), instructions: EndianSlice::new(&[], LittleEndian), }; @@ -5830,7 +5862,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -5847,7 +5878,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, @@ -5905,7 +5935,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -5922,7 +5951,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, @@ -5979,7 +6007,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -6000,7 +6027,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -6012,7 +6038,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie1.clone(), - initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, @@ -6024,7 +6049,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie2.clone(), - initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, @@ -6076,7 +6100,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -6113,7 +6136,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0, address_range: 100, augmentation: None, @@ -6253,7 +6275,6 @@ mod tests { version: 4, augmentation: None, address_size: 8, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(3), @@ -6267,7 +6288,6 @@ mod tests { version: 4, augmentation: None, address_size: 4, - segment_size: 0, code_alignment_factor: 1, data_alignment_factor: 1, return_address_register: Register(1), @@ -6292,7 +6312,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie1.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 200, augmentation: None, @@ -6304,7 +6323,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie2.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, @@ -6336,7 +6354,7 @@ mod tests { *unwind_info, UnwindTableRow { start_address: fde1.initial_address() + 100, - end_address: fde1.initial_address() + fde1.len(), + end_address: fde1.end_address(), saved_args_size: 0, cfa: CfaRule::RegisterAndOffset { register: Register(4), @@ -6550,7 +6568,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 9, address_range: 4, augmentation: None, @@ -6561,7 +6578,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 20, address_range: 8, augmentation: None, @@ -6692,7 +6708,6 @@ mod tests { length: 0, format: Format::Dwarf64, cie: make_test_cie(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 39, augmentation: None, @@ -6741,7 +6756,7 @@ mod tests { fn test_eh_frame_resolve_cie_offset_underflow() { let buf = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; assert_eq!( - resolve_cie_offset(&buf, ::core::usize::MAX), + resolve_cie_offset(&buf, usize::MAX), Err(Error::OffsetOutOfBounds) ); } @@ -6769,7 +6784,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, @@ -6814,7 +6828,6 @@ mod tests { length: 0, format: Format::Dwarf64, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_beef, address_range: 999, augmentation: None, @@ -7057,7 +7070,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: None, @@ -7095,7 +7107,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData::default()), @@ -7134,7 +7145,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData { @@ -7176,7 +7186,6 @@ mod tests { length: 0, format: Format::Dwarf32, cie: cie.clone(), - initial_segment: 0, initial_address: 0xfeed_face, address_range: 9000, augmentation: Some(AugmentationData { @@ -7688,7 +7697,7 @@ mod tests { let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, - address_size: 4, + address_size: 8, section: &input, }; assert_eq!( @@ -7791,7 +7800,7 @@ mod tests { let parameters = PointerEncodingParameters { bases: &SectionBaseAddresses::default(), func_base: None, - address_size: 4, + address_size: 8, section: &input, }; assert_eq!( diff --git a/third_party/rust/gimli/src/read/dwarf.rs b/third_party/rust/gimli/src/read/dwarf.rs index c4a65aee3978..d61d76f18016 100644 --- a/third_party/rust/gimli/src/read/dwarf.rs +++ b/third_party/rust/gimli/src/read/dwarf.rs @@ -399,9 +399,9 @@ impl Dwarf { /// - an inline `DW_FORM_string` string /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary - /// object file + /// object file /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str` - /// section + /// section /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit /// /// then return the attribute's string value. Returns an error if the attribute @@ -739,7 +739,7 @@ impl Dwarf { // parent file. self.ranges .set_debug_ranges(parent.ranges.debug_ranges().clone()); - self.sup = parent.sup.clone(); + self.sup.clone_from(&parent.sup); } } diff --git a/third_party/rust/gimli/src/read/endian_reader.rs b/third_party/rust/gimli/src/read/endian_reader.rs index c35267ef0dea..5e65b4d1cfb8 100644 --- a/third_party/rust/gimli/src/read/endian_reader.rs +++ b/third_party/rust/gimli/src/read/endian_reader.rs @@ -5,6 +5,7 @@ use alloc::rc::Rc; use alloc::string::String; use alloc::sync::Arc; use core::fmt::Debug; +use core::hash::{Hash, Hasher}; use core::ops::{Deref, Index, Range, RangeFrom, RangeTo}; use core::slice; use core::str; @@ -116,7 +117,7 @@ pub type EndianArcSlice = EndianReader>; /// pub type MmapFileReader = gimli::EndianReader; /// # fn test(_: &MmapFileReader) { } /// ``` -#[derive(Debug, Clone, Copy, Hash)] +#[derive(Debug, Clone, Copy)] pub struct EndianReader where Endian: Endianity, @@ -144,6 +145,17 @@ where { } +impl Hash for EndianReader +where + Endian: Endianity, + T: CloneStableDeref + Debug, +{ + fn hash(&self, state: &mut H) { + // This must match the `PartialEq` implementation. + self.bytes().hash(state); + } +} + // This is separated out from `EndianReader` so that we can avoid running afoul // of borrowck. We need to `read_slice(&mut self, ...) -> &[u8]` and then call // `self.endian.read_whatever` on the result. The problem is that the returned diff --git a/third_party/rust/gimli/src/read/index.rs b/third_party/rust/gimli/src/read/index.rs index 7629a27819e3..bd8e74bf1fd7 100644 --- a/third_party/rust/gimli/src/read/index.rs +++ b/third_party/rust/gimli/src/read/index.rs @@ -363,9 +363,9 @@ pub enum IndexSectionId { } impl IndexSectionId { - /// Returns the ELF section name for this kind, when found in a .dwo or .dwp file. - pub fn dwo_name(self) -> &'static str { - let section_id = match self { + /// Returns the corresponding `SectionId`. + pub fn section_id(self) -> SectionId { + match self { IndexSectionId::DebugAbbrev => SectionId::DebugAbbrev, IndexSectionId::DebugInfo => SectionId::DebugInfo, IndexSectionId::DebugLine => SectionId::DebugLine, @@ -376,8 +376,12 @@ impl IndexSectionId { IndexSectionId::DebugRngLists => SectionId::DebugRngLists, IndexSectionId::DebugStrOffsets => SectionId::DebugStrOffsets, IndexSectionId::DebugTypes => SectionId::DebugTypes, - }; - section_id.dwo_name().unwrap() + } + } + + /// Returns the ELF section name for this kind, when found in a .dwo or .dwp file. + pub fn dwo_name(self) -> &'static str { + self.section_id().dwo_name().unwrap() } } diff --git a/third_party/rust/gimli/src/read/line.rs b/third_party/rust/gimli/src/read/line.rs index e77f88d96434..ceaf3b3fbecf 100644 --- a/third_party/rust/gimli/src/read/line.rs +++ b/third_party/rust/gimli/src/read/line.rs @@ -1,7 +1,5 @@ use alloc::vec::Vec; -use core::fmt; use core::num::{NonZeroU64, Wrapping}; -use core::result; use crate::common::{ DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format, @@ -9,7 +7,9 @@ use crate::common::{ }; use crate::constants; use crate::endianity::Endianity; -use crate::read::{AttributeValue, EndianSlice, Error, Reader, ReaderOffset, Result, Section}; +use crate::read::{ + AttributeValue, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, Result, Section, +}; /// The `DebugLine` struct contains the source location to instruction mapping /// found in the `.debug_line` section. @@ -240,7 +240,7 @@ where Err(err) => return Err(err), Ok(None) => return Ok(None), Ok(Some(instruction)) => { - if self.row.execute(instruction, &mut self.program) { + if self.row.execute(instruction, &mut self.program)? { if self.row.tombstone { // Perform any reset that was required for the tombstone row. // Normally this is done when `next_row` is called again, but for @@ -276,10 +276,10 @@ where /// > 1. Add a signed integer to the line register. /// > /// > 2. Modify the operation pointer by incrementing the address and - /// > op_index registers as described below. + /// > op_index registers as described below. /// > /// > 3. Append a row to the matrix using the current values of the state - /// > machine registers. + /// > machine registers. /// > /// > 4. Set the basic_block register to “false.” /// > @@ -516,58 +516,6 @@ where } } -impl fmt::Display for LineInstruction -where - R: Reader, - Offset: ReaderOffset, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> { - match *self { - LineInstruction::Special(opcode) => write!(f, "Special opcode {}", opcode), - LineInstruction::Copy => write!(f, "{}", constants::DW_LNS_copy), - LineInstruction::AdvancePc(advance) => { - write!(f, "{} by {}", constants::DW_LNS_advance_pc, advance) - } - LineInstruction::AdvanceLine(increment) => { - write!(f, "{} by {}", constants::DW_LNS_advance_line, increment) - } - LineInstruction::SetFile(file) => { - write!(f, "{} to {}", constants::DW_LNS_set_file, file) - } - LineInstruction::SetColumn(column) => { - write!(f, "{} to {}", constants::DW_LNS_set_column, column) - } - LineInstruction::NegateStatement => write!(f, "{}", constants::DW_LNS_negate_stmt), - LineInstruction::SetBasicBlock => write!(f, "{}", constants::DW_LNS_set_basic_block), - LineInstruction::ConstAddPc => write!(f, "{}", constants::DW_LNS_const_add_pc), - LineInstruction::FixedAddPc(advance) => { - write!(f, "{} by {}", constants::DW_LNS_fixed_advance_pc, advance) - } - LineInstruction::SetPrologueEnd => write!(f, "{}", constants::DW_LNS_set_prologue_end), - LineInstruction::SetEpilogueBegin => { - write!(f, "{}", constants::DW_LNS_set_epilogue_begin) - } - LineInstruction::SetIsa(isa) => write!(f, "{} to {}", constants::DW_LNS_set_isa, isa), - LineInstruction::UnknownStandard0(opcode) => write!(f, "Unknown {}", opcode), - LineInstruction::UnknownStandard1(opcode, arg) => { - write!(f, "Unknown {} with operand {}", opcode, arg) - } - LineInstruction::UnknownStandardN(opcode, ref args) => { - write!(f, "Unknown {} with operands {:?}", opcode, args) - } - LineInstruction::EndSequence => write!(f, "{}", constants::DW_LNE_end_sequence), - LineInstruction::SetAddress(address) => { - write!(f, "{} to {}", constants::DW_LNE_set_address, address) - } - LineInstruction::DefineFile(_) => write!(f, "{}", constants::DW_LNE_define_file), - LineInstruction::SetDiscriminator(discr) => { - write!(f, "{} to {}", constants::DW_LNE_set_discriminator, discr) - } - LineInstruction::UnknownExtended(opcode, _) => write!(f, "Unknown {}", opcode), - } - } -} - /// Deprecated. `OpcodesIter` has been renamed to `LineInstructions`. #[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")] pub type OpcodesIter = LineInstructions; @@ -631,7 +579,7 @@ pub type LineNumberRow = LineRow; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct LineRow { tombstone: bool, - address: Wrapping, + address: u64, op_index: Wrapping, file: u64, line: Wrapping, @@ -652,7 +600,7 @@ impl LineRow { // "At the beginning of each sequence within a line number program, the // state of the registers is:" -- Section 6.2.2 tombstone: false, - address: Wrapping(0), + address: 0, op_index: Wrapping(0), file: 1, line: Wrapping(1), @@ -676,7 +624,7 @@ impl LineRow { /// generated by the compiler." #[inline] pub fn address(&self) -> u64 { - self.address.0 + self.address } /// > An unsigned integer representing the index of an operation within a VLIW @@ -800,21 +748,21 @@ impl LineRow { &mut self, instruction: LineInstruction, program: &mut Program, - ) -> bool + ) -> Result where Program: LineProgram, R: Reader, { - match instruction { + Ok(match instruction { LineInstruction::Special(opcode) => { - self.exec_special_opcode(opcode, program.header()); + self.exec_special_opcode(opcode, program.header())?; true } LineInstruction::Copy => true, LineInstruction::AdvancePc(operation_advance) => { - self.apply_operation_advance(operation_advance, program.header()); + self.apply_operation_advance(operation_advance, program.header())?; false } @@ -846,13 +794,16 @@ impl LineRow { LineInstruction::ConstAddPc => { let adjusted = self.adjust_opcode(255, program.header()); let operation_advance = adjusted / program.header().line_encoding.line_range; - self.apply_operation_advance(u64::from(operation_advance), program.header()); + self.apply_operation_advance(u64::from(operation_advance), program.header())?; false } LineInstruction::FixedAddPc(operand) => { - self.address += Wrapping(u64::from(operand)); - self.op_index.0 = 0; + if !self.tombstone { + let address_size = program.header().address_size(); + self.address = self.address.add_sized(u64::from(operand), address_size)?; + self.op_index.0 = 0; + } false } @@ -879,8 +830,13 @@ impl LineRow { LineInstruction::SetAddress(address) => { let tombstone_address = !0 >> (64 - program.header().encoding.address_size * 8); self.tombstone = address == tombstone_address; - self.address.0 = address; - self.op_index.0 = 0; + if !self.tombstone { + if address < self.address { + return Err(Error::InvalidAddressRange); + } + self.address = address; + self.op_index.0 = 0; + } false } @@ -899,7 +855,7 @@ impl LineRow { | LineInstruction::UnknownStandard1(_, _) | LineInstruction::UnknownStandardN(_, _) | LineInstruction::UnknownExtended(_, _) => false, - } + }) } /// Perform any reset that was required after copying the previous row. @@ -940,7 +896,11 @@ impl LineRow { &mut self, operation_advance: u64, header: &LineProgramHeader, - ) { + ) -> Result<()> { + if self.tombstone { + return Ok(()); + } + let operation_advance = Wrapping(operation_advance); let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length); @@ -950,15 +910,19 @@ impl LineRow { u64::from(header.line_encoding.maximum_operations_per_instruction); let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction); - if maximum_operations_per_instruction.0 == 1 { - self.address += minimum_instruction_length * operation_advance; + let address_advance = if maximum_operations_per_instruction.0 == 1 { self.op_index.0 = 0; + minimum_instruction_length * operation_advance } else { let op_index_with_advance = self.op_index + operation_advance; - self.address += minimum_instruction_length - * (op_index_with_advance / maximum_operations_per_instruction); self.op_index = op_index_with_advance % maximum_operations_per_instruction; - } + minimum_instruction_length + * (op_index_with_advance / maximum_operations_per_instruction) + }; + self.address = self + .address + .add_sized(address_advance.0, header.address_size())?; + Ok(()) } #[inline] @@ -967,7 +931,11 @@ impl LineRow { } /// Section 6.2.5.1 - fn exec_special_opcode(&mut self, opcode: u8, header: &LineProgramHeader) { + fn exec_special_opcode( + &mut self, + opcode: u8, + header: &LineProgramHeader, + ) -> Result<()> { let adjusted_opcode = self.adjust_opcode(opcode, header); let line_range = header.line_encoding.line_range; @@ -979,7 +947,8 @@ impl LineRow { self.apply_line_advance(line_base + i64::from(line_advance)); // Step 2 - self.apply_operation_advance(u64::from(operation_advance), header); + self.apply_operation_advance(u64::from(operation_advance), header)?; + Ok(()) } } @@ -1224,6 +1193,13 @@ where .any(|x| x.content_type == constants::DW_LNCT_MD5) } + /// Return true if the file name entry format contains a source field. + pub fn file_has_source(&self) -> bool { + self.file_name_entry_format + .iter() + .any(|x| x.content_type == constants::DW_LNCT_LLVM_source) + } + /// Get the list of source files that appear in this header's line program. pub fn file_names(&self) -> &[FileEntry] { &self.file_names[..] @@ -1293,7 +1269,7 @@ where } if version >= 5 { - address_size = rest.read_u8()?; + address_size = rest.read_address_size()?; let segment_selector_size = rest.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); @@ -1380,6 +1356,7 @@ where timestamp: 0, size: 0, md5: [0; 16], + source: None, }); file_name_entry_format = Vec::new(); @@ -1579,6 +1556,7 @@ where timestamp: u64, size: u64, md5: [u8; 16], + source: Option>, } impl FileEntry @@ -1598,6 +1576,7 @@ where timestamp, size, md5: [0; 16], + source: None, }; Ok(entry) @@ -1667,6 +1646,16 @@ where pub fn md5(&self) -> &[u8; 16] { &self.md5 } + + /// The source code of this file. (UTF-8 source text string with "\n" line + /// endings). + /// + /// Note: For DWARF v5 files this may return an empty attribute that + /// indicates that no source code is available, which this function + /// represents as Some(). + pub fn source(&self) -> Option> { + self.source.clone() + } } /// The format of a component of an include directory or file name entry. @@ -1686,8 +1675,8 @@ impl FileEntryFormat { let mut path_count = 0; for _ in 0..format_count { let content_type = input.read_uleb128()?; - let content_type = if content_type > u64::from(u16::max_value()) { - constants::DwLnct(u16::max_value()) + let content_type = if content_type > u64::from(u16::MAX) { + constants::DwLnct(u16::MAX) } else { constants::DwLnct(content_type as u16) }; @@ -1733,6 +1722,7 @@ fn parse_file_v5( let mut timestamp = 0; let mut size = 0; let mut md5 = [0; 16]; + let mut source = None; for format in formats { let value = parse_attribute(input, encoding, format.form)?; @@ -1760,6 +1750,9 @@ fn parse_file_v5( } } } + constants::DW_LNCT_LLVM_source => { + source = Some(value); + } // Ignore unknown content types. _ => {} } @@ -1771,6 +1764,7 @@ fn parse_file_v5( timestamp, size, md5, + source, }) } @@ -1886,8 +1880,6 @@ mod tests { use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Error}; use crate::test_util::GimliSectionMethods; - use core::u64; - use core::u8; use test_assembler::{Endian, Label, LabelMaker, Section}; #[test] @@ -1986,6 +1978,7 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)), @@ -1993,6 +1986,7 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }, ]; assert_eq!(header.file_names(), &expected_file_names); @@ -2151,6 +2145,7 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)), @@ -2158,6 +2153,7 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }, ], include_directories: vec![], @@ -2404,6 +2400,7 @@ mod tests { timestamp: 1, size: 2, md5: [0; 16], + source: None, }), ); @@ -2427,6 +2424,7 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }; let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); @@ -2451,7 +2449,7 @@ mod tests { let mut program = IncompleteLineProgram { header }; let is_new_row = registers.execute(opcode, &mut program); - assert_eq!(is_new_row, expect_new_row); + assert_eq!(is_new_row, Ok(expect_new_row)); assert_eq!(registers, expected_registers); } @@ -2504,7 +2502,7 @@ mod tests { let opcode = LineInstruction::Special(52); let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; + expected_registers.address += 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); } @@ -2518,7 +2516,7 @@ mod tests { let opcode = LineInstruction::Special(55); let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; + expected_registers.address += 3; expected_registers.line.0 += 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); @@ -2534,7 +2532,7 @@ mod tests { let opcode = LineInstruction::Special(49); let mut expected_registers = initial_registers; - expected_registers.address.0 += 3; + expected_registers.address += 3; expected_registers.line.0 -= 3; assert_exec_opcode(header, initial_registers, opcode, expected_registers, true); @@ -2563,7 +2561,7 @@ mod tests { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); let mut initial_registers = LineRow::new(&header); - initial_registers.address.0 = 1337; + initial_registers.address = 1337; initial_registers.line.0 = 42; let opcode = LineInstruction::Copy; @@ -2580,23 +2578,33 @@ mod tests { let opcode = LineInstruction::AdvancePc(42); let mut expected_registers = initial_registers; - expected_registers.address.0 += 42; + expected_registers.address += 42; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } #[test] - fn test_exec_advance_pc_overflow() { - let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + fn test_exec_advance_pc_overflow_32() { + let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); + header.encoding.address_size = 4; + let mut registers = LineRow::new(&header); + registers.address = u32::MAX.into(); let opcode = LineInstruction::AdvancePc(42); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } - let mut initial_registers = LineRow::new(&header); - initial_registers.address.0 = u64::MAX; - - let mut expected_registers = initial_registers; - expected_registers.address.0 = 41; - - assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); + #[test] + fn test_exec_advance_pc_overflow_64() { + let mut header = make_test_header(EndianSlice::new(&[], LittleEndian)); + header.encoding.address_size = 8; + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + let opcode = LineInstruction::AdvancePc(42); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); } #[test] @@ -2729,11 +2737,22 @@ mod tests { let opcode = LineInstruction::ConstAddPc; let mut expected_registers = initial_registers; - expected_registers.address.0 += 20; + expected_registers.address += 20; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } + #[test] + fn test_exec_const_add_pc_overflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + let opcode = LineInstruction::ConstAddPc; + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + #[test] fn test_exec_fixed_add_pc() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); @@ -2744,12 +2763,24 @@ mod tests { let opcode = LineInstruction::FixedAddPc(10); let mut expected_registers = initial_registers; - expected_registers.address.0 += 10; + expected_registers.address += 10; expected_registers.op_index.0 = 0; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } + #[test] + fn test_exec_fixed_add_pc_overflow() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut registers = LineRow::new(&header); + registers.address = u64::MAX; + registers.op_index.0 = 1; + let opcode = LineInstruction::FixedAddPc(10); + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::AddressOverflow)); + } + #[test] fn test_exec_set_prologue_end() { let header = make_test_header(EndianSlice::new(&[], LittleEndian)); @@ -2826,7 +2857,7 @@ mod tests { let opcode = LineInstruction::SetAddress(3030); let mut expected_registers = initial_registers; - expected_registers.address.0 = 3030; + expected_registers.address = 3030; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } @@ -2839,11 +2870,22 @@ mod tests { let mut expected_registers = initial_registers; expected_registers.tombstone = true; - expected_registers.address.0 = !0; assert_exec_opcode(header, initial_registers, opcode, expected_registers, false); } + #[test] + fn test_exec_set_address_backwards() { + let header = make_test_header(EndianSlice::new(&[], LittleEndian)); + let mut registers = LineRow::new(&header); + registers.address = 1; + let opcode = LineInstruction::SetAddress(0); + + let mut program = IncompleteLineProgram { header }; + let result = registers.execute(opcode, &mut program); + assert_eq!(result, Err(Error::InvalidAddressRange)); + } + #[test] fn test_exec_define_file() { let mut program = make_test_program(EndianSlice::new(&[], LittleEndian)); @@ -2855,10 +2897,11 @@ mod tests { timestamp: 0, size: 0, md5: [0; 16], + source: None, }; let opcode = LineInstruction::DefineFile(file); - let is_new_row = row.execute(opcode, &mut program); + let is_new_row = row.execute(opcode, &mut program).unwrap(); assert!(!is_new_row); assert_eq!(Some(&file), program.header().file_names.last()); @@ -2916,6 +2959,10 @@ mod tests { timestamp: 0, size: 0, md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16], + source: Some(AttributeValue::String(EndianSlice::new( + b"foobar", + LittleEndian, + ))), }, FileEntry { path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)), @@ -2925,6 +2972,10 @@ mod tests { md5: [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, ], + source: Some(AttributeValue::String(EndianSlice::new( + b"quux", + LittleEndian, + ))), }, ]; @@ -2967,21 +3018,25 @@ mod tests { .append_bytes(b"dir1\0") .append_bytes(b"dir2\0") // File entry format count. - .D8(3) + .D8(4) .uleb(constants::DW_LNCT_path.0 as u64) .uleb(constants::DW_FORM_string.0 as u64) .uleb(constants::DW_LNCT_directory_index.0 as u64) .uleb(constants::DW_FORM_data1.0 as u64) .uleb(constants::DW_LNCT_MD5.0 as u64) .uleb(constants::DW_FORM_data16.0 as u64) + .uleb(constants::DW_LNCT_LLVM_source.0 as u64) + .uleb(constants::DW_FORM_string.0 as u64) // File count. .D8(2) .append_bytes(b"file1\0") .D8(0) .append_bytes(&expected_file_names[0].md5) + .append_bytes(b"foobar\0") .append_bytes(b"file2\0") .D8(1) .append_bytes(&expected_file_names[1].md5) + .append_bytes(b"quux\0") .mark(&header_end) // Dummy line program data. .append_bytes(expected_program) @@ -3033,6 +3088,10 @@ mod tests { FileEntryFormat { content_type: constants::DW_LNCT_MD5, form: constants::DW_FORM_data16, + }, + FileEntryFormat { + content_type: constants::DW_LNCT_LLVM_source, + form: constants::DW_FORM_string, } ] ); diff --git a/third_party/rust/gimli/src/read/lists.rs b/third_party/rust/gimli/src/read/lists.rs index 898a757d379b..bb41901ddca4 100644 --- a/third_party/rust/gimli/src/read/lists.rs +++ b/third_party/rust/gimli/src/read/lists.rs @@ -49,7 +49,7 @@ fn parse_header(input: &mut R) -> Result { return Err(Error::UnknownVersion(u64::from(version))); } - let address_size = input.read_u8()?; + let address_size = input.read_address_size()?; let segment_selector_size = input.read_u8()?; if segment_selector_size != 0 { return Err(Error::UnsupportedSegmentSize); diff --git a/third_party/rust/gimli/src/read/loclists.rs b/third_party/rust/gimli/src/read/loclists.rs index 66fd0eb9ae4b..a28746875834 100644 --- a/third_party/rust/gimli/src/read/loclists.rs +++ b/third_party/rust/gimli/src/read/loclists.rs @@ -6,7 +6,7 @@ use crate::constants; use crate::endianity::Endianity; use crate::read::{ lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader, - ReaderOffset, ReaderOffsetId, Result, Section, + ReaderAddress, ReaderOffset, ReaderOffsetId, Result, Section, }; /// The raw contents of the `.debug_loc` section. @@ -593,7 +593,8 @@ impl LocListIter { &mut self, raw_loc: RawLocListEntry, ) -> Result>> { - let mask = !0 >> (64 - self.raw.encoding.address_size * 8); + let address_size = self.raw.encoding.address_size; + let mask = u64::ones_sized(address_size); let tombstone = if self.raw.encoding.version <= 4 { mask - 1 } else { @@ -620,13 +621,13 @@ impl LocListIter { data, } => { let begin = self.get_address(begin)?; - let end = begin.wrapping_add(length) & mask; + let end = begin.wrapping_add_sized(length, address_size); (Range { begin, end }, data) } RawLocListEntry::DefaultLocation { data } => ( Range { begin: 0, - end: u64::max_value(), + end: u64::MAX, }, data, ), @@ -645,7 +646,7 @@ impl LocListIter { length, data, } => { - let end = begin.wrapping_add(length) & mask; + let end = begin.wrapping_add_sized(length, address_size); (Range { begin, end }, data) } }; @@ -880,7 +881,7 @@ mod tests { Ok(Some(LocationListEntry { range: Range { begin: 0, - end: u64::max_value(), + end: u64::MAX, }, data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), })) @@ -1144,7 +1145,7 @@ mod tests { Ok(Some(LocationListEntry { range: Range { begin: 0, - end: u64::max_value(), + end: u64::MAX, }, data: Expression(EndianSlice::new(&[10, 0, 0, 0], LittleEndian)), })) diff --git a/third_party/rust/gimli/src/read/mod.rs b/third_party/rust/gimli/src/read/mod.rs index 42542cc32a0e..e90d42390276 100644 --- a/third_party/rust/gimli/src/read/mod.rs +++ b/third_party/rust/gimli/src/read/mod.rs @@ -64,22 +64,22 @@ //! * Basic familiarity with DWARF is assumed. //! //! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF -//! sections. It has methods that simplify access to debugging data that spans -//! multiple sections. Use of this type is optional, but recommended. +//! sections. It has methods that simplify access to debugging data that spans +//! multiple sections. Use of this type is optional, but recommended. //! //! * The [`DwarfPackage`](./struct.Dwarf.html) type contains the DWARF -//! package (DWP) sections. It has methods to find a DWARF object (DWO) -//! within the package. +//! package (DWP) sections. It has methods to find a DWARF object (DWO) +//! within the package. //! //! * Each section gets its own type. Consider these types the entry points to -//! the library: +//! the library: //! //! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section. //! //! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section. //! //! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges` -//! section. +//! section. //! //! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section. //! @@ -94,10 +94,10 @@ //! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section. //! //! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames` -//! section. +//! section. //! //! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes` -//! section. +//! section. //! //! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section. //! @@ -118,15 +118,15 @@ //! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section. //! //! * Each section type exposes methods for accessing the debugging data encoded -//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) -//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for -//! iterating over the compilation units defined within it. +//! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) +//! struct has the [`units`](./struct.DebugInfo.html#method.units) method for +//! iterating over the compilation units defined within it. //! //! * Offsets into a section are strongly typed: an offset into `.debug_info` is -//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be -//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because -//! `DebugLine` represents the `.debug_line` section. There are similar types -//! for offsets relative to a compilation unit rather than a section. +//! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be +//! used to index into the [`DebugLine`](./struct.DebugLine.html) type because +//! `DebugLine` represents the `.debug_line` section. There are similar types +//! for offsets relative to a compilation unit rather than a section. //! //! ## Using with `FallibleIterator` //! @@ -275,6 +275,7 @@ pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; /// An error that occurred when parsing. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[non_exhaustive] pub enum Error { /// An I/O error occurred while reading. Io, @@ -386,6 +387,11 @@ pub enum Error { UnknownCallFrameInstruction(constants::DwCfa), /// The end of an address range was before the beginning. InvalidAddressRange, + /// An address calculation overflowed. + /// + /// This is returned in cases where the address is expected to be + /// larger than a previous address, but the calculation overflowed. + AddressOverflow, /// Encountered a call frame instruction in a context in which it is not /// valid. CfiInstructionInInvalidContext, @@ -543,6 +549,7 @@ impl Error { Error::InvalidAddressRange => { "The end of an address range must not be before the beginning." } + Error::AddressOverflow => "An address calculation overflowed.", Error::CfiInstructionInInvalidContext => { "Encountered a call frame instruction in a context in which it is not valid." } diff --git a/third_party/rust/gimli/src/read/op.rs b/third_party/rust/gimli/src/read/op.rs index 2d2ba46c1fe8..42d3cee835b4 100644 --- a/third_party/rust/gimli/src/read/op.rs +++ b/third_party/rust/gimli/src/read/op.rs @@ -2022,7 +2022,6 @@ mod tests { use crate::leb128; use crate::read::{EndianSlice, Error, Result, UnitOffset}; use crate::test_util::GimliSectionMethods; - use core::usize; use test_assembler::{Endian, Section}; fn encoding4() -> Encoding { diff --git a/third_party/rust/gimli/src/read/reader.rs b/third_party/rust/gimli/src/read/reader.rs index 2d55934fa903..b1654feb6b7a 100644 --- a/third_party/rust/gimli/src/read/reader.rs +++ b/third_party/rust/gimli/src/read/reader.rs @@ -187,6 +187,49 @@ impl ReaderOffset for usize { } } +/// A trait for addresses within a DWARF section. +/// +/// Currently this is a simple extension trait for `u64`, but it may be expanded +/// in the future to support user-defined address types. +pub(crate) trait ReaderAddress: Sized { + /// Add a length to an address of the given size. + /// + /// Returns an error for overflow. + fn add_sized(self, length: u64, size: u8) -> Result; + + /// Add a length to an address of the given size. + /// + /// Wraps the result to the size of the address to allow for the possibility + /// that the length is a negative value. + fn wrapping_add_sized(self, length: u64, size: u8) -> Self; + + /// The all-ones value of an address of the given size. + fn ones_sized(size: u8) -> Self; +} + +impl ReaderAddress for u64 { + #[inline] + fn add_sized(self, length: u64, size: u8) -> Result { + let address = self.checked_add(length).ok_or(Error::AddressOverflow)?; + let mask = Self::ones_sized(size); + if address & !mask != 0 { + return Err(Error::AddressOverflow); + } + Ok(address) + } + + #[inline] + fn wrapping_add_sized(self, length: u64, size: u8) -> Self { + let mask = Self::ones_sized(size); + self.wrapping_add(length) & mask + } + + #[inline] + fn ones_sized(size: u8) -> Self { + !0 >> (64 - size * 8) + } +} + #[cfg(not(feature = "read"))] pub(crate) mod seal_if_no_alloc { #[derive(Debug)] @@ -452,6 +495,15 @@ pub trait Reader: Debug + Clone { } } + /// Read a byte and validate it as an address size. + fn read_address_size(&mut self) -> Result { + let size = self.read_u8()?; + match size { + 1 | 2 | 4 | 8 => Ok(size), + _ => Err(Error::UnsupportedAddressSize(size)), + } + } + /// Read an address-sized integer, and return it as a `u64`. fn read_address(&mut self, address_size: u8) -> Result { match address_size { diff --git a/third_party/rust/gimli/src/read/rnglists.rs b/third_party/rust/gimli/src/read/rnglists.rs index f3f713d72c98..47d2a44b1ff2 100644 --- a/third_party/rust/gimli/src/read/rnglists.rs +++ b/third_party/rust/gimli/src/read/rnglists.rs @@ -5,8 +5,8 @@ use crate::common::{ use crate::constants; use crate::endianity::Endianity; use crate::read::{ - lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderOffset, ReaderOffsetId, - Result, Section, + lists::ListsHeader, DebugAddr, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, + ReaderOffsetId, Result, Section, }; /// The raw contents of the `.debug_ranges` section. @@ -527,7 +527,8 @@ impl RngListIter { /// The raw range should have been obtained from `next_raw`. #[doc(hidden)] pub fn convert_raw(&mut self, raw_range: RawRngListEntry) -> Result> { - let mask = !0 >> (64 - self.raw.encoding.address_size * 8); + let address_size = self.raw.encoding.address_size; + let mask = u64::ones_sized(address_size); let tombstone = if self.raw.encoding.version <= 4 { mask - 1 } else { @@ -550,7 +551,7 @@ impl RngListIter { } RawRngListEntry::StartxLength { begin, length } => { let begin = self.get_address(begin)?; - let end = begin.wrapping_add(length) & mask; + let end = begin.wrapping_add_sized(length, address_size); Range { begin, end } } RawRngListEntry::AddressOrOffsetPair { begin, end } @@ -564,7 +565,7 @@ impl RngListIter { } RawRngListEntry::StartEnd { begin, end } => Range { begin, end }, RawRngListEntry::StartLength { begin, length } => { - let end = begin.wrapping_add(length) & mask; + let end = begin.wrapping_add_sized(length, address_size); Range { begin, end } } }; @@ -624,7 +625,7 @@ impl RawRange { } /// An address range from the `.debug_ranges`, `.debug_rnglists`, or `.debug_aranges` sections. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Range { /// The beginning address of the range. pub begin: u64, @@ -637,9 +638,8 @@ impl Range { /// Add a base address to this range. #[inline] pub(crate) fn add_base_address(&mut self, base_address: u64, address_size: u8) { - let mask = !0 >> (64 - address_size * 8); - self.begin = base_address.wrapping_add(self.begin) & mask; - self.end = base_address.wrapping_add(self.end) & mask; + self.begin = base_address.wrapping_add_sized(self.begin, address_size); + self.end = base_address.wrapping_add_sized(self.end, address_size); } } diff --git a/third_party/rust/gimli/src/read/unit.rs b/third_party/rust/gimli/src/read/unit.rs index bd62aa90069c..e8e38620d9bc 100644 --- a/third_party/rust/gimli/src/read/unit.rs +++ b/third_party/rust/gimli/src/read/unit.rs @@ -2,7 +2,6 @@ use core::cell::Cell; use core::ops::{Range, RangeFrom, RangeTo}; -use core::{u16, u8}; use crate::common::{ DebugAbbrevOffset, DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineOffset, @@ -575,7 +574,7 @@ where // reader. if 2 <= version && version <= 4 { abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; - address_size = rest.read_u8()?; + address_size = rest.read_address_size()?; // Before DWARF5, all units in the .debug_info section are compilation // units, and all units in the .debug_types section are type units. unit_type = match unit_offset { @@ -584,7 +583,7 @@ where }; } else if version == 5 { unit_type = parse_unit_type(&mut rest)?; - address_size = rest.read_u8()?; + address_size = rest.read_address_size()?; abbrev_offset = parse_debug_abbrev_offset(&mut rest, format)?; } else { return Err(Error::UnknownVersion(u64::from(version))); @@ -1849,7 +1848,7 @@ where AttributeValue::Data8(data) => data as i64, AttributeValue::Sdata(data) => data, AttributeValue::Udata(data) => { - if data > i64::max_value() as u64 { + if data > i64::MAX as u64 { // Maybe we should emit a warning here return None; } @@ -4197,28 +4196,24 @@ mod tests { )] = &[ (AttributeValue::Data1(1), Some(1), Some(1)), ( - AttributeValue::Data1(core::u8::MAX), - Some(u64::from(std::u8::MAX)), + AttributeValue::Data1(u8::MAX), + Some(u64::from(u8::MAX)), Some(-1), ), (AttributeValue::Data2(1), Some(1), Some(1)), ( - AttributeValue::Data2(core::u16::MAX), - Some(u64::from(std::u16::MAX)), + AttributeValue::Data2(u16::MAX), + Some(u64::from(u16::MAX)), Some(-1), ), (AttributeValue::Data4(1), Some(1), Some(1)), ( - AttributeValue::Data4(core::u32::MAX), - Some(u64::from(std::u32::MAX)), + AttributeValue::Data4(u32::MAX), + Some(u64::from(u32::MAX)), Some(-1), ), (AttributeValue::Data8(1), Some(1), Some(1)), - ( - AttributeValue::Data8(core::u64::MAX), - Some(core::u64::MAX), - Some(-1), - ), + (AttributeValue::Data8(u64::MAX), Some(u64::MAX), Some(-1)), (AttributeValue::Sdata(1), Some(1), Some(1)), (AttributeValue::Sdata(-1), None, Some(-1)), (AttributeValue::Udata(1), Some(1), Some(1)), diff --git a/third_party/rust/gimli/src/write/cfi.rs b/third_party/rust/gimli/src/write/cfi.rs index d1339615f914..8d0a5205ed19 100644 --- a/third_party/rust/gimli/src/write/cfi.rs +++ b/third_party/rust/gimli/src/write/cfi.rs @@ -212,8 +212,7 @@ impl CommonInformationEntry { if encoding.version >= 4 { w.write_u8(encoding.address_size)?; - // TODO: segment_selector_size - w.write_u8(0)?; + w.write_u8(0)?; // segment_selector_size } w.write_uleb128(self.code_alignment_factor.into())?; diff --git a/third_party/rust/gimli/src/write/line.rs b/third_party/rust/gimli/src/write/line.rs index c78e01e418a9..7c47db816ff7 100644 --- a/third_party/rust/gimli/src/write/line.rs +++ b/third_party/rust/gimli/src/write/line.rs @@ -67,6 +67,12 @@ pub struct LineProgram { /// For version 5, this controls whether to emit `DW_LNCT_MD5`. pub file_has_md5: bool, + /// True if the file entries have embedded source code. + /// + /// For version <= 4, this is ignored. + /// For version 5, this controls whether to emit `DW_LNCT_LLVM_source`. + pub file_has_source: bool, + prev_row: LineRow, row: LineRow, // TODO: this probably should be either rows or sequences instead @@ -119,6 +125,7 @@ impl LineProgram { file_has_timestamp: false, file_has_size: false, file_has_md5: false, + file_has_source: false, }; // For all DWARF versions, directory index 0 is comp_dir. // For version <= 4, the entry is implicit. We still add @@ -153,6 +160,7 @@ impl LineProgram { file_has_timestamp: false, file_has_size: false, file_has_md5: false, + file_has_source: false, } } @@ -592,7 +600,8 @@ impl LineProgram { let count = 2 + if self.file_has_timestamp { 1 } else { 0 } + if self.file_has_size { 1 } else { 0 } - + if self.file_has_md5 { 1 } else { 0 }; + + if self.file_has_md5 { 1 } else { 0 } + + if self.file_has_source { 1 } else { 0 }; w.write_u8(count)?; w.write_uleb128(u64::from(constants::DW_LNCT_path.0))?; let file_form = self.comp_file.0.form(); @@ -611,6 +620,10 @@ impl LineProgram { w.write_uleb128(u64::from(constants::DW_LNCT_MD5.0))?; w.write_uleb128(constants::DW_FORM_data16.0.into())?; } + if self.file_has_source { + w.write_uleb128(u64::from(constants::DW_LNCT_LLVM_source.0))?; + w.write_uleb128(constants::DW_FORM_string.0.into())?; + } // File name entries. w.write_uleb128(self.files.len() as u64 + 1)?; @@ -632,6 +645,20 @@ impl LineProgram { if self.file_has_md5 { w.write(&info.md5)?; } + if self.file_has_source { + // Note: An empty DW_LNCT_LLVM_source is interpreted as missing + // source code. Included source code should always be + // terminated by a "\n" line ending. + let empty_str = LineString::String(Vec::new()); + let source = info.source.as_ref().unwrap_or(&empty_str); + source.write( + w, + constants::DW_FORM_string, + self.encoding, + debug_line_str_offsets, + debug_str_offsets, + )?; + } Ok(()) }; write_file(&self.comp_file.0, DirectoryId(0), &self.comp_file.1)?; @@ -937,7 +964,7 @@ mod id { pub use self::id::*; /// Extra information for file in a `LineProgram`. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct FileInfo { /// The implementation defined timestamp of the last modification of the file, /// or 0 if not available. @@ -950,6 +977,15 @@ pub struct FileInfo { /// /// Only used if version >= 5 and `LineProgram::file_has_md5` is `true`. pub md5: [u8; 16], + + /// Optionally some embedded sourcecode. + /// + /// Only used if version >= 5 and `LineProgram::file_has_source` is `true`. + /// + /// NOTE: This currently only supports the `LineString::String` variant, + /// since we're encoding the string with `DW_FORM_string`. + /// Other variants will result in an `LineStringFormMismatch` error. + pub source: Option, } define_section!( @@ -999,6 +1035,15 @@ mod convert { timestamp: comp_file.timestamp(), size: comp_file.size(), md5: *comp_file.md5(), + source: match comp_file.source() { + Some(source) => Some(LineString::from( + source, + dwarf, + line_strings, + strings, + )?), + None => None, + }, }), ) } @@ -1040,6 +1085,7 @@ mod convert { program.file_has_timestamp = from_header.file_has_timestamp(); program.file_has_size = from_header.file_has_size(); program.file_has_md5 = from_header.file_has_md5(); + program.file_has_source = from_header.file_has_source(); for from_file in from_header.file_names().iter().skip(file_skip) { let from_name = LineString::from(from_file.path_name(), dwarf, line_strings, strings)?; @@ -1052,6 +1098,12 @@ mod convert { timestamp: from_file.timestamp(), size: from_file.size(), md5: *from_file.md5(), + source: match from_file.source() { + Some(source) => { + Some(LineString::from(source, dwarf, line_strings, strings)?) + } + None => None, + }, }); files.push(program.add_file(from_name, from_dir, from_info)); } @@ -1074,13 +1126,14 @@ mod convert { Some(val) => address = Some(val), None => return Err(ConvertError::InvalidAddress), } - from_row.execute(read::LineInstruction::SetAddress(0), &mut from_program); + from_row + .execute(read::LineInstruction::SetAddress(0), &mut from_program)?; } read::LineInstruction::DefineFile(_) => { return Err(ConvertError::UnsupportedLineInstruction); } _ => { - if from_row.execute(instruction, &mut from_program) { + if from_row.execute(instruction, &mut from_program)? { if !program.in_sequence() { program.begin_sequence(address); address = None; @@ -1190,6 +1243,13 @@ mod tests { program.file_has_md5 = true; } + // Note: Embedded source code is an accepted extension + // that will become part of DWARF v6. We're using the LLVM extension + // here for v5. + if encoding.version >= 5 { + program.file_has_source = true; + } + let dir_id = program.add_directory(dir2.clone()); assert_eq!(&dir2, program.get_directory(dir_id)); assert_eq!(dir_id, program.add_directory(dir2.clone())); @@ -1202,8 +1262,11 @@ mod tests { } else { [0; 16] }, + source: (encoding.version >= 5) + .then(|| LineString::String(b"the source code\n".to_vec())), }; - let file_id = program.add_file(file2.clone(), dir_id, Some(file_info)); + let file_id = + program.add_file(file2.clone(), dir_id, Some(file_info.clone())); assert_eq!((&file2, dir_id), program.get_file(file_id)); assert_eq!(file_info, *program.get_file_info(file_id)); @@ -1213,7 +1276,7 @@ mod tests { assert_ne!(file_info, *program.get_file_info(file_id)); assert_eq!( file_id, - program.add_file(file2.clone(), dir_id, Some(file_info)) + program.add_file(file2.clone(), dir_id, Some(file_info.clone())) ); assert_eq!(file_info, *program.get_file_info(file_id)); diff --git a/third_party/rust/gimli/src/write/mod.rs b/third_party/rust/gimli/src/write/mod.rs index b3b894e9fa71..b7adbbe265ab 100644 --- a/third_party/rust/gimli/src/write/mod.rs +++ b/third_party/rust/gimli/src/write/mod.rs @@ -6,10 +6,10 @@ //! in memory, and then writing it all at once. It supports two major use cases: //! //! * Use the [`DwarfUnit`](./struct.DwarfUnit.html) type when writing DWARF -//! for a single compilation unit. +//! for a single compilation unit. //! //! * Use the [`Dwarf`](./struct.Dwarf.html) type when writing DWARF for multiple -//! compilation units. +//! compilation units. //! //! The module also supports reading in DWARF debugging information and writing it out //! again, possibly after modifying it. Create a [`read::Dwarf`](../read/struct.Dwarf.html) diff --git a/third_party/rust/gimli/src/write/unit.rs b/third_party/rust/gimli/src/write/unit.rs index fe63ec9144e1..53b392e1507d 100644 --- a/third_party/rust/gimli/src/write/unit.rs +++ b/third_party/rust/gimli/src/write/unit.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use std::ops::{Deref, DerefMut}; -use std::{slice, usize}; +use std::slice; use crate::common::{ DebugAbbrevOffset, DebugInfoOffset, DebugLineOffset, DebugMacinfoOffset, DebugMacroOffset, diff --git a/third_party/rust/gimli/src/write/writer.rs b/third_party/rust/gimli/src/write/writer.rs index 1ce3641fca5b..9ee071bf61f8 100644 --- a/third_party/rust/gimli/src/write/writer.rs +++ b/third_party/rust/gimli/src/write/writer.rs @@ -329,7 +329,6 @@ mod tests { use super::*; use crate::write; use crate::{BigEndian, LittleEndian}; - use std::{i64, u64}; #[test] fn test_writer() { diff --git a/third_party/rust/goblin/.cargo-checksum.json b/third_party/rust/goblin/.cargo-checksum.json index 3b4146645f23..e3f4be4926d5 100644 --- a/third_party/rust/goblin/.cargo-checksum.json +++ b/third_party/rust/goblin/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"50453c2109df5663c2e96b8f1f23525249c5fc2f59c8f74ec5c2b3646ac21144","Cargo.lock":"b9dbea5eb49f6f64c350b16cc7c13dc16086e6888b7a622794393400137a4280","Cargo.toml":"f57048482755f5bddc3ed3a06b469ebec4923b647df060ae53f3a349932ddf76","LICENSE":"655e3ee7a4c27430774962e62a6d37d7348e5f2f292010ad674ce1bebefd24bc","README.md":"d108b8d55ecd89934af0d94c6c86d4e39ed2daefa8d2ad5a229cae61dfe6f531","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"2837231dd3e2341008842e031b81cbb9999214a2f9e6738c6374a5464d62555d","src/elf/dynamic.rs":"907146d1968f656fc9cc3621037c193877e30675ccd8ec6eb2e3adbc1e2afd27","src/elf/gnu_hash.rs":"4592b5516d807a61a9dccc3f97266587c032eea621708bd78e23c70be6128228","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"e952fc4f79ac6a08f218a4758321ab94f172c376dc5235a82f70732682cca82f","src/elf/section_header.rs":"72eb788e8807f16a97683d20add21d5c3feaae06813509e2a87b76a7cd0c376f","src/elf/sym.rs":"267996f926f337b88058908af260be30473afbe1fe6d72cdeb8dd0ed474671d8","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"a1bb56d82db52ac627e55b163f489f06a78c939a8ccfdec210b4f726d6ed6e9d","src/lib.rs":"f29832bdf7d7f7d9e34f65704afea2710d578df60cc171dd179b5ce889faaf12","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"42e6f0973092185db233230e71e9312bbac7c2e1090bb6d713804020319dfa33","src/mach/mod.rs":"f1e120b7aabe370fa2af43e359f97ffa3e187fdb5743ef19c37402264e92b326","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"947acd8a724b41d0afbbd9e2727f41be51f1be439f47417258e829db1a4765e6","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"36b5b3ddc9806f679cf21418bc13af4b277eba87096304dfb50946bc0f941206","src/pe/certificate_table.rs":"f6c31ba518d9fc4b6e12d2f24d6c9d58b21b341a1f189cbcf2aae0ae51304ad3","src/pe/characteristic.rs":"2ffa012ec225f3c8570689713969a7dc34a92eaf4f944a27881fd0c248cc8b20","src/pe/data_directories.rs":"d0352ccc03e0ab2935235e91b391cc55828406087f026f90ec11ca5906fd8c8c","src/pe/debug.rs":"3811c616a9b6d6b54e15348bb369b794bb89532e04fe19eca91b745d7c51a553","src/pe/dll_characteristic.rs":"d63e86ecb38ccdd81493268be34535391b794651d619e8d4ccc1a56aa10e1679","src/pe/exception.rs":"3935900334692a6f54f7176eca044688289834bcde1b579b88d6ed1af3c3c005","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"dea84fd7101aff56c7cb6ff08a1efdde5cf43a04328397b6177d36ab1c2a3774","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"1d8a7cb3ddb8443e34939adda4794308a31737bc29f66668d36dfa22950ba69f","src/pe/optional_header.rs":"f2411a0f272e22c280a1fe3c15919b07d1f152448b47db31acaacad8a0a9a153","src/pe/options.rs":"457877197f768c331437297d787dc718b1053b813e3a1dd9b968133fb1540d44","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"e4b1a2f78c2336aaa0355b5ef102dbe29138c4fa1ba29ed3f379aad1fc64bdff","src/pe/subsystem.rs":"162a851e217b617aa8afa1b83e37ea9c5a793f76a17be57b56b550d7cabb7b8a","src/pe/symbol.rs":"1a5fb5bec5727752a6506682ed2ab57829ea810f21f951932a0107861ec0e092","src/pe/utils.rs":"e6da9979ba5f2ae7d1274eef8230cdc4dd90c90a79c7bb9438f8b8ff0aef74be","src/strtab.rs":"110c774b2998514b4d0be1d575b3e2a8eb85f801b6f782e4ed3a8f7521920689","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9"},"package":"1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47"} \ No newline at end of file +{"files":{"CHANGELOG.md":"052930023a92d0dbf45d189df2ecf26e5469ef5c19d7140ea1290c44f9fa9c35","Cargo.lock":"d5985b8c733c8687aa69004e66d67e15db06f6b4eb8615df053fe404f8b7e017","Cargo.toml":"917e3955b6516af682981eb51bb7d665155a804674cb9f8871bfff9d9a745923","LICENSE":"655e3ee7a4c27430774962e62a6d37d7348e5f2f292010ad674ce1bebefd24bc","README.md":"3cdbab44cacba8d4d39443affba422adf22d7f00d9c68bac80c7d25b94520dc5","src/archive/mod.rs":"ae739638d7267011bedf51712516d3485171d8f2df2ab6746a0d942d86efd6a6","src/elf/compression_header.rs":"2eb5fdda9177c1c897310d86714967de019b39c6e23b1f3a890dd3a659be0acc","src/elf/constants_header.rs":"f2ede290ecacf60b1719e9994aa45612bf0f7baf63806a293d4530a674e5861a","src/elf/constants_relocation.rs":"2837231dd3e2341008842e031b81cbb9999214a2f9e6738c6374a5464d62555d","src/elf/dynamic.rs":"907146d1968f656fc9cc3621037c193877e30675ccd8ec6eb2e3adbc1e2afd27","src/elf/gnu_hash.rs":"4592b5516d807a61a9dccc3f97266587c032eea621708bd78e23c70be6128228","src/elf/header.rs":"3391a1fa9b8e3923f7ce74caff0668d8ddb5b34767bf3da309ff497fd81c34c7","src/elf/mod.rs":"2ee0faa0917deb5e90ca60e9c852434745a4c7f553e609e9603a57b7d55b739f","src/elf/note.rs":"bf5e45e2697f7700d5adbb52f890ea4c63b70b7077ca0e7c751420bb92923529","src/elf/program_header.rs":"4c322eb124c4e2bdeec4915067d2bb11fe9e7fba1811dc351a3f7581df121da0","src/elf/reloc.rs":"e952fc4f79ac6a08f218a4758321ab94f172c376dc5235a82f70732682cca82f","src/elf/section_header.rs":"72eb788e8807f16a97683d20add21d5c3feaae06813509e2a87b76a7cd0c376f","src/elf/sym.rs":"267996f926f337b88058908af260be30473afbe1fe6d72cdeb8dd0ed474671d8","src/elf/symver.rs":"3f899201f64a702653d44288f860003e7acd75e38111d36479af823ed92b1341","src/error.rs":"a1bb56d82db52ac627e55b163f489f06a78c939a8ccfdec210b4f726d6ed6e9d","src/lib.rs":"06771b56b262fa30396e4bacbf0a4996b6088d1cfa5defa20dedf69a2c58d3b3","src/mach/bind_opcodes.rs":"1dcacfb853d05c2c7e6dbb4509ee705a8ea645db0d334991a2293fef92eee851","src/mach/constants.rs":"c2a2381a0b9c3047d37582465e8965d995dca414d0da21fb7bcc6b8334e49eb6","src/mach/exports.rs":"d22122744673a3ce5f54b2b4b20bfa47d17378e64d3dda2858dd13add74ed3dc","src/mach/fat.rs":"45a3228aaa1ab8b77f322dd4924b7383f1357e226ffc079846d67c0268389ea7","src/mach/header.rs":"006619188f51fa43051dc04aa4b2ecd5f89136cf05cb6a7b23a228228008e6ae","src/mach/imports.rs":"2153269dfff32e23d72f76a82d658be06bd79b7e35d79b7e17115e4eb24b13d5","src/mach/load_command.rs":"42e6f0973092185db233230e71e9312bbac7c2e1090bb6d713804020319dfa33","src/mach/mod.rs":"f1e120b7aabe370fa2af43e359f97ffa3e187fdb5743ef19c37402264e92b326","src/mach/relocation.rs":"11b0b76ed7d997c87e396100515f931fe84473c228bed0e980fbab311530070a","src/mach/segment.rs":"947acd8a724b41d0afbbd9e2727f41be51f1be439f47417258e829db1a4765e6","src/mach/symbols.rs":"d2505fa8d65ea267abfcb6a9fc4d1acd47d5605aa6775935757e2fa8e92af507","src/pe/authenticode.rs":"36b5b3ddc9806f679cf21418bc13af4b277eba87096304dfb50946bc0f941206","src/pe/certificate_table.rs":"f6c31ba518d9fc4b6e12d2f24d6c9d58b21b341a1f189cbcf2aae0ae51304ad3","src/pe/characteristic.rs":"2ffa012ec225f3c8570689713969a7dc34a92eaf4f944a27881fd0c248cc8b20","src/pe/data_directories.rs":"d0352ccc03e0ab2935235e91b391cc55828406087f026f90ec11ca5906fd8c8c","src/pe/debug.rs":"485758ff505c070da2a26df9099b90fc421e679b05b520d7b13c95a63647d1a0","src/pe/dll_characteristic.rs":"d63e86ecb38ccdd81493268be34535391b794651d619e8d4ccc1a56aa10e1679","src/pe/exception.rs":"3935900334692a6f54f7176eca044688289834bcde1b579b88d6ed1af3c3c005","src/pe/export.rs":"c98f5ce0b1b18bb87f06d1d41dbf70f443d65ecb1624cb23a1ef6c5f93a892e1","src/pe/header.rs":"9e765f03be5e2ee6d80add0fa4fa81f38e973d7bb646f8df31fdeda106e8aa1d","src/pe/import.rs":"855276e46c01ccd7631104e4d1265592e36c9468aadcacc937a40c29d94aabe3","src/pe/mod.rs":"21ea8aed0716df6e2f5c13658f40a05bfbf6ce2c467dfd2391f661896c79d54b","src/pe/optional_header.rs":"f2411a0f272e22c280a1fe3c15919b07d1f152448b47db31acaacad8a0a9a153","src/pe/options.rs":"457877197f768c331437297d787dc718b1053b813e3a1dd9b968133fb1540d44","src/pe/relocation.rs":"c479b80bb1d6910f2168505dda4f2d8925b7edc34bed4e25d069546f88f52bb3","src/pe/section_table.rs":"e4b1a2f78c2336aaa0355b5ef102dbe29138c4fa1ba29ed3f379aad1fc64bdff","src/pe/subsystem.rs":"162a851e217b617aa8afa1b83e37ea9c5a793f76a17be57b56b550d7cabb7b8a","src/pe/symbol.rs":"1a5fb5bec5727752a6506682ed2ab57829ea810f21f951932a0107861ec0e092","src/pe/tls.rs":"d674d46c870e090e90e6b709620abd3de990ae1f85a66253b81004cce03d1b6a","src/pe/utils.rs":"adf5b8bd79e90211e82cda8f01ee775b9cdfd20bfafdee36c54000daea8592c0","src/strtab.rs":"110c774b2998514b4d0be1d575b3e2a8eb85f801b6f782e4ed3a8f7521920689","tests/bins/elf/gnu_hash/README.md":"52581e2ea7067a55bd8aedf4079200fb76448573ae9ffef7d886b9556e980db9","tests/bins/te/README.md":"a0daf347449bcf82c38d981b2a700d9fd4657c3a7e7dbfa22f90e74750c6bc0d"},"package":"53ab3f32d1d77146981dea5d6b1e8fe31eedcb7013e5e00d6ccd1259a4b4d923"} \ No newline at end of file diff --git a/third_party/rust/goblin/CHANGELOG.md b/third_party/rust/goblin/CHANGELOG.md index 0a0c1160ddd9..1c06d490363b 100644 --- a/third_party/rust/goblin/CHANGELOG.md +++ b/third_party/rust/goblin/CHANGELOG.md @@ -3,9 +3,30 @@ All notable changes to this project will be documented in this file. Before 1.0, this project does not adhere to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -Goblin is now 0.8, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97 +Goblin is now 0.9, which means we will try our best to ease breaking changes. Tracking issue is here: https://github.com/m4b/goblin/issues/97 -## [0.8.1] - 2024-04-27 +## [0.9.2] - 2024-10-26 +### Fixed +pe: fix PE with zero `raw_data_size` of section, thanks @ideeockus: https://github.com/m4b/goblin/pull/396 +### Added +pe: allow parsing pe::Header without dos stubs, `Header::parse_without_dos`, thanks @ideeockus: https://github.com/m4b/goblin/pull/396 + +## [0.9.1] - 2024-10-24 +### (hot) Fix +pe: fix parsing of tls in certain cases (issue: https://github.com/m4b/goblin/issues/424), thanks @kkent030315: https://github.com/m4b/goblin/pull/425 + +## [0.9.0] - 2024-10-20 +### Added, Breaking +pe: add TE (terse executable) support, big thanks @Javagedes: https://github.com/m4b/goblin/pull/397 +pe: add support for codeview PDB 2.0, thanks @joschock: https://github.com/m4b/goblin/pull/409 +pe: parse TLS in data directories, thanks @kkent030315: https://github.com/m4b/goblin/pull/404 + +## [0.8.2] - 2024-04-29 +Everything in 0.8.1 except TE support in https://github.com/m4b/goblin/pull/397 was reverted, +due to it being technically a breaking change. +0.8.1 was yanked from crates. + +## [0.8.1] - 2024-04-27 (YANKED) ### Docs pe: document pe header, thanks @JohnScience: https://github.com/m4b/goblin/pull/399 pe, elf: fix doc warnings, thanks @5225225: https://github.com/m4b/goblin/pull/395 diff --git a/third_party/rust/goblin/Cargo.lock b/third_party/rust/goblin/Cargo.lock index 91a973f869d9..5413e1ded283 100644 --- a/third_party/rust/goblin/Cargo.lock +++ b/third_party/rust/goblin/Cargo.lock @@ -74,7 +74,7 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "goblin" -version = "0.8.2" +version = "0.9.2" dependencies = [ "log", "plain", diff --git a/third_party/rust/goblin/Cargo.toml b/third_party/rust/goblin/Cargo.toml index 7da9d7382596..fb50e284dda4 100644 --- a/third_party/rust/goblin/Cargo.toml +++ b/third_party/rust/goblin/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.63.0" name = "goblin" -version = "0.8.2" +version = "0.9.2" authors = [ "m4b ", "seu ", @@ -21,6 +21,7 @@ authors = [ "Philip Craig ", "Lzu Tao ", ] +build = false include = [ "src", "CHANGELOG.md", @@ -28,6 +29,10 @@ include = [ "LICENSE", "README.md", ] +autobins = false +autoexamples = false +autotests = false +autobenches = false description = "An impish, cross-platform, ELF, Mach-o, and PE binary parsing and loading crate" documentation = "https://docs.rs/goblin" readme = "README.md" @@ -45,6 +50,10 @@ categories = [ license = "MIT" repository = "https://github.com/m4b/goblin" +[lib] +name = "goblin" +path = "src/lib.rs" + [dependencies.log] version = "0.4" optional = true @@ -55,7 +64,7 @@ version = "0.2.3" [dependencies.scroll] version = "0.12" -default_features = false +default-features = false [dev-dependencies.stderrlog] version = "0.5.4" @@ -74,6 +83,7 @@ default = [ "mach64", "pe32", "pe64", + "te", "archive", "endian_fd", ] @@ -102,6 +112,10 @@ std = [ "alloc", "scroll/std", ] +te = [ + "alloc", + "endian_fd", +] [badges.travis-ci] branch = "master" diff --git a/third_party/rust/goblin/README.md b/third_party/rust/goblin/README.md index 36648a4b677a..be3f08342a1c 100644 --- a/third_party/rust/goblin/README.md +++ b/third_party/rust/goblin/README.md @@ -26,7 +26,7 @@ Add to your `Cargo.toml` ```toml [dependencies] -goblin = "0.8" +goblin = "0.9" ``` ### Features @@ -97,6 +97,7 @@ Here are some things you could do with this crate (or help to implement so they * mach32 - 32-bit mach-o `repr(C)` struct defs * pe32 - 32-bit PE `repr(C)` struct defs * pe64 - 64-bit PE `repr(C)` struct defs ++ te - Terse Executable (TE) `repr(C)` struct defs * archive - a Unix Archive parser * endian_fd - parses according to the endianness in the binary * std - to allow `no_std` environments @@ -124,6 +125,7 @@ In lexicographic order: - [@glandium] - [@h33p] - [@ibabushkin] +- [@ideeockus] - [@jackcmay] - [@jan-auer] - [@Javagedes] @@ -132,6 +134,7 @@ In lexicographic order: - [@Jhynjhiruu] - [@johannst] - [@JohnScience] +- [@joschock] - [@jrmuizel] - [@jsgf] - [@keith] @@ -207,6 +210,7 @@ In lexicographic order: [@glandium]: https://github.com/glandium [@h33p]: https://github.com/h33p [@ibabushkin]: https://github.com/ibabushkin +[@ideeockus]: https://github.com/ideeockus [@jackcmay]: https://github.com/jackcmay [@jan-auer]: https://github.com/jan-auer [@Javagedes]: https://github.com/Javagedes @@ -214,6 +218,7 @@ In lexicographic order: [@Jhynjhiruu]: https://github.com/Jhynjhiruu [@JohnScience]: https://github.com/JohnScience [@johannst]: https://github.com/johannst +[@joschock]: https://github.com/joschock [@jdub]: https://github.com/jdub [@jrmuizel]: https://github.com/jrmuizel [@jsgf]: https://github.com/jsgf diff --git a/third_party/rust/goblin/src/lib.rs b/third_party/rust/goblin/src/lib.rs index ec77f93d5c26..e811de1ea5dc 100644 --- a/third_party/rust/goblin/src/lib.rs +++ b/third_party/rust/goblin/src/lib.rs @@ -229,6 +229,7 @@ pub enum Hint { Mach(HintData), MachFat(usize), PE, + TE, COFF, Archive, Unknown(u64), @@ -236,7 +237,7 @@ pub enum Hint { macro_rules! if_everything { ($($i:item)*) => ($( - #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] + #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "te", feature = "mach64", feature = "mach32", feature = "archive"))] $i )*) } @@ -262,6 +263,7 @@ if_everything! { } else { match *&bytes[0..2].pread_with::(0, LE)? { pe::header::DOS_MAGIC => Ok(Hint::PE), + pe::header::TE_MAGIC => Ok(Hint::TE), pe::header::COFF_MACHINE_X86 | pe::header::COFF_MACHINE_X86_64 | pe::header::COFF_MACHINE_ARM64 => Ok(Hint::COFF), @@ -290,6 +292,8 @@ if_everything! { Elf(elf::Elf<'a>), /// A PE32/PE32+! PE(pe::PE<'a>), + /// A TE! + TE(pe::TE<'a>), /// A COFF COFF(pe::Coff<'a>), /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container! @@ -309,6 +313,7 @@ if_everything! { Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)), Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)), Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)), + Hint::TE => Ok(Object::TE(pe::TE::parse(bytes)?)), Hint::COFF => Ok(Object::COFF(pe::Coff::parse(bytes)?)), Hint::Unknown(magic) => Ok(Object::Unknown(magic)), } diff --git a/third_party/rust/goblin/src/pe/debug.rs b/third_party/rust/goblin/src/pe/debug.rs index 311bc632cbdf..89e6d21a6013 100644 --- a/third_party/rust/goblin/src/pe/debug.rs +++ b/third_party/rust/goblin/src/pe/debug.rs @@ -10,6 +10,7 @@ use crate::pe::utils; pub struct DebugData<'a> { pub image_debug_directory: ImageDebugDirectory, pub codeview_pdb70_debug_info: Option>, + pub codeview_pdb20_debug_info: Option>, } impl<'a> DebugData<'a> { @@ -39,10 +40,13 @@ impl<'a> DebugData<'a> { ImageDebugDirectory::parse_with_opts(bytes, dd, sections, file_alignment, opts)?; let codeview_pdb70_debug_info = CodeviewPDB70DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?; + let codeview_pdb20_debug_info = + CodeviewPDB20DebugInfo::parse_with_opts(bytes, &image_debug_directory, opts)?; Ok(DebugData { image_debug_directory, codeview_pdb70_debug_info, + codeview_pdb20_debug_info, }) } @@ -92,7 +96,7 @@ impl ImageDebugDirectory { ) } - fn parse_with_opts( + pub(crate) fn parse_with_opts( bytes: &[u8], dd: data_directories::DataDirectory, sections: &[section_table::SectionTable], @@ -184,3 +188,74 @@ impl<'a> CodeviewPDB70DebugInfo<'a> { } } } + +// http://llvm.org/doxygen/CVDebugRecord_8h_source.html +#[repr(C)] +#[derive(Debug, PartialEq, Copy, Clone, Default)] +pub struct CodeviewPDB20DebugInfo<'a> { + pub codeview_signature: u32, + pub codeview_offset: u32, + pub signature: u32, + pub age: u32, + pub filename: &'a [u8], +} + +impl<'a> CodeviewPDB20DebugInfo<'a> { + pub fn parse(bytes: &'a [u8], idd: &ImageDebugDirectory) -> error::Result> { + Self::parse_with_opts(bytes, idd, &options::ParseOptions::default()) + } + + pub fn parse_with_opts( + bytes: &'a [u8], + idd: &ImageDebugDirectory, + opts: &options::ParseOptions, + ) -> error::Result> { + if idd.data_type != IMAGE_DEBUG_TYPE_CODEVIEW { + // not a codeview debug directory + // that's not an error, but it's not a CodeviewPDB20DebugInfo either + return Ok(None); + } + + // ImageDebugDirectory.pointer_to_raw_data stores a raw offset -- not a virtual offset -- which we can use directly + let mut offset: usize = match opts.resolve_rva { + true => idd.pointer_to_raw_data as usize, + false => idd.address_of_raw_data as usize, + }; + + // calculate how long the eventual filename will be, which doubles as a check of the record size + let filename_length = idd.size_of_data as isize - 16; + if filename_length < 0 { + // the record is too short to be plausible + return Err(error::Error::Malformed(format!( + "ImageDebugDirectory size of data seems wrong: {:?}", + idd.size_of_data + ))); + } + let filename_length = filename_length as usize; + + // check the codeview signature + let codeview_signature: u32 = bytes.gread_with(&mut offset, scroll::LE)?; + if codeview_signature != CODEVIEW_PDB20_MAGIC { + return Ok(None); + } + let codeview_offset: u32 = bytes.gread_with(&mut offset, scroll::LE)?; + + // read the rest + let signature: u32 = bytes.gread_with(&mut offset, scroll::LE)?; + let age: u32 = bytes.gread_with(&mut offset, scroll::LE)?; + if let Some(filename) = bytes.get(offset..offset + filename_length) { + Ok(Some(CodeviewPDB20DebugInfo { + codeview_signature, + codeview_offset, + signature, + age, + filename, + })) + } else { + Err(error::Error::Malformed(format!( + "ImageDebugDirectory seems corrupted: {:?}", + idd + ))) + } + } +} diff --git a/third_party/rust/goblin/src/pe/header.rs b/third_party/rust/goblin/src/pe/header.rs index 3a0f6abb3930..d1b4f36a4fa3 100644 --- a/third_party/rust/goblin/src/pe/header.rs +++ b/third_party/rust/goblin/src/pe/header.rs @@ -1,5 +1,5 @@ use crate::error; -use crate::pe::{optional_header, section_table, symbol}; +use crate::pe::{data_directories, optional_header, section_table, symbol}; use crate::strtab; use alloc::vec::Vec; use log::debug; @@ -791,14 +791,7 @@ pub struct Header { } impl Header { - pub fn parse(bytes: &[u8]) -> error::Result { - let dos_header = DosHeader::parse(&bytes)?; - let dos_stub = bytes.pread(DOS_STUB_OFFSET as usize).map_err(|_| { - error::Error::Malformed(format!( - "cannot parse DOS stub (offset {:#x})", - DOS_STUB_OFFSET - )) - })?; + fn parse_impl(bytes: &[u8], dos_header: DosHeader, dos_stub: DosStub) -> error::Result { let mut offset = dos_header.pe_pointer as usize; let signature = bytes.gread_with(&mut offset, scroll::LE).map_err(|_| { error::Error::Malformed(format!("cannot parse PE signature (offset {:#x})", offset)) @@ -809,6 +802,7 @@ impl Header { } else { None }; + Ok(Header { dos_header, dos_stub, @@ -817,6 +811,25 @@ impl Header { optional_header, }) } + + /// Parses PE header from the given bytes; this will fail if the DosHeader or DosStub is malformed or missing in some way + pub fn parse(bytes: &[u8]) -> error::Result { + let dos_header = DosHeader::parse(&bytes)?; + let dos_stub = bytes.pread(DOS_STUB_OFFSET as usize).map_err(|_| { + error::Error::Malformed(format!( + "cannot parse DOS stub (offset {:#x})", + DOS_STUB_OFFSET + )) + })?; + + Header::parse_impl(bytes, dos_header, dos_stub) + } + + /// Parses PE header from the given bytes, a default DosHeader and DosStub are generated, and any malformed header or stub is ignored + pub fn parse_without_dos(bytes: &[u8]) -> error::Result { + let dos_header = DosHeader::default(); + Header::parse_impl(bytes, dos_header, DosStub::default()) + } } impl ctx::TryIntoCtx for Header { @@ -835,6 +848,147 @@ impl ctx::TryIntoCtx for Header { } } +/// The TE header is a reduced PE32/PE32+ header containing only fields +/// required for execution in the Platform Initialization +/// ([PI](https://uefi.org/specs/PI/1.8/V1_Introduction.html)) architecture. +/// The TE header is described in this specification: +/// +#[cfg(feature = "te")] +#[repr(C)] +#[derive(Debug, Default, PartialEq, Copy, Clone, Pread, Pwrite)] +pub struct TeHeader { + /// Te signature, always [TE_MAGIC] + pub signature: u16, + /// The machine type + pub machine: u16, + /// The number of sections + pub number_of_sections: u8, + /// The subsystem + pub subsystem: u8, + /// the amount of bytes stripped from the header when converting from a + /// PE32/PE32+ header to a TE header. Used to resolve addresses + pub stripped_size: u16, + /// The entry point of the binary + pub entry_point: u32, + /// The base of the code section + pub base_of_code: u32, + /// The image base + pub image_base: u64, + /// The size and address of the relocation directory + pub reloc_dir: data_directories::DataDirectory, + /// The size and address of the debug directory + pub debug_dir: data_directories::DataDirectory, +} + +#[cfg(feature = "te")] +#[doc(alias("IMAGE_TE_SIGNATURE"))] +pub const TE_MAGIC: u16 = 0x5a56; + +#[cfg(feature = "te")] +impl TeHeader { + /// Parse the TE header from the given bytes. + pub fn parse(bytes: &[u8], offset: &mut usize) -> error::Result { + let mut header: TeHeader = bytes.gread_with(offset, scroll::LE)?; + let adj_offset = header.stripped_size as u32 - core::mem::size_of::() as u32; + header.fixup_header(adj_offset); + Ok(header) + } + + /// Parse the sections from the TE header. + pub fn sections( + &self, + bytes: &[u8], + offset: &mut usize, + ) -> error::Result> { + let adj_offset = self.stripped_size as u32 - core::mem::size_of::() as u32; + let nsections = self.number_of_sections as usize; + + // a section table is at least 40 bytes + if nsections > bytes.len() / 40 { + return Err(error::Error::BufferTooShort(nsections, "sections")); + } + + let mut sections = Vec::with_capacity(nsections); + for i in 0..nsections { + let mut section = section_table::SectionTable::parse(bytes, offset, 0)?; + TeHeader::fixup_section(&mut section, adj_offset); + debug!("({}) {:#?}", i, section); + sections.push(section); + } + Ok(sections) + } + + // Adjust addresses in the header to account for the stripped size + fn fixup_header(&mut self, adj_offset: u32) { + debug!( + "Entry point fixed up from: 0x{:x} to 0x{:X}", + self.entry_point, + self.entry_point.wrapping_sub(adj_offset) + ); + self.entry_point = self.entry_point.wrapping_sub(adj_offset); + + debug!( + "Base of code fixed up from: 0x{:x} to 0x{:X}", + self.base_of_code, + self.base_of_code.wrapping_sub(adj_offset) + ); + self.base_of_code = self.base_of_code.wrapping_sub(adj_offset); + + debug!( + "Relocation Directory fixed up from: 0x{:x} to 0x{:X}", + self.reloc_dir.virtual_address, + self.reloc_dir.virtual_address.wrapping_sub(adj_offset) + ); + self.reloc_dir.virtual_address = self.reloc_dir.virtual_address.wrapping_sub(adj_offset); + + debug!( + "Debug Directory fixed up from: 0x{:x} to 0x{:X}", + self.debug_dir.virtual_address, + self.debug_dir.virtual_address.wrapping_sub(adj_offset) + ); + self.debug_dir.virtual_address = self.debug_dir.virtual_address.wrapping_sub(adj_offset); + } + + // Adjust addresses in the section to account for the stripped size + fn fixup_section(section: &mut section_table::SectionTable, adj_offset: u32) { + debug!( + "Section virtual address fixed up from: 0x{:X} to 0x{:X}", + section.virtual_address, + section.virtual_address.wrapping_sub(adj_offset) + ); + section.virtual_address = section.virtual_address.wrapping_sub(adj_offset); + + if section.pointer_to_linenumbers > 0 { + debug!( + "Section pointer to line numbers fixed up from: 0x{:X} to 0x{:X}", + section.pointer_to_linenumbers, + section.pointer_to_linenumbers.wrapping_sub(adj_offset) + ); + section.pointer_to_linenumbers = + section.pointer_to_linenumbers.wrapping_sub(adj_offset); + } + + if section.pointer_to_raw_data > 0 { + debug!( + "Section pointer to raw data fixed up from: 0x{:X} to 0x{:X}", + section.pointer_to_raw_data, + section.pointer_to_raw_data.wrapping_sub(adj_offset) + ); + section.pointer_to_raw_data = section.pointer_to_raw_data.wrapping_sub(adj_offset); + } + + if section.pointer_to_relocations > 0 { + debug!( + "Section pointer to relocations fixed up from: 0x{:X} to 0x{:X}", + section.pointer_to_relocations, + section.pointer_to_relocations.wrapping_sub(adj_offset) + ); + section.pointer_to_relocations = + section.pointer_to_relocations.wrapping_sub(adj_offset); + } + } +} + /// Convert machine to str representation. Any case of "COFF_UNKNOWN" /// should be expected to change to a more specific value. pub fn machine_to_str(machine: u16) -> &'static str { diff --git a/third_party/rust/goblin/src/pe/mod.rs b/third_party/rust/goblin/src/pe/mod.rs index dd9c2c5dff03..3c8c3c3e4623 100644 --- a/third_party/rust/goblin/src/pe/mod.rs +++ b/third_party/rust/goblin/src/pe/mod.rs @@ -26,6 +26,7 @@ pub mod relocation; pub mod section_table; pub mod subsystem; pub mod symbol; +pub mod tls; pub mod utils; use crate::container; @@ -71,6 +72,8 @@ pub struct PE<'a> { pub libraries: Vec<&'a str>, /// Debug information, if any, contained in the PE header pub debug_data: Option>, + /// TLS information, if any, contained in the PE header + pub tls_data: Option>, /// Exception handling and stack unwind information, if any, contained in the PE header pub exception_data: Option>, /// Certificates present, if any, described by the Certificate Table @@ -106,6 +109,7 @@ impl<'a> PE<'a> { let mut import_data = None; let mut libraries = vec![]; let mut debug_data = None; + let mut tls_data = None; let mut exception_data = None; let mut certificates = Default::default(); let mut is_64 = false; @@ -216,6 +220,29 @@ impl<'a> PE<'a> { )?); } + if let Some(tls_table) = optional_header.data_directories.get_tls_table() { + tls_data = if is_64 { + tls::TlsData::parse_with_opts::( + bytes, + image_base, + tls_table, + §ions, + file_alignment, + opts, + )? + } else { + tls::TlsData::parse_with_opts::( + bytes, + image_base, + &tls_table, + §ions, + file_alignment, + opts, + )? + }; + debug!("tls data: {:#?}", tls_data); + } + if header.coff_header.machine == header::COFF_MACHINE_X86_64 { // currently only x86_64 is supported debug!("exception data: {:#?}", exception_data); @@ -275,6 +302,7 @@ impl<'a> PE<'a> { imports, libraries, debug_data, + tls_data, exception_data, certificates, }) @@ -467,6 +495,98 @@ impl<'a> ctx::TryIntoCtx for PE<'a> { } } +/// An analyzed TE binary +/// +/// A TE binary is a PE/PE32+ binary that has had it's header stripped and +/// re-formatted to the TE specification. This presents a challenge for +/// parsing, as all relative addresses (RVAs) are not updated to take this into +/// account, and are thus incorrect. The parsing of a TE must take this into +/// account by using the [header::TeHeader::stripped_size`] field of the TE +/// header to adjust the RVAs during parsing. +#[cfg(feature = "te")] +#[derive(Debug)] +pub struct TE<'a> { + /// The TE header + pub header: header::TeHeader, + /// A list of the sections in this TE binary + pub sections: Vec, + /// Debug information, contained in the PE header + pub debug_data: debug::DebugData<'a>, + /// The offset to apply to addresses not parsed by the TE parser + /// itself: [header::TeHeader::stripped_size] - size_of::<[header::TeHeader]>() + pub rva_offset: usize, +} + +#[cfg(feature = "te")] +impl<'a> TE<'a> { + /// Reads a TE binary from the underlying `bytes` + pub fn parse(bytes: &'a [u8]) -> error::Result { + let opts = &options::ParseOptions { + resolve_rva: false, + parse_attribute_certificates: false, + }; + + let mut offset = 0; + + // Parse the TE header and adjust the offsets + let header = header::TeHeader::parse(bytes, &mut offset)?; + let rva_offset = header.stripped_size as usize - core::mem::size_of::(); + + // Parse the sections and adjust the offsets + let sections = header.sections(bytes, &mut offset)?; + + // Parse the debug data. Must adjust offsets before parsing the image_debug_directory + let mut debug_data = debug::DebugData::default(); + debug_data.image_debug_directory = debug::ImageDebugDirectory::parse_with_opts( + bytes, + header.debug_dir, + §ions, + 0, + opts, + )?; + TE::fixup_debug_data(&mut debug_data, rva_offset as u32); + debug_data.codeview_pdb70_debug_info = debug::CodeviewPDB70DebugInfo::parse_with_opts( + bytes, + &debug_data.image_debug_directory, + opts, + )?; + + Ok(TE { + header, + sections, + debug_data, + rva_offset, + }) + } + + /// Adjust all addresses in the TE binary debug data. + fn fixup_debug_data(dd: &mut debug::DebugData, rva_offset: u32) { + debug!( + "ImageDebugDirectory address of raw data fixed up from: 0x{:X} to 0x{:X}", + dd.image_debug_directory.address_of_raw_data, + dd.image_debug_directory + .address_of_raw_data + .wrapping_sub(rva_offset), + ); + dd.image_debug_directory.address_of_raw_data = dd + .image_debug_directory + .address_of_raw_data + .wrapping_sub(rva_offset); + + debug!( + "ImageDebugDirectory pointer to raw data fixed up from: 0x{:X} to 0x{:X}", + dd.image_debug_directory.pointer_to_raw_data, + dd.image_debug_directory + .pointer_to_raw_data + .wrapping_sub(rva_offset), + ); + dd.image_debug_directory.pointer_to_raw_data = dd + .image_debug_directory + .pointer_to_raw_data + .wrapping_sub(rva_offset); + } +} + /// An analyzed COFF object #[derive(Debug)] pub struct Coff<'a> { diff --git a/third_party/rust/goblin/src/pe/tls.rs b/third_party/rust/goblin/src/pe/tls.rs new file mode 100644 index 000000000000..2369bb0e6f11 --- /dev/null +++ b/third_party/rust/goblin/src/pe/tls.rs @@ -0,0 +1,247 @@ +use crate::error; +use alloc::vec::Vec; +use scroll::{Pread, Pwrite, SizeWith}; + +use crate::pe::data_directories; +use crate::pe::options; +use crate::pe::section_table; +use crate::pe::utils; + +/// Represents the TLS directory `IMAGE_TLS_DIRECTORY64`. +#[repr(C)] +#[derive(Debug, PartialEq, Copy, Clone, Default, Pread, Pwrite, SizeWith)] +pub struct ImageTlsDirectory { + /// The starting address of the TLS raw data. + // NOTE: `u32` for 32-bit binaries, `u64` for 64-bit binaries. + pub start_address_of_raw_data: u64, + /// The ending address of the TLS raw data. + // NOTE: `u32` for 32-bit binaries, `u64` for 64-bit binaries. + pub end_address_of_raw_data: u64, + /// The address of the TLS index. + // NOTE: `u32` for 32-bit binaries, `u64` for 64-bit binaries. + pub address_of_index: u64, + /// The address of the TLS callback functions. + /// + /// Terminated by a null pointer. + // NOTE: `u32` for 32-bit binaries, `u64` for 64-bit binaries. + pub address_of_callbacks: u64, + /// The size of the zero fill. + pub size_of_zero_fill: u32, + /// The characteristics of the TLS. + pub characteristics: u32, +} + +/// TLS information. +#[derive(Debug, Clone, PartialEq, Default)] +pub struct TlsData<'a> { + /// TLS directory. + pub image_tls_directory: ImageTlsDirectory, + /// Raw data of the TLS. + pub raw_data: Option<&'a [u8]>, + /// TLS index. + pub slot: Option, + /// TLS callbacks. + pub callbacks: Vec, +} + +impl ImageTlsDirectory { + pub fn parse( + bytes: &[u8], + dd: data_directories::DataDirectory, + sections: &[section_table::SectionTable], + file_alignment: u32, + ) -> error::Result { + Self::parse_with_opts::( + bytes, + dd, + sections, + file_alignment, + &options::ParseOptions::default(), + ) + } + + pub fn parse_with_opts( + bytes: &[u8], + dd: data_directories::DataDirectory, + sections: &[section_table::SectionTable], + file_alignment: u32, + opts: &options::ParseOptions, + ) -> error::Result { + let rva = dd.virtual_address as usize; + let mut offset = + utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| { + error::Error::Malformed(format!( + "Cannot map ImageTlsDirectory rva {:#x} into offset", + rva + )) + })?; + + let is_64 = core::mem::size_of::() == 8; + + let start_address_of_raw_data = if is_64 { + bytes.gread_with::(&mut offset, scroll::LE)? + } else { + bytes.gread_with::(&mut offset, scroll::LE)? as u64 + }; + let end_address_of_raw_data = if is_64 { + bytes.gread_with::(&mut offset, scroll::LE)? + } else { + bytes.gread_with::(&mut offset, scroll::LE)? as u64 + }; + let address_of_index = if is_64 { + bytes.gread_with::(&mut offset, scroll::LE)? + } else { + bytes.gread_with::(&mut offset, scroll::LE)? as u64 + }; + let address_of_callbacks = if is_64 { + bytes.gread_with::(&mut offset, scroll::LE)? + } else { + bytes.gread_with::(&mut offset, scroll::LE)? as u64 + }; + let size_of_zero_fill = bytes.gread_with::(&mut offset, scroll::LE)?; + let characteristics = bytes.gread_with::(&mut offset, scroll::LE)?; + + let itd = Self { + start_address_of_raw_data, + end_address_of_raw_data, + address_of_index, + address_of_callbacks, + size_of_zero_fill, + characteristics, + }; + + Ok(itd) + } +} + +impl<'a> TlsData<'a> { + pub fn parse( + bytes: &'a [u8], + image_base: usize, + dd: &data_directories::DataDirectory, + sections: &[section_table::SectionTable], + file_alignment: u32, + ) -> error::Result> { + Self::parse_with_opts::( + bytes, + image_base, + dd, + sections, + file_alignment, + &options::ParseOptions::default(), + ) + } + + pub fn parse_with_opts( + bytes: &'a [u8], + image_base: usize, + dd: &data_directories::DataDirectory, + sections: &[section_table::SectionTable], + file_alignment: u32, + opts: &options::ParseOptions, + ) -> error::Result> { + let mut raw_data = None; + let mut slot = None; + let mut callbacks = Vec::new(); + + let is_64 = core::mem::size_of::() == 8; + + let itd = + ImageTlsDirectory::parse_with_opts::(bytes, *dd, sections, file_alignment, opts)?; + + // Parse the raw data if any + if itd.end_address_of_raw_data != 0 && itd.start_address_of_raw_data != 0 { + if itd.start_address_of_raw_data > itd.end_address_of_raw_data { + return Err(error::Error::Malformed(format!( + "tls start_address_of_raw_data ({:#x}) is greater than end_address_of_raw_data ({:#x})", + itd.start_address_of_raw_data, + itd.end_address_of_raw_data + ))); + } + + if (itd.start_address_of_raw_data as usize) < image_base { + return Err(error::Error::Malformed(format!( + "tls start_address_of_raw_data ({:#x}) is less than image base ({:#x})", + itd.start_address_of_raw_data, image_base + ))); + } + + // VA to RVA + let rva = itd.start_address_of_raw_data as usize - image_base; + let size = itd.end_address_of_raw_data - itd.start_address_of_raw_data; + let offset = + utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| { + error::Error::Malformed(format!( + "cannot map tls start_address_of_raw_data rva ({:#x}) into offset", + rva + )) + })?; + raw_data = Some(&bytes[offset..offset + size as usize]); + } + + // Parse the index if any + if itd.address_of_index != 0 { + if (itd.address_of_index as usize) < image_base { + return Err(error::Error::Malformed(format!( + "tls address_of_index ({:#x}) is less than image base ({:#x})", + itd.address_of_index, image_base + ))); + } + + // VA to RVA + let rva = itd.address_of_index as usize - image_base; + let offset = utils::find_offset(rva, sections, file_alignment, opts); + slot = offset.and_then(|x| bytes.pread_with::(x, scroll::LE).ok()); + } + + // Parse the callbacks if any + if itd.address_of_callbacks != 0 { + if (itd.address_of_callbacks as usize) < image_base { + return Err(error::Error::Malformed(format!( + "tls address_of_callbacks ({:#x}) is less than image base ({:#x})", + itd.address_of_callbacks, image_base + ))); + } + + // VA to RVA + let rva = itd.address_of_callbacks as usize - image_base; + let offset = + utils::find_offset(rva, sections, file_alignment, opts).ok_or_else(|| { + error::Error::Malformed(format!( + "cannot map tls address_of_callbacks rva ({:#x}) into offset", + rva + )) + })?; + let mut i = 0; + // Read the callbacks until we find a null terminator + loop { + let callback: u64 = if is_64 { + bytes.pread_with::(offset + i * 8, scroll::LE)? + } else { + bytes.pread_with::(offset + i * 4, scroll::LE)? as u64 + }; + if callback == 0 { + break; + } + // Each callback is an VA so convert it to RVA + let callback_rva = callback as usize - image_base; + // Check if the callback is in the image + if utils::find_offset(callback_rva, sections, file_alignment, opts).is_none() { + return Err(error::Error::Malformed(format!( + "cannot map tls callback ({:#x})", + callback + ))); + } + callbacks.push(callback); + i += 1; + } + } + + Ok(Some(TlsData { + image_tls_directory: itd, + raw_data, + slot, + callbacks, + })) + } +} diff --git a/third_party/rust/goblin/src/pe/utils.rs b/third_party/rust/goblin/src/pe/utils.rs index 289ccc529b85..d4d01726bf0f 100644 --- a/third_party/rust/goblin/src/pe/utils.rs +++ b/third_party/rust/goblin/src/pe/utils.rs @@ -64,6 +64,8 @@ fn section_read_size(section: §ion_table::SectionTable, file_alignment: u32) if virtual_size == 0 { read_size + } else if read_size == 0 { + virtual_size } else { cmp::min(read_size, round_size(virtual_size)) } diff --git a/third_party/rust/goblin/tests/bins/te/README.md b/third_party/rust/goblin/tests/bins/te/README.md new file mode 100644 index 000000000000..c60f263332a0 --- /dev/null +++ b/third_party/rust/goblin/tests/bins/te/README.md @@ -0,0 +1,24 @@ +# TE binaries + +Binaries located in this directory are precompiled PE32/PE32+ binaries using a +terse executable (TE) header as defined in the Platform Initialization (PI) +specification: [TE](https://uefi.org/specs/PI/1.8/V1_TE_Image.html#te-header). +These binaries were compiled using the +[EDK2](https://github.com/tianocore/edk2) build system. + +## test_image.te + +This binary is a simple Terse executable binary + +## test_image_loaded.bin + +This binary is the same as `test_image.te`, but it has been loaded by a loader, +meaning the sections have been placed in the expected address. Please note that +this particular binary has not been relocated, so no relocations have been +applied + +## test_image_relocated.bin + +This binary is the same as `test_image.te`, but it has been loaded by a loader, +meaning the sections have been placed in the expected address, and any any +relocations have been applied. diff --git a/third_party/rust/minidump-common/.cargo-checksum.json b/third_party/rust/minidump-common/.cargo-checksum.json index 47128563f7ad..46c2ec51eb5e 100644 --- a/third_party/rust/minidump-common/.cargo-checksum.json +++ b/third_party/rust/minidump-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3fe59b28a1e995925fd0d0a750787be30686e0ee5f93c0ff23ec5cdf9ef1ab87","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"4c2a1448aab9177fd5f033faaf704af7bb222bf0804079fd3cff90fa1df4b812","src/errors/linux.rs":"df743ac9478e39f8a577f4f10f2d1317babad7b7c0d26cdbba2ea6b5426f4126","src/errors/macos.rs":"4516aaeb7abf6209f5cd94e86a1e55a9675ef77262f52e3b2d5596fd4b858458","src/errors/mod.rs":"f224af66124fd31a040c8da11bbab7b7795b48e4edea76e01c1f4dee537ea38a","src/errors/windows.rs":"0567af7bfac3ae2a8dff418e10873d8a5bf15a8b8ac6892c5ffdab08ec3ac901","src/format.rs":"17daa7037ba9b4e8aa30a880975e883f618b3ff3ebb0b88a81313a895700fc6c","src/lib.rs":"0900c00594b3c386b86127055889006f0d7d0004b08455fadb0e60d55a469cab","src/traits.rs":"93127ad69a849325ed66a0626e0bdae05868488f81c539d35c71a7bfbb9e51ac","src/utils.rs":"6ab64a2fc39187903de0813d27db370cbeb57ba4984c6a993034829176bed4d7"},"package":"0cd8a9fb054833d2f402e82e256aeef544e595e45fe8fca2de6d03ed605f6647"} \ No newline at end of file +{"files":{"Cargo.toml":"9ae1d211e4d197c8a257a67d4f9436738aeccab960401283e6b5cf1f2e9c19d4","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"4c2a1448aab9177fd5f033faaf704af7bb222bf0804079fd3cff90fa1df4b812","src/errors/linux.rs":"df743ac9478e39f8a577f4f10f2d1317babad7b7c0d26cdbba2ea6b5426f4126","src/errors/macos.rs":"4516aaeb7abf6209f5cd94e86a1e55a9675ef77262f52e3b2d5596fd4b858458","src/errors/mod.rs":"f224af66124fd31a040c8da11bbab7b7795b48e4edea76e01c1f4dee537ea38a","src/errors/windows.rs":"0567af7bfac3ae2a8dff418e10873d8a5bf15a8b8ac6892c5ffdab08ec3ac901","src/format.rs":"db607fd726e74da5aa4be8e8458409e7238c8194db201b3a0cb09ab822b738d2","src/lib.rs":"0900c00594b3c386b86127055889006f0d7d0004b08455fadb0e60d55a469cab","src/traits.rs":"e78a0dbf496b73b4d904874475ebc621ef5912db47b04bb37d3b2100c82629d3","src/utils.rs":"6ab64a2fc39187903de0813d27db370cbeb57ba4984c6a993034829176bed4d7"},"package":"5273687f49325b3977f7d372a1bbe2e528694d18128de8dcac78d134448e83b4"} \ No newline at end of file diff --git a/third_party/rust/minidump-common/Cargo.toml b/third_party/rust/minidump-common/Cargo.toml index a6f89e0c0d97..064185b31b93 100644 --- a/third_party/rust/minidump-common/Cargo.toml +++ b/third_party/rust/minidump-common/Cargo.toml @@ -12,9 +12,10 @@ [package] edition = "2018" name = "minidump-common" -version = "0.22.1" +version = "0.24.0" authors = ["Ted Mielczarek "] build = false +autolib = false autobins = false autoexamples = false autotests = false diff --git a/third_party/rust/minidump-common/src/format.rs b/third_party/rust/minidump-common/src/format.rs index 3de259582135..b86add7dbbd8 100644 --- a/third_party/rust/minidump-common/src/format.rs +++ b/third_party/rust/minidump-common/src/format.rs @@ -323,6 +323,9 @@ pub enum MINIDUMP_STREAM_TYPE { /// The contents of /proc/self/limits from a Linux system MozLinuxLimits = 0x4d7a0003, + + /// Soft errors reported during minidump generation + MozSoftErrors = 0x4d7a0004, } impl From for u32 { @@ -470,7 +473,7 @@ pub struct CV_INFO_PDB20 { pub pdb_file_name: Vec, } -impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_PDB20 { +impl scroll::ctx::TryFromCtx<'_, Endian> for CV_INFO_PDB20 { type Error = scroll::Error; fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -506,7 +509,7 @@ pub struct CV_INFO_PDB70 { pub pdb_file_name: Vec, } -impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for CV_INFO_PDB70 { +impl scroll::ctx::TryFromCtx<'_, Endian> for CV_INFO_PDB70 { type Error = scroll::Error; fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> { @@ -1742,7 +1745,7 @@ pub struct XstateFeatureIter<'a> { idx: usize, } -impl<'a> Iterator for XstateFeatureIter<'a> { +impl Iterator for XstateFeatureIter<'_> { type Item = (usize, XSTATE_FEATURE); fn next(&mut self) -> Option { while self.idx < self.info.features.len() { @@ -2055,7 +2058,7 @@ pub struct MINIDUMP_UTF8_STRING { pub buffer: Vec, } -impl<'a> scroll::ctx::TryFromCtx<'a, Endian> for MINIDUMP_UTF8_STRING { +impl scroll::ctx::TryFromCtx<'_, Endian> for MINIDUMP_UTF8_STRING { type Error = scroll::Error; fn try_from_ctx(src: &[u8], endian: Endian) -> Result<(Self, usize), Self::Error> { diff --git a/third_party/rust/minidump-common/src/traits.rs b/third_party/rust/minidump-common/src/traits.rs index 33de6b846804..3e1e047e4fdb 100644 --- a/third_party/rust/minidump-common/src/traits.rs +++ b/third_party/rust/minidump-common/src/traits.rs @@ -39,7 +39,7 @@ pub trait Module { /// Implement Module for 2-tuples of (&str, DebugId) for convenience. /// `breakpad-symbols`' `Symbolizer::get_symbol_at_address` uses this. -impl<'a> Module for (&'a str, DebugId) { +impl Module for (&str, DebugId) { fn base_address(&self) -> u64 { 0 } diff --git a/third_party/rust/minidump-unwind/.cargo-checksum.json b/third_party/rust/minidump-unwind/.cargo-checksum.json index 289dfd799f6d..7560f30025fa 100644 --- a/third_party/rust/minidump-unwind/.cargo-checksum.json +++ b/third_party/rust/minidump-unwind/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ec7d84e19cbefba8024be68cc043fc067d1efca8739db4e449b04677b113d500","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"0202d4bced7cbc5fb801a916d11c752019111a0043fb6476ef945414d322588e","src/amd64.rs":"c05bfdb7479ba5e2d3ba942b75e66e38784b2fe7deef5045344db43d438bb9c8","src/amd64_unittest.rs":"9a0aea53f153201bd8ffcfec215966be671098de508ce1429d4536402893c0d5","src/arm.rs":"a61b28eabf8c72ea7d16911426c6bbab4e08766ca43e75099d0cd7817e02a977","src/arm64.rs":"c8233f255b64d116ea804a0fe15a4ee0211124f9434d0125a957d267ab6ea3c2","src/arm64_old.rs":"78843e9a46e3ce5f461a19d63445fd1b2aac7f4e6d91aac0f3b9e352b958606c","src/arm64_unittest.rs":"d48d7577422aa53bb041bc243e866d369bdc57fd1219ebe7f7032b9bfedfc1dc","src/arm_unittest.rs":"b2e64e57ed638c228d41ecf35ea57f0a6f9ca007a5288bc63a779fa759548c50","src/lib.rs":"77e4267e6c91195e848f0cddca1ad1b3e564c950d21781a835de3540a6bee7f5","src/mips.rs":"897aa10ade29adc4253bb2049b19a7e1690bf548ce015ba63eba1f8bcc04361c","src/symbols/debuginfo.rs":"c857a28410ac09b5ced5be21ff593ab5348478395e24addbbbfa873cafc60283","src/symbols/mod.rs":"a598e48bf2ef657e7c833f7f2d3950a10c68483e71b98f136c7975baba9ad238","src/system_info.rs":"228ac55b18a647e5302b5cb7c10e65c9d046decb5d9207e4ded098405bf1739c","src/x86.rs":"fab7ccec6285a9970da7f13709b8e7e53b1198ca275235e4bd415a620d87197e","src/x86_unittest.rs":"73212f5b1c2ce4605e540230c5574de817e42e0447ffe304b8822b69066aa7c8"},"package":"efde3c09258c297c0f6761f04d97771ef82a59a6734e7ba0e6e2ef961fb3cbb3"} \ No newline at end of file +{"files":{"Cargo.toml":"343d32b03896ac26322b052dc1b4b068af995593b696ad12b0b296f1ee64b3f7","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"0202d4bced7cbc5fb801a916d11c752019111a0043fb6476ef945414d322588e","src/amd64.rs":"c05bfdb7479ba5e2d3ba942b75e66e38784b2fe7deef5045344db43d438bb9c8","src/amd64_unittest.rs":"9a0aea53f153201bd8ffcfec215966be671098de508ce1429d4536402893c0d5","src/arm.rs":"a61b28eabf8c72ea7d16911426c6bbab4e08766ca43e75099d0cd7817e02a977","src/arm64.rs":"c8233f255b64d116ea804a0fe15a4ee0211124f9434d0125a957d267ab6ea3c2","src/arm64_old.rs":"78843e9a46e3ce5f461a19d63445fd1b2aac7f4e6d91aac0f3b9e352b958606c","src/arm64_unittest.rs":"d48d7577422aa53bb041bc243e866d369bdc57fd1219ebe7f7032b9bfedfc1dc","src/arm_unittest.rs":"b2e64e57ed638c228d41ecf35ea57f0a6f9ca007a5288bc63a779fa759548c50","src/lib.rs":"77e4267e6c91195e848f0cddca1ad1b3e564c950d21781a835de3540a6bee7f5","src/mips.rs":"897aa10ade29adc4253bb2049b19a7e1690bf548ce015ba63eba1f8bcc04361c","src/symbols/debuginfo.rs":"4301681af1a4cb1e52ed100654ec298cf74fe16e20f14256e45ba460424f580b","src/symbols/mod.rs":"a598e48bf2ef657e7c833f7f2d3950a10c68483e71b98f136c7975baba9ad238","src/system_info.rs":"228ac55b18a647e5302b5cb7c10e65c9d046decb5d9207e4ded098405bf1739c","src/x86.rs":"fab7ccec6285a9970da7f13709b8e7e53b1198ca275235e4bd415a620d87197e","src/x86_unittest.rs":"73212f5b1c2ce4605e540230c5574de817e42e0447ffe304b8822b69066aa7c8"},"package":"c30454f5703c77433b4059bf5e196266b800b14223c55793ee636e49c8f9160e"} \ No newline at end of file diff --git a/third_party/rust/minidump-unwind/Cargo.toml b/third_party/rust/minidump-unwind/Cargo.toml index 1214ff2f4e4e..4d924c6ec0be 100644 --- a/third_party/rust/minidump-unwind/Cargo.toml +++ b/third_party/rust/minidump-unwind/Cargo.toml @@ -12,9 +12,10 @@ [package] edition = "2018" name = "minidump-unwind" -version = "0.22.1" +version = "0.24.0" authors = ["Alex Franchuk "] build = false +autolib = false autobins = false autoexamples = false autotests = false @@ -37,14 +38,14 @@ path = "src/lib.rs" version = "0.1.52" [dependencies.breakpad-symbols] -version = "0.22.1" +version = "0.24.0" [dependencies.cachemap2] version = "0.3.0" optional = true [dependencies.framehop] -version = "0.12" +version = "0.13" optional = true [dependencies.futures-util] @@ -56,10 +57,10 @@ version = "0.9" optional = true [dependencies.minidump] -version = "0.22.1" +version = "0.24.0" [dependencies.minidump-common] -version = "0.22.1" +version = "0.24.0" [dependencies.object] version = "0.36" diff --git a/third_party/rust/minidump-unwind/src/symbols/debuginfo.rs b/third_party/rust/minidump-unwind/src/symbols/debuginfo.rs index 0a72d325487c..25cfc7978774 100644 --- a/third_party/rust/minidump-unwind/src/symbols/debuginfo.rs +++ b/third_party/rust/minidump-unwind/src/symbols/debuginfo.rs @@ -301,7 +301,7 @@ mod object_section_info { #[repr(transparent)] pub struct ObjectSectionInfo<'a, O>(pub &'a O); - impl<'a, O> std::ops::Deref for ObjectSectionInfo<'a, O> { + impl std::ops::Deref for ObjectSectionInfo<'_, O> { type Target = O; fn deref(&self) -> &Self::Target { diff --git a/third_party/rust/minidump-writer/.cargo-checksum.json b/third_party/rust/minidump-writer/.cargo-checksum.json index bdb271ac8d2e..61a81cd6f08c 100644 --- a/third_party/rust/minidump-writer/.cargo-checksum.json +++ b/third_party/rust/minidump-writer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"de5a20a4e18f39ebe3c25cbd484639b5c4d8c55da1ed323d9661f04b97c36e4e","Cargo.lock":"ef50600e4a895edb2613179dc5d6a883fb44858b48a3ce784c40c572e0613af4","Cargo.toml":"46c59cf4e6a9616d45e76529a535e10990ee441bb4f1c038a8553fc8ec04076f","LICENSE":"1ecdd8e8977af83c07c5f97bec87b47d27059b7ea323ca3160fbfa2314f5d99c","README.md":"71742b170ac34ceecf317d6d69456063bf5d8974453075e9cd2838785717fcdb","build.rs":"689cd32a441f5011f694a9f86bc03bc27c2a09bcb4130f47e04fe00bb069b1b5","deny.toml":"d577f092e50e1a99829a6bd7a3e74fbca4c9acd677323da23126a0e1738d2d76","examples/synthetic.rs":"cd13bd0bba64a1d8c8c326bb1ce1818bead6904e5708418fd09edeaef1437c24","release.toml":"f554067378aec602383b96e5fa63427136533a7dd00137fd0664b279fb8fcc56","src/bin/test.rs":"11cf3df44cfa4975e1d10df2c833e6cad91807ff9d0bf5f80fcde1d6b94d79ed","src/dir_section.rs":"b7c83b16acefb4327b406612e1a667dffb91f86bec40f9330171dba8d10346ff","src/lib.rs":"6f393273ea6b354f412e70c9a4925fe2e646bc477591962c96a61aed9fde4e3b","src/linux.rs":"e57979dac2a75557925188e5f9bbd4d7462034c9e93e05ec4da24f5f2750560a","src/linux/android.rs":"1cb8a70601dba78cf48aa06388a3b5c34cd1da6c0bd8099c6326e41310455e3c","src/linux/app_memory.rs":"5f093e4ed0aecc6086366a9c09658761fdd3b0e6e9ff2111690719e56612df64","src/linux/auxv/mod.rs":"bfa027ea8db877f698c2cfd06f76bd7026db33023ee56453ca8e0f454c5ce231","src/linux/auxv/reader.rs":"9b21cdc85674b1a6aaf4408202ea1da1de8d64d58c8635d2889d9738971cab3d","src/linux/crash_context.rs":"069d949c7a9fc23a1e8710f7c018cacf71af2326a2dd6ca0283d492c5253107a","src/linux/crash_context/aarch64.rs":"158d02200b25a7ca029ff5132ba3b7f76a05c9976ff529a5658523aff370e4d2","src/linux/crash_context/arm.rs":"a4f41aae015937d3dccdf759df84bc657cf457d8baaf07711617d17f4b40f6f1","src/linux/crash_context/x86.rs":"d464680ee9df8a7f11dae2bb199cc4efb66dfc790a87c9b773c3a9b44b9339d8","src/linux/crash_context/x86_64.rs":"dceabbcf4d3c4ff5ad7658daa7dec3349cad9b61091385bcd868de6b11eb4957","src/linux/dso_debug.rs":"fe68638cbbf32e7c58777315954ff6bcdecb16c1f2819656511b93ab4a377c4c","src/linux/dumper_cpu_info.rs":"76558ffc85386e416bbfc49adc550f61fb206dfbfb0b6a25f620a5fc91f32bc1","src/linux/dumper_cpu_info/arm.rs":"6fc140181f3a32504c3b66f0235136e730424be830602c87cfbeb1dfb4c1cec3","src/linux/dumper_cpu_info/x86_mips.rs":"181a16ae60f82d15901945b7b586b98a6af23e8a4da27acaad2e25f03330209e","src/linux/errors.rs":"4c82e5ae0659e0030784cd6923610509cb7f3f679ce775b08464ddbb3761562f","src/linux/maps_reader.rs":"dcdeb068bcca025c2337be610f479bf324dbd041e50161b35e9ca3d5adea9ec6","src/linux/mem_reader.rs":"59acd30cad931288cc6415ffcc452827425dc3a7a7af349f9859c8749d0548f2","src/linux/minidump_writer.rs":"bc984dc14a4844b13b47b380e0225cdb323b3e562a6e7f49da7569b2f86ac550","src/linux/module_reader.rs":"1b46a8bac323c5eee16d642d9023518625af20a36ad84d8cc1e7eea629405d8b","src/linux/ptrace_dumper.rs":"5ff7c0408a317e1cb2d62d4fe232faf41771516ebf334523924d4a73de50e56f","src/linux/sections.rs":"98aabd7e4b0542201783af90cafdc66bb3845585d0ed24af7476c1ea3ab40fb9","src/linux/sections/app_memory.rs":"079d64591045704dc99a8e653eb820f1b730fdfb68f3c44fd54c6823fcc0842e","src/linux/sections/exception_stream.rs":"e1b73b5168506f8804479206ef0941aca5f792500cc56c5c17db55cd6b273a99","src/linux/sections/handle_data_stream.rs":"3aae030c009543142555d493f9273e3445454b18085dfdb3b44bc83d43b510dd","src/linux/sections/mappings.rs":"acab4f11a2057bd6676888bae169054593d5e100e5d317084babe7d043e73bf0","src/linux/sections/memory_info_list_stream.rs":"bd927824e859e2fcbc85ef9d5e3d8b7be13c4918a636f70f0712070d6c65b002","src/linux/sections/memory_list_stream.rs":"f2d5b33fb4167b502dc8e74371d50b4ad66e0b48f541fe16bcbf5fb62491bf2d","src/linux/sections/systeminfo_stream.rs":"02373c97d4caeb66f4601c066d430ad2929b5584eaa0af3be1dc51ef818e5cb8","src/linux/sections/thread_list_stream.rs":"c7aaeb7f8f8cec3403fd6a5f6a78768a586b999e373e5a741f061499b2baf5a2","src/linux/sections/thread_names_stream.rs":"2a123335626e941cf0a3349f9327c3e7606af593a8370ef5f71325012107b91f","src/linux/thread_info.rs":"7c6ccf00433cf9a2b061fdbb7bd17131c04130d3149077ddfa5fc2bdce291391","src/linux/thread_info/aarch64.rs":"f3fd7c2b3bd332791d7e8003f7a74cac79433d3482ac3aadd467f04e76cebb3b","src/linux/thread_info/arm.rs":"b4fca145d47d93033aea5a0a3dd981cd3c5c9ce0a0e1d4d23013d068d83e5972","src/linux/thread_info/mips.rs":"535b9924e96cb4067c4aae9034e32cf8dd3957e0bc45f8d9ab66fa34586a7c57","src/linux/thread_info/x86.rs":"9b74e80cde0271a963705209f1a3d5042a2735136829133a26b64641a0e16f11","src/mac.rs":"4671ad90c433db559ec633c880c3fe083f38a2e185ef4fc99577318526076519","src/mac/errors.rs":"696473d1187a0f003409e3ac0fc83a02cafbad8451a62bda868b08acc36e7443","src/mac/mach.rs":"f5f5b3bde9fd3ea85903b75c80ddb15931a56d5d4425f01fda9643fba8e419d3","src/mac/minidump_writer.rs":"d6f07685779c45f6b773d4163965f5dc5e0a73421937d9ec6b8e4d3320d23e85","src/mac/streams.rs":"82e1b9fefa26d98f1c0efdd98de0aed9a9ee9edf3e4b4f636212c73f8d3e464e","src/mac/streams/breakpad_info.rs":"9aafbc3f376050e39a2295e77a1b764223403ffdd47bded39efa9450a53b5a06","src/mac/streams/exception.rs":"6ad730ff0fbba4ec8a7c8576effb737138ca92e0f676eeff5d8e3c47d20a1434","src/mac/streams/memory_list.rs":"e507a1ada858ef535e3e211d91195901e9976ba0ff6cf601919d7cacb48c5e9f","src/mac/streams/misc_info.rs":"ed9fe394ded145cae62094adf3a9e454e23bfd5b6fab7871f0cf62c6a5e79017","src/mac/streams/module_list.rs":"959239425c1ea4c9766303fd10a12c82d1fed27b462f836a8a317a470ea0ace7","src/mac/streams/system_info.rs":"4bd0d171c9d7c97afbacf6fd144d5554f0e46d47ae78f00b85331d6d1a1d24b3","src/mac/streams/thread_list.rs":"2b003e3409daebbd38ebc8a49a2c24e7a75b296d28f58a2c85114cf611174c1b","src/mac/streams/thread_names.rs":"cc1464c2610e6022046b5322d9b48a72a6b5d35923d75afd7aa4b82d355c7dc4","src/mac/task_dumper.rs":"b22f42b11bb7e9af5976ec04cbf9f8bf4d1d70c3c7738b1072e7bd41e8d5af3c","src/mem_writer.rs":"44d594e4b8a4bedf28c61f89c34f13be42deb9a8820a1d3267dd9572d65d0c97","src/minidump_cpu.rs":"ccb3dc179699159883e539e29285f8f6ba936afb8ce8980dbcb5060a80b6618c","src/minidump_format.rs":"9d5940d71da3a543efa90279e287e0dbbe303de386a4d5aab15e8ccfdd556116","src/windows.rs":"7aae8747519b203f1889c369cb1122ff308d255e9514cf9d4d3f09257a3bb96c","src/windows/errors.rs":"9b8752122784417ed48b9c3fccc9bdabc6c4e6285cdb77c79723cba56cb0de82","src/windows/ffi.rs":"24a6f99de9f25ae7bc80f2763d8c5b97e65699682a99ec6265ebc435c3310999","src/windows/minidump_writer.rs":"fbbb576161f753d9572c5e8c78a85066070948917e0ee2c111e63f3fc14fd5d3","tests/common/mod.rs":"8d1f0110b74e7a31231d3767731070a345e95672945ff602b161f5fa5f355e0d","tests/linux_minidump_writer.rs":"b4f07a835b563171a5d138b1341624516d18fdf3201be07f05ffd23d42c73c7e","tests/mac_minidump_writer.rs":"355e28635e9f8ccc831627e3323fe37907915047cd525f07eefd15d658cf4823","tests/ptrace_dumper.rs":"8f65bc2a1c82ac6a60f65bae336e0a8c8655c591a983c698ba50b14a2f54fe19","tests/task_dumper.rs":"3881899e4cfef0dae772d16b1a783497eebd2b58025394e0819cb03a0960d480","tests/windows_minidump_writer.rs":"138551179c4e610141d56ba99305a0fc05531c8e9924805dd071d380338f0f74"},"package":"1c75ff36a030d76801ed7ec3ea4ae45f12c0f1297f3447790288194274e9aa98"} \ No newline at end of file +{"files":{"CHANGELOG.md":"a381394c4873e8fa1459cd68cb7036a7b3d0798a7416919002354c95b2dba782","Cargo.lock":"0f5e2031583176b62b48c4f5a27fef6dd561ace42d15ad03b22cf20ce4e6ba0e","Cargo.toml":"82ea1b9e0080a89f3c2a2be21e7dca085c34f200ba95a4f9e284cab65b4cd821","LICENSE":"1ecdd8e8977af83c07c5f97bec87b47d27059b7ea323ca3160fbfa2314f5d99c","README.md":"71742b170ac34ceecf317d6d69456063bf5d8974453075e9cd2838785717fcdb","build.rs":"689cd32a441f5011f694a9f86bc03bc27c2a09bcb4130f47e04fe00bb069b1b5","deny.toml":"764229c5a5619e336675a4c512b0a2830e2173681c7026d376980ebd75569d04","examples/synthetic.rs":"cd13bd0bba64a1d8c8c326bb1ce1818bead6904e5708418fd09edeaef1437c24","release.toml":"f554067378aec602383b96e5fa63427136533a7dd00137fd0664b279fb8fcc56","src/bin/test.rs":"b92e7a9091584bce2f40f90c289d04218efcb32e4a31911612b8392dfb38a2c2","src/dir_section.rs":"5386b73683fda9a3bf19fc656071d3ec7b4248284dc26ca3b8cbfdfc61d3726a","src/lib.rs":"c5585d46d0f2b72bda0f90aa748ef5ae522e7f7fea4c6f1b0ac01ffce8630e44","src/linux.rs":"7f4141364082b0bd2bfb2ff1a59acec7989d33f44b39c69ebb36e26c959de1ac","src/linux/android.rs":"1cb8a70601dba78cf48aa06388a3b5c34cd1da6c0bd8099c6326e41310455e3c","src/linux/app_memory.rs":"5f093e4ed0aecc6086366a9c09658761fdd3b0e6e9ff2111690719e56612df64","src/linux/auxv/mod.rs":"b5a9a5d7e3ef46847ddbb86c191bdafcf531ddf75d802fa71cf4ad88deb9c8d7","src/linux/auxv/reader.rs":"9b21cdc85674b1a6aaf4408202ea1da1de8d64d58c8635d2889d9738971cab3d","src/linux/crash_context.rs":"069d949c7a9fc23a1e8710f7c018cacf71af2326a2dd6ca0283d492c5253107a","src/linux/crash_context/aarch64.rs":"158d02200b25a7ca029ff5132ba3b7f76a05c9976ff529a5658523aff370e4d2","src/linux/crash_context/arm.rs":"a4f41aae015937d3dccdf759df84bc657cf457d8baaf07711617d17f4b40f6f1","src/linux/crash_context/x86.rs":"d464680ee9df8a7f11dae2bb199cc4efb66dfc790a87c9b773c3a9b44b9339d8","src/linux/crash_context/x86_64.rs":"dceabbcf4d3c4ff5ad7658daa7dec3349cad9b61091385bcd868de6b11eb4957","src/linux/dso_debug.rs":"fe68638cbbf32e7c58777315954ff6bcdecb16c1f2819656511b93ab4a377c4c","src/linux/dumper_cpu_info.rs":"76558ffc85386e416bbfc49adc550f61fb206dfbfb0b6a25f620a5fc91f32bc1","src/linux/dumper_cpu_info/arm.rs":"6fc140181f3a32504c3b66f0235136e730424be830602c87cfbeb1dfb4c1cec3","src/linux/dumper_cpu_info/x86_mips.rs":"230f6e1c36c66efa979fd0bc909d3e50e62139b48e9259ce9249016f58d83c68","src/linux/errors.rs":"c9c7e3e1edb1c4ff7939ef7427b48ad1ef70c28f0a0b2c959f251c86933d3543","src/linux/maps_reader.rs":"1c98f73004fe4f426aadee926d7e16be61059e2e9d23b6bf62de8fd2069b36e1","src/linux/mem_reader.rs":"4b77fcb9c72b1ac2d12d4e59ba9edacf3ff03b9c8fbc067b31311f1c644c94dc","src/linux/minidump_writer.rs":"f7fc9b8d62c12fc775a44260556fd1f66e33e0228b49a218233c8abbcf88e0da","src/linux/module_reader.rs":"0887aea253cbe5886e6634c1086104720b1dfc01c14fa903258e35976c6ccd0d","src/linux/ptrace_dumper.rs":"0783b18f5abbd6ef398b1abd5bb323ceb395cacb1c743f96504c538344ba6ea8","src/linux/sections.rs":"98aabd7e4b0542201783af90cafdc66bb3845585d0ed24af7476c1ea3ab40fb9","src/linux/sections/app_memory.rs":"079d64591045704dc99a8e653eb820f1b730fdfb68f3c44fd54c6823fcc0842e","src/linux/sections/exception_stream.rs":"e1b73b5168506f8804479206ef0941aca5f792500cc56c5c17db55cd6b273a99","src/linux/sections/handle_data_stream.rs":"3aae030c009543142555d493f9273e3445454b18085dfdb3b44bc83d43b510dd","src/linux/sections/mappings.rs":"acab4f11a2057bd6676888bae169054593d5e100e5d317084babe7d043e73bf0","src/linux/sections/memory_info_list_stream.rs":"bd927824e859e2fcbc85ef9d5e3d8b7be13c4918a636f70f0712070d6c65b002","src/linux/sections/memory_list_stream.rs":"f2d5b33fb4167b502dc8e74371d50b4ad66e0b48f541fe16bcbf5fb62491bf2d","src/linux/sections/systeminfo_stream.rs":"2d6e6727564d7c112efdcc68b9e9587da21e05e6a88318bb7e24152452b7eb66","src/linux/sections/thread_list_stream.rs":"c7aaeb7f8f8cec3403fd6a5f6a78768a586b999e373e5a741f061499b2baf5a2","src/linux/sections/thread_names_stream.rs":"2a123335626e941cf0a3349f9327c3e7606af593a8370ef5f71325012107b91f","src/linux/serializers.rs":"f3ab10498cdb577ec6c15e39111b4f4faf9e8cecc8895eff9f601bfae3065b99","src/linux/thread_info.rs":"7c6ccf00433cf9a2b061fdbb7bd17131c04130d3149077ddfa5fc2bdce291391","src/linux/thread_info/aarch64.rs":"f3fd7c2b3bd332791d7e8003f7a74cac79433d3482ac3aadd467f04e76cebb3b","src/linux/thread_info/arm.rs":"b4fca145d47d93033aea5a0a3dd981cd3c5c9ce0a0e1d4d23013d068d83e5972","src/linux/thread_info/mips.rs":"535b9924e96cb4067c4aae9034e32cf8dd3957e0bc45f8d9ab66fa34586a7c57","src/linux/thread_info/x86.rs":"9b74e80cde0271a963705209f1a3d5042a2735136829133a26b64641a0e16f11","src/mac.rs":"4671ad90c433db559ec633c880c3fe083f38a2e185ef4fc99577318526076519","src/mac/errors.rs":"696473d1187a0f003409e3ac0fc83a02cafbad8451a62bda868b08acc36e7443","src/mac/mach.rs":"f5f5b3bde9fd3ea85903b75c80ddb15931a56d5d4425f01fda9643fba8e419d3","src/mac/minidump_writer.rs":"d6f07685779c45f6b773d4163965f5dc5e0a73421937d9ec6b8e4d3320d23e85","src/mac/streams.rs":"82e1b9fefa26d98f1c0efdd98de0aed9a9ee9edf3e4b4f636212c73f8d3e464e","src/mac/streams/breakpad_info.rs":"9aafbc3f376050e39a2295e77a1b764223403ffdd47bded39efa9450a53b5a06","src/mac/streams/exception.rs":"6ad730ff0fbba4ec8a7c8576effb737138ca92e0f676eeff5d8e3c47d20a1434","src/mac/streams/memory_list.rs":"e507a1ada858ef535e3e211d91195901e9976ba0ff6cf601919d7cacb48c5e9f","src/mac/streams/misc_info.rs":"ed9fe394ded145cae62094adf3a9e454e23bfd5b6fab7871f0cf62c6a5e79017","src/mac/streams/module_list.rs":"959239425c1ea4c9766303fd10a12c82d1fed27b462f836a8a317a470ea0ace7","src/mac/streams/system_info.rs":"4bd0d171c9d7c97afbacf6fd144d5554f0e46d47ae78f00b85331d6d1a1d24b3","src/mac/streams/thread_list.rs":"2b003e3409daebbd38ebc8a49a2c24e7a75b296d28f58a2c85114cf611174c1b","src/mac/streams/thread_names.rs":"cc1464c2610e6022046b5322d9b48a72a6b5d35923d75afd7aa4b82d355c7dc4","src/mac/task_dumper.rs":"b22f42b11bb7e9af5976ec04cbf9f8bf4d1d70c3c7738b1072e7bd41e8d5af3c","src/mem_writer.rs":"49995b0fca6cc48a8bf47dc8d738d5ee5afbcedea926b0dcba331e6a2b976eb9","src/minidump_cpu.rs":"ccb3dc179699159883e539e29285f8f6ba936afb8ce8980dbcb5060a80b6618c","src/minidump_format.rs":"9d5940d71da3a543efa90279e287e0dbbe303de386a4d5aab15e8ccfdd556116","src/serializers.rs":"7a49ed8dcefa7ddf1f796f9ef9360c6539ef57c80712b237af612275ef70ce83","src/windows.rs":"7aae8747519b203f1889c369cb1122ff308d255e9514cf9d4d3f09257a3bb96c","src/windows/errors.rs":"9b8752122784417ed48b9c3fccc9bdabc6c4e6285cdb77c79723cba56cb0de82","src/windows/ffi.rs":"24a6f99de9f25ae7bc80f2763d8c5b97e65699682a99ec6265ebc435c3310999","src/windows/minidump_writer.rs":"fbbb576161f753d9572c5e8c78a85066070948917e0ee2c111e63f3fc14fd5d3","tests/common/mod.rs":"03af616535a9c159a8b96ce7d37160c95de84fc20b55cc3767eb373037ce8639","tests/linux_minidump_writer.rs":"38b742c40dd68767f7b71835717a5c7b7846bc70a7bdda94eb4e7efccd7c4311","tests/linux_minidump_writer_soft_error.rs":"ebff083d417fe9d36c0d45e8e0c1225530dc2730dbdcdfbae7799f0c2e5f7ddc","tests/mac_minidump_writer.rs":"e7d1f276f9a958f1990432514a652160d39f089f7115988c85b0a324e091ca49","tests/ptrace_dumper.rs":"c08df136fcdec61c61f28afae07136d98e786a5f23cf6747cbb30f9f1a359312","tests/task_dumper.rs":"3881899e4cfef0dae772d16b1a783497eebd2b58025394e0819cb03a0960d480","tests/windows_minidump_writer.rs":"138551179c4e610141d56ba99305a0fc05531c8e9924805dd071d380338f0f74"},"package":"6e9370e1f326cb4385f78355d8a0f68f429e9002fd3ca53fff9b43fded234473"} \ No newline at end of file diff --git a/third_party/rust/minidump-writer/CHANGELOG.md b/third_party/rust/minidump-writer/CHANGELOG.md index f26bff836f04..3e603d02bca2 100644 --- a/third_party/rust/minidump-writer/CHANGELOG.md +++ b/third_party/rust/minidump-writer/CHANGELOG.md @@ -8,6 +8,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] - ReleaseDate +## [0.10.2] - 2025-02-03 +### Added +- [PR#143](https://github.com/rust-minidump/minidump-writer/pull/143) + - turn many errors that are currently treated as critical (and thus prevent minidump generation) into non-critical "soft" errors + - collect non-critical errors and serialize them into a new JSON stream in the minidump + +### Changed +- [PR#145](https://github.com/rust-minidump/minidump-writer/pull/145) updated dependencies. + ## [0.10.1] - 2024-09-20 ### Fixed - [PR#129](https://github.com/rust-minidump/minidump-writer/pull/129) added checking of additions to ensure invalid memory offsets are gracefully handled. @@ -157,7 +166,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Initial release, including basic support for `x86_64-unknown-linux-gnu/musl` and `x86_64-pc-windows-msvc` -[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.10.1...HEAD +[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.10.2...HEAD +[0.10.2]: https://github.com/rust-minidump/minidump-writer/compare/0.10.1...0.10.2 [0.10.1]: https://github.com/rust-minidump/minidump-writer/compare/0.10.0...0.10.1 [0.10.0]: https://github.com/rust-minidump/minidump-writer/compare/0.9.0...0.10.0 [0.9.0]: https://github.com/rust-minidump/minidump-writer/compare/0.8.9...0.9.0 diff --git a/third_party/rust/minidump-writer/Cargo.lock b/third_party/rust/minidump-writer/Cargo.lock index f58e7f26c22f..4288e11550e2 100644 --- a/third_party/rust/minidump-writer/Cargo.lock +++ b/third_party/rust/minidump-writer/Cargo.lock @@ -1,15 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli 0.29.0", -] +version = 4 [[package]] name = "addr2line" @@ -22,10 +13,19 @@ dependencies = [ ] [[package]] -name = "adler" -version = "1.0.2" +name = "addr2line" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli 0.31.1", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "ahash" @@ -36,7 +36,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -65,36 +65,36 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -107,9 +107,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", @@ -118,23 +118,23 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "addr2line 0.22.0", - "cc", + "addr2line 0.24.2", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -157,9 +157,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -172,9 +175,9 @@ dependencies = [ [[package]] name = "breakpad-symbols" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e1ad3f5e2e5c8a42fccedd6792cc05968b39b69c3fe7b5544072ac052f3fe85" +checksum = "05cc04995b4f6f26dc9cc5989e93e42c373def047b4b057aaf8f48400b971d1e" dependencies = [ "async-trait", "cachemap2", @@ -184,15 +187,15 @@ dependencies = [ "minidump-common", "nom", "range-map", - "thiserror", + "thiserror 1.0.69", "tracing", ] [[package]] name = "brotli" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -220,9 +223,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata", @@ -243,9 +246,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cab" @@ -267,9 +270,9 @@ checksum = "68ccbd3153aa153b2f5eff557537ffce81e4dd6c50ae0eddc41dc8d0c388436f" [[package]] name = "cc" -version = "1.1.13" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "jobserver", "libc", @@ -296,14 +299,14 @@ checksum = "b0fc239e0f6cb375d2402d48afb92f76f5404fd1df208a41930ec81eda078bea" [[package]] name = "console" -version = "0.15.8" +version = "0.15.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] @@ -324,18 +327,18 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -390,18 +393,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -418,18 +421,18 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" @@ -468,9 +471,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", @@ -519,25 +522,19 @@ dependencies = [ "syn", ] -[[package]] -name = "dmsort" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" - [[package]] name = "dump_syms" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f422400fd108f0bae551b7f81093d86712926d94376f70f0b679c2ac3a54e7c" +checksum = "70f4c4681ed7bec47acf654be525d45b7bda126d5e15104a514af4d860ae15e4" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags 2.8.0", "cab", "crossbeam", "dirs", - "goblin", - "hashbrown", + "goblin 0.8.2", + "hashbrown 0.14.5", "log", "lzma-rs", "num_cpus", @@ -577,15 +574,15 @@ dependencies = [ [[package]] name = "encode_unicode" -version = "0.3.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -598,12 +595,30 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "error-graph" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b920e777967421aa5f9bf34f842c0ab6ba19b3bdb4a082946093860f5858879" +dependencies = [ + "serde", +] + +[[package]] +name = "failspot" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c942e64b20ecd39933d5ff938ca4fdb6ef0d298cc3855b231179a5ef0b24948d" +dependencies = [ + "flagset", ] [[package]] @@ -620,15 +635,21 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "flagset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -651,23 +672,23 @@ dependencies = [ [[package]] name = "framehop" -version = "0.12.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fd28d2036d4fd99e3629487baca659e5af1c5d554e320168613be79028610fc" +checksum = "59bdf491caf8284489b65c99366d0f88393709b8214e4ccff2f55d9892da7713" dependencies = [ "arrayvec", "cfg-if", "fallible-iterator 0.3.0", - "gimli 0.30.0", - "macho-unwind-info", + "gimli 0.31.1", + "macho-unwind-info 0.5.0", "pe-unwind-info", ] [[package]] name = "fs4" -version = "0.9.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c6b3bd49c37d2aa3f3f2220233b29a7cd23f79d1fe70e5337d25fb390793de" +checksum = "c29c30684418547d476f0b48e84f4821639119c483b1eccd566c8cd0cd05f521" dependencies = [ "rustix", "windows-sys 0.52.0", @@ -675,9 +696,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -690,9 +711,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -700,15 +721,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -717,15 +738,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -734,21 +755,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -779,15 +800,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.29.0" +name = "getrandom" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] [[package]] name = "gimli" @@ -801,9 +830,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" dependencies = [ "fallible-iterator 0.3.0", "stable_deref_trait", @@ -820,6 +849,17 @@ dependencies = [ "scroll 0.12.0", ] +[[package]] +name = "goblin" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745" +dependencies = [ + "log", + "plain", + "scroll 0.12.0", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -831,6 +871,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -845,9 +891,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -879,15 +925,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -904,9 +950,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http", @@ -922,9 +968,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", @@ -935,19 +981,147 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", "tower-service", "tracing", ] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -958,12 +1132,12 @@ checksum = "0cfe9645a18782869361d9c8732246be7b410ad4e919d3609ebabdac00ba12c3" [[package]] name = "indexmap" -version = "2.4.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", "serde", ] @@ -978,9 +1152,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "itertools" @@ -993,9 +1167,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -1014,10 +1188,11 @@ checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1035,9 +1210,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.156" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libredox" @@ -1045,7 +1220,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "libc", ] @@ -1067,7 +1242,7 @@ dependencies = [ "memchr", "prost", "prost-derive", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1076,17 +1251,23 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a563f3068af081e11c8b03dc1fb8ff5654993ce538f7a4b1806e3461a8b86166" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "byteorder", "memchr", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -1122,9 +1303,9 @@ dependencies = [ [[package]] name = "lzxd" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de7336a183103429ad66d11d56d8bdc9c4a2916f6b85a8f11e5b127bde12001" +checksum = "7b29dffab797218e12e4df08ef5d15ab9efca2504038b1b32b9b32fc844b39c9" [[package]] name = "mach2" @@ -1141,9 +1322,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b6086acc74bc23f56b60e88bb082d505e23849d68d6c0f12bb6a7ad5c60e03e" dependencies = [ - "thiserror", - "zerocopy", - "zerocopy-derive", + "thiserror 1.0.69", + "zerocopy 0.7.35", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror 2.0.10", + "zerocopy 0.8.14", + "zerocopy-derive 0.8.14", ] [[package]] @@ -1160,9 +1352,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" dependencies = [ "libc", ] @@ -1184,9 +1376,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minidump" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aefb80650628de087057ed167e3e1ef5bed65dc4b1bd28d47cd707c3848adce2" +checksum = "e03e301d414a75655d4ce80e6e3690fbfe70814b67c496c64c826ba558d18ec9" dependencies = [ "debugid", "encoding_rs", @@ -1196,7 +1388,7 @@ dependencies = [ "procfs-core", "range-map", "scroll 0.12.0", - "thiserror", + "thiserror 1.0.69", "time", "tracing", "uuid", @@ -1204,11 +1396,11 @@ dependencies = [ [[package]] name = "minidump-common" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a2b640f80e5514f49509ff1f97fb24693f95ef5be5ed810d70df4283a68acc" +checksum = "5273687f49325b3977f7d372a1bbe2e528694d18128de8dcac78d134448e83b4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "debugid", "num-derive", "num-traits", @@ -1217,31 +1409,11 @@ dependencies = [ "smart-default", ] -[[package]] -name = "minidump-processor" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d330a92d90c5699e8edd32f8036a1b5afadd6df000eb201fac258d149f8ca78" -dependencies = [ - "async-trait", - "breakpad-symbols", - "debugid", - "futures-util", - "minidump", - "minidump-common", - "minidump-unwind", - "scroll 0.12.0", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "minidump-unwind" -version = "0.22.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb5af4cbb631c54fe8c0c058799e9ac95b31c6e282f1afaaaaad10c2c441fcb" +checksum = "c30454f5703c77433b4059bf5e196266b800b14223c55793ee636e49c8f9160e" dependencies = [ "async-trait", "breakpad-symbols", @@ -1259,16 +1431,18 @@ dependencies = [ [[package]] name = "minidump-writer" -version = "0.10.1" +version = "0.10.2" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "byteorder", "cfg-if", "crash-context", "current_platform", "dump_syms", + "error-graph", + "failspot", "futures", - "goblin", + "goblin 0.9.3", "libc", "log", "mach2", @@ -1276,14 +1450,15 @@ dependencies = [ "memoffset", "minidump", "minidump-common", - "minidump-processor", "minidump-unwind", "nix", "procfs-core", "scroll 0.12.0", + "serde", + "serde_json", "similar-asserts", "tempfile", - "thiserror", + "thiserror 2.0.10", "uuid", ] @@ -1295,22 +1470,21 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1320,7 +1494,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4c25a3bb7d880e8eceab4822f3141ad0700d20f025991c1f03bd3d00219a5fc" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] @@ -1335,7 +1509,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "cfg-if", "cfg_aliases", "libc", @@ -1402,9 +1576,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "flate2", "memchr", @@ -1413,9 +1587,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "option-ext" @@ -1468,28 +1642,28 @@ dependencies = [ "maybe-owned", "pdb", "range-collections 0.2.4", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "pdb-addr2line" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb51ef7ed9998e108891711812822831daac0b17d67768c3bdc69aa909366123" +checksum = "6f4d9133f33529242bbc22aaaffbd05a7c61712833ecb3a23f50acc1055f2bd5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "elsa", "maybe-owned", "pdb2", "range-collections 0.4.5", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "pdb2" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51690a9810e8a4f711186ec92e4b376089e23c53e51380c340ea197fd4f99fe5" +checksum = "266b8733697ccc3aa405a9b2cf485a42746ad1cf73d3b0497b79b24f9e874a71" dependencies = [ "fallible-iterator 0.3.0", "scroll 0.12.0", @@ -1498,15 +1672,15 @@ dependencies = [ [[package]] name = "pe-unwind-info" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ec3b43050c38ffb9de87e17d874e9956e3a9131b343c9b7b7002597727c3891" +checksum = "11fe3d7d11dde0fd142bf734ae5d645a4c62ede7c188bccc73dec5082359ff84" dependencies = [ "arrayvec", - "bitflags 2.6.0", - "thiserror", - "zerocopy", - "zerocopy-derive", + "bitflags 2.8.0", + "thiserror 1.0.69", + "zerocopy 0.7.35", + "zerocopy-derive 0.7.35", ] [[package]] @@ -1524,31 +1698,11 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1558,9 +1712,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain" @@ -1580,7 +1734,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -1591,21 +1745,22 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "procfs-core" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "hex", + "serde", ] [[package]] @@ -1632,9 +1787,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", @@ -1643,46 +1798,50 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror", + "thiserror 2.0.10", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom 0.2.15", "rand", "ring", "rustc-hash", "rustls", + "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.10", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -1714,7 +1873,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -1757,22 +1916,22 @@ checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1797,9 +1956,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1809,9 +1968,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1820,15 +1979,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "async-compression", "base64", @@ -1859,6 +2018,7 @@ dependencies = [ "tokio", "tokio-rustls", "tokio-util", + "tower", "tower-service", "url", "wasm-bindgen", @@ -1866,7 +2026,7 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots", - "winreg", + "windows-registry", ] [[package]] @@ -1877,7 +2037,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -1892,28 +2052,28 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "ring", @@ -1925,25 +2085,27 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -1952,11 +2114,10 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" +checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" dependencies = [ - "byteorder", "twox-hash", ] @@ -1973,7 +2134,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbcdc8625b92ae1b981f37d435599effed5464dd1f37c01f88ccf83c0e90b54d" dependencies = [ "addr2line 0.23.0", - "bitflags 2.6.0", + "bitflags 2.8.0", "cpp_demangle", "debugid", "elsa", @@ -1981,22 +2142,22 @@ dependencies = [ "gimli 0.30.0", "linux-perf-data", "lzma-rs", - "macho-unwind-info", + "macho-unwind-info 0.4.0", "memchr", "msvc-demangler", "nom", "object", - "pdb-addr2line 0.11.0", + "pdb-addr2line 0.11.1", "rangemap", "rustc-demangle", "scala-native-demangle", "srcsrv", - "thiserror", + "thiserror 1.0.69", "uuid", "yoke", "yoke-derive", - "zerocopy", - "zerocopy-derive", + "zerocopy 0.7.35", + "zerocopy-derive 0.7.35", ] [[package]] @@ -2039,24 +2200,24 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -2065,9 +2226,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "itoa", "memchr", @@ -2122,9 +2283,9 @@ dependencies = [ [[package]] name = "similar-asserts" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e041bb827d1bfca18f213411d51b665309f1afb37a04a5d1464530e13779fc0f" +checksum = "cfe85670573cd6f0fa97940f26e7e6601213c3b0555246c24234131f88c5709e" dependencies = [ "console", "similar", @@ -2164,9 +2325,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2185,7 +2346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "022437a70e522e49b1952cb1d923589d629cb4aee97eb56d65ce938c04e8ac70" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2222,9 +2383,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4e155af9f06f8b44963cdb05ad7c9884f424dc040f08adc5a1bb4960937d1d" +checksum = "092f529e0337927f7821ffaef0c74b8cbd53dceb30268b3c97d51575de4e0f56" dependencies = [ "symbolic-cfi", "symbolic-common", @@ -2234,20 +2395,20 @@ dependencies = [ [[package]] name = "symbolic-cfi" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4273aee7b62c172f1723eb06dda7462f951760a79524734fb1da4cf3842a2" +checksum = "4a7eae3fbd0737bdcad5fcb8133c53319979d592d79dd493e6261ce772ba2073" dependencies = [ "symbolic-common", "symbolic-debuginfo", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "symbolic-common" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16629323a4ec5268ad23a575110a724ad4544aae623451de600c747bf87b36cf" +checksum = "cd33e73f154e36ec223c18013f7064a2c120f1162fc086ac9933542def186b00" dependencies = [ "debugid", "memmap2", @@ -2257,18 +2418,17 @@ dependencies = [ [[package]] name = "symbolic-debuginfo" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f629454e4787591257c96c6c7c676c17f792ef8290638699714152140580717d" +checksum = "81accb35fc5ac97eec349bddafd9fbd67f4abd47d9a29484f234ac1f8869adab" dependencies = [ "debugid", - "dmsort", "elementtree", "elsa", "fallible-iterator 0.3.0", "flate2", - "gimli 0.31.0", - "goblin", + "gimli 0.31.1", + "goblin 0.8.2", "lazy_static", "nom", "nom-supreme", @@ -2282,7 +2442,7 @@ dependencies = [ "smallvec", "symbolic-common", "symbolic-ppdb", - "thiserror", + "thiserror 1.0.69", "wasmparser", "zip", "zstd", @@ -2290,9 +2450,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c043a45f08f41187414592b3ceb53fb0687da57209cc77401767fb69d5b596" +checksum = "89e51191290147f071777e37fe111800bb82a9059f9c95b19d2dd41bfeddf477" dependencies = [ "cc", "cpp_demangle", @@ -2303,25 +2463,25 @@ dependencies = [ [[package]] name = "symbolic-ppdb" -version = "12.10.0" +version = "12.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6eaa9dc4774d5e0a9df62a3145d814b3a9ebcbcf37e973bc51c57bcb9eacc7" +checksum = "c657f9d724dd50b954ecd08874aa5cb6c1638c21e056be1ec124fe32ae349a5f" dependencies = [ "flate2", "indexmap", "serde", "serde_json", "symbolic-common", - "thiserror", + "thiserror 1.0.69", "uuid", "watto", ] [[package]] name = "symsrv" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc84816f92e67d3613ceccab0694df7b4a10514770ce5ab9c75b32de512ab53" +checksum = "cc2d3a0369f307303a9c7d36346da26ce084d807af2ca02e136d808b5c0733be" dependencies = [ "async-compression", "cab", @@ -2331,15 +2491,15 @@ dependencies = [ "http", "reqwest", "scopeguard", - "thiserror", + "thiserror 2.0.10", "tokio", ] [[package]] name = "syn" -version = "2.0.74" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -2348,9 +2508,12 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -2365,30 +2528,52 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3" +dependencies = [ + "thiserror-impl 2.0.10", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb" dependencies = [ "proc-macro2", "quote", @@ -2397,9 +2582,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -2418,19 +2603,29 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -2443,9 +2638,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -2458,20 +2653,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -2482,14 +2676,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.13" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -2509,9 +2703,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -2521,9 +2715,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -2532,9 +2726,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] @@ -2561,32 +2755,17 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "untrusted" @@ -2596,9 +2775,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -2606,10 +2785,22 @@ dependencies = [ ] [[package]] -name = "uuid" -version = "1.10.0" +name = "utf16_iter" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" [[package]] name = "version_check" @@ -2633,10 +2824,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.93" +name = "wasi" +version = "0.13.3+wasi-0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -2645,13 +2845,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -2660,21 +2859,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2682,9 +2882,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -2695,15 +2895,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -2719,8 +2919,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5309c1090e3e84dad0d382f42064e9933fdaedb87e468cc239f0eabea73ddcb6" dependencies = [ "ahash", - "bitflags 2.6.0", - "hashbrown", + "bitflags 2.8.0", + "hashbrown 0.14.5", "indexmap", "semver", "serde", @@ -2733,14 +2933,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6746b5315e417144282a047ebb82260d45c92d09bf653fa9ec975e3809be942b" dependencies = [ "leb128", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2748,9 +2958,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -2777,6 +2987,36 @@ dependencies = [ "yoke-derive", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2795,6 +3035,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2917,31 +3166,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winreg" -version = "0.52.0" +name = "wit-bindgen-rt" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "bitflags 2.8.0", ] [[package]] -name = "yoke" -version = "0.7.4" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", + "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", @@ -2956,7 +3217,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" +dependencies = [ + "zerocopy-derive 0.8.14", ] [[package]] @@ -2971,10 +3241,36 @@ dependencies = [ ] [[package]] -name = "zerofrom" -version = "0.1.4" +name = "zerocopy-derive" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] [[package]] name = "zeroize" @@ -2983,10 +3279,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] -name = "zip" -version = "2.1.6" +name = "zerovec" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zip" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" dependencies = [ "arbitrary", "crc32fast", @@ -2995,7 +3313,7 @@ dependencies = [ "flate2", "indexmap", "memchr", - "thiserror", + "thiserror 2.0.10", "zopfli", ] diff --git a/third_party/rust/minidump-writer/Cargo.toml b/third_party/rust/minidump-writer/Cargo.toml index 37353a83e0f5..35ef21371a7d 100644 --- a/third_party/rust/minidump-writer/Cargo.toml +++ b/third_party/rust/minidump-writer/Cargo.toml @@ -12,9 +12,10 @@ [package] edition = "2021" name = "minidump-writer" -version = "0.10.1" +version = "0.10.2" authors = ["Martin Sirringhaus"] build = "build.rs" +autolib = false autobins = false autoexamples = false autotests = false @@ -41,6 +42,10 @@ path = "examples/synthetic.rs" name = "linux_minidump_writer" path = "tests/linux_minidump_writer.rs" +[[test]] +name = "linux_minidump_writer_soft_error" +path = "tests/linux_minidump_writer_soft_error.rs" + [[test]] name = "mac_minidump_writer" path = "tests/mac_minidump_writer.rs" @@ -58,7 +63,7 @@ name = "windows_minidump_writer" path = "tests/windows_minidump_writer.rs" [dependencies.bitflags] -version = "2.4" +version = "2.8" [dependencies.byteorder] version = "1.4" @@ -69,6 +74,13 @@ version = "1.0" [dependencies.crash-context] version = "0.6" +[dependencies.error-graph] +version = "0.1.1" +features = ["serde"] + +[dependencies.failspot] +version = "0.2.0" + [dependencies.log] version = "0.4" @@ -76,20 +88,31 @@ version = "0.4" version = "0.9" [dependencies.minidump-common] -version = "0.22" +version = "0.24" [dependencies.scroll] version = "0.12" +[dependencies.serde] +version = "1.0.208" +features = ["derive"] + +[dependencies.serde_json] +version = "1.0.116" + [dependencies.tempfile] -version = "3.8" +version = "3.16" [dependencies.thiserror] -version = "1.0" +version = "2.0" [dev-dependencies.current_platform] version = "0.2" +[dev-dependencies.failspot] +version = "0.2.0" +features = ["enabled"] + [dev-dependencies.futures] version = "0.3" features = ["executor"] @@ -98,7 +121,7 @@ features = ["executor"] version = "0.9" [dev-dependencies.minidump] -version = "0.22" +version = "0.24" [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.nix] version = "0.29" @@ -113,7 +136,8 @@ features = [ default-features = false [target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies.procfs-core] -version = "0.16" +version = "0.17" +features = ["serde1"] default-features = false [target.'cfg(target_os = "macos")'.dependencies.mach2] @@ -123,25 +147,21 @@ version = "0.4" version = "2.2" default-features = false -[target.'cfg(target_os = "macos")'.dev-dependencies.minidump-processor] -version = "0.22" -default-features = false - [target.'cfg(target_os = "macos")'.dev-dependencies.minidump-unwind] -version = "0.22" +version = "0.24" features = ["debuginfo"] [target.'cfg(target_os = "macos")'.dev-dependencies.similar-asserts] -version = "1.5" +version = "1.6" [target.'cfg(target_os = "macos")'.dev-dependencies.uuid] -version = "1.4" +version = "1.12" [target.'cfg(target_os = "windows")'.dependencies.bitflags] version = "2.4" [target."cfg(unix)".dependencies.goblin] -version = "0.8.2" +version = "0.9.2" [target."cfg(unix)".dependencies.libc] version = "0.2" diff --git a/third_party/rust/minidump-writer/deny.toml b/third_party/rust/minidump-writer/deny.toml index 18ce5feb1616..ed97463c016d 100644 --- a/third_party/rust/minidump-writer/deny.toml +++ b/third_party/rust/minidump-writer/deny.toml @@ -20,5 +20,4 @@ deny = [ skip-tree = [] [licenses] -allow = ["MIT", "Apache-2.0"] -exceptions = [{ allow = ["Unicode-DFS-2016"], name = "unicode-ident" }] +allow = ["MIT", "Apache-2.0", "Unicode-3.0"] diff --git a/third_party/rust/minidump-writer/src/bin/test.rs b/third_party/rust/minidump-writer/src/bin/test.rs index 6713852cba34..9ab42f130e4f 100644 --- a/third_party/rust/minidump-writer/src/bin/test.rs +++ b/third_party/rust/minidump-writer/src/bin/test.rs @@ -6,14 +6,17 @@ pub type Result = std::result::Result; #[cfg(any(target_os = "linux", target_os = "android"))] mod linux { - use super::*; - use minidump_writer::{ - minidump_writer::STOP_TIMEOUT, module_reader, ptrace_dumper::PtraceDumper, - LINUX_GATE_LIBRARY_NAME, - }; - use nix::{ - sys::mman::{mmap_anonymous, MapFlags, ProtFlags}, - unistd::getppid, + use { + super::*, + error_graph::ErrorList, + minidump_writer::{ + minidump_writer::STOP_TIMEOUT, module_reader, ptrace_dumper::PtraceDumper, + LINUX_GATE_LIBRARY_NAME, + }, + nix::{ + sys::mman::{mmap_anonymous, MapFlags, ProtFlags}, + unistd::getppid, + }, }; macro_rules! test { @@ -24,15 +27,40 @@ mod linux { }; } + macro_rules! fail_on_soft_error(($n: ident, $e: expr) => {{ + let mut $n = ErrorList::default(); + let __result = $e; + if !$n.is_empty() { + return Err($n.into()); + } + __result + }}); + fn test_setup() -> Result<()> { let ppid = getppid(); - PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?; + fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid.as_raw(), + STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + )? + ); Ok(()) } fn test_thread_list() -> Result<()> { let ppid = getppid(); - let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?; + let dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid.as_raw(), + STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + )? + ); test!(!dumper.threads.is_empty(), "No threads"); test!( dumper @@ -59,8 +87,17 @@ mod linux { use minidump_writer::mem_reader::MemReader; let ppid = getppid().as_raw(); - let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?; - dumper.suspend_threads()?; + let mut dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid, + STOP_TIMEOUT, + Default::default(), + &mut soft_errors + )? + ); + + fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors)); // We support 3 different methods of reading memory from another // process, ensure they all function and give the same results @@ -113,13 +150,22 @@ mod linux { test!(heap_res == expected_heap, "heap var not correct"); - dumper.resume_threads()?; + fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors)); + Ok(()) } fn test_find_mappings(addr1: usize, addr2: usize) -> Result<()> { let ppid = getppid(); - let dumper = PtraceDumper::new(ppid.as_raw(), STOP_TIMEOUT, Default::default())?; + let dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid.as_raw(), + STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + )? + ); dumper .find_mapping(addr1) .ok_or("No mapping for addr1 found")?; @@ -136,8 +182,19 @@ mod linux { let ppid = getppid().as_raw(); let exe_link = format!("/proc/{ppid}/exe"); let exe_name = std::fs::read_link(exe_link)?.into_os_string(); - let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?; - dumper.suspend_threads()?; + + let mut dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid, + STOP_TIMEOUT, + Default::default(), + &mut soft_errors + )? + ); + + fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors)); + let mut found_exe = None; for (idx, mapping) in dumper.mappings.iter().enumerate() { if mapping.name.as_ref().map(|x| x.into()).as_ref() == Some(&exe_name) { @@ -147,7 +204,9 @@ mod linux { } let idx = found_exe.unwrap(); let module_reader::BuildId(id) = dumper.from_process_memory_for_index(idx)?; - dumper.resume_threads()?; + + fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors)); + assert!(!id.is_empty()); assert!(id.iter().any(|&x| x > 0)); Ok(()) @@ -155,13 +214,21 @@ mod linux { fn test_merged_mappings(path: String, mapped_mem: usize, mem_size: usize) -> Result<()> { // Now check that PtraceDumper interpreted the mappings properly. - let dumper = PtraceDumper::new(getppid().as_raw(), STOP_TIMEOUT, Default::default())?; + let dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + getppid().as_raw(), + STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + )? + ); let mut mapping_count = 0; for map in &dumper.mappings { if map .name .as_ref() - .map_or(false, |name| name.to_string_lossy().starts_with(&path)) + .is_some_and(|name| name.to_string_lossy().starts_with(&path)) { mapping_count += 1; // This mapping should encompass the entire original mapped @@ -177,17 +244,29 @@ mod linux { fn test_linux_gate_mapping_id() -> Result<()> { let ppid = getppid().as_raw(); - let mut dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?; + let mut dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid, + STOP_TIMEOUT, + Default::default(), + &mut soft_errors + )? + ); let mut found_linux_gate = false; for mapping in dumper.mappings.clone() { if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) { found_linux_gate = true; - dumper.suspend_threads()?; + + fail_on_soft_error!(soft_errors, dumper.suspend_threads(&mut soft_errors)); + let module_reader::BuildId(id) = PtraceDumper::from_process_memory_for_mapping(&mapping, ppid)?; test!(!id.is_empty(), "id-vec is empty"); test!(id.iter().any(|&x| x > 0), "all id elements are 0"); - dumper.resume_threads()?; + + fail_on_soft_error!(soft_errors, dumper.resume_threads(&mut soft_errors)); + break; } } @@ -197,7 +276,15 @@ mod linux { fn test_mappings_include_linux_gate() -> Result<()> { let ppid = getppid().as_raw(); - let dumper = PtraceDumper::new(ppid, STOP_TIMEOUT, Default::default())?; + let dumper = fail_on_soft_error!( + soft_errors, + PtraceDumper::new_report_soft_errors( + ppid, + STOP_TIMEOUT, + Default::default(), + &mut soft_errors + )? + ); let linux_gate_loc = dumper.auxv.get_linux_gate_address().unwrap(); test!(linux_gate_loc != 0, "linux_gate_loc == 0"); let mut found_linux_gate = false; @@ -205,7 +292,7 @@ mod linux { if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) { found_linux_gate = true; test!( - linux_gate_loc == mapping.start_address.try_into()?, + usize::try_from(linux_gate_loc)? == mapping.start_address, "linux_gate_loc != start_address" ); diff --git a/third_party/rust/minidump-writer/src/dir_section.rs b/third_party/rust/minidump-writer/src/dir_section.rs index ced5a2d1568a..2aaed65a53f3 100644 --- a/third_party/rust/minidump-writer/src/dir_section.rs +++ b/third_party/rust/minidump-writer/src/dir_section.rs @@ -1,15 +1,22 @@ -use crate::{ - mem_writer::{Buffer, MemoryArrayWriter, MemoryWriterError}, - minidump_format::MDRawDirectory, +use { + crate::{ + mem_writer::{Buffer, MemoryArrayWriter, MemoryWriterError}, + minidump_format::MDRawDirectory, + serializers::*, + }, + std::io::{Error, Seek, Write}, }; -use std::io::{Error, Seek, Write}; pub type DumpBuf = Buffer; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, serde::Serialize)] pub enum FileWriterError { #[error("IO error")] - IOError(#[from] Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + Error, + ), #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), } diff --git a/third_party/rust/minidump-writer/src/lib.rs b/third_party/rust/minidump-writer/src/lib.rs index a76291d0ae9e..67181b4af5c1 100644 --- a/third_party/rust/minidump-writer/src/lib.rs +++ b/third_party/rust/minidump-writer/src/lib.rs @@ -14,8 +14,19 @@ cfg_if::cfg_if! { } } +pub mod dir_section; +pub mod mem_writer; pub mod minidump_cpu; pub mod minidump_format; -pub mod dir_section; -pub mod mem_writer; +mod serializers; + +failspot::failspot_name! { + pub enum FailSpotName { + StopProcess, + FillMissingAuxvInfo, + ThreadName, + SuspendThreads, + CpuInfoFileOpen, + } +} diff --git a/third_party/rust/minidump-writer/src/linux.rs b/third_party/rust/minidump-writer/src/linux.rs index febdeabefea4..dc6050845914 100644 --- a/third_party/rust/minidump-writer/src/linux.rs +++ b/third_party/rust/minidump-writer/src/linux.rs @@ -15,6 +15,7 @@ pub mod minidump_writer; pub mod module_reader; pub mod ptrace_dumper; pub(crate) mod sections; +mod serializers; pub mod thread_info; pub use maps_reader::LINUX_GATE_LIBRARY_NAME; diff --git a/third_party/rust/minidump-writer/src/linux/auxv/mod.rs b/third_party/rust/minidump-writer/src/linux/auxv/mod.rs index 403ab1145dd5..527fc45bea9d 100644 --- a/third_party/rust/minidump-writer/src/linux/auxv/mod.rs +++ b/third_party/rust/minidump-writer/src/linux/auxv/mod.rs @@ -1,6 +1,8 @@ -pub use reader::ProcfsAuxvIter; use { - crate::Pid, + self::reader::ProcfsAuxvIter, + crate::{serializers::*, Pid}, + error_graph::WriteErrorList, + failspot::failspot, std::{fs::File, io::BufReader}, thiserror::Error, }; @@ -79,7 +81,11 @@ pub struct AuxvDumpInfo { } impl AuxvDumpInfo { - pub fn try_filling_missing_info(&mut self, pid: Pid) -> Result<(), AuxvError> { + pub fn try_filling_missing_info( + &mut self, + pid: Pid, + mut soft_errors: impl WriteErrorList, + ) -> Result<(), AuxvError> { if self.is_complete() { return Ok(()); } @@ -87,9 +93,14 @@ impl AuxvDumpInfo { let auxv_path = format!("/proc/{pid}/auxv"); let auxv_file = File::open(&auxv_path).map_err(|e| AuxvError::OpenError(auxv_path, e))?; - for AuxvPair { key, value } in - ProcfsAuxvIter::new(BufReader::new(auxv_file)).filter_map(Result::ok) - { + for pair_result in ProcfsAuxvIter::new(BufReader::new(auxv_file)) { + let AuxvPair { key, value } = match pair_result { + Ok(pair) => pair, + Err(e) => { + soft_errors.push(e); + continue; + } + }; let dest_field = match key { consts::AT_PHNUM => &mut self.program_header_count, consts::AT_PHDR => &mut self.program_header_address, @@ -102,6 +113,8 @@ impl AuxvDumpInfo { } } + failspot!(FillMissingAuxvInfo soft_errors.push(AuxvError::InvalidFormat)); + Ok(()) } pub fn get_program_header_count(&self) -> Option { @@ -124,14 +137,23 @@ impl AuxvDumpInfo { } } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum AuxvError { #[error("Failed to open file {0}")] - OpenError(String, #[source] std::io::Error), + OpenError( + String, + #[source] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("No auxv entry found for PID {0}")] NoAuxvEntryFound(Pid), #[error("Invalid auxv format (should not hit EOF before AT_NULL)")] InvalidFormat, #[error("IO Error")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), } diff --git a/third_party/rust/minidump-writer/src/linux/dumper_cpu_info/x86_mips.rs b/third_party/rust/minidump-writer/src/linux/dumper_cpu_info/x86_mips.rs index 0c03d8e5f1b2..025a97bea759 100644 --- a/third_party/rust/minidump-writer/src/linux/dumper_cpu_info/x86_mips.rs +++ b/third_party/rust/minidump-writer/src/linux/dumper_cpu_info/x86_mips.rs @@ -1,7 +1,11 @@ -use crate::errors::CpuInfoError; -use crate::minidump_format::*; -use std::io::{BufRead, BufReader}; -use std::path; +use { + crate::{errors::CpuInfoError, minidump_format::*}, + failspot::failspot, + std::{ + io::{BufRead, BufReader}, + path, + }, +}; type Result = std::result::Result; @@ -44,6 +48,11 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { MDCPUArchitecture::PROCESSOR_ARCHITECTURE_AMD64 } as u16; + failspot!( + CpuInfoFileOpen + bail(std::io::Error::other("test requested cpuinfo file failure")) + ); + let cpuinfo_file = std::fs::File::open(path::PathBuf::from("/proc/cpuinfo"))?; let mut vendor_id = String::new(); diff --git a/third_party/rust/minidump-writer/src/linux/errors.rs b/third_party/rust/minidump-writer/src/linux/errors.rs index 982445a03a30..95322f10c098 100644 --- a/third_party/rust/minidump-writer/src/linux/errors.rs +++ b/third_party/rust/minidump-writer/src/linux/errors.rs @@ -1,31 +1,22 @@ -use crate::{ - dir_section::FileWriterError, maps_reader::MappingInfo, mem_writer::MemoryWriterError, Pid, +use { + super::{ptrace_dumper::InitError, serializers::*}, + crate::{ + dir_section::FileWriterError, maps_reader::MappingInfo, mem_writer::MemoryWriterError, + serializers::*, Pid, + }, + error_graph::ErrorList, + std::ffi::OsString, + thiserror::Error, }; -use goblin; -use nix::errno::Errno; -use std::ffi::OsString; -use thiserror::Error; -#[derive(Debug, Error)] -pub enum InitError { - #[error("failed to read auxv")] - ReadAuxvFailed(crate::auxv::AuxvError), - #[error("IO error for file {0}")] - IOError(String, #[source] std::io::Error), - #[error("crash thread does not reference principal mapping")] - PrincipalMappingNotReferenced, - #[error("Failed Android specific late init")] - AndroidLateInitError(#[from] AndroidError), - #[error("Failed to read the page size")] - PageSizeError(#[from] Errno), - #[error("Ptrace does not function within the same process")] - CannotPtraceSameProcess, -} - -#[derive(Error, Debug)] +#[derive(Error, Debug, serde::Serialize)] pub enum MapsReaderError { #[error("Couldn't parse as ELF file")] - ELFParsingFailed(#[from] goblin::error::Error), + ELFParsingFailed( + #[from] + #[serde(serialize_with = "serialize_goblin_error")] + goblin::error::Error, + ), #[error("No soname found (filename: {})", .0.to_string_lossy())] NoSoName(OsString, #[source] ModuleReaderError), @@ -33,102 +24,168 @@ pub enum MapsReaderError { #[error("Map entry malformed: No {0} found")] MapEntryMalformed(&'static str), #[error("Couldn't parse address")] - UnparsableInteger(#[from] std::num::ParseIntError), + UnparsableInteger( + #[from] + #[serde(skip)] + std::num::ParseIntError, + ), #[error("Linux gate location doesn't fit in the required integer type")] - LinuxGateNotConvertable(#[from] std::num::TryFromIntError), + LinuxGateNotConvertable( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), // get_mmap() #[error("Not safe to open mapping {}", .0.to_string_lossy())] NotSafeToOpenMapping(OsString), #[error("IO Error")] - FileError(#[from] std::io::Error), + FileError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("Mmapped file empty or not an ELF file")] MmapSanityCheckFailed, #[error("Symlink does not match ({0} vs. {1})")] SymlinkError(std::path::PathBuf, std::path::PathBuf), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum CpuInfoError { #[error("IO error for file /proc/cpuinfo")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("Not all entries of /proc/cpuinfo found!")] NotAllProcEntriesFound, #[error("Couldn't parse core from file")] - UnparsableInteger(#[from] std::num::ParseIntError), + UnparsableInteger( + #[from] + #[serde(skip)] + std::num::ParseIntError, + ), #[error("Couldn't parse cores: {0}")] UnparsableCores(String), } -#[derive(Error, Debug)] +#[derive(Error, Debug, serde::Serialize)] pub enum ThreadInfoError { #[error("Index out of bounds: Got {0}, only have {1}")] IndexOutOfBounds(usize, usize), #[error("Either ppid ({1}) or tgid ({2}) not found in {0}")] InvalidPid(String, Pid, Pid), #[error("IO error")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("Couldn't parse address")] - UnparsableInteger(#[from] std::num::ParseIntError), + UnparsableInteger( + #[from] + #[serde(skip)] + std::num::ParseIntError, + ), #[error("nix::ptrace() error")] - PtraceError(#[from] nix::Error), + PtraceError( + #[from] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error("Invalid line in /proc/{0}/status: {1}")] InvalidProcStatusFile(Pid, String), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum AndroidError { #[error("Failed to copy memory from process")] CopyFromProcessError(#[from] DumperError), #[error("Failed slice conversion")] - TryFromSliceError(#[from] std::array::TryFromSliceError), + TryFromSliceError( + #[from] + #[serde(skip)] + std::array::TryFromSliceError, + ), #[error("No Android rel found")] NoRelFound, } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] #[error("Copy from process {child} failed (source {src}, offset: {offset}, length: {length})")] pub struct CopyFromProcessError { pub child: Pid, pub src: usize, pub offset: usize, pub length: usize, + #[serde(serialize_with = "serialize_nix_error")] pub source: nix::Error, } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum DumperError { #[error("Failed to get PAGE_SIZE from system")] - SysConfError(#[from] nix::Error), + SysConfError( + #[from] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error("wait::waitpid(Pid={0}) failed")] - WaitPidError(Pid, #[source] nix::Error), + WaitPidError( + Pid, + #[source] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error("nix::ptrace::attach(Pid={0}) failed")] - PtraceAttachError(Pid, #[source] nix::Error), + PtraceAttachError( + Pid, + #[source] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error("nix::ptrace::detach(Pid={0}) failed")] - PtraceDetachError(Pid, #[source] nix::Error), + PtraceDetachError( + Pid, + #[source] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error(transparent)] CopyFromProcessError(#[from] CopyFromProcessError), #[error("Skipped thread {0} due to it being part of the seccomp sandbox's trusted code")] DetachSkippedThread(Pid), - #[error("No threads left to suspend out of {0}")] - SuspendNoThreadsLeft(usize), #[error("No mapping for stack pointer found")] NoStackPointerMapping, #[error("Failed slice conversion")] - TryFromSliceError(#[from] std::array::TryFromSliceError), + TryFromSliceError( + #[from] + #[serde(skip)] + std::array::TryFromSliceError, + ), #[error("Couldn't parse as ELF file")] - ELFParsingFailed(#[from] goblin::error::Error), + ELFParsingFailed( + #[from] + #[serde(serialize_with = "serialize_goblin_error")] + goblin::error::Error, + ), #[error("Could not read value from module")] ModuleReaderError(#[from] ModuleReaderError), #[error("Not safe to open mapping: {}", .0.to_string_lossy())] NotSafeToOpenMapping(OsString), #[error("Failed integer conversion")] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), #[error("Maps reader error")] MapsReaderError(#[from] MapsReaderError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionAppMemoryError { #[error("Failed to copy memory from process")] CopyFromProcessError(#[from] DumperError), @@ -136,23 +193,31 @@ pub enum SectionAppMemoryError { MemoryWriterError(#[from] MemoryWriterError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionExceptionStreamError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionHandleDataStreamError { #[error("Failed to access file")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), #[error("Failed integer conversion")] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionMappingsError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), @@ -160,53 +225,75 @@ pub enum SectionMappingsError { GetEffectivePathError(MappingInfo, #[source] MapsReaderError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionMemInfoListError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), #[error("Failed to read from procfs")] - ProcfsError(#[from] procfs_core::ProcError), + ProcfsError( + #[from] + #[serde(serialize_with = "serialize_proc_error")] + procfs_core::ProcError, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionMemListError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionSystemInfoError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), #[error("Failed to get CPU Info")] CpuInfoError(#[from] CpuInfoError), + #[error("Failed trying to write CPU information")] + WriteCpuInformationFailed(#[source] CpuInfoError), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionThreadListError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), #[error("Failed integer conversion")] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), #[error("Failed to copy memory from process")] CopyFromProcessError(#[from] DumperError), #[error("Failed to get thread info")] ThreadInfoError(#[from] ThreadInfoError), #[error("Failed to write to memory buffer")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionThreadNamesError { #[error("Failed integer conversion")] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), #[error("Failed to write to memory buffer")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum SectionDsoDebugError { #[error("Failed to write to memory")] MemoryWriterError(#[from] MemoryWriterError), @@ -215,10 +302,14 @@ pub enum SectionDsoDebugError { #[error("Failed to copy memory from process")] CopyFromProcessError(#[from] DumperError), #[error("Failed to copy memory from process")] - FromUTF8Error(#[from] std::string::FromUtf8Error), + FromUTF8Error( + #[from] + #[serde(serialize_with = "serialize_from_utf8_error")] + std::string::FromUtf8Error, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum WriterError { #[error("Error during init phase")] InitError(#[from] InitError), @@ -249,15 +340,60 @@ pub enum WriterError { #[error("Failed to write to file")] FileWriterError(#[from] FileWriterError), #[error("Failed to get current timestamp when writing header of minidump")] - SystemTimeError(#[from] std::time::SystemTimeError), + SystemTimeError( + #[from] + #[serde(serialize_with = "serialize_system_time_error")] + std::time::SystemTimeError, + ), + #[error("Errors occurred while initializing PTraceDumper")] + InitErrors(#[source] ErrorList), + #[error("Errors occurred while suspending threads")] + SuspendThreadsErrors(#[source] ErrorList), + #[error("Errors occurred while resuming threads")] + ResumeThreadsErrors(#[source] ErrorList), + #[error("Crash thread does not reference principal mapping")] + PrincipalMappingNotReferenced, + #[error("Errors occurred while writing system info")] + WriteSystemInfoErrors(#[source] ErrorList), + #[error("Failed writing cpuinfo")] + WriteCpuInfoFailed(#[source] MemoryWriterError), + #[error("Failed writing thread proc status")] + WriteThreadProcStatusFailed(#[source] MemoryWriterError), + #[error("Failed writing OS Release Information")] + WriteOsReleaseInfoFailed(#[source] MemoryWriterError), + #[error("Failed writing process command line")] + WriteCommandLineFailed(#[source] MemoryWriterError), + #[error("Writing process environment failed")] + WriteEnvironmentFailed(#[source] MemoryWriterError), + #[error("Failed to write auxv file")] + WriteAuxvFailed(#[source] MemoryWriterError), + #[error("Failed to write maps file")] + WriteMapsFailed(#[source] MemoryWriterError), + #[error("Failed writing DSO Debug Stream")] + WriteDSODebugStreamFailed(#[source] SectionDsoDebugError), + #[error("Failed writing limits file")] + WriteLimitsFailed(#[source] MemoryWriterError), + #[error("Failed writing handle data stream")] + WriteHandleDataStreamFailed(#[source] SectionHandleDataStreamError), + #[error("Failed writing handle data stream direction entry")] + WriteHandleDataStreamDirentFailed(#[source] FileWriterError), + #[error("No threads left to suspend out of {0}")] + SuspendNoThreadsLeft(usize), + #[error("Failed to convert soft error list to JSON")] + ConvertToJsonFailed( + #[source] + #[serde(skip)] + serde_json::Error, + ), } -#[derive(Debug, Error)] +#[derive(Debug, Error, serde::Serialize)] pub enum ModuleReaderError { #[error("failed to read module file ({path}): {error}")] MapFile { path: std::path::PathBuf, #[source] + #[serde(serialize_with = "serialize_io_error")] error: std::io::Error, }, #[error("failed to read module memory: {length} bytes at {offset}{}: {error}", .start_address.map(|addr| format!(" (start address: {addr})")).unwrap_or_default())] @@ -266,10 +402,15 @@ pub enum ModuleReaderError { length: u64, start_address: Option, #[source] + #[serde(serialize_with = "serialize_nix_error")] error: nix::Error, }, #[error("failed to parse ELF memory: {0}")] - Parsing(#[from] goblin::error::Error), + Parsing( + #[from] + #[serde(serialize_with = "serialize_goblin_error")] + goblin::error::Error, + ), #[error("no build id notes in program headers")] NoProgramHeaderNote, #[error("no string table available to locate note sections")] diff --git a/third_party/rust/minidump-writer/src/linux/maps_reader.rs b/third_party/rust/minidump-writer/src/linux/maps_reader.rs index e023a21a5f55..3113d35f467d 100644 --- a/third_party/rust/minidump-writer/src/linux/maps_reader.rs +++ b/third_party/rust/minidump-writer/src/linux/maps_reader.rs @@ -1,19 +1,24 @@ -use crate::auxv::AuxvType; -use crate::errors::MapsReaderError; -use byteorder::{NativeEndian, ReadBytesExt}; -use goblin::elf; -use memmap2::{Mmap, MmapOptions}; -use procfs_core::process::{MMPermissions, MMapPath, MemoryMaps}; -use std::ffi::{OsStr, OsString}; -use std::os::unix::ffi::{OsStrExt, OsStringExt}; -use std::{fs::File, mem::size_of, path::PathBuf}; +use { + crate::{auxv::AuxvType, errors::MapsReaderError}, + byteorder::{NativeEndian, ReadBytesExt}, + goblin::elf, + memmap2::{Mmap, MmapOptions}, + procfs_core::process::{MMPermissions, MMapPath, MemoryMaps}, + std::{ + ffi::{OsStr, OsString}, + fs::File, + mem::size_of, + os::unix::ffi::{OsStrExt, OsStringExt}, + path::PathBuf, + }, +}; pub const LINUX_GATE_LIBRARY_NAME: &str = "linux-gate.so"; pub const DELETED_SUFFIX: &[u8] = b" (deleted)"; type Result = std::result::Result; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)] pub struct SystemMappingInfo { pub start_address: usize, pub end_address: usize, @@ -21,7 +26,7 @@ pub struct SystemMappingInfo { // One of these is produced for each mapping in the process (i.e. line in // /proc/$x/maps). -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)] pub struct MappingInfo { // On Android, relocation packing can mean that the reported start // address of the mapping must be adjusted by a bias in order to @@ -88,7 +93,10 @@ impl MappingInfo { self.start_address + self.size } - pub fn aggregate(memory_maps: MemoryMaps, linux_gate_loc: AuxvType) -> Result> { + pub fn aggregate( + memory_maps: MemoryMaps, + linux_gate_loc: Option, + ) -> Result> { let mut infos = Vec::::new(); for mm in memory_maps { @@ -112,9 +120,11 @@ impl MappingInfo { let is_path = is_mapping_a_path(pathname.as_deref()); - if !is_path && linux_gate_loc != 0 && start_address == linux_gate_loc.try_into()? { - pathname = Some(LINUX_GATE_LIBRARY_NAME.into()); - offset = 0; + if let Some(linux_gate_loc) = linux_gate_loc.map(|u| usize::try_from(u).unwrap()) { + if !is_path && start_address == linux_gate_loc { + pathname = Some(LINUX_GATE_LIBRARY_NAME.into()); + offset = 0; + } } if let Some(prev_module) = infos.last_mut() { @@ -451,7 +461,7 @@ mod tests { fn get_mappings_for(map: &str, linux_gate_loc: u64) -> Vec { MappingInfo::aggregate( MemoryMaps::from_read(map.as_bytes()).expect("failed to read mapping info"), - linux_gate_loc, + Some(linux_gate_loc), ) .unwrap_or_default() } diff --git a/third_party/rust/minidump-writer/src/linux/mem_reader.rs b/third_party/rust/minidump-writer/src/linux/mem_reader.rs index e4a504117787..9d04285dc85f 100644 --- a/third_party/rust/minidump-writer/src/linux/mem_reader.rs +++ b/third_party/rust/minidump-writer/src/linux/mem_reader.rs @@ -258,7 +258,7 @@ impl PtraceDumper { src: usize, length: usize, ) -> Result, crate::errors::DumperError> { - let length = std::num::NonZeroUsize::new(length).ok_or_else(|| { + let length = std::num::NonZeroUsize::new(length).ok_or( crate::errors::DumperError::CopyFromProcessError(CopyFromProcessError { src, child: pid, @@ -268,8 +268,8 @@ impl PtraceDumper { // as EINVAL could also come from the syscalls that actually read // memory as well which could be confusing source: nix::errno::Errno::EINVAL, - }) - })?; + }), + )?; let mut mem = MemReader::new(pid); Ok(mem.read_to_vec(src, length)?) diff --git a/third_party/rust/minidump-writer/src/linux/minidump_writer.rs b/third_party/rust/minidump-writer/src/linux/minidump_writer.rs index ba6b82ecaa17..0c6e385a12de 100644 --- a/third_party/rust/minidump-writer/src/linux/minidump_writer.rs +++ b/third_party/rust/minidump-writer/src/linux/minidump_writer.rs @@ -1,23 +1,26 @@ pub use crate::linux::auxv::{AuxvType, DirectAuxvDumpInfo}; -use crate::{ - auxv::AuxvDumpInfo, - dir_section::{DirSection, DumpBuf}, - linux::{ - app_memory::AppMemoryList, - crash_context::CrashContext, - dso_debug, - errors::{InitError, WriterError}, - maps_reader::{MappingInfo, MappingList}, - ptrace_dumper::PtraceDumper, - sections::*, +use { + crate::{ + auxv::AuxvDumpInfo, + dir_section::{DirSection, DumpBuf}, + linux::{ + app_memory::AppMemoryList, + crash_context::CrashContext, + dso_debug, + errors::WriterError, + maps_reader::{MappingInfo, MappingList}, + ptrace_dumper::PtraceDumper, + sections::*, + }, + mem_writer::{Buffer, MemoryArrayWriter, MemoryWriter, MemoryWriterError}, + minidump_format::*, + Pid, + }, + error_graph::{ErrorList, WriteErrorList}, + std::{ + io::{Seek, Write}, + time::Duration, }, - mem_writer::{Buffer, MemoryArrayWriter, MemoryWriter, MemoryWriterError}, - minidump_format::*, - Pid, -}; -use std::{ - io::{Seek, Write}, - time::Duration, }; pub enum CrashingThreadContext { @@ -144,8 +147,24 @@ impl MinidumpWriter { .clone() .map(AuxvDumpInfo::from) .unwrap_or_default(); - let mut dumper = PtraceDumper::new(self.process_id, self.stop_timeout, auxv)?; - dumper.suspend_threads()?; + + let mut soft_errors = ErrorList::default(); + + let mut dumper = PtraceDumper::new_report_soft_errors( + self.process_id, + self.stop_timeout, + auxv, + soft_errors.subwriter(WriterError::InitErrors), + )?; + + let threads_count = dumper.threads.len(); + + dumper.suspend_threads(soft_errors.subwriter(WriterError::SuspendThreadsErrors)); + + if dumper.threads.is_empty() { + soft_errors.push(WriterError::SuspendNoThreadsLeft(threads_count)); + } + dumper.late_init()?; if self.skip_stacks_if_mapping_unreferenced { @@ -154,16 +173,12 @@ impl MinidumpWriter { } if !self.crash_thread_references_principal_mapping(&dumper) { - return Err(InitError::PrincipalMappingNotReferenced.into()); + soft_errors.push(WriterError::PrincipalMappingNotReferenced); } } let mut buffer = Buffer::with_capacity(0); - self.generate_dump(&mut buffer, &mut dumper, destination)?; - - // dumper would resume threads in drop() automatically, - // but in case there is an error, we want to catch it - dumper.resume_threads()?; + self.generate_dump(&mut buffer, &mut dumper, soft_errors, destination)?; Ok(buffer.into()) } @@ -226,11 +241,12 @@ impl MinidumpWriter { &mut self, buffer: &mut DumpBuf, dumper: &mut PtraceDumper, + mut soft_errors: ErrorList, destination: &mut (impl Write + Seek), ) -> Result<()> { // A minidump file contains a number of tagged streams. This is the number // of streams which we write. - let num_writers = 17u32; + let num_writers = 18u32; let mut header_section = MemoryWriter::::alloc(buffer)?; @@ -270,7 +286,10 @@ impl MinidumpWriter { let dirent = exception_stream::write(self, buffer)?; dir_section.write_to_file(buffer, Some(dirent))?; - let dirent = systeminfo_stream::write(buffer)?; + let dirent = systeminfo_stream::write( + buffer, + soft_errors.subwriter(WriterError::WriteSystemInfoErrors), + )?; dir_section.write_to_file(buffer, Some(dirent))?; let dirent = memory_info_list_stream::write(self, buffer)?; @@ -281,7 +300,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxCpuInfo as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteCpuInfoFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -291,7 +313,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxProcStatus as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteThreadProcStatusFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -303,7 +328,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxLsbRelease as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteOsReleaseInfoFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -313,7 +341,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxCmdLine as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteCommandLineFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -323,7 +354,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxEnviron as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteEnvironmentFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -332,7 +366,10 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxAuxv as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteAuxvFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; @@ -341,12 +378,21 @@ impl MinidumpWriter { stream_type: MDStreamType::LinuxMaps as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteMapsFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; - let dirent = dso_debug::write_dso_debug_stream(buffer, self.process_id, &dumper.auxv) - .unwrap_or_default(); + let dirent = match dso_debug::write_dso_debug_stream(buffer, self.process_id, &dumper.auxv) + { + Ok(dirent) => dirent, + Err(e) => { + soft_errors.push(WriterError::WriteDSODebugStreamFailed(e)); + Default::default() + } + }; dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/limits", self.blamed_thread)) @@ -355,17 +401,43 @@ impl MinidumpWriter { stream_type: MDStreamType::MozLinuxLimits as u32, location, }, - Err(_) => Default::default(), + Err(e) => { + soft_errors.push(WriterError::WriteLimitsFailed(e)); + Default::default() + } }; dir_section.write_to_file(buffer, Some(dirent))?; let dirent = thread_names_stream::write(buffer, dumper)?; dir_section.write_to_file(buffer, Some(dirent))?; - // This section is optional, so we ignore errors when writing it - if let Ok(dirent) = handle_data_stream::write(self, buffer) { - let _ = dir_section.write_to_file(buffer, Some(dirent)); - } + let dirent = match handle_data_stream::write(self, buffer) { + Ok(dirent) => dirent, + Err(e) => { + soft_errors.push(WriterError::WriteHandleDataStreamFailed(e)); + Default::default() + } + }; + dir_section.write_to_file(buffer, Some(dirent))?; + + // ======================================================================================== + // + // PAST THIS BANNER, THE THREADS ARE RUNNING IN THE TARGET PROCESS AGAIN. IF YOU NEED TO + // ADD NEW ENTRIES THAT ACCESS THE TARGET MEMORY, DO IT BEFORE HERE! + // + // ======================================================================================== + + // Collect any last-minute soft errors when trying to restart threads + dumper.resume_threads(soft_errors.subwriter(WriterError::ResumeThreadsErrors)); + + // If this fails, there's really nothing we can do about that (other than ignore it). + let dirent = write_soft_errors(buffer, soft_errors) + .map(|location| MDRawDirectory { + stream_type: MDStreamType::MozSoftErrors as u32, + location, + }) + .unwrap_or_default(); + dir_section.write_to_file(buffer, Some(dirent))?; // If you add more directory entries, don't forget to update num_writers, above. Ok(()) @@ -383,3 +455,13 @@ impl MinidumpWriter { Ok(section.location()) } } + +fn write_soft_errors( + buffer: &mut DumpBuf, + soft_errors: ErrorList, +) -> Result { + let soft_errors_json_str = + serde_json::to_string_pretty(&soft_errors).map_err(WriterError::ConvertToJsonFailed)?; + let section = MemoryArrayWriter::write_bytes(buffer, soft_errors_json_str.as_bytes()); + Ok(section.location()) +} diff --git a/third_party/rust/minidump-writer/src/linux/module_reader.rs b/third_party/rust/minidump-writer/src/linux/module_reader.rs index f40e28cca633..ff4c6aecd644 100644 --- a/third_party/rust/minidump-writer/src/linux/module_reader.rs +++ b/third_party/rust/minidump-writer/src/linux/module_reader.rs @@ -36,7 +36,7 @@ impl<'buf> From<&'buf [u8]> for ProcessMemory<'buf> { } } -impl<'buf> From for ProcessMemory<'buf> { +impl From for ProcessMemory<'_> { fn from(value: ProcessReader) -> Self { Self::Process(value) } @@ -207,7 +207,7 @@ impl<'a> DynIter<'a> { } } -impl<'a> Iterator for DynIter<'a> { +impl Iterator for DynIter<'_> { type Item = Result; fn next(&mut self) -> Option { @@ -427,9 +427,9 @@ impl<'buf> ModuleReader<'buf> { let name = self .module_memory .read(strtab_offset + name_offset, strtab_size - name_offset)?; - return CStr::from_bytes_until_nul(&name) + CStr::from_bytes_until_nul(&name) .map(|s| s.to_string_lossy().into_owned()) - .map_err(|_| Error::StrTabNoNulByte); + .map_err(|_| Error::StrTabNoNulByte) } fn section_offset(&self, header: &elf::SectionHeader) -> u64 { diff --git a/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs b/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs index 66f36564b926..7b04a2f58a4d 100644 --- a/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs +++ b/third_party/rust/minidump-writer/src/linux/ptrace_dumper.rs @@ -1,28 +1,43 @@ +use { + super::{ + auxv::AuxvError, + errors::{AndroidError, MapsReaderError}, + serializers::*, + }, + crate::{ + linux::{ + auxv::AuxvDumpInfo, + errors::{DumperError, ThreadInfoError}, + maps_reader::MappingInfo, + module_reader, + thread_info::ThreadInfo, + Pid, + }, + serializers::*, + }, + error_graph::{ErrorList, WriteErrorList}, + failspot::failspot, + nix::{ + errno::Errno, + sys::{ptrace, signal, wait}, + }, + procfs_core::{ + process::{MMPermissions, ProcState, Stat}, + FromRead, ProcError, + }, + std::{ + ffi::OsString, + path, + result::Result, + time::{Duration, Instant}, + }, + thiserror::Error, +}; + #[cfg(target_os = "android")] use crate::linux::android::late_process_mappings; -use crate::linux::{ - auxv::AuxvDumpInfo, - errors::{DumperError, InitError, ThreadInfoError}, - maps_reader::MappingInfo, - module_reader, - thread_info::ThreadInfo, - Pid, -}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use crate::thread_info; -use nix::{ - errno::Errno, - sys::{ptrace, signal, wait}, -}; -use procfs_core::{ - process::{MMPermissions, ProcState, Stat}, - FromRead, ProcError, -}; -use std::{ - path, - result::Result, - time::{Duration, Instant}, -}; #[derive(Debug, Clone)] pub struct Thread { @@ -48,24 +63,91 @@ pub const AT_SYSINFO_EHDR: u64 = 33; impl Drop for PtraceDumper { fn drop(&mut self) { // Always try to resume all threads (e.g. in case of error) - let _ = self.resume_threads(); + self.resume_threads(error_graph::strategy::DontCare); // Always allow the process to continue. let _ = self.continue_process(); } } -#[derive(Debug, thiserror::Error)] -enum StopProcessError { +#[derive(Debug, Error, serde::Serialize)] +pub enum InitError { + #[error("failed to read auxv")] + ReadAuxvFailed(#[source] crate::auxv::AuxvError), + #[error("IO error for file {0}")] + IOError( + String, + #[source] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), + #[error("Failed Android specific late init")] + AndroidLateInitError(#[from] AndroidError), + #[error("Failed to read the page size")] + PageSizeError( + #[from] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), + #[error("Ptrace does not function within the same process")] + CannotPtraceSameProcess, + #[error("Failed to stop the target process")] + StopProcessFailed(#[source] StopProcessError), + #[error("Errors occurred while filling missing Auxv info")] + FillMissingAuxvInfoErrors(#[source] ErrorList), + #[error("Failed filling missing Auxv info")] + FillMissingAuxvInfoFailed(#[source] AuxvError), + #[error("Failed reading proc/pid/task entry for process")] + ReadProcessThreadEntryFailed( + #[source] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), + #[error("Process task entry `{0:?}` could not be parsed as a TID")] + ProcessTaskEntryNotTid(OsString), + #[error("Failed to read thread name")] + ReadThreadNameFailed( + #[source] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), + #[error("Proc task directory `{0:?}` is not a directory")] + ProcPidTaskNotDirectory(String), + #[error("Errors while enumerating threads")] + EnumerateThreadsErrors(#[source] ErrorList), + #[error("Failed to enumerate threads")] + EnumerateThreadsFailed(#[source] Box), + #[error("Failed to read process map file")] + ReadProcessMapFileFailed( + #[source] + #[serde(serialize_with = "serialize_proc_error")] + ProcError, + ), + #[error("Failed to aggregate process mappings")] + AggregateMappingsFailed(#[source] MapsReaderError), + #[error("Failed to enumerate process mappings")] + EnumerateMappingsFailed(#[source] Box), +} + +#[derive(Debug, thiserror::Error, serde::Serialize)] +pub enum StopProcessError { #[error("Failed to stop the process")] - Stop(#[from] Errno), + Stop( + #[from] + #[serde(serialize_with = "serialize_nix_error")] + nix::Error, + ), #[error("Failed to get the process state")] - State(#[from] ProcError), + State( + #[from] + #[serde(serialize_with = "serialize_proc_error")] + ProcError, + ), #[error("Timeout waiting for process to stop")] Timeout, } #[derive(Debug, thiserror::Error)] -enum ContinueProcessError { +pub enum ContinueProcessError { #[error("Failed to continue the process")] Continue(#[from] Errno), } @@ -88,8 +170,13 @@ fn ptrace_detach(child: Pid) -> Result<(), DumperError> { impl PtraceDumper { /// Constructs a dumper for extracting information from the specified process id - pub fn new(pid: Pid, stop_timeout: Duration, auxv: AuxvDumpInfo) -> Result { - if pid == std::process::id() as _ { + pub fn new_report_soft_errors( + pid: Pid, + stop_timeout: Duration, + auxv: AuxvDumpInfo, + soft_errors: impl WriteErrorList, + ) -> Result { + if pid == std::process::id() as i32 { return Err(InitError::CannotPtraceSameProcess); } @@ -101,23 +188,43 @@ impl PtraceDumper { mappings: Vec::new(), page_size: 0, }; - dumper.init(stop_timeout)?; + dumper.init(stop_timeout, soft_errors)?; Ok(dumper) } // TODO: late_init for chromeos and android - pub fn init(&mut self, stop_timeout: Duration) -> Result<(), InitError> { + pub fn init( + &mut self, + stop_timeout: Duration, + mut soft_errors: impl WriteErrorList, + ) -> Result<(), InitError> { // Stopping the process is best-effort. if let Err(e) = self.stop_process(stop_timeout) { - log::warn!("failed to stop process {}: {e}", self.pid); + soft_errors.push(InitError::StopProcessFailed(e)); } - if let Err(e) = self.auxv.try_filling_missing_info(self.pid) { - log::warn!("failed trying to fill in missing auxv info: {e}"); + // Even if we completely fail to fill in any additional Auxv info, we can still press + // forward. + if let Err(e) = self.auxv.try_filling_missing_info( + self.pid, + soft_errors.subwriter(InitError::FillMissingAuxvInfoErrors), + ) { + soft_errors.push(InitError::FillMissingAuxvInfoFailed(e)); + } + + // If we completely fail to enumerate any threads... Some information is still better than + // no information! + if let Err(e) = + self.enumerate_threads(soft_errors.subwriter(InitError::EnumerateThreadsErrors)) + { + soft_errors.push(InitError::EnumerateThreadsFailed(Box::new(e))); + } + + // Same with mappings -- Some information is still better than no information! + if let Err(e) = self.enumerate_mappings() { + soft_errors.push(InitError::EnumerateMappingsFailed(Box::new(e))); } - self.enumerate_threads()?; - self.enumerate_mappings()?; self.page_size = nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE)? .expect("page size apparently unlimited: doesn't make sense.") as usize; @@ -207,42 +314,44 @@ impl PtraceDumper { ptrace_detach(child) } - pub fn suspend_threads(&mut self) -> Result<(), DumperError> { - let threads_count = self.threads.len(); + pub fn suspend_threads(&mut self, mut soft_errors: impl WriteErrorList) { // Iterate over all threads and try to suspend them. // If the thread either disappeared before we could attach to it, or if // it was part of the seccomp sandbox's trusted code, it is OK to // silently drop it from the minidump. - self.threads.retain(|x| Self::suspend_thread(x.tid).is_ok()); + self.threads.retain(|x| match Self::suspend_thread(x.tid) { + Ok(()) => true, + Err(e) => { + soft_errors.push(e); + false + } + }); - if self.threads.is_empty() { - Err(DumperError::SuspendNoThreadsLeft(threads_count)) - } else { - self.threads_suspended = true; - Ok(()) - } + self.threads_suspended = true; + + failspot::failspot!(::SuspendThreads soft_errors.push(DumperError::PtraceAttachError(1234, nix::Error::EPERM))) } - pub fn resume_threads(&mut self) -> Result<(), DumperError> { - let mut result = Ok(()); + pub fn resume_threads(&mut self, mut soft_errors: impl WriteErrorList) { if self.threads_suspended { for thread in &self.threads { match Self::resume_thread(thread.tid) { - Ok(_) => {} - x => { - result = x; + Ok(()) => (), + Err(e) => { + soft_errors.push(e); } } } } self.threads_suspended = false; - result } /// Send SIGSTOP to the process so that we can get a consistent state. /// /// This will block waiting for the process to stop until `timeout` has passed. fn stop_process(&mut self, timeout: Duration) -> Result<(), StopProcessError> { + failspot!(StopProcess bail(nix::Error::EPERM)); + signal::kill(nix::unistd::Pid::from_raw(self.pid), Some(signal::SIGSTOP))?; // Something like waitpid for non-child processes would be better, but we have no such @@ -273,30 +382,54 @@ impl PtraceDumper { /// Parse /proc/$pid/task to list all the threads of the process identified by /// pid. - fn enumerate_threads(&mut self) -> Result<(), InitError> { + fn enumerate_threads( + &mut self, + mut soft_errors: impl WriteErrorList, + ) -> Result<(), InitError> { let pid = self.pid; let filename = format!("/proc/{}/task", pid); let task_path = path::PathBuf::from(&filename); - if task_path.is_dir() { - std::fs::read_dir(task_path) - .map_err(|e| InitError::IOError(filename, e))? - .filter_map(|entry| entry.ok()) // Filter out bad entries - .filter_map(|entry| { - entry - .file_name() // Parse name to Pid, filter out those that are unparsable - .to_str() - .and_then(|name| name.parse::().ok()) - }) - .map(|tid| { - // Read the thread-name (if there is any) - let name = std::fs::read_to_string(format!("/proc/{}/task/{}/comm", pid, tid)) - // NOTE: This is a bit wasteful as it does two allocations in order to trim, but leaving it for now - .map(|s| s.trim_end().to_string()) - .ok(); - (tid, name) - }) - .for_each(|(tid, name)| self.threads.push(Thread { tid, name })); + if !task_path.is_dir() { + return Err(InitError::ProcPidTaskNotDirectory(filename)); } + + for entry in std::fs::read_dir(task_path).map_err(|e| InitError::IOError(filename, e))? { + let entry = match entry { + Ok(entry) => entry, + Err(e) => { + soft_errors.push(InitError::ReadProcessThreadEntryFailed(e)); + continue; + } + }; + let file_name = entry.file_name(); + let tid = match file_name.to_str().and_then(|name| name.parse::().ok()) { + Some(tid) => tid, + None => { + soft_errors.push(InitError::ProcessTaskEntryNotTid(file_name)); + continue; + } + }; + + // Read the thread-name (if there is any) + let name_result = failspot!(if ThreadName { + Err(std::io::Error::other( + "testing requested failure reading thread name", + )) + } else { + std::fs::read_to_string(format!("/proc/{}/task/{}/comm", pid, tid)) + }); + + let name = match name_result { + Ok(name) => Some(name.trim_end().to_string()), + Err(e) => { + soft_errors.push(InitError::ReadThreadNameFailed(e)); + None + } + }; + + self.threads.push(Thread { tid, name }); + } + Ok(()) } @@ -308,39 +441,34 @@ impl PtraceDumper { // case its entry when creating the list of mappings. // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more // information. - let linux_gate_loc = self.auxv.get_linux_gate_address().unwrap_or_default(); + let maps_path = format!("/proc/{}/maps", self.pid); + let maps_file = + std::fs::File::open(&maps_path).map_err(|e| InitError::IOError(maps_path, e))?; + + let maps = procfs_core::process::MemoryMaps::from_read(maps_file) + .map_err(InitError::ReadProcessMapFileFailed)?; + + self.mappings = MappingInfo::aggregate(maps, self.auxv.get_linux_gate_address()) + .map_err(InitError::AggregateMappingsFailed)?; + // Although the initial executable is usually the first mapping, it's not // guaranteed (see http://crosbug.com/25355); therefore, try to use the // actual entry point to find the mapping. - let entry_point_loc = self.auxv.get_entry_address().unwrap_or_default(); - let filename = format!("/proc/{}/maps", self.pid); - let errmap = |e| InitError::IOError(filename.clone(), e); - let maps_path = path::PathBuf::from(&filename); - let maps_file = std::fs::File::open(maps_path).map_err(errmap)?; - - use procfs_core::FromRead; - self.mappings = procfs_core::process::MemoryMaps::from_read(maps_file) - .ok() - .and_then(|maps| MappingInfo::aggregate(maps, linux_gate_loc).ok()) - .unwrap_or_default(); - - if entry_point_loc != 0 { - let mut swap_idx = None; - for (idx, module) in self.mappings.iter().enumerate() { - // If this module contains the entry-point, and it's not already the first - // one, then we need to make it be first. This is because the minidump - // format assumes the first module is the one that corresponds to the main - // executable (as codified in - // processor/minidump.cc:MinidumpModuleList::GetMainModule()). - if entry_point_loc >= module.start_address.try_into().unwrap() - && entry_point_loc < (module.start_address + module.size).try_into().unwrap() - { - swap_idx = Some(idx); - break; - } - } - if let Some(idx) = swap_idx { - self.mappings.swap(0, idx); + if let Some(entry_point_loc) = self + .auxv + .get_entry_address() + .map(|u| usize::try_from(u).unwrap()) + { + // If this module contains the entry-point, and it's not already the first + // one, then we need to make it be first. This is because the minidump + // format assumes the first module is the one that corresponds to the main + // executable (as codified in + // processor/minidump.cc:MinidumpModuleList::GetMainModule()). + if let Some(entry_mapping_idx) = self.mappings.iter().position(|mapping| { + (mapping.start_address..mapping.start_address + mapping.size) + .contains(&entry_point_loc) + }) { + self.mappings.swap(0, entry_mapping_idx); } } Ok(()) diff --git a/third_party/rust/minidump-writer/src/linux/sections/systeminfo_stream.rs b/third_party/rust/minidump-writer/src/linux/sections/systeminfo_stream.rs index a298c00d1531..62ca332caef8 100644 --- a/third_party/rust/minidump-writer/src/linux/sections/systeminfo_stream.rs +++ b/third_party/rust/minidump-writer/src/linux/sections/systeminfo_stream.rs @@ -1,7 +1,12 @@ -use super::*; -use crate::linux::dumper_cpu_info as dci; +use { + super::*, crate::linux::dumper_cpu_info as dci, error_graph::WriteErrorList, + errors::SectionSystemInfoError, +}; -pub fn write(buffer: &mut DumpBuf) -> Result { +pub fn write( + buffer: &mut DumpBuf, + mut soft_errors: impl WriteErrorList, +) -> Result { let mut info_section = MemoryWriter::::alloc(buffer)?; let dirent = MDRawDirectory { stream_type: MDStreamType::SystemInfoStream as u32, @@ -16,7 +21,9 @@ pub fn write(buffer: &mut DumpBuf) -> Result( + error: &goblin::error::Error, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} +/// Serialize [nix::Error] +pub fn serialize_nix_error( + error: &nix::Error, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} +/// Serialize [procfs_core::ProcError] +pub fn serialize_proc_error( + error: &procfs_core::ProcError, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} +/// Serialize [std::string::FromUtf8Error] +pub fn serialize_from_utf8_error( + error: &std::string::FromUtf8Error, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} +/// Serialize [std::time::SystemTimeError] +pub fn serialize_system_time_error( + error: &std::time::SystemTimeError, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} diff --git a/third_party/rust/minidump-writer/src/mem_writer.rs b/third_party/rust/minidump-writer/src/mem_writer.rs index a703d2b11e3d..ae38c79b0018 100644 --- a/third_party/rust/minidump-writer/src/mem_writer.rs +++ b/third_party/rust/minidump-writer/src/mem_writer.rs @@ -1,14 +1,31 @@ -use crate::minidump_format::{MDLocationDescriptor, MDRVA}; -use scroll::ctx::{SizeWith, TryIntoCtx}; +use { + crate::{ + minidump_format::{MDLocationDescriptor, MDRVA}, + serializers::*, + }, + scroll::ctx::{SizeWith, TryIntoCtx}, +}; -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror::Error, serde::Serialize)] pub enum MemoryWriterError { #[error("IO error when writing to DumpBuf")] - IOError(#[from] std::io::Error), + IOError( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), #[error("Failed integer conversion")] - TryFromIntError(#[from] std::num::TryFromIntError), + TryFromIntError( + #[from] + #[serde(skip)] + std::num::TryFromIntError, + ), #[error("Failed to write to buffer")] - Scroll(#[from] scroll::Error), + Scroll( + #[from] + #[serde(serialize_with = "serialize_scroll_error")] + scroll::Error, + ), } type WriteResult = std::result::Result; diff --git a/third_party/rust/minidump-writer/src/serializers.rs b/third_party/rust/minidump-writer/src/serializers.rs new file mode 100644 index 000000000000..a42313dab295 --- /dev/null +++ b/third_party/rust/minidump-writer/src/serializers.rs @@ -0,0 +1,30 @@ +//! Functions used by Serde to serialize types that we don't own (and thus can't implement +//! [Serialize] for) + +use serde::Serializer; +/// Useful for types that implement [Error][std::error::Error] and don't need any special +/// treatment. +pub fn serialize_generic_error( + error: &E, + serializer: S, +) -> Result { + // I guess we'll have to see if it's more useful to store the debug representation of a + // foreign error type or something else (like maybe iterating its error chain into a + // list?) + let dbg = format!("{error:#?}"); + serializer.serialize_str(&dbg) +} +/// Serialize [std::io::Error] +pub fn serialize_io_error( + error: &std::io::Error, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} +/// Serialize [scroll::Error] +pub fn serialize_scroll_error( + error: &scroll::Error, + serializer: S, +) -> Result { + serialize_generic_error(error, serializer) +} diff --git a/third_party/rust/minidump-writer/tests/common/mod.rs b/third_party/rust/minidump-writer/tests/common/mod.rs index cf258819d948..2b5499ef8127 100644 --- a/third_party/rust/minidump-writer/tests/common/mod.rs +++ b/third_party/rust/minidump-writer/tests/common/mod.rs @@ -94,3 +94,38 @@ pub fn start_child_and_return(args: &[&str]) -> Child { .spawn() .expect("failed to execute child") } + +#[allow(unused)] +pub fn read_minidump_soft_errors_or_panic<'a, T>( + dump: &minidump::Minidump<'a, T>, +) -> serde_json::Value +where + T: std::ops::Deref + 'a, +{ + let contents = std::str::from_utf8( + dump.get_raw_stream(minidump_common::format::MINIDUMP_STREAM_TYPE::MozSoftErrors.into()) + .expect("missing soft error stream"), + ) + .expect("expected utf-8 stream"); + + serde_json::from_str(contents).expect("expected json") +} + +#[allow(unused)] +pub fn assert_soft_errors_in_minidump<'a, 'b, T, I>( + dump: &minidump::Minidump<'a, T>, + expected_errors: I, +) where + T: std::ops::Deref + 'a, + I: IntoIterator, +{ + let actual_json = read_minidump_soft_errors_or_panic(dump); + let actual_errors = actual_json.as_array().unwrap(); + + // Ensure that every error we expect is in the actual list somewhere + for expected_error in expected_errors { + assert!(actual_errors + .iter() + .any(|actual_error| actual_error == expected_error)); + } +} diff --git a/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs b/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs index f6a14e346add..d62f56ff09ea 100644 --- a/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs +++ b/third_party/rust/minidump-writer/tests/linux_minidump_writer.rs @@ -1,30 +1,32 @@ #![cfg(any(target_os = "linux", target_os = "android"))] #![allow(unused_imports, unused_variables)] -use minidump::*; -use minidump_common::format::{GUID, MINIDUMP_STREAM_TYPE::*}; -use minidump_writer::{ - app_memory::AppMemory, - crash_context::CrashContext, - errors::*, - maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}, - minidump_writer::MinidumpWriter, - module_reader::{BuildId, ReadFromModule}, - ptrace_dumper::PtraceDumper, - Pid, -}; -use nix::{errno::Errno, sys::signal::Signal}; -use procfs_core::process::MMPermissions; -use std::collections::HashSet; - -use std::{ - io::{BufRead, BufReader}, - os::unix::process::ExitStatusExt, - process::{Command, Stdio}, +use { + common::*, + minidump::*, + minidump_common::format::{GUID, MINIDUMP_STREAM_TYPE::*}, + minidump_writer::{ + app_memory::AppMemory, + crash_context::CrashContext, + errors::*, + maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}, + minidump_writer::MinidumpWriter, + module_reader::{BuildId, ReadFromModule}, + ptrace_dumper::PtraceDumper, + Pid, + }, + nix::{errno::Errno, sys::signal::Signal}, + procfs_core::process::MMPermissions, + serde_json::json, + std::{ + collections::HashSet, + io::{BufRead, BufReader}, + os::unix::process::ExitStatusExt, + process::{Command, Stdio}, + }, }; mod common; -use common::*; #[derive(Debug, PartialEq)] enum Context { @@ -299,6 +301,10 @@ contextual_test! { contextual_test! { fn skip_if_requested(context: Context) { + let expected_errors = vec![ + json!("PrincipalMappingNotReferenced"), + ]; + let num_of_threads = 1; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; @@ -331,7 +337,9 @@ contextual_test! { assert_eq!(waitres.code(), None); assert_eq!(status, Signal::SIGKILL as i32); - assert!(res.is_err()); + // Ensure the MozSoftErrors stream contains the expected errors + let dump = Minidump::read_path(tmpfile.path()).expect("failed to read minidump"); + assert_soft_errors_in_minidump(&dump, &expected_errors); } } @@ -790,6 +798,7 @@ fn memory_info_list_stream() { .dump(&mut tmpfile) .expect("cound not write minidump"); child.kill().expect("Failed to kill process"); + child.wait().expect("Failed to wait on killed process"); // Ensure the minidump has a MemoryInfoListStream present and has at least one entry. let dump = Minidump::read_path(tmpfile.path()).expect("failed to read minidump"); diff --git a/third_party/rust/minidump-writer/tests/linux_minidump_writer_soft_error.rs b/third_party/rust/minidump-writer/tests/linux_minidump_writer_soft_error.rs new file mode 100644 index 000000000000..5c5df2125a44 --- /dev/null +++ b/third_party/rust/minidump-writer/tests/linux_minidump_writer_soft_error.rs @@ -0,0 +1,92 @@ +#![cfg(any(target_os = "linux", target_os = "android"))] + +use { + common::*, + minidump::Minidump, + minidump_writer::{minidump_writer::MinidumpWriter, FailSpotName}, + serde_json::json, +}; + +mod common; + +#[test] +fn soft_error_stream() { + let mut child = start_child_and_wait_for_threads(1); + let pid = child.id() as i32; + + let mut tmpfile = tempfile::Builder::new() + .prefix("soft_error_stream") + .tempfile() + .unwrap(); + + let mut fail_client = FailSpotName::testing_client(); + fail_client.set_enabled(FailSpotName::StopProcess, true); + + // Write a minidump + MinidumpWriter::new(pid, pid) + .dump(&mut tmpfile) + .expect("cound not write minidump"); + child.kill().expect("Failed to kill process"); + child.wait().expect("Failed to wait on killed process"); + + // Ensure the minidump has a MozSoftErrors present + let dump = Minidump::read_path(tmpfile.path()).expect("failed to read minidump"); + read_minidump_soft_errors_or_panic(&dump); +} + +#[test] +fn soft_error_stream_content() { + let expected_errors = vec![ + json!({"InitErrors": [ + {"StopProcessFailed": {"Stop": "EPERM"}}, + {"FillMissingAuxvInfoErrors": ["InvalidFormat"]}, + {"EnumerateThreadsErrors": [ + {"ReadThreadNameFailed": "\ + Custom {\n \ + kind: Other,\n \ + error: \"testing requested failure reading thread name\",\n\ + }" + } + ]} + ]}), + json!({"SuspendThreadsErrors": [{"PtraceAttachError": [1234, "EPERM"]}]}), + json!({"WriteSystemInfoErrors": [ + {"WriteCpuInformationFailed": {"IOError": "\ + Custom {\n \ + kind: Other,\n \ + error: \"test requested cpuinfo file failure\",\n\ + }" + }} + ]}), + ]; + + let mut child = start_child_and_wait_for_threads(1); + let pid = child.id() as i32; + + let mut tmpfile = tempfile::Builder::new() + .prefix("soft_error_stream_content") + .tempfile() + .unwrap(); + + let mut fail_client = FailSpotName::testing_client(); + for name in [ + FailSpotName::StopProcess, + FailSpotName::FillMissingAuxvInfo, + FailSpotName::ThreadName, + FailSpotName::SuspendThreads, + FailSpotName::CpuInfoFileOpen, + ] { + fail_client.set_enabled(name, true); + } + + // Write a minidump + MinidumpWriter::new(pid, pid) + .dump(&mut tmpfile) + .expect("cound not write minidump"); + child.kill().expect("Failed to kill process"); + child.wait().expect("Failed to wait on killed process"); + + // Ensure the MozSoftErrors stream contains the expected errors + let dump = Minidump::read_path(tmpfile.path()).expect("failed to read minidump"); + assert_soft_errors_in_minidump(&dump, &expected_errors); +} diff --git a/third_party/rust/minidump-writer/tests/mac_minidump_writer.rs b/third_party/rust/minidump-writer/tests/mac_minidump_writer.rs index b2474b480dd5..d62a18d272c3 100644 --- a/third_party/rust/minidump-writer/tests/mac_minidump_writer.rs +++ b/third_party/rust/minidump-writer/tests/mac_minidump_writer.rs @@ -140,87 +140,87 @@ fn dump_external_process() { } } -/// Validates we can actually walk the stack for each thread in the minidump, -/// this is using minidump-processor, which (currently) depends on breakpad -/// symbols, however https://github.com/mozilla/dump_syms is not available as -/// a library https://github.com/mozilla/dump_syms/issues/253, so we just require -/// that it already be installed, hence the ignore -#[test] -fn stackwalks() { - if std::env::var("CI").is_ok() { - println!("test disabled, consistently times out because of potato runners"); - return; - } +// /// Validates we can actually walk the stack for each thread in the minidump, +// /// this is using minidump-processor, which (currently) depends on breakpad +// /// symbols, however https://github.com/mozilla/dump_syms is not available as +// /// a library https://github.com/mozilla/dump_syms/issues/253, so we just require +// /// that it already be installed, hence the ignore +// #[test] +// fn stackwalks() { +// if std::env::var("CI").is_ok() { +// println!("test disabled, consistently times out because of potato runners"); +// return; +// } - println!("generating minidump..."); - let md = capture_minidump("stackwalks", mach2::exception_types::EXC_BREAKPOINT); +// println!("generating minidump..."); +// let md = capture_minidump("stackwalks", mach2::exception_types::EXC_BREAKPOINT); - // Generate the breakpad symbols - println!("generating symbols..."); - dump_syms::dumper::single_file( - &dump_syms::dumper::Config { - output: dump_syms::dumper::Output::Store(".test-symbols".into()), - symbol_server: None, - debug_id: None, - code_id: None, - arch: if cfg!(target_arch = "aarch64") { - "arm64" - } else if cfg!(target_arch = "x86_64") { - "x86_64" - } else { - panic!("invalid MacOS target architecture") - }, - num_jobs: 2, // default this - check_cfi: false, - emit_inlines: false, - mapping_var: None, - mapping_src: None, - mapping_dest: None, - mapping_file: None, - }, - "target/debug/test", - ) - .expect("failed to dump symbols"); +// // Generate the breakpad symbols +// println!("generating symbols..."); +// dump_syms::dumper::single_file( +// &dump_syms::dumper::Config { +// output: dump_syms::dumper::Output::Store(".test-symbols".into()), +// symbol_server: None, +// debug_id: None, +// code_id: None, +// arch: if cfg!(target_arch = "aarch64") { +// "arm64" +// } else if cfg!(target_arch = "x86_64") { +// "x86_64" +// } else { +// panic!("invalid MacOS target architecture") +// }, +// num_jobs: 2, // default this +// check_cfi: false, +// emit_inlines: false, +// mapping_var: None, +// mapping_src: None, +// mapping_dest: None, +// mapping_file: None, +// }, +// "target/debug/test", +// ) +// .expect("failed to dump symbols"); - let provider = minidump_unwind::Symbolizer::new(minidump_unwind::simple_symbol_supplier(vec![ - ".test-symbols".into(), - ])); +// let provider = minidump_unwind::Symbolizer::new(minidump_unwind::simple_symbol_supplier(vec![ +// ".test-symbols".into(), +// ])); - let state = futures::executor::block_on(async { - minidump_processor::process_minidump(&md.minidump, &provider).await - }) - .unwrap(); +// let state = futures::executor::block_on(async { +// minidump_processor::process_minidump(&md.minidump, &provider).await +// }) +// .unwrap(); - //state.print(&mut std::io::stdout()).map_err(|_| ()).unwrap(); +// //state.print(&mut std::io::stdout()).map_err(|_| ()).unwrap(); - // We expect at least 2 threads, one of which is the fake crashing thread - let fake_crash_thread = state - .threads - .iter() - .find(|cs| cs.thread_id == md.thread) - .expect("failed to find crash thread"); +// // We expect at least 2 threads, one of which is the fake crashing thread +// let fake_crash_thread = state +// .threads +// .iter() +// .find(|cs| cs.thread_id == md.thread) +// .expect("failed to find crash thread"); - assert_eq!( - fake_crash_thread.thread_name.as_deref(), - Some("test-thread") - ); +// assert_eq!( +// fake_crash_thread.thread_name.as_deref(), +// Some("test-thread") +// ); - assert!( - fake_crash_thread.frames.iter().any(|sf| { - sf.function_name - .as_ref() - .map_or(false, |fname| fname.ends_with("wait_until_killed")) - }), - "unable to locate expected function" - ); +// assert!( +// fake_crash_thread.frames.iter().any(|sf| { +// sf.function_name +// .as_ref() +// .map_or(false, |fname| fname.ends_with("wait_until_killed")) +// }), +// "unable to locate expected function" +// ); - let mod_list: MinidumpModuleList = md - .minidump - .get_stream() - .expect("Couldn't find MinidumpModuleList"); +// let mod_list: MinidumpModuleList = md +// .minidump +// .get_stream() +// .expect("Couldn't find MinidumpModuleList"); - // Ensure we found dyld - assert!(mod_list - .iter() - .any(|module| &module.name == "/usr/lib/dyld")); -} +// // Ensure we found dyld +// assert!(mod_list +// .iter() +// .any(|module| &module.name == "/usr/lib/dyld")); +// } diff --git a/third_party/rust/minidump-writer/tests/ptrace_dumper.rs b/third_party/rust/minidump-writer/tests/ptrace_dumper.rs index 48c4fa2778f6..b166c256f783 100644 --- a/third_party/rust/minidump-writer/tests/ptrace_dumper.rs +++ b/third_party/rust/minidump-writer/tests/ptrace_dumper.rs @@ -1,13 +1,20 @@ //! All of these tests are specific to ptrace #![cfg(any(target_os = "linux", target_os = "android"))] -use minidump_writer::ptrace_dumper::PtraceDumper; -use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use nix::sys::signal::Signal; -use std::convert::TryInto; -use std::io::{BufRead, BufReader}; -use std::mem::size_of; -use std::os::unix::process::ExitStatusExt; +use { + error_graph::ErrorList, + minidump_writer::ptrace_dumper::PtraceDumper, + nix::{ + sys::mman::{mmap, MapFlags, ProtFlags}, + sys::signal::Signal, + }, + std::{ + convert::TryInto, + io::{BufRead, BufReader}, + mem::size_of, + os::unix::process::ExitStatusExt, + }, +}; mod common; use common::*; @@ -23,6 +30,13 @@ macro_rules! disabled_on_ci_and_android { }; } +macro_rules! assert_no_soft_errors(($n: ident, $e: expr) => {{ + let mut $n = ErrorList::default(); + let __result = $e; + assert!($n.is_empty(), "{:?}", $n); + __result +}}); + #[test] fn test_setup() { spawn_child("setup", &[]); @@ -91,14 +105,21 @@ fn test_thread_list_from_parent() { let num_of_threads = 5; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; - let mut dumper = PtraceDumper::new( - pid, - minidump_writer::minidump_writer::STOP_TIMEOUT, - Default::default(), + + let mut dumper = assert_no_soft_errors!( + soft_errors, + PtraceDumper::new_report_soft_errors( + pid, + minidump_writer::minidump_writer::STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + ) ) .expect("Couldn't init dumper"); + assert_eq!(dumper.threads.len(), num_of_threads); - dumper.suspend_threads().expect("Could not suspend threads"); + + assert_no_soft_errors!(soft_errors, dumper.suspend_threads(&mut soft_errors)); // let mut matching_threads = 0; for (idx, curr_thread) in dumper.threads.iter().enumerate() { @@ -146,7 +167,7 @@ fn test_thread_list_from_parent() { 0 }; */ } - dumper.resume_threads().expect("Failed to resume threads"); + assert_no_soft_errors!(soft_errors, dumper.resume_threads(&mut soft_errors)); child.kill().expect("Failed to kill process"); // Reap child @@ -272,14 +293,20 @@ fn test_sanitize_stack_copy() { let heap_addr = usize::from_str_radix(output.next().unwrap().trim_start_matches("0x"), 16) .expect("unable to parse mmap_addr"); - let mut dumper = PtraceDumper::new( - pid, - minidump_writer::minidump_writer::STOP_TIMEOUT, - Default::default(), + let mut dumper = assert_no_soft_errors!( + soft_errors, + PtraceDumper::new_report_soft_errors( + pid, + minidump_writer::minidump_writer::STOP_TIMEOUT, + Default::default(), + &mut soft_errors, + ) ) .expect("Couldn't init dumper"); assert_eq!(dumper.threads.len(), num_of_threads); - dumper.suspend_threads().expect("Could not suspend threads"); + + assert_no_soft_errors!(soft_errors, dumper.suspend_threads(&mut soft_errors)); + let thread_info = dumper .get_thread_info_by_index(0) .expect("Couldn't find thread_info"); @@ -374,7 +401,8 @@ fn test_sanitize_stack_copy() { assert_eq!(simulated_stack[0..size_of::()], defaced); - dumper.resume_threads().expect("Failed to resume threads"); + assert_no_soft_errors!(soft_errors, dumper.resume_threads(&mut soft_errors)); + child.kill().expect("Failed to kill process"); // Reap child diff --git a/third_party/rust/minidump/.cargo-checksum.json b/third_party/rust/minidump/.cargo-checksum.json index 8305b5d9b36c..e0781aed17e2 100644 --- a/third_party/rust/minidump/.cargo-checksum.json +++ b/third_party/rust/minidump/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ffe32239c2958904c0be971a991667397078fe6db3439350a8af4004af7f5473","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"f0fe4547fd7044ef4d06d902491be33a0fc13ba003c4e5af1965d6126907ced8","src/context.rs":"b271075155d33cce5c1f79ce4b1fd2f3335293d9a4344c3681e5825f3caeceb8","src/iostuff.rs":"eedeb0a9cf9f7d2af1558c916c73ec7287de5f4e45b4ff6b9a8013645f09b9e1","src/lib.rs":"a63adbdfbad839969998249ed6032d226557915761b12f9ee029c3766ec9507f","src/minidump.rs":"7a07e390b4790478f1f81208a81a59b9e8dc61fde1588c1c223f21ee21246859","src/strings.rs":"b55266f137550602733319fe6c3a83a6b84931c47ccdcfe13de72c40d3cea1df","src/system_info.rs":"96cbbd3239c388474e60690ef9250040c91331811f8ff06a10ed82b9f55e7455","tests/test_minidump.rs":"d9fb6b8ec7749d3bc6bf6de6b8a9a73d5934c81881a9d98087fcc490e8bb447d"},"package":"cee91aa51259518a08a12c18b5754e45135f89f1d9d7d6aae76ce93b92686698"} \ No newline at end of file +{"files":{"Cargo.toml":"d99d5b3c0c05fb956c6526ce35a3f27cb9e27b0cb78efea22ebd9afa0bf44e87","LICENSE":"06de63df29199a394442b57a28e886059ddc940973e10646877a0793fd53e2c9","README.md":"f0fe4547fd7044ef4d06d902491be33a0fc13ba003c4e5af1965d6126907ced8","src/context.rs":"2d999a7fd135738ca85236ecdc90a124272c85afdb0b8747e5da0454da137072","src/iostuff.rs":"eedeb0a9cf9f7d2af1558c916c73ec7287de5f4e45b4ff6b9a8013645f09b9e1","src/lib.rs":"a63adbdfbad839969998249ed6032d226557915761b12f9ee029c3766ec9507f","src/minidump.rs":"16abaa34f8a53849275499a7a5560ec597d8e1656df5b5d1e68169cd7f7ed485","src/strings.rs":"b55266f137550602733319fe6c3a83a6b84931c47ccdcfe13de72c40d3cea1df","src/system_info.rs":"96cbbd3239c388474e60690ef9250040c91331811f8ff06a10ed82b9f55e7455","tests/test_minidump.rs":"d9fb6b8ec7749d3bc6bf6de6b8a9a73d5934c81881a9d98087fcc490e8bb447d"},"package":"e03e301d414a75655d4ce80e6e3690fbfe70814b67c496c64c826ba558d18ec9"} \ No newline at end of file diff --git a/third_party/rust/minidump/Cargo.toml b/third_party/rust/minidump/Cargo.toml index 5c2bcd8e12c1..0940a7abfe5a 100644 --- a/third_party/rust/minidump/Cargo.toml +++ b/third_party/rust/minidump/Cargo.toml @@ -12,9 +12,10 @@ [package] edition = "2018" name = "minidump" -version = "0.22.1" +version = "0.24.0" authors = ["Ted Mielczarek "] build = false +autolib = false autobins = false autoexamples = false autotests = false @@ -55,13 +56,13 @@ version = "0.8" version = "0.9" [dependencies.minidump-common] -version = "0.22.1" +version = "0.24.0" [dependencies.num-traits] version = "0.2" [dependencies.procfs-core] -version = "0.16" +version = "0.17" default-features = false [dependencies.range-map] diff --git a/third_party/rust/minidump/src/context.rs b/third_party/rust/minidump/src/context.rs index 8b6e1afc91c5..e803a116277a 100644 --- a/third_party/rust/minidump/src/context.rs +++ b/third_party/rust/minidump/src/context.rs @@ -140,7 +140,7 @@ pub struct CpuRegisters<'a, T: ?Sized> { context: &'a T, } -impl<'a, T> Iterator for CpuRegisters<'a, T> +impl Iterator for CpuRegisters<'_, T> where T: CpuContext, { diff --git a/third_party/rust/minidump/src/minidump.rs b/third_party/rust/minidump/src/minidump.rs index e3888dd47505..170d2be9bcc2 100644 --- a/third_party/rust/minidump/src/minidump.rs +++ b/third_party/rust/minidump/src/minidump.rs @@ -601,7 +601,7 @@ pub enum UnifiedMemoryList<'a> { Memory(MinidumpMemoryList<'a>), Memory64(MinidumpMemory64List<'a>), } -impl<'a> Default for UnifiedMemoryList<'a> { +impl Default for UnifiedMemoryList<'_> { fn default() -> Self { Self::Memory(Default::default()) } @@ -1998,7 +1998,7 @@ impl<'a> MinidumpMemory<'a> { } } -impl<'a> MinidumpMemory64<'a> { +impl MinidumpMemory64<'_> { /// Write a human-readable description of this `MinidumpMemory64` to `f`. /// /// This is very verbose, it is the format used by `minidump_dump`. @@ -2184,7 +2184,7 @@ impl<'mdmp, Descriptor> MinidumpMemoryListBase<'mdmp, Descriptor> { } } -impl<'mdmp> MinidumpMemoryList<'mdmp> { +impl MinidumpMemoryList<'_> { /// Write a human-readable description of this `MinidumpMemoryList` to `f`. /// /// This is very verbose, it is the format used by `minidump_dump`. @@ -2205,7 +2205,7 @@ impl<'mdmp> MinidumpMemoryList<'mdmp> { } } -impl<'mdmp> MinidumpMemory64List<'mdmp> { +impl MinidumpMemory64List<'_> { /// Write a human-readable description of this `MinidumpMemory64List` to `f`. /// /// This is very verbose, it is the format used by `minidump_dump`. @@ -2281,7 +2281,7 @@ impl<'mdmp> UnifiedMemoryList<'mdmp> { } } -impl<'a, Descriptor> Default for MinidumpMemoryListBase<'a, Descriptor> { +impl Default for MinidumpMemoryListBase<'_, Descriptor> { fn default() -> Self { Self::new() } @@ -2406,7 +2406,7 @@ impl<'a> MinidumpStream<'a> for MinidumpMemoryInfoList<'a> { } } -impl<'a> Default for MinidumpMemoryInfoList<'a> { +impl Default for MinidumpMemoryInfoList<'_> { fn default() -> Self { Self::new() } @@ -2476,7 +2476,7 @@ impl<'mdmp> MinidumpMemoryInfoList<'mdmp> { } } -impl<'a> MinidumpMemoryInfo<'a> { +impl MinidumpMemoryInfo<'_> { /// Write a human-readable description. pub fn print(&self, f: &mut T) -> io::Result<()> { write!( @@ -2567,7 +2567,7 @@ impl<'a> MinidumpStream<'a> for MinidumpLinuxMaps<'a> { } } -impl<'a> Default for MinidumpLinuxMaps<'a> { +impl Default for MinidumpLinuxMaps<'_> { fn default() -> Self { Self::new() } @@ -2637,7 +2637,7 @@ impl<'mdmp> MinidumpLinuxMaps<'mdmp> { } } -impl<'a> MinidumpLinuxMapInfo<'a> { +impl MinidumpLinuxMapInfo<'_> { /// Write a human-readable description of this. pub fn print(&self, f: &mut T) -> io::Result<()> { write!( @@ -2692,7 +2692,7 @@ impl<'a> MinidumpLinuxMapInfo<'a> { } } -impl<'a> Default for UnifiedMemoryInfoList<'a> { +impl Default for UnifiedMemoryInfoList<'_> { fn default() -> Self { Self::Info(MinidumpMemoryInfoList::default()) } @@ -2811,7 +2811,7 @@ macro_rules! unified_memory_forward { }; } -impl<'a> UnifiedMemoryInfo<'a> { +impl UnifiedMemoryInfo<'_> { unified_memory_forward! { /// Write a human-readable description. pub fn print(&self, f: &mut T) -> io::Result<()>; @@ -3148,7 +3148,7 @@ impl<'a> MinidumpStream<'a> for MinidumpThreadInfoList { } } -impl<'a> MinidumpStream<'a> for MinidumpSystemInfo { +impl MinidumpStream<'_> for MinidumpSystemInfo { const STREAM_TYPE: u32 = MINIDUMP_STREAM_TYPE::SystemInfoStream as u32; fn read( @@ -3537,7 +3537,7 @@ impl RawMiscInfo { ); } -impl<'a> MinidumpStream<'a> for MinidumpMiscInfo { +impl MinidumpStream<'_> for MinidumpMiscInfo { const STREAM_TYPE: u32 = MINIDUMP_STREAM_TYPE::MiscInfoStream as u32; fn read( @@ -3667,7 +3667,7 @@ impl RawMacCrashInfo { ); } -impl<'a> MinidumpStream<'a> for MinidumpMacCrashInfo { +impl MinidumpStream<'_> for MinidumpMacCrashInfo { const STREAM_TYPE: u32 = MINIDUMP_STREAM_TYPE::MozMacosCrashInfoStream as u32; fn read( @@ -3826,7 +3826,7 @@ impl MinidumpMacCrashInfo { } } -impl<'a> MinidumpStream<'a> for MinidumpMacBootargs { +impl MinidumpStream<'_> for MinidumpMacBootargs { const STREAM_TYPE: u32 = MINIDUMP_STREAM_TYPE::MozMacosBootargsStream as u32; fn read( @@ -4145,7 +4145,7 @@ impl MinidumpMiscInfo { } } -impl<'a> MinidumpStream<'a> for MinidumpBreakpadInfo { +impl MinidumpStream<'_> for MinidumpBreakpadInfo { const STREAM_TYPE: u32 = MINIDUMP_STREAM_TYPE::BreakpadInfoStream as u32; fn read( diff --git a/third_party/rust/procfs-core/.cargo-checksum.json b/third_party/rust/procfs-core/.cargo-checksum.json index 11c6d0004f5d..c4f2d75ad86e 100644 --- a/third_party/rust/procfs-core/.cargo-checksum.json +++ b/third_party/rust/procfs-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"bf2944cc99c95272ba1114b998c83af42d5e64e64a6fb48b2f2a921c002d9077","README.md":"ac6e93e07291e148ba9e1913ceabee01d8882e0b7e263ee9287b20a2e500f599","src/cgroups.rs":"fda4941006913801ba0653d3b04924fd6e7cbebf5759814eef4e1176a94b4e91","src/cpuinfo.rs":"2ae02c7183d3ac50625a1958c447fa6d7da351c94e43fec388517a8d01718059","src/diskstats.rs":"e554dbaa8772a6e7cb857a052bd69191058a19b5c0aee4340f260ad8d53a6fba","src/iomem.rs":"2abfd4428ad6f4354ebcca210a8b765dc8b07d5e30f060dcf77cf8296f1e4d38","src/keyring.rs":"a7c156895c70454e453b7701b7036820e673aefe08d5a63ee517b65a4e66bf67","src/lib.rs":"4ae954f01c0886afe0cb196f5cfa38341b8557fc91aaaff95ee5b2f3765ad0ae","src/locks.rs":"5c26a0b39a4dae5951ef79b013856db3c69d8b279981065c71100a9e216a566a","src/meminfo.rs":"5bf226a7773c94db47bd53cbf642b15e72d67292429d20d7fbcd14c891c32622","src/mounts.rs":"181ae262cdd3cf08203fe73f2cd397da8b3db009c0a0c8acb6b22da13149fa67","src/net.rs":"a6a609d2bd2571ccc6fd2a5a9be9354bee5a9b874a913ab02bbdf46fa0968e3f","src/partitions.rs":"f6ea6482b80bfa59a6d90ddf05ea62707467c5cc7b791a490e0858a846dfcd2e","src/pressure.rs":"33a22c29d7f5c01603ad515e102d594235d01d176213668da547ee5634558992","src/process/clear_refs.rs":"59c885bfb839b72e6c2234c148a977146da02af8aadc6d7d24b5936aa42e4ebe","src/process/limit.rs":"3f449b0b266418099f3003c65b04c468a4c92845350aa35dd28cc13d7b7f656e","src/process/mod.rs":"2bd84aadb16a04b7c3ff48b9395ba36b85de979543a90d136c8d63aef0bd004d","src/process/mount.rs":"4ed4c468bd0f37c012b17154d69c214a46e52f059dd9121e07d2d29561fe52ee","src/process/namespaces.rs":"36b65fce5e1554dcce9019acb4cdc0dcc47420ef4336a7d9d97d8fc455ab3297","src/process/pagemap.rs":"0f1a7908dba734a26fbe044510f61c0df7ad00dbfcba6a2279064d2ca7aa8278","src/process/schedstat.rs":"cebbd598e03a765bcf59a22989e846fa78d660c4cb87623d07e594849cf0cf66","src/process/smaps_rollup.rs":"8d7d2c69fc6d54856d240a14ed6dfa4dcc92b8b29c3139fe651d18f2011a7575","src/process/stat.rs":"17849e16b79e34ec8c4c230f196d0e5f1eb756ddb013b3c97e3283b83ff5ef4f","src/process/status.rs":"81de4bd29df76aef0792e23f4f802fff1134ada059f2f4293d9a771a23aa5f02","src/sys/kernel/mod.rs":"54437f0a32eba1e6eaffa11ad041a2e914a16726cb2904af61131dbaa4bae31c","src/sys/mod.rs":"a7b744630e859005307046558f5e827e07b73cb0b5f1dd89acb02f21059e775c","src/sysvipc_shm.rs":"794b2ed9d2b20d25c6da220d6c7ac0b1b54219c9ebb0a1bf6ff9a11dd091f2a7","src/uptime.rs":"ffea251a2ba4da2a311b6a51606102771e55b2db1e33ced5b3569dde319b264b"},"package":"2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"} \ No newline at end of file +{"files":{"COPYRIGHT.txt":"9f595add2d755fc897ea3045cccbf7146acf51f8b5cf5d2669aee18634eef4bf","Cargo.toml":"507766f8c741f4cff4f69b7750af969560df8cd082f37b4d468fb1b273837932","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"c5bbf39118b0639bf8bd391ae0d7d81f25c1cb4066e0fdae6a405b20fb7ca170","README.md":"ac6e93e07291e148ba9e1913ceabee01d8882e0b7e263ee9287b20a2e500f599","src/cgroups.rs":"b96ce48ec7ba93045e1baa23fce4c6a8d209570892314cb8751e57e3386b0fa8","src/cpuinfo.rs":"5717b21bac1b8475550d9090f3ba77bf9f88ba84f37918038f9b9e8389122b9c","src/crypto.rs":"348dfd27896f299d0c421bf9b6bbc563e0bca915b5ea477acb50b10b9bfecf29","src/devices.rs":"332f5bfd3b2c5ff4eac19475bb025b7822ee8bd3c0332c04e2401b54f751cc01","src/diskstats.rs":"e554dbaa8772a6e7cb857a052bd69191058a19b5c0aee4340f260ad8d53a6fba","src/iomem.rs":"2abfd4428ad6f4354ebcca210a8b765dc8b07d5e30f060dcf77cf8296f1e4d38","src/keyring.rs":"a7c156895c70454e453b7701b7036820e673aefe08d5a63ee517b65a4e66bf67","src/kpageflags.rs":"628b445b72f7112e4dd78c3499228bd20ade1a4674d4485bfdf46cf929e10ad6","src/lib.rs":"582cd6ad12f4e3c5fc230f490a3b2d9ccc51229349866cabc051844de317746f","src/locks.rs":"5c26a0b39a4dae5951ef79b013856db3c69d8b279981065c71100a9e216a566a","src/meminfo.rs":"588691e31633a37bc8a265c151d35ef93a5b6dd15603e63579277ab66d91699f","src/mounts.rs":"181ae262cdd3cf08203fe73f2cd397da8b3db009c0a0c8acb6b22da13149fa67","src/net.rs":"938b1857e8170c21969026eb767dcdb6e500b22113400bd1add441aeeb2b2939","src/partitions.rs":"dbe7e9b774980a35450fbd164a3326fcf8774bdffab27b492f3835991570e65b","src/pressure.rs":"33a22c29d7f5c01603ad515e102d594235d01d176213668da547ee5634558992","src/process/clear_refs.rs":"59c885bfb839b72e6c2234c148a977146da02af8aadc6d7d24b5936aa42e4ebe","src/process/limit.rs":"3f449b0b266418099f3003c65b04c468a4c92845350aa35dd28cc13d7b7f656e","src/process/mod.rs":"2bd84aadb16a04b7c3ff48b9395ba36b85de979543a90d136c8d63aef0bd004d","src/process/mount.rs":"0387c79c35ccf7221badf5d6d92a35e8fd4e98bc3c97bbe9b34a7e4af64c0564","src/process/namespaces.rs":"36b65fce5e1554dcce9019acb4cdc0dcc47420ef4336a7d9d97d8fc455ab3297","src/process/pagemap.rs":"94e98463917e23144b9a109b46731443914fc6fc8c12c2730d3a6942f220c789","src/process/schedstat.rs":"cebbd598e03a765bcf59a22989e846fa78d660c4cb87623d07e594849cf0cf66","src/process/smaps_rollup.rs":"8d7d2c69fc6d54856d240a14ed6dfa4dcc92b8b29c3139fe651d18f2011a7575","src/process/stat.rs":"17849e16b79e34ec8c4c230f196d0e5f1eb756ddb013b3c97e3283b83ff5ef4f","src/process/status.rs":"81de4bd29df76aef0792e23f4f802fff1134ada059f2f4293d9a771a23aa5f02","src/sys/kernel/mod.rs":"54437f0a32eba1e6eaffa11ad041a2e914a16726cb2904af61131dbaa4bae31c","src/sys/mod.rs":"a7b744630e859005307046558f5e827e07b73cb0b5f1dd89acb02f21059e775c","src/sysvipc_shm.rs":"794b2ed9d2b20d25c6da220d6c7ac0b1b54219c9ebb0a1bf6ff9a11dd091f2a7","src/uptime.rs":"ffea251a2ba4da2a311b6a51606102771e55b2db1e33ced5b3569dde319b264b"},"package":"239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"} \ No newline at end of file diff --git a/third_party/rust/procfs-core/COPYRIGHT.txt b/third_party/rust/procfs-core/COPYRIGHT.txt new file mode 100644 index 000000000000..f22851cfb057 --- /dev/null +++ b/third_party/rust/procfs-core/COPYRIGHT.txt @@ -0,0 +1,483 @@ +The source code for the procfs library is copyright by Andrew Chin, 2019, and other contributors. + +It is licensed under either of + + * Apache License, Version 2.0, http://www.apache.org/licenses/LICENSE-2.0 + * MIT license, http://opensource.org/licenses/MIT + +at your option. + +The documentation of this library is derived from documentation written by others: + +* The proc(5) man page: + +Copyright (C) 1994, 1995 by Daniel Quinlan (quinlan@yggdrasil.com) +and Copyright (C) 2002-2008,2017 Michael Kerrisk +with networking additions from Alan Cox (A.Cox@swansea.ac.uk) +and scsi additions from Michael Neuffer (neuffer@mail.uni-mainz.de) +and sysctl additions from Andries Brouwer (aeb@cwi.nl) +and System V IPC (as well as various other) additions from +Michael Kerrisk + +Under the GPL Free Documentation License (reproduced below). + +* Other manual pages: + +Copyright (c) 2006, 2008 by Michael Kerrisk + +Under the following license: + + Permission is granted to make and distribute verbatim copies of this + manual provided the copyright notice and this permission notice are + preserved on all copies. + + Permission is granted to copy and distribute modified versions of this + manual under the conditions for verbatim copying, provided that the + entire resulting derived work is distributed under the terms of a + permission notice identical to this one. + + Since the Linux kernel and libraries are constantly changing, this + manual page may be incorrect or out-of-date. The author(s) assume no + responsibility for errors or omissions, or for damages resulting from + the use of the information contained herein. The author(s) may not + have taken the same level of care in the production of this manual, + which is licensed free of charge, as they might when working + professionally. + + Formatted or processed versions of this manual, if unaccompanied by + the source, must acknowledge the copyright and authors of this work. + +* The Linux Documentation Project: + +Copyright 2003 Binh Nguyen + +Under the GPL Free Documenation License. See: http://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/ln14.html + + +================================== +Below is a copy of the GPL license: + +This is free documentation; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +The GNU General Public License's references to "object code" +and "executables" are to be interpreted as the output of any +document formatting or typesetting system, including +intermediate and printed output. + +This manual is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public +License along with this manual; if not, see +. + + +================================== +A full copy of the GNU Free Documentation License, version 1.2, can be found here: +https://www.gnu.org/licenses/old-licenses/fdl-1.2.txt + +Below is a copy of this license: + + + GNU Free Documentation License + Version 1.2, November 2002 + + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + +0. PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +1. APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. + +A "Modified Version" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (Thus, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The "Invariant Sections" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. + +The "Cover Texts" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. + +A "Transparent" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not "Transparent" is called "Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML, PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML, PostScript or PDF produced by some word +processors for output purposes only. + +The "Title Page" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, "Title Page" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit of the Document whose +title either is precisely XYZ or contains XYZ in parentheses following +text that translates XYZ in another language. (Here XYZ stands for a +specific section name mentioned below, such as "Acknowledgements", +"Dedications", "Endorsements", or "History".) To "Preserve the Title" +of such a section when you modify the Document means that it remains a +section "Entitled XYZ" according to this definition. + +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. + + +2. VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. + + +3. COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. + + +4. MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission. +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has fewer than five), + unless they release you from this requirement. +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. +D. Preserve all the copyright notices of the Document. +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below. +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice. +H. Include an unaltered copy of this License. +I. Preserve the section Entitled "History", Preserve its Title, and add + to it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section Entitled "History" in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence. +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the "History" section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission. +K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the section all + the substance and tone of each of the contributor acknowledgements + and/or dedications given therein. +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles. +M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. +N. Do not retitle any existing section to be Entitled "Endorsements" + or to conflict in title with any Invariant Section. +O. Preserve any Warranty Disclaimers. + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. + + +5. COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections Entitled "History" +in the various original documents, forming one section Entitled +"History"; likewise combine any sections Entitled "Acknowledgements", +and any sections Entitled "Dedications". You must delete all sections +Entitled "Endorsements". + + +6. COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. + + +7. AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an "aggregate" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. + + +8. TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. + + +9. TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. + + +10. FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +https://www.gnu.org/licenses/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". + +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. + +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/third_party/rust/procfs-core/Cargo.toml b/third_party/rust/procfs-core/Cargo.toml index 79dfe3562455..019c8a36c2ff 100644 --- a/third_party/rust/procfs-core/Cargo.toml +++ b/third_party/rust/procfs-core/Cargo.toml @@ -13,8 +13,13 @@ edition = "2018" rust-version = "1.48" name = "procfs-core" -version = "0.16.0" +version = "0.17.0" authors = ["Andrew Chin "] +build = false +autobins = false +autoexamples = false +autotests = false +autobenches = false description = "Data structures and parsing for the linux procfs pseudo-filesystem" documentation = "https://docs.rs/procfs-core/" readme = "README.md" @@ -34,6 +39,10 @@ repository = "https://github.com/eminence/procfs" [package.metadata.docs.rs] all-features = true +[lib] +name = "procfs_core" +path = "src/lib.rs" + [dependencies.backtrace] version = "0.3" optional = true diff --git a/third_party/rust/procfs-core/LICENSE-APACHE b/third_party/rust/procfs-core/LICENSE-APACHE new file mode 100644 index 000000000000..8f71f43fee3f --- /dev/null +++ b/third_party/rust/procfs-core/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/third_party/rust/procfs-core/LICENSE-MIT b/third_party/rust/procfs-core/LICENSE-MIT new file mode 100644 index 000000000000..bf280466acb2 --- /dev/null +++ b/third_party/rust/procfs-core/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 The procfs Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/procfs-core/src/cgroups.rs b/third_party/rust/procfs-core/src/cgroups.rs index 71ae9069e494..8f3201bf734e 100644 --- a/third_party/rust/procfs-core/src/cgroups.rs +++ b/third_party/rust/procfs-core/src/cgroups.rs @@ -99,6 +99,7 @@ impl crate::FromBufRead for ProcessCGroups { let hierarchy = from_str!(u32, expect!(s.next(), "hierarchy")); let controllers = expect!(s.next(), "controllers") .split(',') + .filter(|s| !s.is_empty()) .map(|s| s.to_owned()) .collect(); let pathname = expect!(s.next(), "path").to_owned(); diff --git a/third_party/rust/procfs-core/src/cpuinfo.rs b/third_party/rust/procfs-core/src/cpuinfo.rs index 07c8d93f1683..f945bb88ebf5 100644 --- a/third_party/rust/procfs-core/src/cpuinfo.rs +++ b/third_party/rust/procfs-core/src/cpuinfo.rs @@ -110,7 +110,11 @@ impl CpuInfo { /// Get the content of a specific field associated to a CPU /// - /// Returns None if the requested cpu index is not found. + /// If the field is not found in the set of CPU-specific fields, then + /// it is returned from the set of common fields. + /// + /// Returns None if the requested cpu index is not found, or if the field + /// is not found. pub fn get_field(&self, cpu_num: usize, field_name: &str) -> Option<&str> { self.cpus.get(cpu_num).and_then(|cpu_fields| { cpu_fields diff --git a/third_party/rust/procfs-core/src/crypto.rs b/third_party/rust/procfs-core/src/crypto.rs new file mode 100644 index 000000000000..5e7869f6d65b --- /dev/null +++ b/third_party/rust/procfs-core/src/crypto.rs @@ -0,0 +1,597 @@ +use crate::{expect, FromBufRead, ProcError, ProcResult}; + +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashMap, + convert::TryFrom, + io::BufRead, + iter::{once, Peekable}, + str::FromStr, +}; + +/// Represents the data from `/proc/crypto`. +/// +/// Each block represents a cryptographic implementation that has been registered with the kernel. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct CryptoTable { + pub crypto_blocks: HashMap>, +} + +/// Format of a crypto implementation represented in /proc/crypto. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct CryptoBlock { + pub name: String, + pub driver: String, + pub module: String, + pub priority: isize, + pub ref_count: isize, + pub self_test: SelfTest, + pub internal: bool, + pub fips_enabled: bool, + pub crypto_type: Type, +} + +impl FromBufRead for CryptoTable { + fn from_buf_read(r: R) -> ProcResult { + let mut lines = r.lines().peekable(); + let mut crypto_blocks: HashMap> = HashMap::new(); + while let Some(line) = lines.next() { + let line = line?; + // Just skip empty lines + if !line.is_empty() { + let mut split = line.split(':'); + let name = expect!(split.next()); + if name.trim() == "name" { + let name = expect!(split.next()).trim().to_string(); + let block = CryptoBlock::from_iter(&mut lines, name.as_str())?; + let blocks = crypto_blocks.entry(name).or_insert(Vec::new()); + blocks.push(block); + } + } + } + + Ok(CryptoTable { crypto_blocks }) + } +} + +impl CryptoTable { + pub fn get>(&self, target: T) -> Option<&Vec> { + self.crypto_blocks.get(target.as_ref()) + } +} + +impl CryptoBlock { + fn from_iter>>( + iter: &mut Peekable, + name: &str, + ) -> ProcResult { + let driver = parse_line(iter, "driver", name)?; + let module = parse_line(iter, "module", name)?; + let priority = from_str!(isize, &parse_line(iter, "priority", name)?); + let ref_count = from_str!(isize, &parse_line(iter, "refcnt", name)?); + let self_test = SelfTest::try_from(parse_line(iter, "selftest", name)?.as_str())?; + let internal = parse_bool(iter, "internal", name)?; + let fips_enabled = parse_fips(iter, name)?; + let crypto_type = Type::from_iter(iter, name)?; + Ok(CryptoBlock { + name: name.to_string(), + driver, + module, + priority, + ref_count, + self_test, + internal, + fips_enabled, + crypto_type, + }) + } +} + +/// Potential results for selftest. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub enum SelfTest { + Passed, + Unknown, +} + +impl TryFrom<&str> for SelfTest { + type Error = ProcError; + + fn try_from(value: &str) -> Result { + Ok(match value { + "passed" => Self::Passed, + "unknown" => Self::Unknown, + _ => { + return Err(build_internal_error!(format!( + "Could not recognise self test string {value}" + ))) + } + }) + } +} + +/// Enumeration of potential types and their associated data. Unknown at end to catch unrecognised types. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub enum Type { + /// Symmetric Key Cipher + Skcipher(Skcipher), + /// Single Block Cipher + Cipher(Cipher), + /// Syncronous Hash + Shash(Shash), + /// Asyncronous Hash + Ahash(Ahash), + /// Authenticated Encryption with Associated Data + Aead(Aead), + /// Random Number Generator + Rng(Rng), + /// Test algorithm + Larval(Larval), + /// Synchronous Compression + Scomp, + /// General Compression + Compression, + /// Asymmetric Cipher + AkCipher, + /// Key-agreement Protocol Primitive + Kpp, + /// Signature + Sig, + /// Unrecognised type, associated data collected in to a hash map + Unknown(Unknown), +} + +impl Type { + fn from_iter>>( + iter: &mut Peekable, + name: &str, + ) -> ProcResult { + let type_name = parse_line(iter, "type", name)?; + Ok(match type_name.as_str() { + "skcipher" => Self::Skcipher(Skcipher::parse(iter, name)?), + "cipher" => Self::Cipher(Cipher::parse(iter, name)?), + "shash" => Self::Shash(Shash::parse(iter, name)?), + "scomp" => Self::Scomp, + "compression" => Self::Compression, + "akcipher" => Self::AkCipher, + "kpp" => Self::Kpp, + "ahash" => Self::Ahash(Ahash::parse(iter, name)?), + "aead" => Self::Aead(Aead::parse(iter, name)?), + "rng" => Self::Rng(Rng::parse(iter, name)?), + "larval" => Self::Larval(Larval::parse(iter, name)?), + "sig" => Self::Sig, + unknown_name => Self::Unknown(Unknown::parse(iter, unknown_name)), + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Skcipher { + pub async_capable: bool, + pub block_size: usize, + pub min_key_size: usize, + pub max_key_size: usize, + pub iv_size: usize, + pub chunk_size: usize, + pub walk_size: usize, +} + +impl Skcipher { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let async_capable = parse_bool(iter, "async", name)?; + let block_size = from_str!(usize, &parse_line(iter, "blocksize", name)?); + let min_key_size = from_str!(usize, &parse_line(iter, "min keysize", name)?); + let max_key_size = from_str!(usize, &parse_line(iter, "max keysize", name)?); + let iv_size = from_str!(usize, &parse_line(iter, "ivsize", name)?); + let chunk_size = from_str!(usize, &parse_line(iter, "chunksize", name)?); + let walk_size = from_str!(usize, &parse_line(iter, "walksize", name)?); + Ok(Self { + async_capable, + block_size, + min_key_size, + max_key_size, + iv_size, + chunk_size, + walk_size, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Cipher { + pub block_size: usize, + pub min_key_size: usize, + pub max_key_size: usize, +} + +impl Cipher { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let block_size = from_str!(usize, &parse_line(iter, "blocksize", name)?); + let min_key_size = from_str!(usize, &parse_line(iter, "min keysize", name)?); + let max_key_size = from_str!(usize, &parse_line(iter, "max keysize", name)?); + Ok(Self { + block_size, + min_key_size, + max_key_size, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Shash { + pub block_size: usize, + pub digest_size: usize, +} + +impl Shash { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let block_size = from_str!(usize, &parse_line(iter, "blocksize", name)?); + let digest_size = from_str!(usize, &parse_line(iter, "digestsize", name)?); + Ok(Self { + block_size, + digest_size, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Ahash { + pub async_capable: bool, + pub block_size: usize, + pub digest_size: usize, +} + +impl Ahash { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let async_capable = parse_bool(iter, "async", name)?; + let block_size = from_str!(usize, &parse_line(iter, "blocksize", name)?); + let digest_size = from_str!(usize, &parse_line(iter, "digestsize", name)?); + Ok(Self { + async_capable, + block_size, + digest_size, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Aead { + pub async_capable: bool, + pub block_size: usize, + pub iv_size: usize, + pub max_auth_size: usize, + pub gen_iv: Option, +} + +impl Aead { + fn parse>>( + iter: &mut Peekable, + name: &str, + ) -> ProcResult { + let async_capable = parse_bool(iter, "async", name)?; + let block_size = from_str!(usize, &parse_line(iter, "blocksize", name)?); + let iv_size = from_str!(usize, &parse_line(iter, "ivsize", name)?); + let max_auth_size = from_str!(usize, &parse_line(iter, "maxauthsize", name)?); + let gen_iv = parse_gen_iv(iter, name)?; + Ok(Self { + async_capable, + block_size, + iv_size, + max_auth_size, + gen_iv, + }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Rng { + pub seed_size: usize, +} + +impl Rng { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let seed_size = from_str!(usize, &parse_line(iter, "seedsize", name)?); + Ok(Self { seed_size }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Larval { + pub flags: u32, +} + +impl Larval { + fn parse>>(iter: &mut T, name: &str) -> ProcResult { + let flags = from_str!(u32, &parse_line(iter, "flags", name)?); + Ok(Self { flags }) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Unknown { + pub fields: HashMap, +} + +impl Unknown { + fn parse>>(iter: &mut T, unknown_name: &str) -> Self { + let fields = iter + .map_while(|line| { + let line = match line { + Ok(line) => line, + Err(_) => return None, + }; + (!line.is_empty()).then(|| { + line.split_once(':') + .map(|(k, v)| (k.trim().to_string(), v.trim().to_string())) + }) + }) + .flatten() + .chain(once((String::from("name"), unknown_name.to_string()))) + .collect(); + Self { fields } + } +} + +fn parse_line>>( + iter: &mut T, + to_find: &str, + name: &str, +) -> ProcResult { + let line = expect!(iter.next())?; + let (key, val) = expect!(line.split_once(':')); + if key.trim() != to_find { + return Err(build_internal_error!(format!( + "could not locate {to_find} in /proc/crypto, block {name}" + ))); + } + Ok(val.trim().to_string()) +} + +fn parse_fips>>( + iter: &mut Peekable, + name: &str, +) -> ProcResult { + if iter + .peek() + .map(|line| line.as_ref().is_ok_and(|line| line.contains("fips"))) + .unwrap_or(false) + { + let fips = parse_line(iter, "fips", name)?; + if fips == "yes" { + return Ok(true); + } + } + Ok(false) +} + +fn parse_bool>>( + iter: &mut T, + to_find: &str, + name: &str, +) -> ProcResult { + match parse_line(iter, to_find, name)?.as_str() { + "yes" => Ok(true), + "no" => Ok(false), + _ => Err(build_internal_error!(format!( + "{to_find} for {name} was unrecognised term" + ))), + } +} + +fn parse_gen_iv>>( + iter: &mut Peekable, + name: &str, +) -> ProcResult> { + if iter + .peek() + .map(|line| line.as_ref().is_ok_and(|line| line.contains("geniv"))) + .unwrap_or(false) + { + let val = parse_line(iter, "geniv", name)?; + if val != "" { + return Ok(Some(expect!(usize::from_str(&val)))); + } + } + Ok(None) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn parse_line_correct() { + let line = Ok("name : ghash".to_string()); + let mut iter = std::iter::once(line); + let val = match parse_line(&mut iter, "name", "parse_line_correct") { + Ok(val) => val, + Err(e) => panic!("{}", e), + }; + assert_eq!("ghash", val); + } + + #[test] + fn parse_line_incorrect() { + let line = Ok("name : ghash".to_string()); + let mut iter = std::iter::once(line); + let val = match parse_line(&mut iter, "name", "parse_line_incorrect") { + Ok(val) => val, + Err(e) => panic!("{}", e), + }; + assert_ne!("hash", val); + } + + #[test] + fn parse_block() { + let block = r#"driver : deflate-generic +module : kernel +priority : 0 +refcnt : 2 +selftest : passed +internal : no +type : compression"#; + let mut iter = block.lines().map(|s| Ok(s.to_string())).peekable(); + let block = CryptoBlock::from_iter(&mut iter, "deflate"); + let block = block.expect("Should be have read one block"); + assert_eq!(block.name, "deflate"); + assert_eq!(block.driver, "deflate-generic"); + assert_eq!(block.module, "kernel"); + assert_eq!(block.priority, 0); + assert_eq!(block.ref_count, 2); + assert_eq!(block.self_test, SelfTest::Passed); + assert_eq!(block.internal, false); + assert_eq!(block.crypto_type, Type::Compression); + } + + #[test] + fn parse_bad_block() { + let block = r#"driver : deflate-generic +module : kernel +priority : 0 +refcnt : 2 +selftest : passed +internal : no +type : aead"#; + let mut iter = block.lines().map(|s| Ok(s.to_string())).peekable(); + let block = CryptoBlock::from_iter(&mut iter, "deflate"); + eprintln!("{block:?}"); + assert!(block.is_err()); + } + + #[test] + fn parse_two() { + let block = r#"name : ccm(aes) +driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni)) +module : ccm +priority : 300 +refcnt : 4 +selftest : passed +internal : no +type : aead +async : no +blocksize : 1 +ivsize : 16 +maxauthsize : 16 +geniv : + +name : ctr(aes) +driver : ctr(aes-aesni) +module : kernel +priority : 300 +refcnt : 4 +selftest : passed +internal : no +type : skcipher +async : no +blocksize : 1 +min keysize : 16 +max keysize : 32 +ivsize : 16 +chunksize : 16 +walksize : 16 + +"#; + let blocks = CryptoTable::from_buf_read(block.as_bytes()); + let blocks = blocks.expect("Should be have read two blocks"); + assert_eq!(blocks.crypto_blocks.len(), 2); + } + + #[test] + fn parse_duplicate_name() { + let block = r#"name : deflate +driver : deflate-generic +module : kernel +priority : 0 +refcnt : 2 +selftest : passed +internal : no +type : compression + +name : deflate +driver : deflate-non-generic +module : kernel +priority : 0 +refcnt : 2 +selftest : passed +internal : no +type : compression +"#; + let blocks = CryptoTable::from_buf_read(block.as_bytes()); + let blocks = blocks.expect("Should be have read two blocks"); + assert_eq!(blocks.crypto_blocks.len(), 1); + let deflate_vec = blocks + .crypto_blocks + .get("deflate") + .expect("Should have created a vec of deflates"); + assert_eq!(deflate_vec.len(), 2); + } + + #[test] + fn parse_unknown() { + let block = r#"driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni)) +module : ccm +priority : 300 +refcnt : 4 +selftest : passed +internal : no +type : unknown +key : val +key2 : val2 +"#; + let mut iter = block.lines().map(|s| Ok(s.to_string())).peekable(); + let block = CryptoBlock::from_iter(&mut iter, "ccm(aes)"); + let block = block.expect("Should be have read one block"); + let mut compare = HashMap::new(); + compare.insert(String::from("key"), String::from("val")); + compare.insert(String::from("key2"), String::from("val2")); + compare.insert(String::from("name"), String::from("unknown")); + assert_eq!(block.crypto_type, Type::Unknown(Unknown { fields: compare })); + } + + #[test] + fn parse_unknown_top() { + let block = r#"name : ccm(aes) +driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni)) +module : ccm +priority : 300 +refcnt : 4 +selftest : passed +internal : no +type : unknown +key : val +key2 : val2 + +name : ctr(aes) +driver : ctr(aes-aesni) +module : kernel +priority : 300 +refcnt : 4 +selftest : passed +internal : no +type : skcipher +async : no +blocksize : 1 +min keysize : 16 +max keysize : 32 +ivsize : 16 +chunksize : 16 +walksize : 16 +"#; + let blocks = CryptoTable::from_buf_read(block.as_bytes()); + let blocks = blocks.expect("Should be have read one block"); + assert_eq!(blocks.crypto_blocks.len(), 2); + } +} diff --git a/third_party/rust/procfs-core/src/devices.rs b/third_party/rust/procfs-core/src/devices.rs new file mode 100644 index 000000000000..36c41764657e --- /dev/null +++ b/third_party/rust/procfs-core/src/devices.rs @@ -0,0 +1,192 @@ +use std::io::BufRead; + +use super::ProcResult; +use std::str::FromStr; + +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; + +/// Device entries under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct Devices { + /// Character devices + pub char_devices: Vec, + /// Block devices, which can be empty if the kernel doesn't support block devices (without `CONFIG_BLOCK`) + pub block_devices: Vec, +} + +/// A charcter device entry under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct CharDeviceEntry { + /// Device major number + pub major: u32, + /// Device name + pub name: String, +} + +/// A block device entry under `/proc/devices` +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct BlockDeviceEntry { + /// Device major number + pub major: i32, + /// Device name + pub name: String, +} + +impl super::FromBufRead for Devices { + fn from_buf_read(r: R) -> ProcResult { + enum State { + Char, + Block, + } + let mut state = State::Char; // Always start with char devices + let mut devices = Devices { + char_devices: vec![], + block_devices: vec![], + }; + + for line in r.lines() { + let line = expect!(line); + + if line.is_empty() { + continue; + } else if line.starts_with("Character devices:") { + state = State::Char; + continue; + } else if line.starts_with("Block devices:") { + state = State::Block; + continue; + } + + let mut s = line.split_whitespace(); + + match state { + State::Char => { + let major = expect!(u32::from_str(expect!(s.next()))); + let name = expect!(s.next()).to_string(); + + let char_device_entry = CharDeviceEntry { major, name }; + + devices.char_devices.push(char_device_entry); + } + State::Block => { + let major = expect!(i32::from_str(expect!(s.next()))); + let name = expect!(s.next()).to_string(); + + let block_device_entry = BlockDeviceEntry { major, name }; + + devices.block_devices.push(block_device_entry); + } + } + } + + Ok(devices) + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_devices() { + use crate::FromBufRead; + use std::io::Cursor; + + let s = "Character devices: + 1 mem + 4 /dev/vc/0 + 4 tty + 4 ttyS + 5 /dev/tty + 5 /dev/console + 5 /dev/ptmx + 7 vcs + 10 misc + 13 input + 29 fb + 90 mtd +136 pts +180 usb +188 ttyUSB +189 usb_device + +Block devices: + 7 loop + 8 sd + 65 sd + 71 sd +128 sd +135 sd +254 device-mapper +259 blkext +"; + + let cursor = Cursor::new(s); + let devices = Devices::from_buf_read(cursor).unwrap(); + let (chrs, blks) = (devices.char_devices, devices.block_devices); + + assert_eq!(chrs.len(), 16); + + assert_eq!(chrs[1].major, 4); + assert_eq!(chrs[1].name, "/dev/vc/0"); + + assert_eq!(chrs[8].major, 10); + assert_eq!(chrs[8].name, "misc"); + + assert_eq!(chrs[15].major, 189); + assert_eq!(chrs[15].name, "usb_device"); + + assert_eq!(blks.len(), 8); + + assert_eq!(blks[0].major, 7); + assert_eq!(blks[0].name, "loop"); + + assert_eq!(blks[7].major, 259); + assert_eq!(blks[7].name, "blkext"); + } + + #[test] + fn test_devices_without_block() { + use crate::FromBufRead; + use std::io::Cursor; + + let s = "Character devices: + 1 mem + 4 /dev/vc/0 + 4 tty + 4 ttyS + 5 /dev/tty + 5 /dev/console + 5 /dev/ptmx + 7 vcs + 10 misc + 13 input + 29 fb + 90 mtd +136 pts +180 usb +188 ttyUSB +189 usb_device +"; + + let cursor = Cursor::new(s); + let devices = Devices::from_buf_read(cursor).unwrap(); + let (chrs, blks) = (devices.char_devices, devices.block_devices); + + assert_eq!(chrs.len(), 16); + + assert_eq!(chrs[1].major, 4); + assert_eq!(chrs[1].name, "/dev/vc/0"); + + assert_eq!(chrs[8].major, 10); + assert_eq!(chrs[8].name, "misc"); + + assert_eq!(chrs[15].major, 189); + assert_eq!(chrs[15].name, "usb_device"); + + assert_eq!(blks.len(), 0); + } +} diff --git a/third_party/rust/procfs-core/src/kpageflags.rs b/third_party/rust/procfs-core/src/kpageflags.rs new file mode 100644 index 000000000000..d80b68f34ec2 --- /dev/null +++ b/third_party/rust/procfs-core/src/kpageflags.rs @@ -0,0 +1,90 @@ +use bitflags::bitflags; + +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; + +//const fn genmask(high: usize, low: usize) -> u64 { +// let mask_bits = size_of::() * 8; +// (!0 - (1 << low) + 1) & (!0 >> (mask_bits - 1 - high)) +//} + +bitflags! { + /// Represents the fields and flags in a page table entry for a memory page. + #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] + #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] + pub struct PhysicalPageFlags: u64 { + /// The page is being locked for exclusive access, e.g. by undergoing read/write IO + const LOCKED = 1 << 0; + /// IO error occurred + const ERROR = 1 << 1; + /// The page has been referenced since last LRU list enqueue/requeue + const REFERENCED = 1 << 2; + /// The page has up-to-date data. ie. for file backed page: (in-memory data revision >= on-disk one) + const UPTODATE = 1 << 3; + /// The page has been written to, hence contains new data. i.e. for file backed page: (in-memory data revision > on-disk one) + const DIRTY = 1 << 4; + /// The page is in one of the LRU lists + const LRU = 1 << 5; + /// The page is in the active LRU list + const ACTIVE = 1 << 6; + /// The page is managed by the SLAB/SLOB/SLUB/SLQB kernel memory allocator. When compound page is used, SLUB/SLQB will only set this flag on the head page; SLOB will not flag it at all + const SLAB = 1 << 7; + /// The page is being synced to disk + const WRITEBACK = 1 << 8; + /// The page will be reclaimed soon after its pageout IO completed + const RECLAIM = 1 << 9; + /// A free memory block managed by the buddy system allocator. The buddy system organizes free memory in blocks of various orders. An order N block has 2^N physically contiguous pages, with the BUDDY flag set for and _only_ for the first page + const BUDDY = 1 << 10; + /// A memory mapped page + const MMAP = 1 << 11; + /// A memory mapped page that is not part of a file + const ANON = 1 << 12; + /// The page is mapped to swap space, i.e. has an associated swap entry + const SWAPCACHE = 1 << 13; + /// The page is backed by swap/RAM + const SWAPBACKED = 1 << 14; + /// A compound page with order N consists of 2^N physically contiguous pages. A compound page with order 2 takes the form of “HTTT”, where H donates its head page and T donates its tail page(s). The major consumers of compound pages are hugeTLB pages (), the SLUB etc. memory allocators and various device drivers. However in this interface, only huge/giga pages are made visible to end users + const COMPOUND_HEAD = 1 << 15; + /// A compound page tail (see description above) + const COMPOUND_TAIL = 1 << 16; + /// This is an integral part of a HugeTLB page + const HUGE = 1 << 17; + /// The page is in the unevictable (non-)LRU list It is somehow pinned and not a candidate for LRU page reclaims, e.g. ramfs pages, shmctl(SHM_LOCK) and mlock() memory segments + const UNEVICTABLE = 1 << 18; + /// Hardware detected memory corruption on this page: don’t touch the data! + const HWPOISON = 1 << 19; + /// No page frame exists at the requested address + const NOPAGE = 1 << 20; + /// Identical memory pages dynamically shared between one or more processes + const KSM = 1 << 21; + /// Contiguous pages which construct transparent hugepages + const THP = 1 << 22; + /// The page is logically offline + const OFFLINE = 1 << 23; + /// Zero page for pfn_zero or huge_zero page + const ZERO_PAGE = 1 << 24; + /// The page has not been accessed since it was marked idle (see ). Note that this flag may be stale in case the page was accessed via a PTE. To make sure the flag is up-to-date one has to read /sys/kernel/mm/page_idle/bitmap first + const IDLE = 1 << 25; + /// The page is in use as a page table + const PGTABLE = 1 << 26; + + } +} + +impl PhysicalPageFlags { + pub fn parse_info(info: u64) -> Self { + PhysicalPageFlags::from_bits_truncate(info) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_kpageflags_parsing() { + let pagemap_entry: u64 = 0b0000000000000000000000000000000000000000000000000000000000000001; + let info = PhysicalPageFlags::parse_info(pagemap_entry); + assert!(info == PhysicalPageFlags::LOCKED); + } +} diff --git a/third_party/rust/procfs-core/src/lib.rs b/third_party/rust/procfs-core/src/lib.rs index a71ed34761a6..0c6572486cee 100644 --- a/third_party/rust/procfs-core/src/lib.rs +++ b/third_party/rust/procfs-core/src/lib.rs @@ -351,6 +351,12 @@ pub use cgroups::*; mod cpuinfo; pub use cpuinfo::*; +mod crypto; +pub use crypto::*; + +mod devices; +pub use devices::*; + mod diskstats; pub use diskstats::*; @@ -378,6 +384,9 @@ pub use pressure::*; pub mod process; +mod kpageflags; +pub use kpageflags::*; + pub mod sys; pub use sys::kernel::Version as KernelVersion; diff --git a/third_party/rust/procfs-core/src/meminfo.rs b/third_party/rust/procfs-core/src/meminfo.rs index b45268d41f39..8c8e121611b7 100644 --- a/third_party/rust/procfs-core/src/meminfo.rs +++ b/third_party/rust/procfs-core/src/meminfo.rs @@ -139,7 +139,7 @@ pub struct Meminfo { pub shmem: Option, /// In-kernel data structures cache. pub slab: u64, - /// Part of Slab, that cannot be reclaimed on memory pressure. + /// Part of Slab, that can be reclaimed on memory pressure. /// /// (since Linux 2.6.19) pub s_reclaimable: Option, diff --git a/third_party/rust/procfs-core/src/net.rs b/third_party/rust/procfs-core/src/net.rs index 246284e6ee4d..7689d1b6f20e 100644 --- a/third_party/rust/procfs-core/src/net.rs +++ b/third_party/rust/procfs-core/src/net.rs @@ -1015,145 +1015,167 @@ pub struct Snmp { pub udp_lite_ignored_multi: u64, } +/// A /proc/net/snmp section +/// +/// A section represents two lines, 1x header and 1x data +/// Each line has a prefix [ip, icmp, icmpmsg, tcp, udp, udplite] +/// Eg. +/// Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors +/// Tcp: 1 200 120000 -1 177 14 0 6 4 11155 10083 18 0 94 0 +#[derive(Debug)] +struct SnmpSection { + prefix: String, + values: HashMap, +} + +impl<'a> SnmpSection { + fn new(hdr: String, data: String) -> ProcResult { + let mut hdr = hdr.trim_end().split_whitespace(); + let mut data = data.trim_end().split_whitespace(); + let prefix = expect!(hdr.next()).to_owned(); + expect!(data.next()); + let mut values = HashMap::new(); + + for hdr in hdr { + values.insert(hdr.to_owned(), expect!(data.next()).to_owned()); + } + + Ok(Self { prefix, values }) + } +} + +/// An iterator over the /proc/net/snmp sections using `BufRead`. +#[derive(Debug)] +struct SnmpSections { + buf: B, +} + +impl Iterator for SnmpSections { + type Item = ProcResult; + + fn next(&mut self) -> Option { + let mut hdr = String::new(); + match self.buf.read_line(&mut hdr) { + Ok(0) => None, + Ok(_n) => { + let mut data = String::new(); + match self.buf.read_line(&mut data) { + Ok(_n) => Some(SnmpSection::new(hdr, data)), + Err(e) => Some(Err(e.into())), + } + } + Err(e) => Some(Err(e.into())), + } + } +} + impl super::FromBufRead for Snmp { fn from_buf_read(r: R) -> ProcResult { - fn next_group(lines: &mut std::io::Lines, prefix: &str) -> ProcResult { - if cfg!(test) { - let line = lines.next().unwrap()?; - if !line.starts_with(prefix) { - return Err(build_internal_error!(format!( - "`{}` section not found in /proc/net/snmp", - prefix - ))); - } - let line = lines.next().unwrap()?; - if !line.starts_with(prefix) { - return Err(build_internal_error!(format!( - "`{}` section not found in /proc/net/snmp", - prefix - ))); - } - return Ok(line); - } else { - Ok(lines.skip(1).next().unwrap()?) + let mut map = HashMap::new(); + let sections = SnmpSections { buf: r }; + for section in sections.flatten() { + let p = §ion.prefix; + for (hdr, v) in §ion.values { + map.insert(format!("{p}{hdr}"), v.to_owned()); } } - fn expect_none(line: Option<&str>, msg: &str) -> ProcResult<()> { - if cfg!(test) { - match line { - Some(..) => Err(build_internal_error!(format!("`{}` section is not consumed", msg))), - None => Ok(()), - } - } else { - Ok(()) - } - } - - let mut lines = r.lines(); - - let ip = next_group(&mut lines, "Ip:")?; - let mut ip = ip.split_whitespace().skip(1); - let icmp = next_group(&mut lines, "Icmp:")?; - let mut icmp = icmp.split_whitespace().skip(1); - let _ = next_group(&mut lines, "IcmpMsg:")?; - let tcp = next_group(&mut lines, "Tcp:")?; - let mut tcp = tcp.split_whitespace().skip(1); - let udp = next_group(&mut lines, "Udp:")?; - let mut udp = udp.split_whitespace().skip(1); - let udp_lite = next_group(&mut lines, "UdpLite:")?; - let mut udp_lite = udp_lite.split_whitespace().skip(1); let snmp = Snmp { // Ip - ip_forwarding: expect!(IpForwarding::from_u8(from_str!(u8, expect!(ip.next())))), - ip_default_ttl: from_str!(u32, expect!(ip.next())), - ip_in_receives: from_str!(u64, expect!(ip.next())), - ip_in_hdr_errors: from_str!(u64, expect!(ip.next())), - ip_in_addr_errors: from_str!(u64, expect!(ip.next())), - ip_forw_datagrams: from_str!(u64, expect!(ip.next())), - ip_in_unknown_protos: from_str!(u64, expect!(ip.next())), - ip_in_discards: from_str!(u64, expect!(ip.next())), - ip_in_delivers: from_str!(u64, expect!(ip.next())), - ip_out_requests: from_str!(u64, expect!(ip.next())), - ip_out_discards: from_str!(u64, expect!(ip.next())), - ip_out_no_routes: from_str!(u64, expect!(ip.next())), - ip_reasm_timeout: from_str!(u64, expect!(ip.next())), - ip_reasm_reqds: from_str!(u64, expect!(ip.next())), - ip_reasm_oks: from_str!(u64, expect!(ip.next())), - ip_reasm_fails: from_str!(u64, expect!(ip.next())), - ip_frag_oks: from_str!(u64, expect!(ip.next())), - ip_frag_fails: from_str!(u64, expect!(ip.next())), - ip_frag_creates: from_str!(u64, expect!(ip.next())), + ip_forwarding: expect!(IpForwarding::from_u8(from_str!( + u8, + &expect!(map.remove("Ip:Forwarding")) + ))), + ip_default_ttl: from_str!(u32, &expect!(map.remove("Ip:DefaultTTL"))), + ip_in_receives: from_str!(u64, &expect!(map.remove("Ip:InReceives"))), + ip_in_hdr_errors: from_str!(u64, &expect!(map.remove("Ip:InHdrErrors"))), + ip_in_addr_errors: from_str!(u64, &expect!(map.remove("Ip:InAddrErrors"))), + ip_forw_datagrams: from_str!(u64, &expect!(map.remove("Ip:ForwDatagrams"))), + ip_in_unknown_protos: from_str!(u64, &expect!(map.remove("Ip:InUnknownProtos"))), + ip_in_discards: from_str!(u64, &expect!(map.remove("Ip:InDiscards"))), + ip_in_delivers: from_str!(u64, &expect!(map.remove("Ip:InDelivers"))), + ip_out_requests: from_str!(u64, &expect!(map.remove("Ip:OutRequests"))), + ip_out_discards: from_str!(u64, &expect!(map.remove("Ip:OutDiscards"))), + ip_out_no_routes: from_str!(u64, &expect!(map.remove("Ip:OutNoRoutes"))), + ip_reasm_timeout: from_str!(u64, &expect!(map.remove("Ip:ReasmTimeout"))), + ip_reasm_reqds: from_str!(u64, &expect!(map.remove("Ip:ReasmReqds"))), + ip_reasm_oks: from_str!(u64, &expect!(map.remove("Ip:ReasmOKs"))), + ip_reasm_fails: from_str!(u64, &expect!(map.remove("Ip:ReasmFails"))), + ip_frag_oks: from_str!(u64, &expect!(map.remove("Ip:FragOKs"))), + ip_frag_fails: from_str!(u64, &expect!(map.remove("Ip:FragFails"))), + ip_frag_creates: from_str!(u64, &expect!(map.remove("Ip:FragCreates"))), + //ip_out_transmits: from_str!(u64, &expect!(map.remove("Ip:OutTransmits"))), // Icmp - icmp_in_msgs: from_str!(u64, expect!(icmp.next())), - icmp_in_errors: from_str!(u64, expect!(icmp.next())), - icmp_in_csum_errors: from_str!(u64, expect!(icmp.next())), - icmp_in_dest_unreachs: from_str!(u64, expect!(icmp.next())), - icmp_in_time_excds: from_str!(u64, expect!(icmp.next())), - icmp_in_parm_probs: from_str!(u64, expect!(icmp.next())), - icmp_in_src_quenchs: from_str!(u64, expect!(icmp.next())), - icmp_in_redirects: from_str!(u64, expect!(icmp.next())), - icmp_in_echos: from_str!(u64, expect!(icmp.next())), - icmp_in_echo_reps: from_str!(u64, expect!(icmp.next())), - icmp_in_timestamps: from_str!(u64, expect!(icmp.next())), - icmp_in_timestamp_reps: from_str!(u64, expect!(icmp.next())), - icmp_in_addr_masks: from_str!(u64, expect!(icmp.next())), - icmp_in_addr_mask_reps: from_str!(u64, expect!(icmp.next())), - icmp_out_msgs: from_str!(u64, expect!(icmp.next())), - icmp_out_errors: from_str!(u64, expect!(icmp.next())), - icmp_out_dest_unreachs: from_str!(u64, expect!(icmp.next())), - icmp_out_time_excds: from_str!(u64, expect!(icmp.next())), - icmp_out_parm_probs: from_str!(u64, expect!(icmp.next())), - icmp_out_src_quenchs: from_str!(u64, expect!(icmp.next())), - icmp_out_redirects: from_str!(u64, expect!(icmp.next())), - icmp_out_echos: from_str!(u64, expect!(icmp.next())), - icmp_out_echo_reps: from_str!(u64, expect!(icmp.next())), - icmp_out_timestamps: from_str!(u64, expect!(icmp.next())), - icmp_out_timestamp_reps: from_str!(u64, expect!(icmp.next())), - icmp_out_addr_masks: from_str!(u64, expect!(icmp.next())), - icmp_out_addr_mask_reps: from_str!(u64, expect!(icmp.next())), + icmp_in_msgs: from_str!(u64, &expect!(map.remove("Icmp:InMsgs"))), + icmp_in_errors: from_str!(u64, &expect!(map.remove("Icmp:InErrors"))), + icmp_in_csum_errors: from_str!(u64, &expect!(map.remove("Icmp:InCsumErrors"))), + icmp_in_dest_unreachs: from_str!(u64, &expect!(map.remove("Icmp:InDestUnreachs"))), + icmp_in_time_excds: from_str!(u64, &expect!(map.remove("Icmp:InTimeExcds"))), + icmp_in_parm_probs: from_str!(u64, &expect!(map.remove("Icmp:InParmProbs"))), + icmp_in_src_quenchs: from_str!(u64, &expect!(map.remove("Icmp:InSrcQuenchs"))), + icmp_in_redirects: from_str!(u64, &expect!(map.remove("Icmp:InRedirects"))), + icmp_in_echos: from_str!(u64, &expect!(map.remove("Icmp:InEchos"))), + icmp_in_echo_reps: from_str!(u64, &expect!(map.remove("Icmp:InEchoReps"))), + icmp_in_timestamps: from_str!(u64, &expect!(map.remove("Icmp:InTimestamps"))), + icmp_in_timestamp_reps: from_str!(u64, &expect!(map.remove("Icmp:InTimestampReps"))), + icmp_in_addr_masks: from_str!(u64, &expect!(map.remove("Icmp:InAddrMasks"))), + icmp_in_addr_mask_reps: from_str!(u64, &expect!(map.remove("Icmp:InAddrMaskReps"))), + icmp_out_msgs: from_str!(u64, &expect!(map.remove("Icmp:OutMsgs"))), + icmp_out_errors: from_str!(u64, &expect!(map.remove("Icmp:OutErrors"))), + //icmp_out_rate_limit_global: from_str!(u64, &expect!(map.remove("Icmp:OutRateLimitGlobal"))), + //icmp_out_rate_limit_host: from_str!(u64, &expect!(map.remove("Icmp:OutRateLimitHost"))), + icmp_out_dest_unreachs: from_str!(u64, &expect!(map.remove("Icmp:OutDestUnreachs"))), + icmp_out_time_excds: from_str!(u64, &expect!(map.remove("Icmp:OutTimeExcds"))), + icmp_out_parm_probs: from_str!(u64, &expect!(map.remove("Icmp:OutParmProbs"))), + icmp_out_src_quenchs: from_str!(u64, &expect!(map.remove("Icmp:OutSrcQuenchs"))), + icmp_out_redirects: from_str!(u64, &expect!(map.remove("Icmp:OutRedirects"))), + icmp_out_echos: from_str!(u64, &expect!(map.remove("Icmp:OutEchos"))), + icmp_out_echo_reps: from_str!(u64, &expect!(map.remove("Icmp:OutEchoReps"))), + icmp_out_timestamps: from_str!(u64, &expect!(map.remove("Icmp:OutTimestamps"))), + icmp_out_timestamp_reps: from_str!(u64, &expect!(map.remove("Icmp:OutTimestampReps"))), + icmp_out_addr_masks: from_str!(u64, &expect!(map.remove("Icmp:OutAddrMasks"))), + icmp_out_addr_mask_reps: from_str!(u64, &expect!(map.remove("Icmp:OutAddrMaskReps"))), // Tcp - tcp_rto_algorithm: expect!(TcpRtoAlgorithm::from_u8(from_str!(u8, expect!(tcp.next())))), - tcp_rto_min: from_str!(u64, expect!(tcp.next())), - tcp_rto_max: from_str!(u64, expect!(tcp.next())), - tcp_max_conn: from_str!(i64, expect!(tcp.next())), - tcp_active_opens: from_str!(u64, expect!(tcp.next())), - tcp_passive_opens: from_str!(u64, expect!(tcp.next())), - tcp_attempt_fails: from_str!(u64, expect!(tcp.next())), - tcp_estab_resets: from_str!(u64, expect!(tcp.next())), - tcp_curr_estab: from_str!(u64, expect!(tcp.next())), - tcp_in_segs: from_str!(u64, expect!(tcp.next())), - tcp_out_segs: from_str!(u64, expect!(tcp.next())), - tcp_retrans_segs: from_str!(u64, expect!(tcp.next())), - tcp_in_errs: from_str!(u64, expect!(tcp.next())), - tcp_out_rsts: from_str!(u64, expect!(tcp.next())), - tcp_in_csum_errors: from_str!(u64, expect!(tcp.next())), + tcp_rto_algorithm: expect!(TcpRtoAlgorithm::from_u8(from_str!( + u8, + &expect!(map.remove("Tcp:RtoAlgorithm")) + ))), + tcp_rto_min: from_str!(u64, &expect!(map.remove("Tcp:RtoMin"))), + tcp_rto_max: from_str!(u64, &expect!(map.remove("Tcp:RtoMax"))), + tcp_max_conn: from_str!(i64, &expect!(map.remove("Tcp:MaxConn"))), + tcp_active_opens: from_str!(u64, &expect!(map.remove("Tcp:ActiveOpens"))), + tcp_passive_opens: from_str!(u64, &expect!(map.remove("Tcp:PassiveOpens"))), + tcp_attempt_fails: from_str!(u64, &expect!(map.remove("Tcp:AttemptFails"))), + tcp_estab_resets: from_str!(u64, &expect!(map.remove("Tcp:EstabResets"))), + tcp_curr_estab: from_str!(u64, &expect!(map.remove("Tcp:CurrEstab"))), + tcp_in_segs: from_str!(u64, &expect!(map.remove("Tcp:InSegs"))), + tcp_out_segs: from_str!(u64, &expect!(map.remove("Tcp:OutSegs"))), + tcp_retrans_segs: from_str!(u64, &expect!(map.remove("Tcp:RetransSegs"))), + tcp_in_errs: from_str!(u64, &expect!(map.remove("Tcp:InErrs"))), + tcp_out_rsts: from_str!(u64, &expect!(map.remove("Tcp:OutRsts"))), + tcp_in_csum_errors: from_str!(u64, &expect!(map.remove("Tcp:InCsumErrors"))), // Udp - udp_in_datagrams: from_str!(u64, expect!(udp.next())), - udp_no_ports: from_str!(u64, expect!(udp.next())), - udp_in_errors: from_str!(u64, expect!(udp.next())), - udp_out_datagrams: from_str!(u64, expect!(udp.next())), - udp_rcvbuf_errors: from_str!(u64, expect!(udp.next())), - udp_sndbuf_errors: from_str!(u64, expect!(udp.next())), - udp_in_csum_errors: from_str!(u64, expect!(udp.next())), - udp_ignored_multi: from_str!(u64, expect!(udp.next())), + udp_in_datagrams: from_str!(u64, &expect!(map.remove("Udp:InDatagrams"))), + udp_no_ports: from_str!(u64, &expect!(map.remove("Udp:NoPorts"))), + udp_in_errors: from_str!(u64, &expect!(map.remove("Udp:InErrors"))), + udp_out_datagrams: from_str!(u64, &expect!(map.remove("Udp:OutDatagrams"))), + udp_rcvbuf_errors: from_str!(u64, &expect!(map.remove("Udp:RcvbufErrors"))), + udp_sndbuf_errors: from_str!(u64, &expect!(map.remove("Udp:SndbufErrors"))), + udp_in_csum_errors: from_str!(u64, &expect!(map.remove("Udp:InCsumErrors"))), + udp_ignored_multi: from_str!(u64, &expect!(map.remove("Udp:IgnoredMulti"))), + //udp_mem_errors: from_str!(u64, &expect!(map.remove("Udp:MemErrors"))), // UdpLite - udp_lite_in_datagrams: from_str!(u64, expect!(udp_lite.next())), - udp_lite_no_ports: from_str!(u64, expect!(udp_lite.next())), - udp_lite_in_errors: from_str!(u64, expect!(udp_lite.next())), - udp_lite_out_datagrams: from_str!(u64, expect!(udp_lite.next())), - udp_lite_rcvbuf_errors: from_str!(u64, expect!(udp_lite.next())), - udp_lite_sndbuf_errors: from_str!(u64, expect!(udp_lite.next())), - udp_lite_in_csum_errors: from_str!(u64, expect!(udp_lite.next())), - udp_lite_ignored_multi: from_str!(u64, expect!(udp_lite.next())), + udp_lite_in_datagrams: from_str!(u64, &expect!(map.remove("UdpLite:InDatagrams"))), + udp_lite_no_ports: from_str!(u64, &expect!(map.remove("UdpLite:NoPorts"))), + udp_lite_in_errors: from_str!(u64, &expect!(map.remove("UdpLite:InErrors"))), + udp_lite_out_datagrams: from_str!(u64, &expect!(map.remove("UdpLite:OutDatagrams"))), + udp_lite_rcvbuf_errors: from_str!(u64, &expect!(map.remove("UdpLite:RcvbufErrors"))), + udp_lite_sndbuf_errors: from_str!(u64, &expect!(map.remove("UdpLite:SndbufErrors"))), + udp_lite_in_csum_errors: from_str!(u64, &expect!(map.remove("UdpLite:InCsumErrors"))), + udp_lite_ignored_multi: from_str!(u64, &expect!(map.remove("UdpLite:IgnoredMulti"))), + //udp_lite_mem_errors: from_str!(u64, &expect!(map.remove("UdpLite:MemErrors"))), }; - expect_none(ip.next(), "Ip")?; - expect_none(icmp.next(), "Icmp")?; - expect_none(tcp.next(), "Tcp")?; - expect_none(udp.next(), "Udp")?; - expect_none(udp_lite.next(), "UdpLite")?; - Ok(snmp) } } @@ -1646,4 +1668,64 @@ mod tests { fn test_tcpstate_from() { assert_eq!(TcpState::from_u8(0xA).unwrap(), TcpState::Listen); } + + #[test] + fn test_snmp_debian_6_8_12() { + // Sample from Debian 6.8.12-1 + let data = r#"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates OutTransmits +Ip: 1 64 58881328 0 1 0 0 0 58879082 12449667 9745 1855 0 4 2 0 0 0 0 12449667 +Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps +Icmp: 16667 83 0 16667 0 0 0 0 0 0 0 0 0 0 21854 0 2 81 21854 0 0 0 0 0 0 0 0 0 0 +IcmpMsg: InType3 OutType3 +IcmpMsg: 16667 21854 +Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors +Tcp: 1 200 120000 -1 88170 33742 29003 4952 9 5129401 4676076 3246 60 40857 0 +Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors +Udp: 48327329 21522 6981741 9605045 6981727 9497 14 478236 0 +UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors +UdpLite: 0 0 0 0 0 0 0 0 0 +"#; + + let r = std::io::Cursor::new(data.as_bytes()); + use crate::FromRead; + let res = Snmp::from_read(r).unwrap(); + assert_eq!(res.ip_forwarding, IpForwarding::Forwarding); + assert_eq!(res.ip_in_receives, 58881328); + assert_eq!(res.ip_in_delivers, 58879082); + assert_eq!(res.ip_out_requests, 12449667); + assert_eq!(res.ip_out_no_routes, 1855); + assert_eq!(res.tcp_rto_algorithm, TcpRtoAlgorithm::Other); + assert_eq!(res.tcp_rto_min, 200); + assert_eq!(res.tcp_rto_max, 120000); + assert_eq!(res.tcp_max_conn, -1); + assert_eq!(res.tcp_curr_estab, 9); + assert_eq!(res.tcp_in_segs, 5129401); + assert_eq!(res.tcp_out_segs, 4676076); + assert_eq!(res.udp_in_datagrams, 48327329); + assert_eq!(res.udp_in_csum_errors, 14); + assert_eq!(res.udp_no_ports, 21522); + assert_eq!(res.udp_out_datagrams, 9605045); + println!("{res:?}"); + } + + #[test] + fn test_snmp_missing_icmp_msg() { + // https://github.com/eminence/procfs/issues/310 + let data = r#"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates OutTransmits +Ip: 2 64 12063 0 1 0 0 0 11952 8953 0 0 0 0 0 0 0 0 0 8953 +Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutRateLimitGlobal OutRateLimitHost OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps +Icmp: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors +Tcp: 1 200 120000 -1 177 14 0 6 4 11155 10083 18 0 94 0 +Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors +Udp: 2772 0 0 1890 0 0 0 745 0 +UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti MemErrors +UdpLite: 0 0 0 0 0 0 0 0 0 +"#; + + let r = std::io::Cursor::new(data.as_bytes()); + use crate::FromRead; + let res = Snmp::from_read(r).unwrap(); + println!("{res:?}"); + } } diff --git a/third_party/rust/procfs-core/src/partitions.rs b/third_party/rust/procfs-core/src/partitions.rs index ef297d5aedba..41a6586981ad 100644 --- a/third_party/rust/procfs-core/src/partitions.rs +++ b/third_party/rust/procfs-core/src/partitions.rs @@ -18,7 +18,7 @@ pub struct PartitionEntry { /// Number of 1024 byte blocks pub blocks: u64, /// Device name - pub name: String + pub name: String, } impl super::FromBufRead for Vec { @@ -37,9 +37,9 @@ impl super::FromBufRead for Vec { let partition_entry = PartitionEntry { major, - minor, - blocks, - name + minor, + blocks, + name, }; vec.push(partition_entry); @@ -49,7 +49,6 @@ impl super::FromBufRead for Vec { } } - #[test] fn test_partitions() { use crate::FromBufRead; diff --git a/third_party/rust/procfs-core/src/process/mount.rs b/third_party/rust/procfs-core/src/process/mount.rs index eb79a1d160ff..7df396e92d19 100644 --- a/third_party/rust/procfs-core/src/process/mount.rs +++ b/third_party/rust/procfs-core/src/process/mount.rs @@ -49,6 +49,13 @@ bitflags! { /// This data is taken from the `/proc/[pid]/mountinfo` file. pub struct MountInfos(pub Vec); +impl MountInfos { + /// Returns an borrowed iterator. + pub fn iter(&self) -> std::slice::Iter<'_, MountInfo> { + self.into_iter() + } +} + impl crate::FromBufRead for MountInfos { fn from_buf_read(r: R) -> ProcResult { let lines = r.lines(); diff --git a/third_party/rust/procfs-core/src/process/pagemap.rs b/third_party/rust/procfs-core/src/process/pagemap.rs index a76ead3c16f4..289d24d2a109 100644 --- a/third_party/rust/procfs-core/src/process/pagemap.rs +++ b/third_party/rust/procfs-core/src/process/pagemap.rs @@ -80,6 +80,7 @@ impl MemoryPageFlags { } /// A Page Frame Number, representing a 4 kiB physical memory page +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Pfn(pub u64); diff --git a/toolkit/crashreporter/minidump-analyzer/Cargo.toml b/toolkit/crashreporter/minidump-analyzer/Cargo.toml index a316169497fe..bf5f7fa645be 100644 --- a/toolkit/crashreporter/minidump-analyzer/Cargo.toml +++ b/toolkit/crashreporter/minidump-analyzer/Cargo.toml @@ -10,13 +10,13 @@ edition = "2021" [dependencies] anyhow = "1.0.69" async-trait = "0.1" -breakpad-symbols = "0.22" +breakpad-symbols = "0.24" futures-executor = { version = "0.3", features = ["thread-pool"] } futures-util = { version = "0.3", features = ["channel"] } lazy_static = "1.4.0" log = "0.4" -minidump = "0.22" -minidump-unwind = { version = "0.22", features = ["debuginfo-unwind"] } +minidump = "0.24" +minidump-unwind = { version = "0.24", features = ["debuginfo-unwind"] } serde_json = "1" [dependencies.windows-sys] diff --git a/toolkit/crashreporter/process_reader/Cargo.toml b/toolkit/crashreporter/process_reader/Cargo.toml index 4bbf105e0d26..f866ae31692f 100644 --- a/toolkit/crashreporter/process_reader/Cargo.toml +++ b/toolkit/crashreporter/process_reader/Cargo.toml @@ -8,7 +8,7 @@ license = "MPL-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -goblin = { version = "0.7", features = ["elf32", "elf64", "pe32", "pe64"] } +goblin = { version = "0.9", features = ["elf32", "elf64", "pe32", "pe64"] } memoffset = "0.9" thiserror = "1.0" diff --git a/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml b/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml index 2bc7f8f65717..2e50e6b7df1b 100644 --- a/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml +++ b/toolkit/crashreporter/rust_minidump_writer_linux/Cargo.toml @@ -9,6 +9,6 @@ license = "MPL-2.0" [dependencies] crash-context = "0.6.1" -minidump-writer = "0.10" +minidump-writer = "0.10.2" libc = "0.2.74" anyhow = "1.0"