Bug 1823692 - Storing the memory around the instruction IP is broken in 32-bit Linux builds r=gsvelto,glandium,supply-chain-reviewers

Using the newer version of the crash-context crate corrects the 32-bit Linux context structure,
which was the cause of the IP memory not being stored (among possibly other 32-bit Linux issues).

Differential Revision: https://phabricator.services.mozilla.com/D174314
This commit is contained in:
Alex Franchuk 2023-04-06 13:38:54 +00:00
parent a4517586e4
commit 22d0f39eef
30 changed files with 2766 additions and 742 deletions

View File

@ -105,11 +105,6 @@ git = "https://github.com/mozilla/uniffi-rs.git"
rev = "bc7ff8977bf38d0fdd1a458810b14f434d4dc4de"
replace-with = "vendored-sources"
[source."git+https://github.com/rust-minidump/minidump-writer.git?rev=59179c83ba62e4378619c6967c0b8c0c077cac2d"]
git = "https://github.com/rust-minidump/minidump-writer.git"
rev = "59179c83ba62e4378619c6967c0b8c0c077cac2d"
replace-with = "vendored-sources"
[source."git+https://github.com/servo/rust-cssparser?rev=45bc47e2bcb846f1efb5aea156be5fe7d18624bf"]
git = "https://github.com/servo/rust-cssparser"
rev = "45bc47e2bcb846f1efb5aea156be5fe7d18624bf"

97
Cargo.lock generated
View File

