Compare commits

..

1 Commits

Author SHA1 Message Date
2d8e696909 Failed experiment to use the event layer
Unfortunately the time stamps did not properly match up
2025-09-03 11:44:26 +02:00
39 changed files with 933 additions and 1081 deletions

3
.gitignore vendored
View File

@ -1,5 +1,2 @@
/target
*.log
/nyx_data
/KVM-Nyx-fork
/benchmarks

403
Cargo.lock generated
View File

@ -2,21 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -76,36 +61,12 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "anyhow"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
dependencies = [
"backtrace",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
]
[[package]]
name = "base-x"
version = "0.2.11"
@ -120,11 +81,11 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "bindgen"
version = "0.72.1"
version = "0.72.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.9.1",
"cexpr",
"clang-sys",
"itertools",
@ -135,7 +96,7 @@ dependencies = [
"regex",
"rustc-hash",
"shlex",
"syn 2.0.106",
"syn 2.0.104",
]
[[package]]
@ -146,9 +107,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.4"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "bumpalo"
@ -169,25 +130,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
dependencies = [
"clap",
"heck 0.4.1",
"heck",
"indexmap",
"log",
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn 2.0.106",
"syn 2.0.104",
"tempfile",
"toml",
]
[[package]]
name = "cc"
version = "1.2.36"
version = "1.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54"
checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
dependencies = [
"find-msvc-tools",
"shlex",
]
@ -202,9 +162,9 @@ dependencies = [
[[package]]
name = "cfg-if"
version = "1.0.3"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "clang-sys"
@ -219,19 +179,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.47"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931"
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.47"
version = "4.5.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6"
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
dependencies = [
"anstream",
"anstyle",
@ -239,18 +198,6 @@ dependencies = [
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "clap_lex"
version = "0.7.5"
@ -262,6 +209,7 @@ name = "client"
version = "0.1.0"
dependencies = [
"cc",
"libc",
]
[[package]]
@ -292,7 +240,7 @@ dependencies = [
[[package]]
name = "config"
version = "0.1.0"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#b2a71111ab428fb95055239efe84f6e81f86d4b7"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#d85fc2487a6427a0df699c7eaee37db70bc6858b"
dependencies = [
"libc",
"ron",
@ -306,27 +254,6 @@ version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f8a2ca5ac02d09563609681103aada9e1777d54fc57a5acd7a41404f9c93b6e"
[[package]]
name = "csv"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
[[package]]
name = "derivative"
version = "2.2.0"
@ -338,26 +265,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "discard"
version = "1.0.4"
@ -384,12 +291,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
dependencies = [
"libc",
"windows-sys 0.61.0",
"windows-sys 0.60.2",
]
[[package]]
@ -398,12 +305,6 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "find-msvc-tools"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
[[package]]
name = "fs4"
version = "0.5.4"
@ -417,7 +318,7 @@ dependencies = [
[[package]]
name = "fuzz_runner"
version = "0.1.0"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#b2a71111ab428fb95055239efe84f6e81f86d4b7"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#d85fc2487a6427a0df699c7eaee37db70bc6858b"
dependencies = [
"byteorder",
"colored",
@ -457,26 +358,20 @@ dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.5+wasi-0.2.4",
"wasi 0.14.2+wasi-0.2.4",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.3"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.15.5"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
@ -484,17 +379,11 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "indexmap"
version = "2.11.1"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921"
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
dependencies = [
"equivalent",
"hashbrown",
@ -529,21 +418,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.175"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libipt"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c3143c4dae9794d23fa2bbc6315847fdf3ef718caa09a7ba09238bce19fe9d4"
dependencies = [
"bitflags 2.9.4",
"derive_more",
"libipt-sys",
"num_enum",
]
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libipt-sys"
@ -568,7 +445,7 @@ dependencies = [
[[package]]
name = "libnyx"
version = "0.1.0"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#b2a71111ab428fb95055239efe84f6e81f86d4b7"
source = "git+https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork#d85fc2487a6427a0df699c7eaee37db70bc6858b"
dependencies = [
"cbindgen",
"config",
@ -578,15 +455,15 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "log"
version = "0.4.28"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
@ -596,9 +473,9 @@ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "memmap2"
version = "0.9.8"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7"
checksum = "483758ad303d734cec05e5c12b41d7e93e6a6390c5e9dae6bdeb7c1259012d28"
dependencies = [
"libc",
]
@ -618,15 +495,6 @@ 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 = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "nix"
version = "0.26.4"
@ -650,37 +518,6 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "num_enum"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
dependencies = [
"num_enum_derive",
"rustversion",
]
[[package]]
name = "num_enum_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -710,21 +547,12 @@ dependencies = [
[[package]]
name = "prettyplease"
version = "0.2.37"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2"
dependencies = [
"proc-macro2",
"syn 2.0.106",
]
[[package]]
name = "proc-macro-crate"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
"toml_edit",
"syn 2.0.104",
]
[[package]]
@ -735,9 +563,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
version = "1.0.101"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
@ -746,18 +574,14 @@ dependencies = [
name = "pt-dump-decoder"
version = "0.1.0"
dependencies = [
"libipt",
"libipt-sys",
"memmap2",
"raw-cpuid",
]
[[package]]
name = "qemu-nyx-runner"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"csv",
"libnyx",
"pt-dump-decoder",
]
@ -824,20 +648,11 @@ dependencies = [
"rand_core",
]
[[package]]
name = "raw-cpuid"
version = "11.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186"
dependencies = [
"bitflags 2.9.4",
]
[[package]]
name = "regex"
version = "1.11.2"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@ -847,9 +662,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.10"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@ -858,9 +673,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.6"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "ron"
@ -873,12 +688,6 @@ dependencies = [
"serde",
]
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
version = "2.1.1"
@ -896,22 +705,22 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.1.2"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
dependencies = [
"bitflags 2.9.4",
"bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.0",
"windows-sys 0.60.2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
[[package]]
name = "ryu"
@ -951,14 +760,14 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
"syn 2.0.104",
]
[[package]]
name = "serde_json"
version = "1.0.143"
version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [
"itoa",
"memchr",
@ -1104,9 +913,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.106"
version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@ -1115,15 +924,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.22.0"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.61.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1216,9 +1025,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "unicode-ident"
version = "1.0.19"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "utf8parse"
@ -1240,54 +1049,44 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.14.5+wasi-0.2.4"
version = "0.14.2+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4"
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
version = "1.0.0+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24"
dependencies = [
"wit-bindgen",
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.101"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.101"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn 2.0.106",
"syn 2.0.104",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.101"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -1295,22 +1094,22 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.101"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
"syn 2.0.104",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.101"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
@ -1343,12 +1142,6 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
[[package]]
name = "windows-sys"
version = "0.59.0"
@ -1367,15 +1160,6 @@ dependencies = [
"windows-targets 0.53.3",
]
[[package]]
name = "windows-sys"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
dependencies = [
"windows-link 0.2.0",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@ -1398,7 +1182,7 @@ version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link 0.1.3",
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
@ -1507,35 +1291,38 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.7.13"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen"
version = "0.45.1"
name = "wit-bindgen-rt"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
dependencies = [
"bitflags 2.9.1",
]
[[package]]
name = "zerocopy"
version = "0.8.27"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.27"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
"syn 2.0.104",
]

View File

@ -9,10 +9,4 @@ edition = "2024"
[dependencies]
libnyx = { git = "https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork" }
pt-dump-decoder = { path = "pt-dump-decoder" }
csv = "1.3.1"
clap.workspace = true
anyhow = { version = "1.0.99", features = ["backtrace"] }
[workspace.dependencies]
clap = { version = "4.5.47", features = ["derive"] }
pt-dump-decoder = { path = "pt-dump-decoder" }

View File

@ -1,12 +0,0 @@
# qemu-nyx-runner
This repository contains the source code of `qemu-nyx-runner`,
a tool which can be used to execute programs inside a `Nyx` hypervisor, trace them with `Intel PT`,
and analyze the resulting trace files to estimate its execution without all this instrumentation.
## Set Up
To use this project, `KVM-Nyx-fork`s kernel modules have to be installed and loaded.
use the `setup-kvm.sh` script for that.
To run a program with `qemu-nyx-runner`, use `cargo r --release -- path/to/program`

View File

@ -1,18 +0,0 @@
set -e
cargo build --workspace --release
echo "Disabling turbo..."
echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo
for file in client/src/bin/*.rs; do
bin_name=$(basename "$file" .rs)
bin_path=./target/release/${bin_name}
echo "Benchmarking $bin_name..."
sudo -E nice -n -20 taskset -c 0 ./target/release/qemu-nyx-runner "$bin_path"
done
echo 0 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo
echo "Done!"

102
build.rs Normal file
View File

@ -0,0 +1,102 @@
use std::env;
use std::path::Path;
use std::process::Command;
fn main() {
println!("cargo:rerun-if-changed=client");
let out_dir = env::var("OUT_DIR").unwrap();
let client_bin = build_client(&out_dir);
setup_nyx(&out_dir);
create_nyx_workdir(&out_dir, &client_bin);
}
#[track_caller]
fn shell(cwd: impl AsRef<Path>, command_string: &str) {
println!(
"cargo:warning=Running ({}) {command_string}",
cwd.as_ref().display()
);
let cwd = cwd.as_ref();
let mut parts = command_string.split(" ");
let command_name = parts.next().unwrap();
let mut command = Command::new(command_name);
command.current_dir(cwd);
command.stdout(std::process::Stdio::inherit());
command.stderr(std::process::Stdio::inherit());
command.args(parts);
let mut process = command.spawn().unwrap();
let exit_status = process.wait().unwrap();
if !exit_status.success() {
panic!(
"Command failed with {exit_status}: {}> {command_string}",
cwd.display()
);
}
}
/// Builds the client and returns the path to its binary
fn build_client(out_dir: &str) -> String {
// Change the target dir to avoid a cargo target dir deadlock
shell(
"client",
&format!("cargo build --release --target-dir {out_dir}/client_target"),
);
format!("{out_dir}/client_target/release/client")
}
/// Downloads and compiles qemu-nyx and packer and compiles them for the current architecture
/// This means that cross-compilation is not supported
fn setup_nyx(out_dir: &str) {
let packer_path = std::path::PathBuf::from(format!("{out_dir}/packer"));
let qemu_path = std::path::PathBuf::from(format!("{out_dir}/QEMU-Nyx"));
if !packer_path.exists() {
shell(out_dir, "git clone https://github.com/nyx-fuzz/packer/");
}
if !qemu_path.exists() {
println!("cargo:warning=Cloning and building QEMU-Nyx. This may take a while...");
shell(
out_dir,
// "git clone https://github.com/nyx-fuzz/QEMU-Nyx --depth 1",
"git clone /fs/scratch/smdavenh/bachelor-project/QEMU-Nyx --depth 1",
);
let is_debug_build = match env::var("DEBUG").unwrap().as_str() {
"true" => true,
"false" => false,
other => panic!("Invalid value for DEBUG: {other}"),
};
let qemu_compile_mode = if is_debug_build {
"debug_static"
} else {
"lto"
};
shell(
qemu_path,
&format!("bash compile_qemu_nyx.sh {qemu_compile_mode}"),
);
}
}
fn create_nyx_workdir(out_dir: &str, client_bin: &str) {
// Create the directory and move required binaries to it
shell(
out_dir,
&format!(
"python3 packer/packer/nyx_packer.py {client_bin} build afl processor_trace --fast_reload_mode --purge"
),
);
// Create the nyx config
shell(
out_dir,
"python3 packer/packer/nyx_config_gen.py build Kernel",
);
// Pass the path to the build directory to src/main.rs
println!("cargo:rustc-env=NYX_SHAREDIR={out_dir}/build")
}

View File

@ -3,5 +3,8 @@ name = "client"
version = "0.1.0"
edition = "2024"
[dependencies]
libc = "*"
[build-dependencies]
cc = "1.2.36"
cc = "1.0"

View File

@ -1,104 +1,5 @@
//! Somewhat hacky build script for downloading and linking embench.
//! Each benchmark is compiled individually, so that we can run them through rust
//! and add some instrumentation around the benchmarks.
use std::fmt::Write;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::{env, fs};
const BENCHMARKS: &[&str] = &[
"src/ud/libud.c",
"src/wikisort/libwikisort.c",
"src/nbody/nbody.c",
"src/edn/libedn.c",
// "src/st/libst.c", Collides with matmult-int
"src/aha-mont64/mont64.c",
"src/matmult-int/matmult-int.c",
"src/slre/libslre.c",
"src/tarfind/tarfind.c",
"src/sglib-combined/combined.c",
"src/huffbench/libhuffbench.c",
"src/nsichneu/libnsichneu.c",
"src/minver/libminver.c",
"src/statemate/libstatemate.c",
"src/crc32/crc_32.c",
// "src/picojpeg/libpicojpeg.c", Contains multiple source fails, maybe a todo if relevant
"src/cubic/basicmath_small.c",
"src/md5sum/md5.c",
"src/qrduino/qrtest.c",
"src/nettle-aes/nettle-aes.c",
"src/primecount/primecount.c",
"src/nettle-sha256/nettle-sha256.c",
];
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=nyx-wrapper.c");
let out_dir = env::var("OUT_DIR").unwrap();
Command::new("git")
.args(["clone", "https://github.com/embench/embench-iot"])
.current_dir(&out_dir)
.spawn()
.unwrap()
.wait()
.unwrap();
let embench_dir = PathBuf::from_str(&format!("{out_dir}/embench-iot")).unwrap();
let mut generated_code = String::new();
for &benchmark_file in BENCHMARKS {
let path = embench_dir.join(benchmark_file);
let dir = path.parent().unwrap();
let benchmark_name = dir.file_name().unwrap().to_string_lossy().replace("-", "_");
let mut build = cc::Build::new();
build
.include(embench_dir.join("support"))
.file(embench_dir.join("support/beebsc.c"))
.file(&path)
.warnings(false)
// Just use some roughly accurate value, it just influences how long each benchmark runs
.define("CPU_MHZ", "2700");
// Rename all functions that are defined multiple times to avoid collisions
let colliding_functions = [
"benchmark",
"initialise_benchmark",
"warm_caches",
"verify_benchmark",
];
for name in colliding_functions {
build.define(name, format!("{benchmark_name}_{name}").as_str());
}
build.compile(&format!("libembench_{benchmark_name}.a"));
write!(
generated_code,
r#"
#[allow(non_camel_case_types)] pub struct {benchmark_name};
unsafe extern "C" {{
fn {benchmark_name}_benchmark();
fn {benchmark_name}_initialise_benchmark();
}}
impl Benchmark for {benchmark_name} {{
unsafe fn init() {{
unsafe {{ {benchmark_name}_initialise_benchmark(); }}
}}
unsafe fn benchmark() {{
unsafe {{ {benchmark_name}_benchmark(); }}
}}
}}
"#
)
.unwrap();
}
fs::write(format!("{out_dir}/libembench-sys.rs"), generated_code).unwrap();
cc::Build::new().file("nyx-wrapper.c").compile("nyx");
}

9
client/nyx-wrapper.c Normal file
View File

@ -0,0 +1,9 @@
#include "nyx.h"
void rust_hprintf(const char * format) {
hprintf(format);
}
uint32_t rust_perform_hypercall(uint32_t hypercall, uint32_t argument) {
return kAFL_hypercall(hypercall, argument);
}

372
client/nyx.h Normal file
View File

@ -0,0 +1,372 @@
/*
This file is part of NYX.
Copyright (c) 2021 Sergej Schumilo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef KAFL_USER_H
#define KAFL_USER_H
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#ifndef __MINGW64__
#include <sys/mman.h>
#endif
#ifdef __MINGW64__
#ifndef uint64_t
#define uint64_t UINT64
#endif
#ifndef int32_t
#define int32_t INT32
#endif
#ifndef uint8_t
#define uint8_t UINT8
#endif
#else
#include <stdint.h>
#endif
#define HYPERCALL_KAFL_RAX_ID 0x01f
#define HYPERCALL_KAFL_ACQUIRE 0
#define HYPERCALL_KAFL_GET_PAYLOAD 1
/* deprecated */
#define HYPERCALL_KAFL_GET_PROGRAM 2
/* deprecated */
#define HYPERCALL_KAFL_GET_ARGV 3
#define HYPERCALL_KAFL_RELEASE 4
#define HYPERCALL_KAFL_SUBMIT_CR3 5
#define HYPERCALL_KAFL_SUBMIT_PANIC 6
/* deprecated */
#define HYPERCALL_KAFL_SUBMIT_KASAN 7
#define HYPERCALL_KAFL_PANIC 8
/* deprecated */
#define HYPERCALL_KAFL_KASAN 9
#define HYPERCALL_KAFL_LOCK 10
/* deprecated */
#define HYPERCALL_KAFL_INFO 11
#define HYPERCALL_KAFL_NEXT_PAYLOAD 12
#define HYPERCALL_KAFL_PRINTF 13
/* deprecated */
#define HYPERCALL_KAFL_PRINTK_ADDR 14
/* deprecated */
#define HYPERCALL_KAFL_PRINTK 15
/* user space only hypercalls */
#define HYPERCALL_KAFL_USER_RANGE_ADVISE 16
#define HYPERCALL_KAFL_USER_SUBMIT_MODE 17
#define HYPERCALL_KAFL_USER_FAST_ACQUIRE 18
/* 19 is already used for exit reason KVM_EXIT_KAFL_TOPA_MAIN_FULL */
#define HYPERCALL_KAFL_USER_ABORT 20
#define HYPERCALL_KAFL_RANGE_SUBMIT 29
#define HYPERCALL_KAFL_REQ_STREAM_DATA 30
#define HYPERCALL_KAFL_PANIC_EXTENDED 32
#define HYPERCALL_KAFL_CREATE_TMP_SNAPSHOT 33
#define HYPERCALL_KAFL_DEBUG_TMP_SNAPSHOT 34 /* hypercall for debugging / development purposes */
#define HYPERCALL_KAFL_GET_HOST_CONFIG 35
#define HYPERCALL_KAFL_SET_AGENT_CONFIG 36
#define HYPERCALL_KAFL_DUMP_FILE 37
#define HYPERCALL_KAFL_REQ_STREAM_DATA_BULK 38
#define HYPERCALL_KAFL_PERSIST_PAGE_PAST_SNAPSHOT 39
/* hypertrash only hypercalls */
#define HYPERTRASH_HYPERCALL_MASK 0xAA000000
#define HYPERCALL_KAFL_NESTED_PREPARE (0 | HYPERTRASH_HYPERCALL_MASK)
#define HYPERCALL_KAFL_NESTED_CONFIG (1 | HYPERTRASH_HYPERCALL_MASK)
#define HYPERCALL_KAFL_NESTED_ACQUIRE (2 | HYPERTRASH_HYPERCALL_MASK)
#define HYPERCALL_KAFL_NESTED_RELEASE (3 | HYPERTRASH_HYPERCALL_MASK)
#define HYPERCALL_KAFL_NESTED_HPRINTF (4 | HYPERTRASH_HYPERCALL_MASK)gre
#define HPRINTF_MAX_SIZE 0x1000 /* up to 4KB hprintf strings */
/* specific defines to enable support for NYX hypercalls on unmodified KVM builds */
/* PIO port number used by VMWare backdoor */
#define VMWARE_PORT 0x5658
/* slightly changed RAX_ID to avoid vmware backdoor collisions */
#define HYPERCALL_KAFL_RAX_ID_VMWARE 0x8080801f
typedef struct{
int32_t size;
uint8_t data[];
} kAFL_payload;
typedef struct{
uint64_t ip[4];
uint64_t size[4];
uint8_t enabled[4];
} kAFL_ranges;
#define KAFL_MODE_64 0
#define KAFL_MODE_32 1
#define KAFL_MODE_16 2
#if defined(__i386__)
#define KAFL_HYPERCALL_NO_PT(_ebx, _ecx) ({ \
uint32_t _eax = HYPERCALL_KAFL_RAX_ID_VMWARE; \
do{ \
asm volatile( \
"outl %%eax, %%dx;" \
: "+a" (_eax) \
: "b" (_ebx), "c" (_ecx), "d" (VMWARE_PORT) \
: "cc", "memory" \
); \
} while(0); \
_eax; \
})
#define KAFL_HYPERCALL_PT(_ebx, _ecx) ({ \
uint32_t _eax = HYPERCALL_KAFL_RAX_ID; \
do{ \
asm volatile( \
"vmcall;" \
: "+a" (_eax) \
: "b" (_ebx), "c" (_ecx) \
: "cc", "memory" \
); \
} while(0); \
_eax; \
})
#else
#define KAFL_HYPERCALL_NO_PT(_rbx, _rcx) ({ \
uint64_t _rax = HYPERCALL_KAFL_RAX_ID_VMWARE; \
do{ \
asm volatile( \
"outl %%eax, %%dx;" \
: "+a" (_rax) \
: "b" (_rbx), "c" (_rcx), "d" (VMWARE_PORT) \
: "cc", "memory" \
); \
} while(0); \
_rax; \
})
#define KAFL_HYPERCALL_PT(_rbx, _rcx) ({ \
uint64_t _rax = HYPERCALL_KAFL_RAX_ID; \
do{ \
asm volatile( \
"vmcall;" \
: "+a" (_rax) \
: "b" (_rbx), "c" (_rcx) \
: "cc", "memory" \
); \
} while(0); \
_rax; \
})
#endif
#if defined(__i386__)
#ifdef NO_PT_NYX
#define KAFL_HYPERCALL(__rbx, __rcx) \
KAFL_HYPERCALL_NO_PT(_rbx, _rcx); \
}while(0)
static inline uint32_t kAFL_hypercall(uint32_t rbx, uint32_t rcx){
return KAFL_HYPERCALL_NO_PT(rbx, rcx);
}
#else
#define KAFL_HYPERCALL(__rbx, __rcx) \
KAFL_HYPERCALL_PT(_rbx, _rcx); \
}while(0)
static inline uint32_t kAFL_hypercall(uint32_t rbx, uint32_t rcx){
# ifndef __NOKAFL
return KAFL_HYPERCALL_PT(rbx, rcx);
# endif
return 0;
}
#endif
#elif defined(__x86_64__)
#ifdef NO_PT_NYX
#define KAFL_HYPERCALL(__rbx, __rcx) \
KAFL_HYPERCALL_NO_PT(_rbx, _rcx); \
}while(0)
static inline uint64_t kAFL_hypercall(uint64_t rbx, uint64_t rcx){
return KAFL_HYPERCALL_NO_PT(rbx, rcx);
}
#else
#define KAFL_HYPERCALL(__rbx, __rcx) \
KAFL_HYPERCALL_PT(_rbx, _rcx); \
}while(0)
static inline uint64_t kAFL_hypercall(uint64_t rbx, uint64_t rcx){
# ifndef __NOKAFL
return KAFL_HYPERCALL_PT(rbx, rcx);
# endif
return 0;
}
#endif
#endif
//extern uint8_t* hprintf_buffer;
static inline uint8_t alloc_hprintf_buffer(uint8_t** hprintf_buffer){
if(!*hprintf_buffer){
#ifdef __MINGW64__
*hprintf_buffer = (uint8_t*)VirtualAlloc(0, HPRINTF_MAX_SIZE, MEM_COMMIT, PAGE_READWRITE);
#else
*hprintf_buffer = (uint8_t*)mmap((void*)NULL, HPRINTF_MAX_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
#endif
if(!*hprintf_buffer){
return 0;
}
}
return 1;
}
#ifdef __NOKAFL
int (*hprintf)(const char * format, ...) = printf;
#else
static void hprintf(const char * format, ...) __attribute__ ((unused));
static void hprintf(const char * format, ...){
static uint8_t* hprintf_buffer = NULL;
va_list args;
va_start(args, format);
if(alloc_hprintf_buffer(&hprintf_buffer)){
vsnprintf((char*)hprintf_buffer, HPRINTF_MAX_SIZE, format, args);
kAFL_hypercall(HYPERCALL_KAFL_PRINTF, (uintptr_t)hprintf_buffer);
}
//vprintf(format, args);
va_end(args);
}
#endif
static void habort(char* msg){
kAFL_hypercall(HYPERCALL_KAFL_USER_ABORT, (uintptr_t)msg);
}
#define NYX_HOST_MAGIC 0x4878794e
#define NYX_AGENT_MAGIC 0x4178794e
#define NYX_HOST_VERSION 2
#define NYX_AGENT_VERSION 1
typedef struct host_config_s{
uint32_t host_magic;
uint32_t host_version;
uint32_t bitmap_size;
uint32_t ijon_bitmap_size;
uint32_t payload_buffer_size;
uint32_t worker_id;
/* more to come */
} __attribute__((packed)) host_config_t;
typedef struct agent_config_s{
uint32_t agent_magic;
uint32_t agent_version;
uint8_t agent_timeout_detection;
uint8_t agent_tracing;
uint8_t agent_ijon_tracing;
uint8_t agent_non_reload_mode;
uint64_t trace_buffer_vaddr;
uint64_t ijon_trace_buffer_vaddr;
uint32_t coverage_bitmap_size;
uint32_t input_buffer_size; // TODO: remove this later
uint8_t dump_payloads; /* set by hypervisor */
/* more to come */
} __attribute__((packed)) agent_config_t;
typedef struct kafl_dump_file_s{
uint64_t file_name_str_ptr;
uint64_t data_ptr;
uint64_t bytes;
uint8_t append;
} __attribute__((packed)) kafl_dump_file_t;
enum nyx_cpu_type{
unkown = 0,
nyx_cpu_v1, /* Nyx CPU used by KVM-PT */
nyx_cpu_v2 /* Nyx CPU used by vanilla KVM + VMWare backdoor */
};
#define cpuid(in,a,b,c,d)\
asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
static int is_nyx_vcpu(void){
unsigned long eax,ebx,ecx,edx;
char str[8];
cpuid(0x80000004,eax,ebx,ecx,edx);
for(int j=0;j<4;j++){
str[j] = eax >> (8*j);
str[j+4] = ebx >> (8*j);
}
return !memcmp(&str, "NYX vCPU", 8);
}
static int get_nyx_cpu_type(void){
unsigned long eax,ebx,ecx,edx;
char str[9];
cpuid(0x80000004,eax,ebx,ecx,edx);
for(int j=0;j<4;j++){
str[j] = eax >> (8*j);
str[j+4] = ebx >> (8*j);
}
if(memcmp(&str, "NYX vCPU", 8) != 0){
return unkown;
}
for(int j=0;j<4;j++){
str[j] = ecx >> (8*j);
str[j+4] = edx >> (8*j);
}
if(memcmp(&str, " (NO-PT)", 8) != 0){
return nyx_cpu_v1;
}
return nyx_cpu_v2;
str[8] = 0;
printf("ECX: %s\n", str);
}
typedef struct req_data_bulk_s{
char file_name[256];
uint64_t num_addresses;
uint64_t addresses[479];
} req_data_bulk_t;
#endif

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::sglib_combined>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::crc32>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::edn>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::huffbench>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::matmult_int>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::md5sum>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::minver>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::aha_mont64>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::nbody>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::nettle_aes>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::nettle_sha256>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::nsichneu>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::primecount>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::slre>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::statemate>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::tarfind>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::ud>();
}

