diff --git a/Cargo.lock b/Cargo.lock index 7b367e2..23f0227 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,83 +1,113 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.15.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "0.7.15" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] -name = "ansi_term" -version = "0.11.0" +name = "anstream" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "arrayvec" -version = "0.5.2" +name = "anstyle" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] -name = "atty" -version = "0.2.14" +name = "anstyle-parse" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" -version = "1.0.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.59" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-link", ] [[package]] name = "bad64" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5352295386f01551b3802dbb8e6f7227770340092070e302133b93dd58991d0e" +checksum = "cdfe7137c8817d4649b0f05e559c759efa8fb376cd25a33c4d069288332f1202" dependencies = [ "bad64-sys", "cstr_core", @@ -88,142 +118,134 @@ dependencies = [ [[package]] name = "bad64-sys" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4b87f097c8622246494597ccdf357a8c74bf009b3deb652580590a114a6c37" +checksum = "95ee29370ca1576779cbf37adc0bebd518ef7956bb457f64fe499817a7774aea" dependencies = [ - "bindgen 0.59.1", + "bindgen 0.59.2", "cc", "glob", ] [[package]] name = "base64" -version = "0.13.0" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bindgen" -version = "0.58.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ - "bitflags", - "cexpr 0.4.0", + "bitflags 1.3.2", + "cexpr", "clang-sys", - "clap", - "env_logger", "lazy_static", "lazycell", - "log", "peeking_take_while", "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", - "which", ] [[package]] name = "bindgen" -version = "0.59.1" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags", - "cexpr 0.5.0", + "bitflags 2.11.0", + "cexpr", "clang-sys", - "clap", - "env_logger", - "lazy_static", - "lazycell", + "itertools", "log", - "peeking_take_while", + "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 2.1.1", "shlex", - "which", + "syn 2.0.117", ] [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bitvec" -version = "0.19.5" +name = "bitflags" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "cc" -version = "1.0.69" +name = "bytes" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" -dependencies = [ - "jobserver", -] +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] -name = "cexpr" -version = "0.4.0" +name = "cc" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ - "nom 5.1.2", + "find-msvc-tools", + "jobserver", + "libc", + "shlex", ] [[package]] name = "cexpr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 6.2.1", + "nom 7.1.3", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "chrono" -version = "0.4.19" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", -] +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clang-sys" -version = "1.2.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", @@ -232,79 +254,60 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", + "clap_builder", ] [[package]] -name = "clipboard-win" -version = "4.2.1" +name = "clap_builder" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ - "error-code", - "str-buf", - "winapi", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "crossbeam-channel" -version = "0.5.1" +name = "clap_lex" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] -name = "crossbeam-deque" -version = "0.8.1" +name = "clipboard-win" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", + "error-code", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.5" +name = "cmake" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", + "cc", ] [[package]] -name = "crossbeam-utils" -version = "0.8.5" +name = "colorchoice" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if", - "lazy_static", -] +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "cstr_core" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3" +checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" dependencies = [ "cty", "memchr", @@ -312,36 +315,35 @@ dependencies = [ [[package]] name = "cty" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7313c0d620d0cb4dbd9d019e461a4beb501071ff46ec0ab933efb4daa76d73e3" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] -name = "dirs-next" -version = "2.0.0" +name = "deranged" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "cfg-if", - "dirs-sys-next", + "powerfmt", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "libc", - "redox_users", - "winapi", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "either" -version = "1.6.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "endian-type" @@ -350,16 +352,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] -name = "env_logger" -version = "0.8.4" +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "libc", + "windows-sys 0.61.2", ] [[package]] @@ -374,33 +373,28 @@ dependencies = [ [[package]] name = "error-code" -version = "2.3.0" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" -dependencies = [ - "libc", - "str-buf", -] +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" [[package]] name = "falcon" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1613c8042d02d7b730e016ca2a16d48666311dbcf578bff4faf1e6664d7ecd94" +checksum = "8b40c0134b29f28ebfe0beaf951275d36afb908b3c3b2f67ffa831bd75d3bee1" dependencies = [ "bad64", - "base64", - "bitflags", - "error-chain", + "base64 0.21.7", + "bitflags 1.3.2", "falcon_capstone", - "goblin", + "goblin 0.6.1", "log", "num-bigint", "num-traits", - "rustc-hash", + "rustc-hash 1.1.0", "serde", - "serde_derive", "serde_json", + "thiserror 1.0.69", ] [[package]] @@ -412,12 +406,10 @@ dependencies = [ "error-chain", "falcon", "falcon-z3", - "falcon_capstone", - "goblin", + "goblin 0.10.5", "lazy_static", "log", - "nom 6.2.1", - "rayon", + "nom 8.0.0", "rustyline", "serde", "serde_derive", @@ -426,675 +418,1885 @@ dependencies = [ [[package]] name = "falcon-z3" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d2584b76536c35b15c7fd40b99f2463559d5ca668df671c5438e0fd937d2b0" +checksum = "e592f2c68868529fbba27f5e72c13c36cb29877350d39c7edd0342261bba60ae" dependencies = [ - "error-chain", "falcon", "num-bigint", "num-traits", + "thiserror 2.0.18", "z3-sys", ] [[package]] name = "falcon_capstone" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63eb2923d04810575c35e6d0b754e716ca1d3db575aeb16d0778d7e40975578b" +checksum = "214957a031d4c6d944adef01c62e592a2970931f7a7015319e0066928ab44a14" dependencies = [ - "bindgen 0.59.1", + "bindgen 0.72.1", + "cmake", + "fs_extra", "libc", - "pkg-config", ] [[package]] name = "fd-lock" -version = "3.0.0" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8806dd91a06a7a403a8e596f9bfbfb34e469efbc363fc9c9713e79e26472e36" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "libc", - "winapi", + "rustix", + "windows-sys 0.59.0", ] [[package]] -name = "funty" -version = "1.1.0" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] -name = "getrandom" -version = "0.2.3" +name = "form_urlencoded" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ - "cfg-if", - "libc", - "wasi", + "percent-encoding", ] [[package]] -name = "gimli" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" - -[[package]] -name = "glob" -version = "0.3.0" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] -name = "goblin" -version = "0.4.2" +name = "futures-channel" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b1800b95efee8ad4ef04517d4d69f8e209e763b1668f1179aeeedd0e454da55" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ - "log", - "plain", - "scroll", + "futures-core", + "futures-sink", ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "futures-core" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] -name = "humantime" -version = "2.1.0" +name = "futures-io" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] -name = "itoa" -version = "0.4.7" +name = "futures-sink" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] -name = "jobserver" -version = "0.1.24" +name = "futures-task" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] -name = "lazy_static" -version = "1.4.0" +name = "futures-util" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "getrandom" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] [[package]] -name = "lexical-core" -version = "0.7.6" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "arrayvec", - "bitflags", "cfg-if", - "ryu", - "static_assertions", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", ] [[package]] -name = "libc" -version = "0.2.99" +name = "gimli" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] -name = "libloading" -version = "0.7.0" +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" -dependencies = [ - "cfg-if", - "winapi", -] +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "log" -version = "0.4.14" +name = "goblin" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" dependencies = [ - "cfg-if", + "log", + "plain", + "scroll 0.11.0", ] [[package]] -name = "memchr" -version = "2.3.4" +name = "goblin" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "983a6aafb3b12d4c41ea78d39e189af4298ce747353945ff5105b54a056e5cd9" +dependencies = [ + "log", + "plain", + "scroll 0.13.0", +] [[package]] -name = "memoffset" -version = "0.6.4" +name = "home" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "autocfg", + "windows-sys 0.61.2", ] [[package]] -name = "miniz_oxide" -version = "0.4.4" +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "adler", - "autocfg", + "bytes", + "itoa", ] [[package]] -name = "nibble_vec" -version = "0.1.0" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "smallvec", + "bytes", + "http", ] [[package]] -name = "nix" -version = "0.22.1" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", ] [[package]] -name = "nom" -version = "5.1.2" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check", -] +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "nom" -version = "6.2.1" +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", ] [[package]] -name = "num-bigint" -version = "0.4.0" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "autocfg", - "num-integer", - "num-traits", - "serde", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", ] [[package]] -name = "num-derive" -version = "0.3.3" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] -name = "num-integer" -version = "0.1.44" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ - "autocfg", - "num-traits", + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "num-traits" -version = "0.2.14" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "autocfg", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "hermit-abi", - "libc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "object" -version = "0.24.0" +name = "icu_normalizer_data" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] -name = "peeking_take_while" -version = "0.1.2" +name = "icu_properties" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] [[package]] -name = "pkg-config" -version = "0.3.19" +name = "icu_properties_data" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] -name = "plain" -version = "0.2.3" +name = "icu_provider" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] [[package]] -name = "proc-macro2" -version = "1.0.28" +name = "idna" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "unicode-xid", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "quote" -version = "1.0.9" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "proc-macro2", + "icu_normalizer", + "icu_properties", ] [[package]] -name = "radium" -version = "0.5.3" +name = "ipnet" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] -name = "radix_trie" -version = "0.2.1" +name = "iri-string" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ - "endian-type", - "nibble_vec", + "memchr", + "serde", ] [[package]] -name = "rayon" -version = "1.5.1" +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ - "autocfg", - "crossbeam-deque", "either", - "rayon-core", ] [[package]] -name = "rayon-core" -version = "1.9.1" +name = "itoa" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "redox_syscall" -version = "0.2.10" +name = "jobserver" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "bitflags", + "getrandom 0.3.4", + "libc", ] [[package]] -name = "redox_users" -version = "0.4.0" +name = "js-sys" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ - "getrandom", - "redox_syscall", + "once_cell", + "wasm-bindgen", ] [[package]] -name = "regex" -version = "1.4.6" +name = "lazy_static" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", ] [[package]] -name = "regex-syntax" -version = "0.6.25" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] -name = "rustc-demangle" -version = "0.1.20" +name = "litemap" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "log" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] -name = "rustyline" -version = "9.0.0" +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ - "bitflags", - "cfg-if", - "clipboard-win", - "dirs-next", - "fd-lock", "libc", - "log", - "memchr", - "nix", - "radix_trie", - "scopeguard", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ "smallvec", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "winapi", ] [[package]] -name = "ryu" -version = "1.0.5" +name = "nix" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "libc", +] [[package]] -name = "scopeguard" -version = "1.1.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] [[package]] -name = "scroll" -version = "0.10.2" +name = "nom" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ - "scroll_derive", + "memchr", ] [[package]] -name = "scroll_derive" -version = "0.10.5" +name = "num-bigint" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "proc-macro2", - "quote", - "syn", + "num-integer", + "num-traits", + "serde", ] [[package]] -name = "serde" -version = "1.0.127" +name = "num-conv" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] -name = "serde_derive" -version = "1.0.127" +name = "num-derive" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "serde_json" -version = "1.0.66" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "itoa", - "ryu", - "serde", + "num-traits", ] [[package]] -name = "shlex" -version = "1.0.0" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] [[package]] -name = "simplelog" -version = "0.10.0" +name = "num_threads" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d0fe306a0ced1c88a58042dc22fc2ddd000982c26d75f6aa09a394547c41e0" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ - "chrono", - "log", - "termcolor", + "libc", ] [[package]] -name = "smallvec" -version = "1.6.1" +name = "object" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "str-buf" -version = "1.0.5" +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "strsim" -version = "0.8.0" +name = "peeking_take_while" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] -name = "syn" -version = "1.0.74" +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "potential_utf" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "quote", - "unicode-xid", + "syn 2.0.117", ] [[package]] -name = "tap" -version = "1.0.1" +name = "proc-macro2" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] [[package]] -name = "termcolor" -version = "1.1.2" +name = "quinn" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ - "winapi-util", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "quinn-proto" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ - "unicode-width", + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", ] [[package]] -name = "time" -version = "0.1.43" +name = "quinn-udp" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ + "cfg_aliases", "libc", - "winapi", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", ] [[package]] -name = "unicode-segmentation" -version = "1.8.0" +name = "quote" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] [[package]] -name = "unicode-width" -version = "0.1.8" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "radix_trie" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] [[package]] -name = "utf8parse" -version = "0.2.0" +name = "rand" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] [[package]] -name = "vec_map" -version = "0.8.2" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] [[package]] -name = "version_check" -version = "0.9.3" +name = "rand_core" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] [[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +name = "regex" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] [[package]] -name = "which" -version = "3.1.1" +name = "regex-automata" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ - "libc", + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", ] [[package]] -name = "winapi" -version = "0.3.9" +name = "ring" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "rustc-demangle" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] -name = "winapi-util" -version = "0.1.5" +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "winapi", + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "rustls" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] [[package]] -name = "wyz" -version = "0.2.0" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +dependencies = [ + "web-time", + "zeroize", +] [[package]] -name = "z3-sys" -version = "0.7.0" +name = "rustls-webpki" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06b2f89b9301ab628c1b2ce7eb99e3a0bc50701652afa5a88b9e2b4ea9ce75f" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ - "bindgen 0.58.1", + "ring", + "rustls-pki-types", + "untrusted", ] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "rustyline" +version = "17.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e902948a25149d50edc1a8e0141aad50f54e22ba83ff988cf8f7c9ef07f50564" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "windows-sys 0.60.2", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive 0.11.1", +] + +[[package]] +name = "scroll" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1257cd4248b4132760d6524d6dda4e053bc648c9070b960929bf50cfb1e7add" +dependencies = [ + "scroll_derive 0.13.1", +] + +[[package]] +name = "scroll_derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "scroll_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed76efe62313ab6610570951494bdaa81568026e0318eaa55f167de70eeea67d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "z3-sys" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82b97329d02d87da6802ed9fda083f1b255d822ab13d5b1fb961196b58a69a1" +dependencies = [ + "bindgen 0.72.1", + "pkg-config", + "reqwest", +] + +[[package]] +name = "zerocopy" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 298cb2e..5b9f94f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,22 +9,19 @@ readme = "README.md" edition = "2018" [dependencies] -byteorder = "1.3" -clap = "2.33" +byteorder = "1.5" +clap = "4" error-chain = "0.12" -falcon = "0.5.2" -falcon_capstone = "0.5.0" -falcon-z3 = "0.5.2" -goblin = "0.4" -lazy_static = "1.4" +falcon = "0.6.0" +falcon-z3 = "0.6.0" +goblin = "0.10" +lazy_static = "1.5" log = "0.4" -nom = "6.2" -rayon = "1.0" -rustyline = "9" +nom = "8" +rustyline = "17" serde = "1.0" serde_derive = "1.0" -simplelog = "0.10" -# unicorn = "0.9.1" +simplelog = "0.12" [lib] name = "finch" @@ -35,7 +32,6 @@ name = "finch-bin" path = "src/main.rs" [features] -capstone4 = ["falcon/capstone4"] thread_safe = ["falcon/thread_safe"] [profile.release] diff --git a/lib/executor/driver.rs b/lib/executor/driver.rs index 7acf916..60576d5 100644 --- a/lib/executor/driver.rs +++ b/lib/executor/driver.rs @@ -263,7 +263,7 @@ impl Driver { } /// Retrieve the RefProgramLocation for this Driver - pub fn ref_program_location(&self) -> il::RefProgramLocation { + pub fn ref_program_location(&self) -> il::RefProgramLocation<'_> { self.location.apply(&self.program).unwrap() } diff --git a/lib/executor/hash_expression.rs b/lib/executor/hash_expression.rs index af250dc..dd8a4d6 100644 --- a/lib/executor/hash_expression.rs +++ b/lib/executor/hash_expression.rs @@ -105,6 +105,10 @@ impl ExpressionHash { ehbinop(self, bits, HashExpression::Shr) } + pub fn ashr(self, other: ExpressionHash) -> ExpressionHash { + ehbinop(self, other, HashExpression::AShr) + } + pub fn cmpeq(self, other: ExpressionHash) -> ExpressionHash { ehbinop(self, other, HashExpression::Cmpeq) } @@ -215,6 +219,10 @@ impl ExpressionHash { sym(&lhs, s, replacers), sym(&rhs, s, replacers), )), + HashExpression::AShr(lhs, rhs) => he2eh(&HashExpression::AShr( + sym(&lhs, s, replacers), + sym(&rhs, s, replacers), + )), HashExpression::Cmpeq(lhs, rhs) => he2eh(&HashExpression::Cmpeq( sym(&lhs, s, replacers), sym(&rhs, s, replacers), @@ -272,6 +280,7 @@ enum HashExpression { Xor(ExpressionHash, ExpressionHash), Shl(ExpressionHash, ExpressionHash), Shr(ExpressionHash, ExpressionHash), + AShr(ExpressionHash, ExpressionHash), Cmpeq(ExpressionHash, ExpressionHash), Cmpneq(ExpressionHash, ExpressionHash), Cmpltu(ExpressionHash, ExpressionHash), @@ -298,7 +307,8 @@ impl HashExpression { | HashExpression::Or(ref lhs, _) | HashExpression::Xor(ref lhs, _) | HashExpression::Shl(ref lhs, _) - | HashExpression::Shr(ref lhs, _) => lhs.bits(), + | HashExpression::Shr(ref lhs, _) + | HashExpression::AShr(ref lhs, _) => lhs.bits(), HashExpression::Cmpeq(_, _) | HashExpression::Cmpneq(_, _) | HashExpression::Cmpltu(_, _) @@ -342,7 +352,8 @@ impl HashExpressionStore { | HashExpression::Or(ref lhs, _) | HashExpression::Xor(ref lhs, _) | HashExpression::Shl(ref lhs, _) - | HashExpression::Shr(ref lhs, _) => self.bits(lhs), + | HashExpression::Shr(ref lhs, _) + | HashExpression::AShr(ref lhs, _) => self.bits(lhs), HashExpression::Cmpeq(_, _) | HashExpression::Cmpneq(_, _) | HashExpression::Cmpltu(_, _) @@ -394,6 +405,9 @@ impl HashExpressionStore { HashExpression::Shr(ref lhs, ref rhs) => { il::Expression::shr(self.expression(lhs)?, self.expression(rhs)?)? } + HashExpression::AShr(ref lhs, ref rhs) => { + il::Expression::ashr(self.expression(lhs)?, self.expression(rhs)?)? + } HashExpression::Cmpeq(ref lhs, ref rhs) => { il::Expression::cmpeq(self.expression(lhs)?, self.expression(rhs)?)? } @@ -472,6 +486,9 @@ impl HashExpressionStore { il::Expression::Shr(ref lhs, ref rhs) => { HashExpression::Shr(gh(hes, lhs), gh(hes, rhs)) } + il::Expression::AShr(ref lhs, ref rhs) => { + HashExpression::AShr(gh(hes, lhs), gh(hes, rhs)) + } il::Expression::Cmpeq(ref lhs, ref rhs) => { HashExpression::Cmpeq(gh(hes, lhs), gh(hes, rhs)) } diff --git a/lib/executor/memory.rs b/lib/executor/memory.rs index b425dd8..33909a2 100644 --- a/lib/executor/memory.rs +++ b/lib/executor/memory.rs @@ -12,15 +12,13 @@ pub const PAGE_SIZE: usize = 4096; pub struct Page { cells: HashMap>, permissions: Option, - size: usize, } impl Page { - fn new(size: usize) -> Page { + fn new() -> Page { Page { cells: HashMap::new(), permissions: None, - size, } } @@ -104,7 +102,7 @@ impl Memory { RC::make_mut( self.pages .entry(address + (i * PAGE_SIZE) as u64) - .or_insert_with(|| RC::new(Page::new(PAGE_SIZE))), + .or_insert_with(|| RC::new(Page::new())), ) .set_permissions(permissions); } @@ -113,7 +111,7 @@ impl Memory { } pub fn backing(&self) -> Option<&backing::Memory> { - self.backing.as_ref().map(|b| RC::borrow(b)) + self.backing.as_ref().map(RC::borrow) } pub fn flatten(&mut self) -> Result<()> { @@ -156,8 +154,8 @@ impl Memory { } { - let mut backing = self.backing.as_mut().unwrap(); - let backing = RC::make_mut(&mut backing); + let backing = self.backing.as_mut().unwrap(); + let backing = RC::make_mut(backing); for (address, bytes, permissions) in flattened { backing.set_memory(address, bytes, permissions); @@ -171,7 +169,7 @@ impl Memory { RC::make_mut( self.pages .entry(address & (!(PAGE_SIZE as u64 - 1))) - .or_insert_with(|| RC::new(Page::new(PAGE_SIZE))), + .or_insert_with(|| RC::new(Page::new())), ) .set((address % PAGE_SIZE as u64) as usize, Some(byte)); } @@ -369,3 +367,200 @@ impl TranslationMemory for Memory { self.backing().and_then(|backing| backing.get8(address)) } } + +#[cfg(test)] +mod tests { + use super::*; + use falcon::executor::eval; + use falcon::memory::MemoryPermissions; + + #[test] + fn test_32bit_little_endian_byte_order() { + let mut mem = Memory::new(Endian::Little); + mem.store(0x1000, &il::expr_const(0xDEADBEEF, 32)).unwrap(); + + let b0 = mem.load(0x1000, 8).unwrap().unwrap(); + let b1 = mem.load(0x1001, 8).unwrap().unwrap(); + let b2 = mem.load(0x1002, 8).unwrap().unwrap(); + let b3 = mem.load(0x1003, 8).unwrap().unwrap(); + + assert_eq!(eval(&b0).unwrap().value_u64().unwrap(), 0xEF); + assert_eq!(eval(&b1).unwrap().value_u64().unwrap(), 0xBE); + assert_eq!(eval(&b2).unwrap().value_u64().unwrap(), 0xAD); + assert_eq!(eval(&b3).unwrap().value_u64().unwrap(), 0xDE); + } + + #[test] + fn test_32bit_big_endian_byte_order() { + let mut mem = Memory::new(Endian::Big); + mem.store(0x1000, &il::expr_const(0xDEADBEEF, 32)).unwrap(); + + let b0 = mem.load(0x1000, 8).unwrap().unwrap(); + let b1 = mem.load(0x1001, 8).unwrap().unwrap(); + let b2 = mem.load(0x1002, 8).unwrap().unwrap(); + let b3 = mem.load(0x1003, 8).unwrap().unwrap(); + + assert_eq!(eval(&b0).unwrap().value_u64().unwrap(), 0xDE); + assert_eq!(eval(&b1).unwrap().value_u64().unwrap(), 0xAD); + assert_eq!(eval(&b2).unwrap().value_u64().unwrap(), 0xBE); + assert_eq!(eval(&b3).unwrap().value_u64().unwrap(), 0xEF); + } + + #[test] + fn test_store_load_crossing_page_boundary() { + let mut mem = Memory::new(Endian::Little); + let addr = (PAGE_SIZE as u64) - 2; // 4094 + mem.store(addr, &il::expr_const(0xAABBCCDD, 32)).unwrap(); + let loaded = mem.load(addr, 32).unwrap().unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0xAABBCCDD); + } + + #[test] + fn test_load_partially_uninitialized_returns_none() { + let mut mem = Memory::new(Endian::Little); + mem.store(0x2000, &il::expr_const(0x42, 8)).unwrap(); + // Second byte at 0x2001 is uninitialized + let loaded = mem.load(0x2000, 16).unwrap(); + assert!(loaded.is_none()); + } + + #[test] + fn test_backing_memory_fallback() { + let mut backing = backing::Memory::new(Endian::Little); + backing.set_memory( + 0x3000, + vec![0x41, 0x42, 0x43, 0x44], + MemoryPermissions::READ, + ); + let mem = Memory::new_with_backing(Endian::Little, RC::new(backing)); + + let b0 = mem.load(0x3000, 8).unwrap().unwrap(); + let b1 = mem.load(0x3001, 8).unwrap().unwrap(); + let b2 = mem.load(0x3002, 8).unwrap().unwrap(); + let b3 = mem.load(0x3003, 8).unwrap().unwrap(); + + assert_eq!(eval(&b0).unwrap().value_u64().unwrap(), 0x41); + assert_eq!(eval(&b1).unwrap().value_u64().unwrap(), 0x42); + assert_eq!(eval(&b2).unwrap().value_u64().unwrap(), 0x43); + assert_eq!(eval(&b3).unwrap().value_u64().unwrap(), 0x44); + } + + #[test] + fn test_page_overrides_backing() { + let mut backing = backing::Memory::new(Endian::Little); + backing.set_memory(0x3000, vec![0xFF], MemoryPermissions::READ); + let mut mem = Memory::new_with_backing(Endian::Little, RC::new(backing)); + + mem.store(0x3000, &il::expr_const(0x42, 8)).unwrap(); + let loaded = mem.load(0x3000, 8).unwrap().unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0x42); + } + + #[test] + fn test_set_permissions_unaligned_address_errors() { + let mut mem = Memory::new(Endian::Little); + let result = mem.set_permissions(0x1, 4096, Some(MemoryPermissions::READ)); + assert!(result.is_err()); + } + + #[test] + fn test_set_permissions_unaligned_length_errors() { + let mut mem = Memory::new(Endian::Little); + let result = mem.set_permissions(0x0, 100, Some(MemoryPermissions::READ)); + assert!(result.is_err()); + } + + #[test] + fn test_flatten_concrete_to_backing() { + let mut mem = Memory::new(Endian::Little); + mem.store(0x0, &il::expr_const(0x41, 8)).unwrap(); + mem.store(0x1, &il::expr_const(0x42, 8)).unwrap(); + + // Before flatten, page exists + assert!(!mem.pages.is_empty()); + + mem.flatten().unwrap(); + + // After flatten, page removed (all concrete) + assert!(mem.pages.is_empty()); + + // Bytes still accessible via backing + let b0 = mem.load(0x0, 8).unwrap().unwrap(); + let b1 = mem.load(0x1, 8).unwrap().unwrap(); + assert_eq!(eval(&b0).unwrap().value_u64().unwrap(), 0x41); + assert_eq!(eval(&b1).unwrap().value_u64().unwrap(), 0x42); + } + + #[test] + fn test_flatten_keeps_symbolic_page() { + let mut mem = Memory::new(Endian::Little); + let symbolic = il::expr_scalar("x", 8); + mem.store(0x0, &symbolic).unwrap(); + + mem.flatten().unwrap(); + + // Page should still exist (symbolic bytes can't flatten) + assert!(!mem.pages.is_empty()); + } + + #[test] + fn test_merge_differing_bytes_produce_ite() { + let mut mem_a = Memory::new(Endian::Little); + mem_a.store(0x0, &il::expr_const(0x41, 8)).unwrap(); + + let mut mem_b = Memory::new(Endian::Little); + mem_b.store(0x0, &il::expr_const(0x42, 8)).unwrap(); + + let constraint = il::expr_scalar("cond", 1); + let merged = mem_a.merge(&mem_b, &constraint).unwrap(); + let loaded = merged.load(0x0, 8).unwrap().unwrap(); + + // Result should be an ITE, not a plain constant + assert!(!loaded.all_constants()); + } + + #[test] + fn test_merge_identical_bytes_unchanged() { + let mut mem_a = Memory::new(Endian::Little); + mem_a.store(0x0, &il::expr_const(0x41, 8)).unwrap(); + + let mut mem_b = Memory::new(Endian::Little); + mem_b.store(0x0, &il::expr_const(0x41, 8)).unwrap(); + + let constraint = il::expr_scalar("cond", 1); + let merged = mem_a.merge(&mem_b, &constraint).unwrap(); + let loaded = merged.load(0x0, 8).unwrap().unwrap(); + + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0x41); + } + + #[test] + fn test_store_load_symbolic_roundtrip() { + let mut mem = Memory::new(Endian::Little); + let sym = il::expr_scalar("x", 8); + mem.store(0x1000, &sym).unwrap(); + let loaded = mem.load(0x1000, 8).unwrap().unwrap(); + assert_eq!(loaded, sym); + } + + #[test] + fn test_load_buf_partially_uninitialized() { + let mut mem = Memory::new(Endian::Little); + mem.store(0x0, &il::expr_const(0x41, 8)).unwrap(); + mem.store(0x1, &il::expr_const(0x42, 8)).unwrap(); + // Only 2 bytes initialized, try to load 4 + let result = mem.load_buf(0x0, 4).unwrap(); + assert!(result.is_none()); + } + + #[test] + fn test_initialize_blank_fills_zeros() { + let mut mem = Memory::new(Endian::Little); + mem.initialize_blank(0x4000, 4).unwrap(); + + for i in 0..4u64 { + let byte = mem.load(0x4000 + i, 8).unwrap().unwrap(); + assert_eq!(eval(&byte).unwrap().value_u64().unwrap(), 0); + } + } +} diff --git a/lib/executor/mod.rs b/lib/executor/mod.rs index e81596e..44f4cd0 100644 --- a/lib/executor/mod.rs +++ b/lib/executor/mod.rs @@ -247,6 +247,9 @@ pub fn simplify(expression: &il::Expression) -> Result { il::Expression::Shr(ref lhs, ref rhs) => { il::Expression::shr(simplify(lhs)?, simplify(rhs)?)? } + il::Expression::AShr(ref lhs, ref rhs) => { + il::Expression::ashr(simplify(lhs)?, simplify(rhs)?)? + } il::Expression::Cmpeq(ref lhs, ref rhs) => { il::Expression::cmpeq(simplify(lhs)?, simplify(rhs)?)? } @@ -284,6 +287,7 @@ pub fn expression_complexity(e: &il::Expression) -> usize { | il::Expression::Xor(lhs, rhs) | il::Expression::Shl(lhs, rhs) | il::Expression::Shr(lhs, rhs) + | il::Expression::AShr(lhs, rhs) | il::Expression::Cmpeq(lhs, rhs) | il::Expression::Cmpneq(lhs, rhs) | il::Expression::Cmplts(lhs, rhs) @@ -301,3 +305,542 @@ pub fn expression_complexity(e: &il::Expression) -> usize { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_expression_complexity_scalar() { + let s = il::expr_scalar("x", 32); + assert_eq!(expression_complexity(&s), 1); + } + + #[test] + fn test_expression_complexity_constant() { + let c = il::expr_const(42, 32); + assert_eq!(expression_complexity(&c), 1); + } + + #[test] + fn test_expression_complexity_binary_op() { + let expr = il::Expression::add(il::expr_scalar("x", 32), il::expr_const(1, 32)).unwrap(); + assert_eq!(expression_complexity(&expr), 3); + } + + #[test] + fn test_expression_complexity_nested() { + let inner = il::Expression::add(il::expr_scalar("x", 32), il::expr_const(1, 32)).unwrap(); + let outer = il::Expression::mul(inner, il::expr_const(2, 32)).unwrap(); + // (x + 1) * 2 => complexity = (1 + 1 + 1) + 1 + 1 = 5 + assert_eq!(expression_complexity(&outer), 5); + } + + #[test] + fn test_simplify_constant_folding() { + let expr = il::Expression::add(il::expr_const(1, 32), il::expr_const(2, 32)).unwrap(); + let result = simplify(&expr).unwrap(); + assert_eq!(result, il::expr_const(3, 32)); + } + + #[test] + fn test_simplify_or_with_zero() { + let x = il::expr_scalar("x", 32); + let zero = il::expr_const(0, 32); + let expr = il::Expression::or(zero, x.clone()).unwrap(); + let result = simplify(&expr).unwrap(); + assert_eq!(result, x); + } + + #[test] + fn test_simplify_nested_zext() { + let x = il::expr_scalar("x", 8); + let inner = il::Expression::zext(16, x.clone()).unwrap(); + let outer = il::Expression::zext(32, inner).unwrap(); + let result = simplify(&outer).unwrap(); + let expected = il::Expression::zext(32, x).unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn test_simplify_trun_zext_same_bits() { + let x = il::expr_scalar("x", 8); + let zext = il::Expression::zext(32, x.clone()).unwrap(); + let trun = il::Expression::trun(8, zext).unwrap(); + let result = simplify(&trun).unwrap(); + assert_eq!(result, x); + } + + #[test] + fn test_simplify_identity() { + let x = il::expr_scalar("x", 32); + let result = simplify(&x).unwrap(); + assert_eq!(result, x); + } + + #[test] + fn test_symbolic_memory_store_load_little_endian() { + let mut mem = SymbolicMemory::new(Endian::Little); + let val = il::expr_const(0x42, 8); + mem.store(0x1000, val.clone()).unwrap(); + let loaded = mem.load(0x1000, 8).unwrap().unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0x42); + } + + #[test] + fn test_symbolic_memory_store_load_32bit_little_endian() { + let mut mem = SymbolicMemory::new(Endian::Little); + let val = il::expr_const(0xDEADBEEF, 32); + mem.store(0x1000, val).unwrap(); + let loaded = mem.load(0x1000, 32).unwrap().unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0xDEADBEEF); + } + + #[test] + fn test_symbolic_memory_store_load_32bit_big_endian() { + let mut mem = SymbolicMemory::new(Endian::Big); + let val = il::expr_const(0xDEADBEEF, 32); + mem.store(0x1000, val).unwrap(); + let loaded = mem.load(0x1000, 32).unwrap().unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0xDEADBEEF); + } + + #[test] + fn test_symbolic_memory_load_uninitialized() { + let mem = SymbolicMemory::new(Endian::Little); + let loaded = mem.load(0x2000, 8).unwrap(); + assert!(loaded.is_none()); + } + + // --- Simplify edge-case tests --- + + #[test] + fn test_simplify_and_bitmask_eliminates_zext() { + // and(0xFFFFFF00:32, or(zext(32, x:8), zext(32, y:8))) → 0:32 + // Because 0xFFFFFF00 has 8 trailing zeros, and both zext operands have <=8 bits + // eliminate_lower_bits only applies to Or expressions + let x = il::expr_scalar("x", 8); + let y = il::expr_scalar("y", 8); + let zext_x = il::Expression::zext(32, x).unwrap(); + let zext_y = il::Expression::zext(32, y).unwrap(); + let or_expr = il::Expression::or(zext_x, zext_y).unwrap(); + let mask = il::expr_const(0xFFFFFF00, 32); + let expr = il::Expression::and(mask, or_expr).unwrap(); + let result = simplify(&expr).unwrap(); + // Both zext operands eliminated to 0, result is or(0,0) which evaluates to 0 + assert!(result.all_constants()); + assert_eq!(eval(&result).unwrap().value_u64().unwrap(), 0); + } + + #[test] + fn test_simplify_and_bitmask_preserves_wider_zext() { + // and(0xFFFFFF00:32, zext(32, x:16)) → NOT eliminated (16 > 8 trailing zeros) + let x = il::expr_scalar("x", 16); + let zext = il::Expression::zext(32, x.clone()).unwrap(); + let mask = il::expr_const(0xFFFFFF00, 32); + let expr = il::Expression::and(mask, zext).unwrap(); + let result = simplify(&expr).unwrap(); + // Should not be simplified to zero since 16-bit value extends beyond 8 trailing zeros + assert_ne!(result, il::expr_const(0, 32)); + } + + #[test] + fn test_simplify_trun_eliminates_upper_or_bits() { + // trun(8, or(0xFFFFFF00:32, x:32)) → trun(8, x:32) + let x = il::expr_scalar("x", 32); + let mask = il::expr_const(0xFFFFFF00, 32); + let or_expr = il::Expression::or(mask, x.clone()).unwrap(); + let trun = il::Expression::trun(8, or_expr).unwrap(); + let result = simplify(&trun).unwrap(); + let expected = il::Expression::trun(8, x).unwrap(); + assert_eq!(result, expected); + } + + #[test] + fn test_simplify_trun_zext_different_bits_no_collapse() { + // trun(16, zext(32, x:8)) → doesn't collapse to x (inner 8 != trun 16) + let x = il::expr_scalar("x", 8); + let zext = il::Expression::zext(32, x.clone()).unwrap(); + let trun = il::Expression::trun(16, zext).unwrap(); + let result = simplify(&trun).unwrap(); + // Should NOT collapse to just x since 8 != 16 + assert_ne!(result, x); + } + + #[test] + fn test_simplify_or_zero_right() { + // or(x:32, 0:32) → x:32 + let x = il::expr_scalar("x", 32); + let zero = il::expr_const(0, 32); + let expr = il::Expression::or(x.clone(), zero).unwrap(); + let result = simplify(&expr).unwrap(); + assert_eq!(result, x); + } + + #[test] + fn test_simplify_idempotent() { + // simplify(simplify(expr)) == simplify(expr) + let x = il::expr_scalar("x", 32); + let inner = il::Expression::add(x.clone(), il::expr_const(0, 32)).unwrap(); + let outer = il::Expression::or(inner, il::expr_const(0, 32)).unwrap(); + let once = simplify(&outer).unwrap(); + let twice = simplify(&once).unwrap(); + assert_eq!(once, twice); + } + + // --- State edge-case tests --- + + fn make_state(endian: Endian) -> State { + State::new(Memory::new(endian), Box::new(crate::platform::Dummy::new())) + } + + #[test] + fn test_state_scalar_not_set_returns_none() { + let state = make_state(Endian::Little); + assert!(state.scalar("nonexistent").is_none()); + } + + #[test] + fn test_symbolize_replaces_nested_scalars() { + let mut state = make_state(Endian::Little); + state.set_scalar("y", &il::expr_const(10, 32)).unwrap(); + let y_scalar = il::expr_scalar("y", 32); + let expr = il::Expression::add(y_scalar, il::expr_const(1, 32)).unwrap(); + state.set_scalar("x", &expr).unwrap(); + + // symbolize_expression does one level of substitution, then we need + // to symbolize again to resolve nested scalars + let first = state + .symbolize_expression(&il::expr_scalar("x", 32)) + .unwrap(); + let second = state.symbolize_expression(&first).unwrap(); + assert!(second.all_constants()); + assert_eq!(eval(&second).unwrap().value_u64().unwrap(), 11); + } + + #[test] + fn test_eval_constant_fast_path() { + let state = make_state(Endian::Little); + let expr = il::Expression::add(il::expr_const(3, 32), il::expr_const(4, 32)).unwrap(); + let result = state.eval(&expr).unwrap().unwrap(); + assert_eq!(result.value_u64().unwrap(), 7); + } + + #[test] + fn test_eval_unsatisfiable_returns_none() { + let mut state = make_state(Endian::Little); + let x = il::expr_scalar("x", 32); + // x == 5 + state + .add_path_constraint(&il::Expression::cmpeq(x.clone(), il::expr_const(5, 32)).unwrap()) + .unwrap(); + // x == 10 (contradicts) + state + .add_path_constraint(&il::Expression::cmpeq(x.clone(), il::expr_const(10, 32)).unwrap()) + .unwrap(); + let result = state.eval(&x).unwrap(); + assert!(result.is_none()); + } + + #[test] + fn test_eval_and_concretize_adds_constraint() { + let mut state = make_state(Endian::Little); + let x = il::expr_scalar("x", 32); + state.set_scalar("x", &x).unwrap(); + + let constraints_before = state.path_constraints().len(); + let _result = state + .eval_and_concretize(&il::expr_scalar("x", 32)) + .unwrap(); + let constraints_after = state.path_constraints().len(); + // Should have added a cmpeq constraint since x is symbolic + assert!(constraints_after > constraints_before); + } + + #[test] + fn test_eval_and_concretize_constant_skips_constraint() { + let mut state = make_state(Endian::Little); + state.set_scalar("x", &il::expr_const(42, 32)).unwrap(); + + let constraints_before = state.path_constraints().len(); + let result = state + .eval_and_concretize(&il::expr_scalar("x", 32)) + .unwrap() + .unwrap(); + let constraints_after = state.path_constraints().len(); + + assert_eq!(result.value_u64().unwrap(), 42); + // Should NOT add constraint for a constant + assert_eq!(constraints_before, constraints_after); + } + + #[test] + fn test_symbolize_and_assert_satisfiable() { + let state = make_state(Endian::Little); + let x = il::expr_scalar("x", 32); + let constraint = il::Expression::cmpeq(x, il::expr_const(5, 32)).unwrap(); + assert!(state.symbolize_and_assert(&constraint).unwrap()); + } + + #[test] + fn test_symbolize_and_assert_unsatisfiable() { + let mut state = make_state(Endian::Little); + let x = il::expr_scalar("x", 32); + state + .add_path_constraint(&il::Expression::cmpeq(x.clone(), il::expr_const(5, 32)).unwrap()) + .unwrap(); + // Assert x == 10, but x is constrained to 5 + let constraint = il::Expression::cmpeq(x, il::expr_const(10, 32)).unwrap(); + assert!(!state.symbolize_and_assert(&constraint).unwrap()); + } + + #[test] + fn test_symbolize_and_assert_constant_true() { + let state = make_state(Endian::Little); + // cmpeq(5, 5) → all constants → evaluates to true + let constraint = + il::Expression::cmpeq(il::expr_const(5, 32), il::expr_const(5, 32)).unwrap(); + assert!(state.symbolize_and_assert(&constraint).unwrap()); + } + + #[test] + fn test_symbolize_and_assert_constant_false() { + let state = make_state(Endian::Little); + let constraint = + il::Expression::cmpeq(il::expr_const(5, 32), il::expr_const(6, 32)).unwrap(); + assert!(!state.symbolize_and_assert(&constraint).unwrap()); + } + + #[test] + fn test_execute_assign() { + let state = make_state(Endian::Little); + let op = il::Operation::assign(il::scalar("x", 32), il::expr_const(42, 32)); + let successors = state.execute(&op).unwrap(); + assert_eq!(successors.len(), 1); + let succ_state = successors[0].state(); + assert_eq!( + eval(&succ_state.scalar("x").unwrap()) + .unwrap() + .value_u64() + .unwrap(), + 42 + ); + assert!(matches!(successors[0].type_(), SuccessorType::FallThrough)); + } + + #[test] + fn test_execute_store_concrete() { + let mut state = make_state(Endian::Little); + state + .set_scalar("addr", &il::expr_const(0x1000, 32)) + .unwrap(); + state + .memory_mut() + .set_permissions(0x0, PAGE_SIZE, Some(MemoryPermissions::ALL)) + .unwrap(); + + let op = il::Operation::store(il::expr_const(0x1000, 32), il::expr_const(0xBEEF, 16)); + let successors = state.execute(&op).unwrap(); + assert_eq!(successors.len(), 1); + let loaded = successors[0] + .state() + .memory() + .load(0x1000, 16) + .unwrap() + .unwrap(); + assert_eq!(eval(&loaded).unwrap().value_u64().unwrap(), 0xBEEF); + } + + #[test] + fn test_execute_load_uninitialized_empty_successors() { + let state = make_state(Endian::Little); + // Load from uninitialized address → empty successors + let op = il::Operation::load(il::scalar("dst", 32), il::expr_const(0x9999, 32)); + let successors = state.execute(&op).unwrap(); + assert!(successors.is_empty()); + } + + #[test] + fn test_execute_load_undefined_scalar_in_index() { + let state = make_state(Endian::Little); + // Index references undefined scalar "addr" → empty Vec (early guard) + let op = il::Operation::load(il::scalar("dst", 32), il::expr_scalar("addr", 32)); + let successors = state.execute(&op).unwrap(); + assert!(successors.is_empty()); + } + + #[test] + fn test_execute_branch() { + let state = make_state(Endian::Little); + let op = il::Operation::branch(il::expr_const(0xDEAD, 32)); + let successors = state.execute(&op).unwrap(); + assert_eq!(successors.len(), 1); + assert!(matches!( + successors[0].type_(), + SuccessorType::Branch(0xDEAD) + )); + } + + #[test] + fn test_execute_nop() { + let state = make_state(Endian::Little); + let op = il::Operation::nop(); + let successors = state.execute(&op).unwrap(); + assert_eq!(successors.len(), 1); + assert!(matches!(successors[0].type_(), SuccessorType::FallThrough)); + } + + #[test] + fn test_execute_intrinsic_dummy_errors() { + let state = make_state(Endian::Little); + let intrinsic = il::Intrinsic::new( + "test_intrinsic", + "test_intrinsic", + Vec::new(), + None, + None, + Vec::new(), + ); + let op = il::Operation::Intrinsic { + intrinsic: intrinsic.clone(), + }; + let result = state.execute(&op); + assert!(result.is_err()); + } + + #[test] + fn test_make_symbolic_buffer() { + let mut state = make_state(Endian::Little); + let (addr, exprs) = state.make_symbolic_buffer("buf", 4).unwrap(); + assert_eq!(addr, 0x8000_0000); + assert_eq!(exprs.len(), 4); + // Each expression should be a scalar + for (i, expr) in exprs.iter().enumerate() { + if let il::Expression::Scalar(s) = expr { + assert_eq!(s.name(), &format!("buf_{}", i)); + assert_eq!(s.bits(), 8); + } else { + panic!("Expected scalar expression"); + } + } + // Next buffer should start at 0x8000_0004 + let (addr2, _) = state.make_symbolic_buffer("buf2", 2).unwrap(); + assert_eq!(addr2, 0x8000_0004); + } + + #[test] + fn test_make_symbolic_string_null_terminated() { + let mut state = make_state(Endian::Little); + let addr = state.make_symbolic_string("str", 4).unwrap(); + assert_eq!(addr, 0x8000_0000); + // 3 symbolic bytes + 1 null terminator + // Check null terminator at offset 3 + let null_byte = state.memory().load(addr + 3, 8).unwrap().unwrap(); + assert_eq!(eval(&null_byte).unwrap().value_u64().unwrap(), 0); + // First 3 bytes should be symbolic (scalars) + for i in 0..3u64 { + let byte = state.memory().load(addr + i, 8).unwrap().unwrap(); + assert!(!byte.all_constants()); + } + } + + #[test] + fn test_get_string_reads_null_terminated() { + let mut state = make_state(Endian::Little); + // Store "Hi\0" + state + .memory_mut() + .store(0x1000, &il::expr_const(b'H' as u64, 8)) + .unwrap(); + state + .memory_mut() + .store(0x1001, &il::expr_const(b'i' as u64, 8)) + .unwrap(); + state + .memory_mut() + .store(0x1002, &il::expr_const(0, 8)) + .unwrap(); + let s = state.get_string(0x1000).unwrap().unwrap(); + assert_eq!(s, "Hi"); + } + + #[test] + fn test_get_string_uninitialized_returns_none() { + let state = make_state(Endian::Little); + let result = state.get_string(0x5000).unwrap(); + assert!(result.is_none()); + } + + #[test] + fn test_merge_differing_scalars_ite() { + let mut state_a = make_state(Endian::Little); + state_a.set_scalar("x", &il::expr_const(1, 32)).unwrap(); + + let mut state_b = make_state(Endian::Little); + let cond = il::expr_scalar("cond", 1); + state_b + .add_path_constraint(&il::Expression::cmpeq(cond, il::expr_const(1, 1)).unwrap()) + .unwrap(); + state_b.set_scalar("x", &il::expr_const(2, 32)).unwrap(); + + let merged = state_a.merge(&state_b).unwrap(); + let x = merged.scalar("x").unwrap(); + // Should be an ITE, not a plain constant + assert!(!x.all_constants()); + } + + #[test] + fn test_merge_same_scalars_unchanged() { + let mut state_a = make_state(Endian::Little); + state_a.set_scalar("x", &il::expr_const(5, 32)).unwrap(); + + let mut state_b = make_state(Endian::Little); + state_b.set_scalar("x", &il::expr_const(5, 32)).unwrap(); + + let merged = state_a.merge(&state_b).unwrap(); + let x = merged.scalar("x").unwrap(); + assert_eq!(eval(&x).unwrap().value_u64().unwrap(), 5); + } + + #[test] + fn test_merge_other_has_extra_scalar() { + let state_a = make_state(Endian::Little); + + let mut state_b = make_state(Endian::Little); + state_b.set_scalar("y", &il::expr_const(10, 32)).unwrap(); + + let merged = state_a.merge(&state_b).unwrap(); + let y = merged.scalar("y").unwrap(); + // y should be ite(constraint, 10, 0) — not all constants since constraint is const(1,1) + // Actually with empty path constraints, constraint = const(1,1), so ite(1, 10, 0) = 10 + assert_eq!(eval(&y).unwrap().value_u64().unwrap(), 10); + } + + #[test] + fn test_ecv_creates_constraint_and_increments() { + let mut state = make_state(Endian::Little); + let expr = il::Expression::add(il::expr_scalar("a", 32), il::expr_const(1, 32)).unwrap(); + + let constraints_before = state.path_constraints().len(); + let ecv0 = state.expression_complexity_variable(expr).unwrap(); + let constraints_after = state.path_constraints().len(); + + // Should have added a cmpeq constraint + assert_eq!(constraints_after, constraints_before + 1); + // Should be ecv_0 + if let il::Expression::Scalar(s) = &ecv0 { + assert_eq!(s.name(), "ecv_0"); + } else { + panic!("Expected scalar"); + } + + // Next call increments to ecv_1 + let expr2 = il::Expression::add(il::expr_scalar("b", 32), il::expr_const(2, 32)).unwrap(); + let ecv1 = state.expression_complexity_variable(expr2).unwrap(); + if let il::Expression::Scalar(s) = &ecv1 { + assert_eq!(s.name(), "ecv_1"); + } else { + panic!("Expected scalar"); + } + } +} diff --git a/lib/executor/state.rs b/lib/executor/state.rs index 50509ec..aed693e 100644 --- a/lib/executor/state.rs +++ b/lib/executor/state.rs @@ -146,8 +146,8 @@ impl State { /// Get the names of the scalars in this `State`. pub fn scalars(&self) -> Vec { self.scalars - .iter() - .map(|(name, _)| name.to_string()) + .keys() + .map(|name| name.to_string()) .collect::>() } @@ -287,6 +287,10 @@ impl State { self.symbolize_expression(lhs)?, self.symbolize_expression(rhs)?, )?, + il::Expression::AShr(ref lhs, ref rhs) => il::Expression::ashr( + self.symbolize_expression(lhs)?, + self.symbolize_expression(rhs)?, + )?, il::Expression::Cmpeq(ref lhs, ref rhs) => il::Expression::cmpeq( self.symbolize_expression(lhs)?, self.symbolize_expression(rhs)?, @@ -523,8 +527,8 @@ impl State { // merge all scalars for (name, scalar) in other .scalars - .iter() - .map(|(name, _)| (name, other.scalar(name).unwrap())) + .keys() + .map(|name| (name, other.scalar(name).unwrap())) { let e = if let Some(self_scalar) = self.scalar(name) { if !self_scalar.all_constants() || self_scalar != scalar { @@ -597,24 +601,13 @@ impl State { /// /// This is a null-terminated symbolic buffer. pub fn make_symbolic_string(&mut self, name: &str, length: usize) -> Result { - let (address, expressions) = self.make_symbolic_buffer(name, length - 1)?; + let (address, _) = self.make_symbolic_buffer(name, length - 1)?; let null_byte_address = self.next_symbolic_memory_address(); self.memory .store(null_byte_address, &il::expr_const(0, 8))?; - let mut expression_hashes = Vec::new(); - - for expression in expressions { - expression_hashes.push( - HASH_EXPRESSION_STORE - .write() - .unwrap() - .get_hash(&expression)?, - ); - } - - let symbolic_string = SymbolicString::new(expression_hashes); + let symbolic_string = SymbolicString::new(); self.symbolic_strings .insert(name.to_string(), symbolic_string); diff --git a/lib/executor/symbolic_string.rs b/lib/executor/symbolic_string.rs index 338f0f9..bb7e589 100644 --- a/lib/executor/symbolic_string.rs +++ b/lib/executor/symbolic_string.rs @@ -1,14 +1,10 @@ //! A convenience struct for maintaining state of symbolic strings. -use crate::executor::*; - #[derive(Clone, Debug)] -pub struct SymbolicString { - bytes: Vec, -} +pub struct SymbolicString {} impl SymbolicString { - pub fn new(bytes: Vec) -> SymbolicString { - SymbolicString { bytes } + pub fn new() -> SymbolicString { + SymbolicString {} } } diff --git a/lib/lib.rs b/lib/lib.rs index 2dc6240..559a5a8 100644 --- a/lib/lib.rs +++ b/lib/lib.rs @@ -3,14 +3,10 @@ extern crate error_chain; #[macro_use] extern crate serde_derive; -// extern crate unicorn; - pub mod executor; pub mod platform; -// pub mod unicorn_verify_amd64; -// pub mod unicorn_verify_mips; -// pub mod unicorn_verify_x86; +#[allow(unexpected_cfgs)] pub mod error { error_chain! { types { @@ -18,7 +14,7 @@ pub mod error { } foreign_links { - Falcon(::falcon::error::Error); + Falcon(::falcon::Error); FalconZ3(::falcon_z3::error::Error); FromUtf8Error(::std::string::FromUtf8Error); IoError(::std::io::Error); diff --git a/lib/platform/linux/amd64.rs b/lib/platform/linux/amd64.rs index c119c18..783fe77 100644 --- a/lib/platform/linux/amd64.rs +++ b/lib/platform/linux/amd64.rs @@ -136,7 +136,7 @@ impl Amd64 { )) .environment_variable(EnvironmentString::new_concrete("LOCALDOMAIN=localdomain")); - environment.initialize_process64(&mut state.memory_mut(), STACK_BASE, elf_linker)?; + environment.initialize_process64(state.memory_mut(), STACK_BASE, elf_linker)?; for i in 0..0x8000 { state @@ -420,7 +420,7 @@ impl Amd64 { .linux .lseek(fd, offset as isize, origin)?; - state.set_scalar("rax", &il::expr_const(result as u64, 64))?; + state.set_scalar("rax", &il::expr_const(result, 64))?; trace!( "lseek 0x{:x} 0x{:x} 0x{:x} is {}", fd, @@ -442,7 +442,7 @@ impl Amd64 { .linux .mmap(&mut state.memory, addr, len, prot, flags, fd, off)?; - state.set_scalar("rax", &il::expr_const(address as u64, 64))?; + state.set_scalar("rax", &il::expr_const(address, 64))?; trace!( "mmap(0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x}, 0x{:x} = 0x{:x}", @@ -466,7 +466,7 @@ impl Amd64 { .linux .mprotect(&mut state.memory, addr, len, prot)?; - state.set_scalar("rax", &il::expr_const(result as u64, 64))?; + state.set_scalar("rax", &il::expr_const(result, 64))?; trace!( "mprotect(0x{:x}, 0x{:x}, 0x{:x}) = 0x{:x}", @@ -629,9 +629,8 @@ impl Amd64 { } // We need to read all the bytes we are writing - let bytes: ::std::result::Result, Error> = (0..len) - .into_iter() - .try_fold(Vec::new(), |mut bytes, offset| { + let bytes: ::std::result::Result, Error> = + (0..len).try_fold(Vec::new(), |mut bytes, offset| { fn get(state: &State, address: u64) -> Result { state.memory().load(address, 8)?.ok_or_else(|| { format!("Value for write was None address=0x{:08x}", address).into() diff --git a/lib/platform/linux/environment.rs b/lib/platform/linux/environment.rs index 8bdae16..14116b5 100644 --- a/lib/platform/linux/environment.rs +++ b/lib/platform/linux/environment.rs @@ -81,7 +81,7 @@ impl Environment { /// will configure the process in the passed memory, which should be blank. pub fn initialize_process32( &self, - mut memory: &mut Memory, + memory: &mut Memory, stack_address: u64, elf_linker: &ElfLinker, ) -> Result<()> { @@ -154,7 +154,7 @@ impl Environment { // push argc push( - &mut memory, + memory, &mut stack_address, &il::expr_const(self.command_line_arguments.len() as u64, 32), )?; @@ -162,34 +162,34 @@ impl Environment { // push argv for command_line_argument in &self.command_line_arguments { push( - &mut memory, + memory, &mut stack_address, &il::expr_const(strings_address, 32), )?; - set_string(&mut memory, &mut strings_address, command_line_argument)?; + set_string(memory, &mut strings_address, command_line_argument)?; } // null word separates argv from environment variables - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; // push a null word if there are no environment variables if self.environment_variables.is_empty() { - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; } // otherwise push environment variables else { for environment_variable in &self.environment_variables { push( - &mut memory, + memory, &mut stack_address, &il::expr_const(strings_address, 32), )?; - set_string(&mut memory, &mut strings_address, environment_variable)?; + set_string(memory, &mut strings_address, environment_variable)?; } } // null word terminates environment variables - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; // We need some information from the Elf for the Elf Auxiliary Table // entries @@ -223,9 +223,9 @@ impl Environment { let ehdr = elf.elf().header; // 0xbff00028 AT_PHDR (0x3) is beginning of PHDR for this binary - push(&mut memory, &mut stack_address, &il::expr_const(3, 32))?; + push(memory, &mut stack_address, &il::expr_const(3, 32))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(phdr_address, 32), )?; @@ -233,9 +233,9 @@ impl Environment { // state.memory_mut().store(0xbff0002c, &il::expr_const(phdr_address, 32))?; // 0xbff00030 AT_PHENT (0x4) - push(&mut memory, &mut stack_address, &il::expr_const(4, 32))?; + push(memory, &mut stack_address, &il::expr_const(4, 32))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(ehdr.e_phentsize as u64, 32), )?; @@ -243,9 +243,9 @@ impl Environment { // state.memory_mut().store(0xbff00034, &il::expr_const(ehdr.e_phentsize as u64, 32))?; // 0xbff00038 AT_PHNUM (0x5) - push(&mut memory, &mut stack_address, &il::expr_const(5, 32))?; + push(memory, &mut stack_address, &il::expr_const(5, 32))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(ehdr.e_phnum as u64, 32), )?; @@ -253,8 +253,8 @@ impl Environment { // state.memory_mut().store(0xbff0003c, &il::expr_const(ehdr.e_phnum as u64, 32))?; // 0xbff00040 AT_PAGESZ (0x6) - push(&mut memory, &mut stack_address, &il::expr_const(6, 32))?; - push(&mut memory, &mut stack_address, &il::expr_const(0x1000, 32))?; + push(memory, &mut stack_address, &il::expr_const(6, 32))?; + push(memory, &mut stack_address, &il::expr_const(0x1000, 32))?; // state.memory_mut().store(0xbff00040, &il::expr_const(6, 32))?; // state.memory_mut().store(0xbff00044, &il::expr_const(0x1000, 32))?; @@ -265,25 +265,25 @@ impl Environment { .unwrap_or(0); // 0xbff00048 AT_BASE (0x7) - push(&mut memory, &mut stack_address, &il::expr_const(7, 32))?; + push(memory, &mut stack_address, &il::expr_const(7, 32))?; push( - &mut memory, + memory, &mut stack_address, - &il::expr_const(interpreter_base_address as u64, 32), + &il::expr_const(interpreter_base_address, 32), )?; // state.memory_mut().store(0xbff00048, &il::expr_const(7, 32))?; // state.memory_mut().store(0xbff0004c, &il::expr_const(interpreter_base_address, 32))?; // 0xbff00050 AT_BASE (0x8) - push(&mut memory, &mut stack_address, &il::expr_const(8, 32))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(8, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; // state.memory_mut().store(0xbff00050, &il::expr_const(8, 32))?; // state.memory_mut().store(0xbff00054, &il::expr_const(0, 32))?; // 0xbff00058 AT_ENTRY (0x9) - push(&mut memory, &mut stack_address, &il::expr_const(9, 32))?; + push(memory, &mut stack_address, &il::expr_const(9, 32))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(elf.program_entry(), 32), )?; @@ -291,8 +291,8 @@ impl Environment { // state.memory_mut().store(0xbff0005c, &il::expr_const(elf.program_entry(), 32))?; // 0xbff00060 AT_NULL (0x0) - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; + push(memory, &mut stack_address, &il::expr_const(0, 32))?; // state.memory_mut().store(0xbff00060, &il::expr_const(0, 32))?; // state.memory_mut().store(0xbff00064, &il::expr_const(0, 32))?; @@ -305,7 +305,7 @@ impl Environment { /// will configure the process in the passed memory, which should be blank. pub fn initialize_process64( &self, - mut memory: &mut Memory, + memory: &mut Memory, stack_address: u64, elf_linker: &ElfLinker, ) -> Result<()> { @@ -383,7 +383,7 @@ impl Environment { // push argc push( - &mut memory, + memory, &mut stack_address, &il::expr_const(self.command_line_arguments.len() as u64, 64), )?; @@ -391,34 +391,34 @@ impl Environment { // push argv for command_line_argument in &self.command_line_arguments { push( - &mut memory, + memory, &mut stack_address, &il::expr_const(strings_address, 64), )?; - set_string(&mut memory, &mut strings_address, command_line_argument)?; + set_string(memory, &mut strings_address, command_line_argument)?; } // null word separates argv from environment variables - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; // push a null word if there are no environment variables if self.environment_variables.is_empty() { - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; } // otherwise push environment variables else { for environment_variable in &self.environment_variables { push( - &mut memory, + memory, &mut stack_address, &il::expr_const(strings_address, 64), )?; - set_string(&mut memory, &mut strings_address, environment_variable)?; + set_string(memory, &mut strings_address, environment_variable)?; } } // null word terminates environment variables - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; // We need some information from the Elf for the Elf Auxiliary Table // entries @@ -452,9 +452,9 @@ impl Environment { let ehdr = elf.elf().header; // 0xbff00028 AT_PHDR (0x3) is beginning of PHDR for this binary - push(&mut memory, &mut stack_address, &il::expr_const(3, 64))?; + push(memory, &mut stack_address, &il::expr_const(3, 64))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(phdr_address, 64), )?; @@ -462,9 +462,9 @@ impl Environment { // state.memory_mut().store(0xbff0002c, &il::expr_const(phdr_address, 32))?; // 0xbff00030 AT_PHENT (0x4) - push(&mut memory, &mut stack_address, &il::expr_const(4, 64))?; + push(memory, &mut stack_address, &il::expr_const(4, 64))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(ehdr.e_phentsize as u64, 64), )?; @@ -472,9 +472,9 @@ impl Environment { // state.memory_mut().store(0xbff00034, &il::expr_const(ehdr.e_phentsize as u64, 32))?; // 0xbff00038 AT_PHNUM (0x5) - push(&mut memory, &mut stack_address, &il::expr_const(5, 64))?; + push(memory, &mut stack_address, &il::expr_const(5, 64))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(ehdr.e_phnum as u64, 64), )?; @@ -482,8 +482,8 @@ impl Environment { // state.memory_mut().store(0xbff0003c, &il::expr_const(ehdr.e_phnum as u64, 32))?; // 0xbff00040 AT_PAGESZ (0x6) - push(&mut memory, &mut stack_address, &il::expr_const(6, 64))?; - push(&mut memory, &mut stack_address, &il::expr_const(0x1000, 64))?; + push(memory, &mut stack_address, &il::expr_const(6, 64))?; + push(memory, &mut stack_address, &il::expr_const(0x1000, 64))?; // state.memory_mut().store(0xbff00040, &il::expr_const(6, 32))?; // state.memory_mut().store(0xbff00044, &il::expr_const(0x1000, 32))?; @@ -494,25 +494,25 @@ impl Environment { .unwrap_or(0); // 0xbff00048 AT_BASE (0x7) - push(&mut memory, &mut stack_address, &il::expr_const(7, 64))?; + push(memory, &mut stack_address, &il::expr_const(7, 64))?; push( - &mut memory, + memory, &mut stack_address, - &il::expr_const(interpreter_base_address as u64, 64), + &il::expr_const(interpreter_base_address, 64), )?; // state.memory_mut().store(0xbff00048, &il::expr_const(7, 32))?; // state.memory_mut().store(0xbff0004c, &il::expr_const(interpreter_base_address, 32))?; // 0xbff00050 AT_BASE (0x8) - push(&mut memory, &mut stack_address, &il::expr_const(8, 64))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(8, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; // state.memory_mut().store(0xbff00050, &il::expr_const(8, 32))?; // state.memory_mut().store(0xbff00054, &il::expr_const(0, 32))?; // 0xbff00058 AT_ENTRY (0x9) - push(&mut memory, &mut stack_address, &il::expr_const(9, 64))?; + push(memory, &mut stack_address, &il::expr_const(9, 64))?; push( - &mut memory, + memory, &mut stack_address, &il::expr_const(elf.program_entry(), 64), )?; @@ -520,10 +520,10 @@ impl Environment { // state.memory_mut().store(0xbff0005c, &il::expr_const(elf.program_entry(), 32))?; // 0xbff00060 AT_NULL (0x0) - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; - push(&mut memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; + push(memory, &mut stack_address, &il::expr_const(0, 64))?; // state.memory_mut().store(0xbff00060, &il::expr_const(0, 32))?; // state.memory_mut().store(0xbff00064, &il::expr_const(0, 32))?; diff --git a/lib/platform/linux/filesystem.rs b/lib/platform/linux/filesystem.rs index 3341bc1..c608464 100644 --- a/lib/platform/linux/filesystem.rs +++ b/lib/platform/linux/filesystem.rs @@ -124,18 +124,18 @@ impl FileSystem { /// Returns true if the file descriptor exists. pub fn fd_valid(&self, fd: usize) -> bool { - self.file_descriptors.get(&fd).is_some() + self.file_descriptors.contains_key(&fd) } /// Attempt to open a file and read it into the filesystem model. Returns /// a file descriptor if the file exists, or None. pub fn open(&mut self, path: &str) -> Result> { - if self.files.get(path).is_some() { + if self.files.contains_key(path) { return Ok(Some(self.add_file_descriptor(path))); } if self.get_path(path).exists() { - let mut file = File::open(&self.get_path(path))?; + let mut file = File::open(self.get_path(path))?; let mut buf = Vec::new(); file.read_to_end(&mut buf)?; @@ -164,7 +164,7 @@ impl FileSystem { /// Return true if a file exists, false otherwise pub fn exists(&self, path: &str) -> bool { - self.files.get(path).is_some() || PathBuf::from(path.to_string()).exists() + self.files.contains_key(path) || PathBuf::from(path.to_string()).exists() } /// Zeroize the data in a file @@ -179,7 +179,7 @@ impl FileSystem { /// Get a mutable reference to the data for a file pub fn file_bytes_mut(&mut self, path: &str) -> Option<&mut Vec> { - self.files.get_mut(path).map(|v| RC::make_mut(v)) + self.files.get_mut(path).map(RC::make_mut) } /// Get the bytes to a file pointed to by a file descriptor @@ -194,7 +194,7 @@ impl FileSystem { /// otherwise pub fn close_fd(&mut self, fd: usize) -> bool { if self.file_descriptors.remove(&fd).is_some() { - while self.file_descriptors.get(&(self.next_fd - 1)).is_none() { + while !self.file_descriptors.contains_key(&(self.next_fd - 1)) { if self.next_fd == 0 { break; } @@ -290,25 +290,283 @@ impl FileSystem { } } -#[test] -fn test() { - use std::fs::File; - use std::io::Write; +#[cfg(test)] +mod tests { + use super::*; - let mut file = File::create("/tmp/test.finch.filesystem").unwrap(); - file.write_all("AAAABBBBCCCCDDDD".as_bytes()).unwrap(); + #[test] + fn test_existing_filesystem_open_read() { + use std::fs::File; + use std::io::Write; - let mut filesystem = FileSystem::new(Some("/tmp".into())).unwrap(); - let fd = filesystem.open("/test.finch.filesystem").unwrap().unwrap(); + let mut file = File::create("/tmp/test.finch.filesystem").unwrap(); + file.write_all("AAAABBBBCCCCDDDD".as_bytes()).unwrap(); - let bytes = filesystem.read_fd(fd, 16).unwrap().unwrap(); + let mut filesystem = FileSystem::new(Some("/tmp".into())).unwrap(); + let fd = filesystem.open("/test.finch.filesystem").unwrap().unwrap(); - assert_eq!(bytes[1], il::expr_const(0x41, 8)); - assert_eq!(bytes[5], il::expr_const(0x42, 8)); - assert_eq!(bytes[10], il::expr_const(0x43, 8)); - assert_eq!(bytes[12], il::expr_const(0x44, 8)); + let bytes = filesystem.read_fd(fd, 16).unwrap().unwrap(); - assert_eq!(bytes.len(), 16); + assert_eq!(bytes[1], il::expr_const(0x41, 8)); + assert_eq!(bytes[5], il::expr_const(0x42, 8)); + assert_eq!(bytes[10], il::expr_const(0x43, 8)); + assert_eq!(bytes[12], il::expr_const(0x44, 8)); - assert_eq!(filesystem.size_fd(fd).unwrap(), 16); + assert_eq!(bytes.len(), 16); + + assert_eq!(filesystem.size_fd(fd).unwrap(), 16); + } + + #[test] + fn test_new_creates_stdin_stdout_stderr() { + let fs = FileSystem::new(None).unwrap(); + assert!(fs.fd_valid(0)); // stdin + assert!(fs.fd_valid(1)); // stdout + assert!(fs.fd_valid(2)); // stderr + assert!(!fs.fd_valid(3)); + } + + #[test] + fn test_create_existing_file_gets_new_fd() { + let mut fs = FileSystem::new(None).unwrap(); + let fd1 = fs.create("/testfile").unwrap(); + let fd2 = fs.create("/testfile").unwrap(); + assert_ne!(fd1, fd2); + } + + #[test] + fn test_read_fd_at_eof_returns_empty() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/eof_test").unwrap(); + // Write 2 bytes + fs.write( + "/eof_test", + vec![il::expr_const(0x41, 8), il::expr_const(0x42, 8)], + 0, + ) + .unwrap(); + // Read all bytes + let bytes = fs.read_fd(fd, 10).unwrap().unwrap(); + assert_eq!(bytes.len(), 2); + // Read again — at EOF + let bytes = fs.read_fd(fd, 10).unwrap().unwrap(); + assert!(bytes.is_empty()); + } + + #[test] + fn test_read_fd_short_read() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/short").unwrap(); + fs.write( + "/short", + vec![ + il::expr_const(0x41, 8), + il::expr_const(0x42, 8), + il::expr_const(0x43, 8), + ], + 0, + ) + .unwrap(); + // Request 10, only 3 available + let bytes = fs.read_fd(fd, 10).unwrap().unwrap(); + assert_eq!(bytes.len(), 3); + } + + #[test] + fn test_fd_seek_set() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/seek_test").unwrap(); + fs.write( + "/seek_test", + vec![ + il::expr_const(0x41, 8), + il::expr_const(0x42, 8), + il::expr_const(0x43, 8), + il::expr_const(0x44, 8), + ], + 0, + ) + .unwrap(); + let offset = fs.fd_seek(fd, 2, Whence::Set).unwrap(); + assert_eq!(offset, 2); + let bytes = fs.read_fd(fd, 2).unwrap().unwrap(); + assert_eq!(bytes[0], il::expr_const(0x43, 8)); + assert_eq!(bytes[1], il::expr_const(0x44, 8)); + } + + #[test] + fn test_fd_seek_cursor_forward_and_back() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/cursor_test").unwrap(); + fs.write( + "/cursor_test", + vec![ + il::expr_const(0x41, 8), + il::expr_const(0x42, 8), + il::expr_const(0x43, 8), + il::expr_const(0x44, 8), + il::expr_const(0x45, 8), + ], + 0, + ) + .unwrap(); + // Cursor +3 + let offset = fs.fd_seek(fd, 3, Whence::Cursor).unwrap(); + assert_eq!(offset, 3); + // Cursor -1 + let offset = fs.fd_seek(fd, -1, Whence::Cursor).unwrap(); + assert_eq!(offset, 2); + let bytes = fs.read_fd(fd, 1).unwrap().unwrap(); + assert_eq!(bytes[0], il::expr_const(0x43, 8)); + } + + #[test] + fn test_fd_seek_end() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/end_test").unwrap(); + fs.write( + "/end_test", + vec![ + il::expr_const(0x41, 8), + il::expr_const(0x42, 8), + il::expr_const(0x43, 8), + il::expr_const(0x44, 8), + il::expr_const(0x45, 8), + ], + 0, + ) + .unwrap(); + // Seek to end + let offset = fs.fd_seek(fd, 0, Whence::End).unwrap(); + assert_eq!(offset, 5); + // Seek end - 3 + let offset = fs.fd_seek(fd, -3, Whence::End).unwrap(); + assert_eq!(offset, 2); + } + + #[test] + fn test_write_at_offset_past_eof_fills_zeros() { + let mut fs = FileSystem::new(None).unwrap(); + fs.create("/gap_test").unwrap(); + fs.write( + "/gap_test", + vec![il::expr_const(0x41, 8), il::expr_const(0x42, 8)], + 0, + ) + .unwrap(); + // Write at offset 5 (gap of 3 bytes) + fs.write("/gap_test", vec![il::expr_const(0x99, 8)], 5) + .unwrap(); + let bytes = fs.file_bytes("/gap_test").unwrap(); + assert_eq!(bytes.len(), 6); + // Gap bytes should be zero + assert_eq!(bytes[2], il::expr_const(0, 8)); + assert_eq!(bytes[3], il::expr_const(0, 8)); + assert_eq!(bytes[4], il::expr_const(0, 8)); + assert_eq!(bytes[5], il::expr_const(0x99, 8)); + } + + #[test] + fn test_write_to_nonexistent_creates_file() { + let mut fs = FileSystem::new(None).unwrap(); + fs.write("/new_file", vec![il::expr_const(0x41, 8)], 0) + .unwrap(); + let bytes = fs.file_bytes("/new_file").unwrap(); + assert_eq!(bytes.len(), 1); + assert_eq!(bytes[0], il::expr_const(0x41, 8)); + } + + #[test] + fn test_write_to_nonexistent_with_offset() { + let mut fs = FileSystem::new(None).unwrap(); + fs.write("/offset_new", vec![il::expr_const(0x99, 8)], 3) + .unwrap(); + let bytes = fs.file_bytes("/offset_new").unwrap(); + assert_eq!(bytes.len(), 4); + assert_eq!(bytes[0], il::expr_const(0, 8)); + assert_eq!(bytes[1], il::expr_const(0, 8)); + assert_eq!(bytes[2], il::expr_const(0, 8)); + assert_eq!(bytes[3], il::expr_const(0x99, 8)); + } + + #[test] + fn test_close_fd_reclaims_highest() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/close_test").unwrap(); + assert_eq!(fd, 3); + // next_fd should be 4 + assert!(fs.close_fd(fd)); + // After closing the highest fd, next_fd should go back to 3 + let fd2 = fs.create("/close_test2").unwrap(); + assert_eq!(fd2, 3); + } + + #[test] + fn test_close_fd_gap_no_reclaim() { + let mut fs = FileSystem::new(None).unwrap(); + let _fd3 = fs.create("/a").unwrap(); // fd 3 + let _fd4 = fs.create("/b").unwrap(); // fd 4 + // Close fd 3 (middle), fd 4 still exists + assert!(fs.close_fd(3)); + // next_fd should stay at 5 since fd 4 still exists + let fd_next = fs.create("/c").unwrap(); + assert_eq!(fd_next, 5); + } + + #[test] + fn test_close_fd_invalid_returns_false() { + let mut fs = FileSystem::new(None).unwrap(); + assert!(!fs.close_fd(99)); + } + + #[test] + fn test_fd_valid_after_close() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/valid_test").unwrap(); + assert!(fs.fd_valid(fd)); + fs.close_fd(fd); + assert!(!fs.fd_valid(fd)); + } + + #[test] + fn test_zeroize_empties_file() { + let mut fs = FileSystem::new(None).unwrap(); + fs.create("/zero_test").unwrap(); + fs.write( + "/zero_test", + vec![il::expr_const(0x41, 8), il::expr_const(0x42, 8)], + 0, + ) + .unwrap(); + assert_eq!(fs.file_bytes("/zero_test").unwrap().len(), 2); + fs.zeroize("/zero_test"); + assert!(fs.file_bytes("/zero_test").unwrap().is_empty()); + } + + #[test] + fn test_size_fd_invalid() { + let fs = FileSystem::new(None).unwrap(); + assert!(fs.size_fd(99).is_none()); + } + + #[test] + fn test_write_fd_extends_file() { + let mut fs = FileSystem::new(None).unwrap(); + let fd = fs.create("/extend_test").unwrap(); + fs.write( + "/extend_test", + vec![il::expr_const(0x41, 8), il::expr_const(0x42, 8)], + 0, + ) + .unwrap(); + // Seek to end via Set + fs.fd_seek(fd, 2, Whence::Set).unwrap(); + // Write via fd past end + fs.write_fd(fd, vec![il::expr_const(0x43, 8), il::expr_const(0x44, 8)]) + .unwrap(); + let bytes = fs.file_bytes("/extend_test").unwrap(); + assert_eq!(bytes.len(), 4); + assert_eq!(bytes[2], il::expr_const(0x43, 8)); + assert_eq!(bytes[3], il::expr_const(0x44, 8)); + } } diff --git a/lib/platform/linux/linux_.rs b/lib/platform/linux/linux_.rs index 06b46a4..1130b22 100644 --- a/lib/platform/linux/linux_.rs +++ b/lib/platform/linux/linux_.rs @@ -143,7 +143,10 @@ impl Linux { let address = if address > 0 { if address + length > self.mmap_address { self.mmap_address = address + length; - if self.mmap_address % crate::executor::PAGE_SIZE as u64 > 0 { + if !self + .mmap_address + .is_multiple_of(crate::executor::PAGE_SIZE as u64) + { self.mmap_address += crate::executor::PAGE_SIZE as u64; self.mmap_address &= !(crate::executor::PAGE_SIZE as u64 - 1); } @@ -151,18 +154,19 @@ impl Linux { address } else { let address = self.mmap_address; - let permissions_length = if length as usize % crate::executor::PAGE_SIZE > 0 { - let pl = length as usize + crate::executor::PAGE_SIZE; - pl & (!(crate::executor::PAGE_SIZE - 1)) - } else { - length as usize - }; + let permissions_length = + if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) { + let pl = length as usize + crate::executor::PAGE_SIZE; + pl & (!(crate::executor::PAGE_SIZE - 1)) + } else { + length as usize + }; self.mmap_address += permissions_length as u64; address }; // this straight code-copying, ugly shiz. fix later - let permissions_length = if length as usize % crate::executor::PAGE_SIZE > 0 { + let permissions_length = if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) { let pl = length as usize + crate::executor::PAGE_SIZE; pl & (!(crate::executor::PAGE_SIZE - 1)) } else { @@ -205,7 +209,7 @@ impl Linux { permissions |= MemoryPermissions::EXECUTE; } - let permissions_length = if length as usize % crate::executor::PAGE_SIZE > 0 { + let permissions_length = if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) { let pl = length as usize + crate::executor::PAGE_SIZE; pl & (!(crate::executor::PAGE_SIZE - 1)) } else { diff --git a/lib/platform/linux/mips.rs b/lib/platform/linux/mips.rs index 5b71ab3..db14253 100644 --- a/lib/platform/linux/mips.rs +++ b/lib/platform/linux/mips.rs @@ -135,7 +135,7 @@ impl Mips { 128, )); - environment.initialize_process32(&mut state.memory_mut(), STACK_BASE, elf_linker)?; + environment.initialize_process32(state.memory_mut(), STACK_BASE, elf_linker)?; for i in 0..0x8000 { state @@ -392,7 +392,7 @@ impl Mips { .linux .lseek(a0, (a1 as i32) as isize, a2)?; - state.set_scalar("$v0", &il::expr_const(result as u64, 32))?; + state.set_scalar("$v0", &il::expr_const(result, 32))?; if result as i64 >= 0 { state.set_scalar("$a3", &il::expr_const(0, 32))?; } else { @@ -413,7 +413,7 @@ impl Mips { .linux .mmap(&mut state.memory, a0, a1, a2, a3, stack0, stack1)?; - state.set_scalar("$v0", &il::expr_const(address as u64, 32))?; + state.set_scalar("$v0", &il::expr_const(address, 32))?; state.set_scalar("$a3", &il::expr_const(0, 32))?; trace!( @@ -438,7 +438,7 @@ impl Mips { .linux .mprotect(&mut state.memory, a0, a1, a2)?; - state.set_scalar("$v0", &il::expr_const(result as u64, 32))?; + state.set_scalar("$v0", &il::expr_const(result, 32))?; if result == 0 { state.set_scalar("$a3", &il::expr_const(0, 32))?; @@ -653,9 +653,8 @@ impl Mips { } // We need to read all the bytes we are writing - let bytes: ::std::result::Result, Error> = (0..a2) - .into_iter() - .try_fold(Vec::new(), |mut bytes, offset| { + let bytes: ::std::result::Result, Error> = + (0..a2).try_fold(Vec::new(), |mut bytes, offset| { fn get(state: &State, address: u64) -> Result { state.memory().load(address, 8)?.ok_or_else(|| { format!( diff --git a/lib/unicorn_verify_amd64.rs b/lib/unicorn_verify_amd64.rs deleted file mode 100644 index 2c2f95a..0000000 --- a/lib/unicorn_verify_amd64.rs +++ /dev/null @@ -1,389 +0,0 @@ -//! Verify Finch's execution and semantics against Unicorn. - -use crate::error::*; -use crate::executor::{Driver, State, StateTranslator}; -use falcon::il; -use falcon::translator::TranslationMemory; -use std::collections::HashSet; -use unicorn; -use unicorn::{Cpu, CpuX86}; - -struct RegisterMapping { - register: unicorn::RegisterX86, - name: &'static str, -} - -const REGISTER_MAPPINGS: &[RegisterMapping] = &[ - RegisterMapping { - register: unicorn::RegisterX86::RAX, - name: "rax", - }, - RegisterMapping { - register: unicorn::RegisterX86::RBX, - name: "rbx", - }, - RegisterMapping { - register: unicorn::RegisterX86::RCX, - name: "rcx", - }, - RegisterMapping { - register: unicorn::RegisterX86::RDX, - name: "rdx", - }, - RegisterMapping { - register: unicorn::RegisterX86::RDI, - name: "rdi", - }, - RegisterMapping { - register: unicorn::RegisterX86::RSI, - name: "rsi", - }, - RegisterMapping { - register: unicorn::RegisterX86::R8, - name: "r8", - }, - RegisterMapping { - register: unicorn::RegisterX86::R9, - name: "r9", - }, - RegisterMapping { - register: unicorn::RegisterX86::R10, - name: "r10", - }, - RegisterMapping { - register: unicorn::RegisterX86::R11, - name: "r11", - }, - RegisterMapping { - register: unicorn::RegisterX86::R12, - name: "r12", - }, - RegisterMapping { - register: unicorn::RegisterX86::R13, - name: "r13", - }, - RegisterMapping { - register: unicorn::RegisterX86::R14, - name: "r14", - }, - RegisterMapping { - register: unicorn::RegisterX86::R15, - name: "r15", - }, - RegisterMapping { - register: unicorn::RegisterX86::RBP, - name: "rbp", - }, - RegisterMapping { - register: unicorn::RegisterX86::RSP, - name: "rsp", - }, -]; - -fn make_emu(mut driver: Driver) -> Result<(Driver, CpuX86)> { - // create the emu emulator - let mode = unicorn::Mode::MODE_64 as i32; - let mode = unsafe { ::std::mem::transmute::(mode) }; - let emu = CpuX86::new(mode).expect("Failed to initialize unicorn engine"); - - trace!("Unicorn engine created"); - - // We need to track the pages we map, because we can't map a page twice - let mut mapped_pages: HashSet = HashSet::new(); - - let page_addresses: HashSet = driver - .state() - .memory() - .pages() - .into_iter() - .map(|(address, _)| address) - .collect::>(); - - // set up memory - for address in &page_addresses { - if mapped_pages.contains(address) { - continue; - } - mapped_pages.insert(*address); - - let mut length = crate::executor::PAGE_SIZE as u64; - loop { - if page_addresses.contains(&(address + length)) - && !mapped_pages.contains(&(address + length)) - { - mapped_pages.insert(*address + length); - length += crate::executor::PAGE_SIZE as u64; - } else { - break; - } - } - - emu.mem_map(*address, length as usize, unicorn::Protection::ALL) - .expect(&format!("Failed to map memory 0x{:x}", address)); - } - - // println!("memory pages mapped"); - - if let Some(backing) = driver.state().memory().backing() { - for (address, section) in backing.sections() { - let length = if section.len() % 0x1000 > 0 { - (section.len() + 0x1000) & (!0xfff) - } else { - section.len() - }; - - let mut map_address = *address; - let mut map_length = length; - - if map_address % 0x1000 > 0 { - map_address = map_address & (!0xfff); - map_length += 0x1000; - } - - // Mapping lots of 0x1000 pages is slow, so we're going to first - // try 0x10000 increments, and default back to 0x1000 - let mut i: u64 = 0; - while i < map_length as u64 { - let large_increment = !(0..16) - .into_iter() - .any(|j| mapped_pages.contains(&(map_address + i + (j * 0x1000)))); - - if large_increment { - emu.mem_map(map_address + i, 0x10000, unicorn::Protection::ALL) - .expect("Failed to map memory"); - for j in 0..16 { - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } else { - for j in 0..16 { - if mapped_pages.contains(&(map_address + i + (j * 0x1000))) { - continue; - } - emu.mem_map( - map_address + i + (j * 0x1000), - 0x1000, - unicorn::Protection::ALL, - ) - .expect(&format!( - "Failed to map memory 0x{:x}", - map_address + i + (j * 0x1000) - )); - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } - i = i + 0x10000; - } - - // println!("Write at 0x{:08x}, len=0x{:x}", address, section.data().len()); - emu.mem_write(*address, section.data()) - .expect(&format!("Failed to write memory at 0x{:x}", address)); - } - } - - trace!("memory backing mapped"); - - let state = driver.state().clone(); - let state_translator = StateTranslator::new(state); - - for (address, _) in driver.state().memory().pages() { - for i in 0..crate::executor::PAGE_SIZE { - if let Some(byte) = state_translator.get_u8(address + i as u64) { - emu.mem_write(address + i as u64, &[byte]).expect(&format!( - "Failed to write 0x{:02x} at 0x{:x}", - byte, address - )); - } - } - } - - let mut state: State = state_translator.into(); - - // initialize all our registers - for register_mapping in REGISTER_MAPPINGS { - let value = state.eval_and_concretize(&il::expr_scalar(register_mapping.name, 64))?; - match value { - Some(value) => emu - .reg_write( - register_mapping.register.clone(), - value.value_u64().unwrap(), - ) - .expect("Failed to write register"), - None => emu - .reg_write(register_mapping.register.clone(), 0) - .expect("Failed to write register"), - }; - } - - // including the pc register - emu.reg_write( - unicorn::RegisterX86::RIP, - driver - .instruction() - .expect("Failed to get instruction to start unicorn stepping") - .address() - .expect("Failed to get address of instruction to start unicorn stepping"), - ) - .expect("Failed to write PC register"); - - // driver takes this state - *driver.state_mut() = state; - - trace!("make emu complete"); - - Ok((driver, emu)) -} - -fn panic_step(emu: &mut CpuX86, steps: usize) { - let pc = emu - .reg_read(unicorn::RegisterX86::RIP) - .expect("Failed to get PC register"); - - // println!("panic_step: 0x{:08x}", pc); - - match emu.emu_start(pc, 0, 0, steps) { - Ok(_) => {} - Err(err) => match err { - unicorn::Error::OK => panic!("Qemu Error OK {}", err as i32), - _ => panic!("Qemu error {:?}", err), - }, - } -} - -pub fn step_with_unicorn(driver: Driver, steps: usize) -> Result<()> { - let (mut driver, mut emu) = make_emu(driver)?; - - let debug = false; - - // Dump the initial stack - // for i in 0..(0x200 / 16) { - // let line_address = 0xBFF000000000 + (i * 16); - // println!( - // "0x{:016x}: {} {}", - // line_address, - // crate::executor::simplify(&driver.state().memory().load(line_address, 64)?.unwrap())?, - // crate::executor::simplify( - // &driver.state().memory().load(line_address + 8, 64)?.unwrap() - // )? - // ); - // } - - for step in 0..steps { - panic_step(&mut emu, 1); - - // if driver.address().unwrap_or(0) == 0x4001a6c5 { - // let driver = driver.step()?.pop().unwrap(); - // panic!("{}", driver.state().scalar("temp_0.0").unwrap()); - // } - - let mut step_over = false; - if let Some(instruction) = driver.instruction() { - match instruction.operation() { - il::Operation::Intrinsic { intrinsic } => { - if intrinsic.mnemonic() == "cpuid" - || intrinsic.mnemonic() == "rdtsc" - || intrinsic.mnemonic() == "syscall" - { - step_over = true; - } - } - _ => {} - } - } - - if step_over { - let mut drivers = driver.step()?; - driver = drivers.pop().unwrap(); - let (d, e) = make_emu(driver)?; - driver = d; - emu = e; - continue; - } - - // get the new pc - let pc = emu - .reg_read(unicorn::RegisterX86::RIP) - .expect("Failed to get PC register"); - - if debug { - println!("pc=0x{:08x}, step={}", pc, step); - } - - // step the driver until it hits this address - for _ in 0..256 { - let mut drivers = driver.step()?; - if drivers.len() != 1 { - bail!("Drivers len != 1"); - } - driver = drivers.pop().unwrap(); - - if debug { - println!("{}", driver.location().apply(driver.program())?); - } - - if let Some(instruction) = driver.instruction() { - match instruction.operation() { - il::Operation::Branch { .. } => { - // println!("Branch"); - } - _ => {} - } - } - if driver - .address() - .map(|address| address == pc) - .unwrap_or(false) - { - break; - } - } - - // make sure address matches - if !driver - .address() - .map(|address| address == pc) - .unwrap_or(false) - { - println!( - "unicorn-pc=0x{:08x}, driver-address={:?}, step={}", - pc, - driver.address(), - step - ); - println!("{}", driver.location().apply(driver.program())?); - panic!("Driver address does not match"); - } - - // verify registers - for register_mapping in REGISTER_MAPPINGS { - if let Some(value) = driver - .state() - .scalar(register_mapping.name) - .and_then(|expr| driver.state().symbolize_and_eval(&expr).unwrap()) - { - let unicorn_value = emu - .reg_read(register_mapping.register) - .expect("Failed to read x86 register"); - if debug { - println!( - " {} unicorn=0x{:08x} finch=0x{:08x}", - register_mapping.name, - unicorn_value, - value.value_u64().unwrap() - ); - } - if value.value_u64().unwrap() != unicorn_value { - panic!("Register mismatch, step={}", step); - } - } - } - // println!( - // " ZF={} CF={} SF={} OF={}", - // driver.state().scalar("ZF").unwrap_or(il::expr_const(0, 1)), - // driver.state().scalar("CF").unwrap_or(il::expr_const(0, 1)), - // driver.state().scalar("SF").unwrap_or(il::expr_const(0, 1)), - // driver.state().scalar("OF").unwrap_or(il::expr_const(0, 1)) - // ); - } - - Ok(()) -} diff --git a/lib/unicorn_verify_mips.rs b/lib/unicorn_verify_mips.rs deleted file mode 100644 index 34b0e87..0000000 --- a/lib/unicorn_verify_mips.rs +++ /dev/null @@ -1,421 +0,0 @@ -//! Verify Finch's execution and semantics against Unicorn. - -use error::*; -use executor::{Driver, State, StateTranslator}; -use falcon::il; -use falcon::translator::TranslationMemory; -use falcon_capstone::{capstone, capstone_sys}; -use platform::Platform; -use std::collections::HashSet; -use unicorn; -use unicorn::{Cpu, CpuMIPS}; - - -struct RegisterMapping { - register: unicorn::RegisterMIPS, - name: &'static str -} - - -const REGISTER_MAPPINGS: &[RegisterMapping] = &[ - RegisterMapping { register: unicorn::RegisterMIPS::AT, name: "$at" }, - RegisterMapping { register: unicorn::RegisterMIPS::V0, name: "$v0" }, - RegisterMapping { register: unicorn::RegisterMIPS::V1, name: "$v1" }, - RegisterMapping { register: unicorn::RegisterMIPS::A0, name: "$a0" }, - RegisterMapping { register: unicorn::RegisterMIPS::A1, name: "$a1" }, - RegisterMapping { register: unicorn::RegisterMIPS::A2, name: "$a2" }, - RegisterMapping { register: unicorn::RegisterMIPS::A3, name: "$a3" }, - RegisterMapping { register: unicorn::RegisterMIPS::T0, name: "$t0" }, - RegisterMapping { register: unicorn::RegisterMIPS::T1, name: "$t1" }, - RegisterMapping { register: unicorn::RegisterMIPS::T2, name: "$t2" }, - RegisterMapping { register: unicorn::RegisterMIPS::T3, name: "$t3" }, - RegisterMapping { register: unicorn::RegisterMIPS::T4, name: "$t4" }, - RegisterMapping { register: unicorn::RegisterMIPS::T5, name: "$t5" }, - RegisterMapping { register: unicorn::RegisterMIPS::T6, name: "$t6" }, - RegisterMapping { register: unicorn::RegisterMIPS::T7, name: "$t7" }, - RegisterMapping { register: unicorn::RegisterMIPS::S0, name: "$s0" }, - RegisterMapping { register: unicorn::RegisterMIPS::S1, name: "$s1" }, - RegisterMapping { register: unicorn::RegisterMIPS::S2, name: "$s2" }, - RegisterMapping { register: unicorn::RegisterMIPS::S3, name: "$s3" }, - RegisterMapping { register: unicorn::RegisterMIPS::S4, name: "$s4" }, - RegisterMapping { register: unicorn::RegisterMIPS::S5, name: "$s5" }, - RegisterMapping { register: unicorn::RegisterMIPS::S6, name: "$s6" }, - RegisterMapping { register: unicorn::RegisterMIPS::S7, name: "$s7" }, - RegisterMapping { register: unicorn::RegisterMIPS::T8, name: "$t8" }, - RegisterMapping { register: unicorn::RegisterMIPS::T9, name: "$t9" }, - RegisterMapping { register: unicorn::RegisterMIPS::K0, name: "$k0" }, - RegisterMapping { register: unicorn::RegisterMIPS::K1, name: "$k1" }, - RegisterMapping { register: unicorn::RegisterMIPS::GP, name: "$gp" }, - RegisterMapping { register: unicorn::RegisterMIPS::SP, name: "$sp" }, - RegisterMapping { register: unicorn::RegisterMIPS::FP, name: "$fp" }, - RegisterMapping { register: unicorn::RegisterMIPS::RA, name: "$ra" }, -]; - - -fn make_emu>(mut driver: Driver

) - -> Result<(Driver

, CpuMIPS)> { - - // create the emu emulator - let mode = unicorn::Mode::BIG_ENDIAN as i32 | unicorn::Mode::MODE_32 as i32; - let mode = unsafe { ::std::mem::transmute::(mode) }; - let emu = CpuMIPS::new(mode) - .expect("Failed to initialize unicorn engine"); - - println!("Unicorn engine created"); - - // We need to track the pages we map, because we can't map a page twice - let mut mapped_pages: HashSet = HashSet::new(); - - let page_addresses: HashSet = - driver.state() - .memory() - .pages() - .into_iter() - .map(|(address, _)| address) - .collect::>(); - - // set up memory - for address in &page_addresses { - if mapped_pages.contains(address) { - continue; - } - mapped_pages.insert(*address); - - let mut length = ::executor::PAGE_SIZE as u64; - loop { - if page_addresses.contains(&(address + length)) - && !mapped_pages.contains(&(address + length)) { - mapped_pages.insert(*address + length); - length += ::executor::PAGE_SIZE as u64; - } - else { - break; - } - } - - emu.mem_map(*address, length as usize, unicorn::PROT_ALL) - .expect(&format!("Failed to map memory 0x{:x}", address)); - } - - // println!("memory pages mapped"); - - if let Some(backing) = driver.state().memory().backing() { - for (address, section) in backing.sections() { - let length = if section.len() % 0x1000 > 0 { - (section.len() + 0x1000) & (!0xfff) - } - else { - section.len() - }; - - let mut map_address = *address; - let mut map_length = length; - - if map_address % 0x1000 > 0 { - map_address = map_address & (!0xfff); - map_length += 0x1000; - } - - // Mapping lots of 0x1000 pages is slow, so we're going to first - // try 0x10000 increments, and default back to 0x1000 - let mut i: u64 = 0; - while i < map_length as u64 { - let large_increment = - !(0..16).into_iter().any(|j| - mapped_pages.contains(&(map_address + i + (j * 0x1000)))); - - if large_increment { - emu.mem_map(map_address + i, 0x10000, unicorn::PROT_ALL) - .expect("Failed to map memory"); - for j in 0..16 { - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } - else { - for j in 0..16 { - if mapped_pages.contains(&(map_address + i + (j * 0x1000))) { - continue; - } - emu.mem_map(map_address + i + (j * 0x1000), - 0x1000, - unicorn::PROT_ALL) - .expect(&format!("Failed to map memory 0x{:x}", - map_address + i + (j * 0x1000))); - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } - i = i + 0x10000; - } - - // println!("Write at 0x{:08x}, len=0x{:x}", address, section.data().len()); - emu.mem_write(*address, section.data()) - .expect(&format!("Failed to write memory at 0x{:x}", address)); - } - } - - println!("memory backing mapped"); - - let state = driver.state().clone(); - let state_translator = StateTranslator::new(state); - - for (address, _) in driver.state().memory().pages() { - for i in 0..::executor::PAGE_SIZE { - if let Some(byte) = state_translator.get_u8(address + i as u64) { - emu.mem_write(address + i as u64, &[byte]) - .expect(&format!("Failed to write 0x{:02x} at 0x{:x}", - byte, - address)); - } - } - } - - let mut state: State

= state_translator.into(); - - // initialize all our registers - for register_mapping in REGISTER_MAPPINGS { - let value = - state.eval_and_concretize( - &il::expr_scalar(register_mapping.name, 32))?; - match value { - Some(value) => - emu.reg_write(register_mapping.register.clone(), - value.value_u64().unwrap()) - .expect("Failed to write register"), - None => - emu.reg_write(register_mapping.register.clone(), 0) - .expect("Failed to write register") - }; - } - - // including the pc register - emu.reg_write( - unicorn::RegisterMIPS::PC, - driver.instruction() - .expect("Failed to get instruction to start unicorn stepping") - .address() - .expect("Failed to get address of instruction to start unicorn stepping") - ).expect("Failed to write PC register"); - - // driver takes this state - *driver.state_mut() = state; - - Ok((driver, emu)) -} - - -fn panic_step(emu: &mut CpuMIPS, steps: usize) { - let pc = emu.reg_read(unicorn::RegisterMIPS::PC) - .expect("Failed to get PC register"); - - println!("panic_step: 0x{:08x}", pc); - println!("$v0: 0x{:x}", emu.reg_read(unicorn::RegisterMIPS::V0).unwrap()); - - match emu.emu_start(pc, 0, 0, steps) { - Ok(_) => {}, - Err(err) => match err { - unicorn::Error::OK => panic!("Qemu Error OK {}", err as i32), - _ => { - let mem = emu.mem_read(0xc000102c, 16).unwrap(); - for i in 0..16 { - let address: u64 = 0xc000102c; - println!("0x{:x}: {:02x}", address + i, mem[i as usize]); - } - panic!("Qemu error {:?}", err) - } - } - } -} - - -pub fn step_with_unicorn>(driver: Driver

, steps: usize) - -> Result<()> { - - let (mut driver, mut emu) = make_emu(driver)?; - - enum WhatToDo { - Steps(usize), - Skip, - Syscall - } - - fn instruction_id(emu: &CpuMIPS) -> Option { - let pc = emu.reg_read(unicorn::RegisterMIPS::PC) - .expect("Failed to get PC register"); - - let mem = emu.mem_read(pc, 4).expect("Failed to read instruction"); - - let mode = capstone::CS_MODE_32 | capstone::CS_MODE_BIG_ENDIAN; - let cs = capstone::Capstone::new(capstone::cs_arch::CS_ARCH_MIPS, mode) - .expect("Failed to create capstone context"); - - let instruction = - cs.disasm(&mem, pc, 1) - .expect("Capstone disassembly error") - .get(0) - .unwrap(); - - let instruction_bytes = - mem.iter() - .map(|b| format!("{:02x}", b)) - .collect::>() - .join(""); - - println!("{}: {} {}", - instruction_bytes, - instruction.mnemonic, - instruction.op_str); - - if let capstone::InstrIdArch::MIPS(instruction_id) = instruction.id { - Some(instruction_id) - } - else { - None - } - } - - fn what_to_do(emu: &CpuMIPS) -> WhatToDo { - if let Some(instruction_id) = instruction_id(emu) { - println!("instruction_id: {:?}", instruction_id); - match instruction_id { - capstone::mips_insn::MIPS_INS_B | - capstone::mips_insn::MIPS_INS_BAL | - capstone::mips_insn::MIPS_INS_BEQ | - capstone::mips_insn::MIPS_INS_BEQZ | - capstone::mips_insn::MIPS_INS_BGEZ | - capstone::mips_insn::MIPS_INS_BGEZAL | - capstone::mips_insn::MIPS_INS_BGTZ | - capstone::mips_insn::MIPS_INS_BLEZ | - capstone::mips_insn::MIPS_INS_BLTZ | - capstone::mips_insn::MIPS_INS_BLTZAL | - capstone::mips_insn::MIPS_INS_BNE | - capstone::mips_insn::MIPS_INS_BNEZ | - capstone::mips_insn::MIPS_INS_J | - capstone::mips_insn::MIPS_INS_JR | - capstone::mips_insn::MIPS_INS_JAL | - capstone::mips_insn::MIPS_INS_JALR => WhatToDo::Steps(2), - capstone::mips_insn::MIPS_INS_MOVN => WhatToDo::Skip, - capstone::mips_insn::MIPS_INS_RDHWR | - capstone::mips_insn::MIPS_INS_SYSCALL => WhatToDo::Syscall, - _ => WhatToDo::Steps(1) - } - } - else { - panic!("Could not disassemble mips instruction"); - } - } - - 'emulator_step: for step in 0..steps { - // Perform an action - match what_to_do(&emu) { - WhatToDo::Skip => { - panic_step(&mut emu, 1); - continue; - }, - WhatToDo::Steps(steps) => { - panic_step(&mut emu, steps) - }, - WhatToDo::Syscall => { - println!("syscall"); - let mut drivers = driver.step()?; - if drivers.len() != 1 { - panic!("Multiple drivers following syscall"); - } - driver = drivers.pop().unwrap(); - if emu.reg_read(unicorn::RegisterMIPS::PC).unwrap() == 0x685318e4 { - println!("Shortcut"); - emu.reg_write(unicorn::RegisterMIPS::V1, 0xc0008000).unwrap(); - emu.reg_write(unicorn::RegisterMIPS::PC, 0x685318e8).unwrap(); - } - else { - let (driver_, emu_) = make_emu(driver)?; - driver = driver_; - emu = emu_; - println!("New emu pc=0x{:08x}", - emu.reg_read(unicorn::RegisterMIPS::PC).unwrap()); - } - continue; - } - } - - // Check to make sure we aren't sitting on a skip instruction - match what_to_do(&emu) { - WhatToDo::Skip => { - panic_step(&mut emu, 1); - continue; - } - _ => {} - } - - // get the new pc - let pc = emu.reg_read(unicorn::RegisterMIPS::PC) - .expect("Failed to get PC register"); - println!("pc=0x{:08x}, step={}", pc, step); - - // step the driver until it hits this address - for _ in 0..16 { - let mut drivers = driver.step()?; - if drivers.len() != 1 { - bail!("Drivers len != 1"); - } - driver = drivers.pop().unwrap(); - - if let Some(address) = driver.address() { - println!("driver address = 0x{:x}", address); - } - - if let Some(instruction) = driver.instruction() { - match instruction.operation() { - il::Operation::Branch { .. } => { - println!("Branch"); - }, - _ => {} - } - } - if driver.address().map(|address| address == pc).unwrap_or(false) { - break; - } - } - - // make sure address matches - if !driver.address().map(|address| address == pc).unwrap_or(false) { - panic!("Driver address does not match"); - } - - // verify registers - for register_mapping in REGISTER_MAPPINGS { - if let Some(value) = driver.state() - .scalar(register_mapping.name) - .and_then(|expr| driver.state().symbolize_and_eval(&expr).unwrap()) { - let unicorn_value = emu.reg_read(register_mapping.register) - .expect("Failed to read MIPS register"); - println!(" {} 0x{:08x} 0x{:08x}", - register_mapping.name, - unicorn_value, - value.value_u64().unwrap()); - // if unicorn_value != value.value_u64().unwrap() { - // for i in 0..16 { - // let address = 0x680006a0 - 16 + i; - // println!("0x{:08x}: {}", - // address, - // driver.state().memory().load(address, 8)?.unwrap()); - // } - // bail!("Register values differ"); - // } - } - } - - // verify 0x6800069d - // if let Some(constant) = driver.state().memory().load(0x6800069d, 8)? { - // let model8 = driver.state().symbolize_and_eval(&constant)?.unwrap().value_u64().unwrap() as u8; - // if emu.mem_regions().unwrap().into_iter().any(|region| - // region.begin <= 0x6800069d && region.end >= 0x6800069d) { - // let mem = emu.mem_read(0x6800069d, 1).unwrap(); - // if model8 != mem[0] { - // panic!("mismatch at address 0x6800069d") - // } - // } - // } - } - - Ok(()) -} \ No newline at end of file diff --git a/lib/unicorn_verify_x86.rs b/lib/unicorn_verify_x86.rs deleted file mode 100644 index 04f9b9a..0000000 --- a/lib/unicorn_verify_x86.rs +++ /dev/null @@ -1,257 +0,0 @@ -//! Verify Finch's execution and semantics against Unicorn. - -use error::*; -use executor::{Driver, State, StateTranslator}; -use falcon::il; -use falcon::translator::TranslationMemory; -use platform::Platform; -use std::collections::HashSet; -use unicorn; -use unicorn::{Cpu, CpuX86}; - - -struct RegisterMapping { - register: unicorn::RegisterX86, - name: &'static str -} - - -const REGISTER_MAPPINGS: &[RegisterMapping] = &[ - RegisterMapping { register: unicorn::RegisterX86::EAX, name: "eax" }, - RegisterMapping { register: unicorn::RegisterX86::EBX, name: "ebx" }, - RegisterMapping { register: unicorn::RegisterX86::ECX, name: "ecx" }, - RegisterMapping { register: unicorn::RegisterX86::EDX, name: "edx" }, - RegisterMapping { register: unicorn::RegisterX86::EDI, name: "edi" }, - RegisterMapping { register: unicorn::RegisterX86::ESI, name: "esi" }, - RegisterMapping { register: unicorn::RegisterX86::EBP, name: "ebp" }, - RegisterMapping { register: unicorn::RegisterX86::ESP, name: "esp" }, -]; - - -fn make_emu>(mut driver: Driver

) - -> Result<(Driver

, CpuX86)> { - - // create the emu emulator - let mode = unicorn::Mode::MODE_32 as i32; - let mode = unsafe { ::std::mem::transmute::(mode) }; - let emu = CpuX86::new(mode) - .expect("Failed to initialize unicorn engine"); - - println!("Unicorn engine created"); - - // We need to track the pages we map, because we can't map a page twice - let mut mapped_pages: HashSet = HashSet::new(); - - let page_addresses: HashSet = - driver.state() - .memory() - .pages() - .into_iter() - .map(|(address, _)| address) - .collect::>(); - - // set up memory - for address in &page_addresses { - if mapped_pages.contains(address) { - continue; - } - mapped_pages.insert(*address); - - let mut length = ::executor::PAGE_SIZE as u64; - loop { - if page_addresses.contains(&(address + length)) - && !mapped_pages.contains(&(address + length)) { - mapped_pages.insert(*address + length); - length += ::executor::PAGE_SIZE as u64; - } - else { - break; - } - } - - emu.mem_map(*address, length as usize, unicorn::PROT_ALL) - .expect(&format!("Failed to map memory 0x{:x}", address)); - } - - // println!("memory pages mapped"); - - if let Some(backing) = driver.state().memory().backing() { - for (address, section) in backing.sections() { - let length = if section.len() % 0x1000 > 0 { - (section.len() + 0x1000) & (!0xfff) - } - else { - section.len() - }; - - let mut map_address = *address; - let mut map_length = length; - - if map_address % 0x1000 > 0 { - map_address = map_address & (!0xfff); - map_length += 0x1000; - } - - // Mapping lots of 0x1000 pages is slow, so we're going to first - // try 0x10000 increments, and default back to 0x1000 - let mut i: u64 = 0; - while i < map_length as u64 { - let large_increment = - !(0..16).into_iter().any(|j| - mapped_pages.contains(&(map_address + i + (j * 0x1000)))); - - if large_increment { - emu.mem_map(map_address + i, 0x10000, unicorn::PROT_ALL) - .expect("Failed to map memory"); - for j in 0..16 { - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } - else { - for j in 0..16 { - if mapped_pages.contains(&(map_address + i + (j * 0x1000))) { - continue; - } - emu.mem_map(map_address + i + (j * 0x1000), - 0x1000, - unicorn::PROT_ALL) - .expect(&format!("Failed to map memory 0x{:x}", - map_address + i + (j * 0x1000))); - mapped_pages.insert(map_address + i + (j * 0x1000)); - } - } - i = i + 0x10000; - } - - // println!("Write at 0x{:08x}, len=0x{:x}", address, section.data().len()); - emu.mem_write(*address, section.data()) - .expect(&format!("Failed to write memory at 0x{:x}", address)); - } - } - - println!("memory backing mapped"); - - let state = driver.state().clone(); - let state_translator = StateTranslator::new(state); - - for (address, _) in driver.state().memory().pages() { - for i in 0..::executor::PAGE_SIZE { - if let Some(byte) = state_translator.get_u8(address + i as u64) { - emu.mem_write(address + i as u64, &[byte]) - .expect(&format!("Failed to write 0x{:02x} at 0x{:x}", - byte, - address)); - } - } - } - - let mut state: State

= state_translator.into(); - - // initialize all our registers - for register_mapping in REGISTER_MAPPINGS { - let value = - state.eval_and_concretize( - &il::expr_scalar(register_mapping.name, 32))?; - match value { - Some(value) => - emu.reg_write(register_mapping.register.clone(), - value.value_u64().unwrap()) - .expect("Failed to write register"), - None => - emu.reg_write(register_mapping.register.clone(), 0) - .expect("Failed to write register") - }; - } - - // including the pc register - emu.reg_write( - unicorn::RegisterX86::EIP, - driver.instruction() - .expect("Failed to get instruction to start unicorn stepping") - .address() - .expect("Failed to get address of instruction to start unicorn stepping") - ).expect("Failed to write PC register"); - - // driver takes this state - *driver.state_mut() = state; - - Ok((driver, emu)) -} - - -fn panic_step(emu: &mut CpuX86, steps: usize) { - let pc = emu.reg_read(unicorn::RegisterX86::EIP) - .expect("Failed to get PC register"); - - println!("panic_step: 0x{:08x}", pc); - - match emu.emu_start(pc, 0, 0, steps) { - Ok(_) => {}, - Err(err) => match err { - unicorn::Error::OK => panic!("Qemu Error OK {}", err as i32), - _ => panic!("Qemu error {:?}", err) - } - } -} - - -pub fn step_with_unicorn>(driver: Driver

, steps: usize) - -> Result<()> { - - let (mut driver, mut emu) = make_emu(driver)?; - - for step in 0..steps { - panic_step(&mut emu, 1); - - // get the new pc - let pc = emu.reg_read(unicorn::RegisterX86::EIP) - .expect("Failed to get PC register"); - println!("pc=0x{:08x}, step={}", pc, step); - - // step the driver until it hits this address - for _ in 0..16 { - let mut drivers = driver.step()?; - if drivers.len() != 1 { - bail!("Drivers len != 1"); - } - driver = drivers.pop().unwrap(); - - if let Some(address) = driver.address() { - println!("driver address = 0x{:x}", address); - } - - if let Some(instruction) = driver.instruction() { - match instruction.operation() { - il::Operation::Branch { .. } => { - println!("Branch"); - }, - _ => {} - } - } - if driver.address().map(|address| address == pc).unwrap_or(false) { - break; - } - } - - // make sure address matches - if !driver.address().map(|address| address == pc).unwrap_or(false) { - panic!("Driver address does not match"); - } - - // verify registers - for register_mapping in REGISTER_MAPPINGS { - if let Some(value) = driver.state() - .scalar(register_mapping.name) - .and_then(|expr| driver.state().symbolize_and_eval(&expr).unwrap()) { - let unicorn_value = emu.reg_read(register_mapping.register) - .expect("Failed to read x86 register"); - println!(" {} 0x{:08x} 0x{:08x}", - register_mapping.name, - unicorn_value, - value.value_u64().unwrap()); - } - } - } - - Ok(()) -} \ No newline at end of file diff --git a/src/debugger.rs b/src/debugger.rs index 0bacc40..6fce40f 100644 --- a/src/debugger.rs +++ b/src/debugger.rs @@ -174,22 +174,20 @@ impl Debugger { // Ok(v) // }); - let drivers_ = temp_drivers.into_iter().try_fold(Vec::new(), |mut v, d| { - v.append(&mut d.step()?); - Ok(v) - }); + let drivers_: Result> = + temp_drivers.into_iter().try_fold(Vec::new(), |mut v, d| { + v.append(&mut d.step()?); + Ok(v) + }); - drivers = match drivers_ { - Ok(drivers) => drivers, - Err(e) => return Err(e), - }; + drivers = drivers_?; - let address = drivers.get(0).unwrap().address().unwrap_or(0); + let address = drivers.first().unwrap().address().unwrap_or(0); // if _i == 1645 { if address == 0x4000b343 { use falcon::il; - let driver = drivers.get(0).unwrap(); + let driver = drivers.first().unwrap(); let trace = driver.trace(); let sliced_trace = trace.slice_backwards(&il::scalar("r14", 64), driver.program())?; @@ -205,7 +203,7 @@ impl Debugger { // panic!("11213"); } - if let Some(driver) = drivers.get(0) { + if let Some(driver) = drivers.first() { println!("{}", driver.location().apply(driver.program())?); // use falcon::il; // if let Some(instruction) = driver.instruction() { diff --git a/src/hooks.rs b/src/hooks.rs index fbbca6a..fd4e82c 100644 --- a/src/hooks.rs +++ b/src/hooks.rs @@ -1,14 +1,16 @@ use crate::error::*; use finch::executor::Driver; +type HookFn = Box Result>>>; + pub struct Hook { - hook: Box Result>>>, + hook: HookFn, } impl Hook { - pub fn new(hook: F) -> Hook + pub fn new(hook: F) -> Hook where - F: Fn(&Driver) -> Result>>, + F: Fn(&Driver) -> Result>> + 'static, { Hook { hook: Box::new(hook), diff --git a/src/interpreter.rs b/src/interpreter.rs index ca2dc93..0be7013 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -4,7 +4,12 @@ use std::fs::File; use std::io::Read; use std::path::Path; -use nom::{alt, map_res, named, tag, take_while1, tuple}; +use nom::{ + branch::alt, + bytes::complete::{tag, take_while1}, + combinator::map_res, + IResult, Parser, +}; #[derive(Clone, Debug)] pub enum Command { @@ -32,93 +37,205 @@ fn map_decimal_u64(input: &str) -> ::std::result::Result bool { - matches!(c, '0'..='9' | 'a'..='f' | 'A'..='F') + c.is_ascii_hexdigit() } fn is_decimal_digit(c: char) -> bool { - matches!(c, '0'..='9') + c.is_ascii_digit() } -named!(parse_hex_u64<&str, u64>, alt!( - tuple!( - tag!("0x"), - map_res!(take_while1!(is_hex_digit), map_address) - ) => { |(_, value)| value } -)); +fn parse_hex_u64(input: &str) -> IResult<&str, u64> { + let (input, (_, value)) = + (tag("0x"), map_res(take_while1(is_hex_digit), map_address)).parse(input)?; + Ok((input, value)) +} -named!(parse_decimal_u64<&str, u64>, - map_res!(take_while1!(is_decimal_digit), map_decimal_u64) -); +fn parse_decimal_u64(input: &str) -> IResult<&str, u64> { + map_res(take_while1(is_decimal_digit), map_decimal_u64).parse(input) +} -named!(parse_u64<&str, u64>, alt!( - parse_hex_u64 | - parse_decimal_u64 -)); +fn parse_u64(input: &str) -> IResult<&str, u64> { + alt((parse_hex_u64, parse_decimal_u64)).parse(input) +} fn is_space(c: char) -> bool { matches!(c, ' ' | '\t') } -named!(parse_info<&str, Command>, alt!( - alt!(tag!("breakpoints") | tag!("b")) => {|_| Command::InfoBreakpoints} | - alt!(tag!("drivers") | tag!("d")) => {|_| Command::InfoDrivers} | - alt!(tag!("killpoints") | tag!("k")) => {|_| Command::InfoKillPoints} -)); - -named!(parse_delete<&str, Command>, alt!( - alt!(tag!("breakpoints") | tag!("b")) => { |_| Command::DeleteBreakpoints } -)); - -named!(parse_command <&str, Command>, alt!( - tuple!( - alt!(tag!("breakpoint") | tag!("b")), - take_while1!(is_space), - parse_u64 - ) => { |(_, _, address)| - Command::AddBreakpoint(address) - } | - - tuple!( - alt!( tag!("continue") | tag!("c")), - take_while1!(is_space), - parse_u64 - ) => { |(_, _, address)| - Command::Continue(address as usize) - } | - - tag!("cull") => { |_| Command::CullDrivers } | - - tuple!( - alt!(tag!("delete") | tag!("d")), - take_while1!(is_space), - parse_delete - ) => {|(_, _, command)| command } | - - tag!("flatten") => { |_| Command::Flatten } | - - alt!(tag!("help") | tag!("h")) => { |_| Command::Help } | - - tuple!( - alt!(tag!("info") | tag!("i")), - take_while1!(is_space), - parse_info - ) => { |(_, _, command)| command } | - - tuple!( - alt!(tag!("killpoint") | tag!("k")), - take_while1!(is_space), - parse_u64 - ) => { |(_, _, address)| - Command::AddKillPoint(address) - } | - - alt!(tag!("quit") | tag!("q")) => { |_| Command::Quit } -)); +fn parse_info(input: &str) -> IResult<&str, Command> { + alt(( + |i| { + alt((tag("breakpoints"), tag("b"))) + .parse(i) + .map(|(r, _)| (r, Command::InfoBreakpoints)) + }, + |i| { + alt((tag("drivers"), tag("d"))) + .parse(i) + .map(|(r, _)| (r, Command::InfoDrivers)) + }, + |i| { + alt((tag("killpoints"), tag("k"))) + .parse(i) + .map(|(r, _)| (r, Command::InfoKillPoints)) + }, + )) + .parse(input) +} + +fn parse_delete(input: &str) -> IResult<&str, Command> { + let (input, _) = alt((tag("breakpoints"), tag("b"))).parse(input)?; + Ok((input, Command::DeleteBreakpoints)) +} + +fn parse_command(input: &str) -> IResult<&str, Command> { + alt(( + |i| { + let (i, (_, _, address)) = ( + alt((tag("breakpoint"), tag("b"))), + take_while1(is_space), + parse_u64, + ) + .parse(i)?; + Ok((i, Command::AddBreakpoint(address))) + }, + |i| { + let (i, (_, _, address)) = ( + alt((tag("continue"), tag("c"))), + take_while1(is_space), + parse_u64, + ) + .parse(i)?; + Ok((i, Command::Continue(address as usize))) + }, + |i| { + let (i, _) = tag("cull").parse(i)?; + Ok((i, Command::CullDrivers)) + }, + |i| { + let (i, (_, _, command)) = ( + alt((tag("delete"), tag("d"))), + take_while1(is_space), + parse_delete, + ) + .parse(i)?; + Ok((i, command)) + }, + |i| { + let (i, _) = tag("flatten").parse(i)?; + Ok((i, Command::Flatten)) + }, + |i| { + let (i, _) = alt((tag("help"), tag("h"))).parse(i)?; + Ok((i, Command::Help)) + }, + |i| { + let (i, (_, _, command)) = ( + alt((tag("info"), tag("i"))), + take_while1(is_space), + parse_info, + ) + .parse(i)?; + Ok((i, command)) + }, + |i| { + let (i, (_, _, address)) = ( + alt((tag("killpoint"), tag("k"))), + take_while1(is_space), + parse_u64, + ) + .parse(i)?; + Ok((i, Command::AddKillPoint(address))) + }, + |i| { + let (i, _) = alt((tag("quit"), tag("q"))).parse(i)?; + Ok((i, Command::Quit)) + }, + )) + .parse(input) +} pub struct Interpreter { debugger: Debugger, } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_hex_u64() { + let (_, val) = parse_hex_u64("0xff").unwrap(); + assert_eq!(val, 255); + let (_, val) = parse_hex_u64("0xDEAD").unwrap(); + assert_eq!(val, 0xDEAD); + } + + #[test] + fn test_parse_decimal_u64() { + let (_, val) = parse_decimal_u64("42").unwrap(); + assert_eq!(val, 42); + let (_, val) = parse_decimal_u64("0").unwrap(); + assert_eq!(val, 0); + } + + #[test] + fn test_parse_u64_hex_and_decimal() { + let (_, val) = parse_u64("0x10").unwrap(); + assert_eq!(val, 16); + let (_, val) = parse_u64("10").unwrap(); + assert_eq!(val, 10); + } + + #[test] + fn test_parse_command_breakpoint() { + let (_, cmd) = parse_command("b 0x1000").unwrap(); + assert!(matches!(cmd, Command::AddBreakpoint(0x1000))); + } + + #[test] + fn test_parse_command_continue() { + let (_, cmd) = parse_command("c 10").unwrap(); + assert!(matches!(cmd, Command::Continue(10))); + } + + #[test] + fn test_parse_command_quit() { + let (_, cmd) = parse_command("q").unwrap(); + assert!(matches!(cmd, Command::Quit)); + let (_, cmd) = parse_command("quit").unwrap(); + assert!(matches!(cmd, Command::Quit)); + } + + #[test] + fn test_parse_command_help() { + let (_, cmd) = parse_command("h").unwrap(); + assert!(matches!(cmd, Command::Help)); + let (_, cmd) = parse_command("help").unwrap(); + assert!(matches!(cmd, Command::Help)); + } + + #[test] + fn test_parse_command_info() { + let (_, cmd) = parse_command("i breakpoints").unwrap(); + assert!(matches!(cmd, Command::InfoBreakpoints)); + let (_, cmd) = parse_command("i d").unwrap(); + assert!(matches!(cmd, Command::InfoDrivers)); + } + + #[test] + fn test_parse_command_cull() { + let (_, cmd) = parse_command("cull").unwrap(); + assert!(matches!(cmd, Command::CullDrivers)); + } + + #[test] + fn test_parse_command_flatten() { + let (_, cmd) = parse_command("flatten").unwrap(); + assert!(matches!(cmd, Command::Flatten)); + } +} + impl Interpreter { pub fn new(debugger: Debugger) -> Interpreter { Interpreter { debugger } @@ -152,11 +269,11 @@ impl Interpreter { } pub fn interactive(&mut self) -> Result<()> { - let mut rl = rustyline::Editor::<()>::new(); + let mut rl = rustyline::Editor::<(), rustyline::history::DefaultHistory>::new()?; 'debugger_loop: loop { let line = rl.readline("> ")?; - rl.add_history_entry(&line); + let _ = rl.add_history_entry(&line); let command = match parse_command(&line) { Ok(command) => command.1, diff --git a/src/main.rs b/src/main.rs index 1faca34..e212a28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ pub mod driver; pub mod hooks; pub mod interpreter; +#[allow(unexpected_cfgs)] pub mod error { error_chain! { types { @@ -18,7 +19,7 @@ pub mod error { } foreign_links { - Falcon(::falcon::error::Error); + Falcon(::falcon::Error); Finch(::finch::error::Error); IoError(::std::io::Error); ReadLineError(::rustyline::error::ReadlineError); @@ -33,76 +34,68 @@ use finch::platform; use std::path::{Path, PathBuf}; fn run2(driver: Driver, matches: &clap::ArgMatches) -> Result<()> { - if matches.is_present("debugger") { + if matches.get_flag("debugger") { let debugger = debugger::Debugger::new(vec![driver]); let mut interpreter = interpreter::Interpreter::new(debugger); interpreter.interactive() - } else if let Some(debugger_script) = matches.value_of("debugger_script") { + } else if let Some(debugger_script) = matches.get_one::("debugger_script") { let debugger = debugger::Debugger::new(vec![driver]); let mut interpreter = interpreter::Interpreter::new(debugger); interpreter.script(Path::new(debugger_script)) } else { unimplemented!("Unicorn testing"); - // let driver = driver::drive_to_address(driver, 0x1000, 1000000)? - // .get(0) - // .unwrap() - // .clone(); - // unimplemented!("unicorn testing"); - // info!("Being unicorn testing"); - // Ok(finch::unicorn_verify_amd64::step_with_unicorn( - // driver, 100000, - // )?) } } fn run() -> Result<()> { - let matches = clap::App::new("finch") + let matches = clap::Command::new("finch") .version("0.1.0") .about("Falcon Symbolic Executor") .author("Alex Eubanks") .arg( - clap::Arg::with_name("filename") - .short("f") + clap::Arg::new("filename") + .short('f') .value_name("FILE") .help("Binary to symbolically execute") .required(true), ) .arg( - clap::Arg::with_name("base_path") - .short("b") + clap::Arg::new("base_path") + .short('b') .value_name("BASE_PATH") .help("Base path of filesystem") .required(true), ) .arg( - clap::Arg::with_name("debugger") - .short("d") - .help("Start the interactive debugger"), + clap::Arg::new("debugger") + .short('d') + .help("Start the interactive debugger") + .action(clap::ArgAction::SetTrue), ) .arg( - clap::Arg::with_name("debugger_script") - .short("x") + clap::Arg::new("debugger_script") + .short('x') .long("debugger_script") .value_name("DEBUGGER_SCRIPT") .conflicts_with("debugger") .help("Give a file filled with debugger command"), ) .arg( - clap::Arg::with_name("log") - .short("l") + clap::Arg::new("log") + .short('l') .long("log") .value_name("LOG_LEVEL") .help("Log level"), ) .get_matches(); - let filename = matches.value_of("filename").unwrap(); + let filename = matches.get_one::("filename").unwrap(); let base_path: Option = matches - .value_of("base_path") + .get_one::("base_path") .map(|base_path| base_path.into()); - if let Some(log_level) = matches.value_of("log") { + if let Some(log_level) = matches.get_one::("log").map(|s| s.as_str()) { let level_filter = match log_level { "debug" => Some(simplelog::LevelFilter::Debug), "info" => Some(simplelog::LevelFilter::Info),