diff --git a/Cargo.lock b/Cargo.lock index 00a5507b..2662af05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,7 +333,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -350,7 +350,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -470,7 +470,7 @@ version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cexpr", "clang-sys", "itertools 0.12.1", @@ -483,7 +483,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.66", + "syn 2.0.68", "which 4.4.2", ] @@ -495,9 +495,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitmaps" @@ -805,9 +805,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" dependencies = [ "jobserver", "libc", @@ -896,7 +896,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -929,7 +929,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1267,7 +1267,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1305,13 +1305,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1707,7 +1707,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -1786,7 +1786,7 @@ version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", "libgit2-sys", "log", @@ -1964,7 +1964,7 @@ version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbd06203b1a9b33a78c88252a625031b094d9e1b647260070c25b09910c0a804" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-path", "libc", @@ -1990,9 +1990,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367ee9093b0c2b04fd04c5c7c8b6a1082713534eab537597ae343663a518fa99" +checksum = "9eed6931f21491ee0aeb922751bd7ec97b4b2fe8fbfedcb678e2a2dce5f3b8c0" dependencies = [ "bstr", "itoa", @@ -2108,7 +2108,7 @@ version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a29ad0990cf02c48a7aac76ed0dbddeb5a0d070034b83675cc3bbf937eace4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-features", "gix-path", @@ -2154,7 +2154,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d8c5a5f1c58edcbc5692b174cda2703aba82ed17d7176ff4c1752eb48b1b167" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "filetime", "fnv", @@ -2195,7 +2195,7 @@ checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -2204,7 +2204,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d57dec54544d155a495e01de947da024471e1825d7d3f2724301c07a310d6184" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -2299,9 +2299,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23623cf0f475691a6d943f898c4d0b89f5c1a2a64d0f92bce0e0322ee6528783" +checksum = "ca987128ffb056d732bd545db5db3d8b103d252fbf083c2567bb0796876619a4" dependencies = [ "bstr", "gix-trace", @@ -2316,7 +2316,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76cab098dc10ba2d89f634f66bf196dea4d7db4bf10b75c7a9c201c55a2ee19" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "bstr", "gix-attributes", "gix-config-value", @@ -2440,7 +2440,7 @@ version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fddc27984a643b20dd03e97790555804f98cf07404e0e552c0ad8133266a79a1" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-path", "libc", "windows-sys 0.52.0", @@ -2505,7 +2505,7 @@ version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f20cb69b63eb3e4827939f42c05b7756e3488ef49c25c412a876691d568ee2a0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "gix-commitgraph", "gix-date", "gix-hash", @@ -2851,134 +2851,14 @@ dependencies = [ "tokio-io-timeout", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "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.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" -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 2.0.66", -] - [[package]] name = "idna" -version = "1.0.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "icu_normalizer", - "icu_properties", - "smallvec", - "utf8_iter", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -3204,14 +3084,14 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -3268,9 +3148,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets 0.52.5", @@ -3298,7 +3178,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -3377,12 +3257,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "litemap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" - [[package]] name = "lock_api" version = "0.4.12" @@ -3482,7 +3356,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -3552,7 +3426,7 @@ checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -3616,7 +3490,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4c25a3bb7d880e8eceab4822f3141ad0700d20f025991c1f03bd3d00219a5fc" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -3658,7 +3532,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -3947,6 +3821,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.1" @@ -4096,7 +3976,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -4177,7 +4057,7 @@ dependencies = [ "proc-macro2", "quote", "semver", - "syn 2.0.66", + "syn 2.0.68", "which 6.0.1", ] @@ -4347,7 +4227,7 @@ dependencies = [ [[package]] name = "playdate-symbolize" -version = "0.1.3" +version = "0.2.0" dependencies = [ "anyhow", "async-stream", @@ -4356,6 +4236,7 @@ dependencies = [ "env_logger", "futures-util", "log", + "paste", "playdate-build-utils", "regex", "rusqlite", @@ -4493,7 +4374,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -4507,9 +4388,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -4525,11 +4406,11 @@ dependencies = [ [[package]] name = "proptest" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "lazy_static", "num-traits", "rand", @@ -4559,7 +4440,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -4672,7 +4553,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -4746,7 +4627,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "fallible-iterator 0.3.0", "fallible-streaming-iterator", "hashlink", @@ -4798,7 +4679,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.14", @@ -4864,7 +4745,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -4887,7 +4768,7 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -4951,7 +4832,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -4965,9 +4846,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "itoa", "ryu", @@ -4989,7 +4870,7 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5a15d0be940df84846264b09b51b10b931fb2f275becb80934e3568a016828" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "core-foundation-sys", "io-kit-sys", @@ -5217,9 +5098,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "supports-color" @@ -5346,9 +5227,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -5361,17 +5242,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "tar" version = "0.4.41" @@ -5449,7 +5319,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -5495,21 +5365,11 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" dependencies = [ "tinyvec_macros", ] @@ -5558,7 +5418,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -5710,7 +5570,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -5823,6 +5683,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-bom" version = "2.0.3" @@ -5864,9 +5730,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "url" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -5892,18 +5758,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "utf8parse" version = "0.2.2" @@ -5912,9 +5766,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" [[package]] name = "valuable" @@ -5992,7 +5846,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -6026,7 +5880,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6044,7 +5898,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07035cc9a9b41e62d3bb3a3815a66ab87c993c06fe1cf6b2a3f2a18499d937db" dependencies = [ "ahash", - "bitflags 2.5.0", + "bitflags 2.6.0", "hashbrown 0.14.5", "indexmap 2.2.6", "semver", @@ -6184,7 +6038,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -6195,7 +6049,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] @@ -6401,18 +6255,6 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "xml5ever" version = "0.17.0" @@ -6424,30 +6266,6 @@ dependencies = [ "markup5ever", ] -[[package]] -name = "yoke" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.7.34" @@ -6465,28 +6283,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "zerofrom" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", - "synstructure", + "syn 2.0.68", ] [[package]] @@ -6506,29 +6303,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", -] - -[[package]] -name = "zerovec" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.66", + "syn 2.0.68", ] [[package]] diff --git a/support/addr2line/Cargo.toml b/support/addr2line/Cargo.toml index c7839737..38551735 100644 --- a/support/addr2line/Cargo.toml +++ b/support/addr2line/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-symbolize" -version = "0.1.3" +version = "0.2.0" readme = "README.md" description = "Tools for symbolise addresses from bin (pdex.elf) and Playdate's trace or crashlog." keywords = ["playdate", "bin", "elf", "addr2line", "utility"] @@ -36,6 +36,7 @@ symbolic = { version = "12.8", features = ["demangle"] } regex.workspace = true const-str = { version = "0.5", default-features = false, optional = true } +paste = "1.0" tokio = { workspace = true, features = ["full", "rt-multi-thread"] } async-stream = "0.3" diff --git a/support/addr2line/src/addr2line-crashlog.rs b/support/addr2line/src/addr2line-crashlog.rs index d734b9fb..6d32ff5f 100644 --- a/support/addr2line/src/addr2line-crashlog.rs +++ b/support/addr2line/src/addr2line-crashlog.rs @@ -9,11 +9,12 @@ use futures_util::StreamExt; use futures_util::TryStreamExt; use pd::elf::map_result_fallback_os; -use pd::fmt::crashlog::CrashLog; -use pd::fmt::report::WriteReport as _; use pd::*; +const ADDR_REG: &[&str] = &["lr", "pc", "mmfar", "bfar", "r0", "r1", "r2", "r3", "r12"]; + + #[tokio::main] async fn main() -> anyhow::Result<()> { let cfg = cli_ext::parse(); @@ -31,11 +32,11 @@ async fn main() -> anyhow::Result<()> { let docs: Vec<_> = { let addrs = &mut addrs; stream.map(move |doc| -> Result<_, anyhow::Error> { - let count = doc.ptrs - .values() - .filter(|v| addrs.insert(**v)) - .map_while(|v| tx.send(*v).map_err(|err| error!("{err}")).ok()) - .count(); + let count = ADDR_REG.into_iter() + .flat_map(|v| doc.ptrs.get(*v)) + .filter(|v| addrs.insert(**v)) + .map_while(|v| tx.send(*v).map_err(|err| error!("{err}")).ok()) + .count(); let date = doc.date.as_deref().unwrap_or("n/a"); debug!("sent to resolve {count} addrs for doc by {date}"); Ok(doc) @@ -65,36 +66,17 @@ async fn main() -> anyhow::Result<()> { os_db.close().await?; - let docs: Vec<_> = docs.into_iter() - .map(|doc| { - let CrashLog { date, - build, - heap, - ptrs, } = doc; - let ptrs = ptrs.into_iter() - .map(|(k, v)| { - match resolved_addrs.get(&v) { - Some(rep) => (k, rep), - None => unreachable!("Key not found: {v:#08x?}"), - } - }) - .collect(); - CrashLog { date, - build, - heap, - ptrs } - }) - .collect(); - - for doc in docs { - doc.default_print( - std::io::stdout(), - true, - 0, - cfg.base.flags.functions, - cfg.base.flags.basenames, - cfg.base.flags.ranges, - cfg.base.flags.demangle, + + for doc in &docs { + doc.pretty_print( + std::io::stdout(), + &resolved_addrs, + true, + 0, + cfg.base.flags.functions, + cfg.base.flags.basenames, + cfg.base.flags.ranges, + cfg.base.flags.demangle, )?; } diff --git a/support/addr2line/src/ef.rs b/support/addr2line/src/ef.rs new file mode 100644 index 00000000..8861a1b4 --- /dev/null +++ b/support/addr2line/src/ef.rs @@ -0,0 +1,876 @@ +#![allow(dead_code)] +#![allow(non_snake_case)] + +use std::collections::HashMap; +use std::fmt::Binary; +use std::fmt::Display; +use std::fmt::Debug; + +use crate::fmt::addr::Addr; + + +/// SCB+ +#[derive(Debug, Clone)] +pub struct ExceptionFrame { + // General-purpose registers: + // Low regs: + r0: u32, + r1: u32, + r2: u32, + r3: u32, + // High regs: + r12: u32, + /// Link Register (r14) + lr: Addr, + /// Program Counter (r15) + /// Current program address. + pc: Addr, + + // Special registers: + /// Program status register. + /// + /// The Program Status Register combines: + /// - Application Program Status Register ([`APSR`]). + /// - Interrupt Program Status Register ([`IPSR`]). + /// - Execution Program Status Register ([`EPSR`]). + psr: PSR, + + /// Configurable Fault Status + /// + /// combines [`ufsr`][Self::ufsr] + [`bfsr`][Self::bfsr] + [`mmfsr`][Self::mmfsr]. + cfsr: CFSR, + + /// HardFault Status + hfsr: HSFR, + + /// MemManage Fault Address + /// + /// The BFAR address is associated with a precise data access BusFault. + /// _This field is valid only when [`MMFSR::MMARVALID`] is set._ + mmfar: Addr, + + /// BusFault Address. + /// Data address for a precise BusFault. + /// + /// Contains the address of a location that produced a BusFault. + /// The [`BFSR`] shows the reason for the fault. + /// _This field is valid only when [`BFSR::BFARVALID`] is set._ + bfar: Addr, + + /// `bootinfo.rcccsr` value + rcccsr: u32, +} + + +pub const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20; +pub const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; +pub const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; + +impl ExceptionFrame { + pub fn ufsr(&self) -> UFSR { self.cfsr.ufsr() } + pub fn bfsr(&self) -> BFSR { self.cfsr.bfsr() } + pub fn mmfsr(&self) -> MMFSR { self.cfsr.mmfsr() } +} + + +impl ExceptionFrame { + pub fn new_from(values: &HashMap>) -> Result { + Ok(Self { r0: values.get("r0").ok_or("no r0")?.value(), + r1: values.get("r1").ok_or("no r1")?.value(), + r2: values.get("r2").ok_or("no r2")?.value(), + r3: values.get("r3").ok_or("no r3")?.value(), + r12: values.get("r12").ok_or("no r12")?.value(), + lr: values.get("lr").ok_or("no lr")?.to_owned(), + pc: values.get("pc").ok_or("no pc")?.to_owned(), + psr: values.get("psr").ok_or("no psr")?.value().into(), + cfsr: values.get("cfsr").ok_or("no cfsr")?.value().into(), + hfsr: values.get("hfsr").ok_or("no hfsr")?.value().into(), + mmfar: values.get("mmfar").ok_or("no mmfar")?.to_owned(), + bfar: values.get("bfar").ok_or("no bfar")?.to_owned(), + rcccsr: values.get("rcccsr").ok_or("no rcccsr")?.value().into() }) + } +} + + +macro_rules! bit { + ($mask:literal, $name:ident.$field:ident, $doc:literal) => { + impl $name { + bit! {$mask, $field, $doc} + } + }; + ($mask:literal, $name:ident) => { + pub fn $name(&self) -> bool { self.0 & $mask != 0 } + + paste::paste! { + pub const []: &'static str = stringify!($name); + } + }; + ($mask:literal, $name:ident, $doc:literal) => { + #[doc = $doc] + pub fn $name(&self) -> bool { self.0 & $mask != 0 } + + paste::paste! { + pub const []: &'static str = $doc; + } + }; + + ($name:ident, $mask:literal) => { + bit!($mask, $name) + }; + ($name:ident, $mask:literal, $doc:literal) => { + bit!($mask, $name, $doc) + }; +} + + +macro_rules! impl_fmt { + ($name:ident) => { + impl Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) } + } + impl Binary for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { Binary::fmt(&self.0, f) } + } + }; + + ($name:ident, $($next:ident),+) => { + impl_fmt!($name); + impl_fmt!($($next),+); + } + } + + +macro_rules! impl_from { + ($name:ident) => { + impl_from! {impl $name} + impl_from! {impl $name} + }; + ($name:ident) => { + impl_from! {impl $name} + impl_from! {impl $name} + impl_from! {$name} + }; + ($name:ident) => { + impl_from! {impl $name} + impl_from! {impl $name} + impl_from! {$name} + }; + ($name:ident) => { + impl_from! {impl $name} + impl_from! {impl $name} + impl_from! {$name} + }; + ($name:ident) => { + impl_from! {$name} + }; + + (impl $name:ident<$t:ty>) => { + impl From<$t> for $name { + fn from(value: $t) -> Self { Self(value as _) } + } + }; +} + +macro_rules! impl_try_from { + ($name:ident) => { + impl_try_from! {impl $name} + impl_try_from! {impl $name} + impl_try_from! {impl $name} + }; + ($name:ident) => { + impl_try_from! {impl $name} + impl_try_from! {impl $name} + }; + ($name:ident) => { + impl_try_from! {impl $name} + }; + ($name:ident) => {}; + ($name:ident) => { + impl_try_from! {$name} + }; + + (impl $name:ident<$t:ty, $th:ty>) => { + impl TryFrom<$th> for $name + where $t: TryFrom<$th>, + Self: From<$t> + { + type Error = <$t as TryFrom<$th>>::Error; + fn try_from(value: $th) -> Result { + let value: $t = value.try_into()?; + Ok(Self::from(value)) + } + } + }; +} + +macro_rules! impl_to { + ($name:ident) => { + impl_to! {impl $name} + impl_to! {impl $name} + impl_to! {$name} + }; + ($name:ident) => { + impl_to! {impl $name} + impl_to! {impl $name} + impl_to! {$name} + }; + ($name:ident) => { + impl_to! {impl $name} + impl_to! {impl $name} + impl_to! {$name} + }; + ($name:ident) => { + impl_to! {impl $name} + impl_to! {impl $name} + }; + ($name:ident) => { + impl_to! {$name} + }; + + (impl $name:ident<$t:ty>) => { + impl From<$name> for $t { + fn from(value: $name) -> Self { value.0 as _ } + } + }; +} + +macro_rules! impl_convert { + ($name:ident) => { + impl_to! {$name} + impl_from! {$name} + impl_try_from! {$name} + }; + ($name:ident) => { + impl_to! {$name} + impl_from! {$name} + impl_try_from! {$name} + }; + ($name:ident) => { + impl_to! {$name} + impl_from! {$name} + impl_try_from! {$name} + }; + ($name:ident) => { + impl_to! {$name} + impl_from! {$name} + impl_try_from! {$name} + }; + ($name:ident) => { + impl_convert! {$name} + }; +} + +macro_rules! impl_reg { + ($name:ident) => { + impl_reg!{$name} + }; + ($name:ident<$t:ty>) => { + impl_fmt!{$name} + }; + + ($name:ident$(<$t:ty>)?, $($next:ident$(<$tn:ty>)?),+) => { + impl_reg!($name$(<$t>)?); + impl_reg!($($next$(<$tn>)?),+); + } + } + +impl_reg! {PSR, IPSR, APSR, EPSR, CFSR, UFSR, BFSR, MMFSR, HSFR} +impl_convert! { PSR } +impl_convert! { IPSR } +impl_convert! { APSR } +impl_convert! { EPSR } +impl_convert! { CFSR } +impl_convert! { UFSR } +impl_convert! { BFSR } +impl_convert! { MMFSR } +impl_convert! { HSFR } + +// _PSR entry in the crash log also includes the EPSR as well._ +// ESPR - Execution Program Status Register +// +/// Program status register. +/// +/// The Program Status Register (PSR) combines: +/// - Application Program Status Register (APSR). +/// - Interrupt Program Status Register (IPSR). +/// - Execution Program Status Register (EPSR). +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct PSR(u32); + +impl PSR { + pub fn apsr(&self) -> APSR { APSR(((self.0 & 0b11111000_00000111_00000000_00000000) >> 16) as u16) } + pub fn ipsr(&self) -> IPSR { IPSR((self.0 & 0b00000000_00000000_00000001_11111111) as u16) } + pub fn epsr(&self) -> EPSR { EPSR(self.0 & 0b00000111_00000000_11111100_00000000) } +} + +impl Debug for PSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PSR") + .field("APSR", &self.apsr()) + .field("IPSR", &self.ipsr()) + .field("EPSR", &self.epsr()) + .finish() + } +} + + +/// Application Program Status Register. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct APSR(u16); +bit! {0b1000_0000_00000000, APSR.N, r#"Negative"#} +bit! {0b0100_0000_00000000, APSR.Z, r#"Zero"#} +bit! {0b0010_0000_00000000, APSR.C, r#"Carry or borrow"#} +bit! {0b0001_0000_00000000, APSR.V, r#"Overflow"#} +bit! {0b0000_1000_00000000, APSR.Q, r#"DSP overflow and saturation"#} +bit! {0b0000_0000_00000111, APSR.GE, r#"Greater than or Equals"#} +impl Debug for APSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("APSR") + .field("N", &self.N()) + .field("Z", &self.Z()) + .field("C", &self.C()) + .field("V", &self.V()) + .field("Q", &self.Q()) + .field("GE", &self.GE()) + .finish() + } +} +impl RegTags for APSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if !self.is_empty() { + [ + self.N().then_some(("N", Self::DOC_N)), + self.Z().then_some(("Z", Self::DOC_Z)), + self.C().then_some(("C", Self::DOC_C)), + self.V().then_some(("V", Self::DOC_V)), + self.Q().then_some(("Q", Self::DOC_Q)), + self.GE().then_some(("GE", Self::DOC_GE)), + ].into_iter() + .flatten() + } else { + <[_; 6]>::default().into_iter().flatten() + } + } +} + +/// Interrupt Program Status Register. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct IPSR(u16); +bit! {0b0000_0000_00000001, IPSR.TM, r#"Thread mode"#} +bit! {0b0000_0000_00000100, IPSR.NMI, r#"NMI"#} +bit! {0b0000_0000_00001000, IPSR.HF, r#"HardFault"#} +bit! {0b0000_0000_00010000, IPSR.MM, r#"MemManage"#} +bit! {0b0000_0000_00100000, IPSR.BF, r#"BusFault"#} +bit! {0b0000_0000_01000000, IPSR.UF, r#"UsageFault"#} +impl Debug for IPSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("IPSR") + .field("TM", &self.TM()) + .field("NMI", &self.NMI()) + .field("HF", &self.HF()) + .field("MM", &self.MM()) + .field("BF", &self.BF()) + .field("UF", &self.UF()) + .finish() + } +} +impl RegTags for IPSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if !self.is_empty() { + [ + self.TM().then_some(("TM", Self::DOC_TM)), + self.NMI().then_some(("NMI", Self::DOC_NMI)), + self.HF().then_some(("HF", Self::DOC_HF)), + self.MM().then_some(("MM", Self::DOC_MM)), + self.BF().then_some(("BF", Self::DOC_BF)), + self.UF().then_some(("UF", Self::DOC_UF)), + ].into_iter() + .flatten() + } else { + <[_; 6]>::default().into_iter().flatten() + } + } +} + +/// Execution Program Status Register. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct EPSR(u32); +bit! {0b00000110_00000000_00001100_00000000, EPSR.IS_NOT_ICI, r#"Interruptible-continuable instruction bits."#} +bit! {0b00000000_00000000_11110000_00000000, EPSR.ICI, r#"Interruptible-continuable instruction bits."#} +bit! {0b00000110_00000000_11111100_00000000, EPSR.IT, r#"If-Then block. Indicates the execution state bits of the IT instruction"#} +bit! {0b00000001_00000000_00000000_00000000, EPSR.T, r#"Thumb state"#} +impl Debug for EPSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EPSR") + .field("IS_NOT_ICI", &self.IS_NOT_ICI()) + .field("ICI", &self.ICI()) + .field("IT", &self.IT()) + .field("T", &self.T()) + .finish() + } +} +impl RegTags for EPSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if !self.is_empty() { + [ + self.IS_NOT_ICI().then_some(("IS_NOT_ICI", Self::DOC_IS_NOT_ICI)), + self.ICI().then_some(("ICI", Self::DOC_ICI)), + self.IT().then_some(("IT", Self::DOC_IT)), + self.T().then_some(("T", Self::DOC_T)), + ].into_iter() + .flatten() + } else { + <[_; 4]>::default().into_iter().flatten() + } + } +} + + +/// HardFault Status Register. +/// +/// The Hard Fault status register indicates an incorrect usage of a CPU instruction. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct HSFR(u32); +impl HSFR { + // When this bit is set, the PC value stacked for the exception return points to the instruction + // that was preempted by the exception. This error is always a Hard Fault. + bit! {0b00000000_00000000_00000000_00000010, VECTTBL, r#"Bus Fault on vector table read."#} + bit! {0b01000000_00000000_00000000_00000000, FORCED, r#"Forced Hard Fault."#} + bit! {0b10000000_00000000_00000000_00000000, DEBUGEVT, r#"Reserved for Debug use."#} +} +impl Debug for HSFR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("HSFR") + .field("VECTTBL", &self.VECTTBL()) + .field("FORCED", &self.FORCED()) + .field("DEBUGEVT", &self.DEBUGEVT()) + .finish() + } +} +impl RegTags for HSFR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if !self.is_empty() { + [ + self.VECTTBL().then_some(("VECTTBL", Self::DOC_VECTTBL)), + self.FORCED().then_some(("FORCED", Self::DOC_FORCED)), + self.DEBUGEVT().then_some(("DEBUGEVT", Self::DOC_DEBUGEVT)), + ].into_iter() + .flatten() + } else { + <[_; 3]>::default().into_iter().flatten() + } + } +} + + +/// Configurable Fault Status +/// +/// combines [`ufsr`][Self::ufsr] + [`bfsr`][Self::bfsr] + [`mmfsr`][Self::mmfsr]. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct CFSR(u32); + +impl CFSR { + pub fn ufsr(&self) -> UFSR { UFSR(((self.0 & 0b11111111_11111111_00000000_00000000) >> 16) as u16) } + pub fn bfsr(&self) -> BFSR { BFSR(((self.0 & 0b00000000_00000000_11111111_00000000) >> 8) as u8) } + pub fn mmfsr(&self) -> MMFSR { MMFSR(self.0 as u8) } +} + +impl Debug for CFSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CFSR") + .field("UFSR", &self.ufsr()) + .field("BFSR", &self.bfsr()) + .field("MMFSR", &self.mmfsr()) + .finish() + } +} + + +/// The UsageFault Status Register contains the status for some instruction execution faults, and for data access. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct UFSR(u16); +impl UFSR { + bit! {0b0000_0000_0000_0001, UNDEFINSTR, r#"Undefined instruction."#} + bit! {0b0000_0000_0000_0010, INVSTATE, r#"Invalid state."#} + bit! {0b0000_0000_0000_0100, INVPC, r#"Invalid `PC` load UsageFault, caused by an invalid `EXC_RETURN` value."#} + bit! {0b0000_0000_0000_1000, NOCP, r#"No coprocessor."#} + bit! {0b0000_0001_0000_0000, UNALIGNED, r#"Unaligned access UsageFault."#} + bit! {0b0010_0000, DIVBYZERO, r#"Divide by zero UsageFault."#} +} + + +impl RegTags for UFSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if self.is_empty() { + return [None, None, None, None, None, None].into_iter().flatten(); + } + + [ + self.UNDEFINSTR().then_some(("UNDEFINSTR", Self::DOC_UNDEFINSTR)), + self.INVSTATE().then_some(("INVSTATE", Self::DOC_INVSTATE)), + self.INVPC().then_some(("INVPC", Self::DOC_INVPC)), + self.NOCP().then_some(("NOCP", Self::DOC_NOCP)), + self.UNALIGNED().then_some(("UNALIGNED", Self::DOC_UNALIGNED)), + self.DIVBYZERO().then_some(("DIVBYZERO", Self::DOC_DIVBYZERO)), + ].into_iter() + .flatten() + } +} + +impl Debug for UFSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UFSR") + .field("UNDEFINSTR", &self.UNDEFINSTR()) + .field("INVSTATE", &self.INVSTATE()) + .field("INVPC", &self.INVPC()) + .field("NOCP", &self.NOCP()) + .field("UNALIGNED", &self.UNALIGNED()) + .field("DIVBYZERO", &self.DIVBYZERO()) + .finish() + } +} + + +/// The BusFault Status Register shows the status of bus errors resulting from instruction fetches and data accesses +/// and indicates memory access faults detected during a bus operation. +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct BFSR(u8); +impl BFSR { + bit! {0b0000_0001, IBUSERR, r#"Instruction bus error. Records whether a BusFault on an instruction prefetch has occurred."#} + bit! {0b0000_0010, PRECISERR, r#"Precise data bus error."#} + bit! {0b0000_0100, IMPRECISERR, r#"Imprecise data bus error."#} + bit! {0b0000_1000, UNSTKERR, r#"BusFault on unstacking for a return from exception."#} + bit! {0b0001_0000, STKERR, r#"BusFault on stacking for exception entry."#} + bit! {0b0010_0000, LSPERR, r#"BusFault during floating point lazy state preservation (only when FPU present)."#} + bit! {0b1000_0000, BFARVALID, r#"BusFault Address Register valid flag. BFAR holds a valid fault address."#} +} +impl Debug for BFSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BFSR") + .field("IBUSERR", &self.IBUSERR()) + .field("PRECISERR", &self.PRECISERR()) + .field("IMPRECISERR", &self.IMPRECISERR()) + .field("UNSTKERR", &self.UNSTKERR()) + .field("STKERR", &self.STKERR()) + .field("LSPERR", &self.LSPERR()) + .field("BFARVALID", &self.BFARVALID()) + .finish() + } +} +impl RegTags for BFSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if !self.is_empty() { + [ + self.IBUSERR().then_some(("IBUSERR", Self::DOC_IBUSERR)), + self.PRECISERR().then_some(("PRECISERR", Self::DOC_PRECISERR)), + self.IMPRECISERR() + .then_some(("IMPRECISERR", Self::DOC_IMPRECISERR)), + self.UNSTKERR().then_some(("UNSTKERR", Self::DOC_UNSTKERR)), + self.STKERR().then_some(("STKERR", Self::DOC_STKERR)), + self.LSPERR().then_some(("LSPERR", Self::DOC_LSPERR)), + ].into_iter() + .flatten() + } else { + <[_; 6]>::default().into_iter().flatten() + } + } +} + + +/// The MemManage fault status register +/// indicates a memory access violation detected by the Memory Protection Unit (MPU). +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct MMFSR(u8); +impl Debug for MMFSR { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MMFSR") + .field("IACCVIOL", &self.IACCVIOL()) + .field("DACCVIOL", &self.DACCVIOL()) + .field("MUNSTKERR", &self.MUNSTKERR()) + .field("MSTKERR", &self.MSTKERR()) + .field("MLSPERR", &self.MLSPERR()) + .field("MMARVALID", &self.MMARVALID()) + .finish() + } +} +impl MMFSR { + // Instruction access violation flag. + // The processor attempted an instruction fetch from a location that does not permit execution + // + // The PC value stacked for the exception return points to the faulting instruction. The processor + // has not written a fault address to the `MMFAR`. This fault condition occurs on any attempt of + // instruction fetches to an XN (eXecute Never) region, even when the MPU is disabled or not + // present. Potential reasons: + // - Branch to regions that are not defined in the MPU or defined as non-executable. + // - Invalid return due to corrupted stack content. + // - Incorrect entry in the exception vector table. + bit! {0b0000_0001, IACCVIOL, r#"Instruction access violation. + The processor attempted an instruction fetch from a location that does not permit execution. + Faulting instruction: see `PC`. + "#} + + // Data access violation flag. + // The processor attempted a load or store at a location that does not permit the operation. + // + // The PC value stacked for the exception return points to the faulting instruction. + // The processor has loaded the `MMFAR` with the address of the attempted access. + bit! {0b0000_0010, DACCVIOL, r#"Data access violation. + The processor attempted a load or store at a location that does not permit the operation. + Faulting instruction: see `PC`. + Address of the attempted access: see `MMFAR`. + "#} + + // MemManage fault on unstacking for a return from exception. + // + // Unstacking for an exception return has caused one or more access violations. + // + // This fault is chained to the handler which means that the original return stack is still present. + // The processor has not adjusted the SP from the failing return, and has not performed a new + // save. The processor has not written a fault address to the `MMFAR`. Potential reasons: + // - Stack pointer is corrupted + // - MPU region for the stack changed during execution of the exception handler. + bit! {0b0000_1000, MUNSTKERR, r#"MemManage fault on unstacking for a return from exception. + Fault address - see MMFAR. + Potential reasons: + - Stack pointer is corrupted + - MPU region for the stack changed during execution of the exception handler + "#} + + + bit! {0b0001_0000, MSTKERR, r#" + MemManage fault on stacking for exception entry. + + The SP is still adjusted but the values in the context area on the stack might be incorrect. The + processor has not written a fault address to the MMFAR. Potential reasons: + - Stack pointer is corrupted or not initialized + - Stack is reaching a region not defined by the MPU as read/write memory. + "#} + + bit! {0b0010_0000, MLSPERR, r#"MemManage fault during floating point lazy state preservation (only Cortex-M4 with FPU)."#} + bit! {0b1000_0000, MMARVALID, r#"MemManage Fault Address Register (MMFAR) valid flag. SCB->MMFAR holds a valid fault address."#} +} + +impl RegTags for MMFSR { + fn is_empty(&self) -> bool { self.0 == 0 } + + fn tags(&self) -> impl IntoIterator { + if self.is_empty() { + return [None, None, None, None, None].into_iter().flatten(); + } + + [ + self.IACCVIOL().then_some(("IACCVIOL", Self::DOC_IACCVIOL)), + self.DACCVIOL().then_some(("DACCVIOL", Self::DOC_DACCVIOL)), + self.MUNSTKERR().then_some(("MUNSTKERR", Self::DOC_MUNSTKERR)), + self.MSTKERR().then_some(("MSTKERR", Self::DOC_MSTKERR)), + self.MLSPERR().then_some(("MLSPERR", Self::DOC_MLSPERR)), + ].into_iter() + .flatten() + } +} + + +pub trait RegTags { + /// Has no tags + fn is_empty(&self) -> bool; + + /// Returns `true` tags as (name + description) + fn tags(&self) -> impl IntoIterator; +} + + +pub enum FaultKind { + // HFSR: + /// Bus error on a vector read error HardFault + VECTTBL, + /// Fault that is escalated to a hard fault + FORCED, + /// Fault on breakpoint escalation + DEBUGEVT, + + // MMFSR: + /// Fault on instruction access MemManage + IACCVIOL, + /// Fault on direct data access + DACCVIOL, + /// Context stacking, because of an MPU access violation + MSTKERR, + /// Context unstacking, because of an MPU access violation + MUNSTKERR, + /// During lazy floating-point state preservation + MLSPERR, + + // BFSR: + /// During exception stacking BusFault + STKERR, + /// During exception unstacking + UNSTKERR, + /// During instruction prefetching, precise + IBUSERR, + /// During lazy floating-point state preservation + LSPERR, + /// Precise data access error, precise + PRECISERR, + /// Imprecise data access error, imprecise + IMPRECISERR, + + // UFSR: + /// Undefined instruction UsageFault + UNDEFINSTR, + /// Attempt to enter an invalid instruction set state + INVSTATE, + /// Failed integrity check on exception return + INVPC, + /// Attempt to access a non-existing coprocessor + NOCPC, + /// Illegal unaligned load or store + UNALIGNED, + /// Stack overflow + STKOF, + /// Divide By 0 + DIVBYZERO, +} + + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum FpuAccessMode { + /// FPU is not accessible + Disabled, + /// FPU is accessible in Privileged and User mode + Enabled, + /// FPU is accessible in Privileged mode only + Privileged, +} + + +/// Active exception number +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)] +pub enum VectActive { + /// Thread mode + ThreadMode, + + /// Processor core exception (internal interrupts) + Exception(Exception), + + /// Device specific exception (external interrupts) + Interrupt { + /// Interrupt number. This number is always within half open range `[0, 512)` (9 bit) + irqn: u16, + }, +} + +impl VectActive { + /// Converts a vector number into `VectActive` + #[inline] + pub fn from(vect_active: u16) -> Option { + Some(match vect_active { + 0 => VectActive::ThreadMode, + 2 => VectActive::Exception(Exception::NonMaskableInt), + 3 => VectActive::Exception(Exception::HardFault), + 4 => VectActive::Exception(Exception::MemoryManagement), + 5 => VectActive::Exception(Exception::BusFault), + 6 => VectActive::Exception(Exception::UsageFault), + 7 => VectActive::Exception(Exception::SecureFault), + 11 => VectActive::Exception(Exception::SVCall), + 12 => VectActive::Exception(Exception::DebugMonitor), + 14 => VectActive::Exception(Exception::PendSV), + 15 => VectActive::Exception(Exception::SysTick), + irqn if (16..512).contains(&irqn) => VectActive::Interrupt { irqn: irqn - 16 }, + _ => return None, + }) + } +} + + +/// Processor core exceptions (internal interrupts) +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash)] +pub enum Exception { + /// Non maskable interrupt + NonMaskableInt, + + /// Hard fault interrupt + HardFault, + + /// Memory management interrupt (not present on Cortex-M0 variants) + MemoryManagement, + + /// Bus fault interrupt (not present on Cortex-M0 variants) + BusFault, + + /// Usage fault interrupt (not present on Cortex-M0 variants) + UsageFault, + + /// Secure fault interrupt (only on ARMv8-M) + SecureFault, + + /// SV call interrupt + SVCall, + + /// Debug monitor interrupt (not present on Cortex-M0 variants) + DebugMonitor, + + /// Pend SV interrupt + PendSV, + + /// System Tick interrupt + SysTick, +} + + +#[cfg(test)] +mod tests { + use super::*; + + + #[test] + fn test_mmfsr_daccviol() { + let reg = ExceptionFrame { r0: 0x00000004, + r1: 0x00000008, + r2: 0x00000008, + r3: 0x00000008, + r12: 0x00000008, + lr: 0x6000d2e7.into(), + pc: 0x6000d5e8.into(), + psr: 0x010f0000.into(), + cfsr: 0x00000082.into(), + hfsr: 0x00000000.into(), + mmfar: 0x00000004.into(), + bfar: 0x00000004.into(), + rcccsr: 0x00000000 }; + let mmfsr = reg.mmfsr(); + assert!(mmfsr.DACCVIOL()); + assert!(mmfsr.MMARVALID()); + } + + #[test] + fn test_mmfsr_daccviol__() { + let reg = ExceptionFrame { r0: 0x00000004, + r1: 0x00000008, + r2: 0x00000008, + r3: 0x00000008, + r12: 0x00000008, + lr: 0x6000d2e7.into(), + pc: 0x6000d5e8.into(), + psr: 0x010f0000.into(), + cfsr: 0x00000082.into(), + hfsr: 0x00000000.into(), + mmfar: 0x00000004.into(), + bfar: 0x00000004.into(), + rcccsr: 0x00000000 }; + let mmfsr = reg.mmfsr(); + assert!(mmfsr.DACCVIOL()); + assert!(mmfsr.MMARVALID()); + } +} diff --git a/support/addr2line/src/fmt/crashlog.rs b/support/addr2line/src/fmt/crashlog.rs index ecb1d9eb..28ee6c2a 100644 --- a/support/addr2line/src/fmt/crashlog.rs +++ b/support/addr2line/src/fmt/crashlog.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::io::prelude::Write; use std::path::Path; use std::io::Read; @@ -95,17 +96,298 @@ pub struct CrashLog> { pub ptrs: HashMap, } +// impl CrashLog { +// pub fn new() -> Self { +// // +// // +// // +// } +// } + + +impl CrashLog { + pub fn pretty_print_sub_title(&self, mut out: W, indent: &str, title: &str) -> std::io::Result<()> { + writeln!(out, "{indent} {title}") + } + + fn pretty_print_head(&self, mut out: W, title: bool, indent: usize) -> std::io::Result<()> { + let indented = INDENT.repeat(indent); + if title { + write!(out, "{indented}Crash")?; + if let Some(s) = self.date.as_deref() { + writeln!(out, " at {s}")?; + } else { + writeln!(out)?; + } + } + + if let Some(s) = self.build.as_deref() { + writeln!(out, "{indented} BUILD: {s}")?; + } + + if let Some(v) = &self.heap { + writeln!(out, "{indented} HEAP: {v}")?; + } + + Ok(()) + } +} + + +impl CrashLog> where Addr: std::cmp::Eq + std::hash::Hash + WriteReport { + pub fn pretty_print_regs<'a, 'b, W, I>(&self, + mut out: W, + regs: I, + resolved: &HashMap, Report>, + header: &str, + title: bool, + indent: usize, + funcs: bool, + short: bool, + ranges: bool, + demangle: bool) + -> std::io::Result<()> + where W: Write, + I: IntoIterator + { + let indented = INDENT.repeat(indent); + + // title: + self.pretty_print_sub_title(&mut out, &indented, header)?; + + + for (k, name) in regs { + let addr = &self.ptrs[k]; + + let space = " ".repeat(8 - name.len()); + write!(out, "{indented} {name}:{space}")?; + addr.default_print(&mut out, title, indent, funcs, short, ranges, demangle)?; + write!(out, ":")?; + + if let Some(report) = resolved.get(addr) && + !report.symbols.is_empty() + { + write!(out, "\n")?; + report.default_print(&mut out, false, indent + 2, funcs, short, ranges, demangle)?; + } else { + write!(out, " ??\n")?; + } + } + Ok(()) + } + + /// General-purpose registers + pub fn pretty_print_gpr(&self, + mut out: W, + resolved: &HashMap, Report>, + title: bool, + indent: usize, + funcs: bool, + short: bool, + ranges: bool, + demangle: bool) + -> std::io::Result<()> { + let gpr = [ + ("r0", "0"), + ("r1", "1"), + ("r2", "2"), + ("r3", "3"), + ("r12", "12"), + ("lr", "14 LR"), + ("pc", "15 PC"), + ]; + let header = "General-purpose registers (stack)"; + self.pretty_print_regs(&mut out, gpr, resolved, header, title, indent, funcs, short, ranges, demangle) + + // let indented = INDENT.repeat(indent); + + // // title: + // self.pretty_print_sub_title(&mut out, &indented, "General-purpose registers (stack)")?; + + // for k in GPR { + // let addr = &self.ptrs[*k]; + + // let space = " ".repeat(8 - k.len()); + // write!(out, "{indented} {k}:{space}")?; + // addr.default_print(&mut out, title, indent, funcs, short, ranges, demangle)?; + // write!(out, ":")?; + + // if let Some(report) = resolved.get(addr) && + // !report.symbols.is_empty() + // { + // write!(out, "\n")?; + // report.default_print(&mut out, false, indent + 2, funcs, short, ranges, demangle)?; + // } else { + // write!(out, " ??\n")?; + // } + // } + // Ok(()) + } + + + /// Special registers + pub fn pretty_print_sr(&self, + mut out: W, + resolved: &HashMap, Report>, + title: bool, + indent: usize, + funcs: bool, + short: bool, + ranges: bool, + demangle: bool) + -> std::io::Result<()> + where crate::ef::PSR: TryFrom, + crate::ef::CFSR: TryFrom, + crate::ef::HSFR: TryFrom + { + use crate::ef::*; + + + let gpr = [("mmfar", "MMFAR"), ("bfar", "BFAR"), ("rcccsr", "rcccsr")]; + let header = "Special registers"; + self.pretty_print_regs(&mut out, gpr, resolved, header, title, indent, funcs, short, ranges, demangle)?; + + let indented = INDENT.repeat(indent); + + + fn print_reg(mut out: W, + reg: R, + name: &str, + doc: &str, + indent: &str) + -> std::io::Result<()> { + if !reg.is_empty() { + let space = " ".repeat(8 - name.len()); + writeln!(out, "{indent} {space}{name}: {reg:#032b} {doc}")?; + + let mut max_tag_len = 0; + for (tag, doc) in reg.tags() { + max_tag_len = max_tag_len.max(tag.len()); + let doc: Vec<_> = doc.trim() + .lines() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .collect(); + let gap = " ".repeat(max_tag_len - tag.len()); + let pre = format!("{indent} {space} {tag}"); + write!(out, "{pre}")?; + if !doc.is_empty() { + writeln!(out, ":{gap} {}", doc.first().unwrap())?; + let space = " ".repeat(pre.len()); + for line in doc.into_iter().skip(1) { + writeln!(out, "{space} {gap} {line}")?; + } + } + } + } + + Ok(()) + } + + // PSR: + if let Some(Ok(reg)) = self.ptrs.get("psr").map(|a| a.value()).map(PSR::try_from) { + let space = " ".repeat(8 - "PSR".len()); + let doc = "(Program Status Register)"; + writeln!(out, "{indented} PSR:{space} {reg:#032b} {doc}")?; + let apsr = reg.apsr(); + let ipsr = reg.ipsr(); + let epsr = reg.epsr(); + + + print_reg( + &mut out, + apsr, + "APSR", + "(Application Program Status Register)", + &indented, + )?; + print_reg( + &mut out, + ipsr, + "IPSR", + "(Interrupt Program Status Register)", + &indented, + )?; + print_reg( + &mut out, + epsr, + "EPSR", + "(Execution Program Status Register)", + &indented, + )?; + } + + + // CFSR: + if let Some(Ok(reg)) = self.ptrs.get("cfsr").map(|a| a.value()).map(CFSR::try_from) { + let space = " ".repeat(8 - "CFSR".len()); + let doc = "(Configurable Fault Status)"; + writeln!(out, "{indented} CFSR:{space} {reg:#032b} {doc}")?; + let ufsr = reg.ufsr(); + let bfsr = reg.bfsr(); + let mmfsr = reg.mmfsr(); + + + print_reg(&mut out, ufsr, "UFSR", "(UsageFault Status Register)", &indented)?; + print_reg(&mut out, bfsr, "BFSR", "(BusFault Status Register)", &indented)?; + print_reg( + &mut out, + mmfsr, + "MMFSR", + "(MemManage Fault Status Register)", + &indented, + )?; + } + + + // HSFR: + if let Some(Ok(reg)) = self.ptrs.get("hsfr").map(|a| a.value()).map(HSFR::try_from) { + let doc = "(HardFault Status Register)"; + print_reg(&mut out, reg, "HSFR", doc, &indented)?; + } + + Ok(()) + } + + + pub fn pretty_print(&self, + mut out: W, + resolved: &HashMap, Report>, + title: bool, + indent: usize, + funcs: bool, + short: bool, + ranges: bool, + demangle: bool) + -> std::io::Result<()> + where crate::ef::PSR: TryFrom, + crate::ef::CFSR: TryFrom, + crate::ef::HSFR: TryFrom + { + // Header: + self.pretty_print_head(&mut out, title, indent)?; + + // Stack: + self.pretty_print_gpr(&mut out, resolved, title, indent, funcs, short, ranges, demangle)?; + + // Registers: + self.pretty_print_sr(&mut out, resolved, title, indent, funcs, short, ranges, demangle)?; + + writeln!(out) + } +} + impl WriteReport for CrashLog<&'_ Report> { - fn default_print(&self, - mut out: W, - title: bool, - indent: usize, - funcs: bool, - short: bool, - ranges: bool, - nice: bool) - -> std::io::Result<()> { + fn default_print(&self, + mut out: W, + title: bool, + indent: usize, + funcs: bool, + short: bool, + ranges: bool, + demangle: bool) + -> std::io::Result<()> { let indented = INDENT.repeat(indent); if title { write!(out, "{indented}Crash")?; @@ -131,13 +413,13 @@ impl WriteReport for CrashLog<&'_ Report> { let space = " ".repeat(8 - k.len()); write!(out, "{indented} {k}:{space}")?; v.addr - .default_print(&mut out, title, indent, funcs, short, ranges, nice)?; + .default_print(&mut out, title, indent, funcs, short, ranges, demangle)?; write!(out, ":")?; if v.symbols.is_empty() { write!(out, " ??\n")?; } else { write!(out, "\n")?; - v.default_print(&mut out, false, indent + 2, funcs, short, ranges, nice)?; + v.default_print(&mut out, false, indent + 2, funcs, short, ranges, demangle)?; } } diff --git a/support/addr2line/src/lib.rs b/support/addr2line/src/lib.rs index 6355b1a6..28d50525 100644 --- a/support/addr2line/src/lib.rs +++ b/support/addr2line/src/lib.rs @@ -1,3 +1,6 @@ +#![feature(let_chains)] + +pub mod ef; pub mod fmt; pub mod trace; pub mod elf;