summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock962
-rw-r--r--plugins/warp/Cargo.toml1
-rw-r--r--plugins/warp/api/python/_warpcore.py23
-rw-r--r--plugins/warp/api/python/warp.py7
-rw-r--r--plugins/warp/api/warp.cpp10
-rw-r--r--plugins/warp/api/warp.h2
-rw-r--r--plugins/warp/api/warpcore.h2
-rw-r--r--plugins/warp/src/container.rs13
-rw-r--r--plugins/warp/src/container/network.rs332
-rw-r--r--plugins/warp/src/container/network/client.rs228
-rw-r--r--plugins/warp/src/plugin.rs89
-rw-r--r--plugins/warp/src/plugin/ffi/container.rs21
-rw-r--r--plugins/warp/src/plugin/settings.rs28
-rw-r--r--plugins/warp/src/plugin/workflow.rs17
-rw-r--r--plugins/warp/ui/matches.cpp71
-rw-r--r--plugins/warp/ui/matches.h9
-rw-r--r--plugins/warp/ui/plugin.cpp3
17 files changed, 1770 insertions, 48 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c3d7bb56..e9b6202e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -150,6 +150,12 @@ dependencies = [
]
[[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.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -171,6 +177,12 @@ dependencies = [
]
[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
name = "binaryninja"
version = "0.1.0"
dependencies = [
@@ -286,6 +298,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -423,6 +441,22 @@ dependencies = [
]
[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
name = "cpp_demangle"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -594,6 +628,17 @@ dependencies = [
]
[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "dwarf_export"
version = "0.1.0"
dependencies = [
@@ -737,6 +782,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -849,6 +918,17 @@ dependencies = [
[[package]]
name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
@@ -856,7 +936,7 @@ dependencies = [
"cfg-if",
"libc",
"r-efi",
- "wasi",
+ "wasi 0.14.2+wasi-0.2.4",
]
[[package]]
@@ -877,6 +957,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
+name = "h2"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
name = "half"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -914,6 +1013,210 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
+name = "http"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hyper"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "system-configuration",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "windows-registry",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+
+[[package]]
+name = "icu_properties"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "potential_utf",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+
+[[package]]
+name = "icu_provider"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
name = "idb-rs"
version = "0.1.10"
source = "git+https://github.com/Vector35/idb-rs?tag=0.1.10#f5e97df2a7949793d6d7319b95ee9aae2b3792c6"
@@ -946,6 +1249,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
name = "image"
version = "0.25.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -981,6 +1305,33 @@ dependencies = [
]
[[package]]
+name = "io-uring"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013"
+dependencies = [
+ "bitflags 2.9.1",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+
+[[package]]
+name = "iri-string"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1031,7 +1382,7 @@ version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
dependencies = [
- "getrandom",
+ "getrandom 0.3.3",
"libc",
]
@@ -1080,6 +1431,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
+[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1111,6 +1468,22 @@ dependencies = [
]
[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
name = "minidump"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1187,12 +1560,40 @@ dependencies = [
]
[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "msp430-asm"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91c22f111c205b788cc10e2a58aed039d5dd5554d3a9236be3d413a912ff3cb"
[[package]]
+name = "native-tls"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1365,6 +1766,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
+name = "openssl"
+version = "0.10.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
+dependencies = [
+ "bitflags 2.9.1",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "parking_lot"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1489,6 +1934,15 @@ dependencies = [
]
[[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1667,6 +2121,63 @@ dependencies = [
]
[[package]]
+name = "reqwest"
+version = "0.12.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "mime",
+ "mime_guess",
+ "native-tls",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-native-tls",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.16",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "riscv-dis"
version = "0.1.0"
dependencies = [
@@ -1757,6 +2268,39 @@ dependencies = [
]
[[package]]
+name = "rustls"
+version = "0.23.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
+dependencies = [
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
name = "rustversion"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1798,6 +2342,15 @@ dependencies = [
]
[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1836,6 +2389,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21"
[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags 2.9.1",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1874,6 +2450,18 @@ dependencies = [
]
[[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 = "serial_test"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1946,6 +2534,16 @@ dependencies = [
]
[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1964,6 +2562,12 @@ 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 = "svd-parser"
version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2022,6 +2626,47 @@ dependencies = [
]
[[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",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags 2.9.1",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "tempdir"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2038,7 +2683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
- "getrandom",
+ "getrandom 0.3.3",
"once_cell",
"rustix 1.0.7",
"windows-sys 0.59.0",
@@ -2127,6 +2772,16 @@ dependencies = [
]
[[package]]
+name = "tinystr"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2137,6 +2792,56 @@ dependencies = [
]
[[package]]
+name = "tokio"
+version = "1.46.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "io-uring",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "slab",
+ "socket2",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2154,6 +2859,51 @@ dependencies = [
]
[[package]]
+name = "tower"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+dependencies = [
+ "bitflags 2.9.1",
+ "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.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2186,6 +2936,12 @@ dependencies = [
]
[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
name = "twox-hash"
version = "1.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2196,12 +2952,41 @@ dependencies = [
]
[[package]]
+name = "unicase"
+version = "2.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
+
+[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[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.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[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"
@@ -2213,13 +2998,19 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
- "getrandom",
+ "getrandom 0.3.3",
"js-sys",
"sha1_smol",
"wasm-bindgen",
]
[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2236,6 +3027,15 @@ dependencies = [
]
[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
name = "warp"
version = "1.0.0"
source = "git+https://github.com/Vector35/warp/?tag=1.0.0#57dcb5abea59a611466be9550ba25b36c5399ce6"
@@ -2264,6 +3064,7 @@ dependencies = [
"minijinja-embed",
"rayon",
"regex",
+ "reqwest",
"serde",
"serde_json",
"tempdir",
@@ -2275,6 +3076,12 @@ dependencies = [
[[package]]
name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasi"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
@@ -2309,6 +3116,19 @@ dependencies = [
]
[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2388,6 +3208,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[package]]
+name = "windows-registry"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
+dependencies = [
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link",
+]
+
+[[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"
@@ -2609,6 +3473,12 @@ dependencies = [
]
[[package]]
+name = "writeable"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[package]]
name = "x11rb"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2626,6 +3496,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
[[package]]
+name = "yoke"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
name = "zerocopy"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2646,6 +3540,66 @@ dependencies = [
]
[[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",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/plugins/warp/Cargo.toml b/plugins/warp/Cargo.toml
index afebf577..761ac961 100644
--- a/plugins/warp/Cargo.toml
+++ b/plugins/warp/Cargo.toml
@@ -24,6 +24,7 @@ thiserror = "2.0"
ar = { git = "https://github.com/mdsteele/rust-ar" }
tempdir = "0.3.7"
regex = "1.11"
+reqwest = { version = "0.12", features = ["blocking", "json", "multipart"] }
# For reports
minijinja = "2.10.2"
diff --git a/plugins/warp/api/python/_warpcore.py b/plugins/warp/api/python/_warpcore.py
index 740072ab..da262f18 100644
--- a/plugins/warp/api/python/_warpcore.py
+++ b/plugins/warp/api/python/_warpcore.py
@@ -205,6 +205,29 @@ def BNWARPContainerCommitSource(
# -------------------------------------------------------
+# _BNWARPContainerFetchFunctions
+
+_BNWARPContainerFetchFunctions = core.BNWARPContainerFetchFunctions
+_BNWARPContainerFetchFunctions.restype = None
+_BNWARPContainerFetchFunctions.argtypes = [
+ ctypes.POINTER(BNWARPContainer),
+ ctypes.POINTER(BNWARPTarget),
+ ctypes.POINTER(BNWARPTypeGUID),
+ ctypes.c_ulonglong,
+ ]
+
+
+# noinspection PyPep8Naming
+def BNWARPContainerFetchFunctions(
+ container: ctypes.POINTER(BNWARPContainer),
+ target: ctypes.POINTER(BNWARPTarget),
+ guids: ctypes.POINTER(BNWARPTypeGUID),
+ count: int
+ ) -> None:
+ return _BNWARPContainerFetchFunctions(container, target, guids, count)
+
+
+# -------------------------------------------------------
# _BNWARPContainerGetFunctionsWithGUID
_BNWARPContainerGetFunctionsWithGUID = core.BNWARPContainerGetFunctionsWithGUID
diff --git a/plugins/warp/api/python/warp.py b/plugins/warp/api/python/warp.py
index c761c323..c7486b8c 100644
--- a/plugins/warp/api/python/warp.py
+++ b/plugins/warp/api/python/warp.py
@@ -305,6 +305,13 @@ class WarpContainer(metaclass=_WarpContainerMetaclass):
core_guids[i] = guids[i].uuid
return warpcore.BNWARPContainerRemoveTypes(self.handle, source.uuid, core_guids, count)
+ def fetch_functions(self, target: WarpTarget, guids: List[FunctionGUID]):
+ count = len(guids)
+ core_guids = (warpcore.BNWARPFunctionGUID * count)()
+ for i in range(count):
+ core_guids[i] = guids[i].uuid
+ warpcore.BNWARPContainerFetchFunctions(self.handle, target.handle, core_guids, count)
+
def get_sources_with_function_guid(self, target: WarpTarget, guid: FunctionGUID) -> List[Source]:
count = ctypes.c_size_t()
sources = warpcore.BNWARPContainerGetSourcesWithFunctionGUID(self.handle, target.handle, guid.uuid, count)
diff --git a/plugins/warp/api/warp.cpp b/plugins/warp/api/warp.cpp
index 147add8e..52c7ea9d 100644
--- a/plugins/warp/api/warp.cpp
+++ b/plugins/warp/api/warp.cpp
@@ -249,6 +249,16 @@ bool Container::RemoveTypes(const Source &source, const std::vector<TypeGUID> &g
return result;
}
+void Container::FetchFunctions(const Target &target, const std::vector<FunctionGUID> &guids) const
+{
+ size_t count = guids.size();
+ BNWARPFunctionGUID *apiGuids = new BNWARPFunctionGUID[count];
+ for (size_t i = 0; i < count; i++)
+ apiGuids[i] = *guids[i].Raw();
+ BNWARPContainerFetchFunctions(m_object, target.m_object, apiGuids, count);
+ delete[] apiGuids;
+}
+
std::vector<Source> Container::GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const
{
size_t count;
diff --git a/plugins/warp/api/warp.h b/plugins/warp/api/warp.h
index b57a0c7b..807ba998 100644
--- a/plugins/warp/api/warp.h
+++ b/plugins/warp/api/warp.h
@@ -354,6 +354,8 @@ namespace Warp {
bool RemoveTypes(const Source &source, const std::vector<TypeGUID> &guids) const;
+ void FetchFunctions(const Target& target, const std::vector<FunctionGUID> &guids) const;
+
std::vector<Source> GetSourcesWithFunctionGUID(const Target& target, const FunctionGUID &guid) const;
std::vector<Source> GetSourcesWithTypeGUID(const TypeGUID &guid) const;
diff --git a/plugins/warp/api/warpcore.h b/plugins/warp/api/warpcore.h
index 09190126..20a59b7b 100644
--- a/plugins/warp/api/warpcore.h
+++ b/plugins/warp/api/warpcore.h
@@ -108,6 +108,8 @@ extern "C"
WARP_FFI_API bool BNWARPContainerRemoveFunctions(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPSource* source, BNWARPFunction** functions, size_t count);
WARP_FFI_API bool BNWARPContainerRemoveTypes(BNWARPContainer* container, const BNWARPSource* source, BNWARPTypeGUID* types, size_t count);
+ WARP_FFI_API void BNWARPContainerFetchFunctions(BNWARPContainer* container, BNWARPTarget* target, const BNWARPTypeGUID* guids, size_t count);
+
WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithFunctionGUID(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPFunctionGUID* guid, size_t* count);
WARP_FFI_API BNWARPSource* BNWARPContainerGetSourcesWithTypeGUID(BNWARPContainer* container, const BNWARPTypeGUID* guid, size_t* count);
WARP_FFI_API BNWARPFunction** BNWARPContainerGetFunctionsWithGUID(BNWARPContainer* container, const BNWARPTarget* target, const BNWARPSource* source, const BNWARPFunctionGUID* guid, size_t* count);
diff --git a/plugins/warp/src/container.rs b/plugins/warp/src/container.rs
index 8d720021..4cabc60e 100644
--- a/plugins/warp/src/container.rs
+++ b/plugins/warp/src/container.rs
@@ -208,6 +208,19 @@ pub trait Container: Send + Sync + Display + Debug {
functions: &[Function],
) -> ContainerResult<()>;
+ /// Fetches WARP information for the associated functions.
+ ///
+ /// Typically, a container that resides only in memory has nothing to fetch, so the default implementation
+ /// will do nothing. This function is blocking, so assume it will take a few seconds for a container
+ /// that intends to fetch over the network.
+ fn fetch_functions(
+ &mut self,
+ _target: &Target,
+ _functions: &[FunctionGUID],
+ ) -> ContainerResult<()> {
+ Ok(())
+ }
+
/// Get the sources that contain a type with the given [`TypeGUID`].
fn sources_with_type_guid(&self, guid: &TypeGUID) -> ContainerResult<Vec<SourceId>>;
diff --git a/plugins/warp/src/container/network.rs b/plugins/warp/src/container/network.rs
index ffbe6108..2a2d7c65 100644
--- a/plugins/warp/src/container/network.rs
+++ b/plugins/warp/src/container/network.rs
@@ -1,13 +1,323 @@
-pub struct NetworkContainer {}
+use crate::container::disk::DiskContainer;
+use crate::container::{Container, ContainerError, ContainerResult, SourceId, SourcePath};
+use std::collections::HashMap;
+use std::fmt::{Debug, Display, Formatter};
+use warp::chunk::{Chunk, ChunkKind, CompressionType};
+use warp::r#type::guid::TypeGUID;
+use warp::r#type::{ComputedType, Type};
+use warp::signature::chunk::SignatureChunk;
+use warp::signature::function::{Function, FunctionGUID};
+use warp::target::Target;
+use warp::{WarpFile, WarpFileHeader};
-// TODO: The container is populated as the user is navigating a binary
-// TODO: We need to have a few helper functions here to post and pull
-// TODO: Then in the interface we operate off the network cache
-// TODO: The network cache could just be a disk container? Or disk container sources?
-// TODO: We should also store the cache on the filesystem for a certain time, will need to timestamp
-// TODO: When we commit we need to actually POST i believe.
-// TODO: There needs to be a setting that adjusts the sweep size of functions at the cursor.
-// TODO: Probably need a callback or something to tell the network containers to refresh from the network.
-// TODO: The network container should never instantiate itself, unless its gurenteed to not have any data in it?
+pub mod client;
-// TODO: Need to PUSH chunks and PULL chunks
+pub use client::NetworkClient;
+
+/// This is the id on the server for the [`Target`], we can get it via [`NetworkClient::query_target_id`].
+pub type NetworkTargetId = i32;
+
+pub struct NetworkContainer {
+ client: NetworkClient,
+ /// This is the store that the interface will write to; then we have special functions for pulling
+ /// and pushing to the network source.
+ cache: DiskContainer,
+ /// Populated when targets are queried.
+ known_targets: HashMap<Target, Option<NetworkTargetId>>,
+ /// Populated with function sources are queried.
+ known_function_sources: HashMap<FunctionGUID, Vec<SourceId>>,
+ /// Populated when user adds function, this is used for writing back to the server.
+ added_chunks: HashMap<SourceId, Vec<Chunk<'static>>>,
+}
+
+impl NetworkContainer {
+ pub fn new(client: NetworkClient) -> Self {
+ Self {
+ cache: DiskContainer::new("Network Container".to_string(), HashMap::new()),
+ client,
+ known_targets: HashMap::new(),
+ known_function_sources: HashMap::new(),
+ added_chunks: HashMap::new(),
+ }
+ }
+
+ /// Gets the network id for the `target`, this will be used in later function queries.
+ ///
+ /// **This is blocking**
+ ///
+ /// # Caching policy
+ ///
+ /// The [`NetworkTargetId`] is unique and immutable, so they will be persisted indefinitely.
+ pub fn get_target_id(&mut self, target: &Target) -> Option<NetworkTargetId> {
+ // It's highly probable we have previously queried the target, check that first.
+ if let Some(target_id) = self.known_targets.get(target) {
+ return target_id.clone();
+ }
+
+ let target_id = self.client.query_target_id(target);
+ // Keep the target id so the next lookup is free.
+ self.known_targets.insert(target.clone(), target_id);
+ target_id
+ }
+
+ /// Pulls sources for the set of unseen function guids.
+ ///
+ /// **This is blocking**
+ ///
+ /// # Caching policy
+ ///
+ /// When we get the source, we store the results indefinitely in the container; this is fine
+ /// for now as the requests for functions come at the request of some user interaction. Any guid
+ /// with no sources will still be cached.
+ pub fn get_unseen_functions_source(
+ &mut self,
+ target: Option<&Target>,
+ guids: &[FunctionGUID],
+ ) -> HashMap<SourceId, Vec<FunctionGUID>> {
+ let Some(target_id) = target.and_then(|t| self.get_target_id(t)) else {
+ log::debug!("Cannot query functions source without a target, skipping...");
+ return HashMap::new();
+ };
+
+ // Split guids into known and unknown
+ let (_known, unknown): (Vec<_>, Vec<_>) = guids
+ .into_iter()
+ .cloned()
+ .partition(|guid| self.known_function_sources.contains_key(guid));
+
+ let mut result: HashMap<SourceId, Vec<FunctionGUID>> = HashMap::new();
+ // Only query server for unknown guids if we have any.
+ if !unknown.is_empty() {
+ if let Some(queried_results) = self
+ .client
+ .query_functions_source(Some(target_id), &unknown)
+ {
+ // Cache the new results, this means we will not try and contact the server for that guids source.
+ // NOTE: Here we do not just simply list the queried results because we also
+ // want to cache function guids which have no source, this is important so that we never
+ // attempt to contact the server for that guid.
+ for guid in &unknown {
+ let sources = queried_results
+ .keys()
+ .filter(|source_id| queried_results[source_id].contains(guid))
+ .cloned()
+ .collect();
+ self.known_function_sources.insert(*guid, sources);
+ }
+
+ for (source_id, guids) in queried_results {
+ result.entry(source_id).or_default().extend(guids);
+ }
+ }
+ }
+
+ result
+ }
+
+ /// Pulls function metadata from the server and adds it into the container cache.
+ ///
+ /// **This is blocking**
+ ///
+ /// # Caching policy
+ ///
+ /// Every request we store the returned objects on disk, this means that users will first
+ /// query against the disk objects, then the server. This also means we need to cache functions f
+ /// or which we have not received any functions for, as otherwise we would keep trying to query it.
+ pub fn pull_functions(
+ &mut self,
+ target: &Target,
+ source: &SourceId,
+ functions: &[FunctionGUID],
+ ) {
+ let target_id = self.get_target_id(target);
+ if let Some(file) = self
+ .client
+ .query_functions(target_id, Some(*source), functions)
+ {
+ log::debug!("Got {} chunks from server", file.chunks.len());
+ for chunk in &file.chunks {
+ match &chunk.kind {
+ ChunkKind::Signature(sc) => {
+ let functions: Vec<_> = sc.functions().collect();
+ match self.cache.add_functions(target, source, &functions) {
+ Ok(_) => log::debug!(
+ "Added {} functions into cached source '{}'",
+ functions.len(),
+ source
+ ),
+ Err(err) => log::error!(
+ "Failed to add {} function into cached source '{}': {}",
+ functions.len(),
+ source,
+ err
+ ),
+ }
+ }
+ // TODO; Probably want to pull type in with this.
+ ChunkKind::Type(_) => {}
+ }
+ }
+ }
+ }
+
+ /// Push a file to the network source.
+ ///
+ /// **This is blocking**
+ pub fn push_file(&mut self, source_id: SourceId, file: &WarpFile) {
+ self.client.push_file(source_id, file);
+ }
+}
+
+impl Container for NetworkContainer {
+ fn sources(&self) -> ContainerResult<Vec<SourceId>> {
+ self.cache.sources()
+ }
+
+ fn add_source(&mut self, path: SourcePath) -> ContainerResult<SourceId> {
+ // TODO: How do we want to let users create new sources?
+ log::error!("NetworkContainer::add_source not allowed");
+ Err(ContainerError::CannotCreateSource(path))
+ }
+
+ fn commit_source(&mut self, source: &SourceId) -> ContainerResult<bool> {
+ let chunks = self
+ .added_chunks
+ .remove(source)
+ .ok_or(ContainerError::SourceNotFound(source.clone()))?;
+ let file = WarpFile::new(WarpFileHeader::new(), chunks);
+ self.push_file(*source, &file);
+ Ok(true)
+ }
+
+ fn is_source_writable(&self, source: &SourceId) -> ContainerResult<bool> {
+ // TODO: This is retrievable from /users/me/sources we will grab it when connecting.
+ log::error!("NetworkContainer::is_source_writable not allowed");
+ Err(ContainerError::SourceNotWritable(source.clone()))
+ }
+
+ fn is_source_uncommitted(&self, source: &SourceId) -> ContainerResult<bool> {
+ Ok(self.added_chunks.contains_key(source))
+ }
+
+ fn source_path(&self, source: &SourceId) -> ContainerResult<SourcePath> {
+ self.cache.source_path(source)
+ }
+
+ fn add_computed_types(
+ &mut self,
+ source: &SourceId,
+ types: &[ComputedType],
+ ) -> ContainerResult<()> {
+ self.cache.add_computed_types(source, types)
+ }
+
+ fn remove_types(&mut self, source: &SourceId, guids: &[TypeGUID]) -> ContainerResult<()> {
+ self.cache.remove_types(source, guids)
+ }
+
+ fn add_functions(
+ &mut self,
+ target: &Target,
+ source: &SourceId,
+ functions: &[Function],
+ ) -> ContainerResult<()> {
+ let signature_chunk = SignatureChunk::new(functions).ok_or(
+ ContainerError::CorruptedData("signature chunk failed to validate"),
+ )?;
+ let chunk = Chunk::new_with_target(
+ ChunkKind::Signature(signature_chunk),
+ CompressionType::None,
+ target.clone(),
+ );
+ self.added_chunks.entry(*source).or_default().push(chunk);
+ Ok(())
+ }
+
+ fn remove_functions(
+ &mut self,
+ target: &Target,
+ source: &SourceId,
+ functions: &[Function],
+ ) -> ContainerResult<()> {
+ // TODO: Wont persist, need to add remote removal.
+ self.cache.remove_functions(target, source, functions)
+ }
+
+ fn fetch_functions(
+ &mut self,
+ target: &Target,
+ functions: &[FunctionGUID],
+ ) -> ContainerResult<()> {
+ // NOTE: Blocking request to get the mapped function sources.
+ let mapped_unseen_functions = self.get_unseen_functions_source(Some(&target), functions);
+
+ // Actually get the function data for the unseen guids, we really only want to do this once per
+ // session, anymore, and this is annoying!
+ for (source, unseen_guids) in mapped_unseen_functions {
+ // NOTE: Blocking request to get the function data in the container cache.
+ self.pull_functions(&target, &source, &unseen_guids);
+ }
+
+ Ok(())
+ }
+
+ fn sources_with_type_guid(&self, guid: &TypeGUID) -> ContainerResult<Vec<SourceId>> {
+ self.cache.sources_with_type_guid(guid)
+ }
+
+ fn sources_with_type_guids(
+ &self,
+ guids: &[TypeGUID],
+ ) -> ContainerResult<HashMap<TypeGUID, Vec<SourceId>>> {
+ self.cache.sources_with_type_guids(guids)
+ }
+
+ fn type_guids_with_name(
+ &self,
+ source: &SourceId,
+ name: &str,
+ ) -> ContainerResult<Vec<TypeGUID>> {
+ self.cache.type_guids_with_name(source, name)
+ }
+
+ fn type_with_guid(&self, source: &SourceId, guid: &TypeGUID) -> ContainerResult<Option<Type>> {
+ self.cache.type_with_guid(source, guid)
+ }
+
+ fn sources_with_function_guid(
+ &self,
+ target: &Target,
+ guid: &FunctionGUID,
+ ) -> ContainerResult<Vec<SourceId>> {
+ self.cache.sources_with_function_guid(target, guid)
+ }
+
+ fn sources_with_function_guids(
+ &self,
+ target: &Target,
+ guids: &[FunctionGUID],
+ ) -> ContainerResult<HashMap<FunctionGUID, Vec<SourceId>>> {
+ self.cache.sources_with_function_guids(target, guids)
+ }
+
+ fn functions_with_guid(
+ &self,
+ target: &Target,
+ source: &SourceId,
+ guid: &FunctionGUID,
+ ) -> ContainerResult<Vec<Function>> {
+ self.cache.functions_with_guid(target, source, guid)
+ }
+}
+
+impl Debug for NetworkContainer {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("NetworkContainer").finish()
+ }
+}
+
+impl Display for NetworkContainer {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("NetworkContainer").finish()
+ }
+}
diff --git a/plugins/warp/src/container/network/client.rs b/plugins/warp/src/container/network/client.rs
new file mode 100644
index 00000000..f77f1118
--- /dev/null
+++ b/plugins/warp/src/container/network/client.rs
@@ -0,0 +1,228 @@
+use crate::container::network::NetworkTargetId;
+use crate::container::SourceId;
+use reqwest::blocking::Client;
+use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
+use reqwest::StatusCode;
+use serde_json::json;
+use std::collections::HashMap;
+use std::str::FromStr;
+use warp::signature::function::FunctionGUID;
+use warp::target::Target;
+use warp::WarpFile;
+
+/// Responsible for sending and receiving data from the server.
+///
+/// NOTE: **All requests are blocking**.
+#[derive(Clone, Debug)]
+pub struct NetworkClient {
+ client: Client,
+ server_url: String,
+}
+
+impl NetworkClient {
+ pub fn new(
+ server_url: String,
+ server_token: Option<String>,
+ https_proxy: Option<String>,
+ ) -> reqwest::Result<Self> {
+ let version_info = binaryninja::version_info();
+ // TODO: IIRC we had a user agent format already for some other thing.
+ let client_agent = format!(
+ "Binary Ninja/{}.{}.{}",
+ version_info.major, version_info.minor, version_info.build
+ );
+ // TODO: This might want to be kept for the request header?
+ let mut headers = HeaderMap::new();
+ if let Some(token) = &server_token {
+ headers.insert(
+ AUTHORIZATION,
+ HeaderValue::from_str(&format!("Bearer {}", token)).unwrap(),
+ );
+ }
+ // TODO: Configurable timeout?
+ let mut client_builder = Client::builder()
+ .connect_timeout(std::time::Duration::from_secs(10))
+ .default_headers(headers)
+ .user_agent(client_agent);
+ if let Some(https_proxy) = https_proxy {
+ client_builder = client_builder.proxy(reqwest::Proxy::all(&https_proxy)?);
+ }
+ Ok(Self {
+ client: client_builder.build()?,
+ server_url,
+ })
+ }
+
+ /// Check to see the status of the server.
+ ///
+ /// This is useful if you want to fail early and prevent constructing a network container to a
+ /// server that is unresponsive.
+ ///
+ /// Route: `api/v1/status`
+ pub fn status(&self) -> reqwest::Result<StatusCode> {
+ let status_url = format!("{}/api/v1/status", self.server_url);
+ let resp = self.client.get(&status_url).send()?;
+ Ok(resp.status())
+ }
+
+ /// Query the [`NetworkTargetId`] for the given [`Target`].
+ ///
+ /// NOTE: **THIS IS BLOCKING**
+ ///
+ /// Route: `api/v1/targets/query` (TODO: Comment about the query)
+ pub fn query_target_id(&self, target: &Target) -> Option<NetworkTargetId> {
+ let query_target_url = format!("{}/api/v1/targets/query", self.server_url);
+
+ let mut query = HashMap::new();
+ if let Some(platform) = &target.platform {
+ query.insert("platform", platform);
+ }
+ if let Some(architecture) = &target.architecture {
+ query.insert("architecture", architecture);
+ }
+
+ // NOTE: This is blocking.
+ let target_id: NetworkTargetId = self
+ .client
+ .get(query_target_url)
+ .query(&query)
+ .send()
+ .ok()?
+ .json::<NetworkTargetId>()
+ .ok()?;
+
+ Some(target_id)
+ }
+
+ fn query_functions_body(
+ target: Option<NetworkTargetId>,
+ source: Option<SourceId>,
+ guids: &[FunctionGUID],
+ ) -> serde_json::Value {
+ let guids_str: Vec<String> = guids.iter().map(|g| g.to_string()).collect();
+ // TODO: The limit here needs to be somewhat flexible. But 1000 will do for now.
+ let mut body = json!({
+ "format": "flatbuffer",
+ "guids": guids_str,
+ "limit": 1000
+ });
+ if let Some(target_id) = target {
+ body["target_id"] = json!(target_id);
+ }
+ if let Some(source_id) = source {
+ body["source_id"] = json!(source_id.to_string());
+ }
+ body
+ }
+
+ /// Query the functions, returning the warp file response containing the entries.
+ ///
+ /// NOTE: **THIS IS BLOCKING**
+ ///
+ /// Route: `api/v1/functions/query` (TODO: Comment about the query)
+ pub fn query_functions(
+ &self,
+ target: Option<NetworkTargetId>,
+ source: Option<SourceId>,
+ guids: &[FunctionGUID],
+ ) -> Option<WarpFile<'static>> {
+ let query_functions_url = format!("{}/api/v1/functions/query", self.server_url);
+ let payload = Self::query_functions_body(target, source, guids);
+
+ // Make the POST request
+ let response = self
+ .client
+ .post(&query_functions_url)
+ .json(&payload)
+ .send()
+ .ok()?;
+ if !response.status().is_success() {
+ log::error!("Failed to query functions: {}", response.status());
+ return None;
+ }
+
+ // Get response bytes and convert to WarpFile
+ let bytes = response.bytes().ok()?;
+ WarpFile::from_owned_bytes(bytes.to_vec())
+ }
+
+ /// Query the functions, returning the sources and the corresponding function guids.
+ ///
+ /// NOTE: **THIS IS BLOCKING**
+ ///
+ /// Route: `api/v1/functions/query/source` (TODO: Comment about the query)
+ pub fn query_functions_source(
+ &self,
+ target: Option<NetworkTargetId>,
+ guids: &[FunctionGUID],
+ ) -> Option<HashMap<SourceId, Vec<FunctionGUID>>> {
+ let query_functions_source_url =
+ format!("{}/api/v1/functions/query/source", self.server_url);
+ let payload = Self::query_functions_body(target, None, guids);
+
+ // Make the POST request
+ let response = self
+ .client
+ .post(&query_functions_source_url)
+ .json(&payload)
+ .send()
+ .ok()?;
+ if !response.status().is_success() {
+ log::error!("Failed to query functions source: {}", response.status());
+ return None;
+ }
+
+ // Mapping of source id to function guids
+ let json_response: HashMap<String, Vec<String>> = response.json().ok()?;
+ let mapped_function_guids = json_response
+ .into_iter()
+ .filter_map(|(source_str, guid_strs)| {
+ let source_id = SourceId::from_str(&source_str).ok()?;
+ let guids = guid_strs
+ .into_iter()
+ .filter_map(|guid_str| FunctionGUID::from_str(&guid_str).ok())
+ .collect();
+ Some((source_id, guids))
+ })
+ .collect();
+
+ Some(mapped_function_guids)
+ }
+
+ /// Pushes the file to the remote source.
+ ///
+ /// NOTE: **THIS IS BLOCKING**
+ ///
+ /// Route: `api/v1/files/{source}`
+ pub fn push_file(&self, source_id: SourceId, file: &WarpFile) -> bool {
+ let push_file_url = format!("{}/api/v1/files/{}", self.server_url, source_id.to_string());
+
+ // Convert WarpFile to bytes
+ let file_bytes = file.to_bytes();
+
+ // Create the form part with the file
+ let form = reqwest::blocking::multipart::Form::new().part(
+ "file",
+ reqwest::blocking::multipart::Part::bytes(file_bytes)
+ .file_name("data.warp")
+ .mime_str("application/octet-stream")
+ .unwrap(),
+ );
+
+ // Send the request
+ match self.client.post(&push_file_url).multipart(form).send() {
+ Ok(response) => {
+ if response.status().is_success() {
+ true
+ } else {
+ log::error!("Failed to push file: {}", response.status());
+ false
+ }
+ }
+ Err(e) => {
+ log::error!("Failed to send push request: {}", e);
+ false
+ }
+ }
+ }
+}
diff --git a/plugins/warp/src/plugin.rs b/plugins/warp/src/plugin.rs
index 3380c619..7f0481b8 100644
--- a/plugins/warp/src/plugin.rs
+++ b/plugins/warp/src/plugin.rs
@@ -3,6 +3,7 @@ use std::time::Instant;
use crate::cache::container::add_cached_container;
use crate::container::disk::DiskContainer;
+use crate::container::network::{NetworkClient, NetworkContainer};
use crate::matcher::MatcherSettings;
use crate::plugin::render_layer::HighlightRenderLayer;
use crate::plugin::settings::PluginSettings;
@@ -11,9 +12,11 @@ use binaryninja::background_task::BackgroundTask;
use binaryninja::command::{
register_command, register_command_for_function, register_command_for_project,
};
+use binaryninja::is_ui_enabled;
use binaryninja::logger::Logger;
use binaryninja::settings::Settings;
use log::LevelFilter;
+use reqwest::StatusCode;
mod create;
mod debug;
@@ -26,6 +29,63 @@ mod render_layer;
mod settings;
mod workflow;
+fn load_bundled_signatures() {
+ let global_bn_settings = Settings::new();
+ let plugin_settings = PluginSettings::from_settings(&global_bn_settings);
+ // We want to load all the bundled directories into the container cache.
+ let background_task = BackgroundTask::new("Loading WARP files...", false);
+ let start = Instant::now();
+ if plugin_settings.load_bundled_files {
+ let core_disk_container = DiskContainer::new_from_dir(core_signature_dir());
+ log::debug!("{:#?}", core_disk_container);
+ add_cached_container(core_disk_container);
+ }
+ if plugin_settings.load_user_files {
+ let user_disk_container = DiskContainer::new_from_dir(user_signature_dir());
+ log::debug!("{:#?}", user_disk_container);
+ add_cached_container(user_disk_container);
+ }
+ log::info!("Loading bundled files took {:?}", start.elapsed());
+ background_task.finish();
+}
+
+fn load_network_container() {
+ let global_bn_settings = Settings::new();
+ let plugin_settings = PluginSettings::from_settings(&global_bn_settings);
+ let background_task = BackgroundTask::new("Initializing WARP server...", false);
+ let start = Instant::now();
+ if plugin_settings.enable_server {
+ let server_url = plugin_settings.server_url.clone();
+ let server_api_key = plugin_settings.server_api_key.clone();
+ let https_proxy_str = global_bn_settings.get_string("network.httpsProxy");
+ let https_proxy = if https_proxy_str.is_empty() {
+ None
+ } else {
+ Some(https_proxy_str)
+ };
+ match NetworkClient::new(server_url.clone(), server_api_key, https_proxy) {
+ Ok(network_client) => {
+ // Before constructing the container, let's make sure that the server is OK.
+ if let Ok(StatusCode::OK) = network_client.status() {
+ let network_container = NetworkContainer::new(network_client);
+ log::debug!("{:#?}", network_container);
+ add_cached_container(network_container);
+ } else {
+ log::error!(
+ "Server '{}' is not reachable, disabling container...",
+ server_url
+ );
+ }
+ }
+ Err(e) => {
+ log::error!("Failed to add networked container: {}", e);
+ }
+ }
+ }
+ log::debug!("Initializing warp server took {:?}", start.elapsed());
+ background_task.finish();
+}
+
#[no_mangle]
#[allow(non_snake_case)]
pub extern "C" fn CorePluginInit() -> bool {
@@ -44,22 +104,21 @@ pub extern "C" fn CorePluginInit() -> bool {
workflow::insert_workflow();
- let plugin_settings = PluginSettings::from_settings(&global_bn_settings);
- // We want to load all the bundled directories into the container cache.
- let background_task = BackgroundTask::new("Loading WARP files...", false);
- let start = Instant::now();
- if plugin_settings.load_bundled_files {
- let core_disk_container = DiskContainer::new_from_dir(core_signature_dir());
- log::debug!("{:#?}", core_disk_container);
- add_cached_container(core_disk_container);
+ // TODO: Make the retrieval of containers wait on this to be done.
+ // TODO: We could also have a mechanism for lazily loading the files using the chunk header target.
+ // Loading bundled signatures might take a few hundred milliseconds.
+ if is_ui_enabled() {
+ std::thread::spawn(|| {
+ load_bundled_signatures();
+ load_network_container();
+ });
+ } else {
+ load_bundled_signatures();
+ std::thread::spawn(|| {
+ // Dependence on this is likely to not matter in headless, so we throw it on another thread.
+ load_network_container();
+ });
}
- if plugin_settings.load_user_files {
- let user_disk_container = DiskContainer::new_from_dir(user_signature_dir());
- log::debug!("{:#?}", user_disk_container);
- add_cached_container(user_disk_container);
- }
- log::info!("Loading bundled files took {:?}", start.elapsed());
- background_task.finish();
register_command(
"WARP\\Run Matcher",
diff --git a/plugins/warp/src/plugin/ffi/container.rs b/plugins/warp/src/plugin/ffi/container.rs
index 21ad4dc0..4de6bab3 100644
--- a/plugins/warp/src/plugin/ffi/container.rs
+++ b/plugins/warp/src/plugin/ffi/container.rs
@@ -36,6 +36,27 @@ pub unsafe extern "C" fn BNWARPContainerGetName(container: *mut BNWARPContainer)
}
#[no_mangle]
+pub unsafe extern "C" fn BNWARPContainerFetchFunctions(
+ container: *mut BNWARPContainer,
+ target: *mut BNWARPTarget,
+ guids: *const BNWARPFunctionGUID,
+ count: usize,
+) {
+ let arc_container = ManuallyDrop::new(Arc::from_raw(container));
+ let Ok(mut container) = arc_container.write() else {
+ return;
+ };
+
+ let target = unsafe { ManuallyDrop::new(Arc::from_raw(target)) };
+
+ let guids = unsafe { std::slice::from_raw_parts(guids, count) };
+
+ if let Err(e) = container.fetch_functions(&target, guids) {
+ log::error!("Failed to fetch functions: {}", e);
+ }
+}
+
+#[no_mangle]
pub unsafe extern "C" fn BNWARPContainerGetSources(
container: *mut BNWARPContainer,
count: *mut usize,
diff --git a/plugins/warp/src/plugin/settings.rs b/plugins/warp/src/plugin/settings.rs
index 6cd2e0cc..489deb23 100644
--- a/plugins/warp/src/plugin/settings.rs
+++ b/plugins/warp/src/plugin/settings.rs
@@ -19,7 +19,7 @@ pub struct PluginSettings {
/// The API key to use for the selected WARP server, if not specified, you will be unable to push data and may be rate-limited.
///
/// This is set to [PluginSettings::SERVER_API_KEY_DEFAULT] by default.
- pub server_api_key: String,
+ pub server_api_key: Option<String>,
/// Whether to allow networked WARP requests. Turning this off will not disable local WARP functionality.
///
/// This is set to [PluginSettings::ENABLE_SERVER_DEFAULT] by default.
@@ -33,9 +33,9 @@ impl PluginSettings {
pub const LOAD_USER_FILES_SETTING: &'static str = "analysis.warp.loadUserFiles";
pub const SERVER_URL_DEFAULT: &'static str = "https://warp.binary.ninja";
pub const SERVER_URL_SETTING: &'static str = "analysis.warp.serverUrl";
- pub const SERVER_API_KEY_DEFAULT: &'static str = "";
+ pub const SERVER_API_KEY_DEFAULT: Option<String> = None;
pub const SERVER_API_KEY_SETTING: &'static str = "analysis.warp.serverApiKey";
- pub const ENABLE_SERVER_DEFAULT: bool = true;
+ pub const ENABLE_SERVER_DEFAULT: bool = false;
pub const ENABLE_SERVER_SETTING: &'static str = "network.enableWARP";
pub fn register(bn_settings: &mut BNSettings) {
@@ -44,7 +44,8 @@ impl PluginSettings {
"type" : "boolean",
"default" : Self::LOAD_BUNDLED_FILES_DEFAULT,
"description" : "Whether to load bundled WARP files on startup. Turn this off if you want to manually load them.",
- "ignore" : ["SettingsProjectScope", "SettingsResourceScope"]
+ "ignore" : ["SettingsProjectScope", "SettingsResourceScope"],
+ "requiresRestart" : true
});
bn_settings.register_setting_json(
Self::LOAD_BUNDLED_FILES_SETTING,
@@ -55,7 +56,8 @@ impl PluginSettings {
"type" : "boolean",
"default" : Self::LOAD_USER_FILES_DEFAULT,
"description" : "Whether to load user WARP files on startup. Turn this off if you want to manually load them.",
- "ignore" : ["SettingsProjectScope", "SettingsResourceScope"]
+ "ignore" : ["SettingsProjectScope", "SettingsResourceScope"],
+ "requiresRestart" : true
});
bn_settings.register_setting_json(
Self::LOAD_USER_FILES_SETTING,
@@ -66,7 +68,8 @@ impl PluginSettings {
"type" : "string",
"default" : Self::SERVER_URL_DEFAULT,
"description" : "The WARP server to use.",
- "ignore" : ["SettingsProjectScope", "SettingsResourceScope"]
+ "ignore" : ["SettingsProjectScope", "SettingsResourceScope"],
+ "requiresRestart" : true
});
bn_settings.register_setting_json(Self::SERVER_URL_SETTING, &server_url_prop.to_string());
let server_api_key_prop = json!({
@@ -75,7 +78,8 @@ impl PluginSettings {
"default" : Self::SERVER_API_KEY_DEFAULT,
"description" : "The API key to use for the selected WARP server, if not specified you will be unable to push data, and may be rate limited.",
"ignore" : ["SettingsProjectScope", "SettingsResourceScope"],
- "hidden": true
+ "hidden": true,
+ "requiresRestart" : true
});
bn_settings.register_setting_json(
Self::SERVER_API_KEY_SETTING,
@@ -86,7 +90,8 @@ impl PluginSettings {
"type" : "boolean",
"default" : Self::ENABLE_SERVER_DEFAULT,
"description" : "Whether or not to allow networked WARP requests. Turning this off will not disable local WARP functionality.",
- "ignore" : ["SettingsProjectScope", "SettingsResourceScope"]
+ "ignore" : ["SettingsProjectScope", "SettingsResourceScope"],
+ "requiresRestart" : true
});
bn_settings.register_setting_json(
Self::ENABLE_SERVER_SETTING,
@@ -107,7 +112,10 @@ impl PluginSettings {
settings.server_url = bn_settings.get_string(Self::SERVER_URL_SETTING);
}
if bn_settings.contains(Self::SERVER_API_KEY_SETTING) {
- settings.server_url = bn_settings.get_string(Self::SERVER_API_KEY_SETTING);
+ let server_api_key_str = bn_settings.get_string(Self::SERVER_API_KEY_SETTING);
+ if !server_api_key_str.is_empty() {
+ settings.server_api_key = Some(server_api_key_str);
+ }
}
if bn_settings.contains(Self::ENABLE_SERVER_SETTING) {
settings.enable_server = bn_settings.get_bool(Self::ENABLE_SERVER_SETTING);
@@ -122,7 +130,7 @@ impl Default for PluginSettings {
load_bundled_files: PluginSettings::LOAD_BUNDLED_FILES_DEFAULT,
load_user_files: PluginSettings::LOAD_USER_FILES_DEFAULT,
server_url: PluginSettings::SERVER_URL_DEFAULT.to_string(),
- server_api_key: PluginSettings::SERVER_API_KEY_DEFAULT.to_string(),
+ server_api_key: PluginSettings::SERVER_API_KEY_DEFAULT,
enable_server: PluginSettings::ENABLE_SERVER_DEFAULT,
}
}
diff --git a/plugins/warp/src/plugin/workflow.rs b/plugins/warp/src/plugin/workflow.rs
index 2d76222c..c2f82bd9 100644
--- a/plugins/warp/src/plugin/workflow.rs
+++ b/plugins/warp/src/plugin/workflow.rs
@@ -60,6 +60,15 @@ impl Command for RunMatcher {
fn action(&self, view: &BinaryView) {
let view = view.to_owned();
std::thread::spawn(move || {
+ // For embedded targets the user may not have set the sections up.
+ // Alert the user if we have no actual regions (+1 comes from the synthetic section).
+ let regions = relocatable_regions(&view);
+ if regions.len() <= 1 && view.memory_map().is_activated() {
+ log::warn!(
+ "No relocatable regions found, for best results please define sections for the binary!"
+ );
+ }
+
run_matcher(&view);
});
}
@@ -75,14 +84,6 @@ pub fn run_matcher(view: &BinaryView) {
let _ = get_warp_tag_type(view);
view.file().forget_undo_actions(&undo_id);
- // Alert the user if we have no actual regions (one comes from the synthetic section).
- let regions = relocatable_regions(view);
- if regions.len() <= 1 && view.memory_map().is_activated() {
- log::warn!(
- "No relocatable regions found, for best results please define sections for the binary!"
- );
- }
-
// Then we want to actually find matching functions.
let background_task = BackgroundTask::new("Matching on WARP functions...", true);
let start = Instant::now();
diff --git a/plugins/warp/ui/matches.cpp b/plugins/warp/ui/matches.cpp
index fad729d6..ed77085a 100644
--- a/plugins/warp/ui/matches.cpp
+++ b/plugins/warp/ui/matches.cpp
@@ -5,6 +5,7 @@
#include <QClipboard>
#include <QFormLayout>
+#include <thread>
#include "theme.h"
#include "warp.h"
@@ -15,6 +16,8 @@ WarpCurrentFunctionWidget::WarpCurrentFunctionWidget(FunctionRef current)
// NOTE: Might be nullptr if the no selected function.
m_current = current;
+ m_logger = new BinaryNinja::Logger("WARP");
+
// Create the QT stuff
QGridLayout *layout = new QGridLayout(this);
layout->setContentsMargins(2, 2, 2, 2);
@@ -110,6 +113,26 @@ void WarpCurrentFunctionWidget::SetCurrentFunction(FunctionRef current)
return;
m_current = current;
m_infoWidget->SetAnalysisFunction(m_current);
+
+ if (current)
+ {
+ // Add the function to the processing list only if we have no already done so.
+ // If a user goes to a function, then navigates away, they do not want to
+ // have us try and send a network request!
+ {
+ std::lock_guard<std::mutex> lock(m_requestMutex);
+ uint64_t funcStart = current->GetStart();
+ if (m_processedFunctions.find(funcStart) == m_processedFunctions.end()) {
+ m_pendingRequests.push_back(current);
+ }
+ }
+ if (!m_requestInProgress.exchange(true)) {
+ BinaryNinja::WorkerPriorityEnqueue([this]() {
+ ProcessPendingFetchRequests();
+ });
+ }
+ }
+
UpdateMatches();
}
@@ -162,3 +185,51 @@ void WarpCurrentFunctionWidget::UpdateMatches()
m_tableWidget->SetFunctions(matches);
}
+
+void WarpCurrentFunctionWidget::ProcessPendingFetchRequests()
+{
+ std::vector<FunctionRef> requests;
+ {
+ std::lock_guard<std::mutex> lock(m_requestMutex);
+ requests = std::move(m_pendingRequests);
+ m_pendingRequests.clear();
+ }
+
+ if (requests.empty()) {
+ m_requestInProgress = false;
+ return;
+ }
+
+ auto start_time = std::chrono::high_resolution_clock::now();
+
+ std::vector<Warp::FunctionGUID> guids;
+ Warp::Ref<Warp::Target> target;
+ for (const auto& func : requests) {
+ // TODO: Need to send multiple requests if there is multiple targets.
+ if (!target)
+ target = Warp::Target::FromPlatform(*func->GetPlatform());
+ if (const auto guid = Warp::GetAnalysisFunctionGUID(*func); guid.has_value())
+ guids.push_back(guid.value());
+ }
+
+ // Actually fetch the data!
+ if (!guids.empty())
+ for (const auto &container: Warp::Container::All())
+ container->FetchFunctions(*target, guids);
+
+ {
+ std::lock_guard<std::mutex> lock(m_requestMutex);
+ for (const auto& func : requests) {
+ m_processedFunctions.insert(func->GetStart());
+ }
+ }
+
+ // TODO: Update the matches, make sure there was stuff added first lol.
+ // TODO: UpdateMatches();
+
+ const auto end_time = std::chrono::high_resolution_clock::now();
+ const std::chrono::duration<double> elapsed_time = end_time - start_time;
+ m_logger->LogDebug("ProcessPendingRequests took %f seconds", elapsed_time.count());
+
+ m_requestInProgress = false;
+}
diff --git a/plugins/warp/ui/matches.h b/plugins/warp/ui/matches.h
index 4021f10c..251dcb89 100644
--- a/plugins/warp/ui/matches.h
+++ b/plugins/warp/ui/matches.h
@@ -16,6 +16,13 @@ class WarpCurrentFunctionWidget : public QWidget
WarpFunctionTableWidget *m_tableWidget;
WarpFunctionInfoWidget *m_infoWidget;
+ LoggerRef m_logger;
+
+ std::mutex m_requestMutex;
+ std::vector<FunctionRef> m_pendingRequests;
+ std::atomic<bool> m_requestInProgress {false};
+ std::unordered_set<uint64_t> m_processedFunctions;
+
public:
explicit WarpCurrentFunctionWidget(FunctionRef current);
@@ -26,4 +33,6 @@ public:
FunctionRef GetCurrentFunction() { return m_current; };
void UpdateMatches();
+
+ void ProcessPendingFetchRequests();
};
diff --git a/plugins/warp/ui/plugin.cpp b/plugins/warp/ui/plugin.cpp
index 69aaaf34..923a79b3 100644
--- a/plugins/warp/ui/plugin.cpp
+++ b/plugins/warp/ui/plugin.cpp
@@ -170,6 +170,9 @@ void WarpSidebarWidget::notifyViewChanged(ViewFrame *view)
void WarpSidebarWidget::notifyViewLocationChanged(View *view, const ViewLocation &location)
{
+ // Warp sidebar really should only update if it is visible, otherwise its a waste of cycles.
+ if (!this->isVisible())
+ return;
auto function = location.getFunction();
// TODO: Only update if the function exists?
// NOTE: The function called will exit early if it is the same function.