View File

@ -1,5 +0,0 @@
use client::program;
fn main() {
program::<client::embench_sys::wikisort>();
}

View File

@ -1,32 +0,0 @@
use std::arch::asm;
pub mod embench_sys {
pub trait Benchmark {
unsafe fn init();
unsafe fn benchmark();
}
include!(concat!(env!("OUT_DIR"), "/libembench-sys.rs"));
}
pub use embench_sys::Benchmark;
fn ptwrite(val: u32) {
unsafe {
asm!("ptwrite {0:e}", in(reg) val);
}
}
pub fn program<B: Benchmark>() {
unsafe {
B::init();
}
let start = std::time::Instant::now();
ptwrite(42);
unsafe {
B::benchmark();
}
ptwrite(43);
println!("{}", start.elapsed().as_secs_f64());
}

55
client/src/main.rs Normal file
View File

@ -0,0 +1,55 @@
use std::arch::asm;
use std::ffi::{CStr, CString};
unsafe extern "C" {
fn rust_hprintf(format: *const libc::c_char);
fn rust_perform_hypercall(hypercall: u32, argument: u32);
}
fn hprint(message: &CStr) {
unsafe {
rust_hprintf(message.as_ptr());
}
}
enum NyxHypercall {
Acquire = 0,
// Release = 4,
// Panic = 8,
}
fn hypercall(hypercall: NyxHypercall, argument: u32) {
unsafe {
rust_perform_hypercall(hypercall as u32, argument);
}
}
fn ptwrite(val: u32) {
unsafe {
asm!("ptwrite {0:e}", in(reg) val);
}
}
fn main() {
hprint(c"Acuiring again!\n");
hypercall(NyxHypercall::Acquire, 100);
let start = std::time::Instant::now();
let mut last_time = std::time::Duration::ZERO;
ptwrite(42);
loop {
let elapsed = start.elapsed();
if elapsed.as_secs() >= 2 {
let msg = CString::new(format!("Passed: {:?}\n", elapsed.as_secs())).unwrap();
let msg: &'static CStr = Box::leak(Box::new(msg));
hprint(msg);
break;
}
if last_time.as_secs() != elapsed.as_secs() {
hprint(c"A second passed\n");
}
last_time = elapsed;
}
ptwrite(43);
hprint(c"Done\n");
}