@ -43,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44"
dependencies = [
"alsa-sys",
"bitflags",
"bitflags 1.3.2",
"libc",
"nix 0.24.99",
]
@ -248,7 +248,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd92208b8b0c2477d1123f9fa898e35d9f7d9340e3f26ddda27bf37a608eff99"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -325,7 +325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e73e25e6ae754b553f930c48af8f0e5ca71e641c419151e95bafd5644ff6e21b"
dependencies = [
"base64",
"bitflags",
"bitflags 1.3.2",
"cfg-if 1.0.0",
"core-foundation",
"devd-rs",
@ -420,7 +420,7 @@ version = "0.64.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cexpr",
"clang-sys",
"lazy_static",
@ -455,6 +455,13 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.999.999"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "bitreader"
version = "0.3.6"
@ -733,7 +740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
dependencies = [
"atty",
"bitflags",
"bitflags 1.3.2",
"clap_derive",
"clap_lex",
"indexmap",
@ -821,7 +828,7 @@ version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation",
"core-graphics-types",
"foreign-types",
@ -834,7 +841,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"core-foundation",
"foreign-types",
"libc",
@ -918,14 +925,13 @@ dependencies = [
[[package]]
name = "crash-context"
version = "0.5.1"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8bb7283a39cb25312513ccd35ce14098a4a8398e821a13130c76bb803c4a3b0"
checksum = "6d433b84b88830c0c253292a52fe43bd3f385668b6a39a84ce291e6e7db52724"
dependencies = [
"cfg-if 1.0.0",
"libc",
"mach2",
"winapi",
]
[[package]]
@ -1064,7 +1070,7 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6203cd567a2ae4382077cc2160738517462c93cf77f3910fa18b2a74549abc84"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cubeb-sys",
]
@ -1075,7 +1081,7 @@ source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=93b5c01a131f65c8
dependencies = [
"atomic",
"audio-mixer",
"bitflags",
"bitflags 1.3.2",
"coreaudio-sys-utils",
"cubeb-backend",
"float-cmp",
@ -1113,7 +1119,7 @@ name = "d3d12"
version = "0.6.0"
source = "git+https://github.com/gfx-rs/d3d12-rs?rev=b940b1d71#b940b1d71ab7083ae80eec697872672dc1f2bd32"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"libloading",
"winapi",
]
@ -1357,7 +1363,7 @@ dependencies = [
name = "dom"
version = "0.1.0"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -1823,7 +1829,7 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"fuchsia-zircon-sys",
]
@ -2304,7 +2310,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"gpu-alloc-types",
]
@ -2314,7 +2320,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -2323,7 +2329,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"gpu-descriptor-types",
"hashbrown",
]
@ -2334,7 +2340,7 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -2397,7 +2403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584"
dependencies = [
"base64",
"bitflags",
"bitflags 1.3.2",
"bytes",
"headers-core",
"http",
@ -2970,7 +2976,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447a296f7aca299cfbb50f4e4f3d49451549af655fb7215d7f8c0c3d64bad42b"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"byteorder",
"libc",
"lmdb-rkv-sys",
@ -3160,7 +3166,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de11355d1f6781482d027a3b4d4de7825dcedb197bf573e0596d00008402d060"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"block",
"core-graphics-types",
"foreign-types",
@ -3174,7 +3180,7 @@ version = "0.7.0"
source = "git+https://github.com/mozilla/midir.git?rev=519e651241e867af3391db08f9ae6400bc023e18#519e651241e867af3391db08f9ae6400bc023e18"
dependencies = [
"alsa",
"bitflags",
"bitflags 1.3.2",
"coremidi",
"js-sys",
"libc",
@ -3216,7 +3222,7 @@ version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "694717103b2c15f8c16ddfaec1333fe15673bc22b10ffa6164427415701974ba"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"debugid",
"enum-primitive-derive",
"num-traits",
@ -3227,9 +3233,11 @@ dependencies = [
[[package]]
name = "minidump-writer"
version = "0.7.0"
source = "git+https://github.com/rust-minidump/minidump-writer.git?rev=59179c83ba62e4378619c6967c0b8c0c077cac2d#59179c83ba62e4378619c6967c0b8c0c077cac2d"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8109e02c3cf4a587eea0bec18ccdfecc9041f91b5ebffa223b1e692c9a223c26"
dependencies = [
"bitflags 2.999.999",
"byteorder",
"cfg-if 1.0.0",
"crash-context",
@ -3243,7 +3251,6 @@ dependencies = [
"scroll",
"tempfile",
"thiserror",
"winapi",
]
[[package]]
@ -3481,7 +3488,7 @@ version = "0.11.0"
source = "git+https://github.com/gfx-rs/naga?rev=9742f1616c3e3dd2cc9a5880616fc886c391bb9f#9742f1616c3e3dd2cc9a5880616fc886c391bb9f"
dependencies = [
"bit-set",
"bitflags",
"bitflags 1.3.2",
"codespan-reporting",
"hexf-parse",
"indexmap",
@ -3627,7 +3634,7 @@ version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cfg-if 1.0.0",
"libc",
"static_assertions",
@ -3675,7 +3682,7 @@ source = "git+https://github.com/mozilla/application-services?rev=86c84c217036c1
name = "nsstring"
version = "0.1.0"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"encoding_rs",
]
@ -4215,7 +4222,7 @@ name = "pulse"
version = "0.3.0"
source = "git+https://github.com/mozilla/cubeb-pulse-rs?rev=cf48897be5cbe147d051ebbbe1eaf5fd8fb6bbc9#cf48897be5cbe147d051ebbbe1eaf5fd8fb6bbc9"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"pulse-ffi",
]
@ -4350,7 +4357,7 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
@ -4406,7 +4413,7 @@ checksum = "9f0ea3af1393b22f8fe25615b6fa5d13072b7b622e66acffc8b12b2baa0342b1"
dependencies = [
"arrayref",
"bincode",
"bitflags",
"bitflags 1.3.2",
"byteorder",
"id-arena",
"lazy_static",
@ -4428,7 +4435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff"
dependencies = [
"base64",
"bitflags",
"bitflags 1.3.2",
"serde",
]
@ -4470,7 +4477,7 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
@ -4602,7 +4609,7 @@ dependencies = [
name = "selectors"
version = "0.22.0"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"cssparser",
"derive_more",
"fxhash",
@ -4887,7 +4894,7 @@ version = "0.2.0+1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"num-traits",
]
@ -4961,7 +4968,7 @@ dependencies = [
"arrayvec",
"atomic_refcell",
"bindgen 0.64.0",
"bitflags",
"bitflags 1.3.2",
"byteorder",
"cssparser",
"derive_more",
@ -5026,7 +5033,7 @@ name = "style_traits"
version = "0.0.1"
dependencies = [
"app_units",
"bitflags",
"bitflags 1.3.2",
"cssparser",
"euclid",
"lazy_static",
@ -6008,7 +6015,7 @@ name = "webrender"
version = "0.62.0"
dependencies = [
"bincode",
"bitflags",
"bitflags 1.3.2",
"build-parallel",
"byteorder",
"derive_more",
@ -6045,7 +6052,7 @@ name = "webrender_api"
version = "0.62.0"
dependencies = [
"app_units",
"bitflags",
"bitflags 1.3.2",
"byteorder",
"crossbeam-channel",
"euclid",
@ -6092,7 +6099,7 @@ dependencies = [
name = "webrender_build"
version = "0.0.2"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"lazy_static",
"serde",
]
@ -6123,7 +6130,7 @@ source = "git+https://github.com/gfx-rs/wgpu?rev=73b4257b17cc62ecc8df6d6aa3730bd
dependencies = [
"arrayvec",
"bit-vec",
"bitflags",
"bitflags 1.3.2",
"codespan-reporting",
"fxhash",
"log",
@ -6148,7 +6155,7 @@ dependencies = [
"arrayvec",
"ash",
"bit-set",
"bitflags",
"bitflags 1.3.2",
"block",
"core-graphics-types",
"d3d12",
@ -6181,7 +6188,7 @@ name = "wgpu-types"
version = "0.15.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=73b4257b17cc62ecc8df6d6aa3730bd9c6cba4b9#73b4257b17cc62ecc8df6d6aa3730bd9c6cba4b9"
dependencies = [
"bitflags",
"bitflags 1.3.2",
"js-sys",
"serde",
"web-sys",

View File

@ -93,6 +93,9 @@ vcpkg = { path = "build/rust/vcpkg" }
# Helper crate for integration in the gecko build system.
mozbuild = { path = "build/rust/mozbuild" }
# Patch bitflags 2.0 to 1.0 while not too many crates use 2.0 features
bitflags = { path = "build/rust/bitflags" }
# Patch cfg-if 0.1 to 1.0
cfg-if = { path = "build/rust/cfg-if" }
@ -160,7 +163,6 @@ firefox-on-glean = { path = "toolkit/components/glean/api" }
libudev-sys = { path = "dom/webauthn/libudev-sys" }
packed_simd = { package = "packed_simd_2", git = "https://github.com/hsivonen/packed_simd", rev="412f9a0aa556611de021bde89dee8fefe6e0fbbd" }
midir = { git = "https://github.com/mozilla/midir.git", rev = "519e651241e867af3391db08f9ae6400bc023e18" }
minidump-writer = { git = "https://github.com/rust-minidump/minidump-writer.git", rev = "59179c83ba62e4378619c6967c0b8c0c077cac2d" }
# warp 0.3.3 + https://github.com/seanmonstar/warp/pull/1007
warp = { git = "https://github.com/glandium/warp", rev = "4af45fae95bc98b0eba1ef0db17e1dac471bb23d" }

View File

@ -0,0 +1,11 @@
[package]
name = "bitflags"
version = "2.999.999"
edition = "2018"
license = "MPL-2.0"
[lib]
path = "lib.rs"
[dependencies.bitflags]
version = "1.0"

View File

@ -0,0 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub use bitflags::*;

View File

@ -313,6 +313,12 @@ criteria = "safe-to-deploy"
version = "0.6.3"
notes = "Another crate I own via contain-rs that is ancient and in maintenance mode but otherwise perfectly fine."
[[audits.bitflags]]
who = "Alex Franchuk <afranchuk@mozilla.com>"
criteria = "safe-to-deploy"
delta = "1.3.2 -> 2.0.2"
notes = "Removal of some unsafe code/methods. No changes to externals, just some refactoring (mostly internal)."
[[audits.block-buffer]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -458,6 +464,16 @@ criteria = "safe-to-deploy"
version = "0.5.1"
notes = "Mozilla employees contributed to this crate and the remaining code was fully audited"
[[audits.crash-context]]
who = "Alex Franchuk <afranchuk@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.5.1 -> 0.6.0"
notes = """
There are few changes. The main change is the removal of `winapi` in favor of
manually-generated bindings (which are minimal). The few small bugfixes are
sound.
"""
[[audits.crossbeam-channel]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -1408,6 +1424,12 @@ who = "Bobby Holley <bobbyholley@gmail.com>"
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.7.0@git:7d76616d27b9dc87fe3a94639b8b4f947d52a6aa"
[[audits.minidump-writer]]
who = "Alex Franchuk <afranchuk@mozilla.com>"
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.8.0"
notes = "The code in this crate was written or reviewed by Mozilla employees, the crate it evolved from was written specifically for gecko."
[[audits.miniz_oxide]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"

View File

@ -87,10 +87,6 @@ notes = "This is a first-party crate which is also published to crates.io. We ce
audit-as-crates-io = true
notes = "This is a pinned version of the upstream code, presumably to get a fix that hadn't been released yet. We should consider switching to the latest official release."
[policy.minidump-writer]
audit-as-crates-io = true
notes = "This is a pinned version of the upstream code, presumably to get a fix that hadn't been released yet. We should consider switching to the latest official release."
[policy."mio:0.6.23"]
audit-as-crates-io = true
notes = "Version 0.6.23 is a local fork of upstream which just twiddles some dependencies."

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"314a7e0b67fad194bbf9b7a3fe0e6ce6855545b16102c96d04dbb99d4b116507","Cargo.toml":"e4e9c2b053fd3370115968d95fc2f1a7a7163e59c55bf0e624d3c7279ed0fda4","LICENSE-APACHE":"8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90","LICENSE-MIT":"090a294a492ab2f41388252312a65cf2f0e423330b721a68c6665ac64766753b","README.md":"5df5b51de9b86b2e724954224209463a48f8549fd023bcb10c1d9cecc754fff2","release.toml":"287ba3b6c89e3b289eae59827d36d6eb6e27b88cc2ada2c0d9a663c8b487117e","src/lib.rs":"26957a6a2555ab82aa9b6d3d1f24efaf20753d6c5eb1510395789283890ac1d1","src/linux.rs":"744008378bfe2d2bbe59d6bbbfb458a5f6401d4a4f8834dbc09e0d0b172b45cc","src/linux/getcontext.rs":"4164236732556d71cbb9e04bf4f2b41fd6f51f9bb94dfb974158cc5f49c3c789","src/linux/getcontext/aarch64.rs":"1193e68f06f7f2f4d3e64d80a196804e6cdfd03643ac50332c7af10928a5eccb","src/linux/getcontext/arm.rs":"682f163f4a96c21930e37427a6d687efc68199cbd8a9125b34d99a81280dd31b","src/linux/getcontext/x86.rs":"9f83062e99204d6ed24001be4d3b0d39974ab7a644003fb503795fcdf9316e87","src/linux/getcontext/x86_64.rs":"278ee4e5c64230da96c018ae2c539d1e3203f0ad4c9a9750044c2f88708f091e","src/mac.rs":"13d25443466d387eabf28adae361708f4b6297949c7eeb5bf1b38cb0ca13a418","src/mac/guard.rs":"115d1e8d5ac7bd9ecc666b11a0c584ed1e997160aacb0a1cc0f215ff5a1e9803","src/mac/ipc.rs":"2fc139ee5b70964bd726a30853d7fe9f74f7a6e0f8cf3d150e72a2ac802c1fba","src/mac/resource.rs":"78db4d344b285258befbb1c47cb4fba580f55ed03742242e561d4b3f383d1ada","src/windows.rs":"e22f7b5f1d067c08da1ff7c435ec3a3b2abe5cc9804490c4e26d1f08f0d2aefb","src/windows/ffi.rs":"87fb4d4e11ae19bf805f05b77daac81a265ca512ffc3506951a85974cdbb11a0","src/windows/ffi/aarch64.rs":"312ea235320a8b72b427857812637fe40e08aeef484b80fd6b5a0ca96d6b9c10","src/windows/ffi/x86_64.rs":"4d65503b229a995efce95536a11632b879d78fe4a1c7d38d89a378900c0aec86"},"package":"b8bb7283a39cb25312513ccd35ce14098a4a8398e821a13130c76bb803c4a3b0"}
{"files":{"CHANGELOG.md":"5108348ce76a50393b51b3711f77910f419fd782eaf5b5aff0c6650c50ad65c4","Cargo.toml":"d116b62ca2aec61c49001c19a37d5768407ee3d31fd8b8835ab8e9565e25b884","LICENSE-APACHE":"8173d5c29b4f956d532781d2b86e4e30f83e6b7878dce18c919451d6ba707c90","LICENSE-MIT":"090a294a492ab2f41388252312a65cf2f0e423330b721a68c6665ac64766753b","README.md":"5df5b51de9b86b2e724954224209463a48f8549fd023bcb10c1d9cecc754fff2","release.toml":"287ba3b6c89e3b289eae59827d36d6eb6e27b88cc2ada2c0d9a663c8b487117e","src/lib.rs":"26957a6a2555ab82aa9b6d3d1f24efaf20753d6c5eb1510395789283890ac1d1","src/linux.rs":"cf05c1217709a60adeea08e8623438f68a18dea66758b194de0e07ff398b090d","src/linux/getcontext.rs":"4164236732556d71cbb9e04bf4f2b41fd6f51f9bb94dfb974158cc5f49c3c789","src/linux/getcontext/aarch64.rs":"1193e68f06f7f2f4d3e64d80a196804e6cdfd03643ac50332c7af10928a5eccb","src/linux/getcontext/arm.rs":"682f163f4a96c21930e37427a6d687efc68199cbd8a9125b34d99a81280dd31b","src/linux/getcontext/x86.rs":"9f83062e99204d6ed24001be4d3b0d39974ab7a644003fb503795fcdf9316e87","src/linux/getcontext/x86_64.rs":"278ee4e5c64230da96c018ae2c539d1e3203f0ad4c9a9750044c2f88708f091e","src/mac.rs":"13d25443466d387eabf28adae361708f4b6297949c7eeb5bf1b38cb0ca13a418","src/mac/guard.rs":"115d1e8d5ac7bd9ecc666b11a0c584ed1e997160aacb0a1cc0f215ff5a1e9803","src/mac/ipc.rs":"2fc139ee5b70964bd726a30853d7fe9f74f7a6e0f8cf3d150e72a2ac802c1fba","src/mac/resource.rs":"8289db9294a45d6148329d537530512913c456a182783059a832767e39c67295","src/windows.rs":"c6c043cf56cf0840cc1373edc4bd39cf829566d181e50589174745629ab2ad37","tests/capture_context.rs":"899e94c522cd015fd1f45230aff5c8970346ba20623da46cd34da892bbd07f7e"},"package":"6d433b84b88830c0c253292a52fe43bd3f385668b6a39a84ce291e6e7db52724"}

View File

@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [0.6.0] - 2023-04-03
### Changed
- [PR#70](https://github.com/EmbarkStudios/crash-handling/pull/70) removed the `winapi` dependency in favor of embedded bindings to avoid dependencies.
- [PR#70](https://github.com/EmbarkStudios/crash-handling/pull/70) removed the asm implementations for Windows CPU context retrieval in favor of using `RtlCaptureContext`. This means that floating state is not captured, but is otherwise and improvement.
## [0.5.1] - 2022-11-17
### Fixed
- [PR#66](https://github.com/EmbarkStudios/crash-handling/pull/66) (apparently) resolved [#65](https://github.com/EmbarkStudios/crash-handling/issues/65) by...changing from AT&T to Intel syntax. This shouldn't have changed anything, but it did, and I'm too tired and have other things to work on, so here we are.
@ -53,7 +58,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Initial pass of crash-context, Linux only
<!-- next-url -->
[Unreleased]: https://github.com/EmbarkStudios/crash-handling/compare/crash-context-0.5.1...HEAD
[Unreleased]: https://github.com/EmbarkStudios/crash-handling/compare/crash-context-0.6.0...HEAD
[0.6.0]: https://github.com/EmbarkStudios/crash-handling/compare/crash-context-0.5.1...crash-context-0.6.0
[0.5.1]: https://github.com/EmbarkStudios/crash-handling/compare/crash-context-0.5.0...crash-context-0.5.1
[0.5.0]: https://github.com/EmbarkStudios/crash-handling/compare/crash-context-0.4.0...crash-context-0.5.0
[0.4.0]: https://github.com/EmbarkStudios/crash-handling/compare/0.3.1...crash-context-0.4.0

View File

@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.59.0"
name = "crash-context"
version = "0.5.1"
version = "0.6.0"
authors = [
"Embark <opensource@embark-studios.com>",
"Jake Shadle <jake.shadle@embark-studios.com>",
@ -40,7 +40,3 @@ version = "0.2"
[target."cfg(target_os = \"macos\")".dependencies.mach2]
version = "0.4"
[target."cfg(target_os = \"windows\")".dependencies.winapi]
version = "0.3"
features = ["winnt"]

View File

@ -131,7 +131,7 @@ cfg_if::cfg_if! {
#[derive(Clone)]
#[doc(hidden)]
pub struct mcontext_t {
pub gregs: [i64; 23],
pub gregs: [i32; 23],
pub fpregs: *mut fpregset_t,
pub oldmask: u32,
pub cr2: u32,

View File

@ -185,7 +185,7 @@ impl CpuResourceException {
debug_assert_eq!(resource_exc_kind(code), ResourceKind::Cpu as u8);
let flavor = Flavor::from(code);
let interval_seconds = ((code >> 7) & 0x1ffffff) as u64;
let interval_seconds = (code >> 7) & 0x1ffffff;
let limit = (code & 0x7f) as u8;
let consumed = subcode.map_or(0, |sc| sc & 0x7f) as u8;
@ -262,7 +262,7 @@ impl WakeupsResourceException {
let flavor = Flavor::from(code);
// Note that Apple has a bug in exc_resource.h where the masks in the
// decode macros for the interval and the permitted wakeups have been swapped
let interval_seconds = ((code >> 20) & 0xfff) as u64;
let interval_seconds = (code >> 20) & 0xfff;
let permitted = (code & 0xfffff) as u32;
let observed = subcode.map_or(0, |sc| sc & 0xfffff) as u32;
@ -388,7 +388,7 @@ impl IoResourceException {
debug_assert_eq!(resource_exc_kind(code), ResourceKind::Io as u8);
let flavor = Flavor::from(code);
let interval_seconds = ((code >> 15) & 0x1ffff) as u64;
let interval_seconds = (code >> 15) & 0x1ffff;
let limit_mib = (code & 0x7fff) as u16;
let observed_mib = subcode.map_or(0, |sc| sc & 0x7fff) as u16;

View File

@ -1,18 +1,262 @@
pub mod ffi;
/// Full Windows crash context
pub struct CrashContext {
/// The information on the exception.
///
/// Note that this is a pointer into the actual memory of the crashed process,
/// and is a pointer to an [EXCEPTION_POINTERS](https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_pointers)
pub exception_pointers: *const ffi::EXCEPTION_POINTERS,
pub exception_pointers: *const EXCEPTION_POINTERS,
/// The top level exception code from the exception_pointers. This is provided
/// so that external processes don't need to use `ReadProcessMemory` to inspect
/// the exception code
pub exception_code: u32,
pub exception_code: i32,
/// The pid of the process that crashed
pub process_id: u32,
/// The thread id on which the exception occurred
pub thread_id: u32,
}
#[link(name = "kernel32")]
extern "system" {
#[link_name = "RtlCaptureContext"]
pub fn capture_context(ctx_rec: *mut CONTEXT);
}
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
#[repr(C, align(16))]
pub struct M128A {
pub Low: u64,
pub High: i64,
}
#[repr(C)]
pub struct CONTEXT_0_0 {
pub Header: [M128A; 2],
pub Legacy: [M128A; 8],
pub Xmm0: M128A,
pub Xmm1: M128A,
pub Xmm2: M128A,
pub Xmm3: M128A,
pub Xmm4: M128A,
pub Xmm5: M128A,
pub Xmm6: M128A,
pub Xmm7: M128A,
pub Xmm8: M128A,
pub Xmm9: M128A,
pub Xmm10: M128A,
pub Xmm11: M128A,
pub Xmm12: M128A,
pub Xmm13: M128A,
pub Xmm14: M128A,
pub Xmm15: M128A,
}
#[repr(C, align(16))]
pub struct XSAVE_FORMAT {
pub ControlWord: u16,
pub StatusWord: u16,
pub TagWord: u8,
pub Reserved1: u8,
pub ErrorOpcode: u16,
pub ErrorOffset: u32,
pub ErrorSelector: u16,
pub Reserved2: u16,
pub DataOffset: u32,
pub DataSelector: u16,
pub Reserved3: u16,
pub MxCsr: u32,
pub MxCsr_Mask: u32,
pub FloatRegisters: [M128A; 8],
pub XmmRegisters: [M128A; 16],
pub Reserved4: [u8; 96],
}
#[repr(C)]
pub union CONTEXT_0 {
pub FltSave: std::mem::ManuallyDrop<XSAVE_FORMAT>,
pub Anonymous: std::mem::ManuallyDrop<CONTEXT_0_0>,
}
#[repr(C, align(16))]
pub struct CONTEXT {
pub P1Home: u64,
pub P2Home: u64,
pub P3Home: u64,
pub P4Home: u64,
pub P5Home: u64,
pub P6Home: u64,
pub ContextFlags: u32,
pub MxCsr: u32,
pub SegCs: u16,
pub SegDs: u16,
pub SegEs: u16,
pub SegFs: u16,
pub SegGs: u16,
pub SegSs: u16,
pub EFlags: u32,
pub Dr0: u64,
pub Dr1: u64,
pub Dr2: u64,
pub Dr3: u64,
pub Dr6: u64,
pub Dr7: u64,
pub Rax: u64,
pub Rcx: u64,
pub Rdx: u64,
pub Rbx: u64,
pub Rsp: u64,
pub Rbp: u64,
pub Rsi: u64,
pub Rdi: u64,
pub R8: u64,
pub R9: u64,
pub R10: u64,
pub R11: u64,
pub R12: u64,
pub R13: u64,
pub R14: u64,
pub R15: u64,
pub Rip: u64,
pub Anonymous: CONTEXT_0,
pub VectorRegister: [M128A; 26],
pub VectorControl: u64,
pub DebugControl: u64,
pub LastBranchToRip: u64,
pub LastBranchFromRip: u64,
pub LastExceptionToRip: u64,
pub LastExceptionFromRip: u64,
}
} else if #[cfg(target_arch = "x86")] {
#[repr(C)]
pub struct FLOATING_SAVE_AREA {
pub ControlWord: u32,
pub StatusWord: u32,
pub TagWord: u32,
pub ErrorOffset: u32,
pub ErrorSelector: u32,
pub DataOffset: u32,
pub DataSelector: u32,
pub RegisterArea: [u8; 80],
pub Spare0: u32,
}
#[repr(C, packed(4))]
pub struct CONTEXT {
pub ContextFlags: u32,
pub Dr0: u32,
pub Dr1: u32,
pub Dr2: u32,
pub Dr3: u32,
pub Dr6: u32,
pub Dr7: u32,
pub FloatSave: FLOATING_SAVE_AREA,
pub SegGs: u32,
pub SegFs: u32,
pub SegEs: u32,
pub SegDs: u32,
pub Edi: u32,
pub Esi: u32,
pub Ebx: u32,
pub Edx: u32,
pub Ecx: u32,
pub Eax: u32,
pub Ebp: u32,
pub Eip: u32,
pub SegCs: u32,
pub EFlags: u32,
pub Esp: u32,
pub SegSs: u32,
pub ExtendedRegisters: [u8; 512],
}
} else if #[cfg(target_arch = "aarch64")] {
#[repr(C)]
pub struct ARM64_NT_NEON128_0 {
pub Low: u64,
pub High: i64,
}
#[repr(C)]
pub union ARM64_NT_NEON128 {
pub Anonymous: std::mem::ManuallyDrop<ARM64_NT_NEON128_0>,
pub D: [f64; 2],
pub S: [f32; 4],
pub H: [u16; 8],
pub B: [u8; 16],
}
#[repr(C)]
pub struct CONTEXT_0_0 {
pub X0: u64,
pub X1: u64,
pub X2: u64,
pub X3: u64,
pub X4: u64,
pub X5: u64,
pub X6: u64,
pub X7: u64,
pub X8: u64,
pub X9: u64,
pub X10: u64,
pub X11: u64,
pub X12: u64,
pub X13: u64,
pub X14: u64,
pub X15: u64,
pub X16: u64,
pub X17: u64,
pub X18: u64,
pub X19: u64,
pub X20: u64,
pub X21: u64,
pub X22: u64,
pub X23: u64,
pub X24: u64,
pub X25: u64,
pub X26: u64,
pub X27: u64,
pub X28: u64,
pub Fp: u64,
pub Lr: u64,
}
#[repr(C)]
pub union CONTEXT_0 {
pub Anonymous: std::mem::ManuallyDrop<CONTEXT_0_0>,
pub X: [u64; 31],
}
#[repr(C, align(16))]
pub struct CONTEXT {
pub ContextFlags: u32,
pub Cpsr: u32,
pub Anonymous: CONTEXT_0,
pub Sp: u64,
pub Pc: u64,
pub V: [ARM64_NT_NEON128; 32],
pub Fpcr: u32,
pub Fpsr: u32,
pub Bcr: [u32; 8],
pub Bvr: [u64; 8],
pub Wcr: [u32; 2],
pub Wvr: [u64; 2],
}
}
}
pub type NTSTATUS = i32;
pub type BOOL = i32;
#[repr(C)]
pub struct EXCEPTION_RECORD {
pub ExceptionCode: NTSTATUS,
pub ExceptionFlags: u32,
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ExceptionAddress: *mut std::ffi::c_void,
pub NumberParameters: u32,
pub ExceptionInformation: [usize; 15],
}
#[repr(C)]
pub struct EXCEPTION_POINTERS {
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ContextRecord: *mut CONTEXT,
}

View File

@ -1,49 +0,0 @@
//! Custom bindings to `CONTEXT` and some structures that relate to it, to both
//! deal with bugs in bindings, as well as not be dependent particularly on
//! `windows-sys` due the massive amount of version churn that crate introduces.
//!
//! Both [`winapi`](https://docs.rs/winapi/latest/winapi/) and
//! [`windows-sys`](https://docs.rs/windows-sys/latest/windows_sys/) have
//! incorrect bindings with regards to `CONTEXT` and its related structures.
//! These structures **must** be aligned to 16 bytes, but [are not](https://github.com/microsoft/win32metadata/issues/1044).
#![allow(non_snake_case)]
extern "C" {
/// Reimplementation of [`RtlCaptureContext`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtlcapturecontext)
///
/// As noted above, the structures from `winapi` and `windows-sys` have
/// incorrect alignment.
///
/// In addition, `RtlCaptureContext` only captures the state of the integer
/// registers, while this implementation additionally captures floating point
/// and vector state.
///
/// The implementation is ported from Crashpad.
///
/// - [x86](https://github.com/chromium/crashpad/blob/f742c1aa4aff1834dc55e97895f8cdfdfc945a21/util/misc/capture_context_win.asm)
/// - [aarch64](https://github.com/chromium/crashpad/blob/f742c1aa4aff1834dc55e97895f8cdfdfc945a21/util/misc/capture_context_win_arm64.asm)
pub fn capture_context(ctx: *mut CONTEXT);
}
pub use winapi::um::winnt::EXCEPTION_RECORD;
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
mod x86_64;
pub use x86_64::*;
} else if #[cfg(target_arch = "x86")] {
compile_error!("Please file an issue if you care about this target");
//mod x86;
} else if #[cfg(target_arch = "aarch64")] {
mod aarch64;
pub use aarch64::*;
}
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct EXCEPTION_POINTERS {
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ContextRecord: *mut CONTEXT,
}

View File

@ -1,143 +0,0 @@
// Copyright 2019 The Crashpad Authors
//
// 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.
#[derive(Copy, Clone)]
// Note this is intentionally using natural alignment
#[repr(C)]
pub union ARM64_NT_NEON128 {
pub Anonymous: ARM64_NT_NEON128_0,
pub D: [f64; 2],
pub S: [f32; 4],
pub H: [u16; 8],
pub B: [u8; 16],
}
#[derive(Copy, Clone)]
// Note this is intentionally using natural alignment
#[repr(C)]
pub struct ARM64_NT_NEON128_0 {
pub Low: u64,
pub High: i64,
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT {
pub ContextFlags: u32,
pub Cpsr: u32,
pub Anonymous: CONTEXT_0,
pub Sp: u64,
pub Pc: u64,
pub V: [ARM64_NT_NEON128; 32],
pub Fpcr: u32,
pub Fpsr: u32,
pub Bcr: [u32; 8],
pub Bvr: [u64; 8],
pub Wcr: [u32; 2],
pub Wvr: [u64; 2],
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub union CONTEXT_0 {
pub Anonymous: CONTEXT_0_0,
pub X: [u64; 31],
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT_0_0 {
pub X0: u64,
pub X1: u64,
pub X2: u64,
pub X3: u64,
pub X4: u64,
pub X5: u64,
pub X6: u64,
pub X7: u64,
pub X8: u64,
pub X9: u64,
pub X10: u64,
pub X11: u64,
pub X12: u64,
pub X13: u64,
pub X14: u64,
pub X15: u64,
pub X16: u64,
pub X17: u64,
pub X18: u64,
pub X19: u64,
pub X20: u64,
pub X21: u64,
pub X22: u64,
pub X23: u64,
pub X24: u64,
pub X25: u64,
pub X26: u64,
pub X27: u64,
pub X28: u64,
pub Fp: u64,
pub Lr: u64,
}
std::arch::global_asm! {
".text",
".global capture_context",
"capture_context:",
// Save general purpose registers in context.regs[i].
// The original x0 can't be recovered.
"stp x0, x1, [x0, #0x008]",
"stp x2, x3, [x0, #0x018]",
"stp x4, x5, [x0, #0x028]",
"stp x6, x7, [x0, #0x038]",
"stp x8, x9, [x0, #0x048]",
"stp x10, x11, [x0, #0x058]",
"stp x12, x13, [x0, #0x068]",
"stp x14, x15, [x0, #0x078]",
"stp x16, x17, [x0, #0x088]",
"stp x18, x19, [x0, #0x098]",
"stp x20, x21, [x0, #0x0a8]",
"stp x22, x23, [x0, #0x0b8]",
"stp x24, x25, [x0, #0x0c8]",
"stp x26, x27, [x0, #0x0d8]",
"stp x28, x29, [x0, #0x0e8]",
// The original LR can't be recovered.
"str LR, [x0, #0x0f8]",
// Use x1 as a scratch register.
"mov x1, SP",
// context.sp
"str x1, [x0, #0x100]",
// The link register holds the return address for this function.
// context.pc
"str LR, [x0, #0x108]",
// pstate should hold SPSR but NZCV are the only bits we know about.
"mrs x1, NZCV",
// Enable Control flags, such as CONTEXT_ARM64, CONTEXT_CONTROL,
// CONTEXT_INTEGER
"ldr w1, =0x00400003",
// Set ControlFlags /0x000/ and pstate /0x004/ at the same time.
"str x1, [x0, #0x000]",
// Restore x1 from the saved context.
"ldr x1, [x0, #0x010]",
// TODO(https://crashpad.chromium.org/bug/300): save floating-point registers
"ret",
}

View File

@ -1,250 +0,0 @@
// Copyright 2015 The Crashpad Authors
//
// 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.
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct M128A {
pub Low: u64,
pub High: i64,
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct XSAVE_FORMAT {
pub ControlWord: u16,
pub StatusWord: u16,
pub TagWord: u8,
pub Reserved1: u8,
pub ErrorOpcode: u16,
pub ErrorOffset: u32,
pub ErrorSelector: u16,
pub Reserved2: u16,
pub DataOffset: u32,
pub DataSelector: u16,
pub Reserved3: u16,
pub MxCsr: u32,
pub MxCsr_Mask: u32,
pub FloatRegisters: [M128A; 8],
pub XmmRegisters: [M128A; 16],
pub Reserved4: [u8; 96],
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT {
pub P1Home: u64,
pub P2Home: u64,
pub P3Home: u64,
pub P4Home: u64,
pub P5Home: u64,
pub P6Home: u64,
pub ContextFlags: u32,
pub MxCsr: u32,
pub SegCs: u16,
pub SegDs: u16,
pub SegEs: u16,
pub SegFs: u16,
pub SegGs: u16,
pub SegSs: u16,
pub EFlags: u32,
pub Dr0: u64,
pub Dr1: u64,
pub Dr2: u64,
pub Dr3: u64,
pub Dr6: u64,
pub Dr7: u64,
pub Rax: u64,
pub Rcx: u64,
pub Rdx: u64,
pub Rbx: u64,
pub Rsp: u64,
pub Rbp: u64,
pub Rsi: u64,
pub Rdi: u64,
pub R8: u64,
pub R9: u64,
pub R10: u64,
pub R11: u64,
pub R12: u64,
pub R13: u64,
pub R14: u64,
pub R15: u64,
pub Rip: u64,
pub Anonymous: CONTEXT_0,
pub VectorRegister: [M128A; 26],
pub VectorControl: u64,
pub DebugControl: u64,
pub LastBranchToRip: u64,
pub LastBranchFromRip: u64,
pub LastExceptionToRip: u64,
pub LastExceptionFromRip: u64,
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub union CONTEXT_0 {
pub FltSave: XSAVE_FORMAT,
pub Anonymous: CONTEXT_0_0,
}
#[derive(Copy, Clone)]
#[repr(C, align(16))]
pub struct CONTEXT_0_0 {
pub Header: [M128A; 2],
pub Legacy: [M128A; 8],
pub Xmm0: M128A,
pub Xmm1: M128A,
pub Xmm2: M128A,
pub Xmm3: M128A,
pub Xmm4: M128A,
pub Xmm5: M128A,
pub Xmm6: M128A,
pub Xmm7: M128A,
pub Xmm8: M128A,
pub Xmm9: M128A,
pub Xmm10: M128A,
pub Xmm11: M128A,
pub Xmm12: M128A,
pub Xmm13: M128A,
pub Xmm14: M128A,
pub Xmm15: M128A,
}
std::arch::global_asm! {
".text",
".global capture_context",
"capture_context:",
".seh_proc capture_context",
"push rbp",
".seh_pushreg rbp",
"mov rbp, rsp",
".seh_setframe rbp, 0",
// Note that 16-byte stack alignment is not maintained because this function
// does not call out to any other.
// pushfq first, because some instructions affect rflags. rflags will be in [rbp-8].
"pushfq",
".seh_stackalloc 8",
".seh_endprologue",
"mov dword ptr [rcx+0x30], 0x10000", // ContextFlags
// General-purpose registers whose values havent changed can be captured directly.
"mov qword ptr [rcx+0x78], rax", // Rax
"mov qword ptr [rcx+0x88], rdx", // Rdx
"mov qword ptr [rcx+0x90], rbx", // Rbx
"mov qword ptr [rcx+0xa8], rsi", // Rsi
"mov qword ptr [rcx+0xb0], rdi", // Rdi
"mov qword ptr [rcx+0xb8], r8", // R8
"mov qword ptr [rcx+0xc0], r9", // R9
"mov qword ptr [rcx+0xc8], r10", // R10
"mov qword ptr [rcx+0xd0], r11", // R11
"mov qword ptr [rcx+0xd8], r12", // R12
"mov qword ptr [rcx+0xe0], r13", // R13
"mov qword ptr [rcx+0xe8], r14", // R14
"mov qword ptr [rcx+0xf0], r15", // R15
// Because of the calling convention, theres no way to recover the value of
// the callers rcx as it existed prior to calling this function. This
// function captures a snapshot of the register state at its return, which
// involves rcx containing a pointer to its first argument.
"mov qword ptr [rcx+0x80], rcx", // Rcx
// Now that the original value of rax has been saved, it can be repurposed to
// hold other registers values.
// Save mxcsr. This is duplicated in context->FltSave.MxCsr, saved by fxsave
// below.
"stmxcsr [rcx+0x34]", // MxCsr
// Segment registers.
"mov word ptr [rcx+0x38], cs", // SegCs
"mov word ptr [rcx+0x3a], ds", // SegDs
"mov word ptr [rcx+0x3c], es", // SegEs
"mov word ptr [rcx+0x3e], fs", // SegFs
"mov word ptr [rcx+0x40], gs", // SegGs
"mov word ptr [rcx+0x42], ss", // SegSs
// The original rflags was saved on the stack above. Note that the CONTEXT
// structure only stores eflags, the low 32 bits. The high 32 bits in rflags
// are reserved.
"mov rax, [rbp-8]",
"mov dword ptr [rcx+0x44], eax", // EFlags
// rsp was saved in rbp in this functions prologue, but the callers rsp is
// 16 more than this value: 8 for the original rbp saved on the stack in this
// functions prologue, and 8 for the return address saved on the stack by the
// call instruction that reached this function.
"lea rax, qword ptr [rbp+16]",
"mov qword ptr [rcx+0x98], rax",
// The original rbp was saved on the stack in this functions prologue.
"mov rax, rbp",
"mov qword ptr [rcx+0xa0], rax",
// rip cant be accessed directly, but the return address saved on the stack by
// the call instruction that reached this function can be used.
"mov rax, [rbp+8]",
"mov qword ptr [rcx+0xf8], rax",
// Zero out the fxsave area before performing the fxsave. Some of the fxsave
// area may not be written by fxsave, and some is definitely not written by
// fxsave. This also zeroes out the rest of the CONTEXT structure to its end,
// including the unused VectorRegister and VectorControl fields, and the debug
// control register fields.
"mov rbx, rcx",
"cld",
"lea rdi, [rcx+0x100]",
"xor rax, rax",
"mov rcx, 122",
"rep stosq",
"mov rcx, rbx",
// Save the floating point (including SSE) state. The CONTEXT structure is
// declared as 16-byte-aligned, which is correct for this operation.
"fxsave [rcx+0x100]",
// TODO: AVX/xsave support. https://crashpad.chromium.org/bug/58
// The register parameter home address fields arent used, so zero them out.
"mov qword ptr [rcx+0], 0",
"mov qword ptr [rcx+0x8], 0",
"mov qword ptr [rcx+0x10], 0",
"mov qword ptr [rcx+0x18], 0",
"mov qword ptr [rcx+0x20], 0",
// The debug registers cant be read from user code, so zero them out in the
// CONTEXT structure. context->ContextFlags doesnt indicate that they are
// present.
"mov qword ptr [rcx+0x48], 0",
"mov qword ptr [rcx+0x50], 0",
"mov qword ptr [rcx+0x58], 0",
"mov qword ptr [rcx+0x60], 0",
"mov qword ptr [rcx+0x68], 0",
"mov qword ptr [rcx+0x70], 0",
"mov qword ptr [rcx+0x78], 0",
// Clean up by restoring clobbered registers, even those considered volatile by
// the ABI, so that the captured context represents the state at this
// functions exit.
"mov rax, [rcx+0x78]",
"mov rbx, [rcx+0x90]",
"mov rdi, [rcx+0xb0]",
"popfq",
"pop rbp",
"ret",
".seh_endproc",
}

View File

@ -0,0 +1,49 @@
#[test]
fn captures() {
fn one() {
two();
}
fn two() {
three();
}
#[allow(unsafe_code)]
fn three() {
cfg_if::cfg_if! {
if #[cfg(target_os = "windows")] {
let ctx = unsafe {
let mut ctx = std::mem::MaybeUninit::zeroed();
crash_context::capture_context(ctx.as_mut_ptr());
ctx.assume_init()
};
cfg_if::cfg_if! {
if #[cfg(target_arch = "x86_64")] {
assert!(ctx.Rbp != 0);
assert!(ctx.Rsp != 0);
assert!(ctx.Rip != 0);
} else if #[cfg(target_arch = "x86")] {
assert!(ctx.Ebp != 0);
assert!(ctx.Esp != 0);
assert!(ctx.Eip != 0);
}
}
} else if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
let ctx = unsafe {
let mut ctx = std::mem::MaybeUninit::zeroed();
assert_eq!(crash_context::crash_context_getcontext(ctx.as_mut_ptr()), 0);
ctx.assume_init()
};
let gregs = &ctx.uc_mcontext.gregs;
assert!(gregs[libc::REG_RBP as usize] != 0);
assert!(gregs[libc::REG_RSP as usize] != 0);
assert!(gregs[libc::REG_RIP as usize] != 0);
}
}
}
one();
}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
* @Jake-Shadle

View File

@ -1,22 +0,0 @@
name: Security audit
on:
schedule:
# Runs at 00:00 UTC everyday
- cron: "0 0 * * *"
push:
paths:
- "**/Cargo.toml"
- "**/Cargo.lock"
- "**/audit.toml"
jobs:
audit:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: deny audit
uses: EmbarkStudios/cargo-deny-action@v1
with:
command: check advisories

View File

@ -1,86 +0,0 @@
name: Continuous Integration
on:
push:
branches:
- main
- github-actions
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt,clippy
- name: rustfmt
run: cargo fmt --all -- --check
- name: clippy
run: cargo clippy --all-features --all-targets -- -D warnings
test:
name: Test
runs-on: ${{ matrix.job.os }}
strategy:
matrix:
job:
- { os: ubuntu-22.04, target: x86_64-unknown-linux-gnu }
- { os: ubuntu-22.04, target: x86_64-unknown-linux-musl }
- { os: windows-2022, target: x86_64-pc-windows-msvc }
- { os: macos-12, target: x86_64-apple-darwin }
# TODO: Add macos aarch64 here once it becomes available as a runner
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
target: ${{ matrix.job.target }}
- name: Fetch
run: cargo fetch --target ${{ matrix.job.target }}
- name: Build
run: cargo test --target ${{ matrix.job.target }} --no-run
- name: Test
run: cargo test --target ${{ matrix.job.target }}
# This job builds non-tier1 targets that aren't already tested
build_lower_tier:
name: Build sources
runs-on: ${{ matrix.job.os }}
strategy:
matrix:
job:
- { os: ubuntu-22.04, target: i686-unknown-linux-gnu, use-cross: true }
#- { os: ubuntu-latest, target: i686-unknown-linux-musl, use-cross: true }
- { os: ubuntu-22.04, target: aarch64-unknown-linux-gnu, use-cross: true }
- { os: ubuntu-22.04, target: aarch64-unknown-linux-musl, use-cross: true }
#- { os: ubuntu-22.04, target: aarch64-linux-android, use-cross: true }
- { os: ubuntu-22.04, target: arm-unknown-linux-gnueabi, use-cross: true }
- { os: ubuntu-22.04, target: arm-unknown-linux-musleabi, use-cross: true }
- { os: ubuntu-22.04, target: arm-linux-androideabi, use-cross: true }
- { os: ubuntu-22.04, target: arm-unknown-linux-gnueabihf, use-cross: true }
# TODO: Remove this when aarch64 macs can be used as runners
- { os: macos-12, target: aarch64-apple-darwin, use-cross: false }
steps:
- uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
target: ${{ matrix.job.target }}
#- name: Unit tests
- name: Build
uses: actions-rs/cargo@v1
with:
#command: test
command: build
use-cross: ${{ matrix.job.use-cross }}
args: --target ${{ matrix.job.target }} --verbose --all-targets
#args: --target ${{ matrix.job.target }} --verbose -- --nocapture

View File

@ -8,6 +8,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- next-header -->
## [Unreleased] - ReleaseDate
## [0.8.0] - 2023-04-03
### Removed
- [PR#77](https://github.com/rust-minidump/minidump-writer/pull/77) removed the dependency on `winapi`, all bindings are either part of `minidump-writer` or `crash-context` now.
### Changed
- [PR#77](https://github.com/rust-minidump/minidump-writer/pull/77) closed [#67](https://github.com/rust-minidump/minidump-writer/issues/67) by allowing the user to specify the `MinidumpType` flags when creating a minidump.
### Fixed
- [PR#68](https://github.com/rust-minidump/minidump-writer/pull/68) resolved [#29](https://github.com/rust-minidump/minidump-writer/issues/29) by ignoring the bening `ESRCH` error when detaching pthreads. Thanks [@afranchuk](https://github.com/afranchuk)!
- [PR#74](https://github.com/rust-minidump/minidump-writer/pull/74) resolved [#73](https://github.com/rust-minidump/minidump-writer/issues/73) by ensuring the `NT_GNU_BUILD_ID` section had the proper correct `GNU` name before using it as the build identifier.
## [0.7.0] - 2022-11-17
### Changed
- [PR#65](https://github.com/rust-minidump/minidump-writer/pull/65) updated `crash-context` to 0.5, which has support for a custom `capture_context` to replace `RtlCaptureContext` on Windows, due to improper bindings and deficiencies, resolving [#63](https://github.com/rust-minidump/minidump-writer/issues/63).
@ -60,7 +71,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`
<!-- next-url -->
[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.7.0...HEAD
[Unreleased]: https://github.com/rust-minidump/minidump-writer/compare/0.8.0...HEAD
[0.8.0]: https://github.com/rust-minidump/minidump-writer/compare/0.7.0...0.8.0
[0.7.0]: https://github.com/rust-minidump/minidump-writer/compare/0.6.0...0.7.0
[0.6.0]: https://github.com/rust-minidump/minidump-writer/compare/0.5.0...0.6.0
[0.5.0]: https://github.com/rust-minidump/minidump-writer/compare/0.4.0...0.5.0

1839
third_party/rust/minidump-writer/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
[package]
edition = "2021"
name = "minidump-writer"
version = "0.7.0"
version = "0.8.0"
authors = ["Martin Sirringhaus"]
description = "Rust rewrite of Breakpad's minidump_writer"
homepage = "https://github.com/rust-minidump/minidump-writer"
@ -20,24 +20,40 @@ readme = "README.md"
license = "MIT"
repository = "https://github.com/rust-minidump/minidump-writer"
[dependencies]
byteorder = "1.3.2"
cfg-if = "1.0"
crash-context = "0.5"
memoffset = "0.8"
minidump-common = "0.15"
scroll = "0.11"
tempfile = "3.1.0"
thiserror = "1.0.21"
[dependencies.byteorder]
version = "1.3.2"
[dev-dependencies]
memmap2 = "0.5"
minidump = "0.15"
[dependencies.cfg-if]
version = "1.0"
[dependencies.crash-context]
version = "0.6"
[dependencies.memoffset]
version = "0.8"
[dependencies.minidump-common]
version = "0.15"
[dependencies.scroll]
version = "0.11"
[dependencies.tempfile]
version = "3.1.0"
[dependencies.thiserror]
version = "1.0.21"
[dev-dependencies.futures]
version = "0.3"
features = ["executor"]
[dev-dependencies.memmap2]
version = "0.5"
[dev-dependencies.minidump]
version = "0.15"
[target."cfg(any(target_os = \"linux\", target_os = \"android\"))".dependencies.nix]
version = "0.26"
features = [
@ -48,12 +64,8 @@ features = [
]
default-features = false
[target."cfg(target_os = \"macos\")".dependencies]
mach2 = "0.4"
[target."cfg(target_os = \"macos\")".dev-dependencies]
similar-asserts = "1.2"
uuid = "1.0"
[target."cfg(target_os = \"macos\")".dependencies.mach2]
version = "0.4"
[target."cfg(target_os = \"macos\")".dev-dependencies.dump_syms]
version = "2.0.0"
@ -63,16 +75,20 @@ default-features = false
version = "0.15"
default-features = false
[target."cfg(target_os = \"windows\")".dependencies.winapi]
version = "0.3"
features = [
"handleapi",
"minwindef",
"processthreadsapi",
"winnt",
]
[target."cfg(target_os = \"macos\")".dev-dependencies.similar-asserts]
version = "1.2"
[target."cfg(unix)".dependencies]
goblin = "0.6"
libc = "0.2.74"
memmap2 = "0.5"
[target."cfg(target_os = \"macos\")".dev-dependencies.uuid]
version = "1.0"
[target."cfg(target_os = \"windows\")".dependencies.bitflags]
version = "2.0"
[target."cfg(unix)".dependencies.goblin]
version = "0.6"
[target."cfg(unix)".dependencies.libc]
version = "0.2.74"
[target."cfg(unix)".dependencies.memmap2]
version = "0.5"

View File

@ -295,14 +295,17 @@ mod linux {
#[cfg(target_os = "windows")]
mod windows {
use minidump_writer::ffi::{
GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId, GetThreadContext,
EXCEPTION_POINTERS, EXCEPTION_RECORD,
};
use super::*;
use std::mem;
#[link(name = "kernel32")]
extern "system" {
pub fn GetCurrentProcessId() -> u32;
pub fn GetCurrentThreadId() -> u32;
pub fn GetCurrentThread() -> isize;
pub fn GetThreadContext(thread: isize, context: *mut crash_context::CONTEXT) -> i32;
}
#[inline(never)]
pub(super) fn real_main(args: Vec<String>) -> Result<()> {
let exception_code = u32::from_str_radix(&args[0], 16).unwrap();
@ -310,7 +313,7 @@ mod windows {
// Generate the exception and communicate back where the exception pointers
// are
unsafe {
let mut exception_record: EXCEPTION_RECORD = mem::zeroed();
let mut exception_record: crash_context::EXCEPTION_RECORD = mem::zeroed();
let mut exception_context = std::mem::MaybeUninit::uninit();
let pid = GetCurrentProcessId();
@ -320,12 +323,12 @@ mod windows {
let mut exception_context = exception_context.assume_init();
let exception_ptrs = EXCEPTION_POINTERS {
let exception_ptrs = crash_context::EXCEPTION_POINTERS {
ExceptionRecord: &mut exception_record,
ContextRecord: &mut exception_context,
};
exception_record.ExceptionCode = exception_code;
exception_record.ExceptionCode = exception_code as _;
let exc_ptr_addr = &exception_ptrs as *const _ as usize;

View File

@ -1,3 +1,5 @@
pub mod errors;
pub mod ffi;
mod ffi;
pub mod minidump_writer;
pub use ffi::MinidumpType;

View File

@ -7,51 +7,151 @@
//! cause crashes or bad data, so the [`crash_context::ffi::CONTEXT`] is used
//! instead. See [#63](https://github.com/rust-minidump/minidump-writer/issues/63)
#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
#![allow(
non_snake_case,
non_camel_case_types,
non_upper_case_globals,
clippy::upper_case_acronyms
)]
pub use crash_context::ffi::{capture_context, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD};
pub use winapi::{
shared::minwindef::BOOL,
um::{
processthreadsapi::{
GetCurrentProcess, GetCurrentProcessId, GetCurrentThread, GetCurrentThreadId,
OpenProcess, OpenThread, ResumeThread, SuspendThread,
},
winnt::HANDLE,
},
};
pub use crash_context::{capture_context, CONTEXT, EXCEPTION_POINTERS, EXCEPTION_RECORD};
pub type MINIDUMP_TYPE = u32;
pub type HANDLE = isize;
pub type BOOL = i32;
pub const FALSE: BOOL = 0;
pub const MiniDumpNormal: MINIDUMP_TYPE = 0u32;
pub type Hresult = i32;
pub const STATUS_NONCONTINUABLE_EXCEPTION: i32 = -1073741787;
pub type MINIDUMP_CALLBACK_ROUTINE = Option<
unsafe extern "system" fn(
callbackparam: *mut ::core::ffi::c_void,
callbackinput: *const MINIDUMP_CALLBACK_INPUT,
callbackoutput: *mut MINIDUMP_CALLBACK_OUTPUT,
) -> BOOL,
>;
pub type PROCESS_ACCESS_RIGHTS = u32;
pub const PROCESS_ALL_ACCESS: PROCESS_ACCESS_RIGHTS = 2097151;
#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_INPUT {
dummy: u32,
pub type THREAD_ACCESS_RIGHTS = u32;
pub const THREAD_SUSPEND_RESUME: THREAD_ACCESS_RIGHTS = 2;
pub const THREAD_GET_CONTEXT: THREAD_ACCESS_RIGHTS = 8;
pub const THREAD_QUERY_INFORMATION: THREAD_ACCESS_RIGHTS = 64;
bitflags::bitflags! {
/// <https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_type>
#[derive(Copy, Clone, Debug)]
#[repr(transparent)]
pub struct MinidumpType: u32 {
/// Include just the information necessary to capture stack traces for all
/// existing threads in a process.
const Normal = 0;
/// Include the data sections from all loaded modules.
///
/// This results in the inclusion of global variables, which can make
/// the minidump file significantly larger.
const WithDataSegs = 1 << 0;
/// Include all accessible memory in the process.
///
/// The raw memory data is included at the end, so that the initial
/// structures can be mapped directly without the raw memory information.
/// This option can result in a very large file.
const WithFullMemory = 1 << 1;
/// Include high-level information about the operating system handles that
/// are active when the minidump is made.
const WithHandleData = 1 << 2;
/// Stack and backing store memory written to the minidump file should be
/// filtered to remove all but the pointer values necessary to reconstruct a
/// stack trace.
const FilterMemory = 1 << 3;
/// Stack and backing store memory should be scanned for pointer references
/// to modules in the module list.
///
/// If a module is referenced by stack or backing store memory, the
/// [`MINIDUMP_CALLBACK_OUTPUT_0::ModuleWriteFlags`] field is set to
/// [`ModuleWriteFlags::ModuleReferencedByMemory`].
const ScanMemory = 1 << 4;
/// Include information from the list of modules that were recently
/// unloaded, if this information is maintained by the operating system.
const WithUnloadedModules = 1 << 5;
/// Include pages with data referenced by locals or other stack memory.
/// This option can increase the size of the minidump file significantly.
const WithIndirectlyReferencedMemory = 1 << 6;
/// Filter module paths for information such as user names or important
/// directories.
///
/// This option may prevent the system from locating the image file and
/// should be used only in special situations.
const FilterModulePaths = 1 << 7;
/// Include complete per-process and per-thread information from the
/// operating system.
const WithProcessThreadData = 1 << 8;
/// Scan the virtual address space for [`PAGE_READWRITE`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants)
/// memory to be included.
const WithPrivateReadWriteMemory = 1 << 9;
/// Reduce the data that is dumped by eliminating memory regions that
/// are not essential to meet criteria specified for the dump.
///
/// This can avoid dumping memory that may contain data that is private
/// to the user. However, it is not a guarantee that no private information
/// will be present.
const WithoutOptionalData = 1 << 10;
/// Include memory region information.
///
/// See [MINIDUMP_MEMORY_INFO_LIST](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_memory_info_list)
const WithFullMemoryInfo = 1 << 11;
/// Include thread state information.
///
/// See [MINIDUMP_THREAD_INFO_LIST](https://learn.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_thread_info_list)
const WithThreadInfo = 1 << 12;
/// Include all code and code-related sections from loaded modules to
/// capture executable content.
///
/// For per-module control, use the [`ModuleWriteFlags::ModuleWriteCodeSegs`]
const WithCodeSegs = 1 << 13;
/// Turns off secondary auxiliary-supported memory gathering.
const WithoutAuxiliaryState = 1 << 14;
/// Requests that auxiliary data providers include their state in the
/// dump image; the state data that is included is provider dependent.
///
/// This option can result in a large dump image.
const WithFullAuxiliaryState = 1 << 15;
/// Scans the virtual address space for [`PAGE_WRITECOPY`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants) memory to be included.
const WithPrivateWriteCopyMemory = 1 << 16;
/// If you specify [`MinidumpType::MiniDumpWithFullMemory`], the
/// `MiniDumpWriteDump` function will fail if the function cannot read
/// the memory regions; however, if you include
/// [`IgnoreInaccessibleMemory`], the `MiniDumpWriteDump` function will
/// ignore the memory read failures and continue to generate the dump.
///
/// Note that the inaccessible memory regions are not included in the dump.
const IgnoreInaccessibleMemory = 1 << 17;
/// Adds security token related data.
///
/// This will make the "!token" extension work when processing a user-mode dump.
const WithTokenInformation = 1 << 18;
/// Adds module header related data.
const WithModuleHeaders = 1 << 19;
/// Adds filter triage related data.
const FilterTriage = 1 << 20;
/// Adds AVX crash state context registers.
const WithAvxXStateContext = 1 << 21;
/// Adds Intel Processor Trace related data.
const WithIptTrace = 1 << 22;
/// Scans inaccessible partial memory pages.
const ScanInaccessiblePartialPages = 1 << 23;
/// Exclude all memory with the virtual protection attribute of [`PAGE_WRITECOMBINE`](https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants).
const FilterWriteCombinedMemory = 1 << 24;
}
}
#[derive(Copy, Clone)]
pub type VS_FIXEDFILEINFO_FILE_FLAGS = u32;
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_OUTPUT {
dummy: u32,
pub struct MINIDUMP_USER_STREAM {
pub Type: u32,
pub BufferSize: u32,
pub Buffer: *mut std::ffi::c_void,
}
#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_INFORMATION {
pub CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE,
pub CallbackParam: *mut ::core::ffi::c_void,
pub struct MINIDUMP_USER_STREAM_INFORMATION {
pub UserStreamCount: u32,
pub UserStreamArray: *mut MINIDUMP_USER_STREAM,
}
#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct MINIDUMP_EXCEPTION_INFORMATION {
pub ThreadId: u32,
@ -59,30 +159,291 @@ pub struct MINIDUMP_EXCEPTION_INFORMATION {
pub ClientPointers: BOOL,
}
#[derive(Copy, Clone)]
pub type VS_FIXEDFILEINFO_FILE_OS = i32;
pub type VS_FIXEDFILEINFO_FILE_TYPE = i32;
pub type VS_FIXEDFILEINFO_FILE_SUBTYPE = i32;
#[repr(C)]
pub struct VS_FIXEDFILEINFO {
pub dwSignature: u32,
pub dwStrucVersion: u32,
pub dwFileVersionMS: u32,
pub dwFileVersionLS: u32,
pub dwProductVersionMS: u32,
pub dwProductVersionLS: u32,
pub dwFileFlagsMask: u32,
pub dwFileFlags: VS_FIXEDFILEINFO_FILE_FLAGS,
pub dwFileOS: VS_FIXEDFILEINFO_FILE_OS,
pub dwFileType: VS_FIXEDFILEINFO_FILE_TYPE,
pub dwFileSubtype: VS_FIXEDFILEINFO_FILE_SUBTYPE,
pub dwFileDateMS: u32,
pub dwFileDateLS: u32,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_USER_STREAM {
pub struct MINIDUMP_MODULE_CALLBACK {
pub FullPath: *mut u16,
pub BaseOfImage: u64,
pub SizeOfImage: u32,
pub CheckSum: u32,
pub TimeDateStamp: u32,
pub VersionInfo: VS_FIXEDFILEINFO,
pub CvRecord: *mut std::ffi::c_void,
pub SizeOfCvRecord: u32,
pub MiscRecord: *mut std::ffi::c_void,
pub SizeOfMiscRecord: u32,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_INCLUDE_THREAD_CALLBACK {
pub ThreadId: u32,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_INCLUDE_MODULE_CALLBACK {
pub BaseOfImage: u64,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_IO_CALLBACK {
pub Handle: HANDLE,
pub Offset: u64,
pub Buffer: *mut std::ffi::c_void,
pub BufferBytes: u32,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_READ_MEMORY_FAILURE_CALLBACK {
pub Offset: u64,
pub Bytes: u32,
pub FailureStatus: Hresult,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_VM_QUERY_CALLBACK {
pub Offset: u64,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_VM_PRE_READ_CALLBACK {
pub Offset: u64,
pub Buffer: *mut std::ffi::c_void,
pub Size: u32,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_VM_POST_READ_CALLBACK {
pub Offset: u64,
pub Buffer: *mut std::ffi::c_void,
pub Size: u32,
pub Completed: u32,
pub Status: Hresult,
}
/// Oof, so we have a problem with these structs, they are all packed(4), but
/// `CONTEXT` is aligned by either 4 (x86) or 16 (x86_64/aarch64)...which Rust
/// doesn't currently allow https://github.com/rust-lang/rust/issues/59154, so
/// we need to basically cheat with a big byte array until that issue is fixed (possibly never)
#[repr(C)]
pub struct CALLBACK_CONTEXT([u8; std::mem::size_of::<CONTEXT>()]);
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
#[repr(C, packed(4))]
pub struct MINIDUMP_THREAD_CALLBACK {
pub ThreadId: u32,
pub ThreadHandle: HANDLE,
pub Context: CALLBACK_CONTEXT,
pub SizeOfContext: u32,
pub StackBase: u64,
pub StackEnd: u64,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_THREAD_EX_CALLBACK {
pub ThreadId: u32,
pub ThreadHandle: HANDLE,
pub Context: CALLBACK_CONTEXT,
pub SizeOfContext: u32,
pub StackBase: u64,
pub StackEnd: u64,
pub BackingStoreBase: u64,
pub BackingStoreEnd: u64,
}
} else if #[cfg(target_arch = "aarch64")] {
#[repr(C, packed(4))]
pub struct MINIDUMP_THREAD_CALLBACK {
pub ThreadId: u32,
pub ThreadHandle: HANDLE,
pub Pad: u32,
pub Context: CALLBACK_CONTEXT,
pub SizeOfContext: u32,
pub StackBase: u64,
pub StackEnd: u64,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_THREAD_EX_CALLBACK {
pub ThreadId: u32,
pub ThreadHandle: HANDLE,
pub Pad: u32,
pub Context: CALLBACK_CONTEXT,
pub SizeOfContext: u32,
pub StackBase: u64,
pub StackEnd: u64,
pub BackingStoreBase: u64,
pub BackingStoreEnd: u64,
}
}
}
#[repr(C)]
pub union MINIDUMP_CALLBACK_INPUT_0 {
pub Status: Hresult,
pub Thread: std::mem::ManuallyDrop<MINIDUMP_THREAD_CALLBACK>,
pub ThreadEx: std::mem::ManuallyDrop<MINIDUMP_THREAD_EX_CALLBACK>,
pub Module: std::mem::ManuallyDrop<MINIDUMP_MODULE_CALLBACK>,
pub IncludeThread: std::mem::ManuallyDrop<MINIDUMP_INCLUDE_THREAD_CALLBACK>,
pub IncludeModule: std::mem::ManuallyDrop<MINIDUMP_INCLUDE_MODULE_CALLBACK>,
pub Io: std::mem::ManuallyDrop<MINIDUMP_IO_CALLBACK>,
pub ReadMemoryFailure: std::mem::ManuallyDrop<MINIDUMP_READ_MEMORY_FAILURE_CALLBACK>,
pub SecondaryFlags: u32,
pub VmQuery: std::mem::ManuallyDrop<MINIDUMP_VM_QUERY_CALLBACK>,
pub VmPreRead: std::mem::ManuallyDrop<MINIDUMP_VM_PRE_READ_CALLBACK>,
pub VmPostRead: std::mem::ManuallyDrop<MINIDUMP_VM_POST_READ_CALLBACK>,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_INPUT {
pub ProcessId: u32,
pub ProcessHandle: HANDLE,
pub CallbackType: u32,
pub Anonymous: MINIDUMP_CALLBACK_INPUT_0,
}
pub type VIRTUAL_ALLOCATION_TYPE = u32;
#[repr(C, packed(4))]
pub struct MINIDUMP_MEMORY_INFO {
pub BaseAddress: u64,
pub AllocationBase: u64,
pub AllocationProtect: u32,
__alignment1: u32,
pub RegionSize: u64,
pub State: VIRTUAL_ALLOCATION_TYPE,
pub Protect: u32,
pub Type: u32,
pub BufferSize: u32,
pub Buffer: *mut ::core::ffi::c_void,
__alignment2: u32,
}
#[derive(Copy, Clone)]
#[repr(C, packed(4))]
pub struct MINIDUMP_USER_STREAM_INFORMATION {
pub UserStreamCount: u32,
pub UserStreamArray: *mut MINIDUMP_USER_STREAM,
pub struct MINIDUMP_CALLBACK_OUTPUT_0_0 {
pub MemoryBase: u64,
pub MemorySize: u32,
}
#[repr(C)]
pub struct MINIDUMP_CALLBACK_OUTPUT_0_1 {
pub CheckCancel: BOOL,
pub Cancel: BOOL,
}
#[repr(C)]
pub struct MINIDUMP_CALLBACK_OUTPUT_0_2 {
pub VmRegion: MINIDUMP_MEMORY_INFO,
pub Continue: BOOL,
}
#[repr(C)]
pub struct MINIDUMP_CALLBACK_OUTPUT_0_3 {
pub VmQueryStatus: Hresult,
pub VmQueryResult: MINIDUMP_MEMORY_INFO,
}
#[repr(C)]
pub struct MINIDUMP_CALLBACK_OUTPUT_0_4 {
pub VmReadStatus: Hresult,
pub VmReadBytesCompleted: u32,
}
bitflags::bitflags! {
/// Identifies the type of module information that will be written to the
/// minidump file by the MiniDumpWriteDump function.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct ModuleWriteFlags: u32 {
/// Only module information will be written to the minidump file.
const ModuleWriteModule = 0x0001;
const ModuleWriteDataSeg = 0x0002;
const ModuleWriteMiscRecord = 0x0004;
const ModuleWriteCvRecord = 0x0008;
const ModuleReferencedByMemory = 0x0010;
const ModuleWriteTlsData = 0x0020;
const ModuleWriteCodeSegs = 0x0040;
}
}
#[repr(C)]
pub union MINIDUMP_CALLBACK_OUTPUT_0 {
pub ModuleWriteFlags: ModuleWriteFlags,
pub ThreadWriteFlags: u32,
pub SecondaryFlags: u32,
pub Anonymous1: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_0>,
pub Anonymous2: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_1>,
pub Handle: HANDLE,
pub Anonymous3: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_2>,
pub Anonymous4: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_3>,
pub Anonymous5: std::mem::ManuallyDrop<MINIDUMP_CALLBACK_OUTPUT_0_4>,
pub Status: Hresult,
}
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_OUTPUT {
pub Anonymous: MINIDUMP_CALLBACK_OUTPUT_0,
}
pub type MINIDUMP_CALLBACK_ROUTINE = Option<
unsafe extern "system" fn(
CallbackParam: *mut std::ffi::c_void,
CallbackInput: *const MINIDUMP_CALLBACK_INPUT,
CallbackOutput: *mut MINIDUMP_CALLBACK_OUTPUT,
) -> BOOL,
>;
#[repr(C, packed(4))]
pub struct MINIDUMP_CALLBACK_INFORMATION {
pub CallbackRoutine: MINIDUMP_CALLBACK_ROUTINE,
pub CallbackParam: *mut std::ffi::c_void,
}
#[link(name = "kernel32")]
extern "system" {
pub fn CloseHandle(handle: HANDLE) -> BOOL;
pub fn GetCurrentProcess() -> HANDLE;
pub fn GetCurrentThreadId() -> u32;
pub fn OpenProcess(
desired_access: PROCESS_ACCESS_RIGHTS,
inherit_handle: BOOL,
process_id: u32,
) -> HANDLE;
pub fn OpenThread(
desired_access: THREAD_ACCESS_RIGHTS,
inherit_handle: BOOL,
thread_id: u32,
) -> HANDLE;
pub fn ResumeThread(thread: HANDLE) -> u32;
pub fn SuspendThread(thread: HANDLE) -> u32;
pub fn GetThreadContext(thread: HANDLE, context: *mut CONTEXT) -> BOOL;
}
#[link(name = "dbghelp")]
extern "system" {
pub fn GetThreadContext(hthread: HANDLE, lpcontext: *mut CONTEXT) -> BOOL;
pub fn MiniDumpWriteDump(
hprocess: HANDLE,
processid: u32,
hfile: HANDLE,
dumptype: MINIDUMP_TYPE,
exceptionparam: *const MINIDUMP_EXCEPTION_INFORMATION,
userstreamparam: *const MINIDUMP_USER_STREAM_INFORMATION,
callbackparam: *const MINIDUMP_CALLBACK_INFORMATION,
process: HANDLE,
process_id: u32,
file: HANDLE,
dump_type: MinidumpType,
exception_param: *const MINIDUMP_EXCEPTION_INFORMATION,
user_stream_param: *const MINIDUMP_USER_STREAM_INFORMATION,
callback_param: *const MINIDUMP_CALLBACK_INFORMATION,
) -> BOOL;
}

View File

@ -1,22 +1,17 @@
#![allow(unsafe_code)]
use crate::windows::errors::Error;
use crate::windows::ffi::{
capture_context, GetCurrentProcess, GetCurrentThreadId, GetThreadContext, MiniDumpNormal,
MiniDumpWriteDump, OpenProcess, OpenThread, ResumeThread, SuspendThread, EXCEPTION_POINTERS,
HANDLE, MINIDUMP_EXCEPTION_INFORMATION, MINIDUMP_USER_STREAM, MINIDUMP_USER_STREAM_INFORMATION,
capture_context, CloseHandle, GetCurrentProcess, GetCurrentThreadId, GetThreadContext,
MiniDumpWriteDump, MinidumpType, OpenProcess, OpenThread, ResumeThread, SuspendThread,
EXCEPTION_POINTERS, EXCEPTION_RECORD, FALSE, HANDLE, MINIDUMP_EXCEPTION_INFORMATION,
MINIDUMP_USER_STREAM, MINIDUMP_USER_STREAM_INFORMATION, PROCESS_ALL_ACCESS,
STATUS_NONCONTINUABLE_EXCEPTION, THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION,
THREAD_SUSPEND_RESUME,
};
use minidump_common::format::{BreakpadInfoValid, MINIDUMP_BREAKPAD_INFO, MINIDUMP_STREAM_TYPE};
use scroll::Pwrite;
use std::os::windows::io::AsRawHandle;
use winapi::{
shared::minwindef::FALSE,
um::{
handleapi::CloseHandle,
winnt::{
EXCEPTION_RECORD, PROCESS_ALL_ACCESS, STATUS_NONCONTINUABLE_EXCEPTION,
THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,
},
},
};
pub struct MinidumpWriter {
/// Optional exception information
@ -29,7 +24,7 @@ pub struct MinidumpWriter {
tid: u32,
/// The exception code for the dump
#[allow(dead_code)]
exception_code: u32,
exception_code: i32,
/// Whether we are dumping the current process or not
is_external_process: bool,
}
@ -49,8 +44,9 @@ impl MinidumpWriter {
/// function can also fail if `thread_id` is specified and we are unable to
/// acquire the thread's context
pub fn dump_local_context(
exception_code: Option<u32>,
exception_code: Option<i32>,
thread_id: Option<u32>,
minidump_type: Option<MinidumpType>,
destination: &mut std::fs::File,
) -> Result<(), Error> {
let exception_code = exception_code.unwrap_or(STATUS_NONCONTINUABLE_EXCEPTION);
@ -76,7 +72,7 @@ impl MinidumpWriter {
tid, // thread id
);
if thread_handle.is_null() {
if thread_handle == 0 {
return Err(Error::ThreadOpen(std::io::Error::last_os_error()));
}
@ -134,7 +130,7 @@ impl MinidumpWriter {
exception_code,
};
Self::dump_crash_context(cc, destination)
Self::dump_crash_context(cc, minidump_type, destination)
}
}
@ -154,6 +150,7 @@ impl MinidumpWriter {
/// for the duration of this function call.
pub fn dump_crash_context(
crash_context: crash_context::CrashContext,
minidump_type: Option<MinidumpType>,
destination: &mut std::fs::File,
) -> Result<(), Error> {
let pid = crash_context.process_id;
@ -167,7 +164,7 @@ impl MinidumpWriter {
pid, // pid
);
if proc.is_null() {
if proc == 0 {
return Err(std::io::Error::last_os_error().into());
}
@ -208,11 +205,15 @@ impl MinidumpWriter {
is_external_process,
};
mdw.dump(destination)
mdw.dump(minidump_type, destination)
}
/// Writes a minidump to the specified file
fn dump(mut self, destination: &mut std::fs::File) -> Result<(), Error> {
fn dump(
mut self,
minidump_type: Option<MinidumpType>,
destination: &mut std::fs::File,
) -> Result<(), Error> {
let exc_info = self.exc_info.take();
let mut user_streams = Vec::with_capacity(1);
@ -241,7 +242,7 @@ impl MinidumpWriter {
self.crashing_process, // HANDLE to the process with the crash we want to capture
self.pid, // process id
destination.as_raw_handle() as HANDLE, // file to write the minidump to
MiniDumpNormal, // MINIDUMP_TYPE - we _might_ want to make this configurable
minidump_type.unwrap_or(MinidumpType::Normal),
exc_info
.as_ref()
.map_or(std::ptr::null(), |ei| ei as *const _), // exceptionparam - the actual exception information
@ -276,7 +277,7 @@ impl MinidumpWriter {
validity: BreakpadInfoValid::DumpThreadId.bits()
| BreakpadInfoValid::RequestingThreadId.bits(),
dump_thread_id: self.tid,
// Safety: syscall
// SAFETY: syscall
requesting_thread_id: unsafe { GetCurrentThreadId() },
};

View File

@ -8,10 +8,11 @@ use minidump_writer::minidump_writer::MinidumpWriter;
mod common;
use common::start_child_and_return;
use winapi::um::{minwinbase::EXCEPTION_ILLEGAL_INSTRUCTION, winnt::STATUS_INVALID_PARAMETER};
const EXCEPTION_ILLEGAL_INSTRUCTION: i32 = -1073741795;
const STATUS_INVALID_PARAMETER: i32 = -1073741811;
#[link(name = "kernel32")]
extern "system" {
pub(crate) fn GetCurrentThreadId() -> u32;
fn GetCurrentThreadId() -> u32;
}
fn get_crash_reason<'a, T: std::ops::Deref<Target = [u8]> + 'a>(
@ -35,8 +36,13 @@ fn dump_current_process() {
.tempfile()
.unwrap();
MinidumpWriter::dump_local_context(Some(STATUS_INVALID_PARAMETER), None, tmpfile.as_file_mut())
.expect("failed to write minidump");
MinidumpWriter::dump_local_context(
Some(STATUS_INVALID_PARAMETER),
None,
None,
tmpfile.as_file_mut(),
)
.expect("failed to write minidump");
let md = Minidump::read_path(tmpfile.path()).expect("failed to read minidump");
@ -83,6 +89,7 @@ fn dump_specific_thread() {
MinidumpWriter::dump_local_context(
Some(STATUS_INVALID_PARAMETER),
Some(crashing_thread_id),
None,
tmpfile.as_file_mut(),
)
.expect("failed to write minidump");
@ -140,6 +147,7 @@ fn dump_external_process() {
(process_id, exception_pointers, thread_id, exception_code)
};
let exception_code = exception_code as i32;
assert_eq!(exception_code, EXCEPTION_ILLEGAL_INSTRUCTION);
let crash_context = crash_context::CrashContext {
@ -156,7 +164,7 @@ fn dump_external_process() {
// SAFETY: We keep the process we are dumping alive until the minidump is written
// and the test process keep the pointers it sent us alive until it is killed
MinidumpWriter::dump_crash_context(crash_context, tmpfile.as_file_mut())
MinidumpWriter::dump_crash_context(crash_context, None, tmpfile.as_file_mut())
.expect("failed to write minidump");
child.kill().expect("failed to kill child");

View File

@ -8,8 +8,8 @@ license = "MPL-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
crash-context = "0.5.1"
minidump-writer = "0.7.0"
crash-context = "0.6.0"
minidump-writer = "0.8.0"
libc = "0.2.74"
anyhow = "1.0"
nsstring = { path = "../../../xpcom/rust/nsstring/" }