View File

@ -7,6 +7,6 @@ edition = "2024"
[dependencies]
libipt = { version = "0.4.0", features = ["libipt_master"] }
#libipt = { version = "0.4.0", features = ["libipt_master"] }
libipt-sys = "0.2.4"
memmap2 = "0.9.7"
raw-cpuid = "11.5.0"

View File

@ -1,8 +1,4 @@
use libipt::enc_dec_builder::EncoderDecoderBuilder;
use libipt::packet::{Packet, PacketDecoder};
use memmap2::Mmap;
use raw_cpuid::{CpuId, cpuid};
use std::collections::HashMap;
use std::error::Error;
use std::fs::File;
use std::path::Path;
@ -10,131 +6,278 @@ use std::time::Duration;
#[derive(Debug)]
pub struct AnalyzeData {
pub packets: u64,
pub lost_cyc: u64,
pub time_qemu: Duration,
pub time_tsc: Duration,
pub time_cyc: Duration,
pub time_main: Duration,
pub total_time: Duration,
pub time_in_client: Duration,
}
#[derive(Debug, Eq, PartialEq)]
enum Scope {
#[derive(Debug, Clone)]
struct Scope {
kind: ScopeKind,
start_tsc: u64,
end_tsc: u64,
}
impl Scope {
#[track_caller]
fn new(kind: ScopeKind, start_tsc: u64, end_tsc: u64) -> Self {
assert!(
start_tsc <= end_tsc,
"start_tsc {start_tsc} is greater than end_tsc {end_tsc}"
);
Self {
kind,
start_tsc,
end_tsc,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ScopeKind {
Main,
PreRun,
PostRun,
PacketGenerationDisabled,
}
pub fn analyze_dump(
path: impl AsRef<Path>,
qemu_duration: Duration,
) -> Result<AnalyzeData, Box<dyn Error>> {
const PT_EVENT_ENABLED: u32 = 0;
const PT_EVENT_DISABLED: u32 = 1;
const PT_EVENT_ASYNC_DISABLED: u32 = 2;
const PT_EVENT_PTWRITE: u32 = 16;
#[derive(Debug, Clone, Copy)]
enum DecoderState {
Enabled {
kind: ScopeKind,
start_tsc: u64,
},
Disabled {
enabled_kind: ScopeKind,
start_tsc: Option<u64>,
},
}
pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
let trace_file = File::open(path)?;
// Safety: We only read from the trace file, never write to it
// UB occurs when it is modified out-of-process, though
let mmap = unsafe { Mmap::map(&trace_file)? };
let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
// Safety: The mmap outlives the builder
let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
let mut events = vec![];
let mut state = DecoderState::Disabled {
enabled_kind: ScopeKind::PreRun,
start_tsc: None,
};
let mut decoder = builder.build()?;
// Required before it can be used
decoder.sync_forward()?;
unsafe {
let mut config: libipt_sys::pt_config = std::mem::zeroed();
config.size = size_of::<libipt_sys::pt_config>();
config.begin = mmap.as_ptr() as *mut _;
config.end = config.begin.add(mmap.len());
let mut segments = vec![(Scope::PreRun, Duration::ZERO)];
let mut total = 0u64;
let mut lost_cyc = 0;
// cpuid(0x16):ecx returns the bus frequency in mHz (See volume 2, chapter 1.3 CPUID in the intel manual)
// Combined with the core to bus ration we can calculate the core frequency
let f_bus = cpuid!(0x16).ecx as f64 * 1_000_000.0;
let mut current_cbr = 0u8;
let mut cyc_duration_before_first_tsc = Duration::ZERO;
let mut first_tsc = None::<u64>;
let mut cyc_duration_after_last_tsc = Duration::ZERO;
let mut last_tsc = None::<u64>;
let mut seen_cbrs = HashMap::<u8, u64>::new();
for packet in decoder {
total += 1;
match packet {
Ok(Packet::Cyc(cyc)) => {
// Ignore cycle packets when there was no cbr packet yet.
if current_cbr == 0 {
lost_cyc += 1;
continue;
}
let f_core = f_bus * current_cbr as f64;
let duration = Duration::from_secs_f64(cyc.value() as f64 / f_core);
if first_tsc.is_none() {
cyc_duration_before_first_tsc += duration;
}
if last_tsc.is_some() {
cyc_duration_after_last_tsc += duration;
}
segments.last_mut().unwrap().1 += duration;
}
Ok(Packet::Tsc(tsc)) => {
if first_tsc.is_none() {
first_tsc = Some(tsc.tsc());
}
cyc_duration_after_last_tsc = Duration::ZERO;
last_tsc = Some(tsc.tsc());
}
Ok(Packet::Cbr(cbr)) => {
current_cbr = cbr.ratio();
*seen_cbrs.entry(cbr.ratio()).or_default() += 1;
}
Ok(Packet::Ptw(ptwrite)) => {
if ptwrite.payload() == 42 {
// Main enter
segments.push((Scope::Main, Duration::ZERO));
} else if ptwrite.payload() == 43 {
// Main exit
segments.push((Scope::PostRun, Duration::ZERO));
} else {
// println!("GOT PTWRITE!!!!!: {ptwrite:?}");
}
}
Ok(Packet::Ovf(overflow)) => {
panic!("Got overflow packet: {overflow:?}, index {total}");
}
Ok(_) => {}
Err(error) => println!("Got error: {error:?}"),
let decoder = libipt_sys::pt_evt_alloc_decoder(&config);
if decoder.is_null() {
panic!("Could not create decoder");
}
}
// dbg!(seen_cbrs);
let duration_total = segments.iter().map(|(_, duration)| *duration).sum();
let main_duration = duration_in_mode(&segments, Scope::Main);
let f_tsc = CpuId::new()
.get_tsc_info()
.unwrap()
.tsc_frequency()
.unwrap();
let first_tsc_main = first_tsc.expect("Should have recorded a tsc") as f64 / f_tsc as f64
+ cyc_duration_before_first_tsc.as_secs_f64();
let last_tsc_main = last_tsc.expect("Should have recorded a tsc") as f64 / f_tsc as f64
+ cyc_duration_after_last_tsc.as_secs_f64();
let total_seconds_tsc = last_tsc_main - first_tsc_main;
let status = libipt_sys::pt_evt_sync_forward(decoder);
if status < 0 {
panic!("Could not sync: {status}");
}
let mut last_tsc = 0;
let mut last_event = 0;
loop {
let mut event = std::mem::MaybeUninit::uninit();
let status = libipt_sys::pt_evt_next(
decoder,
event.as_mut_ptr(),
size_of::<libipt_sys::pt_event>(),
);
if status < 0 {
if (-status & (1 << 2)) == 0 {
println!("Expected EOI, got {status}");
}
break;
}
let event = event.assume_init();
if (event.has_tsc() > 0 && event.tsc < last_tsc && event.type_ != 20 && event.type_ != 21) {
println!("WARN: Event {} happens before last event ({last_event})!", event.type_);
continue;
}
last_tsc = event.tsc;
last_event = event.type_;
// println!("Has tsc: {}, tsc: {}, {}, {}", event.has_tsc(), event.tsc, event.lost_mtc, event.lost_cyc);
let next_state = match event.type_ {
PT_EVENT_ENABLED | PT_EVENT_ASYNC_DISABLED => match state {
DecoderState::Disabled { enabled_kind, .. } => {
assert!(event.has_tsc() > 0);
DecoderState::Enabled {
kind: enabled_kind,
start_tsc: event.tsc,
}
}
DecoderState::Enabled { .. } => continue,
},
PT_EVENT_DISABLED => match state {
DecoderState::Enabled { kind, .. } => {
assert!(event.has_tsc() > 0);
DecoderState::Disabled {
enabled_kind: kind,
start_tsc: Some(event.tsc),
}
}
DecoderState::Disabled { .. } => {
continue;
}
},
PT_EVENT_PTWRITE => {
assert!(event.has_tsc() > 0);
let value = event.variant.ptwrite.payload;
let new_scope = match value {
42 => ScopeKind::Main,
43 => ScopeKind::PostRun,
other => panic!("Unknown ptwrite {other}"),
};
match state {
DecoderState::Disabled { .. } => {
unreachable!("Ptwrite cannot happen if the decoder is deactivate")
}
DecoderState::Enabled { .. } => DecoderState::Enabled {
kind: new_scope,
start_tsc: event.tsc,
},
}
}
_ => continue,
};
println!("{state:?}, {next_state:?}, lost cyc: {}, lost mtc: {}", event.lost_cyc, event.lost_mtc);
match (state, next_state) {
(
DecoderState::Enabled { kind, start_tsc },
DecoderState::Enabled {
start_tsc: end_tsc, ..
}
| DecoderState::Disabled {
start_tsc: Some(end_tsc),
..
},
) => {
events.push(Scope::new(kind, start_tsc, end_tsc));
}
(
DecoderState::Disabled {
start_tsc: Some(start_tsc),
..
},
DecoderState::Enabled {
start_tsc: end_tsc, ..
},
) => events.push(Scope::new(
ScopeKind::PacketGenerationDisabled,
start_tsc,
end_tsc,
)),
(
DecoderState::Disabled {
start_tsc: None, ..
},
DecoderState::Enabled { .. },
) => {}
_ => unreachable!("{state:?}, {next_state:?}"),
}
state = next_state;
}
// TODO: Add last event!
libipt_sys::pt_evt_free_decoder(decoder);
}
let total_duration = filter_time(&events, |_| true);
let duration_in_client = filter_time(&events, |kind| matches!(kind, ScopeKind::Main));
Ok(AnalyzeData {
packets: total,
lost_cyc,
time_cyc: duration_total,
time_main: main_duration,
time_tsc: Duration::from_secs_f64(total_seconds_tsc),
time_qemu: qemu_duration,
total_time: total_duration,
time_in_client: duration_in_client,
})
}
fn duration_in_mode(segments: &[(Scope, Duration)], scope: Scope) -> Duration {
segments
.iter()
.filter(|(it, _)| *it == scope)
.map(|(_, duration)| *duration)
.sum::<Duration>()
fn filter_time(events: &[Scope], mut filter: impl FnMut(ScopeKind) -> bool) -> Duration {
let iter = events.iter().filter(|scope| filter(scope.kind));
let total_cycles = iter
.map(|scope| scope.end_tsc - scope.start_tsc)
.sum::<u64>() as f64;
let cycles_per_second = 2_700_000_000.0;
Duration::from_secs_f64(total_cycles / cycles_per_second)
}
// pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
// let trace_file = File::open(path)?;
// let mmap = unsafe { Mmap::map(&trace_file)? };
//
// let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
// // I hope this is safe if the buffer is never written to
// let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
//
// let mut decoder = builder.build()?;
// // Required before it can be used
// decoder.sync_forward()?;
//
// let mut segments = vec![(Scope::PreRun, 0u64)];
// let mut total = 0u64;
//
// for packet in decoder {
// total += 1;
// match packet {
// Ok(Packet::Cyc(cyc)) => {
// segments.last_mut().unwrap().1 += cyc.value();
// }
// Ok(Packet::TipPgd(pgd)) => {
// segments.push((Scope::PacketGenerationDisabled, 0));
// }
// Ok(Packet::TipPge(pge)) => {
// match segments.as_slice() {
// [.., (previous_segment, _), (Scope::PacketGenerationDisabled, _)] => {
// segments.push((*previous_segment, 0));
// }
// [_] | [] => {}
// [.., _, (other_scope, _)] => {
// panic!("Invalid segments layout: {other_scope:?}");
// }
// }
// }
// Ok(Packet::Ptw(ptwrite)) => {
// if ptwrite.payload() == 42 {
// // Main enter
// segments.push((Scope::Main, 0));
// } else if ptwrite.payload() == 43 {
// // Main exit
// segments.push((Scope::PostRun, 0));
// } else {
// println!("GOT PTWRITE!!!!!: {ptwrite:?}");
// }
// }
// Ok(_) => {}
// Err(error) => println!("Got error: {error:?}"),
// }
// }
// dbg!(&segments);
// let cycles_main: u64 = segments
// .iter()
// .filter(|(scope, _)| matches!(scope, Scope::Main))
// .map(|(_, cycles)| cycles)
// .sum();
// let cycles_total = segments.iter().map(|(_, cycles)| cycles).sum();
// let total_seconds = cycles_total as f64 / 2_700_000_000.0;
// let total_seconds_no_hypervisor = cycles_main as f64 / 2_700_000_000.0;
// Ok(AnalyzeData {
// packets: total,
// cycles: cycles_total,
// time: Duration::from_secs_f64(total_seconds),
// time_outside_hypervisor: Duration::from_secs_f64(total_seconds_no_hypervisor),
// })
// }

View File

@ -1,10 +0,0 @@
if [ ! -d KVM-Nyx-fork ]; then
echo "Could not find KVM-Nyx-fork"
echo "Download from https://git.cs.tu-dortmund.de/david.venhoff/KVM-Nyx-fork"
echo "Then setup the config with \`make oldconfig\`"
exit
fi
cd KVM-Nyx-fork || exit
sh compile_kvm_nyx_standalone.sh
sh load_kvm_nyx.sh
echo "Done"

View File

@ -1,17 +0,0 @@
use std::fmt::Debug;
use std::io::Write;
/// Used for benchmarking nyx + pt, nyx - pt, and the baseline
pub trait Benchmark {
const TITLE: &'static str;
type BenchmarkResult: ToCsv + Debug;
fn execute_once(&mut self) -> Self::BenchmarkResult;
}
pub trait ToCsv {
const HEADERS: &'static [&'static str];
fn write(&self, writer: &mut csv::Writer<impl Write>) -> csv::Result<()>;
}

View File

@ -1,34 +0,0 @@
use crate::benchmark::{Benchmark, ToCsv};
use csv::Writer;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::time::Duration;
/// Executes the given program without any instrumentation
pub struct Baseline<'a>(pub &'a Path);
impl Benchmark for Baseline<'_> {
const TITLE: &'static str = "baseline";
type BenchmarkResult = Duration;
fn execute_once(&mut self) -> Self::BenchmarkResult {
let output = Command::new(self.0)
.output()
.expect("Command should succeed");
let output = String::from_utf8_lossy(&output.stdout);
let Ok(duration) = output.trim().parse() else {
panic!("Invalid output: {}", output);
};
Duration::from_secs_f64(duration)
}
}
impl ToCsv for Duration {
const HEADERS: &'static [&'static str] = &["time"];
fn write(&self, writer: &mut Writer<impl Write>) -> csv::Result<()> {
writer.write_record([self.as_secs_f64().to_string()])
}
}

View File

@ -1,26 +0,0 @@
use crate::benchmark::Benchmark;
use crate::nyx::{NyxRunner, TraceMode};
use std::path::Path;
use std::time::Duration;
/// Executes the given program with nyx, but without tracing
pub struct BenchmarkNyxNoPt(NyxRunner);
impl BenchmarkNyxNoPt {
pub fn new(client_path: &Path) -> anyhow::Result<Self> {
Ok(BenchmarkNyxNoPt(NyxRunner::setup(
client_path,
TraceMode::Disabled,
)?))
}
}
impl Benchmark for BenchmarkNyxNoPt {
const TITLE: &'static str = "nyx";
type BenchmarkResult = Duration;
fn execute_once(&mut self) -> Self::BenchmarkResult {
self.0.execute()
}
}

View File

@ -1,43 +0,0 @@
use crate::benchmark::{Benchmark, ToCsv};
use crate::nyx::{NyxRunner, TraceMode};
use csv::Writer;
use pt_dump_decoder::{AnalyzeData, analyze_dump};
use std::io::Write;
use std::path::Path;
/// Executes the given program with nyx and tracing
pub struct BenchmarkNyx(NyxRunner);
impl BenchmarkNyx {
pub fn new(client_bin: &Path) -> anyhow::Result<Self> {
Ok(BenchmarkNyx(NyxRunner::setup(
client_bin,
TraceMode::Enabled,
)?))
}
}
impl Benchmark for BenchmarkNyx {
const TITLE: &'static str = "nyx_and_pt";
type BenchmarkResult = AnalyzeData;
fn execute_once(&mut self) -> AnalyzeData {
let qemu_duration = self.0.execute();
let dump_path = self.0.workdir().join("pt_trace_dump_0");
analyze_dump(dump_path, qemu_duration).expect("Should be able to analyze the data")
}
}
impl ToCsv for AnalyzeData {
const HEADERS: &'static [&'static str] = &["time_main_cyc", "time_total_cyc", "time_total_tsc", "time_total_qemu"];
fn write(&self, writer: &mut Writer<impl Write>) -> csv::Result<()> {
writer.write_record([
self.time_main.as_secs_f64().to_string(),
self.time_cyc.as_secs_f64().to_string(),
self.time_tsc.as_secs_f64().to_string(),
self.time_qemu.as_secs_f64().to_string(),
])
}
}

View File

@ -1,105 +1,47 @@
//! Translated from libnyx/test.c
mod benchmark;
mod benchmark_baseline;
mod benchmark_nyx_no_pt;
mod benchmark_nyx_pt;
mod nyx;
use libnyx::ffi::nyx_print_aux_buffer;
use libnyx::{NyxConfig, NyxProcess, NyxProcessRole, NyxReturnValue};
use pt_dump_decoder::analyze_dump;
use std::error::Error;
use crate::benchmark::{Benchmark, ToCsv};
use crate::benchmark_baseline::Baseline;
use crate::benchmark_nyx_no_pt::BenchmarkNyxNoPt;
use crate::benchmark_nyx_pt::BenchmarkNyx;
use anyhow::Context;
use clap::Parser;
use std::fmt::Debug;
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{Duration, Instant};
const WORKDIR_PATH: &str = "/tmp/wdir";
// The sharedir path gets set by the build script
const SHAREDIR_PATH: &str = env!("NYX_SHAREDIR");
#[derive(Debug, Parser)]
#[command(about = "Tool to execute a program with nyx and trace it with intel pt")]
struct Args {
/// Path to the client binary to execute
client: PathBuf,
/// Directory where the benchmark files get stored
#[arg(short = 'o', long = "output", default_value = "benchmarks")]
output_dir: PathBuf,
/// Whether to only execute a single nyx run, used for testing
#[arg(short = 'd', long = "debug", default_value = "false")]
debug: bool,
}
fn main() -> anyhow::Result<()> {
let args = Args::parse();
if args.debug {
dbg!(BenchmarkNyx::new(&args.client)?.execute_once());
return Ok(());
}
let binary_name = args.client.file_name().unwrap().to_str().unwrap();
{
let benchmark_nyx = BenchmarkNyx::new(&args.client)?;
benchmark(binary_name, &args.output_dir, benchmark_nyx)?;
}
{
let benchmark_nyx_no_pt = BenchmarkNyxNoPt::new(&args.client)?;
benchmark(binary_name, &args.output_dir, benchmark_nyx_no_pt)?;
}
benchmark(binary_name, &args.output_dir, Baseline(&args.client))?;
fn main() -> Result<(), Box<dyn Error>> {
let _ = std::fs::remove_dir_all(WORKDIR_PATH);
run_client()?;
println!("Analyzing pt data...");
let dump_path = format!("{WORKDIR_PATH}/pt_trace_dump_0");
let result = analyze_dump(dump_path)?;
println!("{result:?}");
Ok(())
}
fn benchmark<B: Benchmark>(
binary_name: &str,
output_dir: &Path,
mut benchmark: B,
) -> anyhow::Result<()> {
warmup(&mut benchmark);
let results = benchmark_loop(&mut benchmark);
write_results::<B>(binary_name, output_dir, &results).with_context(|| "Writing results")?;
Ok(())
}
/// Warm up to make sure caches are initialized, etc.
fn warmup(benchmark: &mut impl Benchmark) {
let warmup_duration = Duration::from_secs(5);
println!("Warming up for {warmup_duration:?}");
let mut iterations = 0;
let start = Instant::now();
while start.elapsed() < warmup_duration {
benchmark.execute_once();
iterations += 1;
}
println!("Warmed up for {iterations} iterations");
}
fn benchmark_loop<B: Benchmark>(benchmark: &mut B) -> Vec<B::BenchmarkResult> {
let n = 500;
println!("Perform {n} iterations...");
(0..n)
.map(|_| std::hint::black_box(benchmark.execute_once()))
.collect::<Vec<_>>()
}
fn write_results<B: Benchmark>(
binary_name: &str,
output_dir: &Path,
results: &[B::BenchmarkResult],
) -> anyhow::Result<()> {
fs::create_dir_all(output_dir)
.with_context(|| format!("Creating output directory {output_dir:?}"))?;
let filename = format!("benchmark_{binary_name}_{}", B::TITLE);
let file =
fs::File::create(output_dir.join(filename)).with_context(|| "Creating output file")?;
let mut writer = csv::WriterBuilder::new().from_writer(file);
writer.write_record(B::BenchmarkResult::HEADERS)?;
for result in results {
result.write(&mut writer)?;
}
fn run_client() -> Result<(), Box<dyn Error>> {
let mut nyx_config = NyxConfig::load(SHAREDIR_PATH)?;
nyx_config.set_workdir_path(WORKDIR_PATH.to_string());
nyx_config.set_input_buffer_size(0x2000);
nyx_config.set_nyx_debug_log_path("qemu_nyx.log".to_string());
nyx_config.set_process_role(NyxProcessRole::StandAlone);
nyx_config.print();
let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0)?;
nyx_runner.option_set_trace_mode(true);
nyx_runner.option_set_timeout(10, 0);
nyx_runner.option_apply();
let result = nyx_runner.exec();
assert!(
matches!(result, NyxReturnValue::Normal),
"Unexpected return value {result:?}"
);
nyx_print_aux_buffer(&mut nyx_runner as *mut _);
nyx_runner.shutdown();
Ok(())
}

View File

@ -1,171 +0,0 @@
//! This module contains functionality to download and setup nyx,
//! so that it can be used to execute a binary.
use anyhow::{Context, anyhow, bail};
use libnyx::{NyxConfig, NyxProcess, NyxProcessRole, NyxReturnValue};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;
use std::{fs, io};
const WORKDIR_PATH: &str = "/tmp/wdir";
#[derive(Debug, Clone, Copy)]
pub enum TraceMode {
Enabled,
Disabled,
}
pub struct NyxRunner(NyxProcess);
impl NyxRunner {
pub fn setup(client_bin: &Path, trace_mode: TraceMode) -> anyhow::Result<Self> {
if let Err(e) = fs::remove_dir_all(WORKDIR_PATH)
&& !matches!(e.kind(), io::ErrorKind::NotFound)
{
panic!("Could not remove working directory at {WORKDIR_PATH}");
}
let sharedir = setup_nyx(&PathBuf::from("nyx_data"), client_bin)?;
let sharedir = sharedir.to_str().expect("Expected unicode path");
let mut nyx_config = NyxConfig::load(sharedir)
.map_err(|err| anyhow!(err))
.with_context(|| "Creating nyx config")?;
nyx_config.set_workdir_path(WORKDIR_PATH.to_string());
nyx_config.set_input_buffer_size(0x2000);
nyx_config.set_nyx_debug_log_path("qemu_nyx.log".to_string());
nyx_config.set_pt_enabled(matches!(trace_mode, TraceMode::Enabled));
nyx_config.set_process_role(NyxProcessRole::StandAlone);
nyx_config.print();
let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0)
.map_err(|err| anyhow!(err))
.with_context(|| "Creating Nyx Process")?;
nyx_runner.option_set_trace_mode(true);
nyx_runner.option_set_reload_mode(false);
nyx_runner.option_set_timeout(10, 0);
nyx_runner.option_apply();
Ok(NyxRunner(nyx_runner))
}
/// Executes the program with Nyx and intel PT.
///
/// Returns the duration of the program as recorded by QEMU.
pub fn execute(&mut self) -> Duration {
let result = self.0.exec();
// nyx_print_aux_buffer(&mut self.0 as *mut _);
assert!(
matches!(result, NyxReturnValue::Normal),
"Unexpected return value: {result:?}"
);
self.0.aux_result_duration()
}
pub fn workdir(&self) -> &Path {
Path::new(WORKDIR_PATH)
}
}
impl Drop for NyxRunner {
fn drop(&mut self) {
self.0.shutdown();
}
}
/// Downloads and installs nyx
///
/// [out_dir] Is the directory to which all tools get downloaded and
/// where the working directory gets created.
///
/// [client] Is the path to the client binary.
///
/// Returns the path to the working directory
pub fn setup_nyx(out_dir: &Path, client: &Path) -> anyhow::Result<PathBuf> {
if !out_dir.exists() {
fs::create_dir(out_dir)?;
}
println!("Installing nyx...");
let result = setup_nyx_tools(out_dir);
if let Err(e) = result {
// Remove the out directory as it may be tainted
fs::remove_dir_all(out_dir)
.with_context(|| format!("Error while handling error: {e}"))?;
return Err(e);
}
create_nyx_workdir(out_dir, client).with_context(|| "Creating the nyx working directory")
}
#[track_caller]
fn shell(cwd: impl AsRef<Path>, command_string: &str) -> anyhow::Result<()> {
println!("Running ({}) {command_string}", cwd.as_ref().display());
let cwd = cwd.as_ref();
let mut parts = command_string.split(" ");
let command_name = parts.next().unwrap();
let mut command = Command::new(command_name);
command.current_dir(cwd);
command.stdout(std::process::Stdio::inherit());
command.stderr(std::process::Stdio::inherit());
command.args(parts);
let mut process = command.spawn()?;
let exit_status = process.wait()?;
if !exit_status.success() {
bail!("Command ({command_string}) failed with {exit_status}");
}
Ok(())
}
/// Downloads and compiles qemu-nyx and packer and compiles them for the current architecture
/// This means that cross-compilation is not supported
fn setup_nyx_tools(out_dir: &Path) -> anyhow::Result<()> {
let packer_path = out_dir.join("packer");
let qemu_path = out_dir.join("QEMU-Nyx");
if !packer_path.exists() {
shell(out_dir, "git clone https://github.com/nyx-fuzz/packer/")?;
}
if !qemu_path.exists() {
println!("Cloning and building QEMU-Nyx. This may take a while...");
shell(
out_dir,
"git clone https://git.cs.tu-dortmund.de/david.venhoff/QEMU-Nyx-fork QEMU-Nyx --depth 1",
)?;
// Compile with maximum optimizations
let qemu_compile_mode = "lto";
shell(
qemu_path,
&format!("bash compile_qemu_nyx.sh {qemu_compile_mode}"),
)?;
}
Ok(())
}
fn create_nyx_workdir(out_dir: &Path, client_bin: &Path) -> anyhow::Result<PathBuf> {
let client_bin =
fs::canonicalize(client_bin).with_context(|| format!("canonicalizing {client_bin:?}"))?;
let client_bin = client_bin.to_str().expect("Expected unicode path");
// Create the directory and move required binaries to it
shell(
out_dir,
&format!(
"python3 packer/packer/nyx_packer.py {client_bin} build afl processor_trace --purge"
),
)?;
// Create the nyx config
shell(
out_dir,
"python3 packer/packer/nyx_config_gen.py build Kernel",
)?;
Ok(out_dir.join("build"))
}