diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm.tar.gz b/pwn/35-shades-of-wasm/35ShadesOfWasm.tar.gz new file mode 100644 index 0000000..635889f Binary files /dev/null and b/pwn/35-shades-of-wasm/35ShadesOfWasm.tar.gz differ diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/Dockerfile b/pwn/35-shades-of-wasm/35ShadesOfWasm/Dockerfile new file mode 100644 index 0000000..c0a9773 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/Dockerfile @@ -0,0 +1,16 @@ +FROM debian:bookworm-slim@sha256:ea5ad531efe1ac11ff69395d032909baf423b8b88e9aade07e11b40b2e5a1338 + +EXPOSE 1337 + +RUN DEBIAN_FRONTEND=noninteractive; \ + apt -y update; \ + apt -y install socat + +WORKDIR /app + +COPY chall/chall app +COPY chall/flag.txt flag.txt + +CMD socat -T 60 \ + TCP-LISTEN:1337,nodelay,reuseaddr,fork \ + EXEC:"stdbuf -i0 -o0 -e0 /app/app",stderr diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/Makefile b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/Makefile new file mode 100644 index 0000000..61d3ed6 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/Makefile @@ -0,0 +1,8 @@ +build: wasm_host/src/main.rs + cd wasm_host && cargo build --release && cd .. + cp wasm_host/target/release/wasm_host chall + +debug: wasm_host/src/main.rs + cd wasm_host && cargo build && cd .. + +all: build diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/chall b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/chall new file mode 100755 index 0000000..f37f965 Binary files /dev/null and b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/chall differ diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/flag.txt b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/flag.txt new file mode 100644 index 0000000..16c87fc --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/flag.txt @@ -0,0 +1 @@ +gctf{NotTheFlag} \ No newline at end of file diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.lock b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.lock new file mode 100644 index 0000000..a0ee346 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.lock @@ -0,0 +1,1940 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cap-fs-ext" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc48200a1a0fa6fba138b1802ad7def18ec1cdd92f7b2a04e21f1bd887f7b9" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes 1.0.11", + "windows-sys 0.48.0", +] + +[[package]] +name = "cap-primitives" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b6df5b295dca8d56f35560be8c391d59f0420f72e546997154e24e765e6451" +dependencies = [ + "ambient-authority", + "fs-set-times 0.19.2", + "io-extras", + "io-lifetimes 1.0.11", + "ipnet", + "maybe-owned", + "rustix 0.37.27", + "windows-sys 0.48.0", + "winx 0.35.1", +] + +[[package]] +name = "cap-rand" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25555efacb0b5244cf1d35833d55d21abc916fff0eaad254b8e2453ea9b8ab" +dependencies = [ + "ambient-authority", + "rand", +] + +[[package]] +name = "cap-std" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3373a62accd150b4fcba056d4c5f3b552127f0ec86d3c8c102d60b978174a012" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes 1.0.11", + "rustix 0.37.27", +] + +[[package]] +name = "cap-time-ext" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95002993b7baee6b66c8950470e59e5226a23b3af39fc59c47fe416dd39821a" +dependencies = [ + "cap-primitives", + "once_cell", + "rustix 0.37.27", + "winx 0.35.1", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc42ba2e232e5b20ff7dc299a812d53337dadce9a7e39a238e6a5cb82d2e57b" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567d9f6e919bac076f39b902a072686eaf9e6d015baa34d10a61b85105b7af59" +dependencies = [ + "arrayvec", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e72b2d5ec8917b2971fe83850187373d0a186db4748a7c23a5f48691b8d92bb" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3461c0e0c2ebbeb92533aacb27e219289f60dc84134ef34fbf2d77c9eddf07ef" + +[[package]] +name = "cranelift-entity" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f42ea692c7b450ad18b8c9889661505d51c09ec4380cf1c2d278dbb2da22cae1" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef4f8f3984d772c199a48896d2fb766f96301bf71b371e03a2b99f4f3b7b931" + +[[package]] +name = "cranelift-native" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e3f4f0779a1b0f286a6ef19835d8665f88326e656a6d7d84fa9a39fa38ca32" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.9.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fd-lock" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b0377f1edc77dbd1118507bc7a66e4ab64d2b90c66f90726dc801e73a8c68f9" +dependencies = [ + "cfg-if", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "file-per-thread-logger" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-set-times" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "857cf27edcb26c2a36d84b2954019573d335bb289876113aceacacdca47a4fd4" +dependencies = [ + "io-lifetimes 1.0.11", + "rustix 0.36.17", + "windows-sys 0.45.0", +] + +[[package]] +name = "fs-set-times" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d167b646a876ba8fda6b50ac645cfd96242553cbaf0ca4fccaa39afcbf0801f" +dependencies = [ + "io-lifetimes 1.0.11", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "id-arena" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + +[[package]] +name = "io-extras" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde93d48f0d9277f977a333eca8313695ddd5301dc96f7e02aeddcb0dd99096f" +dependencies = [ + "io-lifetimes 1.0.11", + "windows-sys 0.48.0", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb4def18c48926ccac55c1223e02865ce1a821751a95920448662696e7472c" + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "ittapi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a5c0b993601cad796222ea076565c5d9f337d35592f8622c753724f06d7271" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7b5e473765060536a660eed127f758cf1a810c73e49063264959c60d1727d9" +dependencies = [ + "cc", +] + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memfd" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix 0.38.21", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown", + "indexmap", + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regalloc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.36.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes 1.0.11", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes 1.0.11", + "itoa", + "libc", + "linux-raw-sys 0.3.8", + "once_cell", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys 0.4.10", + "windows-sys 0.48.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shellexpand" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4" +dependencies = [ + "dirs", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-interface" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10081a99cbecbc363d381b9503563785f0b02735fccbb0d4c1a2cb3d39f7e7fe" +dependencies = [ + "bitflags 2.4.1", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes 2.0.2", + "rustix 0.38.21", + "windows-sys 0.48.0", + "winx 0.36.2", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + +[[package]] +name = "termcolor" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi-cap-std-sync" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7c5b2a394b5f6affc28f3b6c08010cd03458cdb7509b02a6a70771f6873635" +dependencies = [ + "anyhow", + "async-trait", + "cap-fs-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times 0.18.1", + "io-extras", + "io-lifetimes 1.0.11", + "is-terminal", + "once_cell", + "rustix 0.36.17", + "system-interface", + "tracing", + "wasi-common", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasi-common" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "101bb1e5f6cf20b27055006af27f9c6e6a09084469d197ec0cb5884da38968a7" +dependencies = [ + "anyhow", + "bitflags 1.3.2", + "cap-rand", + "cap-std", + "io-extras", + "rustix 0.36.17", + "thiserror", + "tracing", + "wasmtime", + "wiggle", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53ae0be20bf87918df4fa831bfbbd0b491d24aee407ed86360eae4c2c5608d38" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasm_host" +version = "0.1.0" +dependencies = [ + "anyhow", + "base64 0.21.5", + "cranelift-codegen", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "wasmparser" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "wasmtime" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9010891d0b8e367c3be94ca35d7bc25c1de3240463bb1d61bcfc8c2233c4e0d0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "cfg-if", + "indexmap", + "libc", + "log", + "object", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-component-macro", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit", + "wasmtime-runtime", + "wat", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65805c663eaa8257b910666f6d4b056b5c7329750da754ba5df54f3af7dbf35c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2049ddfc1b10efc3c5591d0e84b9570ca50478f8818f3bfabb1a467918f53fb4" +dependencies = [ + "anyhow", + "base64 0.13.1", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix 0.36.17", + "serde", + "sha2", + "toml", + "windows-sys 0.42.0", + "zstd", +] + +[[package]] +name = "wasmtime-component-macro" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9086679497e0a0b441d47ebb4781def9fed3d224feee913464a9a9e2950bac89" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasmtime-component-util", + "wasmtime-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-component-util" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3dd61938af6e06b60b9c5b916b48c9d2b77102e80559fcb4e5afb0c5f5bfdf" + +[[package]] +name = "wasmtime-cranelift" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9065cad6a724fa838ec8497567e0b23acc26417bb2449f8d9d2021925c72f2" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f964bb0b91fa021b8d1b488c62cc77b346c1dae6e3ebd010050b57c1f2ca657" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap", + "log", + "object", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-fiber" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9172517a3331b2a486266f7e16b637b27db6cdf5cddf7d055cd145da14cada46" +dependencies = [ + "cc", + "cfg-if", + "rustix 0.36.17", + "wasmtime-asm-macros", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a1d06f5d109539e0168fc74fa65e3948ac8dac3bb8cdbd08b62b36a0ae27b8" +dependencies = [ + "addr2line", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli", + "ittapi", + "log", + "object", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76ef2e410329aaf8555ac6571d6fe07711be0646dcdf7ff3ab750a42ed2e583" +dependencies = [ + "object", + "once_cell", + "rustix 0.36.17", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271aef9b4ca2e953a866293683f2db33cda46f6933c5e431e68d8373723d4ab6" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.6.5", + "paste", + "rand", + "rustix 0.36.17", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-fiber", + "wasmtime-jit-debug", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-types" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e5572c5727c1ee7e8f28717aaa8400e4d22dcbd714ea5457d85b5005206568" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-wasi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b1bc5cfbbfb4636702aa95d164f8f53bafb9c13e531789edc9e1ce5d4066b29" +dependencies = [ + "anyhow", + "wasi-cap-std-sync", + "wasi-common", + "wasmtime", + "wiggle", +] + +[[package]] +name = "wasmtime-wit-bindgen" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92eb1c58cfa115b29e04ff3882ecbd1c8b6db3639b200c72418be5fd43eab3ff" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "67.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c2933efd77ff2398b83817a98984ffe4b67aefd9aa1d2c8e68e19b553f1c38" +dependencies = [ + "leb128", + "memchr", + "unicode-width", + "wasm-encoder", +] + +[[package]] +name = "wat" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02905d13751dcb18f4e19f489d37a1bf139f519feaeef28d072a41a78e69a74" +dependencies = [ + "wast 67.0.0", +] + +[[package]] +name = "wiggle" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ac5d1216c18d8ee0a6bf37509d2061b17c8c5b11c405b0073108a041438f05" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 1.3.2", + "thiserror", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebca53f8c1f32e202dfd63f0b18bf01a5a9680e526b626758aa7678af04b2c18" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "shellexpand", + "syn 1.0.109", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3bec97d55f7a62d8d45d76fff91af294196b4aa9d1f45cd6784a964c84c067f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wiggle-generate", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winx" +version = "0.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c52a121f0fbf9320d5f2a9a5d82f6cb7557eda5e8b47fc3e7f359ec866ae960" +dependencies = [ + "bitflags 1.3.2", + "io-lifetimes 1.0.11", + "windows-sys 0.48.0", +] + +[[package]] +name = "winx" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357bb8e2932df531f83b052264b050b81ba0df90ee5a59b2d1d3949f344f81e5" +dependencies = [ + "bitflags 2.4.1", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-parser" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f887c3da527a51b321076ebe6a7513026a4757b6d4d144259946552d6fc728b3" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "pulldown-cmark", + "unicode-xid", + "url", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror", + "wast 35.0.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.toml b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.toml new file mode 100644 index 0000000..2394b7b --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "wasm_host" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +base64 = "0.21.5" +wasmtime = "=6.0.0" +wasmtime-wasi = "=6.0.0" +cranelift-codegen = "=0.93.0" +cranelift-codegen-meta = "=0.93.0" +cranelift-codegen-shared = "=0.93.0" diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/src/main.rs b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/src/main.rs new file mode 100644 index 0000000..d60846d --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/chall/wasm_host/src/main.rs @@ -0,0 +1,55 @@ +use anyhow::anyhow; +use base64::{engine::general_purpose as base64_engine, Engine as _}; +use wasmtime::*; +use wasmtime_wasi::sync::WasiCtxBuilder; + +fn main() -> anyhow::Result<()> { + let mut config = Config::new(); + + config.debug_info(false); + config.cranelift_debug_verifier(false); + + config.strategy(Strategy::Cranelift); + config.cranelift_opt_level(OptLevel::SpeedAndSize); + + config.static_memory_forced(true); + + let engine = Engine::new(&config)?; + let mut linker = Linker::new(&engine); + + wasmtime_wasi::add_to_linker(&mut linker, |s| s)?; + + let wasi = WasiCtxBuilder::new().inherit_stdio().build(); + + let mut store = Store::new(&engine, wasi); + + println!("Enter your module in base64:"); + let user_module_wat = { + let stdin = std::io::stdin(); + let mut user_module_wat = String::new(); + stdin.read_line(&mut user_module_wat)?; + + let user_module_wat = user_module_wat + .strip_suffix("\n") + .unwrap_or(&user_module_wat); + + match base64_engine::STANDARD.decode(&user_module_wat) { + Ok(user_module_wat) => user_module_wat, + Err(_) => return Err(anyhow!("invalid base64")), + } + }; + + let user_module = match Module::new(&engine, user_module_wat) { + Ok(user_module) => user_module, + Err(_) => return Err(anyhow!("invalid module")), + }; + + let _ = linker.module(&mut store, "module", &user_module)?; + + linker + .get_default(&mut store, "module")? + .typed::<(), ()>(&store)? + .call(&mut store, ())?; + + Ok(()) +} diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/docker-compose.yml b/pwn/35-shades-of-wasm/35ShadesOfWasm/docker-compose.yml new file mode 100644 index 0000000..87cc5d3 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/docker-compose.yml @@ -0,0 +1,20 @@ +# Read the comments, they are actually helpful. (like this one) +version: "3" + +services: + app: + # Challenge related options + build: . + ports: + - 1337:1337 + # Uncomment this block during development + # Every time you rebuild your file you can immeditately test it + # volumes: + # - ./chall:/app + + # Security releated options + user: 1337:1337 + privileged: false + read_only: true + cap_add: [] # See "man 7 capabilities" for a full list + cap_drop: [] # See "man 7 capabilities" for a full list diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/Makefile b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/Makefile new file mode 100644 index 0000000..237d4be --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/Makefile @@ -0,0 +1,8 @@ +wasi-sdk=/opt/wasi-sdk + +payload: payload.c + $(wasi-sdk)/bin/clang payload.c --target=wasm32-unknown-wasi --sysroot $(wasi-sdk)/share/wasi-sysroot/ \ + -O0 -g -o payload.wasm + base64 payload.wasm -w 0 > payload.wasm.base64 + +all: payload diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/payload.c b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/payload.c new file mode 100644 index 0000000..d5797f9 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/payload.c @@ -0,0 +1,5 @@ +#include + +int main(int argc, char ** argv) { + printf("Hello Wasi\n"); +} diff --git a/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/readme.md b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/readme.md new file mode 100644 index 0000000..3b53624 --- /dev/null +++ b/pwn/35-shades-of-wasm/35ShadesOfWasm/payload_example/readme.md @@ -0,0 +1,5 @@ +# Example +This example uses [wasi-sdk](https://github.com/WebAssembly/wasi-sdk). +You have to install it and then you might need to modify the wasi-sdk variable in the Makefile. + +Of course this challenge can be solved in any language that has a wasm+wasi target. diff --git a/pwn/35-shades-of-wasm/README.md b/pwn/35-shades-of-wasm/README.md new file mode 100644 index 0000000..3a1c2a7 --- /dev/null +++ b/pwn/35-shades-of-wasm/README.md @@ -0,0 +1,7 @@ +My friend hosts this wasm runtime that uses an outdated version of wasmtime. We pwned it and left a flag there. Can you get it? + +author: PaideiaDilemma + +``` +nc chall.glacierctf.com 13389 +``` \ No newline at end of file diff --git a/pwn/flipper/README.md b/pwn/flipper/README.md new file mode 100644 index 0000000..f307a60 --- /dev/null +++ b/pwn/flipper/README.md @@ -0,0 +1,8 @@ +Our OS professor keeps talking about Rowhammer, and how dangerous it is. I don't believe him, so you even get 3 bitflips to try and steal the flag from my kernel! + +Base repo is https://github.com/IAIK/sweb (commit ad1b59a5c2acbd4bff346bdf282a4d5e21bd9cb1) Build instructions at here + +author: hweissi +``` +nc chall.glacierctf.com 13371 +``` \ No newline at end of file diff --git a/pwn/flipper/chall.zip b/pwn/flipper/chall.zip new file mode 100644 index 0000000..1823f23 Binary files /dev/null and b/pwn/flipper/chall.zip differ diff --git a/pwn/flipper/challenge.diff b/pwn/flipper/challenge.diff new file mode 100644 index 0000000..0f14b8b --- /dev/null +++ b/pwn/flipper/challenge.diff @@ -0,0 +1,173 @@ +diff --git a/common/include/kernel/Scheduler.h b/common/include/kernel/Scheduler.h +index c8fa74bf..dd7a9b45 100644 +--- a/common/include/kernel/Scheduler.h ++++ b/common/include/kernel/Scheduler.h +@@ -26,7 +26,6 @@ class Scheduler + bool isCurrentlyCleaningUp(); + void incTicks(); + size_t getTicks(); +- + /** + * NEVER EVER EVER CALL THIS METHOD OUTSIDE OF AN INTERRUPT CONTEXT + * this is the method that decides which threads will be scheduled next +@@ -34,6 +33,7 @@ class Scheduler + * and changes the global variables currentThread and currentThreadRegisters + */ + void schedule(); ++ int flipped_already; // Here to have it in a singleton + + protected: + friend class IdleThread; +diff --git a/common/include/kernel/Syscall.h b/common/include/kernel/Syscall.h +index 8088db19..f0656a69 100644 +--- a/common/include/kernel/Syscall.h ++++ b/common/include/kernel/Syscall.h +@@ -15,7 +15,7 @@ class Syscall + static size_t close(size_t fd); + static size_t open(size_t path, size_t flags); + static void pseudols(const char *pathname, char *buffer, size_t size); +- ++ static int flipBit(char* address, int bitnum); + static size_t createprocess(size_t path, size_t sleep); + static void trace(); + }; +diff --git a/common/include/kernel/syscall-definitions.h b/common/include/kernel/syscall-definitions.h +index dd99d197..88525f9b 100644 +--- a/common/include/kernel/syscall-definitions.h ++++ b/common/include/kernel/syscall-definitions.h +@@ -17,3 +17,5 @@ + #define sc_createprocess 191 + #define sc_trace 252 + ++#define sc_flip_bit 69 ++ +diff --git a/common/include/kernel/user_progs.h b/common/include/kernel/user_progs.h +index 65617274..79e5b2a2 100644 +--- a/common/include/kernel/user_progs.h ++++ b/common/include/kernel/user_progs.h +@@ -3,7 +3,7 @@ + // DO NOT CHANGE THE NAME OR THE TYPE OF THE user_progs VARIABLE! + char const *user_progs[] = { + // for reasons of automated testing +- "/usr/shell.sweb", ++ "/usr/exploit.sweb", + 0 + }; + +diff --git a/common/source/kernel/Scheduler.cpp b/common/source/kernel/Scheduler.cpp +index 31ef1da9..2148b991 100644 +--- a/common/source/kernel/Scheduler.cpp ++++ b/common/source/kernel/Scheduler.cpp +@@ -28,6 +28,7 @@ Scheduler *Scheduler::instance() + + Scheduler::Scheduler() + { ++ flipped_already = 0; + block_scheduling_ = 0; + ticks_ = 0; + addNewThread(&cleanup_thread_); +diff --git a/common/source/kernel/Syscall.cpp b/common/source/kernel/Syscall.cpp +index 964cd5b4..9c161cad 100644 +--- a/common/source/kernel/Syscall.cpp ++++ b/common/source/kernel/Syscall.cpp +@@ -7,6 +7,9 @@ + #include "ProcessRegistry.h" + #include "File.h" + #include "Scheduler.h" ++#include "ArchMemory.h" ++#include "Loader.h" ++ + + size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5) + { +@@ -49,6 +52,10 @@ size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2 + case sc_pseudols: + pseudols((const char*) arg1, (char*) arg2, arg3); + break; ++ case sc_flip_bit: ++ return_value = flipBit((char*) arg1, (int) arg2); ++ break; ++ + default: + return_value = -1; + kprintf("Syscall::syscallException: Unimplemented Syscall Number %zd\n", syscall_number); +@@ -56,6 +63,24 @@ size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2 + return return_value; + } + ++int Syscall::flipBit(char* address, int bitnum) ++{ ++ ++ if(bitnum > 7 || bitnum < 0) ++ { ++ return -1; ++ } ++ if(Scheduler::instance()->flipped_already != 0) ++ { ++ return -2; ++ } ++ Scheduler::instance()->flipped_already = 0xfff; ++ char mask = (1 << bitnum); ++ *address ^= mask; ++ ++ return 0; ++} ++ + void Syscall::pseudols(const char *pathname, char *buffer, size_t size) + { + if(buffer && ((size_t)buffer >= USER_BREAK || (size_t)buffer + size > USER_BREAK)) +diff --git a/common/source/kernel/main.cpp b/common/source/kernel/main.cpp +index f7957074..c51fef8b 100644 +--- a/common/source/kernel/main.cpp ++++ b/common/source/kernel/main.cpp +@@ -28,6 +28,8 @@ + + extern void* kernel_end_address; + ++const char* flag = "gctf{TEST_FLAG_NOT_REAL_HF}"; ++ + uint8 boot_stack[0x4000] __attribute__((aligned(0x4000))); + SystemState system_state; + FileSystemInfo* default_working_dir; +diff --git a/userspace/libc/include/nonstd.h b/userspace/libc/include/nonstd.h +index 3f341b55..cc5dd694 100644 +--- a/userspace/libc/include/nonstd.h ++++ b/userspace/libc/include/nonstd.h +@@ -15,7 +15,7 @@ extern "C" { + * + */ + extern int createprocess(const char* path, int sleep); +- ++extern int flipBit(const void* address, int bit_num); + #ifdef __cplusplus + } + #endif +diff --git a/userspace/libc/src/nonstd.c b/userspace/libc/src/nonstd.c +index b9ec3d11..043a2466 100644 +--- a/userspace/libc/src/nonstd.c ++++ b/userspace/libc/src/nonstd.c +@@ -8,6 +8,12 @@ int createprocess(const char* path, int sleep) + return __syscall(sc_createprocess, (long) path, sleep, 0x00, 0x00, 0x00); + } + ++int flipBit(const void* address, int bit_num) ++{ ++ return __syscall(sc_flip_bit, (long) address, bit_num, 0, 0, 0); ++} ++ ++ + extern int main(); + + void _start() +diff --git a/utils/images/menu.lst b/utils/images/menu.lst +index cf7fd93d..f230876e 100644 +--- a/utils/images/menu.lst ++++ b/utils/images/menu.lst +@@ -1,6 +1,6 @@ + + default 0 +- ++timeout=0 + title = Sweb + root (hd0,0) + kernel = /boot/kernel.x diff --git a/pwn/flipper/dist/CMakeLists.txt b/pwn/flipper/dist/CMakeLists.txt new file mode 100644 index 0000000..a76f9a6 --- /dev/null +++ b/pwn/flipper/dist/CMakeLists.txt @@ -0,0 +1,255 @@ +cmake_minimum_required(VERSION 3.5) +set(CMAKE_DISABLE_SOURCE_CHANGES ON) +set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) + +# Include custom CMake modules from the cmake/ subdirectory +list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +set(HDD_IMAGE_RAW "SWEB-flat.vmdk") +set(HDD_IMAGE "SWEB.qcow2") + + +set (ARCH "x86/64") + +MESSAGE("-- Target architecture: ${ARCH}") + +unset(CMAKE_CROSSCOMPILING) +if(APPLE OR WIN32) + set(CMAKE_CROSSCOMPILING 1) + MESSAGE("-- Cross-Compiling on Apple/Windows") +endif(APPLE OR WIN32) + +# add-dbg for userspace binaries +include(AddDebugInfo) + +# include(arch/${ARCH}/CMakeLists.compiler) + +project(sweb + LANGUAGES C CXX ASM) + +string(REPLACE "/" ";" ARCH_LIST ${ARCH}) +string(REPLACE "/" "_" ARCH_ESC ${ARCH}) +string(TOUPPER ${ARCH_ESC} ARCH_ESC) + +add_definitions(-DCMAKE_${ARCH_ESC}=1) + +list(LENGTH ARCH_LIST ARCH_DEPTH) + +#Find program executables needed during compilation +find_program(LD_EXECUTABLE gcc) +find_program(OBJCOPY_EXECUTABLE objcopy) +find_program(DOXYGEN_EXECUTABLE doxygen) +find_program(STAT_EXECUTABLE stat) + +set(ColourReset "") +set(BoldRed "") +if(NOT WIN32) + string(ASCII 27 Esc) + set(ColourReset "${Esc}[m") + set(BoldRed "${Esc}[1;31m") +endif() +# set(TMPFS_CHECK "none") +# execute_process(COMMAND ${STAT_EXECUTABLE} --file-system --format=%T ${PROJECT_BINARY_DIR} +# OUTPUT_VARIABLE TMPFS_CHECK +# OUTPUT_STRIP_TRAILING_WHITESPACE) +# if(NOT("${TMPFS_CHECK}" STREQUAL "tmpfs")) +# MESSAGE("-- ${BoldRed}WARNING: build folder is not tmpfs - compilation will be slow and bad for the hard disk${ColourReset}") +# endif(NOT("${TMPFS_CHECK}" STREQUAL "tmpfs")) + +set(NOPIEFLAG -no-pie) +execute_process(COMMAND ${LD_EXECUTABLE} ${NOPIEFLAG} + ERROR_VARIABLE PIE_CHECK + ERROR_STRIP_TRAILING_WHITESPACE) +if("${PIE_CHECK}" MATCHES ".*unrecognized.*") +set(NOPIEFLAG ) +endif() +set(NOPICFLAG -fno-PIC) +execute_process(COMMAND ${CMAKE_C_COMPILER} ${NOPICFLAG} + ERROR_VARIABLE PIC_CHECK + ERROR_STRIP_TRAILING_WHITESPACE) +if("${PIC_CHECK}" MATCHES ".*unrecognized.*") +set(NOPICFLAG ) +endif() + +#Initialize CMake output directories +set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib") +set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}") + +include(arch/${ARCH}/CMakeLists.include) +include(arch/${ARCH}/CMakeLists.userspace) +string (REPLACE ";" " " KERNEL_CMAKE_C_FLAGS_STR "${KERNEL_CMAKE_C_FLAGS}") +set(CMAKE_ASM_FLAGS ${KERNEL_CMAKE_C_FLAGS_STR}) + +if(CMAKE_CROSSCOMPILING) + set(CMAKE_CROSS_COMPILE_FLAGS -G "Unix Makefiles") +else(CMAKE_CROSSCOMPILING) # not cross compiling + set(CMAKE_CROSS_COMPILE_FLAGS ) +endif(CMAKE_CROSSCOMPILING) + +# if ("${DEBUG}" STREQUAL "1") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG=1") +# endif() + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kernel.x + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kernel64.x + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + + +# Searches for asm, c and cpp files and adds the library +function(ADD_PROJECT_LIBRARY LIBRARY_NAME) + arch2obj(archobj_libname ${LIBRARY_NAME}) + + file(GLOB source_files ${SOURCE_WILDCARDS}) + + set(library_files) + + if(source_files) + set(library_files ${source_files}) + endif(source_files) + + if(archobj_libname) + set(library_files ${library_files} $) + endif(archobj_libname) + + if(library_files) + add_library(${LIBRARY_NAME} ${library_files}) + + if(archobj_libname) + add_dependencies(${LIBRARY_NAME} ${archobj_libname}) + endif(archobj_libname) + + target_compile_options(${LIBRARY_NAME} PRIVATE + $<$:${KERNEL_CMAKE_CXX_FLAGS}> + $<$:${KERNEL_CMAKE_C_FLAGS}> + ) + + set(ENV{LIBRARY_NAMES} "$ENV{LIBRARY_NAMES};${LIBRARY_NAME}") + endif(library_files) +endfunction(ADD_PROJECT_LIBRARY) + +set (SOURCE_WILDCARDS *.cpp *.c *.S) + +set(LIBRARY_FILENAMES) + +#Initialize global (environment) variables +set(ENV{LIBRARY_NAMES}) + +#Create target for userspace libc (Need to to that here because some files (e.g. syscall.c) are all over the place) +add_library(userspace_libc "") +target_compile_options(userspace_libc PUBLIC ${ARCH_USERSPACE_COMPILE_OPTIONS}) + +#Add the source directories +add_subdirectory(arch) +# add_subdirectory(common) +add_subdirectory(utils) +add_subdirectory(userspace) + + +#FINAL_LIB_NAMES should contain the names of all libraries +#these names can be used to link the kernel, no unpacking of *.a files is needed anymore +set(FINAL_LIB_NAMES $ENV{LIBRARY_NAMES}) + +#Name of the executables of the userspace, needed for dependency checking +set(FINAL_USERSPACE_NAMES $ENV{USERSPACE_NAMES}) + + + +#Build the Linker command +set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -g -u entry -Wl,-T ${CMAKE_SOURCE_DIR}/arch/${ARCH}/utils/kernel-ld-script.ld) +set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -o ${PROJECT_BINARY_DIR}/kernel.x) +#set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,-Map -Wl,${PROJECT_BINARY_DIR}/kernel.map) + +set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,--start-group) +foreach(libfile ${FINAL_LIB_NAMES}) + set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} ${LIBRARY_OUTPUT_PATH}/lib${libfile}.a) +endforeach(libfile) +set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,--end-group) +set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} ${ARCH_APPEND_LD_ARGUMENTS}) + +#Build userspace exe2minixfs command +set(MINIXFS_ARGUMENT "") +foreach(file $ENV{USERSPACE_NAMES_EXE2MINIX}) + list(APPEND MINIXFS_ARGUMENT ${file}) +endforeach(file) + +file(GLOB userspace_data userspace/data/*) +foreach(file ${userspace_data}) + get_filename_component(datafile ${file} NAME) + list(APPEND MINIXFS_ARGUMENT ${file} ${datafile}) +endforeach(file) + +#Custom Target: hdd_image +#Creates the hd image and copies all files to it +add_custom_target (hdd_image ALL + DEPENDS kernel_to_image userspace_to_image + COMMAND qemu-img convert -f raw -O qcow2 ${HDD_IMAGE_RAW} ${HDD_IMAGE} +) + +#Custom Command: invoke exe2minixfs and copy boot files to our hd image +add_custom_target (kernel_to_image + DEPENDS blank_hdd_image exe2minixfs + + # x86/32 doesn't generate kernel.dbg + COMMAND ${CMAKE_COMMAND} -E touch "./kernel.dbg" + COMMAND ./exe2minixfs ${HDD_IMAGE_RAW} 32256 "${CMAKE_SOURCE_DIR}/utils/images/menu.lst" boot/grub/menu.lst + ./kernel.x boot/kernel.x + ./kernel.dbg boot/kernel.dbg + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Copying kernel files to image..." +) + + + +#Custom Command: invoke exe2minixfs and copy all userspace programs to our hd image second partition +add_custom_target (userspace_to_image + DEPENDS blank_hdd_image ${FINAL_USERSPACE_NAMES} exe2minixfs + COMMAND mkdir -p userspace/data + COMMAND cp -f ${CMAKE_SOURCE_DIR}/userspace/data/* ${PROJECT_BINARY_DIR}/userspace/data + COMMAND ./exe2minixfs ${HDD_IMAGE_RAW} 10321920 ${MINIXFS_ARGUMENT} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Copying userspace programs to image..." +) + + +#Custom target: make bochs +#Run bochs in non debugging mode +add_custom_target(bochs + COMMAND ${BOCHS_PATH} -q -f ${PROJECT_SOURCE_DIR}/utils/bochsrc + COMMENT "Going to ${BOCHS_PATH} -f ${PROJECT_SOURCE_DIR}/utils/bochsrc" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} +) + +#Custom target: make bochsgdb +#Run bochs in debugging mode +add_custom_target(bochsgdb + COMMAND ${BOCHS_PATH} -q -f '${PROJECT_SOURCE_DIR}/utils/bochsrc' "gdbstub: enabled=1, port=1234" + COMMENT "Going to ${BOCHS_PATH} -f ${PROJECT_SOURCE_DIR}/utils/bochsrc \"gdbstub: enabled=1, port=1234\"" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} +) + +#Custom target: make emu +#Run qemu in emu mode +add_custom_target(emu + COMMAND cat '${PROJECT_SOURCE_DIR}/utils/emu.txt' +) + + + +# Define the "make ${ARCH}" targets +include(MakeArchTarget) + +MAKE_ARCH_TARGET(x86_32 x86/32 "") +MAKE_ARCH_TARGET(x86_32_pae x86/32/pae "") +MAKE_ARCH_TARGET(x86_64 x86/64 "") + +MAKE_ARCH_TARGET(arm_icp arm/integratorcp "") +MAKE_ARCH_TARGET(arm_rpi2 arm/rpi2 "") +MAKE_ARCH_TARGET(armv8_rpi3 armv8/rpi3 "-DVIRTUALIZED_QEMU=1") +MAKE_ARCH_TARGET(armv8_rpi3_hardware armv8/rpi3 "") + + + + diff --git a/pwn/flipper/dist/README.md b/pwn/flipper/dist/README.md new file mode 100644 index 0000000..a7d4182 --- /dev/null +++ b/pwn/flipper/dist/README.md @@ -0,0 +1,6 @@ +# Notes + +This is a setup to run a fixed kernel with new userspace. +Please read the instructions [here](https://www.iaik.tugraz.at/teaching/materials/os/tutorials/prerequisites-installation/) to find out how to compile and run. + +The same instructions also work for the source code at https://github.com/iaik/sweb, which is probably easier for debugging. \ No newline at end of file diff --git a/pwn/flipper/dist/arch/CMakeLists.txt b/pwn/flipper/dist/arch/CMakeLists.txt new file mode 100644 index 0000000..0174b9e --- /dev/null +++ b/pwn/flipper/dist/arch/CMakeLists.txt @@ -0,0 +1,4 @@ + + +include(${ARCH}/CMakeLists.subfolders) + diff --git a/pwn/flipper/dist/arch/x86/64/.keep b/pwn/flipper/dist/arch/x86/64/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pwn/flipper/dist/arch/x86/64/CMakeLists.compiler b/pwn/flipper/dist/arch/x86/64/CMakeLists.compiler new file mode 100644 index 0000000..8280627 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/CMakeLists.compiler @@ -0,0 +1,14 @@ +if(CMAKE_CROSSCOMPILING) +INCLUDE(CMakeForceCompiler) + +SET(CMAKE_SYSTEM_NAME Generic) +SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +find_program(CMAKE_ASM_COMPILER x86_64-linux-gnu-gcc) +find_program(CMAKE_C_COMPILER x86_64-linux-gnu-gcc) +find_program(CMAKE_CXX_COMPILER x86_64-linux-gnu-g++) + +find_program(LD_EXECUTABLE x86_64-linux-gnu-gcc) +find_program(OBJCOPY_EXECUTABLE x86_64-linux-gnu-objcopy) + +endif(CMAKE_CROSSCOMPILING) diff --git a/pwn/flipper/dist/arch/x86/64/CMakeLists.include b/pwn/flipper/dist/arch/x86/64/CMakeLists.include new file mode 100644 index 0000000..132dcb0 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/CMakeLists.include @@ -0,0 +1,67 @@ +set(KERNEL_BINARY kernel64.x) + +if (CMAKE_COMPILER_IS_GNUCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8)) + set(FCF_PROTECTION_FLAG -fcf-protection=none) +else() + set(FCF_PROTECTION_FLAG ) +endif() + +set(ARCH_X86_64_KERNEL_CFLAGS -m64 -O0 -gdwarf-2 -Wall -Wextra -Werror -Wno-error=format -Wno-nonnull-compare -nostdinc -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -fno-exceptions -fno-stack-protector -ffreestanding -mcmodel=kernel -mno-red-zone -mgeneral-regs-only -mno-mmx -mno-sse2 -mno-sse3 -mno-3dnow ${FCF_PROTECTION_FLAG} ${NOPICFLAG}) + +set(KERNEL_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=gnu++17 -nostdinc++ -fno-rtti ${ARCH_X86_64_KERNEL_CFLAGS}) +set(KERNEL_CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -std=gnu11 ${ARCH_X86_64_KERNEL_CFLAGS}) + +set(ARCH_LD_ARGUMENTS -m64 -Wl,--build-id=none -Wl,-z,max-page-size=0x1000 -Wl,-melf_x86_64 -nostdinc -nostdlib -nodefaultlibs) +set(KERNEL_LD_ARGUMENT ${ARCH_LD_ARGUMENTS} -mcmodel=kernel ${NOPIEFLAG}) +set(ARCH_APPEND_LD_ARGUMENTS ) + + +function(ARCH2OBJ ARCHOBJ_LIBNAME LIBRARY_NAME) + file(GLOB arch_files "*.32.C") + + if(arch_files) + set(ARCHOBJS_TARGET ${LIBRARY_NAME}_archobjs) + + add_library(${ARCHOBJS_TARGET} OBJECT ${arch_files}) + + target_compile_options(${ARCHOBJS_TARGET} PRIVATE + $<$:${KERNEL_CMAKE_CXX_FLAGS}> + $<$:${KERNEL_CMAKE_C_FLAGS}> + -m32 -g0 -mcmodel=32 -mgeneral-regs-only -momit-leaf-frame-pointer -Wa,--64 -fno-toplevel-reorder ${FCF_PROTECTION_FLAG} + ) + + set(${ARCHOBJ_LIBNAME} ${ARCHOBJS_TARGET} PARENT_SCOPE) + endif(arch_files) +endfunction(ARCH2OBJ) + +set(KERNEL_IMAGE_OBJCOPY COMMAND ${OBJCOPY_EXECUTABLE} ${PROJECT_BINARY_DIR}/kernel.x --strip-unneeded ${PROJECT_BINARY_DIR}/kernel.x) +if ("${DEBUG}" STREQUAL "1") + set(KERNEL_IMAGE_OBJCOPY ) +endif() +set(KERNEL_IMAGE_OBJCOPY + COMMAND ${PROJECT_BINARY_DIR}/add-dbg ${PROJECT_BINARY_DIR}/kernel.x ${PROJECT_BINARY_DIR}/kernel.dbg + ${KERNEL_IMAGE_OBJCOPY} + COMMAND mv ${PROJECT_BINARY_DIR}/kernel.x ${PROJECT_BINARY_DIR}/kernel64.x && ${OBJCOPY_EXECUTABLE} -O elf32-i386 ${PROJECT_BINARY_DIR}/kernel64.x ${PROJECT_BINARY_DIR}/kernel.x + ) + +set(AVAILABLE_MEMORY 8M) + +set(QEMU_BIN qemu-system-x86_64) +set(QEMU_FLAGS_COMMON -m ${AVAILABLE_MEMORY} -drive file=${HDD_IMAGE},index=0,media=disk -debugcon stdio -no-reboot) +string(REPLACE ";" " " QEMU_FLAGS_COMMON_STR "${QEMU_FLAGS_COMMON}") + +# qemu: Run qemu in non debugging mode +add_custom_target(qemu + COMMAND ${QEMU_BIN} ${QEMU_FLAGS_COMMON} -cpu qemu64 | tee output.log + COMMENT "Executing `${QEMU_BIN} ${QEMU_FLAGS_COMMON_STR} -cpu qemu64`" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMAND reset -I + ) + +# qemugdb: Run qemu in debugging mode +add_custom_target(qemugdb + COMMAND ${QEMU_BIN} ${QEMU_FLAGS_COMMON} -s -S | tee output.log + COMMENT "Executing `gdb ${QEMU_BIN} ${QEMU_FLAGS_COMMON_STR} -s -S on localhost:1234`" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMAND reset -I + ) diff --git a/pwn/flipper/dist/arch/x86/64/CMakeLists.subfolders b/pwn/flipper/dist/arch/x86/64/CMakeLists.subfolders new file mode 100644 index 0000000..dbd89b5 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/CMakeLists.subfolders @@ -0,0 +1,3 @@ +add_subdirectory(x86) +add_subdirectory(x86/64) + diff --git a/pwn/flipper/dist/arch/x86/64/CMakeLists.txt b/pwn/flipper/dist/arch/x86/64/CMakeLists.txt new file mode 100644 index 0000000..bf9cec0 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(userspace) diff --git a/pwn/flipper/dist/arch/x86/64/CMakeLists.userspace b/pwn/flipper/dist/arch/x86/64/CMakeLists.userspace new file mode 100644 index 0000000..f773a58 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/CMakeLists.userspace @@ -0,0 +1,2 @@ +set(ARCH_USERSPACE_COMPILE_OPTIONS -Wall -Werror -std=gnu11 -g -O0 -m64 -static -nostdinc -fno-builtin -nostdlib -nodefaultlibs -fno-stack-protector -fno-common -Werror=implicit-function-declaration -fno-stack-clash-protection) +set(ARCH_USERSPACE_LINKER_OPTIONS -static) diff --git a/pwn/flipper/dist/arch/x86/64/userspace/CMakeLists.txt b/pwn/flipper/dist/arch/x86/64/userspace/CMakeLists.txt new file mode 100644 index 0000000..07c5172 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/userspace/CMakeLists.txt @@ -0,0 +1,5 @@ +FILE(GLOB userspace_libc_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.c) + +target_sources(userspace_libc + PRIVATE + ${userspace_libc_SOURCES}) diff --git a/pwn/flipper/dist/arch/x86/64/userspace/syscalls.c b/pwn/flipper/dist/arch/x86/64/userspace/syscalls.c new file mode 100644 index 0000000..192467b --- /dev/null +++ b/pwn/flipper/dist/arch/x86/64/userspace/syscalls.c @@ -0,0 +1,8 @@ +#include "types.h" + +size_t __syscall(size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5, + size_t arg6) + { + asm("int $0x80\n" : "=a"(arg1) : "a"(arg1), "b"(arg2), "c"(arg3), "d"(arg4), "S"(arg5), "D"(arg6)); + return arg1; +} diff --git a/pwn/flipper/dist/arch/x86/CMakeLists.txt b/pwn/flipper/dist/arch/x86/CMakeLists.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pwn/flipper/dist/arch/x86/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/pwn/flipper/dist/cmake/AddDebugInfo.cmake b/pwn/flipper/dist/cmake/AddDebugInfo.cmake new file mode 100644 index 0000000..7a4afc6 --- /dev/null +++ b/pwn/flipper/dist/cmake/AddDebugInfo.cmake @@ -0,0 +1,18 @@ +# This macro adds a post-build hook to the specified target in order to attach +# SWEB-readable debug info. + +function(ADD_DEBUG_INFO TARGET) + set(dbg_binary $) + + add_custom_command(TARGET ${TARGET} + POST_BUILD + COMMAND "${CMAKE_BINARY_DIR}/add-dbg" "${dbg_binary}" "${dbg_binary}.dbg" + COMMAND "${OBJCOPY_EXECUTABLE}" --remove-section .swebdbg "${dbg_binary}" + COMMAND "${OBJCOPY_EXECUTABLE}" --add-section .swebdbg="${dbg_binary}.dbg" + --set-section-flags .swebdbg=noload,readonly "${dbg_binary}" + COMMAND ${CMAKE_COMMAND} -E remove -f "${dbg_binary}.dbg" + ) + + # Requires add-dbg to be built first. + add_dependencies(${TARGET} add-dbg) +endfunction(ADD_DEBUG_INFO) diff --git a/pwn/flipper/dist/cmake/MakeArchTarget.cmake b/pwn/flipper/dist/cmake/MakeArchTarget.cmake new file mode 100644 index 0000000..938c7ad --- /dev/null +++ b/pwn/flipper/dist/cmake/MakeArchTarget.cmake @@ -0,0 +1,12 @@ +# Macro for defining the "make ${ARCH}" targets +# +# If you want to add a target with multiple variable definitions, this is how you do it: +# MAKE_ARCH_TARGET(my_arch my/arch "-DVAR1=VALUE1;-DVAR2=VALUE2;...") + +function(MAKE_ARCH_TARGET TARGET_NAME ARCH_NAME EXTRA_FLAGS) + add_custom_target(${TARGET_NAME} + COMMAND ${PROJECT_SOURCE_DIR}/utils/prompt.sh "rm -fR ${PROJECT_BINARY_DIR}/*: remove all arguments recursively [Y/n]? " + COMMAND rm -fR ${PROJECT_BINARY_DIR}/* || true + COMMAND cmake -DARCH="${ARCH_NAME}" ${EXTRA_FLAGS} ${PROJECT_SOURCE_DIR} ${CMAKE_CROSS_COMPILE_FLAGS} + ) +endfunction(MAKE_ARCH_TARGET) diff --git a/pwn/flipper/dist/common/.keep b/pwn/flipper/dist/common/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pwn/flipper/dist/common/CMakeLists.txt b/pwn/flipper/dist/common/CMakeLists.txt new file mode 100644 index 0000000..4efc51d --- /dev/null +++ b/pwn/flipper/dist/common/CMakeLists.txt @@ -0,0 +1,18 @@ +include_directories( + include + ../arch/common/include + ../arch/${ARCH}/include + ../arch/${ARCH}/common/include + ../arch/${ARCH}/../common/include + ../arch/${ARCH}/../../common/include + include/kernel + include/fs + include/fs/devicefs + include/fs/minixfs + include/fs/pseudofs + include/fs/ramfs + include/util + include/ustl +) + +add_subdirectory(source) diff --git a/pwn/flipper/dist/common/include/.keep b/pwn/flipper/dist/common/include/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pwn/flipper/dist/common/include/console/debug.h b/pwn/flipper/dist/common/include/console/debug.h new file mode 100644 index 0000000..df50d37 --- /dev/null +++ b/pwn/flipper/dist/common/include/console/debug.h @@ -0,0 +1,88 @@ +#pragma once + +#include "kprintf.h" + +enum AnsiColor +{ + Ansi_Red = 31, + Ansi_Green = 32, + Ansi_Yellow = 33, + Ansi_Blue = 34, + Ansi_Magenta = 35, + Ansi_Cyan = 36, + Ansi_White = 37, +}; + +#define OUTPUT_ENABLED 0x80000000 +#define OUTPUT_ADVANCED 0x70000000 +#define OUTPUT_FLAGS (OUTPUT_ENABLED | OUTPUT_ADVANCED) + +#ifndef NOCOLOR +#define DEBUG_FORMAT_STRING "\033[1;%zum[%-11s]\033[0;39m" +#define COLOR_PARAM(flag) (flag & ~OUTPUT_FLAGS), #flag +#else +#define DEBUG_FORMAT_STRING "[%-11s]" +#define COLOR_PARAM(flag) #flag +#endif + +#ifndef EXE2MINIXFS +#define debug(flag, ...) do { if (flag & OUTPUT_ENABLED) { kprintfd(DEBUG_FORMAT_STRING, COLOR_PARAM(flag)); kprintfd(__VA_ARGS__); } } while (0) +#endif + + +//group Block Device +const size_t BD_MANAGER = Ansi_Yellow; +const size_t BD_VIRT_DEVICE = Ansi_Yellow; + +//group Console +const size_t KPRINTF = Ansi_Yellow; + +//group kernel +const size_t LOCK = Ansi_Yellow | OUTPUT_ENABLED; +const size_t LOADER = Ansi_White | OUTPUT_ENABLED; +const size_t SCHEDULER = Ansi_Yellow | OUTPUT_ENABLED; +const size_t SYSCALL = Ansi_Blue | OUTPUT_ENABLED; +const size_t MAIN = Ansi_Red | OUTPUT_ENABLED; +const size_t THREAD = Ansi_Magenta | OUTPUT_ENABLED; +const size_t USERPROCESS = Ansi_Cyan | OUTPUT_ENABLED; +const size_t PROCESS_REG = Ansi_Yellow | OUTPUT_ENABLED; +const size_t BACKTRACE = Ansi_Cyan | OUTPUT_ENABLED; +const size_t USERTRACE = Ansi_Red | OUTPUT_ENABLED; + +//group memory management +const size_t PM = Ansi_Green | OUTPUT_ENABLED; +const size_t PAGEFAULT = Ansi_Green | OUTPUT_ENABLED; +const size_t CPU_ERROR = Ansi_Red | OUTPUT_ENABLED; +const size_t KMM = Ansi_Yellow; + +//group driver +const size_t DRIVER = Ansi_Yellow; +const size_t ATA_DRIVER = Ansi_Yellow; +const size_t IDE_DRIVER = Ansi_Yellow; +const size_t MMC_DRIVER = Ansi_Yellow; + +//group arch +const size_t A_BOOT = Ansi_Yellow | OUTPUT_ENABLED; +const size_t A_COMMON = Ansi_Yellow; +const size_t A_MEMORY = Ansi_Yellow; +const size_t A_SERIALPORT = Ansi_Yellow; +const size_t A_KB_MANAGER = Ansi_Yellow; +const size_t A_INTERRUPTS = Ansi_Yellow; + +//group file system +const size_t FS = Ansi_Yellow; +const size_t RAMFS = Ansi_White; +const size_t DENTRY = Ansi_Blue; +const size_t INODE = Ansi_Blue; +const size_t PATHWALKER = Ansi_Yellow; +const size_t PSEUDOFS = Ansi_Yellow; +const size_t VFSSYSCALL = Ansi_Yellow; +const size_t VFS = Ansi_Yellow | OUTPUT_ENABLED; +const size_t VFS_FILE = Ansi_Yellow; +const size_t SUPERBLOCK = Ansi_Yellow; + +//group minix +const size_t M_STORAGE_MANAGER = Ansi_Yellow; +const size_t M_INODE = Ansi_Yellow; +const size_t M_SB = Ansi_Yellow; +const size_t M_ZONE = Ansi_Yellow; diff --git a/pwn/flipper/dist/common/include/fs/BDManager.h b/pwn/flipper/dist/common/include/fs/BDManager.h new file mode 100644 index 0000000..16dda78 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/BDManager.h @@ -0,0 +1,75 @@ +#pragma once + +#include + +class BDRequest; +class BDVirtualDevice; + +class BDManager +{ + public: + BDManager(); + ~BDManager(); + + /** + * returns singleton instance + * @return the block device manager instance + */ + static BDManager *getInstance(); + + /** + * detects all devices present + */ + void doDeviceDetection(); + + /** + * adds the given device to the manager + * @param dev the device to add + */ + void addVirtualDevice(BDVirtualDevice *dev); + + /** + * returns the device with the given number + * @param dev_num the device number + * @return the device + */ + BDVirtualDevice *getDeviceByNumber(uint32 dev_num); + + /** + * returns the device with the given name + * @param dev_name the device name + * @return the device + */ + BDVirtualDevice *getDeviceByName(const char *dev_name); + + /** + * returns the number of devices in the bd manager + * @return the number of devices + */ + uint32 getNumberOfDevices(); + + /** + * adds the given request to the device given in the request + * @param bdr the request + */ + void addRequest(BDRequest *bdr); + + /** + * calls seviceIRQ on the device the irq with the given number is on + * after that probeIRQ is false + * @param irq_num the irq number + */ + void serviceIRQ(uint32 irq_num); + + /** + * gets false when the irq is serviced + */ + bool probeIRQ; + + ustl::list device_list_; + + protected: + static BDManager *instance_; +}; + + diff --git a/pwn/flipper/dist/common/include/fs/BDVirtualDevice.h b/pwn/flipper/dist/common/include/fs/BDVirtualDevice.h new file mode 100644 index 0000000..03be7de --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/BDVirtualDevice.h @@ -0,0 +1,101 @@ +#pragma once + +#include "types.h" +#include "ulist.h" +#include "ustring.h" + +class BDDriver; +class BDRequest; + +class BDDriver; +class BDRequest; + +class BDVirtualDevice +{ + public: + BDVirtualDevice(BDDriver *driver, uint32 offset, uint32 num_sectors, uint32 sector_size, const char *name, + bool writable); + + void addRequest(BDRequest *command); + + uint32 getBlockSize() const + { + return block_size_; + } + + uint32 getDeviceNumber() const + { + return dev_number_; + } + + BDDriver *getDriver() + { + return driver_; + } + + const char *getName() + { + return name_.c_str(); + } + + uint32 getNumBlocks() + { + return num_sectors_ / (block_size_ / sector_size_); + } + + /** + * reads the data from the inode on the current device + * @param offset where to start to read + * @param size number of bytes that should be read + * @param buffer to save the data that has been read + * + */ + virtual int32 readData(uint32 offset, uint32 size, char *buffer); + + /** + * reads the data from the inode on the current device + * @param offset where to start to write + * @param size number of bytes that should be written + * @param buffer data, that should be written + * + */ + virtual int32 writeData(uint32 offset, uint32 size, char *buffer); + + /** + * the PartitionType is a 8bit field in the PartitionTable of a MBR + * it specifies the FileSystem which is installed on the partition + * @param part_type partition type value to be applied to the Device + */ + void setPartitionType(uint8 part_type); + + /** + * getting the PartitionType of this Device (value of the 8bit field + * in Partition Table of the MBR) + * @return the partition type + */ + uint8 getPartitionType(void) const; + + void setDeviceNumber(uint32 number) + { + dev_number_ = number; + } + + void setBlockSize(uint32 block_size) + { + assert(block_size % sector_size_ == 0); + block_size_ = block_size; + } + + private: + BDVirtualDevice(); + uint32 dev_number_; + uint32 offset_; + uint32 num_sectors_; + uint32 sector_size_; + uint32 block_size_; + bool writable_; + BDDriver* driver_; + uint8 partition_type_; + ustl::string name_; +}; + diff --git a/pwn/flipper/dist/common/include/fs/Dentry.h b/pwn/flipper/dist/common/include/fs/Dentry.h new file mode 100644 index 0000000..2d50d89 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/Dentry.h @@ -0,0 +1,165 @@ +#pragma once + +#include "types.h" +#include +#include "kstring.h" +#include +#include "ustring.h" + +class Inode; + +/** + * The VFS layer does all management of path names of files, and converts them + * into entries in the dentry before passing allowing the underlying + * file-system to see them. The dentry object associates the component to its + * corresponding inode. + */ +class Dentry +{ + protected: + friend class MinixFSInode; + friend class VfsSyscall; + /** + * The pointer to the inode related to this name. + */ + Inode *d_inode_; + + /** + * This will point to the parent dentry. For the root of a file-system, or + * for an anonymous entry like that for a file, this points back to the + * containing dentry itself. + */ + Dentry *d_parent_; + + /** + * This list_head is used to link together all the children of the dentry. + */ + ustl::list d_child_; + + /** + * For a directory that has had a file-system mounted on it, this points to + * the mount point of that current file-system. For other dentries, this + * points back to the dentry itself. + */ + Dentry *d_mounts_; + + public: + + /** + * set the inode to the dentry + * @param inode the inode to set + */ + void setInode(Inode *inode); + + /** + * release the inode to the dentry + */ + void releaseInode() + { + d_inode_ = 0; + } + + /** + * get the inode to dentry + * @return the inode + */ + Inode* getInode() + { + return d_inode_; + } + + /** + * return the parent of the dentry + * @return the dentry + */ + Dentry* getParent() + { + return d_parent_; + } + + /** + * set the parent dentry + * @param parent the parent dentry to set + */ + void setParent(Dentry *parent) + { + d_parent_ = parent; + } + + /** + * return the mount_point of the current file-system + * @return the dentry of the mount point + */ + Dentry* getMountedRoot() + { + return d_mounts_; + } + + /** + * set the mount point + * @param mount_point the dentry to set the mount point to + */ + void setMountedRoot(Dentry *mount_point) + { + d_mounts_ = mount_point; + } + + /** + * set the child to the dentry + * @param dentry the child dentry to set + * @return 0 on success + */ + int32 setChild(Dentry *dentry); + + /** + * check the existance of the child-list + * @return true is empty + */ + bool emptyChild(); + + /** + * get the number of the child + * @return the number of childs + */ + uint32 getNumChild(); + + /** + * get the child of the child-list + * @param indes the index of the child to get + * @return the found child dentry + */ + Dentry* getChild(uint32 index); + + /** + * return the name of the dentry + * @return the dentry's name + */ + const char* getName(); + + /** + * This should compare the name with the all names of the d_child_ list. + * It should return the Dentry if it exists the same name in the list, + * @return the dentry found, 0 if doesn't exist. + */ + virtual Dentry* checkName(const char* name); + + /** + * remove a child_dentry from the d_child_ list. + * @param child_dentry the child dentry of the curent dentry. + * @return 0 on success + */ + virtual int32 childRemove(Dentry *child_dentry); + + /** + * insert a child dentry to the d_child_ list. + * @param child_dentry the child dentry of the current dentry. + */ + virtual void childInsert(Dentry *child_dentry); + + public: + Dentry(Inode* inode); // root dentry + Dentry(Inode* inode, Dentry* parent, const ustl::string& name); // named dentry + virtual ~Dentry(); + ustl::string d_name_; +}; + diff --git a/pwn/flipper/dist/common/include/fs/Dirent.h b/pwn/flipper/dist/common/include/fs/Dirent.h new file mode 100644 index 0000000..0e2640a --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/Dirent.h @@ -0,0 +1,6 @@ +#pragma once + +class Dirent +{ +}; + diff --git a/pwn/flipper/dist/common/include/fs/File.h b/pwn/flipper/dist/common/include/fs/File.h new file mode 100644 index 0000000..01fa0c4 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/File.h @@ -0,0 +1,178 @@ +#pragma once + +#include "types.h" +#include "ulist.h" + +class Superblock; +class Inode; +class Dentry; +class FileDescriptor; + +#define O_RDONLY 0x0001 +#define O_WRONLY 0x0002 +#define O_RDWR 0x0004 +#define O_CREAT 0x0008 +#define O_APPEND 0x0010 +#define O_EXCL 0x0020 +#define O_NONBLOCK 0x0040 +#define O_TRUNC 0x0080 +#define O_SYNC 0x0100 +#define O_DSYNC 0x0200 +#define O_RSYNC O_SYNC + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif + + +class File +{ + public: + uint32 uid; + uint32 gid; + + /** + * interna version number. + */ + uint32 version; + + protected: + + /** + * The superblock pointing to this file + */ + Superblock* f_superblock_; + + /** + * The inode associated to the file. + */ + Inode* f_inode_; + + /** + * The dentry pointing to this file/ + */ + Dentry* f_dentry_; + + /** + * The flags specified when the file was opened + */ + uint32 flag_; + + + /** + * Current offset in the file + */ + l_off_t offset_; + + /** + * List of open file descriptors + */ + ustl::list f_fds_; + + public: + /** + * returns the files flag + * @return the flag + */ + uint32 getFlag() + { + return flag_; + } + + public: + + /** + * The Constructor + * @param inode the files inode + * @param dentry the files dentry + * @param flag the files flag + */ + File(Inode* inode, Dentry* dentry, uint32 flag); + + virtual ~File(); + + virtual FileDescriptor* openFd(); + virtual int closeFd(FileDescriptor* fd); + + + + Dentry* getDentry() + { + return f_dentry_; + } + Inode* getInode() + { + return f_inode_; + } + + /** + * Sets the file position relative to the start of the file, the end of the + * file or the current file position. + * @param offset is the offset to set. + * @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END. + * @returns the offset from the start off the file or -1 on failure. + */ + l_off_t lseek(l_off_t offset, uint8 origin); + + /** + * not implemented here + * reads from the file + * @param buffer is the buffer where the data is written to + * @param count is the number of bytes to read. + * @param offset is the offset to read from counted from the current file position. + */ + virtual int32 read(char */*buffer*/, size_t /*count*/, l_off_t /*offset*/) + { + return 0; + } + + /** + * not implemented here + * write to the file + * @param buffer is the buffer where the data is read from + * @param count is the number of bytes to write. + * @param offset is the offset to write from counted from the current file position + */ + virtual int32 write(const char */*buffer*/, size_t /*count*/, l_off_t /*offset*/) + { + return 0; + } + + /** + * Opens the file + * @param inode is the inode the read the file from. + */ + virtual int32 open(uint32) + { + return 0; + } + + /** + * not implemented here + * Close the file + * @param inode is close, the superblock has the information, that this + * inode is not use anymore. + */ + virtual int32 close() + { + return 0; + } + + /** + * not implemented here + * Flush all off the file's write operations. The File will be written to disk. + * @return is the error code of the flush operation. + */ + virtual int32 flush() + { + return 0; + } + + virtual uint32 getSize(); +}; diff --git a/pwn/flipper/dist/common/include/fs/FileDescriptor.h b/pwn/flipper/dist/common/include/fs/FileDescriptor.h new file mode 100644 index 0000000..5ed96bc --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/FileDescriptor.h @@ -0,0 +1,42 @@ +#pragma once + +#include "types.h" +#include "ulist.h" +#include "umap.h" +#include "Mutex.h" + +class File; +class FileDescriptor; +class FileDescriptorList; + +class FileDescriptor +{ + protected: + size_t fd_; + File* file_; + + public: + FileDescriptor ( File* file ); + virtual ~FileDescriptor(); + uint32 getFd() { return fd_; } + File* getFile() { return file_; } + + friend File; +}; + +class FileDescriptorList +{ +public: + FileDescriptorList(); + ~FileDescriptorList(); + + int add(FileDescriptor* fd); + int remove(FileDescriptor* fd); + FileDescriptor* getFileDescriptor(uint32 fd); + +private: + ustl::list fds_; + Mutex fd_lock_; +}; + +extern FileDescriptorList global_fd_list; diff --git a/pwn/flipper/dist/common/include/fs/FileSystemInfo.h b/pwn/flipper/dist/common/include/fs/FileSystemInfo.h new file mode 100644 index 0000000..9f69672 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/FileSystemInfo.h @@ -0,0 +1,70 @@ +#pragma once + +#include "types.h" +#include "ustring.h" +#include "Path.h" + +class Dentry; +class VfsMount; + +class FileSystemInfo +{ + protected: + /** + * File system root + */ + Path root_; + + /** + * Current working directory + */ + Path pwd_; + + + public: + FileSystemInfo(); + ~FileSystemInfo(); + FileSystemInfo(const FileSystemInfo& fsi); + + /** + * set the ROOT-info to the class + * @param root the root path to set + */ + void setRoot(const Path& path) + { + root_ = path; + } + + /** + * set the PWD-info to the class (PWD: print working directory) + * @param path the current path to set + */ + void setPwd(const Path& path) + { + pwd_ = path; + } + + /** + * get the ROOT-info (ROOT-directory) from the class + * @return the root path + */ + Path& getRoot() + { + return root_; + } + + /** + * get the PWD-info (PWD-directory) from the class + * @return the path of the current directory + */ + Path& getPwd() + { + return pwd_; + } +}; + +extern FileSystemInfo* default_working_dir; +// you use a different getcwd() method depending on where your cpp is being compiled +// (it can come either from Thread.cpp or from exe2minixfs.cpp) +FileSystemInfo* getcwd(); + diff --git a/pwn/flipper/dist/common/include/fs/FileSystemType.h b/pwn/flipper/dist/common/include/fs/FileSystemType.h new file mode 100644 index 0000000..e2cfab4 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/FileSystemType.h @@ -0,0 +1,54 @@ +#pragma once + +#include "types.h" + +class Superblock; +class Dentry; + +#define FS_REQUIRES_DEV 0x0001 // located on a physical disk device +#define FS_NOMOUNT 0x0010 // Filesystem has no mount point + +#define MAX_FILE_SYSTEM_TYPES 16 + +class FileSystemType +{ + + protected: + const char *fs_name_; + int32 fs_flags_; + + public: + FileSystemType(const char *fs_name); + virtual ~FileSystemType(); + + FileSystemType const &operator =(FileSystemType const &instance) + { + fs_name_ = instance.fs_name_; + fs_flags_ = instance.fs_flags_; + return (*this); + } + + const char* getFSName() const; + void setFSName(const char* fs_name); + int32 getFSFlags() const; + void setFSFlags(int32 fs_flags); + + /** + * Reads the superblock from the device. + * @param superblock is the superblock to fill with data. + * @param data is the data given to the mount system call. + * @return is a pointer to the resulting superblock. + */ + virtual Superblock *readSuper(Superblock *superblock, void *data) const = 0; + + /** + * Creates an Superblock object for the actual file system type. + * @param s_dev a valid device number or -1 if no block device is available + * (e.g. for pseudo file systems) + * @return a pointer to the Superblock object, 0 if wasn't possible to + * create a Superblock with the given device number + */ + virtual Superblock *createSuper(uint32 s_dev) = 0; + +}; + diff --git a/pwn/flipper/dist/common/include/fs/Inode.h b/pwn/flipper/dist/common/include/fs/Inode.h new file mode 100644 index 0000000..021c79f --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/Inode.h @@ -0,0 +1,283 @@ +#pragma once + +#include "types.h" +#include "kprintf.h" +#include +#include +#include "Dentry.h" +#include "assert.h" + +class File; +class Superblock; + +/** + * three possible inode state bits: + */ +#define I_UNUSED 0 // the unused inode state +#define I_DIRTY 1 // Dirty inodes are on the per-super-block s_dirty_ list, and +// will be written next time a sync is requested. +#define I_LOCK 2 //state not implemented + +#define A_READABLE 0x0001 +#define A_WRITABLE 0x0002 +#define A_EXECABLE 0x0004 + +/** + * five possible inode type bits: + */ +#define I_FILE 0 +#define I_DIR 1 +#define I_LNK 2 +#define I_CHARDEVICE 3 +#define I_BLOCKDEVICE 4 + +/** + * The per-inode flags: + */ +#define MS_NODEV 2 // If this inode is a device special file, it cannot be +// opend. +#define INODE_DEAD 666 + +class Inode +{ + protected: + ustl::list i_dentrys_; + + /** + * The (open) file of this inode. + */ + ustl::list i_files_; + + /** + * the number of Dentry links to this inode. + */ + uint32 i_nlink_; + + /** + * the number of runtime references to this inode (loaded Dentrys, open files, ...) + */ + uint32 i_refcount_; + + Superblock *superblock_; + + /** + * current file size in bytes + */ + uint32 i_size_; + + /** + * Inode type: I_FILE, I_DIR, I_LNK, ... + */ + uint32 i_type_; + + /** + * There are three possible inode state bits: I_DIRTY, I_LOCK, I_UNUSED. + */ + uint32 i_state_; + + /** + * The inodes permission flag + */ + uint32 i_mode_; + public: + + /** + * contructor + * @param super_block the superblock to create the inode on + * @param inode_type the inode type + */ + Inode(Superblock *super_block, uint32 inode_type); + + virtual ~Inode(); + + uint32 incRefCount(); + uint32 decRefCount(); + uint32 numRefs(); + + uint32 incLinkCount(); + uint32 decLinkCount(); + uint32 numLinks(); + + void addDentry(Dentry* dentry); + void removeDentry(Dentry* dentry); + bool hasDentry(Dentry* dentry); + + + /** + * lookup should check if that name (given by the char-array) exists in the + * directory (I_DIR inode) and should return the Dentry if it does. + * This involves finding and loading the inode. If the lookup failed to find + * anything, this is indicated by returning NULL-pointer. + * @param name the name to look for + * @return the dentry found + */ + virtual Dentry* lookup(const char* /*name*/); + + /** + * Called when a file is opened + */ + virtual File* open(Dentry* /*dentry*/, uint32 /*flag*/) + { + return 0; + } + + /** + * Called when the last reference to a file is closed + */ + virtual int32 release(File* /*file*/); + + /** + * This should create a symbolic link in the given directory with the given + * name having the given value. It should d_instantiate the new inode into + * the dentry on success. + * @param inode the inode to link to + * @param dentry yhe dentry to create the link in + * @param link_name the name of the link to create + * @return 0 on success + */ + virtual int32 symlink(Inode */*inode*/, Dentry */*dentry*/, const char */*link_name*/) + { + return 0; + } + + /** + * Create a directory with the given dentry. + * @param the dentry + * @return 0 on success + */ + virtual int32 mkdir(Dentry *); + + /** + * Create a file with the given dentry. + * @param dentry the dentry + * @return 0 on success + */ + virtual int32 mkfile(Dentry */*dentry*/); + + /** + * Create a special file with the given dentry. + * @param the dentry + * @return 0 on success + */ + virtual int32 mknod(Dentry*); + + /** + * Create a hard link with the given dentry. + * @param the dentry + * @return 0 on success + */ + virtual int32 link(Dentry*); + + /** + * Unlink the given dentry from the inode. + * @param the dentry + * @return 0 on success + */ + virtual int32 unlink(Dentry*); + + /** + * Remove the named directory (if empty). + * @return 0 on success + */ + virtual int32 rmdir(Dentry*); + + /** + * change the name to new_name + * @param new name the new name + * @retunr 0 on success + */ + virtual int32 rename(const char* /*new_name*/) + { + return 0; + } + + /** + * The symbolic link referred to by the dentry is read and the value is + * copied into the user buffer (with copy_to_user) with a maximum length + * given by the integer. + * @param dentry the dentry + * @param max_length the maximum length + * @return the number of bytes read + */ + virtual int32 readlink(Dentry */*dentry*/, char*, int32 /*max_length*/) + { + return 0; + } + + /** + * If the directory (parent dentry) have a directory and a name within that + * directory (child dentry) then the obvious result of following the name + * from the directory would arrive at the child dentry. (for symlink) + * @param prt_dentry the parent dentry + * @param chd_dentry the child dentry + * @return the dentry + */ + virtual Dentry* followLink(Dentry */*prt_dentry*/, Dentry */*chd_dentry*/) + { + return 0; + } + + /** + * read the data from the inode + * @param offset the offset from where to start + * @param size the number of bytes to read + * @param buffer where to store the read data + * @return the number of bytes read + */ + virtual int32 readData(uint32 /*offset*/, uint32 /*size*/, char */*buffer*/) + { + return 0; + } + + /** + * write the data to the inode + * @param offset the offset from where to start writing + * @param size the number of bytes to write + * @param buffer where to write the data to + * @return number of bytes written + */ + virtual int32 writeData(uint32 /*offset*/, uint32 /*size*/, const char*/*buffer*/) + { + return 0; + } + + Superblock* getSuperblock() + { + return superblock_; + } + + void setSuperBlock(Superblock * sb) + { + superblock_ = sb; + } + + uint32 getType() + { + return i_type_; + } + + ustl::list& getDentrys() + { + return i_dentrys_; + } + + uint32 getNumOpenedFile() + { + return i_files_.size(); + } + + uint32 getSize() + { + return i_size_; + } + + uint32 getMode() + { + return i_mode_; + } + + int32 flush() + { + return 0; + } +}; diff --git a/pwn/flipper/dist/common/include/fs/Path.h b/pwn/flipper/dist/common/include/fs/Path.h new file mode 100644 index 0000000..6cd47d9 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/Path.h @@ -0,0 +1,28 @@ +#pragma once + +#include "types.h" +#include "ustring.h" + +class Dentry; +class VfsMount; + +class Path +{ +public: + Path() = default; + Path(Dentry* dentry, VfsMount* mnt); + Path(const Path&) = default; + Path& operator=(const Path&) = default; + bool operator==(const Path&) const; + + Path parent(const Path* global_root = nullptr) const; + int child(const ustl::string& name, Path& out) const; + + ustl::string getAbsolutePath(const Path* global_root = nullptr) const; + + bool isGlobalRoot(const Path* global_root = nullptr) const; + bool isMountRoot() const; + + Dentry* dentry_; + VfsMount* mnt_; +}; diff --git a/pwn/flipper/dist/common/include/fs/PathWalker.h b/pwn/flipper/dist/common/include/fs/PathWalker.h new file mode 100644 index 0000000..5cea19b --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/PathWalker.h @@ -0,0 +1,76 @@ +#pragma once + +#include "types.h" +#include "ustring.h" + +class Dentry; +class VfsMount; +class Path; +class FileSystemInfo; + +/** + * @enum Type of the last component on LOOKUP_PARENT + */ +enum +{ + /** + * The last component is a regular filename + */ + LAST_NORM, + + /** + * The last component is "." + */ + LAST_DOT, + + /** + * The last component is ".." + */ + LAST_DOTDOT, +}; + +/** + * @enum Error Codes for the path walk + */ +enum +{ + PW_SUCCESS = 0, + /** + * The path was not found + */ + PW_ENOTFOUND, + /** + * The path to look up is invalid + */ + PW_EINVALID +}; + +class PathWalker +{ + public: + + /** + * Perform a file system lookup + * @param pathname File pathname to be resolved + * @param pwd Start directory of the file system walk + * @param root Root directory for the file system walk + * @param out Output parameter: Found file path + * @param parent Optional output parameter: Parent directory + * @return Returns 0 on success, != 0 on error + */ + static int32 pathWalk(const char* pathname, const Path& pwd, const Path& root, Path& out, Path* parent = nullptr); + + static int32 pathWalk(const char* pathname, FileSystemInfo* fs_info, Path& out, Path* parent_dir = nullptr); + + static ustl::string pathPrefix(const ustl::string& path); + static ustl::string lastPathSegment(const ustl::string& path, bool ignore_separator_at_end = false); + + private: + static size_t getNextPartLen(const char* path); + static int pathSegmentType(const char* segment); + + PathWalker(); + ~PathWalker(); +}; + + diff --git a/pwn/flipper/dist/common/include/fs/Superblock.h b/pwn/flipper/dist/common/include/fs/Superblock.h new file mode 100644 index 0000000..eebd097 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/Superblock.h @@ -0,0 +1,162 @@ +#pragma once + +#include "types.h" +#include + +class Iattr; +class Statfs; +class WaitQueue; +class FileSystemType; +class VirtualFileSystem; +class FileDescriptor; + +class Dentry; +class Inode; +class File; + +class Superblock +{ + public: + + friend class VirtualFileSystem; + + /** + * This records an identification number that has been read from the device + * to confirm that the data on the device corresponds to the file-system + */ + uint64 s_magic_; + + protected: + + const FileSystemType *s_type_; + + /** + * The device that this file-system is mounted on. + */ + size_t s_dev_; + + /** + * This is a list of flags which are logically with the flags in each + * inode to detemine certain behaviours. There is one flag which applies + * only to the whole file-system. + * exp: MS_RDONLY + * A file-system with the flag set has been mounted read-only. No writing + * be permitted, and no indirect modification, such as mount time in the + * super-block or access times on files, will be made. + */ + uint64 s_flags_; + + /** + * The Dentry refers the root of the file-system. It is normally created by + * loading the root inode from the file-system. + */ + Dentry *s_root_; + + /** + * The old Dentry of the mount point of a mounted file system + */ + Dentry *s_mountpoint_; + + /** + * A list of dirty inodes. + */ + ustl::list dirty_inodes_; + + /** + * A list of used inodes. It is only used to open-file. + */ + ustl::list used_inodes_; + + /** + * inodes of the superblock. + */ + ustl::list all_inodes_; + + /** + * This is a list of files (linked on f_list) of open files on this + * file-system. It is used, for example, to check if there are any files + * open for write before remounting the file-system as read-only. + */ + ustl::list s_files_; + + + public: + + /** + * constructor + * @param s_dev the device number of the new filesystem + */ + Superblock(FileSystemType* fs_type, size_t s_dev); + + virtual ~Superblock(); + + /** + * create a new Inode of the superblock + * @param dentry the dentry to create the inode with + * @param type the inode type + * @return the created inode + */ + virtual Inode* createInode(uint32 type) = 0; + + /** + * This method is called to read a specific inode from a mounted + * file-system. + * @param inode the inode to read + * @return 0 on success + */ + virtual int32 readInode(Inode* /*inode*/) + { + return 0; + } + + /** + * This method is called to write a specific inode to a mounted file-system, + * and gets called on inodes which have been marked dirty. + * @param inode the inode to write + */ + virtual void writeInode(Inode* /*inode*/) + { + } + + /** + * This method is called whenever the reference count on an inode reaches 0, + * and it is found that the link count (i_nlink= is also zero. It si + * presumed that the file-system will deal with this situation be + * invalidating the inode in the file-system and freeing up any resourses + * used. + * @param inode the inode to delete + */ + virtual void deleteInode(Inode* /*inode*/); + + + virtual int fileOpened(File* file); + virtual int fileReleased(File* file); + + virtual void releaseAllOpenFiles(); + virtual void deleteAllInodes(); + + /** + * Get the root Dentry of the Superblock + * @return the root dentry + */ + Dentry *getRoot(); + + /** + * Get the mount point Dentry of the Superblock + * @return the superblocks mount point dentry + */ + Dentry *getMountPoint(); + + /** + * Set the mount point Dentry of the Superblock + */ + void setMountPoint(Dentry* mountpoint); + + /** + * Get the File System Type of the Superblock + * @return the file system type + */ + FileSystemType *getFSType(); +}; + + diff --git a/pwn/flipper/dist/common/include/fs/VfsMount.h b/pwn/flipper/dist/common/include/fs/VfsMount.h new file mode 100644 index 0000000..18e6601 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/VfsMount.h @@ -0,0 +1,108 @@ +#pragma once + +#include "types.h" +#include "VirtualFileSystem.h" + +class Superblock; +class Dentry; + +extern VirtualFileSystem vfs; + +// Mount flags +// Only MS_RDONLY is supported by now. + +/** + * Mount the Filesystem read-only + */ +#define MS_RDONLY 1 + +class VfsMount +{ + protected: + + /** + * Points to the parent filesystem on which this filesystem is mounted on. + */ + VfsMount *mnt_parent_; + + /** + * Points to the Dentry of the mount directory of this filesystem. + */ + Dentry *mnt_mountpoint_; + + /** + * Points to the Dentry of the root directory of this filesystem. + */ + Dentry *mnt_root_; + + /** + * Points to the superblock object of this filesystem. + */ + Superblock *mnt_sb_; + + /** + * The mnt_flags_ field of the descriptor stores the value of several flags + * that specify how some kinds of files in the mounted filesystem are + * handled. + */ + int32 mnt_flags_; + + public: + VfsMount(); + + + /** + * constructor + * @param parent the parent dentry of the mount point + * @param mountpoint the mount points dentry + * @param root the root dentry + * @param superblock the superblock mounted + * @param flags the flags + */ + VfsMount(VfsMount* parent, Dentry * mountpoint, Dentry* root, + Superblock* superblock, int32 flags); + + virtual ~VfsMount(); + + /** + * get the parent-VfsMount of the VfsMount + * @return the parent-VfsMount + */ + VfsMount *getParent() const; + + /** + * get the mount-point of the VfsMount + * @return the mount point dentry + */ + Dentry *getMountPoint() const; + + /** + * get the ROOT-directory of the VfsMount + * @return the root dentry + */ + Dentry *getRoot() const; + + /** + * get the superblock fo the VfsMount + * @return the superblock + */ + Superblock *getSuperblock() const; + + /** + * get the flags + * @return the flags + */ + int32 getFlags() const; + + /** + * NOTE: only used as workaround + */ + void clear(); + + + bool isRootMount() const; + +}; + + + diff --git a/pwn/flipper/dist/common/include/fs/VfsSyscall.h b/pwn/flipper/dist/common/include/fs/VfsSyscall.h new file mode 100644 index 0000000..7360d07 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/VfsSyscall.h @@ -0,0 +1,150 @@ +#pragma once + +#include "types.h" + +class Dirent; +class Dentry; +class VfsMount; +class FileDescriptor; +class VfsSyscall; +class Path; +class FileSystemInfo; + +class VfsSyscall +{ + public: + + /** + * make a new directory. + * i.e. im the path "/file/test/" create a new directory with the name + * "dir". => the new_dir ist "/file/test/dir" + * @param pathname the new directory. + * @param type the permission. + * @return On success, zero is returned. On error, -1 is returned. + */ + static int32 mkdir(const char* pathname, int32 /*type*/); + + /** + * The readdir() displays or saves the names from all childs into buffer and returns a pointer + * to a Dirent. + * @param pathname the destination-directory. + * @param buffer the buffer the output is saved to + * @param size the size of buffer in bytes + * @return the dirent + */ + static Dirent* readdir(const char* pathname, char* buffer = 0, size_t size = 0); + + /** + * chdir() changes the current directory to the specified directory. + * @param dir the destination-directory. + * @return On success, zero is returned. On error, -1 is returned. + */ + static int32 chdir(const char* pathname); + + /** + * delete a directory, which must be empty. + * @param pathname the removed directory + * @return On success, zero is returned. On error, -1 is returned. + */ + static int32 rmdir(const char* pathname); + + /** + * remove a directory (which must be empty) or a file + * @param pathname the removed directory or file + * @return On success, zero is returned. On error, -1 is returned. + */ + static int32 rm(const char* pathname); + + /** + * The open() is used to convert a pathname into a file descriptor, if the + * pathname does not exist, create a new file. + * @param pathname the file pathname + * @param flag specified when the file was opened + * @return On success, file descriptor is returned. On error, -1 is returned. + */ + static int32 open(const char* pathname, uint32 flag); + + /** + * The close() closes a file descriptor. + * @param fd the file descriptor + * @return On success, zero is returned. On error, -1 is returned. + */ + static int32 close(uint32 fd); + + /** + * The read() attempts to read up to count bytes from file descriptor fd + * into the buffer starting at buffter. + * @param fd the file descriptor + * @param buffer the buffer that to read the date + * @param count the size of the byte + * @return On success, the number of bytes read is returned (zero indicates + * end of file), and the file position is advanced by this number. + * On error, -1 is returned. + */ + static int32 read(uint32 fd, char* buffer, uint32 count); + + /** + * Sets the file position relative to the start of the file, the end of the + * file or the current file position. + * @param fd the file descriptor + * @param offset is the offset to set. + * @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END. + * @returns the offset from the start off the file or -1 on failure. + */ + static l_off_t lseek(uint32 fd, l_off_t offset, uint8 origin); + + /** + * write writes up to count bytes to the file referenced by the file + * descriptor fd from the buffer starting at buf. + * @param fd the file descriptor + * @param buffer the buffer that to store the date + * @param count the size of the byte + * @return On success, the number of bytes written are returned (zero + * indicates nothing was written). On error, -1 is returned + */ + static int32 write(uint32 fd, const char *buffer, uint32 count); + + /** + * flushes the file with the given file descriptor to the disc + * so that changes in the system are written to disc + * @param fd the file descriptor + * @return 0 on success, -1 on error + */ + static int32 flush(uint32 fd); + + /** + * mounts a file system + * @param device_name the device name i.e. ida + * @param dir_name the directory name where to mount the filesystem + * @param file_system_name the file system name i.e. minixfs + * @param flag the flag indicates if mounted readonly etc. + * @return 0 on success + */ + static int32 mount(const char *device_name, const char *dir_name, const char *file_system_name, int32 flag); + + /** unmounts a filesystem + * @param dir_name the directory where the filesystem to unmount is mounted + * @param flag not used + * @return 0 on success + */ + static int32 umount(const char *dir_name, int32 flag); + + /** + * returns the size of a file + * @param fd the file looking for + * @return the size + */ + static uint32 getFileSize(uint32 fd); + + /** + * get the File descriptor object from the global variable + * @param the fd int + * @return the file descriptor object + */ + static FileDescriptor* getFileDescriptor(uint32 fd); + + private: + VfsSyscall(); + ~VfsSyscall(); +}; + diff --git a/pwn/flipper/dist/common/include/fs/VirtualFileSystem.h b/pwn/flipper/dist/common/include/fs/VirtualFileSystem.h new file mode 100644 index 0000000..12226dc --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/VirtualFileSystem.h @@ -0,0 +1,106 @@ +#pragma once + +#include "types.h" +#include + +/** + * File system flag indicating if the system in question requires an device. + */ +#define FS_REQUIRES_DEV 0x0001 // located on a physical disk device +#define FS_NOMOUNT 0x0010 // Filesystem has no mount point + +/** + * The maximal number of file system types. + */ +#define MAX_FILE_SYSTEM_TYPES 16 + +class Superblock; +class FileSystemType; +class VfsMount; +class Dentry; +class FileSystemInfo; + +class VirtualFileSystem +{ + protected: + ustl::list superblocks_; + ustl::list mounts_; + ustl::list file_system_types_; + + public: + void initialize(); + VirtualFileSystem(); + ~VirtualFileSystem(); + + /** + * register the file-system-type to the vfs + * @param file_system_type the file system type to register + * @return 0 on success, -1 if a file-system-type with that name has + * already been registered + */ + int32 registerFileSystem(FileSystemType *file_system_type); + + /** + * unregister the file-system-typt to the vfs + * @param file_system_type the file system type to unregister + * @return 0 on success + */ + int32 unregisterFileSystem(FileSystemType *file_system_type); + + /** + * The getFsType function receives a filesystem name as its parameter, scans + * the list of registered filesystems looking at the fs_name field of their + * descriptors, and returns a pointer to the corresponding FileSystemType + * object, if is present. + * @param fs_name the name of the filesystem + * @return the file system type + */ + FileSystemType *getFsType(const char* fs_name); + + /** + * found the VfsMount from mounts_ list with given dentry. + * @param dentry the mount-point-dentry or root-dentry + * @param is_mount_point if it is false, check with root-dentry, + * else mount-point-dentry + */ + VfsMount *getVfsMount(const Dentry* dentry, bool is_root = false); + + /** + * mount the dev_name (device name) to the directory specified by dir_name. + * @param dev_name the device file name of the block device storing the + * filesystem. Shall be a empty string to mount pseudo + * file sytems. + * @param dir_name the mount pointer directory + * @param fs_name the name of the type of filesystem to be mounted + * @param flags the mount flags + * @param data contain arbitray fs-dependent information (or be NULL) + * @return On success, zero is returned. On error, -1 is returned. + */ + int32 mount(const char* dev_name, const char* dir_name, const char* fs_name, uint32 flags/*, void *data*/); + + /** + * unmount the filesystem + * @param dir_name the mount pointer direcotry or (block devie block filename) + * @param flags the umount flags + * @return On success, zero is returned. On error, -1 is returned. + */ + int32 umount(const char* dir_name, uint32 flags); + + /** + * mount the ROOT to the VFS. (special of the mount) + * @param fs_name the name of the type of filesystem to be mounted + * @param flags the mount flags + * @return On success, zero is returned. On error, -1 is returned. + */ + FileSystemInfo *rootMount(const char* fs_name, uint32 flags); + + /** + * umount the ROOT from the VFS (special of the umount) + * @return On success, zero is returned. On error, -1 is returned. + */ + int32 rootUmount(); + +}; + +extern VirtualFileSystem vfs; + diff --git a/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSSuperblock.h b/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSSuperblock.h new file mode 100644 index 0000000..5eb4857 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSSuperblock.h @@ -0,0 +1,44 @@ +#pragma once + +#include "fs/Superblock.h" +#include "fs/ramfs/RamFSSuperblock.h" + +class Inode; +class Superblock; +class CharacterDevice; +class DeviceFSType; + +class DeviceFSSuperBlock : public RamFSSuperblock +{ + public: + static const char ROOT_NAME[]; + static const char DEVICE_ROOT_NAME[]; + + virtual ~DeviceFSSuperBlock(); + + /** + * addsa new device to the superblock + * @param inode the inode of the device to add + * @param node_name the device name + */ + void addDevice(Inode* inode, const char* node_name); + + /** + * Access method to the singleton instance + */ + static DeviceFSSuperBlock* getInstance(); + + private: + + /** + * Constructor + * @param s_root the root Dentry of the new Filesystem + * @param s_dev the device number of the new Filesystem + */ + DeviceFSSuperBlock(DeviceFSType* fs_type, uint32 s_dev); + + protected: + static DeviceFSSuperBlock* instance_; + +}; + diff --git a/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSType.h b/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSType.h new file mode 100644 index 0000000..0e9e29d --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/devicefs/DeviceFSType.h @@ -0,0 +1,34 @@ +#pragma once + +#include "fs/FileSystemType.h" +#include "fs/ramfs/RamFSType.h" + +class DeviceFSType : public RamFSType +{ + public: + DeviceFSType(); + + virtual ~DeviceFSType(); + + /** + * Reads the superblock from the device. + * @param superblock is the superblock to fill with data. + * @param data is the data given to the mount system call. + * @return is a pointer to the resulting superblock. + */ + virtual Superblock *readSuper(Superblock *superblock, void *data) const; + + /** + * Creates an Superblock object for the actual file system type. + * @param root the root dentry of the new superblock + * @param s_dev the device number of the new superblock + * @return a pointer to the Superblock object + */ + virtual Superblock *createSuper(uint32 s_dev); + + static DeviceFSType* getInstance(); + +protected: + static DeviceFSType* instance_; +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixFSFile.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSFile.h new file mode 100644 index 0000000..921ebce --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSFile.h @@ -0,0 +1,43 @@ +#pragma once + +#include "File.h" + +class MinixFSFile : public File +{ + public: + + /** + * constructor + * @param inode the inode of the file + * @param dentry the dentry + * @param flag the flag i.e. readonly + */ + MinixFSFile(Inode* inode, Dentry* dentry, uint32 flag); + + virtual ~MinixFSFile(); + + /** + * reads from the file + * @param buffer the buffer where the data is written to + * @param count the number of bytes to read + * @param offset the offset to read from counted from the current file position + * @return the number of bytes read + */ + virtual int32 read(char *buffer, size_t count, l_off_t offset); + + /** + * writes to the file + * @param buffer the buffer where the data is read from + * @param count the number of bytes to write + * @param offset the offset to write from counted from the current file position + * @return the number of bytes written + */ + virtual int32 write(const char *buffer, size_t count, l_off_t offset); + + /** + * writes all data to disc + * @return 0 on success + */ + virtual int32 flush(); +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixFSInode.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSInode.h new file mode 100644 index 0000000..4586d9c --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSInode.h @@ -0,0 +1,141 @@ +#pragma once + +#include "types.h" +#include "kstring.h" +#include "Inode.h" +#include "MinixFSZone.h" +#include + +class MinixFSInode : public Inode +{ + friend class MinixFSSuperblock; + + protected: + + /** + * the zones storing the addresses of memory of this inode + */ + MinixFSZone *i_zones_; + + /** + * the inode number (the first inode has the i_num 1 on a minix file system) + */ + uint32 i_num_; + + /** + * reads all the inode's children from disc and creates their objects + */ + virtual void loadChildren(); + + public: + + /** + * basic constructor + * @param super_block the superblock the inode is on + * @param inode_type the inode type (I_FILE, I_DIR) + */ + MinixFSInode(Superblock *super_block, uint32 inode_type); + + /** + * constructor of an inode existing on disc with all data given + * @param super_block the superblock the inode is on + * @param i_mode the mode containing the rights and the inode type (I_FILE, I_DIR) + * @param i_size the inodes size + * @param i_nlinks the number of links to this inode + * @param i_zones the first 9 zone addresses + * @param i_num the inode number + */ + MinixFSInode(Superblock *super_block, uint16 i_mode, uint32 i_size, uint16 i_nlinks, uint32* i_zones, uint32 i_num); + virtual ~MinixFSInode(); + + /** + * lookup checks if that name (given by the char-array) exists in the + * directory (I_DIR inode) and returns the Dentry if it does. + * This involves finding and loading the inode. If the lookup failed to find + * anything, this is indicated by returning NULL-pointer. + * @param name the name to look for + * @return the dentry found or NULL otherwise + */ + virtual Dentry* lookup(const char *name); + + /** + * Called when a file is opened + */ + virtual File* open(Dentry* dentry, uint32 /*flag*/); + + /** + * creates a directory with the given dentry. It is only used to with directory. + * @param dentry the dentry to create with + * @return 0 on success + */ + virtual int32 mkdir(Dentry *dentry); + + virtual int32 link(Dentry* dentry); + virtual int32 unlink(Dentry* dentry); + + /** + * removes the directory (if it is empty) + * @return 0 on success + */ + virtual int32 rmdir(Dentry* dentry); + + + /** + * creates a directory with the given dentry. + * @param dentry the dentry + * @return 0 on success + */ + virtual int32 mknod(Dentry *dentry); // no dir no file + + /** + * creates a file with the given dentry. + * @param dentry the dentry + * @return 0 on success + */ + virtual int32 mkfile(Dentry *dentry); + + /** + * read the data from the inode + * @param offset offset byte + * @param size the size of data that read from this inode + * @param buffer the dest char-array to store the data + * @return the number of bytes read + */ + virtual int32 readData(uint32 offset, uint32 size, char *buffer); + + /** + * write the data to the inode + * @param offset offset byte + * @param size the size of data that write to this inode (data_) + * @param buffer the src char-array + * @return the number of bytes written + */ + virtual int32 writeData(uint32 offset, uint32 size, const char *buffer); + + /** + * flushes the inode to the file system + * @return 0 on success + */ + virtual int32 flush(); + + private: + /** + * writes the inode dentry to disc + * @param dest_i_num the inode number to write the dentry to + * @param src_i_num the inode number to write + * @param name the name to write there + */ + void writeDentry(uint32 dest_i_num, uint32 src_i_num, const char* name); + + /** + * finding the position of the dentry of the given inode in this inode + * @param i_num the inode number to look for + * @return the dentry position + */ + int32 findDentry(uint32 i_num); + + /** + * true if the inodes children are allready loaded + */ + bool children_loaded_; +}; diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixFSSuperblock.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSSuperblock.h new file mode 100644 index 0000000..32587f9 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSSuperblock.h @@ -0,0 +1,201 @@ +#pragma once + +#include "Superblock.h" +#include "MinixStorageManager.h" +#include "umap.h" + +class Inode; +class MinixFSInode; +class Superblock; +class MinixFSType; + +class MinixFSSuperblock : public Superblock +{ + public: + friend class MinixFSInode; + friend class MinixFSZone; + friend class MinixStorageManager; + + MinixFSSuperblock(MinixFSType* fs_type, size_t s_dev, uint64 offset); + virtual ~MinixFSSuperblock(); + + /** + * creates one new inode of the superblock + * @param type the file type of the new inode (I_DIR, I_FILE) + * @return the new inode + */ + virtual Inode* createInode(uint32 type); + + /** + * reads one inode from the mounted file system + * @param inode the inode to read + * @return 0 on success + */ + virtual int32 readInode(Inode* inode); + + /** + * writes the inode from the mounted file system + * @param inode the inode to write + */ + virtual void writeInode(Inode* inode); + + /** + * removes one inode from the file system and frees all its resources + * @param inode the inode to delete + */ + virtual void deleteInode(Inode* inode); + + /** + * add an inode to the all_inodes_ data structures + * @param inode to add + */ + void all_inodes_add_inode(Inode* inode); + + /** + * remove an inode to the all_inodes_ data structures + * @param inode to remove + */ + void all_inodes_remove_inode(Inode* inode); + + /** + * allocates one zone on the file system + * @return the zone index + */ + virtual uint16 allocateZone(); + + /** + * frees zone on the file system + * @param index the zone index + */ + virtual void freeZone(uint16 index); + + protected: + + /** + * creates an Inode object with the given number from the file system + * @param i_num the inode number + * @return the Inode object + */ + MinixFSInode *getInode(uint16 i_num); + + /** + * creates an Inode object with the given number from the file system + * this overloaded version should be used; directories usually have + * "." and ".." entries, which are pointing to already loaded inodes!!! + * by now this method is only called from MinixFSInode::loadChildren + * @param i_num the inode number + * @param is_already_loaded should be set to true if already loaded + * @return the Inode object + */ + MinixFSInode *getInode(uint16 i_num, bool &is_already_loaded); + + /** + * reads one Zone from the file system to the given buffer + * @param zone the zone index to read + * @param buffer the buffer to write in + */ + void readZone(uint16 zone, char *buffer); + + /** + * reads the given number of blocks from the file system to the given buffer + * @param block the index of the block to start reading + * @param num_blocks the number of blcoks to read + * @param buffer the buffer to write in + */ + void readBlocks(uint16 block, uint32 num_blocks, char *buffer); + + /** + * writes one zone from the given buffer to the file system + * @param zone the zone index to write + * @param buffer the buffer to write + */ + void writeZone(uint16 zone, char *buffer); + + /** + * writes the given number of blcoks to the file system from the given buffer + * @param block the index of the first block to write + * @param num_blocks the number of blocks to write + * @param buffer the buffer to write + */ + void writeBlocks(uint16 block, uint32 num_blocks, char *buffer); + + /** + * writes the given number of bytes to the filesystem + * the bytes must be on one block + * @param block the block to write to + * @param offset the offset on the block + * @param size the number of bytes to write + * @param buffer the buffer with the bytes to write + * @return the number of bytes written + */ + int32 writeBytes(uint32 block, uint32 offset, uint32 size, char *buffer); + + /** + * reads the given number of bytes from the disc + * the bytes must be on one block + * @param block the block to read from + * @param offset the offset on the block + * @param size the number of bytes to read + * @param buffer the buffer to write to + * @return the number of bytes read + */ + int32 readBytes(uint32 block, uint32 offset, uint32 size, char *buffer); + + /** + * reads the fs header + */ + void readHeader(); + private: + + /** + * reads the root inode and its children from the filesystem + */ + void initInodes(); + + /** + * # usable inodes on the minor device + */ + uint32 s_num_inodes_; + /** + * # of blocks used by inode bit map + */ + uint16 s_num_inode_bm_blocks_; + /** + * # of blocks used by zone bit map + */ + uint16 s_num_zone_bm_blocks_; + /** + * number of first datazone + */ + uint16 s_1st_datazone_; + /** + * log2 of blocks/zone + */ + uint16 s_log_zone_size_; + /** + * maximum file size on this device + */ + uint32 s_max_file_size_; + + uint32 s_zones_; + + uint16 s_block_size_; + + uint8 s_disk_version_; + + MinixStorageManager* storage_manager_; + + + ustl::map all_inodes_set_; + + /** + * pointer to self for compatability + */ + Superblock* superblock_; + + /** + * offset in the image file (in image util) + */ + uint64 offset_; +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixFSType.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSType.h new file mode 100644 index 0000000..90d2d42 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSType.h @@ -0,0 +1,26 @@ +#pragma once + +#include "FileSystemType.h" + +class MinixFSType : public FileSystemType +{ + public: + MinixFSType(); + virtual ~MinixFSType(); + + /** + * reads the superblock from the device + * @param superblock a pointer to the resulting superblock + * @param data the data given to the mount system call + * @return the superblock + */ + virtual Superblock *readSuper(Superblock *superblock, void *data) const; + + /** + * creates an Superblock object for the actual file system type + * @param root the root dentry + * @param s_dev the device number + */ + virtual Superblock *createSuper(uint32 s_dev); +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixFSZone.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSZone.h new file mode 100644 index 0000000..13c9e4d --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixFSZone.h @@ -0,0 +1,39 @@ +#pragma once + +#include "types.h" + +class MinixFSSuperblock; + +class MinixFSZone +{ + public: + + /** + * constructor + * @param superblock the superblock + * @param zones the zone array from the file system + */ + MinixFSZone(MinixFSSuperblock *superblock, uint32 *zones); + ~MinixFSZone(); + uint32 getZone(uint32 index); + void setZone(uint32 index, uint32 zone); + void addZone(uint32 zone); + uint32 getNumZones() + { + return num_zones_; + } + void flush(uint32 inode_num); + void freeZones(); + + private: + + MinixFSSuperblock *superblock_; + uint32 direct_zones_[10]; + uint32 *indirect_zones_; + uint32 *double_indirect_linking_zone_; + uint32 **double_indirect_zones_; + + uint32 num_zones_; + +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/MinixStorageManager.h b/pwn/flipper/dist/common/include/fs/minixfs/MinixStorageManager.h new file mode 100644 index 0000000..b043858 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/MinixStorageManager.h @@ -0,0 +1,45 @@ +#pragma once + +#include "StorageManager.h" +#include "types.h" +#include "minix_fs_consts.h" + +class MinixFSSuperblock; + +class MinixStorageManager : public StorageManager +{ + public: + + /** + * constructor + * @param bm_buffer the buffer with the inode and zone bitmaps from disc + * @param num_inode_bm_blocks the number of blocks used for the inode bitmap + * @param num_zone_bm_blocks the number of blocks used for the zone bitmap + * @param num_inodes the max number of inodes + * @param num_zones the max number of zones + */ + MinixStorageManager(char *bm_buffer, uint16 num_inode_bm_blocks, uint16 num_zone_bm_blocks, uint16 num_inodes, + uint16 num_zones); + + virtual ~MinixStorageManager(); + + virtual size_t allocZone(); + virtual size_t allocInode(); + virtual void freeZone(size_t index); + virtual void freeInode(size_t index); + virtual bool isInodeSet(size_t index); + virtual uint32 getNumUsedInodes(); + void flush(MinixFSSuperblock *superblock); + void printBitmap(); + + private: + + size_t curr_zone_pos_; + size_t curr_inode_pos_; + + uint32 num_inode_bm_blocks_; + uint32 num_zone_bm_blocks_; + +}; + + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/StorageManager.h b/pwn/flipper/dist/common/include/fs/minixfs/StorageManager.h new file mode 100644 index 0000000..9c9fa5a --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/StorageManager.h @@ -0,0 +1,44 @@ +#pragma once + +#include "Bitmap.h" +#include "types.h" + +class StorageManager +{ + public: + + /** + * constructor + * @param num_inodes the max number of inodes + * @param num_zones the max number of zones + */ + StorageManager(uint16 num_inodes, uint16 num_zones); + + virtual ~StorageManager(); + + /** + * frees the zone at the given index + * @param index the zone index + */ + virtual void freeZone(size_t index) = 0; + + /** + * frees the inode at the given index + * @param index the inode index + */ + virtual void freeInode(size_t index) = 0; + + /** + * checks if inode is set + * @param index the inode index + * @return true if the inode is set + */ + virtual bool isInodeSet(size_t index) = 0; + + protected: + + Bitmap inode_bitmap_; + Bitmap zone_bitmap_; + +}; + diff --git a/pwn/flipper/dist/common/include/fs/minixfs/minix_fs_consts.h b/pwn/flipper/dist/common/include/fs/minixfs/minix_fs_consts.h new file mode 100644 index 0000000..a6b97eb --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/minixfs/minix_fs_consts.h @@ -0,0 +1,16 @@ +#pragma once + +#define V3_OFFSET ((superblock_->s_magic_==MINIX_V3) ? 1 : 0) +#define V3_ARRAY(PTR,IDX) ((superblock_->s_magic_==MINIX_V3) ? ((uint32*)(PTR))[(IDX)] : ((uint16*)(PTR))[(IDX)]) +#define SET_V3_ARRAY(PTR,IDX,VAL) do { if (superblock_->s_magic_==MINIX_V3) ((uint32*)(PTR))[(IDX)] = VAL; else ((uint16*)(PTR))[(IDX)] = VAL; } while (0) +#define NUM_ZONE_ADDRESSES ((superblock_->s_magic_==MINIX_V3) ? 256 : 512) +#define ZONE_SIZE 1024U +#define BLOCK_SIZE 1024U +#define INODE_BYTES ((superblock_->s_magic_==MINIX_V3) ? 4 : 2) +#define INODE_SIZE ((superblock_->s_magic_==MINIX_V3) ? 64 : 32) +#define INODES_PER_BLOCK ((superblock_->s_magic_==MINIX_V3) ? 16 : 32) +#define DENTRY_SIZE ((superblock_->s_magic_==MINIX_V3) ? 64 : 32) +#define MAX_NAME_LENGTH ((superblock_->s_magic_==MINIX_V3) ? 60 : 30) +#define NUM_ZONES ((superblock_->s_magic_==MINIX_V3) ? 10 : 9) +#define MINIX_V3 0x4d5a + diff --git a/pwn/flipper/dist/common/include/fs/ramfs/RamFSFile.h b/pwn/flipper/dist/common/include/fs/ramfs/RamFSFile.h new file mode 100644 index 0000000..5c07a9d --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/ramfs/RamFSFile.h @@ -0,0 +1,61 @@ +#pragma once + +#include "fs/File.h" + + +class RamFSFile: public File +{ + public: + + RamFSFile ( Inode* inode, Dentry* dentry, uint32 flag ); + + virtual ~RamFSFile(); + + /** + * Sets the file position relative to the start of the file, the end of + * the file or the current file position. + * @param offset is the offset to set. + * @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END. + * @return the offset from the start off the file or -1 on failure. + */ + l_off_t llSeek ( l_off_t offset, uint8 origin ); + + + /** + * reads from the file + * @param buffer is the buffer where the data is written to + * @param count is the number of bytes to read. + * @param offset is the offset to read from counted from the start of the file. + * @return the number of bytes read + */ + virtual int32 read ( char *buffer, size_t count, l_off_t offset ); + + /** + * writes to the file + * @param buffer is the buffer where the data is read from + * @param count is the number of bytes to write. + * @param offset is the offset to write from counted from the start of the file. + * @return the number of bytes written + */ + virtual int32 write ( const char *buffer, size_t count, l_off_t offset ); + + /** + * Opens the file + * @param flag how to open the file + * @return the filedescriptor + */ + virtual int32 open ( uint32 flag ); + + /** + * Closes the file + * @return 0 on success + */ + virtual int32 close(); + + /** + * Flushes all off the file's write operations. The File will be written to disk. + * @return is the error code of the flush operation. + */ + virtual int32 flush(); +}; + diff --git a/pwn/flipper/dist/common/include/fs/ramfs/RamFSInode.h b/pwn/flipper/dist/common/include/fs/ramfs/RamFSInode.h new file mode 100644 index 0000000..ccef9ac --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/ramfs/RamFSInode.h @@ -0,0 +1,40 @@ +#pragma once + +#include "types.h" +#include "fs/Inode.h" + +class RamFSInode : public Inode +{ + protected: + char* data_; + + public: + /** + * constructor + * @param super_block the superblock to create the inode on + * @param inode_type the inode type + */ + RamFSInode ( Superblock *super_block, uint32 inode_type ); + virtual ~RamFSInode(); + + /** + * Called when a file is opened + */ + virtual File* open(Dentry* dentry, uint32 /*flag*/); + + /// read the data from the inode + /// @param offset offset byte + /// @param size the size of data that read from this inode + /// @buffer the dest char-array to store the data + /// @return On successe, return 0. On error, return -1. + virtual int32 readData ( uint32 offset, uint32 size, char *buffer ); + + /// write the data to the inode + /// @param offset offset byte + /// @param size the size of data that write to this inode (data_) + /// @buffer the src char-array + /// @return On successe, return 0. On error, return -1. + virtual int32 writeData ( uint32 offset, uint32 size, const char *buffer ); + +}; + diff --git a/pwn/flipper/dist/common/include/fs/ramfs/RamFSSuperblock.h b/pwn/flipper/dist/common/include/fs/ramfs/RamFSSuperblock.h new file mode 100644 index 0000000..1dba92c --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/ramfs/RamFSSuperblock.h @@ -0,0 +1,53 @@ +#pragma once + +#include "fs/Superblock.h" + +class Inode; +class Superblock; +class RamFSType; + +class RamFSSuperblock : public Superblock +{ + public: + /** + * constructor + * @param s_root the root dentry of the new filesystem + * @param s_dev the device number of the new filesystem + */ + RamFSSuperblock (RamFSType* type, uint32 s_dev ); + virtual ~RamFSSuperblock(); + + /** + * create a new Inode of the superblock, mknod with dentry, add in the list. + * @param dentry the dentry to create the new inode with + * @param type the inode type + * @return the inode + */ + virtual Inode* createInode (uint32 type ); + + /** + * This method is called to read a specific inode from a mounted file-system. + * @param inode the inode to read + * @return 0 on success + */ + virtual int32 readInode ( Inode* inode ); + + /** + * This method is called to write a specific inode to a mounted file-system, + * and gets called on inodes which have been marked dirty. + * @param inode the inode to write + */ + virtual void writeInode ( Inode* inode ); + + /** + * This method is called whenever the reference count on an inode reaches 0, + * and it is found that the link count (i_nlink= is also zero. It is + * presumed that the file-system will deal with this situation be + * invalidating the inode in the file-system and freeing up any resourses + * used. + * @param inode the inode to delete + */ + virtual void deleteInode ( Inode* inode ); +}; +//----------------------------------------------------------------------------- + diff --git a/pwn/flipper/dist/common/include/fs/ramfs/RamFSType.h b/pwn/flipper/dist/common/include/fs/ramfs/RamFSType.h new file mode 100644 index 0000000..9d9b6e9 --- /dev/null +++ b/pwn/flipper/dist/common/include/fs/ramfs/RamFSType.h @@ -0,0 +1,25 @@ +#pragma once + +#include "fs/FileSystemType.h" + +class RamFSType : public FileSystemType +{ + public: + RamFSType(); + virtual ~RamFSType(); + + /** + * Reads the superblock from the device. + * @param superblock is the superblock to fill with data. + * @param data is the data given to the mount system call. + * @return is a pointer to the resulting superblock. + */ + virtual Superblock *readSuper(Superblock *superblock, void *data) const; + + /** + * Creates an Superblock object for the actual file system type. + * @return a pointer to the Superblock object + */ + virtual Superblock *createSuper(uint32 s_dev); +}; + diff --git a/pwn/flipper/dist/common/include/kernel/.keep b/pwn/flipper/dist/common/include/kernel/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pwn/flipper/dist/common/include/kernel/syscall-definitions.h b/pwn/flipper/dist/common/include/kernel/syscall-definitions.h new file mode 100644 index 0000000..88525f9 --- /dev/null +++ b/pwn/flipper/dist/common/include/kernel/syscall-definitions.h @@ -0,0 +1,21 @@ +#pragma once + +#define fd_stdin 0 +#define fd_stdout 1 +#define fd_stderr 2 + +#define sc_exit 1 +#define sc_fork 2 +#define sc_read 3 +#define sc_write 4 +#define sc_open 5 +#define sc_close 6 +#define sc_lseek 19 +#define sc_pseudols 43 +#define sc_outline 105 +#define sc_sched_yield 158 +#define sc_createprocess 191 +#define sc_trace 252 + +#define sc_flip_bit 69 + diff --git a/pwn/flipper/dist/common/include/ustl/LICENSE b/pwn/flipper/dist/common/include/ustl/LICENSE new file mode 100644 index 0000000..ad459b2 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/LICENSE @@ -0,0 +1,24 @@ +License for the USTL, forked from https://github.com/msharov/ustl + + + The MIT License + +Copyright (c) 2005 by Mike Sharov + +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. diff --git a/pwn/flipper/dist/common/include/ustl/cmemlink.h b/pwn/flipper/dist/common/include/ustl/cmemlink.h new file mode 100644 index 0000000..3a2593e --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/cmemlink.h @@ -0,0 +1,98 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "assert.h" +#include "ualgobase.h" + +/// The ustl namespace contains all ustl classes and algorithms. +namespace ustl { + +class istream; +class ostream; +class ostringstream; + +/// \class cmemlink cmemlink.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief A read-only pointer to a sized block of memory. +/// +/// Use this class the way you would a const pointer to an allocated unstructured block. +/// The pointer and block size are available through member functions and cast operator. +/// +/// Example usage: +/// +/// \code +/// void* p = malloc (46721); +/// cmemlink a, b; +/// a.link (p, 46721); +/// assert (a.size() == 46721)); +/// b = a; +/// assert (b.size() == 46721)); +/// assert (b.DataAt(34) == a.DataAt(34)); +/// assert (0 == memcmp (a, b, 12)); +/// \endcode +/// +class cmemlink { +public: + typedef char value_type; + typedef const value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type reference; + typedef value_type const_reference; + typedef size_t size_type; + typedef uint32_t written_size_type; + typedef ptrdiff_t difference_type; + typedef const_pointer const_iterator; + typedef const_iterator iterator; + typedef const cmemlink& rcself_t; +public: + inline cmemlink (void) : _data (nullptr), _size (0) { } + inline cmemlink (const void* p, size_type n) : _data (const_pointer(p)), _size (n) { assert (p || !n); } + inline cmemlink (const cmemlink& l) : _data (l._data), _size (l._size) {} + inline virtual ~cmemlink (void) noexcept {} + void link (const void* p, size_type n); + inline void link (const cmemlink& l) { link (l.begin(), l.size()); } + inline void link (const void* first, const void* last) { link (first, distance (first, last)); } + inline void relink (const void* p, size_type n); + virtual void unlink (void) noexcept { _data = nullptr; _size = 0; } + inline rcself_t operator= (const cmemlink& l) { link (l); return *this; } + bool operator== (const cmemlink& l) const noexcept; + inline void swap (cmemlink& l) { ::ustl::swap (_data, l._data); ::ustl::swap (_size, l._size); } + inline size_type size (void) const { return _size; } + inline size_type max_size (void) const { return size(); } + inline size_type readable_size (void) const { return size(); } + inline bool empty (void) const { return !size(); } + inline const_pointer data (void) const { return _data; } + inline const_pointer cdata (void) const { return _data; } + inline iterator begin (void) const { return iterator (cdata()); } + inline iterator iat (size_type i) const { assert (i <= size()); return begin() + i; } + inline iterator end (void) const { return iat (size()); } + inline void resize (size_type n) { _size = n; } + inline void read (istream&) { assert (!"ustl::cmemlink is a read-only object."); } + void write (ostream& os) const; + size_type stream_size (void) const noexcept; + void text_write (ostringstream& os) const; + void write_file (const char* filename, int mode = 0644) const; +private: + const_pointer _data; ///< Pointer to the data block (const) + size_type _size; ///< size of the data block +}; + +//---------------------------------------------------------------------- + +/// A fast alternative to link which can be used when relinking to the same block (i.e. when it is resized) +inline void cmemlink::relink (const void* p, size_type n) +{ + _data = reinterpret_cast(p); + _size = n; +} + +//---------------------------------------------------------------------- + +/// Use with cmemlink-derived classes to link to a static array +#define static_link(v) link (VectorBlock(v)) + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/config.h b/pwn/flipper/dist/common/include/ustl/config.h new file mode 100644 index 0000000..1af61b7 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/config.h @@ -0,0 +1,261 @@ +// config.h - Generated from config.h.in by configure. +#pragma once + +// Define to the one symbol short name of this package. +#define USTL_NAME "ustl" +// Define to the full name and version of this package. +// More or less. Was manually merged and updated from version ustl v2.2-3-gf0abf84 with SWEB specific changes. config.h file was mostly left as it is and not updated +// Based on ustl upstream commit c19d8291a471c47c808b5ef303f163df166cd388 +#define USTL_STRING "ustl v2.6-2-gc19d829" +// Define to the version of this package. +#define USTL_VERSION 0x260 +// Define to the address where bug reports for this package should be sent. +#define USTL_BUGREPORT "Mike Sharov " + +/// Define to 1 if you want stream operations to throw exceptions on +/// insufficient data or insufficient space. All these errors should +/// be preventable in output code; the input code should verify the +/// data in a separate step. It slows down stream operations a lot, +/// but it is your decision. By default only debug builds throw. +/// +#define WANT_STREAM_BOUNDS_CHECKING 0 + +/// Define to 1 if you want backtrace symbols demangled. +/// This adds some 15k to the library size, and requires that you link it and +/// any executables you make with the -rdynamic flag (increasing library size +/// even more). By default only the debug build does this. +#undef WANT_NAME_DEMANGLING + +/// Define to 1 if you want to build without libstdc++ +#define WITHOUT_LIBSTDCPP 1 + +/// Define GNU extensions if unavailable. +#ifndef __GNUC__ + /// GCC (and some other compilers) define '__attribute__'; ustl is using this + /// macro to alert the compiler to flag inconsistencies in printf/scanf-like + /// function calls. Just in case '__attribute__' is undefined, make a dummy. + /// + #ifndef __attribute__ + #define __attribute__(p) + #endif +#endif +#define WEAKALIAS(sym) __attribute__((weak,alias(sym))) +#if __GNUC__ >= 4 + #define DLL_EXPORT __attribute__((visibility("default"))) + #define DLL_LOCAL __attribute__((visibility("hidden"))) + #define INLINE __attribute__((always_inline)) +#else + #define DLL_EXPORT + #define DLL_LOCAL + #define INLINE +#endif +#if __cplusplus >= 201103L && (!__GNUC__ || (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 2)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #define HAVE_CPP11 1 + #if __cplusplus >= 201402 + #define HAVE_CPP14 1 + #endif +#endif +#if !HAVE_CPP11 + #define constexpr + #define override + #define final + #define nullptr NULL + #define noexcept throw() +#endif +#if __GNUC__ >= 3 && (__i386__ || __x86_64__) + /// GCC 3+ supports the prefetch directive, which some CPUs use to improve caching + #define prefetch(p,rw,loc) __builtin_prefetch(p,rw,loc) +#else + #define prefetch(p,rw,loc) +#endif +#if __GNUC__ < 3 + /// __alignof__ returns the recommended alignment for the type + #define __alignof__(v) min(sizeof(v), sizeof(void*)) + /// This macro returns 1 if the value of x is known at compile time. + #ifndef __builtin_constant_p + #define __builtin_constant_p(x) 0 + #endif +#endif + +// Define to empty if 'const' does not conform to ANSI C. +#undef const +// Define as '__inline' if that is what the C compiler calls it +#undef inline +// Define to 'long' if does not define. +#undef off_t +// Define to 'unsigned' if does not define. +#undef size_t + +/// gcc has lately decided that inline is just a suggestion +/// Define to 1 if when you say 'inline' you mean it! +#undef WANT_ALWAYS_INLINE +#if WANT_ALWAYS_INLINE + #define inline INLINE inline +#endif + +/// Define to 1 if you have the header file. +#undef HAVE_ASSERT_H + +/// Define to 1 if you have the header file. +#undef HAVE_CTYPE_H + +/// Define to 1 if you have the header file. +#undef HAVE_ERRNO_H + +/// Define to 1 if you have the header file. +#undef HAVE_FCNTL_H + +/// Define to 1 if you have the header file. +#undef HAVE_FLOAT_H + +/// Define to 1 if you have the header file. +#undef HAVE_INTTYPES_H + +/// Define to 1 if you have the header file. +#undef HAVE_LIMITS_H + +/// Define to 1 if you have the header file. +#undef HAVE_LOCALE_H + +// Define to 1 if you have the header file. +#undef HAVE_ALLOCA_H + +// Define to 1 if you have the header file. +#undef HAVE_SIGNAL_H + +// Define to 1 if you have the __va_copy function +#define HAVE_VA_COPY 1 + +// Define to 1 if you have the header file. +#undef HAVE_STDARG_H + +// Define to 1 if you have the header file. +#undef HAVE_STDDEF_H + +// Define to 1 if you have the header file. +#undef HAVE_STDINT_H + +// Define to 1 if you have the header file. +#undef HAVE_STDIO_H + +// Define to 1 if you have the header file. +#undef HAVE_STDLIB_H + +// Define to 1 if you have the header file. +#undef HAVE_STRING_H + +// Define to 1 if you have the 'strrchr' function. +#define HAVE_STRRCHR 1 + +// Define to 1 if you have the 'strsignal' function. +#define HAVE_STRSIGNAL 1 + +// Define to 1 if you have the header file. +#undef HAVE_SYS_STAT_H + +// Define to 1 if you have the header file. +#undef HAVE_SYS_TYPES_H + +// Define to 1 if you have the header file. +#undef HAVE_SYS_MMAN_H + +// Define to 1 if you have the header file. +#undef HAVE_TIME_H + +// Define to 1 if you have the header file. +#undef HAVE_UNISTD_H + +// Define to 1 if you have the header file. +#undef HAVE_MATH_H + +// Define to 1 if you have the header file. +#undef HAVE_EXECINFO_H + +// Define to 1 if you have the header file. +#if __GNUC__ >= 3 + #define HAVE_CXXABI_H 1 +#endif + +// Define to 1 if you have the rintf function. Will use rint otherwise. +#undef HAVE_RINTF + +// STDC_HEADERS is defined to 1 on sane systems. +#if HAVE_ASSERT_H && HAVE_CTYPE_H && HAVE_ERRNO_H && HAVE_FLOAT_H &&\ + HAVE_LIMITS_H && HAVE_LOCALE_H && HAVE_MATH_H && HAVE_SIGNAL_H &&\ + HAVE_STDARG_H && HAVE_STDDEF_H && HAVE_STDIO_H && HAVE_STDLIB_H &&\ + HAVE_STRING_H && HAVE_TIME_H + #define STDC_HEADERS 1 +#endif + +// STDC_HEADERS is defined to 1 on unix systems. +#if HAVE_FCNTL_H && HAVE_SYS_STAT_H && HAVE_UNISTD_H + #define STDUNIX_HEADERS 1 +#endif + +// Define to 1 if your compiler treats char as a separate type along with +// signed char and unsigned char. This will create overloads for char. +#undef HAVE_THREE_CHAR_TYPES + +// Define to 1 if you have 64 bit types available +#undef HAVE_INT64_T + +// Define to 1 if you have the long long type +#undef HAVE_LONG_LONG + +// Define to 1 if you want unrolled specializations for fill and copy +#define WANT_UNROLLED_COPY 1 + +// Define to 1 if you want to use MMX/SSE/3dNow! processor instructions +#define WANT_MMX 0 + +// Define to byte sizes of types +#undef SIZE_OF_CHAR +#undef SIZE_OF_SHORT +#undef SIZE_OF_INT +#undef SIZE_OF_LONG +#undef SIZE_OF_LONG_LONG +#undef SIZE_OF_POINTER +#undef SIZE_OF_SIZE_T +#undef SIZE_OF_BOOL +#undef SIZE_T_IS_LONG + +// Byte order macros, converted in utypes.h +#define USTL_LITTLE_ENDIAN 4321 +#define USTL_BIG_ENDIAN 1234 +#define USTL_BYTE_ORDER USTL_LITTLE_ENDIAN + +#if __i386__ || __x86_64__ +#define __x86__ 1 +#endif + +// Extended CPU capabilities +#undef CPU_HAS_FPU +#undef CPU_HAS_EXT_DEBUG +#undef CPU_HAS_TIMESTAMPC +#undef CPU_HAS_MSR +#undef CPU_HAS_CMPXCHG8 +#undef CPU_HAS_APIC +#undef CPU_HAS_SYSCALL +#undef CPU_HAS_MTRR +#undef CPU_HAS_CMOV +#undef CPU_HAS_FCMOV +#if WANT_MMX +#undef CPU_HAS_MMX +#undef CPU_HAS_FXSAVE +#undef CPU_HAS_SSE +#undef CPU_HAS_SSE2 +#undef CPU_HAS_SSE3 +#undef CPU_HAS_EXT_3DNOW +#undef CPU_HAS_3DNOW +#endif + +// GCC vector extensions +#if (CPU_HAS_MMX || CPU_HAS_SSE) && __GNUC__ >= 3 + #undef HAVE_VECTOR_EXTENSIONS +#endif + +#if CPU_HAS_SSE && __GNUC__ + #define __sse_align __attribute__((aligned(16))) +#else + #define __sse_align +#endif diff --git a/pwn/flipper/dist/common/include/ustl/memblock.h b/pwn/flipper/dist/common/include/ustl/memblock.h new file mode 100644 index 0000000..e1a3ab8 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/memblock.h @@ -0,0 +1,62 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "memlink.h" + +namespace ustl { + +/// \class memblock memblock.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief Allocated memory block. +/// +/// Adds memory management capabilities to memlink. Uses malloc and realloc to +/// maintain the internal pointer, but only if allocated using members of this class, +/// or if linked to using the Manage() member function. Managed memory is automatically +/// freed in the destructor. +/// +class memblock : public memlink { +public: + memblock (void) noexcept; + memblock (const void* p, size_type n); + explicit memblock (size_type n); + explicit memblock (const cmemlink& b); + explicit memblock (const memlink& b); + memblock (const memblock& b); + virtual ~memblock (void) noexcept; + virtual void unlink (void) noexcept override; + inline void assign (const cmemlink& l) { assign (l.cdata(), l.readable_size()); } + inline const memblock& operator= (const cmemlink& l) { assign (l); return *this; } + inline const memblock& operator= (const memlink& l) { assign (l); return *this; } + inline const memblock& operator= (const memblock& l) { assign (l); return *this; } + inline void swap (memblock& l) noexcept { memlink::swap (l); ::ustl::swap (_capacity, l._capacity); } + void assign (const void* p, size_type n); + void reserve (size_type newSize, bool bExact = false); + void resize (size_type newSize, bool bExact = true); + iterator insert (const_iterator start, size_type size); + iterator erase (const_iterator start, size_type size); + inline void clear (void) noexcept { resize (0); } + inline size_type capacity (void) const { return _capacity; } + inline bool is_linked (void) const { return !capacity(); } + inline size_type max_size (void) const { return is_linked() ? memlink::max_size() : SIZE_MAX; } + inline void manage (memlink& l) { manage (l.begin(), l.size()); } + void deallocate (void) noexcept; + void shrink_to_fit (void); + void manage (void* p, size_type n) noexcept; + void copy_link (void); + void read (istream& is); + void read_file (const char* filename); +#if HAVE_CPP11 + inline memblock (memblock&& b) : memlink(), _capacity(0) { swap (b); } + inline memblock& operator= (memblock&& b) { swap (b); return *this; } +#endif +protected: + virtual size_type minimumFreeCapacity (void) const noexcept __attribute__((const)); +private: + size_type _capacity; ///< Number of bytes allocated by Resize. +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/memlink.h b/pwn/flipper/dist/common/include/ustl/memlink.h new file mode 100644 index 0000000..95b6450 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/memlink.h @@ -0,0 +1,98 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "cmemlink.h" +#include "ualgo.h" + +namespace ustl { + +/// \class memlink memlink.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief Wrapper for pointer to block with size. +/// +/// Use this class the way you would a pointer to an allocated unstructured block. +/// The pointer and block size are available through member functions and cast operator. +/// +/// Example usage: +/// \code +/// void* p = malloc (46721); +/// memlink a, b; +/// a.link (p, 46721); +/// assert (a.size() == 46721)); +/// b = a; +/// assert (b.size() == 46721)); +/// assert (b.begin() + 34 == a.begin + 34); +/// assert (0 == memcmp (a, b, 12)); +/// a.fill (673, b, 42, 67); +/// b.erase (87, 12); +/// \endcode +/// +class memlink : public cmemlink { +public: + typedef value_type* pointer; + typedef cmemlink::pointer const_pointer; + typedef cmemlink::const_iterator const_iterator; + typedef pointer iterator; + typedef const memlink& rcself_t; +public: + inline memlink (void) : cmemlink() {} + inline memlink (void* p, size_type n) : cmemlink (p, n) {} + inline memlink (const void* p, size_type n) : cmemlink (p, n) {} + inline memlink (rcself_t l) : cmemlink (l) {} + inline explicit memlink (const cmemlink& l) : cmemlink (l) {} + inline pointer data (void) { return const_cast(cmemlink::data()); } + inline const_pointer data (void) const { return cmemlink::data(); } + inline iterator begin (void) { return iterator (data()); } + inline iterator iat (size_type i) { assert (i <= size()); return begin() + i; } + inline iterator end (void) { return iat (size()); } + inline const_iterator begin (void) const { return cmemlink::begin(); } + inline const_iterator end (void) const { return cmemlink::end(); } + inline const_iterator iat (size_type i) const { return cmemlink::iat (i); } + size_type writable_size (void) const { return size(); } + inline rcself_t operator= (const cmemlink& l) { cmemlink::operator= (l); return *this; } + inline rcself_t operator= (rcself_t l) { cmemlink::operator= (l); return *this; } + inline void link (const void* p, size_type n) { cmemlink::link (p, n); } + inline void link (void* p, size_type n) { cmemlink::link (p, n); } + inline void link (const cmemlink& l) { cmemlink::link (l); } + inline void link (memlink& l) { cmemlink::link (l); } + inline void link (const void* first, const void* last) { link (first, distance (first, last)); } + inline void link (void* first, void* last) { link (first, distance (first, last)); } + inline void relink (const void* p, size_type n) { cmemlink::relink (p, n); } + inline void relink (void* p, size_type n) { cmemlink::relink (p, n); } + inline void swap (memlink& l) { cmemlink::swap (l); } + void fill (const_iterator start, const void* p, size_type elsize, size_type elCount = 1) noexcept; + inline void insert (const_iterator start, size_type size); + inline void erase (const_iterator start, size_type size); + void read (istream& is); +}; + +/// Shifts the data in the linked block from \p start to \p start + \p n. +/// The contents of the uncovered bytes is undefined. +inline void memlink::insert (const_iterator cstart, size_type n) +{ + assert (data() || !n); + assert (cmemlink::begin() || !n); + assert (cstart >= begin() && cstart + n <= end()); + iterator start = const_cast(cstart); + rotate (start, end() - n, end()); +} + +/// Shifts the data in the linked block from \p start + \p n to \p start. +/// The contents of the uncovered bytes is undefined. +inline void memlink::erase (const_iterator cstart, size_type n) +{ + assert (data() || !n); + assert (cmemlink::begin() || !n); + assert (cstart >= begin() && cstart + n <= end()); + iterator start = const_cast(cstart); + rotate (start, start + n, end()); +} + +/// Use with memlink-derived classes to allocate and link to stack space. +#define alloca_link(m,n) (m).link (alloca (n), (n)) + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/metamac.h b/pwn/flipper/dist/common/include/ustl/metamac.h new file mode 100644 index 0000000..4b22a1a --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/metamac.h @@ -0,0 +1,89 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. +// +/// \file metamac.h +/// \brief Macros for complex metaprogramming involving pseudoiteration. + +#pragma once + +//---------------------------------------------------------------------- +// Functors and general utilities. +//---------------------------------------------------------------------- + +/// Evaluates to itself +#define ITSELF(x) x + +/// Concatenates \p a and \p b +#define PASTE(a,b) a##b + +//---------------------------------------------------------------------- +// Lists and other iterators +//---------------------------------------------------------------------- + +/// The maximum number of elements in REPEAT, LIST, and COMMA_LIST +#define METAMAC_MAXN 9 + +/// Simple list with no separators. Repeats x N times. +/// @{ +#define REPEAT_1(x) x(1) +#define REPEAT_2(x) REPEAT_1(x) x(2) +#define REPEAT_3(x) REPEAT_2(x) x(3) +#define REPEAT_4(x) REPEAT_3(x) x(4) +#define REPEAT_5(x) REPEAT_4(x) x(5) +#define REPEAT_6(x) REPEAT_5(x) x(6) +#define REPEAT_7(x) REPEAT_6(x) x(7) +#define REPEAT_8(x) REPEAT_7(x) x(8) +#define REPEAT_9(x) REPEAT_8(x) x(9) +#define REPEAT(N,x) PASTE(REPEAT_,N)(x) +/// @} + +/// Simple separated list. Repeats x N times with sep in between. +/// @{ +#define LIST_1(x,sep) x(1) +#define LIST_2(x,sep) LIST_1(x,sep) sep x(2) +#define LIST_3(x,sep) LIST_2(x,sep) sep x(3) +#define LIST_4(x,sep) LIST_3(x,sep) sep x(4) +#define LIST_5(x,sep) LIST_4(x,sep) sep x(5) +#define LIST_6(x,sep) LIST_5(x,sep) sep x(6) +#define LIST_7(x,sep) LIST_6(x,sep) sep x(7) +#define LIST_8(x,sep) LIST_7(x,sep) sep x(8) +#define LIST_9(x,sep) LIST_8(x,sep) sep x(9) +#define LIST(N,x,sep) PASTE(LIST_,N)(x,sep) +/// @} + +/// Comma separated list. A special case of LIST needed because the preprocessor can't substitute commas. +/// @{ +#define COMMA_LIST_1(x) x(1) +#define COMMA_LIST_2(x) COMMA_LIST_1(x), x(2) +#define COMMA_LIST_3(x) COMMA_LIST_2(x), x(3) +#define COMMA_LIST_4(x) COMMA_LIST_3(x), x(4) +#define COMMA_LIST_5(x) COMMA_LIST_4(x), x(5) +#define COMMA_LIST_6(x) COMMA_LIST_5(x), x(6) +#define COMMA_LIST_7(x) COMMA_LIST_6(x), x(7) +#define COMMA_LIST_8(x) COMMA_LIST_7(x), x(8) +#define COMMA_LIST_9(x) COMMA_LIST_8(x), x(9) +#define COMMA_LIST(N,x) PASTE(COMMA_LIST_,N)(x) +/// @} + +//---------------------------------------------------------------------- +// Macros for defining LIST arguments. +//---------------------------------------------------------------------- + +/// Ignores N, producing lists of identically named arguments. +#define LARG_NONE(name,N) name + +/// Appends N to name. +#define LARG_NUMBER(name,N) name##N + +/// name is a reference type. +#define LARG_REF(name,N) name##N& + +/// Sequential parameter passed by value with sequential types. +#define LARG_MT_PARAM_BY_VALUE(type,name,N) type##N name##N + +/// Sequential parameter passed by reference with sequential types. +#define LARG_MT_PARAM_BY_REF(type,name,N) type##N& name##N + +//---------------------------------------------------------------------- diff --git a/pwn/flipper/dist/common/include/ustl/mistream.h b/pwn/flipper/dist/common/include/ustl/mistream.h new file mode 100644 index 0000000..f80ee3b --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/mistream.h @@ -0,0 +1,295 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "memlink.h" +#include "strmsize.h" +#include "utf8.h" +#include "uios.h" +#if WANT_STREAM_BOUNDS_CHECKING + #include "typeinfo.h" +#endif + +namespace ustl { + +class ostream; +class memlink; +class string; + +/// \class istream mistream.h ustl.h +/// \ingroup BinaryStreams +/// +/// \brief Helper class to read packed binary streams. +/// +/// This class contains a set of functions to read integral types from an +/// unstructured memory block. Unpacking binary file data can be done this +/// way, for instance. aligning the data is your responsibility, and can +/// be accomplished by proper ordering of reads and by calling the align() +/// function. Unaligned access is usually slower by orders of magnitude and, +/// on some architectures, such as PowerPC, can cause your program to crash. +/// Therefore, all read functions have asserts to check alignment. +/// Overreading the end of the stream will also cause a crash (an assert in +/// debug builds). Oh, and don't be intimidated by the size of the inlines +/// here. In the assembly code the compiler will usually chop everything down +/// to five instructions each. +/// +/// Alignment rules for your objects: +/// - Assume your writes start off 4-byte aligned. +/// - After completion, \ref istream::align the stream to at least 4. +/// - If data portability between 32bit and 64bit platforms is important +/// (it often is not, in config files and the like), ensure you are always +/// using fixed-size types and are aligning to a fixed grain. Avoid writing +/// 8-byte types, and if you do, manually align before doing so. +/// - Non-default alignment is allowed if you plan to frequently write this +/// object in array form and alignment would be costly. For example, an +/// array of uint16_t-sized objects may leave the stream uint16_t aligned +/// as long as you know about it and will default-align the stream after +/// writing the array (note: \ref vector will already do this for you) +/// +/// Example code: +/// \code +/// memblock b; +/// b.read_file ("test.file"); +/// ostream is (b); +/// is >> boolVar >> ios::talign(); +/// is >> intVar >> floatVar; +/// is.read (binaryData, binaryDataSize); +/// is.align(); +/// \endcode +/// +class istream : public cmemlink, public ios_base { +public: + inline istream (void) : cmemlink(), _pos (0) {} + inline istream (const void* p, streamsize n) : cmemlink(p, n), _pos (0) {} + inline explicit istream (const cmemlink& source) : cmemlink (source), _pos (0) {} + explicit istream (const ostream& source) noexcept; + inline iterator end (void) const { return cmemlink::end(); } + inline void link (const void* p, streamsize n) { cmemlink::link (p, n); } + inline void link (const cmemlink& l) { cmemlink::link (l.cdata(), l.readable_size()); } + inline void link (const void* f, const void* l) { cmemlink::link (f, l); } + inline void relink (const void* p, streamsize n) { cmemlink::relink (p, n); _pos = 0; } + inline void relink (const cmemlink& l) { relink (l.cdata(), l.readable_size()); } + virtual void unlink (void) noexcept override; + virtual streamsize underflow (streamsize = 1); + inline uoff_t pos (void) const { return _pos; } + inline const_iterator ipos (void) const { return begin() + pos(); } + inline streamsize remaining (void) const { return size() - pos(); } + inline void seek (uoff_t newPos); + inline void iseek (const_iterator newPos); + inline void skip (streamsize nBytes); + inline bool aligned (streamsize grain = c_DefaultAlignment) const; + inline bool verify_remaining (const char* op, const char* type, streamsize n); + inline streamsize align_size (streamsize grain = c_DefaultAlignment) const; + inline void align (streamsize grain = c_DefaultAlignment); + inline void swap (istream& is); + inline void read (void* buffer, streamsize size); + inline void read (memlink& buf) { read (buf.begin(), buf.writable_size()); } + void read_strz (string& str); + streamsize readsome (void* s, streamsize n); + inline void read (istream&) { } + void write (ostream& os) const; + void text_write (ostringstream& os) const; + inline streamsize stream_size (void) const { return remaining(); } + template + inline void iread (T& v); + inline void ungetc (void) { seek (pos() - 1); } + inline off_t tellg (void) const { return pos(); } + inline void seekg (off_t p, seekdir d = beg); +private: + streamoff _pos; ///< The current read position. +}; + +//---------------------------------------------------------------------- + +template +inline streamsize required_stream_size (T, const Stream&) { return 1; } +template +inline streamsize required_stream_size (T v, const istream&) { return stream_size_of(v); } + +template +inline bool stream_at_eof (const Stream& stm) { return stm.eof(); } +template <> +inline bool stream_at_eof (const istream&) { return false; } + +/// \class istream_iterator +/// \ingroup BinaryStreamIterators +/// +/// \brief An iterator over an istream to use with uSTL algorithms. +/// +template +class istream_iterator { +public: + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef typename Stream::size_type size_type; + typedef input_iterator_tag iterator_category; +public: + istream_iterator (void) : _pis (nullptr), _v() {} + explicit istream_iterator (Stream& is) : _pis (&is), _v() { Read(); } + istream_iterator (const istream_iterator& i) : _pis (i._pis), _v (i._v) {} + /// Reads and returns the next value. + inline const T& operator* (void) { return _v; } + inline istream_iterator& operator++ (void) { Read(); return *this; } + inline istream_iterator& operator-- (void) { _pis->seek (_pis->pos() - 2 * stream_size_of(_v)); return operator++(); } + inline istream_iterator operator++ (int) { istream_iterator old (*this); operator++(); return old; } + inline istream_iterator operator-- (int) { istream_iterator old (*this); operator--(); return old; } + inline istream_iterator& operator+= (streamsize n) { while (n--) operator++(); return *this; } + inline istream_iterator& operator-= (streamsize n) { _pis->seek (_pis->pos() - (n + 1) * stream_size_of(_v)); return operator++(); } + inline istream_iterator operator- (streamoff n) const { istream_iterator result (*this); return result -= n; } + inline difference_type operator- (const istream_iterator& i) const { return distance (i._pis->pos(), _pis->pos()) / stream_size_of(_v); } + inline bool operator== (const istream_iterator& i) const { return (!_pis && !i._pis) || (_pis && i._pis && _pis->pos() == i._pis->pos()); } + inline bool operator< (const istream_iterator& i) const { return !i._pis || (_pis && _pis->pos() < i._pis->pos()); } +private: + void Read (void) + { + if (!_pis) + return; + const streamsize rs (required_stream_size (_v, *_pis)); + if (_pis->remaining() < rs && _pis->underflow (rs) < rs) { + _pis = nullptr; + return; + } + *_pis >> _v; + if (stream_at_eof (*_pis)) + _pis = nullptr; + } +private: + Stream* _pis; ///< The host stream. + T _v; ///< Last read value; cached to be returnable as a const reference. +}; + +//---------------------------------------------------------------------- + +/// Checks that \p n bytes are available in the stream, or else throws. +inline bool istream::verify_remaining (const char* op, const char* type, streamsize n) +{ + const streamsize rem = remaining(); + bool enough = n <= rem; + if (!enough) overrun (op, type, n, pos(), rem); + return enough; +} + +/// Sets the current read position to \p newPos +inline void istream::seek (uoff_t newPos) +{ +#if WANT_STREAM_BOUNDS_CHECKING + if (newPos > size()) + return overrun ("seekg", "byte", newPos, pos(), size()); +#else + assert (newPos <= size()); +#endif + _pos = newPos; +} + +/// Sets the current read position to \p newPos +inline void istream::iseek (const_iterator newPos) +{ + seek (distance (begin(), newPos)); +} + +/// Sets the current write position to \p p based on \p d. +inline void istream::seekg (off_t p, seekdir d) +{ + switch (d) { + case beg: seek (p); break; + case cur: seek (pos() + p); break; + case ios_base::end: seek (size() - p); break; + } +} + +/// Skips \p nBytes without reading them. +inline void istream::skip (streamsize nBytes) +{ + seek (pos() + nBytes); +} + +/// Returns the number of bytes to skip to be aligned on \p grain. +inline streamsize istream::align_size (streamsize grain) const +{ + return Align (pos(), grain) - pos(); +} + +/// Returns \c true if the read position is aligned on \p grain +inline bool istream::aligned (streamsize grain) const +{ + return pos() % grain == 0; +} + +/// aligns the read position on \p grain +inline void istream::align (streamsize grain) +{ + seek (Align (pos(), grain)); +} + +/// Reads type T from the stream via a direct pointer cast. +template +inline void istream::iread (T& v) +{ + assert (aligned (stream_align_of (v))); +#if WANT_STREAM_BOUNDS_CHECKING + if (!verify_remaining ("read", typeid(v).name(), sizeof(T))) + return; +#else + assert (remaining() >= sizeof(T)); +#endif + v = *reinterpret_cast(ipos()); + _pos += sizeof(T); +} + +/// Swaps contents with \p is +inline void istream::swap (istream& is) +{ + cmemlink::swap (is); + ::ustl::swap (_pos, is._pos); +} + +/// Reads \p n bytes into \p buffer. +inline void istream::read (void* buffer, size_type n) +{ +#if WANT_STREAM_BOUNDS_CHECKING + if (!verify_remaining ("read", "binary data", n)) + return; +#else + assert (remaining() >= n && "Reading past end of buffer. Make sure you are reading the right format."); +#endif + memcpy (reinterpret_cast(buffer), ipos(), n); + _pos += n; +} + +//---------------------------------------------------------------------- + +template struct object_reader { + inline void operator()(istream& is, T& v) const { v.read (is); } +}; +template struct integral_object_reader { + inline void operator()(istream& is, T& v) const { is.iread (v); } +}; +template +inline istream& operator>> (istream& is, T& v) { + typedef typename tm::Select ::is_integral, + integral_object_reader, object_reader >::Result object_reader_t; + object_reader_t()(is, v); + return is; +} +template +inline istream& operator>> (istream& is, const T& v) { v.read (is); return is; } + +//---------------------------------------------------------------------- + +typedef istream_iterator istream_iterator_for_utf8; +typedef utf8in_iterator utf8istream_iterator; + +/// Returns a UTF-8 adaptor reading from \p is. +inline utf8istream_iterator utf8in (istream& is) +{ + istream_iterator_for_utf8 si (is); + return utf8istream_iterator (si); +} + +//---------------------------------------------------------------------- + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/mostream.h b/pwn/flipper/dist/common/include/ustl/mostream.h new file mode 100644 index 0000000..950fb8d --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/mostream.h @@ -0,0 +1,266 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "memlink.h" +#include "utf8.h" +#include "uios.h" +#include "strmsize.h" +#if WANT_STREAM_BOUNDS_CHECKING + #include "typeinfo.h" +#endif + +namespace ustl { + +class istream; +class string; + +/// \class ostream mostream.h ustl.h +/// \ingroup BinaryStreams +/// +/// \brief Helper class to write packed binary streams. +/// +/// This class contains a set of functions to write integral types into an +/// unstructured memory block. Packing binary file data can be done this +/// way, for instance. aligning the data is your responsibility, and can +/// be accomplished by proper ordering of writes and by calling align. +/// Unaligned access is usually slower by orders of magnitude and, +/// on some architectures, such as PowerPC, can cause your program to crash. +/// Therefore, all write functions have asserts to check alignment. +/// See \ref istream documentation for rules on designing your data format. +/// Overwriting the end of the stream will also cause a crash (an assert in +/// debug builds). Oh, and don't be intimidated by the size of the inlines +/// here. In the assembly code the compiler will usually chop everything down +/// to five instructions each. +/// +/// Example code: +/// \code +/// memblock b; +/// ostream os (b); +/// os << boolVar << ios::talign(); +/// os << intVar << floatVar; +/// os.write (binaryData, binaryDataSize); +/// os.align(); +/// b.resize (os.pos()); +/// b.write_file ("test.file"); +/// \endcode +/// +class ostream : public memlink, public ios_base { +public: + inline ostream (void) : memlink(), _pos(0) {} + inline ostream (void* p, streamsize n) : memlink (p, n), _pos (0) {} + inline explicit ostream (const memlink& source) : memlink (source), _pos (0) {} + inline iterator end (void) { return memlink::end(); } + inline const_iterator end (void) const { return memlink::end(); } + inline void seek (uoff_t newPos); + inline void iseek (const_iterator newPos); + inline void skip (streamsize nBytes); + inline uoff_t pos (void) const { return _pos; } + inline iterator ipos (void) { return begin() + pos(); } + inline const_iterator ipos (void) const { return begin() + pos(); } + inline streamsize remaining (void) const; + inline bool aligned (streamsize grain = c_DefaultAlignment) const; + bool verify_remaining (const char* op, const char* type, size_t n); + inline streamsize align_size (streamsize grain = c_DefaultAlignment) const; + void align (streamsize grain = c_DefaultAlignment); + inline void write (const void* buffer, streamsize size); + inline void write (const cmemlink& buf); + void write_strz (const char* str); + void read (istream& is); + inline void write (ostream& os) const { os.write (begin(), pos()); } + void text_write (ostringstream& os) const; + inline size_t stream_size (void) const { return pos(); } + void insert (iterator start, streamsize size); + void erase (iterator start, streamsize size); + inline void swap (ostream& os); + template + inline void iwrite (const T& v); + inline virtual ostream& flush (void) { return *this; } + inline virtual streamsize overflow (streamsize=1) { return remaining(); } + virtual void unlink (void) noexcept override; + inline void link (void* p, streamsize n) { memlink::link (p, n); } + inline void link (memlink& l) { memlink::link (l.data(), l.writable_size()); } + inline void link (void* f, void* l) { memlink::link (f, l); } + inline void relink (void* p, streamsize n) { memlink::relink (p, n); _pos = 0; } + inline void relink (memlink& l) { relink (l.data(), l.writable_size()); } + inline void seekp (off_t p, seekdir d = beg); + inline off_t tellp (void) const { return pos(); } +protected: + inline void SetPos (uoff_t newPos) { _pos = newPos; } +private: + streamoff _pos; ///< Current write position. +}; + +//---------------------------------------------------------------------- + +/// \class ostream_iterator mostream.h ustl.h +/// \ingroup BinaryStreamIterators +/// +/// \brief An iterator over an ostream to use with uSTL algorithms. +/// +template +class ostream_iterator { +public: + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef typename Stream::size_type size_type; + typedef output_iterator_tag iterator_category; +public: + inline explicit ostream_iterator (Stream& os) + : _os (os) {} + inline ostream_iterator (const ostream_iterator& iter) + : _os (iter._os) {} + /// Writes \p v into the stream. + inline ostream_iterator& operator= (const T& v) + { _os << v; return *this; } + inline ostream_iterator& operator* (void) { return *this; } + inline ostream_iterator& operator++ (void) { return *this; } + inline ostream_iterator operator++ (int) { return *this; } + inline ostream_iterator& operator+= (streamsize n) { _os.skip (n); return *this; } + inline bool operator== (const ostream_iterator& i) const + { return _os.pos() == i._os.pos(); } + inline bool operator< (const ostream_iterator& i) const + { return _os.pos() < i._os.pos(); } +private: + Stream& _os; +}; + +//---------------------------------------------------------------------- + +typedef ostream_iterator ostream_iterator_for_utf8; +typedef utf8out_iterator utf8ostream_iterator; + +/// Returns a UTF-8 adaptor writing to \p os. +inline utf8ostream_iterator utf8out (ostream& os) +{ + ostream_iterator_for_utf8 si (os); + return utf8ostream_iterator (si); +} + +//---------------------------------------------------------------------- + +/// Checks that \p n bytes are available in the stream, or else throws. +inline bool ostream::verify_remaining (const char* op, const char* type, size_t n) +{ + const size_t rem = remaining(); + bool enough = n <= rem; + if (!enough) overrun (op, type, n, pos(), rem); + return enough; +} + +/// Move the write pointer to \p newPos +inline void ostream::seek (uoff_t newPos) +{ +#if WANT_STREAM_BOUNDS_CHECKING + if (newPos > size()) + return overrun ("seekp", "byte", newPos, pos(), size()); +#else + assert (newPos <= size()); +#endif + SetPos (newPos); +} + +/// Sets the current write position to \p newPos +inline void ostream::iseek (const_iterator newPos) +{ + seek (distance (begin(), const_cast(newPos))); +} + +/// Sets the current write position to \p p based on \p d. +inline void ostream::seekp (off_t p, seekdir d) +{ + switch (d) { + case beg: seek (p); break; + case cur: seek (pos() + p); break; + case ios_base::end: seek (size() - p); break; + } +} + +/// Skips \p nBytes without writing anything. +inline void ostream::skip (streamsize nBytes) +{ + seek (pos() + nBytes); +} + +/// Returns number of bytes remaining in the write buffer. +inline streamsize ostream::remaining (void) const +{ + return size() - pos(); +} + +/// Returns \c true if the write pointer is aligned on \p grain +inline bool ostream::aligned (streamsize grain) const +{ + return pos() % grain == 0; +} + +/// Returns the number of bytes to skip to be aligned on \p grain. +inline streamsize ostream::align_size (streamsize grain) const +{ + return Align (pos(), grain) - pos(); +} + +/// Writes \p n bytes from \p buffer. +inline void ostream::write (const void* buffer, size_type n) +{ +#if WANT_STREAM_BOUNDS_CHECKING + if (!verify_remaining ("write", "binary data", n)) + return; +#else + assert (remaining() >= n && "Buffer overrun. Check your stream size calculations."); +#endif + memcpy (ipos(), const_iterator(buffer), n); + _pos += n; +} + +/// Writes the contents of \p buf into the stream as a raw dump. +inline void ostream::write (const cmemlink& buf) +{ + write (buf.begin(), buf.size()); +} + +/// Writes type T into the stream via a direct pointer cast. +template +inline void ostream::iwrite (const T& v) +{ + assert (aligned (stream_align_of (v))); +#if WANT_STREAM_BOUNDS_CHECKING + if (!verify_remaining ("write", typeid(v).name(), sizeof(T))) + return; +#else + assert (remaining() >= sizeof(T)); +#endif + *reinterpret_cast(ipos()) = v; + SetPos (pos() + sizeof(T)); +} + +/// Swaps with \p os +inline void ostream::swap (ostream& os) +{ + memlink::swap (os); + ::ustl::swap (_pos, os._pos); +} + +//---------------------------------------------------------------------- + +template struct object_writer { + inline void operator()(ostream& os, const T& v) const { v.write (os); } +}; +template struct integral_object_writer { + inline void operator()(ostream& os, const T& v) const { os.iwrite (v); } +}; +template +inline ostream& operator<< (ostream& os, const T& v) { + typedef typename tm::Select ::is_integral, + integral_object_writer, object_writer >::Result object_writer_t; + object_writer_t()(os, v); + return os; +} + +//---------------------------------------------------------------------- + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/outerrstream.h b/pwn/flipper/dist/common/include/ustl/outerrstream.h new file mode 100644 index 0000000..3bfa968 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/outerrstream.h @@ -0,0 +1,135 @@ +#pragma once + +#include "sostream.h" +#include "kprintf.h" +#include "uios.h" + +namespace ustl { + + +/// \class coutclass sostream.h ustl.h +/// \ingroup TextStreams +/// +/// \brief This stream writes textual data into a memory block. +/// +class coutclass : public ostream { + public: + static void init(); + coutclass(); + coutclass(void* p, size_t n); + coutclass(void(*m_kprintf)(const char*, ...)); + coutclass(void* p, size_t n, void(*m_kprintf)(const char*, ...)); + void iwrite (uint8_t v); + void iwrite (wchar_t v); + inline void iwrite (int v) { iformat (v); } + inline void iwrite (unsigned int v) { iformat (v); } + inline void iwrite (long int v) { iformat (v); } + inline void iwrite (unsigned long int v) { iformat (v); } + void iwrite (bool v); + inline void iwrite (const char* s) { write (s, strlen(s)); } + inline void iwrite (const string& v) { write (v.begin(), v.size()); } + inline void iwrite (fmtflags f); +#if HAVE_LONG_LONG + inline void iwrite (long long v) { iformat (v); } + inline void iwrite (unsigned long long v) { iformat (v); } +#endif + inline size_type max_size (void) const { return 0; } + inline coutclass& put (char c) { iwrite (uint8_t(c)); return (*this); } + int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + inline void set_base (uint16_t b) { m_Base = b; } + inline void set_width (uint16_t w) { m_Width = w; } + inline void set_decimal_separator (char) { } + inline void set_thousand_separator (char) { } + inline void set_precision (uint16_t v) { m_Precision = v; } + void link (void* p, size_type n); + inline void link (memlink& l) { link (l.data(), l.writable_size()); } + void str (const string& s); + coutclass& write (const void* buffer, size_type size); + inline coutclass& write (const cmemlink& buf) { return (write (buf.begin(), buf.size())); } + inline coutclass& seekp (off_t p __attribute__((unused)), __attribute__((unused)) seekdir d =beg) { return (*this); } + coutclass& flush (void) { return (*this); } + virtual size_type overflow (size_type n = 1); +protected: + inline void reserve (__attribute__((unused)) size_type n) { } + inline size_type capacity (void) const { return 0; } +private: + inline void write_strz (const char*) { assert (!"Writing nul characters into a text stream is not allowed"); } + inline char* encode_dec (char* fmt, uint32_t n) const; + void fmtstring (char* fmt, const char* typestr, bool bInteger) const; + template + void iformat (T v); +private: + uint32_t m_Flags; ///< See ios_base::fmtflags. + uint16_t m_Width; ///< Field width. + uint8_t m_Base; ///< Numeric base for writing numbers. + uint8_t m_Precision; ///< Number of digits after the decimal separator. + void (*m_kprintf)(const char*, ...); +}; + +//---------------------------------------------------------------------- + +template +void coutclass::iformat (T v) +{ + char fmt [16]; + fmtstring (fmt, printf_typestring(v), numeric_limits::is_integer); + kprintf(fmt, v); +} + +/// Sets the flag \p f in the stream. +inline void coutclass::iwrite (fmtflags f) +{ + switch (f.f) { + case oct: set_base (8); break; + case dec: set_base (10); break; + case hex: set_base (16); break; + case left: m_Flags |= left; m_Flags &= ~right; break; + case right: m_Flags |= right; m_Flags &= ~left; break; + default: m_Flags |= f.f; break; + } +} + +//---------------------------------------------------------------------- + +template struct object_text_writer_cout { + inline void operator()(coutclass& os, const T& v) const { v.text_write (os); } +}; +template struct integral_text_object_writer_cout { + inline void operator()(coutclass& os, const T& v) const { os.iwrite (v); } +}; +template +inline coutclass& operator<< (coutclass& os, const T& v) { + typedef typename tm::Select ::is_integral, + integral_text_object_writer_cout, object_text_writer_cout >::Result object_writer_t; + object_writer_t()(os, v); + return (os); +} +// Needed because if called with a char[], numeric_limits will not work. Should be removed if I find out how to partial specialize for arrays... +inline coutclass& operator<< (coutclass& os, const char* v) + { os.iwrite (v); return (os); } +inline coutclass& operator<< (coutclass& os, char* v) + { os.iwrite (v); return (os); } + +//---------------------------------------------------------------------- + +template <> struct object_text_writer_cout { + inline void operator()(coutclass& os, const string& v) const { os.iwrite (v); } +}; +template struct integral_text_object_writer_cout { + inline void operator() (coutclass& os, const T* const& v) const + { os.iwrite ((uintptr_t)(v)); } +}; +#define COUTCLASS_CAST_OPERATOR(RealT, CastT) \ +template <> inline coutclass& operator<< (coutclass& os, const RealT& v) \ + { os.iwrite ((CastT)(v)); return (os); } +COUTCLASS_CAST_OPERATOR (uint8_t* const, const char*) +COUTCLASS_CAST_OPERATOR (int8_t, uint8_t) +COUTCLASS_CAST_OPERATOR (short int, int) +COUTCLASS_CAST_OPERATOR (unsigned short, unsigned int) +#if HAVE_THREE_CHAR_TYPES +COUTCLASS_CAST_OPERATOR (char, uint8_t) +#endif +#undef COUTCLASS_CAST_OPERATOR + +}; + diff --git a/pwn/flipper/dist/common/include/ustl/sistream.h b/pwn/flipper/dist/common/include/ustl/sistream.h new file mode 100644 index 0000000..3c2c4ac --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/sistream.h @@ -0,0 +1,132 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "mistream.h" +#include "ustring.h" +#ifndef EOF + #define EOF (-1) +#endif + +namespace ustl { + +/// \class istringstream sistream.h ustl.h +/// \ingroup TextStreams +/// +/// \brief A stream that reads textual data from a memory block. +/// +class istringstream : public istream { +public: + static const size_type c_MaxDelimiters = 16; ///< Maximum number of word delimiters. +public: + istringstream (void) noexcept; + istringstream (const void* p, size_type n) noexcept; + explicit istringstream (const cmemlink& source) noexcept; + inline fmtflags flags (void) const { return _flags; } + inline fmtflags flags (fmtflags f) { fmtflags of (_flags); _flags.f = f.f; return of; } + inline fmtflags setf (fmtflags f) { fmtflags of (_flags); _flags.f |= f.f; return of; } + inline fmtflags unsetf (fmtflags f) { fmtflags of (_flags); _flags.f &= ~f.f; return of; } + inline fmtflags setf (fmtflags f, fmtflags m) { unsetf(m); return setf(f); } + inline void iread (char& v) { v = skip_delimiters(); } + inline void iread (unsigned char& v) { char c; iread(c); v = c; } + void iread (int& v); + inline void iread (unsigned int& v) { int c; iread(c); v = c; } + inline void iread (short& v) { int c; iread(c); v = c; } + inline void iread (unsigned short& v) { int c; iread(c); v = c; } + void iread (long& v); + inline void iread (unsigned long& v) { long c; iread(c); v = c; } +#if HAVE_THREE_CHAR_TYPES + void iread (signed char& v) { char c; iread(c); v = c; } +#endif +#if HAVE_LONG_LONG + void iread (long long& v); + inline void iread (unsigned long long& v) { long long c; iread(c); v = c; } +#endif + /*inline void iread (float& v) { double c; iread(c); v = c; } + inline void iread (long double& v) { double c; iread(c); v = c; }*/ + inline void iread (fmtflags_bits f); + /*void iread (double& v); + inline void iread (float& v) { double c; iread(c); v = c; } + inline void iread (long double& v) { double c; iread(c); v = c; }*/ + void iread (bool& v); + void iread (wchar_t& v); + void iread (string& v); + inline string str (void) const { string s; s.link (*this); return s; } + inline istringstream& str (const string& s) { link (s); return *this; } + inline istringstream& get (char& c) { return read (&c, sizeof(c)); } + inline int get (void) { char c = EOF; get(c); return c; } + istringstream& get (char* p, size_type n, char delim = '\n'); + istringstream& get (string& s, char delim = '\n'); + istringstream& getline (char* p, size_type n, char delim = '\n'); + istringstream& getline (string& s, char delim = '\n'); + istringstream& ignore (size_type n, char delim = '\0'); + inline char peek (void) { char v = get(); ungetc(); return v; } + inline istringstream& unget (void) { ungetc(); return *this; } + inline void set_delimiters (const char* delimiters); + istringstream& read (void* buffer, size_type size); + inline istringstream& read (memlink& buf) { return read (buf.begin(), buf.size()); } + inline size_type gcount (void) const { return _gcount; } + inline istringstream& seekg (off_t p, seekdir d =beg) { istream::seekg(p,d); return *this; } + inline int sync (void) { skip (remaining()); return 0; } +protected: + char skip_delimiters (void); +private: + inline void read_strz (string&) { assert (!"Reading nul characters is not allowed from text streams"); } + inline bool is_delimiter (char c) const noexcept; + template void read_number (T& v); +private: + fmtflags _flags; + uint32_t _gcount; + char _delimiters [c_MaxDelimiters]; +}; + +//---------------------------------------------------------------------- + +void istringstream::iread (fmtflags_bits f) +{ + if (f & basefield) setf (f, basefield); + else if (f & floatfield) setf (f, floatfield); + else if (f & adjustfield) setf (f, adjustfield); + setf (f); +} + +/// Sets delimiters to the contents of \p delimiters. +void istringstream::set_delimiters (const char* delimiters) +{ +#if __x86__ && __SSE__ && HAVE_VECTOR_EXTENSIONS + typedef uint32_t v16ud_t __attribute__((vector_size(16))); + asm("xorps\t%%xmm0, %%xmm0\n\tmovups\t%%xmm0, %0":"=m"(*noalias_cast(_delimiters))::"xmm0"); +#else + memset (_delimiters, 0, sizeof(_delimiters)); +#endif + memcpy (_delimiters, delimiters, min (strlen(delimiters),sizeof(_delimiters)-1)); +} + +/// Reads a line of text from \p is into \p s +inline istringstream& getline (istringstream& is, string& s, char delim = '\n') + { return is.getline (s, delim); } + +//---------------------------------------------------------------------- + +template struct object_text_reader { + inline void operator()(istringstream& is, T& v) const { v.text_read (is); } +}; +template struct integral_text_object_reader { + inline void operator()(istringstream& is, T& v) const { is.iread (v); } +}; +template +inline istringstream& operator>> (istringstream& is, T& v) { + typedef typename tm::Select ::is_integral, + integral_text_object_reader, object_text_reader >::Result object_reader_t; + object_reader_t()(is, v); + return is; +} + +//---------------------------------------------------------------------- + +template <> struct object_text_reader { + inline void operator()(istringstream& is, string& v) const { is.iread (v); } +}; +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/sostream.h b/pwn/flipper/dist/common/include/ustl/sostream.h new file mode 100644 index 0000000..01ff668 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/sostream.h @@ -0,0 +1,213 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ustring.h" +#include "mostream.h" + +namespace ustl { + +class string; + +/// \class ostringstream sostream.h ustl.h +/// \ingroup TextStreams +/// +/// \brief This stream writes textual data into a memory block. +/// +class ostringstream : public ostream { +public: + ostringstream (const string& v = ""); + ostringstream (void* p, size_t n) noexcept; + inline fmtflags flags (void) const { return _flags; } + inline fmtflags flags (fmtflags f) { fmtflags of (_flags); _flags.f = f.f; return of; } + inline fmtflags setf (fmtflags f) { fmtflags of (_flags); _flags.f |= f.f; return of; } + inline fmtflags unsetf (fmtflags f) { fmtflags of (_flags); _flags.f &= ~f.f; return of; } + inline fmtflags setf (fmtflags f, fmtflags m) { unsetf(m); return setf(f); } + void iwrite (unsigned char v); + void iwrite (wchar_t v); + inline void iwrite (char v) { iwrite (static_cast(v)); } + inline void iwrite (short v) { iformat (v); } + inline void iwrite (unsigned short v) { iformat (v); } + inline void iwrite (int v) { iformat (v); } + inline void iwrite (unsigned int v) { iformat (v); } + inline void iwrite (long int v) { iformat (v); } + inline void iwrite (unsigned long int v) { iformat (v); } + /*inline void iwrite (float v) { iformat (v); } + inline void iwrite (double v) { iformat (v); } + inline void iwrite (long double v) { iformat (v); }*/ + void iwrite (bool v); + inline void iwrite (const char* s) { write (s, strlen(s)); } + inline void iwrite (const unsigned char* s) { iwrite (reinterpret_cast(s)); } + inline void iwrite (const string& v) { write (v.begin(), v.size()); } + inline void iwrite (fmtflags_bits f); +#if HAVE_THREE_CHAR_TYPES + inline void iwrite (signed char v) { iwrite (static_cast(v)); } +#endif +#if HAVE_LONG_LONG + inline void iwrite (long long v) { iformat (v); } + inline void iwrite (unsigned long long v) { iformat (v); } +#endif + inline size_type max_size (void) const { return _buffer.max_size(); } + inline ostringstream& put (char c) { iwrite (uint8_t(c)); return *this; } + int vformat (const char* fmt, va_list args); + int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + inline uint16_t width (void) const { return _width; } + inline void width (uint16_t w) { _width = w; } + inline void set_width (uint16_t w) { _width = w; } + inline char fill (void) const { return _fill; } + inline void fill (char c) { _fill = c; } + inline uint8_t precision (void) const { return _precision; } + inline void precision (uint8_t v) { _precision = v; } + inline void set_precision (uint8_t v) { _precision = v; } + void link (void* p, size_type n) noexcept; + inline void link (memlink& l) { link (l.data(), l.writable_size()); } + inline const string& str (void) { flush(); return _buffer; } + void str (const string& s); + ostringstream& write (const void* buffer, size_type size); + inline ostringstream& write (const cmemlink& buf) { return write (buf.begin(), buf.size()); } + inline ostringstream& seekp (off_t p, seekdir d =beg) { ostream::seekp(p,d); return *this; } + virtual ostream& flush (void) override { ostream::flush(); _buffer.resize (pos()); return *this; } + virtual size_type overflow (size_type n = 1) override; +protected: + inline void reserve (size_type n) { _buffer.reserve (n, false); } + inline size_type capacity (void) const { return _buffer.capacity(); } +private: + inline void write_strz (const char*) { assert (!"Writing nul characters into a text stream is not allowed"); } + inline char* encode_dec (char* fmt, uint32_t n) const noexcept; + void fmtstring (char* fmt, const char* typestr, bool bInteger) const; + template + void iformat (T v); +private: + string _buffer; ///< The output buffer. + fmtflags _flags; ///< See ios_base::fmtflags. + uint16_t _width; ///< Field width. + uint8_t _precision; ///< Number of digits after the decimal separator. + char _fill; ///< Character for padding variable width fields (space or 0 only) +}; + +//---------------------------------------------------------------------- + +template +inline const char* printf_typestring (const T&) { return ""; } +#define PRINTF_TYPESTRING_SPEC(type,str) \ +template <> inline const char* printf_typestring (const type&) { return str; } +PRINTF_TYPESTRING_SPEC (short, "hd") +PRINTF_TYPESTRING_SPEC (unsigned short, "hu") +PRINTF_TYPESTRING_SPEC (int, "d") +PRINTF_TYPESTRING_SPEC (unsigned int, "u") +PRINTF_TYPESTRING_SPEC (long, "ld") +PRINTF_TYPESTRING_SPEC (unsigned long, "lu") +/*PRINTF_TYPESTRING_SPEC (float, "f") +PRINTF_TYPESTRING_SPEC (double, "lf") +PRINTF_TYPESTRING_SPEC (long double, "Lf")*/ +#if HAVE_LONG_LONG +PRINTF_TYPESTRING_SPEC (long long, "lld") +PRINTF_TYPESTRING_SPEC (unsigned long long, "llu") +#endif +#undef PRINTF_TYPESTRING_SPEC + +template +void ostringstream::iformat (T v) +{ + char fmt [16]; + fmtstring (fmt, printf_typestring(v), numeric_limits::is_integer); + format (fmt, v); +} + +void ostringstream::iwrite (fmtflags_bits f) +{ + if (f & basefield) setf (f, basefield); + else if (f & floatfield) setf (f, floatfield); + else if (f & adjustfield) setf (f, adjustfield); + setf (f); +} + +//---------------------------------------------------------------------- + +template struct object_text_writer { + inline void operator()(ostringstream& os, const T& v) const { v.text_write (os); } +}; +template struct integral_text_object_writer { + inline void operator()(ostringstream& os, const T& v) const { os.iwrite (v); } +}; +template +inline ostringstream& operator<< (ostringstream& os, const T& v) { + typedef typename tm::Select ::isFundamental + || tm::TypeTraits::isPointer + || tm::Conversion::exists, + integral_text_object_writer, object_text_writer >::Result object_writer_t; + object_writer_t()(os, v); + return os; +} +// Needed because if called with a char[], numeric_limits will not work. Should be removed if I find out how to partial specialize for arrays... +inline ostringstream& operator<< (ostringstream& os, const char* v) + { os.iwrite (v); return os; } +inline ostringstream& operator<< (ostringstream& os, char* v) + { os.iwrite (v); return os; } + +//---------------------------------------------------------------------- +// Object writer operators + +template <> struct object_text_writer { + inline void operator()(ostringstream& os, const string& v) const { os.iwrite (v); } +}; +template struct integral_text_object_writer { + inline void operator() (ostringstream& os, const T* const& v) const + { os.iwrite (uintptr_t(v)); } +}; + +//---------------------------------------------------------------------- +// Manipulators + +namespace { +static constexpr const struct Sendl { + inline constexpr Sendl (void) {} + inline void text_write (ostringstream& os) const { os << '\n'; os.flush(); } + inline void write (ostream& os) const { os.iwrite ('\n'); } +} endl; +static constexpr const struct Sflush { + inline constexpr Sflush (void) {} + inline void text_write (ostringstream& os) const { os.flush(); } + inline void write (ostringstream& os) const { os.flush(); } + inline void write (ostream&) const { } +} flush; +constexpr const char ends = '\0'; ///< End of string character. +} // namespace + +struct setiosflags { + inline constexpr setiosflags (ios_base::fmtflags f) : _f(f) {} + inline void text_write (ostringstream& os) const { os.setf(_f); } +private: + const ios_base::fmtflags _f; +}; +struct resetiosflags { + inline constexpr resetiosflags (ios_base::fmtflags f) : _f(f) {} + inline void text_write (ostringstream& os) const { os.unsetf(_f); } +private: + const ios_base::fmtflags _f; +}; +class setw { + uint16_t _w; +public: + inline constexpr setw (uint16_t w) : _w(w) {} + inline void text_write (ostringstream& os) const { os.width(_w); } + inline void write (ostringstream& os) const { os.width(_w); } +}; +class setfill { + char _c; +public: + inline constexpr setfill (char c) : _c(c) {} + inline void text_write (ostringstream& os) const { os.fill(_c); } + inline void write (ostringstream& os) const { os.fill(_c); } +}; +class setprecision { + uint8_t _p; +public: + inline constexpr setprecision (uint8_t p) : _p(p) {} + inline void text_write (ostringstream& os) const { os.precision(_p); } + inline void write (ostringstream& os) const { os.precision(_p); } +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/strmsize.h b/pwn/flipper/dist/common/include/ustl/strmsize.h new file mode 100644 index 0000000..d502656 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/strmsize.h @@ -0,0 +1,92 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. +// +/// \file strmsize.h +/// \brief This file contains stream_size_of functions for basic types and *STREAMABLE macros. +/// stream_size_of functions return the size of the object's data that is written or +/// read from a stream. + +#pragma once + +namespace ustl { + +/// For partial specialization of stream_size_of for objects +template struct object_stream_size { + inline streamsize operator()(const T& v) const { return v.stream_size(); } +}; +template struct integral_object_stream_size { + inline streamsize operator()(const T& v) const { return sizeof(v); } +}; +/// Returns the size of the given object. Overloads for standard types are available. +template +inline streamsize stream_size_of (const T& v) { + typedef typename tm::Select ::is_integral, + integral_object_stream_size, object_stream_size >::Result stream_sizer_t; + return stream_sizer_t()(v); +} + +/// \brief Returns the recommended stream alignment for type \p T. Override with ALIGNOF. +/// Because this is occasionally called with a null value, do not access the argument! +template +inline size_t stream_align_of (const T&) +{ + if (numeric_limits::is_integral) + return __alignof__(T); + return 4; +} + +#define ALIGNOF(type,grain) \ +namespace ustl { \ + template <> inline size_t stream_align_of (const type&) { return grain; } } + +} // namespace ustl + +// +// Extra overloads in this macro are needed because it is the one used for +// marshalling pointers. Passing a pointer to stream_size_of creates a +// conversion ambiguity between converting to const pointer& and converting +// to bool; the compiler always chooses the bool conversion (because it +// requires 1 conversion instead of 2 for the other choice). There is little +// point in adding the overloads to other macros, since they are never used +// for pointers. +// +/// Declares that T is to be written as is into binary streams. +#define INTEGRAL_STREAMABLE(T) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T& v) { is.iread(v); return is; } \ + inline ostream& operator<< (ostream& os, const T& v) { os.iwrite(v); return os; } \ + inline ostream& operator<< (ostream& os, T& v) { os.iwrite(v); return os; } \ + template<> inline streamsize stream_size_of(const T& v) { return sizeof(v); } \ + } + +/// Declares that T contains read, write, and stream_size methods. This is no longer needed and is deprecated. +#define STD_STREAMABLE(T) + +/// Declares \p T to be writable to text streams. This is no longer needed and is deprecated. +#define TEXT_STREAMABLE(T) + +/// Declares that T is to be cast into TSUB for streaming. +#define CAST_STREAMABLE(T,TSUB) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T& v) { TSUB sv; is >> sv; v = T(sv); return is; } \ + inline ostream& operator<< (ostream& os, const T& v) { os << TSUB(v); return os; } \ + template<> inline streamsize stream_size_of(const T& v) { return stream_size_of (TSUB(v)); } \ + } + +/// Placed into a class it declares the methods required by STD_STREAMABLE. Syntactic sugar. +#define DECLARE_STD_STREAMABLE \ + public: \ + void read (istream& is); \ + void write (ostream& os) const; \ + streamsize stream_size (void) const + +/// Specifies that \p T is printed by using it as an index into \p Names string array. +#define LOOKUP_TEXT_STREAMABLE(T,Names,nNames) \ + namespace ustl { \ + inline ostringstream& operator<< (ostringstream& os, const T& v) { \ + os << Names[min(uoff_t(v),uoff_t(nNames-1))]; \ + return os; \ + } \ + } diff --git a/pwn/flipper/dist/common/include/ustl/traits.h b/pwn/flipper/dist/common/include/ustl/traits.h new file mode 100644 index 0000000..fbbf875 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/traits.h @@ -0,0 +1,266 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2007 by Mike Sharov +// +// This implementation is adapted from the Loki library, distributed under +// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu. + +#pragma once +#include "typelist.h" + +namespace ustl { +namespace tm { + +//---------------------------------------------------------------------- +// Type classes and type modifiers +//---------------------------------------------------------------------- + +typedef tl::Seq::Type + StdUnsignedInts; +typedef tl::Seq::Type StdSignedInts; +typedef tl::Seq::Type StdOtherInts; +typedef tl::Seq::Type StdFloats; + +template struct Identity { typedef U Result; }; +template struct AddPointer { typedef U* Result; }; +template struct AddPointer { typedef U* Result; }; +template struct AddReference { typedef U& Result; }; +template struct AddReference { typedef U& Result; }; +template <> struct AddReference { typedef NullType Result; }; +template struct AddParameterType { typedef const U& Result; }; +template struct AddParameterType { typedef U& Result; }; +template <> struct AddParameterType { typedef NullType Result; }; +template struct RemoveReference { typedef U Result; }; +template struct RemoveReference { typedef U Result; }; +#if HAVE_CPP11 +template struct RemoveReference { typedef U Result; }; +#endif +template struct EnableIf { typedef void Result; }; +template struct EnableIf { typedef T Result; }; + + +//---------------------------------------------------------------------- +// Function pointer testers +//---------------------------------------------------------------------- +// Macros expand to numerous parameters + +template +struct IsFunctionPointerRaw { enum { result = false}; }; +template +struct IsMemberFunctionPointerRaw { enum { result = false}; }; + +#define TM_FPR_MAXN 9 +#define TM_FPR_TYPE(n) PASTE(T,n) +#define TM_FPR_TYPENAME(n) typename TM_FPR_TYPE(n) + +// First specialize for regular functions +template +struct IsFunctionPointerRaw +{enum {result = true};}; + +#define TM_FPR_SPEC(n) \ +template \ +struct IsFunctionPointerRaw \ +{ enum { result = true }; } + +LIST (TM_FPR_MAXN, TM_FPR_SPEC, ;); + +// Then for those with an ellipsis argument +template +struct IsFunctionPointerRaw +{enum {result = true};}; + +#define TM_FPR_SPEC_ELLIPSIS(n) \ +template \ +struct IsFunctionPointerRaw \ +{ enum { result = true }; } + +LIST (TM_FPR_MAXN, TM_FPR_SPEC_ELLIPSIS, ;); + +// Then for member function pointers +template +struct IsMemberFunctionPointerRaw +{ enum { result = true }; }; + +#define TM_MFPR_SPEC(n) \ +template \ +struct IsMemberFunctionPointerRaw \ +{ enum { result = true };}; + +LIST (TM_FPR_MAXN, TM_MFPR_SPEC, ;); + +// Then for member function pointers with an ellipsis argument +template +struct IsMemberFunctionPointerRaw +{ enum { result = true }; }; + +#define TM_MFPR_SPEC_ELLIPSIS(n) \ +template \ +struct IsMemberFunctionPointerRaw \ +{ enum { result = true }; }; + +LIST (TM_FPR_MAXN, TM_MFPR_SPEC_ELLIPSIS, ;); + +// Then for const member function pointers (getting tired yet?) +template +struct IsMemberFunctionPointerRaw +{ enum { result = true }; }; + +#define TM_CMFPR_SPEC(n) \ +template \ +struct IsMemberFunctionPointerRaw \ +{ enum { result = true };}; + +LIST (TM_FPR_MAXN, TM_CMFPR_SPEC, ;); + +// Finally for const member function pointers with an ellipsis argument (whew!) +template +struct IsMemberFunctionPointerRaw +{ enum { result = true }; }; + +#define TM_CMFPR_SPEC_ELLIPSIS(n) \ +template \ +struct IsMemberFunctionPointerRaw \ +{ enum { result = true }; }; + +LIST (TM_FPR_MAXN, TM_CMFPR_SPEC_ELLIPSIS, ;); + +#undef TM_FPR_SPEC +#undef TM_FPR_SPEC_ELLIPSIS +#undef TM_MFPR_SPEC +#undef TM_MFPR_SPEC_ELLIPSIS +#undef TM_CMFPR_SPEC +#undef TM_CMFPR_SPEC_ELLIPSIS +#undef TM_FPR_TYPENAME +#undef TM_FPR_TYPE +#undef TM_FPR_MAXN + +//---------------------------------------------------------------------- +// Type traits template +//---------------------------------------------------------------------- + +/// Figures out at compile time various properties of any given type +/// Invocations (T is a type, TypeTraits::Propertie): +/// +/// - isPointer : returns true if T is a pointer type +/// - PointeeType : returns the type to which T points if T is a pointer +/// type, NullType otherwise +/// - isReference : returns true if T is a reference type +/// - isLValue : returns true if T is an lvalue +/// - isRValue : returns true if T is an rvalue +/// - ReferredType : returns the type to which T refers if T is a reference +/// type, NullType otherwise +/// - isMemberPointer : returns true if T is a pointer to member type +/// - isStdUnsignedInt: returns true if T is a standard unsigned integral type +/// - isStdSignedInt : returns true if T is a standard signed integral type +/// - isStdIntegral : returns true if T is a standard integral type +/// - isStdFloat : returns true if T is a standard floating-point type +/// - isStdArith : returns true if T is a standard arithmetic type +/// - isStdFundamental: returns true if T is a standard fundamental type +/// - isUnsignedInt : returns true if T is a unsigned integral type +/// - isSignedInt : returns true if T is a signed integral type +/// - isIntegral : returns true if T is a integral type +/// - isFloat : returns true if T is a floating-point type +/// - isArith : returns true if T is a arithmetic type +/// - isFundamental : returns true if T is a fundamental type +/// - ParameterType : returns the optimal type to be used as a parameter for +/// functions that take Ts +/// - isConst : returns true if T is a const-qualified type +/// - NonConstType : Type with removed 'const' qualifier from T, if any +/// - isVolatile : returns true if T is a volatile-qualified type +/// - NonVolatileType : Type with removed 'volatile' qualifier from T, if any +/// - UnqualifiedType : Type with removed 'const' and 'volatile' qualifiers from +/// T, if any +/// - ConstParameterType: returns the optimal type to be used as a parameter +/// for functions that take 'const T's +/// +template +class TypeTraits { +private: + #define TMTT1 template struct + #define TMTT2 template struct + TMTT1 ReferenceTraits { enum { result = false, lvalue = true, rvalue = false }; typedef U ReferredType; }; + TMTT1 ReferenceTraits { enum { result = true, lvalue = true, rvalue = false }; typedef U ReferredType; }; + TMTT1 PointerTraits { enum { result = false }; typedef NullType PointeeType; }; + TMTT1 PointerTraits { enum { result = true }; typedef U PointeeType; }; + TMTT1 PointerTraits { enum { result = true }; typedef U PointeeType; }; + TMTT1 PToMTraits { enum { result = false }; }; + TMTT2 PToMTraits { enum { result = true }; }; + TMTT2 PToMTraits { enum { result = true }; }; + TMTT1 FunctionPointerTraits { enum { result = IsFunctionPointerRaw::result }; }; + TMTT1 PToMFunctionTraits { enum { result = IsMemberFunctionPointerRaw::result }; }; + TMTT1 UnConst { typedef U Result; enum { isConst = false }; }; + TMTT1 UnConst { typedef U Result; enum { isConst = true }; }; + TMTT1 UnConst { typedef U& Result; enum { isConst = true }; }; + TMTT1 UnVolatile { typedef U Result; enum { isVolatile = false }; }; + TMTT1 UnVolatile{ typedef U Result; enum { isVolatile = true }; }; + TMTT1 UnVolatile {typedef U& Result;enum { isVolatile = true }; }; +#if HAVE_CPP11 + TMTT1 ReferenceTraits { enum { result = true, lvalue = false, rvalue = true }; typedef U ReferredType; }; + TMTT1 PointerTraits { enum { result = true }; typedef U PointeeType; }; + TMTT2 PToMTraits { enum { result = true }; }; + TMTT1 UnConst { typedef U&& Result; enum { isConst = true }; }; + TMTT1 UnVolatile {typedef U&& Result;enum { isVolatile = true }; }; +#endif + #undef TMTT2 + #undef TMTT1 +public: + typedef typename UnConst::Result + NonConstType; + typedef typename UnVolatile::Result + NonVolatileType; + typedef typename UnVolatile::Result>::Result + UnqualifiedType; + typedef typename PointerTraits::PointeeType + PointeeType; + typedef typename ReferenceTraits::ReferredType + ReferredType; + + enum { isConst = UnConst::isConst }; + enum { isVolatile = UnVolatile::isVolatile }; + enum { isReference = ReferenceTraits::result }; + enum { isLValue = ReferenceTraits::lvalue }; + enum { isRValue = ReferenceTraits::rvalue }; + enum { isFunction = FunctionPointerTraits::Result >::result }; + enum { isFunctionPointer = FunctionPointerTraits< + typename ReferenceTraits::ReferredType >::result }; + enum { isMemberFunctionPointer= PToMFunctionTraits< + typename ReferenceTraits::ReferredType >::result }; + enum { isMemberPointer = PToMTraits< + typename ReferenceTraits::ReferredType >::result || + isMemberFunctionPointer }; + enum { isPointer = PointerTraits< + typename ReferenceTraits::ReferredType >::result || + isFunctionPointer }; + enum { isStdUnsignedInt = tl::IndexOf::value >= 0 || + tl::IndexOf::ReferredType>::value >= 0}; + enum { isStdSignedInt = tl::IndexOf::value >= 0 || + tl::IndexOf::ReferredType>::value >= 0}; + enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt || + tl::IndexOf::value >= 0 || + tl::IndexOf::ReferredType>::value >= 0}; + enum { isStdFloat = tl::IndexOf::value >= 0 || + tl::IndexOf::ReferredType>::value >= 0}; + enum { isStdArith = isStdIntegral || isStdFloat }; + enum { isStdFundamental = isStdArith || isStdFloat || Conversion::sameType }; + + enum { isUnsignedInt = isStdUnsignedInt }; + enum { isUnsigned = isUnsignedInt || isPointer }; + enum { isSignedInt = isStdSignedInt }; + enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt }; + enum { isFloat = isStdFloat }; + enum { isSigned = isSignedInt || isFloat }; + enum { isArith = isIntegral || isFloat }; + enum { isFundamental = isStdFundamental || isArith }; + + typedef typename Select::Result>::Result + ParameterType; +}; + +} // namespace tm +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/typelist.h b/pwn/flipper/dist/common/include/ustl/typelist.h new file mode 100644 index 0000000..b881f52 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/typelist.h @@ -0,0 +1,219 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2007 by Mike Sharov +// +// This implementation is adapted from the Loki library, distributed under +// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu. + +#pragma once +#include "metamac.h" +#include "typet.h" + +namespace ustl { +namespace tm { + +/// The building block of typelists. Use it throught the Seq templates. +template +struct Typelist { + typedef T Head; + typedef U Tail; +}; + +/// Namespace containing typelist-related functionality. +namespace tl { + +//---------------------------------------------------------------------- +// Seq template definitions. The macros expand to a spec per arg count +// +#define TL_MAX_SEQ_TYPES 9 +#define TL_MAX_SEQ_SPECS 8 +#define TL_SEQ_TYPE(n) T##n +#define TL_SEQ_TYPENAME(n) typename TL_SEQ_TYPE(n) +#define TL_SEQ_NULLTYPE_DEFAULT(n) TL_SEQ_TYPENAME(n)=NullType +#define TL_SEQ_TL_END(n) > +#define TL_SEQ_ONE_TYPELIST(n) Typelist +struct Seq { + typedef COMMA_LIST(TL_MAX_SEQ_TYPES,TL_SEQ_ONE_TYPELIST), + NullType REPEAT(TL_MAX_SEQ_TYPES,TL_SEQ_TL_END) Type; +}; + +#define TL_SEQ_SPEC(n) \ +template \ +struct Seq { \ + typedef COMMA_LIST(n,TL_SEQ_ONE_TYPELIST), \ + NullType REPEAT(n,TL_SEQ_TL_END) Type; \ +} +LIST(TL_MAX_SEQ_SPECS,TL_SEQ_SPEC, ;); + +#undef TL_SEQ_SPEC +#undef TL_SEQ_TL_END +#undef TL_SEQ_ONE_TYPELIST +#undef TL_SEQ_NULLTYPE_DEFAULT +#undef TL_SEQ_TYPE +#undef TL_MAX_SEQ_SPECS + +//---------------------------------------------------------------------- +// Various utility functions follow. + +/// Length::value is the number of types in the typelist. +template struct Length { }; +template <> struct Length { enum { value = 0 }; }; +template +struct Length > { enum { value = 1 + Length::value }; }; + +/// TypeAt::Result is the ith type in List +template struct TypeAt { }; +template +struct TypeAt, 0> { + typedef Head Result; +}; +template +struct TypeAt, index> { + typedef typename TypeAt::Result Result; +}; + +/// TypeAtNonStrict::Result is List[i] or DefaultType if out of range. +template +struct TypeAtNonStrict { + typedef DefaultType Result; +}; +template +struct TypeAtNonStrict, 0, DefaultType> { + typedef Head Result; +}; +template +struct TypeAtNonStrict, index, DefaultType> { + typedef typename TypeAtNonStrict::Result Result; +}; + +/// IndexOf::value is the position of T in List, or -1 if not found. +template struct IndexOf; +template +struct IndexOf { enum { value = -1 }; }; +template +struct IndexOf, T> { enum { value = 0 }; }; +template +struct IndexOf, T> { +private: + enum { iintail = IndexOf::value }; +public: + enum { value = (iintail == -1 ? -1 : 1+iintail) }; +}; + +/// Appends a type or a typelist to another in Append::Result +template struct Append; +template <> struct Append { typedef NullType Result; }; +template struct Append { + typedef Typelist Result; +}; +template +struct Append > { + typedef Typelist Result; +}; +template +struct Append, T> { + typedef Typelist::Result> Result; +}; + +// Erase::Result contains List without the first T. +template struct Erase; +template +struct Erase { typedef NullType Result; }; +template +struct Erase, T> { typedef Tail Result; }; +template +struct Erase, T> { + typedef Typelist::Result> Result; +}; + +// EraseAll::Result contains List without any T. +template struct EraseAll; +template +struct EraseAll { typedef NullType Result; }; +template +struct EraseAll, T> { + typedef typename EraseAll::Result Result; +}; +template +struct EraseAll, T> { + typedef Typelist::Result> Result; +}; + +/// Removes all duplicate types in a typelist +template struct NoDuplicates; +template <> struct NoDuplicates { typedef NullType Result; }; +template +struct NoDuplicates< Typelist > { +private: + typedef typename NoDuplicates::Result L1; + typedef typename Erase::Result L2; +public: + typedef Typelist Result; +}; + +// Replaces the first occurence of a type in a typelist, with another type +template struct Replace; +template +struct Replace { typedef NullType Result; }; +template +struct Replace, T, U> { + typedef Typelist Result; +}; +template +struct Replace, T, U> { + typedef Typelist::Result> Result; +}; + +// Replaces all occurences of a type in a typelist, with another type +template struct ReplaceAll; +template +struct ReplaceAll { typedef NullType Result; }; +template +struct ReplaceAll, T, U> { + typedef Typelist::Result> Result; +}; +template +struct ReplaceAll, T, U> { + typedef Typelist::Result> Result; +}; + +// Reverses a typelist +template struct Reverse; +template <> struct Reverse { typedef NullType Result; }; +template +struct Reverse< Typelist > { + typedef typename Append::Result, Head>::Result Result; +}; + +// Finds the type in a typelist that is the most derived from a given type +template struct MostDerived; +template struct MostDerived { typedef T Result; }; +template +struct MostDerived, T> { +private: + typedef typename MostDerived::Result Candidate; +public: + typedef typename Select::value, Head, Candidate>::Result Result; +}; + +// Arranges the types in a typelist so that the most derived types appear first +template struct DerivedToFront; +template <> struct DerivedToFront { typedef NullType Result; }; +template +struct DerivedToFront< Typelist > { +private: + typedef typename MostDerived::Result TheMostDerived; + typedef typename Replace::Result Temp; + typedef typename DerivedToFront::Result L; +public: + typedef Typelist Result; +}; + +//---------------------------------------------------------------------- + +} // namespace tl +} // namespace tm +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/typet.h b/pwn/flipper/dist/common/include/ustl/typet.h new file mode 100644 index 0000000..bb25e00 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/typet.h @@ -0,0 +1,96 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2007 by Mike Sharov +// +// This implementation is adapted from the Loki library, distributed under +// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu. + +#pragma once + +namespace ustl { +/// Template metaprogramming tools +namespace tm { + +/// An empty type useful as a placeholder. +class NullType { }; + +/// Converts an integer to a type. +template struct Int2Type { enum { value = v }; }; + +/// Converts an type to a unique empty type. +template struct Type2Type { typedef T OriginalType; }; + +/// Selects type Result = flag ? T : U +template +struct Select { typedef T Result; }; +template +struct Select { typedef U Result; }; + +/// IsSameType::value is true when T=U +template +struct IsSameType { enum { value = false }; }; +template +struct IsSameType { enum { value = true }; }; + +/// \brief Checks for conversion possibilities between T and U +/// Conversion::exists is true if T is convertible to U +/// Conversion::sameType is true if U is T +template +struct Conversion { +private: + typedef char UT; + typedef short TT; + static UT Test (U); + static TT Test (...); + static T MakeT (void); +public: + enum { + exists = sizeof(UT) == sizeof(Test(MakeT())), + sameType = false + }; +}; +template +struct Conversion { enum { exists = true, sameType = true }; }; +template +struct Conversion { enum { exists = false, sameType = false }; }; +template +struct Conversion { enum { exists = false, sameType = false }; }; +template <> +struct Conversion { enum { exists = true, sameType = true }; }; + +/// SuperSubclass::value is true when U is derived from T, or when U is T +template +struct SuperSubclass { + enum { value = (::ustl::tm::Conversion::exists && + !::ustl::tm::Conversion::sameType) }; + enum { dontUseWithIncompleteTypes = sizeof(T)==sizeof(U) }; // Dummy enum to make sure that both classes are fully defined. +}; +template <> +struct SuperSubclass { enum { value = false }; }; +template +struct SuperSubclass { + enum { value = false }; + enum { dontUseWithIncompleteTypes = 0==sizeof(U) }; +}; +template +struct SuperSubclass { + enum { value = false }; + enum { dontUseWithIncompleteTypes = 0==sizeof(T) }; +}; + +/// SuperSubclassStrict::value is true when U is derived from T +template +struct SuperSubclassStrict { + enum { value = SuperSubclass::value && + !::ustl::tm::Conversion::sameType }; +}; + +#if !HAVE_CPP11 +// static assert support +template struct CompileTimeError; +template <> struct CompileTimeError {}; +#define static_assert(cond,msg) { ::ustl::tm::CompileTimeError ERROR_##msg; (void) ERROR_##msg; } +#endif + +} // namespace tm +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ualgo.h b/pwn/flipper/dist/common/include/ustl/ualgo.h new file mode 100644 index 0000000..5d97422 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ualgo.h @@ -0,0 +1,733 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "upair.h" +#include "ufunction.h" +#include "umemory.h" +#include "util/qsort.h" + +namespace ustl { + +/// Swaps corresponding elements of [first, last) and [result,) +/// \ingroup SwapAlgorithms +/// +template +inline ForwardIterator2 swap_ranges (ForwardIterator1 first, ForwardIterator2 last, ForwardIterator2 result) +{ + for (; first != last; ++first, ++result) + iter_swap (first, result); + return result; +} + +/// Returns the first iterator i in the range [first, last) such that +/// *i == value. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template +inline InputIterator find (InputIterator first, InputIterator last, const EqualityComparable& value) +{ + while (first != last && !(*first == value)) + ++ first; + return first; +} + +/// Returns the first iterator such that *i == *(i + 1) +/// \ingroup SearchingAlgorithms +/// +template +ForwardIterator adjacent_find (ForwardIterator first, ForwardIterator last) +{ + if (first != last) + for (ForwardIterator prev = first; ++first != last; ++ prev) + if (*prev == *first) + return prev; + return last; +} + +/// Returns the pointer to the first pair of unequal elements. +/// \ingroup SearchingAlgorithms +/// +template +pair +mismatch (InputIterator first1, InputIterator last1, InputIterator first2) +{ + while (first1 != last1 && *first1 == *first2) + ++ first1, ++ first2; + return make_pair (first1, first2); +} + +/// \brief Returns true if two ranges are equal. +/// This is an extension, present in uSTL and SGI STL. +/// \ingroup SearchingAlgorithms +/// +template +inline bool equal (InputIterator first1, InputIterator last1, InputIterator first2) +{ + return mismatch (first1, last1, first2).first == last1; +} + +/// Count finds the number of elements in [first, last) that are equal +/// to value. More precisely, the first version of count returns the +/// number of iterators i in [first, last) such that *i == value. +/// \ingroup SearchingAlgorithms +/// +template +inline size_t count (InputIterator first, InputIterator last, const EqualityComparable& value) +{ + size_t total = 0; + for (; first != last; ++first) + if (*first == value) + ++ total; + return total; +} + +/// +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryFunction op) +{ + for (; first != last; ++result, ++first) + *result = op (*first); + return result; +} + +/// +/// The second version of transform is very similar, except that it uses a +/// Binary Function instead of a Unary Function: it performs the operation +/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns +/// the result to *o, where i2 is the corresponding iterator in the second +/// input range and where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last1 - first1, it performs the assignment +/// *(result + n) = op(*(first1 + n), *(first2 + n). +/// The return value is result + (last1 - first1). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator transform (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryFunction op) +{ + for (; first1 != last1; ++result, ++first1, ++first2) + *result = op (*first1, *first2); + return result; +} + +/// Replace replaces every element in the range [first, last) equal to +/// old_value with new_value. That is: for every iterator i, +/// if *i == old_value then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template +inline void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) +{ + for (; first != last; ++first) + if (*first == old_value) + *first = new_value; +} + +/// Replace_copy copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element equal to old_value +/// is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy performs the +/// assignment *(result+n) = new_value if *(first+n) == old_value, and +/// *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator replace_copy (InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) +{ + for (; first != last; ++result, ++first) + *result = (*first == old_value) ? new_value : *first; +} + +/// Generate assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, last). +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline void generate (ForwardIterator first, ForwardIterator last, Generator gen) +{ + for (; first != last; ++first) + *first = gen(); +} + +/// Generate_n assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, first+n). +/// The return value is first + n. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator generate_n (OutputIterator first, size_t n, Generator gen) +{ + for (uoff_t i = 0; i != n; ++i, ++first) + *first = gen(); + return first; +} + +/// \brief Reverse reverses a range. +/// That is: for every i such that 0 <= i <= (last - first) / 2), +/// it exchanges *(first + i) and *(last - (i + 1)). +/// \ingroup MutatingAlgorithms +/// +template +inline void reverse (BidirectionalIterator first, BidirectionalIterator last) +{ + for (; distance (first, --last) > 0; ++first) + iter_swap (first, last); +} + +/// \brief Reverses [first,last) and writes it to \p output. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator reverse_copy (BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) +{ + for (; first != last; ++result) + *result = *--last; + return result; +} + +/// \brief Exchanges ranges [first, middle) and [middle, last) +/// \ingroup MutatingAlgorithms +/// +template +ForwardIterator rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last) +{ + if (first == middle || middle == last) + return first; + reverse (first, middle); + reverse (middle, last); + for (;first != middle && middle != last; ++first) + iter_swap (first, --last); + reverse (first, (first == middle ? last : middle)); + return first; +} + +/// Specialization for pointers, which can be treated identically. +template +inline T* rotate (T* first, T* middle, T* last) +{ + rotate_fast (first, middle, last); + return first; +} + + +/// \brief Exchanges ranges [first, middle) and [middle, last) into \p result. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator rotate_copy (ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result) +{ + return copy (first, middle, copy (middle, last, result)); +} + +/// \brief Combines two sorted ranges. +/// \ingroup SortingAlgorithms +/// +template +OutputIterator merge (InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + for (; first1 != last1 && first2 != last2; ++result) { + if (*first1 < *first2) + *result = *first1++; + else + *result = *first2++; + } + if (first1 < last1) + return copy (first1, last1, result); + else + return copy (first2, last2, result); +} + +/// Combines two sorted ranges from the same container. +/// \ingroup SortingAlgorithms +/// +template +void inplace_merge (InputIterator first, InputIterator middle, InputIterator last) +{ + for (; middle != last; ++first) { + while (*first < *middle) + ++ first; + reverse (first, middle); + reverse (first, ++middle); + } +} + +/// Remove_copy copies elements that are not equal to value from the range +/// [first, last) to a range beginning at result. The return value is the +/// end of the resulting range. This operation is stable, meaning that the +/// relative order of the elements that are copied is the same as in the +/// range [first, last). +/// \ingroup MutatingAlgorithms +/// +template +OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& value) +{ + for (; first != last; ++first) { + if (!(*first == value)) { + *result = *first; + ++ result; + } + } + return result; +} + +/// Remove_copy copies elements pointed to by iterators in [rfirst, rlast) +/// from the range [first, last) to a range beginning at result. The return +/// value is the end of the resulting range. This operation is stable, meaning +/// that the relative order of the elements that are copied is the same as in the +/// range [first, last). Range [rfirst, rlast) is assumed to be sorted. +/// This algorithm is a uSTL extension. +/// \ingroup MutatingAlgorithms +/// +template +OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, RInputIterator rfirst, RInputIterator rlast) +{ + for (; first != last; ++first) { + while (rfirst != rlast && *rfirst < first) + ++ rfirst; + if (rfirst == rlast || first != *rfirst) { + *result = *first; + ++ result; + } + } + return result; +} + +/// Remove removes from the range [first, last) all elements that are equal to +/// value. That is, remove returns an iterator new_last such that the range +/// [first, new_last) contains no elements equal to value. [1] The iterators +/// in the range [new_last, last) are all still dereferenceable, but the +/// elements that they point to are unspecified. Remove is stable, meaning +/// that the relative order of elements that are not equal to value is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& value) +{ + return remove_copy (first, last, first, value); +} + +/// Unique_copy copies elements from the range [first, last) to a range +/// beginning with result, except that in a consecutive group of duplicate +/// elements only the first one is copied. The return value is the end of +/// the range to which the elements are copied. This behavior is similar +/// to the Unix filter uniq. +/// \ingroup MutatingAlgorithms +/// +template +OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first != last) { + *result = *first; + while (++first != last) + if (!(*first == *result)) + *++result = *first; + ++ result; + } + return result; +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline ForwardIterator unique (ForwardIterator first, ForwardIterator last) +{ + return unique_copy (first, last, first); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), *j < value +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template +ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, size_t(distance (first,last)) / 2); + if (*mid < value) + first = mid + 1; + else + last = mid; + } + return first; +} + +/// Performs a binary search inside the sorted range. +/// \ingroup SearchingAlgorithms +/// +template +inline bool binary_search (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator found = lower_bound (first, last, value); + return found != last && !(value < *found); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), value < *j is false. +/// \ingroup SearchingAlgorithms +/// +template +ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, size_t(distance (first,last)) / 2); + if (value < *mid) + last = mid; + else + first = mid + 1; + } + return last; +} + +/// Returns pair +/// \ingroup SearchingAlgorithms +/// +template +inline pair equal_range (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + pair rv; + rv.second = rv.first = lower_bound (first, last, value); + while (rv.second != last && !(value < *(rv.second))) + ++ rv.second; + return rv; +} + +/// Randomly permute the elements of the container. +/// \ingroup GeneratorAlgorithms +/// +/*template +void random_shuffle (RandomAccessIterator first, RandomAccessIterator last) +{ + for (; first != last; ++ first) + iter_swap (first, first + (rand() % distance (first, last))); + }*/ + +/// \brief Generic compare function adaptor to pass to qsort +/// \ingroup FunctorObjects +template +int qsort_adapter (const void* p1, const void* p2) +{ + ConstPointer i1 = reinterpret_cast(p1); + ConstPointer i2 = reinterpret_cast(p2); + Compare comp; + return comp (*i1, *i2) ? -1 : (comp (*i2, *i1) ? 1 : 0); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +void sort (RandomAccessIterator first, RandomAccessIterator last, Compare) +{ + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::const_pointer const_pointer; + qsort (first, distance (first, last), sizeof(value_type), + &qsort_adapter); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void sort (RandomAccessIterator first, RandomAccessIterator last) +{ + typedef typename iterator_traits::value_type value_type; + sort (first, last, less()); +} + +/// Sorts the container preserving order of equal elements. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +void stable_sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + for (RandomAccessIterator j, i = first; ++i < last;) { // Insertion sort + for (j = i; j-- > first && comp(*i, *j);) ; + if (++j != i) rotate (j, i, i + 1); + } +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void stable_sort (RandomAccessIterator first, RandomAccessIterator last) +{ + typedef typename iterator_traits::value_type value_type; + stable_sort (first, last, less()); +} + +/// \brief Searches for the first subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +template +inline ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) +{ + typedef typename iterator_traits::value_type value_type; + return search (first1, last1, first2, last2, equal_to()); +} + +/// \brief Searches for the last subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +template +inline ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) +{ + typedef typename iterator_traits::value_type value_type; + return find_end (first1, last1, first2, last2, equal_to()); +} + +/// \brief Searches for the first occurence of \p count \p values in [first, last) +/// \ingroup SearchingAlgorithms +template +inline Iterator search_n (Iterator first, Iterator last, size_t count, const T& value) +{ + typedef typename iterator_traits::value_type value_type; + return search_n (first, last, count, value, equal_to()); +} + +/// \brief Searches [first1,last1) for the first occurrence of an element from [first2,last2) +/// \ingroup SearchingAlgorithms +template +inline InputIterator find_first_of (InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2) +{ + typedef typename iterator_traits::value_type value_type; + return find_first_of (first1, last1, first2, last2, equal_to()); +} + +/// \brief Returns true if [first2,last2) is a subset of [first1,last1) +/// \ingroup ConditionAlgorithms +/// \ingroup SetAlgorithms +template +inline bool includes (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) +{ + typedef typename iterator_traits::value_type value_type; + return includes (first1, last1, first2, last2, less()); +} + +/// \brief Merges [first1,last1) with [first2,last2) +/// +/// Result will contain every element that is in either set. If duplicate +/// elements are present, max(n,m) is placed in the result. +/// +/// \ingroup SetAlgorithms +template +inline OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits::value_type value_type; + return set_union (first1, last1, first2, last2, result, less()); +} + +/// \brief Creates a set containing elements shared by the given ranges. +/// \ingroup SetAlgorithms +template +inline OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits::value_type value_type; + return set_intersection (first1, last1, first2, last2, result, less()); +} + +/// \brief Removes from [first1,last1) elements present in [first2,last2) +/// \ingroup SetAlgorithms +template +inline OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits::value_type value_type; + return set_difference (first1, last1, first2, last2, result, less()); +} + +/// \brief Performs union of sets A-B and B-A. +/// \ingroup SetAlgorithms +template +inline OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits::value_type value_type; + return set_symmetric_difference (first1, last1, first2, last2, result, less()); +} + +/// \brief Returns true if the given range is sorted. +/// \ingroup ConditionAlgorithms +template +inline bool is_sorted (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits::value_type value_type; + return is_sorted (first, last, less()); +} + +/// \brief Compares two given containers like strcmp compares strings. +/// \ingroup ConditionAlgorithms +template +inline bool lexicographical_compare (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) +{ + typedef typename iterator_traits::value_type value_type; + return lexicographical_compare (first1, last1, first2, last2, less()); +} + +/// \brief Creates the next lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +template +inline bool next_permutation (BidirectionalIterator first, BidirectionalIterator last) +{ + typedef typename iterator_traits::value_type value_type; + return next_permutation (first, last, less()); +} + +/// \brief Creates the previous lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +template +inline bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last) +{ + typedef typename iterator_traits::value_type value_type; + return prev_permutation (first, last, less()); +} + +/// Returns \p v clamped to the given range +template +inline T clamp (const T& v, const T& l, const T& h, Compare comp) + { return comp(v, l) ? l : comp(h, v) ? h : v; } +template +inline T clamp (const T& v, const T& l, const T& h) + { return v < l ? l : (h < v ? h : v); } + +/// Returns iterator to the max element in [first,last) +/// \ingroup SearchingAlgorithms +template +inline ForwardIterator max_element (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits::value_type value_type; + return max_element (first, last, less()); +} + +/// Returns iterator to the min element in [first,last) +/// \ingroup SearchingAlgorithms +template +inline ForwardIterator min_element (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits::value_type value_type; + return min_element (first, last, less()); +} + +#if HAVE_CPP14 + +/// Returns min,max pair of the argument +template +inline constexpr auto minmax (const T& a, const T& b) + { return a < b ? make_pair(a,b) : make_pair(b,a); } +template +inline constexpr auto minmax (T& a, T& b) + { return a < b ? make_pair(a,b) : make_pair(b,a); } +template +inline constexpr auto minmax (const T& a, const T& b, Compare comp) + { return comp(a,b) ? make_pair(a,b) : make_pair(b,a); } +template constexpr void minmax (T&& a, T&& b) = delete; +template constexpr void minmax (const T& a, const T& b, Compare comp) = delete; + +template +auto minmax (std::initializer_list l) +{ + auto r = make_pair (*l.begin(),*l.begin()); + for (auto& i : l) { + r.first = min (r.first, i); + r.second = max (r.second, i); + } + return r; +} +template +auto minmax (std::initializer_list l, Compare comp) +{ + auto r = make_pair (*l.begin(),*l.begin()); + for (auto& i : l) { + if (comp(i, r.first)) + r.first = i; + if (comp(r.second, i)) + r.second = i; + } + return r; +} +#endif + +template +pair minmax_element (ForwardIterator first, ForwardIterator last) +{ + pair r = make_pair (first, first); + for (; first != last; ++first) { + if (*first < *r.first) + r.first = first; + if (*r.second < *first) + r.second = first; + } + return r; +} +template +pair minmax_element (ForwardIterator first, ForwardIterator last, Compare comp) +{ + pair r = make_pair (first, first); + for (; first != last; ++first) { + if (comp (*first, *r.first)) + r.first = first; + if (comp (*r.second, *first)) + r.second = first; + } + return r; +} + +/// \brief Makes [first,middle) a part of the sorted array. +/// Contents of [middle,last) is undefined. This implementation just calls stable_sort. +/// \ingroup SortingAlgorithms +template +inline void partial_sort (RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) +{ + typedef typename iterator_traits::value_type value_type; + partial_sort (first, middle, last, less()); +} + +/// \brief Puts \p nth element into its sorted position. +/// In this implementation, the entire array is sorted. I can't think of any +/// use for it where the time gained would be useful. +/// \ingroup SortingAlgorithms +/// \ingroup SearchingAlgorithms +/// +template +inline void nth_element (RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) +{ + partial_sort (first, nth, last); +} + +/// \brief Like partial_sort, but outputs to [result_first,result_last) +/// \ingroup SortingAlgorithms +template +inline RandomAccessIterator partial_sort_copy (InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last) +{ + typedef typename iterator_traits::value_type value_type; + return partial_sort_copy (first, last, result_first, result_last, less()); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ualgobase.h b/pwn/flipper/dist/common/include/ustl/ualgobase.h new file mode 100644 index 0000000..fa54dc5 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ualgobase.h @@ -0,0 +1,353 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uutility.h" +#include + +namespace ustl { + +#if HAVE_CPP11 + +template +inline constexpr typename tm::RemoveReference::Result&& move (T&& v) noexcept + { return static_cast::Result&&>(v); } + +template +inline constexpr T&& forward (typename tm::RemoveReference::Result& v) noexcept + { return static_cast(v); } + +template +inline constexpr T&& forward (typename tm::RemoveReference::Result&& v) noexcept + { return static_cast(v); } + +#if HAVE_CPP14 +template +T exchange (T& a, U&& b) +{ + T t = move(a); + a = forward(b); + return t; +} +#endif + +#else + +template +inline constexpr typename tm::RemoveReference::Result& move (T& v) noexcept + { return v; } + +template +inline constexpr T& forward (typename tm::RemoveReference::Result& v) noexcept + { return v; } + +#endif + +/// Assigns the contents of a to b and the contents of b to a. +/// This is used as a primitive operation by many other algorithms. +/// \ingroup SwapAlgorithms +/// +template +inline void swap (T& a, T& b) +{ + typename tm::RemoveReference::Result t = move(a); + a = move(b); + b = move(t); +} + +/// Equivalent to swap (*a, *b) +/// \ingroup SwapAlgorithms +/// +template +inline void iter_swap (Iterator a, Iterator b) +{ + swap (*a, *b); +} + +/// Copy copies elements from the range [first, last) to the range +/// [result, result + (last - first)). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally, +/// for every integer n from 0 to last - first, copy performs the assignment +/// *(result + n) = *(first + n). Assignments are performed in forward order, +/// i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) +{ + for (; first != last; ++result, ++first) + *result = *first; + return result; +} + +/// Copy_n copies elements from the range [first, first + n) to the range +/// [result, result + n). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. Generally, +/// for every integer i from 0 up to (but not including) n, copy_n performs +/// the assignment *(result + i) = *(first + i). Assignments are performed +/// in forward order, i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator copy_n (InputIterator first, size_t count, OutputIterator result) +{ + for (; count; --count, ++result, ++first) + *result = *first; + return result; +} + +/// \brief Copy copies elements from the range (last, first] to result. +/// \ingroup MutatingAlgorithms +/// Copies elements starting at last, decrementing both last and result. +/// +template +inline OutputIterator copy_backward (InputIterator first, InputIterator last, OutputIterator result) +{ + while (first != last) + *--result = *--last; + return result; +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template +inline UnaryFunction for_each (InputIterator first, InputIterator last, UnaryFunction f) +{ + for (; first != last; ++first) + f (*first); + return f; +} + +/// Fill assigns the value value to every element in the range [first, last). +/// That is, for every iterator i in [first, last), +/// it performs the assignment *i = value. +/// \ingroup GeneratorAlgorithms +/// +template +inline void fill (ForwardIterator first, ForwardIterator last, const T& value) +{ + for (; first != last; ++first) + *first = value; +} + +/// Fill_n assigns the value value to every element in the range +/// [first, first+count). That is, for every iterator i in [first, first+count), +/// it performs the assignment *i = value. The return value is first + count. +/// \ingroup GeneratorAlgorithms +/// +template +inline OutputIterator fill_n (OutputIterator first, size_t count, const T& value) +{ + for (; count; --count, ++first) + *first = value; + return first; +} + +#if __MMX__ +extern "C" void copy_n_fast (const void* src, size_t count, void* dest) noexcept; +#else +inline void copy_n_fast (const void* src, size_t count, void* dest) noexcept + { memmove (dest, src, count); } +#endif +#if __x86__ +extern "C" void copy_backward_fast (const void* first, const void* last, void* result) noexcept; +#else +inline void copy_backward_fast (const void* first, const void* last, void* result) noexcept +{ + const size_t nBytes (distance (first, last)); + memmove (advance (result, -nBytes), first, nBytes); +} +#endif +extern "C" void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) noexcept; +extern "C" void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) noexcept; +extern "C" void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) noexcept; +extern "C" void rotate_fast (void* first, void* middle, void* last) noexcept; + +#if __GNUC__ >= 4 +/// \brief Computes the number of 1 bits in a number. +/// \ingroup ConditionAlgorithms +inline size_t popcount (uint32_t v) { return __builtin_popcount (v); } +#if HAVE_INT64_T +inline size_t popcount (uint64_t v) { return __builtin_popcountll (v); } +#endif +#else +size_t popcount (uint32_t v) noexcept; +#if HAVE_INT64_T +size_t popcount (uint64_t v) noexcept; +#endif // HAVE_INT64_T +#endif // __GNUC__ + +//---------------------------------------------------------------------- +// Optimized versions for standard types +//---------------------------------------------------------------------- + +#if WANT_UNROLLED_COPY + +template +inline T* unrolled_copy (const T* first, size_t count, T* result) +{ + copy_n_fast (first, count * sizeof(T), result); + return advance (result, count); +} + +template <> +inline uint8_t* copy_backward (const uint8_t* first, const uint8_t* last, uint8_t* result) +{ + copy_backward_fast (first, last, result); + return result; +} + +template +inline T* unrolled_fill (T* result, size_t count, T value) +{ + for (; count; --count, ++result) + *result = value; + return result; +} +template <> inline uint8_t* unrolled_fill (uint8_t* result, size_t count, uint8_t value) + { fill_n8_fast (result, count, value); return advance (result, count); } +template <> inline uint16_t* unrolled_fill (uint16_t* result, size_t count, uint16_t value) + { fill_n16_fast (result, count, value); return advance (result, count); } +template <> inline uint32_t* unrolled_fill (uint32_t* result, size_t count, uint32_t value) + { fill_n32_fast (result, count, value); return advance (result, count); } +/*template <> inline float* unrolled_fill (float* result, size_t count, float value) + { fill_n32_fast (reinterpret_cast(result), count, *noalias_cast(&value)); return advance (result, count); }*/ + +#if __MMX__ +#define UNROLLED_COPY_SPECIALIZATION(type) \ +template <> inline type* copy (const type* first, const type* last, type* result) \ +{ return unrolled_copy (first, distance (first, last), result); } \ +template <> inline type* copy_n (const type* first, size_t count, type* result) \ +{ return unrolled_copy (first, count, result); } +#define UNROLLED_FILL_SPECIALIZATION(type) \ +template <> inline void fill (type* first, type* last, const type& value) \ +{ unrolled_fill (first, distance (first, last), value); } \ +template <> inline type* fill_n (type* first, size_t count, const type& value) \ +{ return unrolled_fill (first, count, value); } +UNROLLED_COPY_SPECIALIZATION(uint8_t) +UNROLLED_FILL_SPECIALIZATION(uint8_t) +UNROLLED_COPY_SPECIALIZATION(uint16_t) +UNROLLED_FILL_SPECIALIZATION(uint16_t) +UNROLLED_COPY_SPECIALIZATION(uint32_t) +UNROLLED_FILL_SPECIALIZATION(uint32_t) +UNROLLED_COPY_SPECIALIZATION(float) +UNROLLED_FILL_SPECIALIZATION(float) +#undef UNROLLED_FILL_SPECIALIZATION +#undef UNROLLED_COPY_SPECIALIZATION +#endif // WANT_UNROLLED_COPY +#endif // __MMX__ + +// Specializations for void* and char*, aliasing the above optimized versions. +// +// All these need duplication with const and non-const arguments, since +// otherwise the compiler will default to the unoptimized version for +// pointers not const in the caller's context, such as local variables. +// These are all inline, but they sure slow down compilation... :( +// +#define COPY_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy (ctype* first, ctype* last, type* result) \ +{ return reinterpret_cast (copy (reinterpret_cast(first), reinterpret_cast(last), reinterpret_cast(result))); } +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_ALIAS_FUNC(const char, char, uint8_t) +COPY_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_ALIAS_FUNC(const int8_t, int8_t, uint8_t) +COPY_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_ALIAS_FUNC(const int16_t, int16_t, uint16_t) +COPY_ALIAS_FUNC(int16_t, int16_t, uint16_t) +COPY_ALIAS_FUNC(uint16_t, uint16_t, uint16_t) +#if __MMX__ || (SIZE_OF_LONG > 4) +COPY_ALIAS_FUNC(const int32_t, int32_t, uint32_t) +COPY_ALIAS_FUNC(int32_t, int32_t, uint32_t) +COPY_ALIAS_FUNC(uint32_t, uint32_t, uint32_t) +#endif +#endif +COPY_ALIAS_FUNC(const void, void, uint8_t) +COPY_ALIAS_FUNC(void, void, uint8_t) +#undef COPY_ALIAS_FUNC +#define COPY_BACKWARD_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy_backward (ctype* first, ctype* last, type* result) \ +{ return reinterpret_cast (copy_backward (reinterpret_cast(first), reinterpret_cast(last), reinterpret_cast(result))); } +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_BACKWARD_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_BACKWARD_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(uint16_t, uint16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const uint16_t, uint16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(int16_t, int16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const int16_t, int16_t, uint8_t) +#endif +COPY_BACKWARD_ALIAS_FUNC(void, void, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const void, void, uint8_t) +#undef COPY_BACKWARD_ALIAS_FUNC +#define FILL_ALIAS_FUNC(type, alias_type, v_type) \ +template <> inline void fill (type* first, type* last, const v_type& value) \ +{ fill (reinterpret_cast(first), reinterpret_cast(last), alias_type(value)); } +FILL_ALIAS_FUNC(void, uint8_t, char) +FILL_ALIAS_FUNC(void, uint8_t, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +FILL_ALIAS_FUNC(char, uint8_t, char) +FILL_ALIAS_FUNC(char, uint8_t, uint8_t) +#endif +FILL_ALIAS_FUNC(int8_t, uint8_t, int8_t) +FILL_ALIAS_FUNC(int16_t, uint16_t, int16_t) +#if __MMX__ || (SIZE_OF_LONG > 4) +FILL_ALIAS_FUNC(int32_t, uint32_t, int32_t) +#endif +#endif +#undef FILL_ALIAS_FUNC +#define COPY_N_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy_n (ctype* first, size_t count, type* result) \ +{ return reinterpret_cast (copy_n (reinterpret_cast(first), count, reinterpret_cast(result))); } +COPY_N_ALIAS_FUNC(const void, void, uint8_t) +COPY_N_ALIAS_FUNC(void, void, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_N_ALIAS_FUNC(const char, char, uint8_t) +COPY_N_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_N_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_N_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_N_ALIAS_FUNC(const int8_t, int8_t, uint8_t) +COPY_N_ALIAS_FUNC(int16_t, int16_t, uint16_t) +COPY_N_ALIAS_FUNC(uint16_t, uint16_t, uint16_t) +COPY_N_ALIAS_FUNC(const int16_t, int16_t, uint16_t) +#if __MMX__ || (SIZE_OF_LONG > 4) +COPY_N_ALIAS_FUNC(int32_t, int32_t, uint32_t) +COPY_N_ALIAS_FUNC(uint32_t, uint32_t, uint32_t) +COPY_N_ALIAS_FUNC(const int32_t, int32_t, uint32_t) +#endif +#endif +#undef COPY_N_ALIAS_FUNC +#define FILL_N_ALIAS_FUNC(type, alias_type, v_type) \ +template <> inline type* fill_n (type* first, size_t n, const v_type& value) \ +{ return reinterpret_cast (fill_n (reinterpret_cast(first), n, alias_type(value))); } +FILL_N_ALIAS_FUNC(void, uint8_t, char) +FILL_N_ALIAS_FUNC(void, uint8_t, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +FILL_N_ALIAS_FUNC(char, uint8_t, char) +FILL_N_ALIAS_FUNC(char, uint8_t, uint8_t) +#endif +FILL_N_ALIAS_FUNC(int8_t, uint8_t, int8_t) +FILL_N_ALIAS_FUNC(int16_t, uint16_t, int16_t) +#if __MMX__ || (SIZE_OF_LONG > 4) +FILL_N_ALIAS_FUNC(int32_t, uint32_t, int32_t) +#endif +#endif +#undef FILL_N_ALIAS_FUNC + +extern const char _FmtPrtChr[2][8]; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uatomic.h b/pwn/flipper/dist/common/include/ustl/uatomic.h new file mode 100644 index 0000000..fd5e090 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uatomic.h @@ -0,0 +1,115 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2016 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "utypes.h" +#if HAVE_CPP11 + +//{{{ memory_order ----------------------------------------------------- + +namespace ustl { + +enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +}; + +//}}}------------------------------------------------------------------- +//{{{ atomic + +template +class atomic { + T _v; +public: + atomic (void) = default; + inline constexpr atomic (T v) : _v(v) {} + atomic (const atomic&) = delete; + atomic& operator= (const atomic&) = delete; + inline bool is_lock_free (void) const + { return __atomic_is_lock_free (sizeof(T), &_v); } + inline void store (T v, memory_order order = memory_order_seq_cst) + { __atomic_store_n (&_v, v, order); } + inline T load (memory_order order = memory_order_seq_cst) const + { return __atomic_load_n (&_v, order); } + inline T exchange (T v, memory_order order = memory_order_seq_cst) + { return __atomic_exchange_n (&_v, v, order); } + inline bool compare_exchange_weak (T& expected, T desired, memory_order order = memory_order_seq_cst) + { return __atomic_compare_exchange_n (&_v, &expected, desired, true, order, order); } + inline bool compare_exchange_weak (T& expected, T desired, memory_order success, memory_order failure) + { return __atomic_compare_exchange_n (&_v, &expected, desired, true, success, failure); } + inline bool compare_exchange_strong (T& expected, T desired, memory_order success, memory_order failure) + { return __atomic_compare_exchange_n (&_v, &expected, desired, false, success, failure); } + inline T fetch_add (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_fetch_add (&_v, v, order); } + inline T fetch_sub (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_fetch_sub (&_v, v, order); } + inline T fetch_and (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_fetch_and (&_v, v, order); } + inline T fetch_or (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_fetch_or (&_v, v, order); } + inline T fetch_xor (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_fetch_xor (&_v, v, order); } + inline T add_fetch (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_add_fetch (&_v, v, order); } + inline T sub_fetch (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_sub_fetch (&_v, v, order); } + inline T and_fetch (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_and_fetch (&_v, v, order); } + inline T or_fetch (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_or_fetch (&_v, v, order); } + inline T xor_fetch (T v, memory_order order = memory_order_seq_cst ) + { return __atomic_xor_fetch (&_v, v, order); } + inline operator T (void) const { return load(); } + inline T operator= (T v) { store(v); return v; } + inline T operator++ (int) { return fetch_add (1); } + inline T operator-- (int) { return fetch_sub (1); } + inline T operator++ (void) { return add_fetch (1); } + inline T operator-- (void) { return sub_fetch (1); } + inline T operator+= (T v) { return add_fetch (v); } + inline T operator-= (T v) { return sub_fetch (v); } + inline T operator&= (T v) { return and_fetch (v); } + inline T operator|= (T v) { return or_fetch (v); } + inline T operator^= (T v) { return xor_fetch (v); } +}; +#define ATOMIC_VAR_INIT {0} + +//}}}------------------------------------------------------------------- +//{{{ atomic_flag + +class atomic_flag { + bool _v; +public: + atomic_flag (void) = default; + inline constexpr atomic_flag (bool v) : _v(v) {} + atomic_flag (const atomic_flag&) = delete; + atomic_flag& operator= (const atomic_flag&) = delete; + void clear (memory_order order = memory_order_seq_cst) + { __atomic_clear (&_v, order); } + bool test_and_set (memory_order order = memory_order_seq_cst) + { return __atomic_test_and_set (&_v, order); } +}; +#define ATOMIC_FLAG_INIT {false} + +//}}}------------------------------------------------------------------- +//{{{ fence functions + +namespace { + +template +static inline T kill_dependency (T v) noexcept + { T r (v); return r; } +static inline void atomic_thread_fence (memory_order order) noexcept + { __atomic_thread_fence (order); } +static inline void atomic_signal_fence (memory_order order) noexcept + { __atomic_signal_fence (order); } + +} // namespace +} // namespace ustl +#endif // HAVE_CPP11 +//}}}------------------------------------------------------------------- diff --git a/pwn/flipper/dist/common/include/ustl/ubitset.h b/pwn/flipper/dist/common/include/ustl/ubitset.h new file mode 100644 index 0000000..671be85 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ubitset.h @@ -0,0 +1,129 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ustring.h" +#include "ufunction.h" + +namespace ustl { + +class istringstream; + +typedef uint32_t bitset_value_type; + +void convert_to_bitstring (const bitset_value_type* v, size_t n, string& buf) noexcept; +void convert_from_bitstring (const string& buf, bitset_value_type* v, size_t n) noexcept; + +/// \class bitset ubitset.h ustl.h +/// \ingroup Sequences +/// +/// \brief bitset is a fixed-size block of memory with addressable bits. +/// +/// Normally used for state flags; allows setting and unsetting of individual +/// bits as well as bitwise operations on the entire set. The interface is +/// most like that of unsigned integers, and is intended to be used as such. +/// If you were using begin() and end() functions in STL's bitset, you would +/// not be able to do the same thing here, because those functions return +/// host type iterators, not bits. +/// +template +class bitset { +public: + typedef bitset_value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef size_t difference_type; + typedef size_t size_type; + typedef const bitset& rcself_t; +private: + static const size_t s_WordBits = BitsInType (value_type); + static const size_t s_nWords = Size / s_WordBits + ((Size % s_WordBits) != 0); + static const size_t s_nBits = s_nWords * s_WordBits; +private: + inline value_type& BitRef (uoff_t n) { assert (n < Size); return _bits [n / s_WordBits]; } + inline value_type BitRef (uoff_t n) const { assert (n < Size); return _bits [n / s_WordBits]; } + inline value_type Mask (uoff_t n) const { assert (n < Size); return 1 << (n % s_WordBits); } +public: + inline bitset (value_type v = 0) { fill_n (_bits, s_nWords, 0); _bits[0] = v; } + inline bitset (const string& buf) { convert_from_bitstring (buf, _bits, s_nWords); } + inline void flip (uoff_t n) { BitRef(n) ^= Mask(n); } + inline void reset (void) { fill_n (_bits, s_nWords, 0); } + inline void clear (void) { fill_n (_bits, s_nWords, 0); } + inline void set (void) { fill_n (_bits, s_nWords, -1); } + inline bitset operator~ (void) const { bitset rv (*this); rv.flip(); return rv; } + inline size_type size (void) const { return Size; } + inline size_type capacity (void) const { return s_nBits; } + inline bool test (uoff_t n) const { return BitRef(n) & Mask(n); } + inline bool operator[] (uoff_t n) const { return test(n); } + inline const_iterator begin (void) const { return _bits; } + inline iterator begin (void) { return _bits; } + inline const_iterator end (void) const { return _bits + s_nWords; } + inline iterator end (void) { return _bits + s_nWords; } + /// Returns the value_type with the equivalent bits. If size() > 1, you'll get only the first BitsInType(value_type) bits. + inline value_type to_value (void) const { return _bits[0]; } + /// Flips all the bits in the set. + inline void flip (void) { transform (begin(), end(), begin(), bitwise_not()); } + /// Sets or clears bit \p n. + inline void set (uoff_t n, bool val = true) + { + value_type& br (BitRef (n)); + const value_type mask (Mask (n)); + const value_type bOn (br | mask), bOff (br & ~mask); + br = val ? bOn : bOff; + } + // Sets the value of the bitrange \p first through \p last to the equivalent number of bits from \p v. + inline void set (uoff_t first, uoff_t DebugArg(last), value_type v) + { + assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller"); + assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary"); + assert ((v & BitMask(value_type,distance(first,last))) == v && "The value is too large to fit in the given bit range"); + BitRef(first) |= v << (first % s_WordBits); + } + /// Clears the bit \p n. + inline void reset (uoff_t n) { set (n, false); } + /// Returns a string with bits MSB "001101001..." LSB. + inline string to_string (void) const + { + string rv (Size, '0'); + convert_to_bitstring (_bits, s_nWords, rv); + return rv; + } + inline value_type at (uoff_t n) const { return test(n); } + /// Returns the value in bits \p first through \p last. + inline value_type at (uoff_t first, uoff_t last) const + { + assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller"); + assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary"); + return (BitRef(first) >> (first % s_WordBits)) & BitMask(value_type,distance(first, last)); + } + inline bool any (void) const { value_type sum = 0; foreach (const_iterator, i, *this) sum |= *i; return sum; } + inline bool none (void) const { return !any(); } + inline size_t count (void) const { size_t sum = 0; foreach (const_iterator, i, *this) sum += popcount(*i); return sum; } + inline bool operator== (rcself_t v) const + { return s_nWords == 1 ? (_bits[0] == v._bits[0]) : equal (begin(), end(), v.begin()); } + inline bitset operator& (rcself_t v) const + { bitset result; transform (begin(), end(), v.begin(), result.begin(), bitwise_and()); return result; } + inline bitset operator| (rcself_t v) const + { bitset result; transform (begin(), end(), v.begin(), result.begin(), bitwise_or()); return result; } + inline bitset operator^ (rcself_t v) const + { bitset result; transform (begin(), end(), v.begin(), result.begin(), bitwise_xor()); return result; } + inline rcself_t operator&= (rcself_t v) + { transform (begin(), end(), v.begin(), begin(), bitwise_and()); return *this; } + inline rcself_t operator|= (rcself_t v) + { transform (begin(), end(), v.begin(), begin(), bitwise_or()); return *this; } + inline rcself_t operator^= (rcself_t v) + { transform (begin(), end(), v.begin(), begin(), bitwise_xor()); return *this; } + inline void read (istream& is) { nr_container_read (is, *this); } + inline void write (ostream& os) const { nr_container_write (os, *this); } + inline void text_write (ostringstream& os) const { os << to_string(); } + void text_read (istringstream& is); + inline size_t stream_size (void) const { return sizeof(_bits); } +private: + value_type _bits [s_nWords]; +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uctralgo.h b/pwn/flipper/dist/common/include/ustl/uctralgo.h new file mode 100644 index 0000000..aab0bb0 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uctralgo.h @@ -0,0 +1,467 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once + +namespace ustl { + +/// Copy copies elements from the range [first, last) to the range +/// [result, result + (last - first)). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally, +/// for every integer n from 0 to last - first, copy performs the assignment +/// *(result + n) = *(first + n). Assignments are performed in forward order, +/// i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator copy (const Container& ctr, OutputIterator result) +{ + return copy (ctr.begin(), ctr.end(), result); +} + +/// Copy_if copies elements from the range [first, last) to the range +/// [result, result + (last - first)) if pred(*i) returns true. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator copy_if (Container& ctr, OutputIterator result, Predicate pred) +{ + return copy_if (ctr.begin(), ctr.end(), result, pred); +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template +inline UnaryFunction for_each (Container& ctr, UnaryFunction f) +{ + return for_each (ctr.begin(), ctr.end(), f); +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template +inline UnaryFunction for_each (const Container& ctr, UnaryFunction f) +{ + return for_each (ctr.begin(), ctr.end(), f); +} + +/// Returns the first iterator i in the range [first, last) such that +/// *i == value. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template +inline typename Container::const_iterator find (const Container& ctr, const EqualityComparable& value) +{ + return find (ctr.begin(), ctr.end(), value); +} +template +inline typename Container::iterator find (Container& ctr, const EqualityComparable& value) +{ + return find (ctr.begin(), ctr.end(), value); +} + +/// Returns the first iterator i in the range [first, last) such that +/// pred(*i) is true. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template +inline typename Container::const_iterator find_if (const Container& ctr, Predicate pred) +{ + return find_if (ctr.begin(), ctr.end(), pred); +} +template +inline typename Container::iterator find_if (Container& ctr, Predicate pred) +{ + return find_if (ctr.begin(), ctr.end(), pred); +} + +/// Count finds the number of elements in [first, last) that are equal +/// to value. More precisely, the first version of count returns the +/// number of iterators i in [first, last) such that *i == value. +/// \ingroup ConditionAlgorithms +/// +template +inline size_t count (const Container& ctr, const EqualityComparable& value) +{ + return count (ctr.begin(), ctr.end(), value); +} + +/// Count_if finds the number of elements in [first, last) that satisfy the +/// predicate pred. More precisely, the first version of count_if returns the +/// number of iterators i in [first, last) such that pred(*i) is true. +/// \ingroup ConditionAlgorithms +/// +template +inline size_t count_if (const Container& ctr, Predicate pred) +{ + return count_if (ctr.begin(), ctr.end(), pred); +} + +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// +template +inline void transform (Container& ctr, UnaryFunction op) +{ + transform (ctr.begin(), ctr.end(), ctr.begin(), op); +} + +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator transform (Container& ctr, OutputIterator result, UnaryFunction op) +{ + return transform (ctr.begin(), ctr.end(), result, op); +} + +/// The second version of transform is very similar, except that it uses a +/// Binary Function instead of a Unary Function: it performs the operation +/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns +/// the result to *o, where i2 is the corresponding iterator in the second +/// input range and where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last1 - first1, it performs the assignment +/// *(result + n) = op(*(first1 + n), *(first2 + n). +/// The return value is result + (last1 - first1). +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator transform (Container& ctr, InputIterator first, OutputIterator result, BinaryFunction op) +{ + return transform (ctr.begin(), ctr.end(), first, result, op); +} + +/// Replace replaces every element in the range [first, last) equal to +/// old_value with new_value. That is: for every iterator i, +/// if *i == old_value then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template +inline void replace (Container& ctr, const T& old_value, const T& new_value) +{ + replace (ctr.begin(), ctr.end(), old_value, new_value); +} + +/// Replace_if replaces every element in the range [first, last) for which +/// pred returns true with new_value. That is: for every iterator i, if +/// pred(*i) is true then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template +inline void replace_if (Container& ctr, Predicate pred, const T& new_value) +{ + replace_if (ctr.begin(), ctr.end(), pred, new_value); +} + +/// Replace_copy copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element equal to old_value +/// is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy performs the +/// assignment *(result+n) = new_value if *(first+n) == old_value, and +/// *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator replace_copy (const Container& ctr, OutputIterator result, const T& old_value, const T& new_value) +{ + return replace_copy (ctr.begin(), ctr.end(), result, old_value, new_value); +} + +/// Replace_copy_if copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element for which pred is +/// true is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy_if performs the +/// assignment *(result+n) = new_value if pred(*(first+n)), +/// and *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator replace_copy_if (const Container& ctr, OutputIterator result, Predicate pred, const T& new_value) +{ + return replace_copy_if (ctr.begin(), ctr.end(), result, pred, new_value); +} + +/// Fill assigns the value value to every element in the range [first, last). +/// That is, for every iterator i in [first, last), +/// it performs the assignment *i = value. +/// \ingroup GeneratorAlgorithms +/// +template +inline void fill (Container& ctr, const T& value) +{ + fill (ctr.begin(), ctr.end(), value); +} + +/// Generate assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, last). +/// \ingroup GeneratorAlgorithms +/// +template +inline void generate (Container& ctr, Generator gen) +{ + generate (ctr.begin(), ctr.end(), gen); +} + +/// Randomly permute the elements of the container. +/// \ingroup GeneratorAlgorithms +/// +template +inline void random_shuffle (Container& ctr) +{ + random_shuffle (ctr.begin(), ctr.end()); +} + +/// Remove_copy copies elements that are not equal to value from the range +/// [first, last) to a range beginning at result. The return value is the +/// end of the resulting range. This operation is stable, meaning that the +/// relative order of the elements that are copied is the same as in the +/// range [first, last). +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator remove_copy (const Container& ctr, OutputIterator result, const T& value) +{ + return remove_copy (ctr.begin(), ctr.end(), result, value); +} + +/// Remove_copy_if copies elements from the range [first, last) to a range +/// beginning at result, except that elements for which pred is true are not +/// copied. The return value is the end of the resulting range. This operation +/// is stable, meaning that the relative order of the elements that are copied +/// is the same as in the range [first, last). +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator remove_copy_if (const Container& ctr, OutputIterator result, Predicate pred) +{ + return remove_copy_if (ctr.begin(), ctr.end(), result, pred); +} + +/// Remove removes from the range [first, last) all elements that are equal to +/// value. That is, remove returns an iterator new_last such that the range +/// [first, new_last) contains no elements equal to value. Remove is stable, +/// meaning that the relative order of elements that are not equal to value is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline void remove (Container& ctr, const T& value) +{ + ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), value), ctr.end()); +} + +/// Remove removes from the range [first, last) all elements that have an iterator +/// in range [rfirst, rlast). The range is assumed to be sorted. That is, remove +/// returns an iterator new_last such that the range [first, new_last) contains +/// no elements whose iterators are in [rfirst, rlast). Remove is stable, +/// meaning that the relative order of elements that are not equal to value is +/// unchanged. This version of the algorithm is a uSTL extension. +/// \ingroup MutatingAlgorithms +/// +template +inline void remove (Container& ctr, ForwardIterator rfirst, ForwardIterator rlast) +{ + ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), rfirst, rlast), ctr.end()); +} + +/// Remove_if removes from the range [first, last) every element x such that +/// pred(x) is true. That is, remove_if returns an iterator new_last such that +/// the range [first, new_last) contains no elements for which pred is true. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Remove_if is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline void remove_if (Container& ctr, Predicate pred) +{ + ctr.erase (remove_copy_if (ctr.begin(), ctr.end(), ctr.begin(), pred), ctr.end()); +} + +/// Unique_copy copies elements from the range [first, last) to a range +/// beginning with result, except that in a consecutive group of duplicate +/// elements only the first one is copied. The return value is the end of +/// the range to which the elements are copied. This behavior is similar +/// to the Unix filter uniq. +/// \ingroup MutatingAlgorithms +/// +template +inline OutputIterator unique_copy (const Container& ctr, OutputIterator result) +{ + return unique_copy (ctr.begin(), ctr.end(), result); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline void unique (Container& ctr) +{ + ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin()), ctr.end()); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template +inline void unique (Container& ctr, BinaryPredicate binary_pred) +{ + ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin(), binary_pred), ctr.end()); +} + +/// Reverse reverses a range. +/// That is: for every i such that 0 <= i <= (last - first) / 2), +/// it exchanges *(first + i) and *(last - (i + 1)). +/// \ingroup MutatingAlgorithms +/// +template +inline void reverse (Container& ctr) +{ + reverse (ctr.begin(), ctr.end()); +} + +/// Exchanges ranges [first, middle) and [middle, last) +/// \ingroup MutatingAlgorithms +/// +template +inline void rotate (Container& ctr, off_t offset) +{ + assert (size_t(offset > 0 ? offset : -offset) < ctr.size()); + if (offset > 0) + rotate (ctr.begin(), ctr.end() - offset, ctr.end()); + else + rotate (ctr.begin(), ctr.begin() - offset, ctr.end()); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), *j < value +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template +inline typename Container::const_iterator lower_bound (const Container& ctr, const LessThanComparable& value) +{ + return lower_bound (ctr.begin(), ctr.end(), value); +} +template +inline typename Container::iterator lower_bound (Container& ctr, const LessThanComparable& value) +{ + return lower_bound (ctr.begin(), ctr.end(), value); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), value < *j is false. +/// \ingroup SearchingAlgorithms +/// +template +inline typename Container::const_iterator upper_bound (const Container& ctr, const LessThanComparable& value) +{ + return upper_bound (ctr.begin(), ctr.end(), value); +} +template +inline typename Container::iterator upper_bound (Container& ctr, const LessThanComparable& value) +{ + return upper_bound (ctr.begin(), ctr.end(), value); +} + +/// Performs a binary search for \p value. +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template +inline bool binary_search (const Container& ctr, const typename Container::value_type& value) +{ + return binary_search (ctr.begin(), ctr.end(), value); +} +template +inline bool binary_search (Container& ctr, const typename Container::value_type& value) +{ + return binary_search (ctr.begin(), ctr.end(), value); +} + +/// Returns pair +/// \ingroup SearchingAlgorithms +/// +template +inline pair equal_range (const Container& ctr, const LessThanComparable& value) +{ + return equal_range (ctr.begin(), ctr.end(), value); +} +template +inline pair equal_range (Container& ctr, const LessThanComparable& value) +{ + return equal_range (ctr.begin(), ctr.end(), value); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void sort (Container& ctr) +{ + sort (ctr.begin(), ctr.end()); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void sort (Container& ctr, Compare comp) +{ + sort (ctr.begin(), ctr.end(), comp); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void stable_sort (Container& ctr) +{ + stable_sort (ctr.begin(), ctr.end()); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template +inline void stable_sort (Container& ctr, Compare comp) +{ + stable_sort (ctr.begin(), ctr.end(), comp); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ufunction.h b/pwn/flipper/dist/common/include/ustl/ufunction.h new file mode 100644 index 0000000..2c5b5e5 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ufunction.h @@ -0,0 +1,462 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once + +namespace ustl { + +//---------------------------------------------------------------------- +// Standard functors +//---------------------------------------------------------------------- + +/// \brief void-returning function abstract interface. +/// \ingroup FunctorObjects +template +struct void_function { + typedef Result result_type; +}; + +/// \brief \p Result f (\p Arg) function abstract interface. +/// \ingroup FunctorObjects +template +struct unary_function { + typedef Arg argument_type; + typedef Result result_type; +}; + +/// \brief \p Result f (\p Arg1, \p Arg2) function abstract interface. +/// \ingroup FunctorObjects +template +struct binary_function { + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define STD_BINARY_FUNCTOR(name, rv, func) \ +template struct name : public binary_function \ +{ inline rv operator()(const T& a, const T& b) const { return func; } }; +#define STD_UNARY_FUNCTOR(name, rv, func) \ +template struct name : public unary_function \ +{ inline rv operator()(const T& a) const { return func; } }; +#define STD_CONVERSION_FUNCTOR(name, func) \ +template struct name : public unary_function \ +{ inline D operator()(const S& a) const { return func; } }; + +STD_BINARY_FUNCTOR (plus, T, (a + b)) +STD_BINARY_FUNCTOR (minus, T, (a - b)) +STD_BINARY_FUNCTOR (divides, T, (a / b)) +STD_BINARY_FUNCTOR (modulus, T, (a % b)) +STD_BINARY_FUNCTOR (multiplies, T, (a * b)) +STD_BINARY_FUNCTOR (logical_and, T, (a && b)) +STD_BINARY_FUNCTOR (logical_or, T, (a || b)) +STD_UNARY_FUNCTOR (logical_not, T, (!a)) +STD_BINARY_FUNCTOR (bitwise_or, T, (a | b)) +STD_BINARY_FUNCTOR (bitwise_and, T, (a & b)) +STD_BINARY_FUNCTOR (bitwise_xor, T, (a ^ b)) +STD_UNARY_FUNCTOR (bitwise_not, T, (~a)) +STD_UNARY_FUNCTOR (negate, T, (-a)) +STD_BINARY_FUNCTOR (equal_to, bool, (a == b)) +STD_BINARY_FUNCTOR (not_equal_to, bool, (!(a == b))) +STD_BINARY_FUNCTOR (greater, bool, (b < a)) +STD_BINARY_FUNCTOR (less, bool, (a < b)) +STD_BINARY_FUNCTOR (greater_equal, bool, (!(a < b))) +STD_BINARY_FUNCTOR (less_equal, bool, (!(b < a))) +STD_BINARY_FUNCTOR (compare, int, (a < b ? -1 : (b < a))) +STD_UNARY_FUNCTOR (identity, T, (a)) + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// \brief Selects and returns the first argument. +/// \ingroup FunctorObjects +template struct project1st : public binary_function { inline const T1& operator()(const T1& a, const T2&) const { return a; } }; +/// \brief Selects and returns the second argument. +/// \ingroup FunctorObjects +template struct project2nd : public binary_function { inline const T2& operator()(const T1&, const T2& a) const { return a; } }; + +//---------------------------------------------------------------------- +// Generic function to functor converters. +//---------------------------------------------------------------------- + +/// \brief Wrapper object for unary function pointers. +/// Use the ptr_fun accessor to create this object. +/// \ingroup FunctorObjects +template +class pointer_to_unary_function : public unary_function { +public: + typedef Arg argument_type; + typedef Result result_type; + typedef Result (*pfunc_t)(Arg); +public: + explicit inline pointer_to_unary_function (pfunc_t pfn) : _pfn (pfn) {} + inline result_type operator() (argument_type v) const { return _pfn(v); } +private: + pfunc_t _pfn; ///< Pointer to the wrapped function. +}; + +/// \brief Wrapper object for binary function pointers. +/// Use the ptr_fun accessor to create this object. +/// \ingroup FunctorObjects +template +class pointer_to_binary_function : public binary_function { +public: + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; + typedef Result (*pfunc_t)(Arg1, Arg2); +public: + explicit inline pointer_to_binary_function (pfunc_t pfn) : _pfn (pfn) {} + inline result_type operator() (first_argument_type v1, second_argument_type v2) const { return _pfn(v1, v2); } +private: + pfunc_t _pfn; ///< Pointer to the wrapped function. +}; + +/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it. +/// \ingroup FunctorAccessors +template +inline pointer_to_unary_function ptr_fun (Result (*pfn)(Arg)) +{ + return pointer_to_unary_function (pfn); +} + +/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it. +/// \ingroup FunctorAccessors +template +inline pointer_to_binary_function ptr_fun (Result (*pfn)(Arg1,Arg2)) +{ + return pointer_to_binary_function (pfn); +} + +//---------------------------------------------------------------------- +// Negators. +//---------------------------------------------------------------------- + +/// \brief Wraps a unary function to return its logical negative. +/// Use the unary_negator accessor to create this object. +/// \ingroup FunctorObjects +template +class unary_negate : public unary_function { +public: + typedef typename UnaryFunction::argument_type argument_type; + typedef typename UnaryFunction::result_type result_type; +public: + explicit inline unary_negate (UnaryFunction pfn) : _pfn (pfn) {} + inline result_type operator() (argument_type v) const { return !_pfn(v); } +private: + UnaryFunction _pfn; +}; + +/// Returns the functor that negates the result of *pfn(). +/// \ingroup FunctorAccessors +template +inline unary_negate unary_negator (UnaryFunction pfn) +{ + return unary_negate(pfn); +} + +//---------------------------------------------------------------------- +// Argument binders +//---------------------------------------------------------------------- + +/// \brief Converts a binary function to a unary function +/// by binding a constant value to the first argument. +/// Use the bind1st accessor to create this object. +/// \ingroup FunctorObjects +template +class binder1st : public unary_function { +public: + typedef typename BinaryFunction::first_argument_type arg1_t; + typedef typename BinaryFunction::second_argument_type arg2_t; + typedef typename BinaryFunction::result_type result_t; +public: + inline binder1st (const BinaryFunction& pfn, const arg1_t& v) : _pfn (pfn), _v(v) {} + inline result_t operator()(arg2_t v2) const { return _pfn (_v, v2); } +protected: + BinaryFunction _pfn; + arg1_t _v; +}; + +/// \brief Converts a binary function to a unary function +/// by binding a constant value to the second argument. +/// Use the bind2nd accessor to create this object. +/// \ingroup FunctorObjects +template +class binder2nd : public unary_function { +public: + typedef typename BinaryFunction::first_argument_type arg1_t; + typedef typename BinaryFunction::second_argument_type arg2_t; + typedef typename BinaryFunction::result_type result_t; +public: + inline binder2nd (const BinaryFunction& pfn, const arg2_t& v) : _pfn (pfn), _v(v) {} + inline result_t operator()(arg1_t v1) const { return _pfn (v1, _v); } +protected: + BinaryFunction _pfn; + arg2_t _v; +}; + +/// Converts \p pfn into a unary function by binding the first argument to \p v. +/// \ingroup FunctorAccessors +template +inline binder1st +bind1st (BinaryFunction pfn, typename BinaryFunction::first_argument_type v) +{ + return binder1st (pfn, v); +} + +/// Converts \p pfn into a unary function by binding the second argument to \p v. +/// \ingroup FunctorAccessors +template +inline binder2nd +bind2nd (BinaryFunction pfn, typename BinaryFunction::second_argument_type v) +{ + return binder2nd (pfn, v); +} + +//---------------------------------------------------------------------- +// Composition adapters +//---------------------------------------------------------------------- + +/// \brief Chains two unary functions together. +/// +/// When f(x) and g(x) are composed, the result is function c(x)=f(g(x)). +/// Use the \ref compose1 accessor to create this object. +/// This template is an extension, implemented by SGI STL and uSTL. +/// \ingroup FunctorObjects +/// +template +class unary_compose : public unary_function { +public: + typedef typename Operation2::argument_type arg_t; + typedef const arg_t& rcarg_t; + typedef typename Operation1::result_type result_t; +public: + inline unary_compose (const Operation1& f, const Operation2& g) : _f(f), _g(g) {} + inline result_t operator() (rcarg_t x) const { return _f(_g(x)); } +protected: + Operation1 _f; ///< f(x), if c(x) = f(g(x)) + Operation2 _g; ///< g(x), if c(x) = f(g(x)) +}; + +/// Creates a \ref unary_compose object whose function c(x)=f(g(x)) +/// \ingroup FunctorAccessors +template +inline unary_compose +compose1 (const Operation1& f, const Operation2& g) +{ return unary_compose(f, g); } + +/// \brief Chains two unary functions through a binary function. +/// +/// When f(x,y), g(x), and h(x) are composed, the result is function +/// c(x)=f(g(x),h(x)). Use the \ref compose2 accessor to create this +/// object. This template is an extension, implemented by SGI STL and uSTL. +/// \ingroup FunctorObjects +/// +template +class binary_compose : public unary_function { +public: + typedef typename Operation2::argument_type arg_t; + typedef const arg_t& rcarg_t; + typedef typename Operation1::result_type result_t; +public: + inline binary_compose (const Operation1& f, const Operation2& g, const Operation3& h) : _f(f), _g(g), _h(h) {} + inline result_t operator() (rcarg_t x) const { return _f(_g(x), _h(x)); } +protected: + Operation1 _f; ///< f(x,y), if c(x) = f(g(x),h(x)) + Operation2 _g; ///< g(x), if c(x) = f(g(x),h(x)) + Operation3 _h; ///< h(x), if c(x) = f(g(x),h(x)) +}; + +/// Creates a \ref binary_compose object whose function c(x)=f(g(x),h(x)) +/// \ingroup FunctorAccessors +template +inline binary_compose +compose2 (const Operation1& f, const Operation2& g, const Operation3& h) +{ return binary_compose (f, g, h); } + +//---------------------------------------------------------------------- +// Member function adaptors +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define MEM_FUN_T(WrapperName, ClassName, ArgType, FuncType, CallType) \ + template \ + class ClassName : public unary_function { \ + public: \ + typedef Ret (T::*func_t) FuncType; \ + public: \ + explicit inline ClassName (func_t pf) : _pf (pf) {} \ + inline Ret operator() (ArgType p) const { return (p CallType _pf)(); } \ + private: \ + func_t _pf; \ + }; \ + \ + template \ + inline ClassName WrapperName (Ret (T::*pf) FuncType) \ + { \ + return ClassName (pf); \ + } + +MEM_FUN_T(mem_fun, mem_fun_t, T*, (void), ->*) +MEM_FUN_T(mem_fun, const_mem_fun_t, const T*, (void) const, ->*) +MEM_FUN_T(mem_fun_ref, mem_fun_ref_t, T&, (void), .*) +MEM_FUN_T(mem_fun_ref, const_mem_fun_ref_t, const T&, (void) const, .*) + +#define EXT_MEM_FUN_T(ClassName, HostType, FuncType) \ + template \ + class ClassName : public unary_function { \ + public: \ + typedef Ret (T::*func_t)(V) FuncType; \ + public: \ + inline ClassName (HostType t, func_t pf) : _t (t), _pf (pf) {} \ + inline Ret operator() (V v) const { return (_t->*_pf)(v); } \ + private: \ + HostType _t; \ + func_t _pf; \ + }; \ + \ + template \ + inline ClassName mem_fun (HostType p, Ret (T::*pf)(V) FuncType) \ + { \ + return ClassName (p, pf); \ + } + +EXT_MEM_FUN_T(ext_mem_fun_t, T*, ) +EXT_MEM_FUN_T(const_ext_mem_fun_t, const T*, const) + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +//---------------------------------------------------------------------- +// Member variable adaptors (uSTL extension) +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define MEM_VAR_T(FunctorName, ArgType, VarType, BaseClass, CallImpl) \ + template \ + class FunctorName##_t : public BaseClass { \ + public: \ + typedef ArgType argument_type; \ + typedef typename Function::result_type result_type; \ + typedef VarType mem_var_ptr_t; \ + public: \ + inline FunctorName##_t (mem_var_ptr_t pv, Function pfn) : _pv(pv), _pfn(pfn) {} \ + inline result_type operator() CallImpl \ + private: \ + mem_var_ptr_t _pv; \ + Function _pfn; \ + }; \ + \ + template \ + inline FunctorName##_t \ + FunctorName (VT T::*mvp, Function pfn) \ + { \ + return FunctorName##_t (mvp, pfn); \ + } + +#define FUNCTOR_UNARY_BASE(ArgType) unary_function +#define FUNCTOR_BINARY_BASE(ArgType) binary_function + +#define MEM_VAR_UNARY_ARGS (argument_type p) const \ + { return _pfn(p.*_pv); } +#define MEM_VAR_BINARY_ARGS (argument_type p1, argument_type p2) const \ + { return _pfn(p1.*_pv, p2.*_pv); } + +MEM_VAR_T(mem_var1, T&, VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS) +MEM_VAR_T(const_mem_var1, const T&, const VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS) +MEM_VAR_T(mem_var2, T&, VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS) +MEM_VAR_T(const_mem_var2, const T&, const VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS) + +#undef MEM_VAR_UNARY_ARGS +#undef MEM_VAR_BINARY_ARGS + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// Returned functor passes member variable \p mvp reference of given object to equal\. +/// \ingroup FunctorAccessors +template +inline const_mem_var1_t >, T, VT> +mem_var_equal_to (const VT T::*mvp, const VT& v) +{ + return const_mem_var1_t >,T,VT> (mvp, bind2nd(equal_to(), v)); +} + +/// Returned functor passes member variable \p mvp reference of given object to less\. +/// \ingroup FunctorAccessors +template +inline const_mem_var1_t >, T, VT> +mem_var_less (const VT T::*mvp, const VT& v) +{ + return const_mem_var1_t >,T,VT> (mvp, bind2nd(less(), v)); +} + +/// Returned functor passes member variable \p mvp reference of given object to equal\. +/// \ingroup FunctorAccessors +template +inline const_mem_var2_t, T, VT> +mem_var_equal_to (const VT T::*mvp) +{ + return const_mem_var2_t,T,VT> (mvp, equal_to()); +} + +/// Returned functor passes member variable \p mvp reference of given object to less\. +/// \ingroup FunctorAccessors +template +inline const_mem_var2_t, T, VT> +mem_var_less (const VT T::*mvp) +{ + return const_mem_var2_t,T,VT> (mvp, less()); +} + +//---------------------------------------------------------------------- +// Dereference adaptors (uSTL extension) +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define DEREFERENCER_T(ClassName, ArgType, BaseClass, CallImpl, FunctorKey) \ + template \ + class ClassName : public BaseClass { \ + public: \ + typedef ArgType* argument_type; \ + typedef typename Function::result_type result_type; \ + public: \ + inline ClassName (Function pfn) : _pfn (pfn) {} \ + inline result_type operator() CallImpl \ + private: \ + Function _pfn; \ + }; \ + \ + template \ + inline ClassName _dereference (Function pfn, FunctorKey) \ + { \ + return ClassName (pfn); \ + } + +#define DEREF_UNARY_ARGS (argument_type p) const \ + { return _pfn(*p); } +#define DEREF_BINARY_ARGS (argument_type p1, argument_type p2) const \ + { return _pfn(*p1, *p2); } + +DEREFERENCER_T(deref1_t, T, FUNCTOR_UNARY_BASE(T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(T)) +DEREFERENCER_T(const_deref1_t, const T, FUNCTOR_UNARY_BASE(const T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(const T)) +DEREFERENCER_T(deref2_t, T, FUNCTOR_BINARY_BASE(T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(T)) +DEREFERENCER_T(const_deref2_t, const T, FUNCTOR_BINARY_BASE(const T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(const T)) + +#define dereference(f) _dereference(f,f) + +#undef DEREF_UNARY_ARGS +#undef DEREF_BINARY_ARGS + +#endif + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uheap.h b/pwn/flipper/dist/common/include/ustl/uheap.h new file mode 100644 index 0000000..2ed0563 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uheap.h @@ -0,0 +1,161 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ualgobase.h" + +namespace ustl { + +/// \brief Returns true if the given range is a heap under \p comp. +/// A heap is a sequentially encoded binary tree where for every node +/// comp(node,child1) is false and comp(node,child2) is false. +/// \ingroup HeapAlgorithms +/// \ingroup ConditionAlgorithms +/// +template +bool is_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + RandomAccessIterator iChild (first); + for (; ++iChild < last; ++first) + if (comp (*first, *iChild) || (++iChild < last && comp (*first, *iChild))) + return false; + return true; +} + +/// Utility function to "trickle down" the root item - swaps the root item with its +/// largest child and recursively fixes the proper subtree. +template +void trickle_down_heap (RandomAccessIterator first, size_t iHole, size_t heapSize, Compare comp) +{ + typedef typename iterator_traits::value_type value_type; + const value_type v (first[iHole]); + for (size_t iChild; (iChild = 2 * iHole + 1) < heapSize;) { + if (iChild + 1 < heapSize) + iChild += comp (first[iChild], first[iChild + 1]); + if (comp (v, first[iChild])) { + first[iHole] = first[iChild]; + iHole = iChild; + } else + break; + } + first[iHole] = v; +} + +/// \brief make_heap turns the range [first, last) into a heap +/// At completion, is_heap (first, last, comp) is true. +/// The algorithm is adapted from "Classic Data Structures in C++" by Timothy Budd. +/// \ingroup HeapAlgorithms +/// \ingroup SortingAlgorithms +/// +template +void make_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + if (last <= first) + return; + const size_t heapSize = distance (first, last); + for (RandomAccessIterator i = first + (heapSize - 1)/2; i >= first; --i) + trickle_down_heap (first, distance(first,i), heapSize, comp); +} + +/// \brief Inserts the *--last into the preceeding range assumed to be a heap. +/// \ingroup HeapAlgorithms +/// \ingroup MutatingAlgorithms +template +void push_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + if (last <= first) + return; + typedef typename iterator_traits::value_type value_type; + const value_type v (*--last); + while (first < last) { + RandomAccessIterator iParent = first + (distance(first, last) - 1) / 2; + if (comp (v, *iParent)) + break; + *last = *iParent; + last = iParent; + } + *last = v; +} + +/// Removes the largest element from the heap (*first) and places it at *(last-1) +/// [first, last-1) is a heap after this operation. +/// \ingroup HeapAlgorithms +/// \ingroup MutatingAlgorithms +template +void pop_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + if (--last <= first) + return; + iter_swap (first, last); + trickle_down_heap (first, 0, distance(first,last), comp); +} + +/// Sorts heap [first, last) in descending order according to comp. +/// \ingroup HeapAlgorithms +/// \ingroup SortingAlgorithms +template +void sort_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + for (; first < last; --last) + pop_heap (first, last, comp); +} + +#define HEAP_FN_WITH_LESS(rtype, name) \ +template \ +inline rtype name (RandomAccessIterator first, RandomAccessIterator last) \ +{ \ + typedef typename iterator_traits::value_type value_type; \ + return name (first, last, less()); \ +} +HEAP_FN_WITH_LESS (bool, is_heap) +HEAP_FN_WITH_LESS (void, make_heap) +HEAP_FN_WITH_LESS (void, push_heap) +HEAP_FN_WITH_LESS (void, pop_heap) +HEAP_FN_WITH_LESS (void, sort_heap) +#undef HEAP_FN_WITH_LESS + +/// \class priority_queue uheap.h ustl.h +/// \ingroup Sequences +/// +/// \brief Sorted queue adapter to uSTL containers. +/// +/// Acts just like the queue adapter, but keeps the elements sorted by priority +/// specified by the given comparison operator. +/// +template , typename Comp = less > +class priority_queue { +public: + typedef Container container_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::value_type value_type; + typedef typename container_type::reference reference; + typedef typename container_type::const_reference const_reference; + typedef typename container_type::const_iterator const_iterator; +public: + inline explicit priority_queue (const Comp& c = Comp()) : _v(), _c(c) {} + inline priority_queue (const Comp& c, const container_type& v) : _v(v), _c(c) {} + priority_queue (const_iterator f, const_iterator l, const Comp& c = Comp()) + : _v(f, l), _c(c) { make_heap (_v.begin(), _v.end(), _c); } + inline size_type size (void) const { return _v.size(); } + inline bool empty (void) const { return _v.empty(); } + inline const_reference top (void) const { return _v.front(); } + inline void push (const_reference v){ _v.push_back (v); push_heap (_v.begin(), _v.end(), _c); } + inline void pop (void) { pop_heap (_v.begin(), _v.end()); _v.pop_back(); } + inline void swap (priority_queue& v){ _v.swap (v._v); swap (_c, v._c); } +#if HAVE_CPP11 + inline explicit priority_queue (priority_queue&& v) : _v(move(v._v)),_c(v._c) {} + inline priority_queue (const Comp& c, container_type&& v) : _v(move(v)),_c(c) {} + priority_queue (const_iterator f, const_iterator l, const Comp& c, container_type&& v) + : _v(move(v)), _c(c) { _v.insert (_v.end(), f, l); make_heap (_v.begin(), _v.end(), _c); } + inline priority_queue& operator= (priority_queue&& v) { swap (v); return *this; } + template + inline void emplace (Args&&... args) { _v.emplace_back (forward(args)...); push_heap (_v.begin(), _v.end(), _c); } +#endif +private: + container_type _v; ///< Element container. + Comp _c; ///< Comparison functor by value. +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uios.h b/pwn/flipper/dist/common/include/ustl/uios.h new file mode 100644 index 0000000..941fc9e --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uios.h @@ -0,0 +1,99 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "utypes.h" + +namespace ustl { + +class file_exception; + +/// Defines types and constants used by all stream classes. +class ios_base { +public: + /// Used to set parameters for stringstreams + enum fmtflags_bits { + boolalpha = (1 << 0), ///< Boolean values printed as text. + showbase = (1 << 1), ///< Add 0x or 0 prefixes on hex and octal numbers. + showpoint = (1 << 2), ///< Print decimal point. + showpos = (1 << 3), + skipws = (1 << 4), ///< Skip whitespace when reading. + unitbuf = (1 << 5), + uppercase = (1 << 6), + dec = (1 << 7), ///< Decimal number output. + oct = (1 << 8), ///< Octal number output. + hex = (1 << 9), ///< Hexadecimal number output. + fixed = (1 << 10), ///< Fixed-point float output. + scientific = (1 << 11), ///< Scientific float format. + left = (1 << 12), ///< Left alignment. + right = (1 << 13), ///< Right alignment. + internal = (1 << 14), + basefield = dec| oct| hex, + floatfield = fixed| scientific, + adjustfield = left| right| internal + }; + /// For file-based streams, specifies fd mode. + enum openmode_bits { + in = (1 << 0), + out = (1 << 1), + app = (1 << 2), + ate = (1 << 3), + binary = (1 << 4), + trunc = (1 << 5), + #ifndef DOXYGEN_SHOULD_SKIP_THIS + nonblock= (1 << 6), + nocreate= (1 << 7), + noctty = (1 << 8), + nombits = 9 + #endif + }; + /// Seek directions, equivalent to SEEK_SET, SEEK_CUR, and SEEK_END. + enum seekdir { + beg, + cur, + end + }; + /// I/O state bitmasks. + enum iostate_bits { + goodbit = 0, + badbit = (1 << 0), + eofbit = (1 << 1), + failbit = (1 << 2), + #ifndef DOXYGEN_SHOULD_SKIP_THIS + nbadbits = 3, + allbadbits = 0x7 + #endif + }; + + enum { default_stream_buffer_size = 4095 }; + + typedef uint32_t openmode; ///< Holds openmode_bits. + struct fmtflags{ fmtflags(const uint32_t& flags) : f(flags){}; fmtflags() = default; uint32_t f; }; ///< Holds fmtflags_bits for a string stream. + typedef uint32_t iostate; ///< Holds iostate_bits for a file stream. + typedef file_exception failure; ///< Thrown by fstream on errors. + + static const char c_DefaultDelimiters [16]; ///< Default word delimiters for stringstreams. +public: + inline ios_base (void) : _state (goodbit), _exceptions (allbadbits) {} + inline iostate rdstate (void) const { return _state; } + inline bool bad (void) const { return rdstate() & badbit; } + inline bool good (void) const { return rdstate() == goodbit; } + inline bool fail (void) const { return rdstate() & (badbit | failbit); } + inline bool eof (void) const { return rdstate() & eofbit; } + inline bool operator! (void) const { return fail(); } + inline operator bool (void) const { return !fail(); } + inline void clear (iostate v = goodbit) { _state = v; } + inline void setstate (iostate v) { _state |= v; } + inline iostate exceptions (void) const { return _exceptions; } + inline iostate exceptions (iostate v) { return _exceptions = v; } +protected: + inline bool set_and_throw (iostate v) { setstate(v); return exceptions() & v; } + void overrun (const char* op, const char* type, uint32_t n, uint32_t p, uint32_t rem); +private: + uint16_t _state; ///< Open state, using ios::iostate_bits. + uint16_t _exceptions; ///< Exception flags, using ios::iostate_bits. +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uiosfunc.h b/pwn/flipper/dist/common/include/ustl/uiosfunc.h new file mode 100644 index 0000000..eccc6fb --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uiosfunc.h @@ -0,0 +1,82 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "sostream.h" + +namespace ustl { + +class ios : public ios_base { +public: + /// \class align uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline align() calls. + /// + /// Example: os << ios::align(sizeof(uint16_t)); + /// + class align { + public: + inline explicit align (size_t grain = c_DefaultAlignment) : _grain(grain) {} + inline istream& apply (istream& is) const { is.align (_grain); return is; } + inline ostream& apply (ostream& os) const { os.align (_grain); return os; } + inline void read (istream& is) const { apply (is); } + inline void write (ostream& os) const { apply (os); } + inline size_t stream_size (void) const { return _grain - 1; } + private: + const size_t _grain; + }; + + /// \class talign uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow type-based alignment. + template + class talign : public align { + public: + inline explicit talign (void) : align (stream_align_of (NullValue())) {} + }; + + /// \class skip uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline skip() calls. + /// + /// Example: os << ios::skip(sizeof(uint16_t)); + /// + class skip { + public: + inline explicit skip (size_t nBytes) : _nBytes(nBytes) {} + inline istream& apply (istream& is) const { is.skip (_nBytes); return is; } + inline ostream& apply (ostream& os) const { os.skip (_nBytes); return os; } + inline void read (istream& is) const { apply (is); } + inline void write (ostream& os) const { apply (os); } + inline size_t stream_size (void) const { return _nBytes; } + private: + const size_t _nBytes; + }; + + /// \class width uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline set_width() calls. + /// + /// Example: os << ios::width(15); + /// + class width { + public: + inline explicit width (size_t nBytes) : _nBytes(nBytes) {} + inline ostringstream& apply (ostringstream& os) const { os.width (_nBytes); return os; } + inline void text_write (ostringstream& os) const { apply (os); } + private: + const size_t _nBytes; + }; + + // Deprecated way to set output format base. Use setiosflags manipulator instead. + struct base { + inline explicit base (size_t n) : _f (n == 16 ? hex : (n == 8 ? oct : dec)) {} + inline void text_write (ostringstream& os) const { os.setf (_f, basefield); } + private: + fmtflags _f; + }; +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uiostream.h b/pwn/flipper/dist/common/include/ustl/uiostream.h new file mode 100644 index 0000000..c28b579 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uiostream.h @@ -0,0 +1,13 @@ +#pragma once + +#include "sostream.h" +#include "mistream.h" +#include "outerrstream.h" + +namespace ustl +{ + + extern coutclass& cout; + extern coutclass& cerr; + +} diff --git a/pwn/flipper/dist/common/include/ustl/uiterator.h b/pwn/flipper/dist/common/include/ustl/uiterator.h new file mode 100644 index 0000000..c45d8d8 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uiterator.h @@ -0,0 +1,360 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. +// +/// \file uiterator.h +/// \brief Contains various iterator adapters. + +#pragma once +#include "utypes.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +template +struct iterator { + typedef T value_type; + typedef Distance difference_type; + typedef Pointer pointer; + typedef Reference reference; + typedef Category iterator_category; +}; + +//---------------------------------------------------------------------- + +struct input_iterator_tag {}; +struct output_iterator_tag {}; +struct forward_iterator_tag {}; +struct bidirectional_iterator_tag {}; +struct random_access_iterator_tag {}; + +/// \struct iterator_traits uiterator.h ustl.h +/// \brief Contains the type traits of \p Iterator +/// +template +struct iterator_traits { + typedef typename Iterator::value_type value_type; + typedef typename Iterator::difference_type difference_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; + typedef typename Iterator::iterator_category iterator_category; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +struct iterator_traits { + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* const_pointer; + typedef T* pointer; + typedef const T& const_reference; + typedef T& reference; + typedef random_access_iterator_tag iterator_category; +}; + +template +struct iterator_traits { + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* const_pointer; + typedef const T* pointer; + typedef const T& const_reference; + typedef const T& reference; + typedef random_access_iterator_tag iterator_category; +}; + +template <> +struct iterator_traits { + typedef uint8_t value_type; + typedef ptrdiff_t difference_type; + typedef const void* const_pointer; + typedef void* pointer; + typedef const value_type& const_reference; + typedef value_type& reference; + typedef random_access_iterator_tag iterator_category; +}; + +template <> +struct iterator_traits { + typedef uint8_t value_type; + typedef ptrdiff_t difference_type; + typedef const void* const_pointer; + typedef const void* pointer; + typedef const value_type& const_reference; + typedef const value_type& reference; + typedef random_access_iterator_tag iterator_category; +}; + +#endif + +//---------------------------------------------------------------------- + +/// \class reverse_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Wraps \p Iterator to behave in an exactly opposite manner. +/// +template +class reverse_iterator { +public: + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + typedef typename iterator_traits::iterator_category iterator_category; +public: + reverse_iterator (void) : _i() {} + explicit reverse_iterator (Iterator iter) : _i (iter) {} + inline bool operator== (const reverse_iterator& iter) const { return _i == iter._i; } + inline bool operator< (const reverse_iterator& iter) const { return iter._i < _i; } + inline Iterator base (void) const { return _i; } + inline reference operator* (void) const { Iterator prev (_i); --prev; return *prev; } + inline pointer operator-> (void) const { return &(operator*()); } + inline reverse_iterator& operator++ (void) { -- _i; return *this; } + inline reverse_iterator& operator-- (void) { ++ _i; return *this; } + inline reverse_iterator operator++ (int) { reverse_iterator prev (*this); -- _i; return prev; } + inline reverse_iterator operator-- (int) { reverse_iterator prev (*this); ++ _i; return prev; } + inline reverse_iterator& operator+= (size_t n) { _i -= n; return *this; } + inline reverse_iterator& operator-= (size_t n) { _i += n; return *this; } + inline reverse_iterator operator+ (size_t n) const { return reverse_iterator (_i - n); } + inline reverse_iterator operator- (size_t n) const { return reverse_iterator (_i + n); } + inline reference operator[] (uoff_t n) const { return *(*this + n); } + inline difference_type operator- (const reverse_iterator& i) const { return distance (i._i, _i); } +protected: + Iterator _i; +}; + +template +inline reverse_iterator make_reverse_iterator (Iterator i) + { return reverse_iterator(i); } + +//---------------------------------------------------------------------- +#if HAVE_CPP11 + +/// \class move_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Wraps \p Iterator to behave in an exactly opposite manner. +/// +template +class move_iterator { +public: + using value_type = typename iterator_traits::value_type; + using difference_type = typename iterator_traits::difference_type; + using pointer = typename iterator_traits::pointer; + using reference = value_type&&; + using iterator_category = typename iterator_traits::iterator_category; +public: + move_iterator (void) : _i() {} + explicit move_iterator (Iterator iter) : _i (iter) {} + inline bool operator== (const move_iterator& iter) const { return _i == iter._i; } + inline bool operator< (const move_iterator& iter) const { return _i < iter._i; } + inline Iterator base (void) const { return _i; } + inline reference operator* (void) const { return move(*_i); } + inline pointer operator-> (void) const { return &*_i; } + inline move_iterator& operator++ (void) { ++_i; return *this; } + inline move_iterator& operator-- (void) { --_i; return *this; } + inline move_iterator operator++ (int) { move_iterator r (*this); ++ _i; return r; } + inline move_iterator operator-- (int) { move_iterator r (*this); -- _i; return r; } + inline move_iterator& operator+= (size_t n) { _i += n; return *this; } + inline move_iterator& operator-= (size_t n) { _i -= n; return *this; } + inline move_iterator operator+ (size_t n) const { return move_iterator (_i - n); } + inline move_iterator operator- (size_t n) const { return move_iterator (_i + n); } + inline reference operator[] (uoff_t n) const { return move(*(*this + n)); } + inline difference_type operator- (const move_iterator& i) const { return distance (_i, i._i); } +protected: + Iterator _i; +}; + +template +inline move_iterator make_move_iterator (Iterator i) + { return move_iterator(i); } + +#endif +//---------------------------------------------------------------------- + +/// \class insert_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Calls insert on bound container for each assignment. +/// +template +class insert_iterator { +public: + typedef typename Container::value_type value_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::iterator iterator; + typedef output_iterator_tag iterator_category; +public: + explicit insert_iterator (Container& ctr, iterator ip) : _rctr (ctr), _ip (ip) {} + inline insert_iterator& operator= (typename Container::const_reference v) + { _ip = _rctr.insert (_ip, v); return *this; } + inline insert_iterator& operator* (void) { return *this; } + inline insert_iterator& operator++ (void) { ++ _ip; return *this; } + inline insert_iterator operator++ (int) { insert_iterator prev (*this); ++_ip; return prev; } +protected: + Container& _rctr; + iterator _ip; +}; + +/// Returns the insert_iterator for \p ctr. +template +inline insert_iterator inserter (Container& ctr, typename Container::iterator ip) + { return insert_iterator (ctr, ip); } + +//---------------------------------------------------------------------- + +/// \class back_insert_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Calls push_back on bound container for each assignment. +/// +template +class back_insert_iterator { +public: + typedef typename Container::value_type value_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef output_iterator_tag iterator_category; +public: + explicit back_insert_iterator (Container& ctr) : _rctr (ctr) {} + inline back_insert_iterator& operator= (typename Container::const_reference v) + { _rctr.push_back (v); return *this; } + inline back_insert_iterator& operator* (void) { return *this; } + inline back_insert_iterator& operator++ (void) { return *this; } + inline back_insert_iterator operator++ (int) { return *this; } +protected: + Container& _rctr; +}; + +/// Returns the back_insert_iterator for \p ctr. +template +inline back_insert_iterator back_inserter (Container& ctr) + { return back_insert_iterator (ctr); } + +//---------------------------------------------------------------------- + +/// \class front_insert_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Calls push_front on bound container for each assignment. +/// +template +class front_insert_iterator { +public: + typedef typename Container::value_type value_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef output_iterator_tag iterator_category; +public: + explicit front_insert_iterator (Container& ctr) : _rctr (ctr) {} + inline front_insert_iterator& operator= (typename Container::const_reference v) + { _rctr.push_front (v); return *this; } + inline front_insert_iterator& operator* (void) { return *this; } + inline front_insert_iterator& operator++ (void) { return *this; } + inline front_insert_iterator operator++ (int) { return *this; } +protected: + Container& _rctr; +}; + +/// Returns the front_insert_iterator for \p ctr. +template +inline front_insert_iterator front_inserter (Container& ctr) + { return front_insert_iterator (ctr); } + +//---------------------------------------------------------------------- + +/// \class index_iterate uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief Allows iteration through an index container. +/// +/// Converts an iterator into a container of uoff_t indexes to an +/// iterator of iterators into another container. +/// +template +class index_iterate { +public: + typedef RandomAccessIterator value_type; + typedef ptrdiff_t difference_type; + typedef RandomAccessIterator* pointer; + typedef RandomAccessIterator reference; + typedef random_access_iterator_tag iterator_category; +public: + index_iterate (void) : _base(), _i() {} + index_iterate (RandomAccessIterator ibase, IndexIterator iindex) : _base (ibase), _i (iindex) {} + inline bool operator== (const index_iterate& i) const { return _i == i._i; } + inline bool operator< (const index_iterate& i) const { return _i < i._i; } + inline bool operator== (const RandomAccessIterator& i) const { return _base == i; } + inline bool operator< (const RandomAccessIterator& i) const { return _base < i; } + inline IndexIterator base (void) const { return _i; } + inline reference operator* (void) const { return advance(_base, *_i); } + inline pointer operator-> (void) const { return &(operator*()); } + inline index_iterate& operator++ (void) { ++_i; return *this; } + inline index_iterate& operator-- (void) { --_i; return *this; } + inline index_iterate operator++ (int) { index_iterate prev (*this); ++_i; return prev; } + inline index_iterate operator-- (int) { index_iterate prev (*this); --_i; return prev; } + inline index_iterate& operator+= (size_t n) { _i += n; return *this; } + inline index_iterate& operator-= (size_t n) { _i -= n; return *this; } + inline index_iterate operator+ (size_t n) const { return index_iterate (_base, _i + n); } + inline index_iterate operator- (size_t n) const { return index_iterate (_base, _i - n); } + inline reference operator[] (uoff_t n) const { return *(*this + n); } + inline difference_type operator- (const index_iterate& i) const { return distance (_i, i._i); } +private: + RandomAccessIterator _base; + IndexIterator _i; +}; + +/// Returns an index_iterate for \p ibase over \p iindex. +template +inline index_iterate index_iterator (RandomAccessIterator ibase, IndexIterator iindex) +{ + return index_iterate (ibase, iindex); +} + +/// Converts the indexes in \p xc to iterators in \p ic of base \p ibase. +template +inline void indexv_to_iteratorv (typename IteratorContainer::value_type ibase, const IndexContainer& xc, IteratorContainer& ic) +{ + ic.resize (xc.size()); + copy_n (index_iterator (ibase, xc.begin()), xc.size(), ic.begin()); +} + +//---------------------------------------------------------------------- + +/// Converts the given const_iterator into an iterator. +/// +template +inline typename Container::iterator unconst (typename Container::const_iterator i, Container&) + { return const_cast(i); } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define IBYI(Iter1, Iter2, Ctr1, Ctr2) \ +template \ +inline typename Container2::Iter2 ibyi (typename Container1::Iter1 idx, Ctr1& ctr1, Ctr2& ctr2) \ +{ \ + assert (ctr1.size() == ctr2.size()); \ + return ctr2.begin() + (idx - ctr1.begin()); \ +} + +IBYI(const_iterator, const_iterator, const Container1, const Container2) +IBYI(iterator, iterator, Container1, Container2) +IBYI(const_iterator, iterator, const Container1, Container2) +IBYI(iterator, const_iterator, Container1, const Container2) + +#else // DOXYGEN + +#error "This declaration is for doxygen only; it is not compiled." + +/// Converts a const_iterator in one container into a const_iterator in another container. +template +inline typename Container2::iterator ibyi (typename Container1::iterator idx, Container1& ctr1, Container2& ctr2) {} + +#endif // DOXYGEN + +//---------------------------------------------------------------------- + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ulimits.h b/pwn/flipper/dist/common/include/ustl/ulimits.h new file mode 100644 index 0000000..bedceb9 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ulimits.h @@ -0,0 +1,324 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "utypes.h" +#include "traits.h" +#if HAVE_CPP11 + #include "uttraits.h" +#endif + +namespace ustl { + +enum float_denorm_style { + denorm_indeterminate = -1, + denorm_absent, + denorm_present +}; + +enum float_round_style { + round_indeterminate = -1, + round_toward_zero, + round_to_nearest, + round_toward_infinity, + round_toward_neg_infinity +}; + +namespace { + template + struct __limits_digits { enum { value = sizeof(T)*8 };}; + template + struct __limits_digits10 { enum { value = sizeof(T)*8*643/2136+1 };}; +} + +/// \class numeric_limits ulimits.h ustl.h +/// \brief Defines numeric limits for a type. +/// +template +struct numeric_limits { + static inline constexpr T min (void) { return T(); } // Returns the minimum value for type T. + static inline constexpr T max (void) { return T(); } // Returns the minimum value for type T. + static inline constexpr T lowest (void) { return T(); } + static inline constexpr T epsilon (void) { return T(); } + static inline constexpr T round_error (void) { return T(); } + static inline constexpr T infinity (void) { return T(); } + static inline constexpr T quiet_NaN (void) { return T(); } + static inline constexpr T signaling_NaN (void) { return T(); } + static inline constexpr T denorm_min (void) { return T(); } + static constexpr const bool is_specialized = false; + static constexpr const bool is_signed = tm::TypeTraits::isSigned; ///< True if the type is signed. + static constexpr const bool is_integer = tm::TypeTraits::isIntegral; ///< True if stores an exact value. + static constexpr const bool is_exact = tm::TypeTraits::isIntegral; ///< True if stores an exact value. + static constexpr const bool is_integral = tm::TypeTraits::isFundamental; ///< True if fixed size and cast-copyable. + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = false; + static constexpr const bool is_modulo = false; + static constexpr const bool has_infinity = false; + static constexpr const bool has_quiet_NaN = false; + static constexpr const bool has_signaling_NaN = false; + static constexpr const bool has_denorm_loss = false; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const int radix = 0; + static constexpr const int min_exponent = 0; + static constexpr const int min_exponent10 = 0; + static constexpr const int max_exponent = 0; + static constexpr const int max_exponent10 = 0; + static constexpr const float_denorm_style has_denorm = denorm_absent; + static constexpr const float_round_style round_style = round_toward_zero; + static constexpr const unsigned digits = __limits_digits::value; ///< Number of bits in T + static constexpr const unsigned digits10 = 0; + static constexpr const unsigned max_digits10 = 0; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template +struct numeric_limits { + static inline constexpr T* min (void) { return nullptr; } + static inline constexpr T* max (void) { return reinterpret_cast(UINTPTR_MAX); } + static inline constexpr T* lowest (void) { return nullptr; } + static inline constexpr T* epsilon (void) { return nullptr; } + static inline constexpr T* round_error (void) { return nullptr; } + static inline constexpr T* infinity (void) { return nullptr; } + static inline constexpr T* quiet_NaN (void) { return nullptr; } + static inline constexpr T* signaling_NaN (void) { return nullptr; } + static inline constexpr T* denorm_min (void) { return nullptr; } + static constexpr const bool is_specialized = false; + static constexpr const bool is_signed = false; + static constexpr const bool is_integer = true; + static constexpr const bool is_exact = true; + static constexpr const bool is_integral = true; + static constexpr const bool is_iec559 = false; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = true; + static constexpr const bool has_infinity = false; + static constexpr const bool has_quiet_NaN = false; + static constexpr const bool has_signaling_NaN = false; + static constexpr const bool has_denorm_loss = false; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = false; + static constexpr const int radix = 2; + static constexpr const int min_exponent = 0; + static constexpr const int min_exponent10 = 0; + static constexpr const int max_exponent = 0; + static constexpr const int max_exponent10 = 0; + static constexpr const float_denorm_style has_denorm = denorm_absent; + static constexpr const float_round_style round_style = round_toward_zero; + static constexpr const unsigned digits = __limits_digits::value; + static constexpr const unsigned digits10 = __limits_digits10::value; + static constexpr const unsigned max_digits10 = 0; +}; +/* +template <> struct numeric_limits { + static inline constexpr float min (void) { return FLT_MIN; } + static inline constexpr float max (void) { return FLT_MAX; } + static inline constexpr float lowest (void) { return -FLT_MAX; } + static inline constexpr float epsilon (void) { return FLT_EPSILON; } + static inline constexpr float round_error (void) { return 0.5f; } + static inline constexpr float infinity (void) { return __builtin_huge_valf(); } + static inline constexpr float quiet_NaN (void) { return __builtin_nanf(""); } + static inline constexpr float signaling_NaN (void) { return __builtin_nansf(""); } + static inline constexpr float denorm_min (void) { return __FLT_DENORM_MIN__; } + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool is_integral = true; + static constexpr const bool is_iec559 = true; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool has_infinity = __FLT_HAS_INFINITY__; + static constexpr const bool has_quiet_NaN = __FLT_HAS_QUIET_NAN__; + static constexpr const bool has_signaling_NaN = __FLT_HAS_QUIET_NAN__; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = true; + static constexpr const int radix = FLT_RADIX; + static constexpr const int min_exponent = FLT_MIN_EXP; + static constexpr const int min_exponent10 = FLT_MIN_10_EXP; + static constexpr const int max_exponent = FLT_MAX_EXP; + static constexpr const int max_exponent10 = FLT_MAX_10_EXP; + static constexpr const float_denorm_style has_denorm = denorm_present; + static constexpr const float_round_style round_style = round_to_nearest; + static constexpr const unsigned digits = FLT_MANT_DIG; + static constexpr const unsigned digits10 = FLT_DIG; + static constexpr const unsigned max_digits10 = FLT_MANT_DIG; +}; + +template <> struct numeric_limits { + static inline constexpr double min (void) { return DBL_MIN; } + static inline constexpr double max (void) { return DBL_MAX; } + static inline constexpr double lowest (void) { return -DBL_MAX; } + static inline constexpr double epsilon (void) { return DBL_EPSILON; } + static inline constexpr double round_error (void) { return 0.5; } + static inline constexpr double infinity (void) { return __builtin_huge_val(); } + static inline constexpr double quiet_NaN (void) { return __builtin_nan(""); } + static inline constexpr double signaling_NaN (void) { return __builtin_nans(""); } + static inline constexpr double denorm_min (void) { return __DBL_DENORM_MIN__; } + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool is_integral = true; + static constexpr const bool is_iec559 = true; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool has_infinity = __DBL_HAS_INFINITY__; + static constexpr const bool has_quiet_NaN = __DBL_HAS_QUIET_NAN__; + static constexpr const bool has_signaling_NaN = __DBL_HAS_QUIET_NAN__; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = true; + static constexpr const int radix = FLT_RADIX; + static constexpr const int min_exponent = DBL_MIN_EXP; + static constexpr const int min_exponent10 = DBL_MIN_10_EXP; + static constexpr const int max_exponent = DBL_MAX_EXP; + static constexpr const int max_exponent10 = DBL_MAX_10_EXP; + static constexpr const float_denorm_style has_denorm = denorm_present; + static constexpr const float_round_style round_style = round_to_nearest; + static constexpr const unsigned digits = DBL_MANT_DIG; + static constexpr const unsigned digits10 = DBL_DIG; + static constexpr const unsigned max_digits10 = DBL_MANT_DIG; +}; + +template <> struct numeric_limits { + static inline constexpr long double min (void) { return LDBL_MIN; } + static inline constexpr long double max (void) { return LDBL_MAX; } + static inline constexpr long double lowest (void) { return -LDBL_MAX; } + static inline constexpr long double epsilon (void) { return LDBL_EPSILON; } + static inline constexpr long double round_error (void) { return 0.5l; } + static inline constexpr long double infinity (void) { return __builtin_huge_vall(); } + static inline constexpr long double quiet_NaN (void) { return __builtin_nanl(""); } + static inline constexpr long double signaling_NaN (void) { return __builtin_nansl(""); } + static inline constexpr long double denorm_min (void) { return __LDBL_DENORM_MIN__; } + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool is_integral = true; + static constexpr const bool is_iec559 = true; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool has_infinity = __LDBL_HAS_INFINITY__; + static constexpr const bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__; + static constexpr const bool has_signaling_NaN = __LDBL_HAS_QUIET_NAN__; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = true; + static constexpr const int radix = FLT_RADIX; + static constexpr const int min_exponent = LDBL_MIN_EXP; + static constexpr const int min_exponent10 = LDBL_MIN_10_EXP; + static constexpr const int max_exponent = LDBL_MAX_EXP; + static constexpr const int max_exponent10 = LDBL_MAX_10_EXP; + static constexpr const float_denorm_style has_denorm = denorm_present; + static constexpr const float_round_style round_style = round_to_nearest; + static constexpr const unsigned digits = LDBL_MANT_DIG; + static constexpr const unsigned digits10 = LDBL_DIG; + static constexpr const unsigned max_digits10 = LDBL_MANT_DIG; +}; + +template <> struct numeric_limits { + static inline constexpr long double min (void) { return LDBL_MIN; } + static inline constexpr long double max (void) { return LDBL_MAX; } + static inline constexpr long double lowest (void) { return -LDBL_MAX; } + static inline constexpr long double epsilon (void) { return LDBL_EPSILON; } + static inline constexpr long double round_error (void) { return 0.5l; } + static inline constexpr long double infinity (void) { return __builtin_huge_vall(); } + static inline constexpr long double quiet_NaN (void) { return __builtin_nanl(""); } + static inline constexpr long double signaling_NaN (void) { return __builtin_nansl(""); } + static inline constexpr long double denorm_min (void) { return __LDBL_DENORM_MIN__; } + static constexpr const bool is_specialized = true; + static constexpr const bool is_signed = true; + static constexpr const bool is_integer = false; + static constexpr const bool is_exact = false; + static constexpr const bool is_integral = true; + static constexpr const bool is_iec559 = true; + static constexpr const bool is_bounded = true; + static constexpr const bool is_modulo = false; + static constexpr const bool has_infinity = __LDBL_HAS_INFINITY__; + static constexpr const bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__; + static constexpr const bool has_signaling_NaN = __LDBL_HAS_QUIET_NAN__; + static constexpr const bool has_denorm_loss = true; + static constexpr const bool traps = false; + static constexpr const bool tinyness_before = true; + static constexpr const int radix = FLT_RADIX; + static constexpr const int min_exponent = LDBL_MIN_EXP; + static constexpr const int min_exponent10 = LDBL_MIN_10_EXP; + static constexpr const int max_exponent = LDBL_MAX_EXP; + static constexpr const int max_exponent10 = LDBL_MAX_10_EXP; + static constexpr const float_denorm_style has_denorm = denorm_present; + static constexpr const float_round_style round_style = round_to_nearest; + static constexpr const unsigned digits = LDBL_MANT_DIG; + static constexpr const unsigned digits10 = LDBL_DIG; + static constexpr const unsigned max_digits10 = LDBL_MANT_DIG; + };*/ + +#define _NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \ +template <> struct numeric_limits { \ + static inline constexpr type min (void) { return minVal; } \ + static inline constexpr type max (void) { return maxVal; } \ + static inline constexpr type lowest (void) { return minVal; } \ + static inline constexpr type epsilon (void) { return 0; } \ + static inline constexpr type round_error (void) { return 0; } \ + static inline constexpr type infinity (void) { return 0; } \ + static inline constexpr type quiet_NaN (void) { return 0; } \ + static inline constexpr type signaling_NaN (void) { return 0; } \ + static inline constexpr type denorm_min (void) { return 0; } \ + static constexpr const bool is_specialized = true; \ + static constexpr const bool is_signed = bSigned; \ + static constexpr const bool is_integer = bInteger; \ + static constexpr const bool is_exact = bInteger; \ + static constexpr const bool is_integral = bIntegral; \ + static constexpr const bool is_iec559 = false; \ + static constexpr const bool is_bounded = true; \ + static constexpr const bool is_modulo = bIntegral; \ + static constexpr const bool has_infinity = false; \ + static constexpr const bool has_quiet_NaN = false; \ + static constexpr const bool has_signaling_NaN = false; \ + static constexpr const bool has_denorm_loss = false; \ + static constexpr const bool traps = false; \ + static constexpr const bool tinyness_before = false; \ + static constexpr const int radix = 2; \ + static constexpr const int min_exponent = 0; \ + static constexpr const int min_exponent10 = 0; \ + static constexpr const int max_exponent = 0; \ + static constexpr const int max_exponent10 = 0; \ + static constexpr const float_denorm_style has_denorm = denorm_absent; \ + static constexpr const float_round_style round_style = round_toward_zero; \ + static constexpr const unsigned digits = __limits_digits::value; \ + static constexpr const unsigned digits10 = __limits_digits10::value; \ + static constexpr const unsigned max_digits10 = 0; \ +} + +//-------------------------------------------------------------------------------------- +// type min max signed integer integral +//-------------------------------------------------------------------------------------- +_NUMERIC_LIMITS (bool, false, true, false, false, true); +_NUMERIC_LIMITS (char, CHAR_MIN, CHAR_MAX, true, true, true); +_NUMERIC_LIMITS (int, INT_MIN, INT_MAX, true, true, true); +_NUMERIC_LIMITS (short, SHRT_MIN, SHRT_MAX, true, true, true); +_NUMERIC_LIMITS (long, LONG_MIN, LONG_MAX, true, true, true); +#if HAVE_THREE_CHAR_TYPES +_NUMERIC_LIMITS (signed char, SCHAR_MIN, SCHAR_MAX, true, true, true); +#endif +_NUMERIC_LIMITS (unsigned char, 0, UCHAR_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned int, 0, UINT_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned short,0, USHRT_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned long, 0, ULONG_MAX, false, true, true); +_NUMERIC_LIMITS (wchar_t, 0, WCHAR_MAX, false, true, true); +#if HAVE_LONG_LONG +_NUMERIC_LIMITS (long long, LLONG_MIN, LLONG_MAX, true, true, true); +_NUMERIC_LIMITS (unsigned long long, 0, ULLONG_MAX, false, true, true); +#endif +//-------------------------------------------------------------------------------------- + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// Macro for defining numeric_limits specializations +#define NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \ +namespace ustl { _NUMERIC_LIMITS (type, minVal, maxVal, bSigned, bInteger, bIntegral); } + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ulist.h b/pwn/flipper/dist/common/include/ustl/ulist.h new file mode 100644 index 0000000..9884591 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ulist.h @@ -0,0 +1,85 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" +#include "uctralgo.h" + +namespace ustl { + +/// \class list ulist.h ustl.h +/// \ingroup Sequences +/// +/// \brief Linked list, defined as an alias to vector. +/// +template +class list : public vector { +public: + typedef typename vector::size_type size_type; + typedef typename vector::iterator iterator; + typedef typename vector::const_iterator const_iterator; + typedef typename vector::reference reference; + typedef typename vector::const_reference const_reference; +public: + inline list (void) : vector () {} + inline explicit list (size_type n) : vector (n) {} + inline list (size_type n, const T& v) : vector (n, v) {} + inline list (const list& v) : vector (v) {} + inline list (const_iterator i1, const_iterator i2) : vector (i1, i2) {} + inline size_type size (void) const { return vector::size(); } + inline iterator begin (void) { return vector::begin(); } + inline const_iterator begin (void) const { return vector::begin(); } + inline iterator end (void) { return vector::end(); } + inline const_iterator end (void) const { return vector::end(); } + inline void push_front (const T& v) { this->insert (begin(), v); } + inline void pop_front (void) { this->erase (begin()); } + inline const_reference front (void) const { return *begin(); } + inline reference front (void) { return *begin(); } + inline void remove (const T& v) { ::ustl::remove (*this, v); } + template + inline void remove_if (Predicate p) { ::ustl::remove_if (*this, p); } + inline void reverse (void) { ::ustl::reverse (*this); } + inline void unique (void) { ::ustl::unique (*this); } + inline void sort (void) { ::ustl::sort (*this); } + void merge (list& l); + void splice (iterator ip, list& l, iterator first = nullptr, iterator last = nullptr); +#if HAVE_CPP11 + inline list (list&& v) : vector (move(v)) {} + inline list (std::initializer_list v) : vector(v) {} + inline list& operator= (list&& v) { vector::operator= (move(v)); return *this; } + template + inline void emplace_front (Args&&... args) { vector::emplace (begin(), forward(args)...); } + inline void push_front (T&& v) { emplace_front (move(v)); } +#endif +}; + +/// Merges the contents with \p l. Assumes both lists are sorted. +template +void list::merge (list& l) +{ + this->insert_space (begin(), l.size()); + ::ustl::merge (this->iat(l.size()), end(), l.begin(), l.end(), begin()); +} + +/// Moves the range [first, last) from \p l to this list at \p ip. +template +void list::splice (iterator ip, list& l, iterator first, iterator last) +{ + if (!first) + first = l.begin(); + if (!last) + last = l.end(); + this->insert (ip, first, last); + l.erase (first, last); +} + +#if HAVE_CPP11 + template using deque = list; +#else + #define deque list ///< list has all the functionality provided by deque +#endif + + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/umap.h b/pwn/flipper/dist/common/include/ustl/umap.h new file mode 100644 index 0000000..9aa2ff2 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/umap.h @@ -0,0 +1,168 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" +#include "ufunction.h" + +namespace ustl { + +template +struct pair_compare_first : public binary_function { + inline bool operator()(const Pair& a, const Pair& b) { return Comp()(a.first,b.first); } +}; +template +struct pair_compare_first_key : public binary_function,K,bool> { + inline bool operator()(const pair& a, const K& b) { return Comp()(a.first,b); } + inline bool operator()(const K& a, const pair& b) { return Comp()(a,b.first); } +}; + +/// \class map umap.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief A sorted associative container of pair +/// +template > +class map : public vector > { +public: + typedef K key_type; + typedef V data_type; + typedef const K& const_key_ref; + typedef const V& const_data_ref; + typedef const map& rcself_t; + typedef vector > base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair const_range_t; + typedef pair range_t; + typedef pair insertrv_t; + typedef Comp key_compare; + typedef pair_compare_first value_compare; + typedef pair_compare_first_key value_key_compare; +public: + inline map (void) : base_class() {} + explicit inline map (size_type n) : base_class (n) {} + inline map (rcself_t v) : base_class (v) {} + inline map (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; } + inline const_data_ref at (const_key_ref k) const { assert (find(k) != end()); return find(k)->second; } + inline data_type& at (const_key_ref k) { assert (find(k) != end()); return find(k)->second; } + inline const_data_ref operator[] (const_key_ref i) const { return at(i); } + data_type& operator[] (const_key_ref i); + inline key_compare key_comp (void) const { return key_compare(); } + inline value_compare value_comp (void) const { return value_compare(); } + inline size_type size (void) const { return base_class::size(); } + inline iterator begin (void) { return base_class::begin(); } + inline const_iterator begin (void) const { return base_class::begin(); } + inline iterator end (void) { return base_class::end(); } + inline const_iterator end (void) const { return base_class::end(); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline void push_back (const_reference v) { insert (v); } + inline const_iterator find (const_key_ref k) const; + inline iterator find (const_key_ref k) { return const_cast (const_cast(*this).find (k)); } + inline const_iterator find_data (const_data_ref v, const_iterator first = nullptr, const_iterator last = nullptr) const; + inline iterator find_data (const_data_ref v, iterator first = nullptr, iterator last = nullptr) { return const_cast (find_data (v, const_cast(first), const_cast(last))); } + const_iterator lower_bound (const_key_ref k) const { return ::ustl::lower_bound (begin(), end(), k, value_key_compare()); } + inline iterator lower_bound (const_key_ref k) { return const_cast(const_cast(*this).lower_bound (k)); } + const_iterator upper_bound (const_key_ref k) const { return ::ustl::upper_bound (begin(), end(), k, value_key_compare()); } + inline iterator upper_bound (const_key_ref k) { return const_cast(const_cast(*this).upper_bound (k)); } + const_range_t equal_range (const_key_ref k) const { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); } + inline range_t equal_range (const_key_ref k) { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); } + inline size_type count (const_key_ref v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); } + insertrv_t insert (const_reference v); + inline iterator insert (const_iterator, const_reference v) { return insert(v).first; } + void insert (const_iterator i1, const_iterator i2) { for (; i1 != i2; ++i1) insert (*i1); } + inline void erase (const_key_ref k); + inline iterator erase (iterator ep) { return base_class::erase (ep); } + inline iterator erase (iterator ep1, iterator ep2) { return base_class::erase (ep1, ep2); } + inline void clear (void) { base_class::clear(); } + inline void swap (map& v) { base_class::swap (v); } +#if HAVE_CPP11 + using initlist_t = std::initializer_list; + inline map (map&& v) : base_class (move(v)) {} + inline map (initlist_t v) : base_class() { insert (v.begin(), v.end()); } + inline map& operator= (map&& v) { base_class::operator= (move(v)); return *this; } + insertrv_t insert (value_type&& v); + inline iterator insert (const_iterator, value_type&& v) { return insert(move(v)).first; } + inline void insert (initlist_t v) { insert (v.begin(), v.end()); } + template + inline insertrv_t emplace (Args&&... args) { return insert (value_type(forward(args)...)); } + template + inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, value_type(forward(args)...)); } + template + inline insertrv_t emplace_back (Args&&... args) { return insert (value_type(forward(args)...)); } +#endif +}; + +/// Returns the pair where K = \p k. +template +inline typename map::const_iterator map::find (const_key_ref k) const +{ + const_iterator i = lower_bound (k); + return (i < end() && Comp()(k,i->first)) ? end() : i; +} + +/// Returns the pair where V = \p v, occuring in range [first,last). +template +inline typename map::const_iterator map::find_data (const_data_ref v, const_iterator first, const_iterator last) const +{ + if (!first) first = begin(); + if (!last) last = end(); + for (; first != last && first->second != v; ++first) ; + return first; +} + +/// Returns data associated with key \p k. +template +typename map::data_type& map::operator[] (const_key_ref k) +{ + iterator ip = lower_bound (k); + if (ip == end() || Comp()(k,ip->first)) + ip = base_class::insert (ip, make_pair (k, V())); + return ip->second; +} + +/// Inserts the pair into the container. +template +typename map::insertrv_t map::insert (const_reference v) +{ + iterator ip = lower_bound (v.first); + bool bInserted = ip == end() || Comp()(v.first, ip->first); + if (bInserted) + ip = base_class::insert (ip, v); + return make_pair (ip, bInserted); +} + +#if HAVE_CPP11 +/// Inserts the pair into the container. +template +typename map::insertrv_t map::insert (value_type&& v) +{ + iterator ip = lower_bound (v.first); + bool bInserted = ip == end() || Comp()(v.first, ip->first); + if (bInserted) + ip = base_class::insert (ip, move(v)); + return make_pair (ip, bInserted); +} +#endif + +/// Erases the element with key value \p k. +template +inline void map::erase (const_key_ref k) +{ + iterator ip = find (k); + if (ip != end()) + erase (ip); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/umemory.h b/pwn/flipper/dist/common/include/ustl/umemory.h new file mode 100644 index 0000000..3687c8a --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/umemory.h @@ -0,0 +1,546 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "unew.h" +#include "uatomic.h" +#include "uiterator.h" +#include "ulimits.h" +#include "upair.h" + +namespace ustl { + +//{{{ auto_ptr ------------------------------------------------------- + +/// \class auto_ptr umemory.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief A smart pointer. +/// +/// Calls delete in the destructor; assignment transfers ownership. +/// This class does not work with void pointers due to the absence +/// of the required dereference operator. auto_ptr is deprecated in +/// c++11; use unique_ptr instead. +/// +template +class auto_ptr { +public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; +public: + /// Takes ownership of \p p. + inline explicit auto_ptr (pointer p = nullptr) : _p (p) {} + /// Takes ownership of pointer in \p p. \p p relinquishes ownership. + inline auto_ptr (auto_ptr& p) : _p (p.release()) {} + /// Deletes the owned pointer. + inline ~auto_ptr (void) { delete _p; } + /// Returns the pointer without relinquishing ownership. + inline pointer get (void) const { return _p; } + /// Returns the pointer and gives up ownership. + inline pointer release (void) { pointer rv (_p); _p = nullptr; return rv; } + /// Deletes the pointer and sets it equal to \p p. + inline void reset (pointer p) { if (p != _p) { delete _p; _p = p; } } + /// Takes ownership of \p p. + inline auto_ptr& operator= (pointer p) { reset (p); return *this; } + /// Takes ownership of pointer in \p p. \p p relinquishes ownership. + inline auto_ptr& operator= (auto_ptr& p) { reset (p.release()); return *this; } + inline reference operator* (void) const { return *_p; } + inline pointer operator-> (void) const { return _p; } + inline bool operator== (const pointer p) const { return _p == p; } + inline bool operator== (const auto_ptr& p) const { return _p == p._p; } + inline bool operator< (const auto_ptr& p) const { return p._p < _p; } +private: + pointer _p; +}; + +//}}}------------------------------------------------------------------- +//{{{ unique_ptr +#if HAVE_CPP11 + +/// \class unique_ptr memory.h stl.h +/// \ingroup MemoryManagement +/// \brief A smart pointer. +/// Calls delete in the destructor; assignment transfers ownership. +/// This class does not work with void pointers due to the absence +/// of the required dereference operator. +template +class unique_ptr { +public: + using element_type = T; + using pointer = element_type*; + using reference = element_type&; +public: + inline constexpr unique_ptr (void) : _p (nullptr) {} + inline constexpr explicit unique_ptr (pointer p) : _p (p) {} + inline unique_ptr (unique_ptr&& p) : _p (p.release()) {} + unique_ptr (const unique_ptr&) = delete; + inline ~unique_ptr (void) { delete _p; } + inline constexpr pointer get (void) const { return _p; } + inline pointer release (void) { auto rv (_p); _p = nullptr; return rv; } + inline void reset (pointer p = nullptr) { assert (p != _p || !p); auto ov (_p); _p = p; delete ov; } + inline void swap (unique_ptr& v) { ::ustl::swap (_p, v._p); } + inline constexpr explicit operator bool (void) const { return _p != nullptr; } + inline unique_ptr& operator= (pointer p) { reset (p); return *this; } + inline unique_ptr& operator= (unique_ptr&& p) { reset (p.release()); return *this; } + unique_ptr& operator=(const unique_ptr&) = delete; + inline constexpr reference operator* (void) const { return *get(); } + inline constexpr pointer operator-> (void) const { return get(); } + inline constexpr reference operator[] (size_t i) const { return get()[i]; } + inline constexpr bool operator== (const pointer p) const { return _p == p; } + inline constexpr bool operator== (const unique_ptr& p) const { return _p == p._p; } + inline constexpr bool operator< (const unique_ptr& p) const { return _p < p._p; } +private: + pointer _p; +}; + +// array version +template +class unique_ptr { +public: + using element_type = T; + using pointer = element_type*; + using reference = element_type&; +public: + inline constexpr unique_ptr (void) : _p (nullptr) {} + inline constexpr explicit unique_ptr (pointer p) : _p (p) {} + inline unique_ptr (unique_ptr&& p) : _p (p.release()) {} + unique_ptr(const unique_ptr&) = delete; + inline ~unique_ptr (void) { delete [] _p; } + inline constexpr pointer get (void) const { return _p; } + inline pointer release (void) { auto rv (_p); _p = nullptr; return rv; } + inline void reset (pointer p) { assert (p != _p); auto ov (_p); _p = p; delete [] ov; } + inline void swap (unique_ptr& v) { ::ustl::swap (_p, v._p); } + inline constexpr explicit operator bool (void) const { return _p != nullptr; } + inline unique_ptr& operator= (pointer p) { reset (p); return *this; } + inline unique_ptr& operator= (unique_ptr&& p) { reset (p.release()); return *this; } + unique_ptr& operator=(const unique_ptr&) = delete; + inline constexpr reference operator* (void) const { return *_p; } + inline constexpr pointer operator-> (void) const { return _p; } + inline constexpr reference operator[] (size_t i) const { return _p[i]; } + inline constexpr bool operator== (const pointer p) const { return _p == p; } + inline constexpr bool operator== (const unique_ptr& p) const { return _p == p._p; } + inline constexpr bool operator< (const unique_ptr& p) const { return _p < p._p; } +private: + pointer _p; +}; + +#if HAVE_CPP14 + +template struct __make_unique { using __single_object = unique_ptr; }; +template struct __make_unique { using __array = unique_ptr; }; +template struct __make_unique { struct __invalid_type {}; }; + +template +inline typename __make_unique::__single_object + make_unique (Args&&... args) { return unique_ptr (new T (forward(args)...)); } + +template +inline typename __make_unique::__array + make_unique (size_t n) { return unique_ptr (new remove_extent_t[n]()); } + +template +inline typename __make_unique::__invalid_type + make_unique (Args&&...) = delete; + +#endif // HAVE_CPP14 +#endif // HAVE_CPP11 + +//}}}------------------------------------------------------------------- +//{{{ shared_ptr + +#if HAVE_CPP11 + +/// \class shared_ptr memory.h stl.h +/// \ingroup MemoryManagement +/// \brief A smart pointer. +/// Calls delete in the destructor; assignment shares ownership. +template +class shared_ptr { +public: + using element_type = T; + using pointer = element_type*; + using reference = element_type&; +private: + struct container { + pointer p; + atomic refs; + inline constexpr explicit container (pointer np) : p(np),refs(1) {} + inline ~container (void) noexcept { assert (!refs); delete p; } + }; +public: + inline constexpr shared_ptr (void) : _p (nullptr) {} + inline explicit shared_ptr (pointer p) : _p (new container (p)) {} + inline shared_ptr (shared_ptr&& p) : _p (p._p) { p._p = nullptr; } + inline shared_ptr (const shared_ptr& p): _p (p._p) { if (_p) ++_p->refs; } + inline ~shared_ptr (void) { reset(); } + inline constexpr size_t use_count (void) const { return _p ? _p->refs.load() : 0; } + inline constexpr bool unique (void) const { return use_count() == 1; } + inline constexpr pointer get (void) const { return _p ? _p->p : nullptr; } + void reset (pointer p = nullptr) { + assert (p != get() || !p); + auto ov = _p; + _p = p ? new container(p) : nullptr; + if (ov && !--ov->refs) + delete ov; + } + inline void swap (shared_ptr& v) { ::ustl::swap (_p, v._p); } + inline constexpr explicit operator bool (void) const { return get(); } + inline shared_ptr& operator= (pointer p) { reset (p); return *this; } + inline shared_ptr& operator= (shared_ptr&& p) { swap (p); return *this; } + inline shared_ptr& operator= (const shared_ptr& p) { reset(); _p = p._p; if (_p) ++_p->refs; return *this; } + inline constexpr reference operator* (void) const { return *get(); } + inline constexpr pointer operator-> (void) const { return get(); } + inline constexpr reference operator[] (size_t i) const { return get()[i]; } + inline constexpr bool operator== (const pointer p) const { return get() == p; } + inline constexpr bool operator== (const shared_ptr& p) const { return get() == p.get(); } + inline constexpr bool operator< (const shared_ptr& p) const { return get() < p.get(); } +private: + container* _p; +}; + +#if HAVE_CPP14 + +template +inline auto make_shared (Args&&... args) + { return shared_ptr (new T (forward(args)...)); } + +#endif // HAVE_CPP14 + +//}}}------------------------------------------------------------------- +//{{{ scope_exit + +template +class scope_exit { +public: + inline explicit scope_exit (F&& f) noexcept : _f(move(f)),_enabled(true) {} + inline scope_exit (scope_exit&& f) noexcept : _f(move(f._f)),_enabled(f._enabled) { f.release(); } + inline void release (void) noexcept { _enabled = false; } + inline ~scope_exit (void) noexcept (noexcept (declval())) { if (_enabled) _f(); } + scope_exit (const scope_exit&) = delete; + scope_exit& operator= (const scope_exit&) = delete; + scope_exit& operator= (scope_exit&&) = delete; +private: + F _f; + bool _enabled; +}; + +#if HAVE_CPP14 +template +auto make_scope_exit (F&& f) noexcept + { return scope_exit>(forward(f)); } +#endif // HAVE_CPP14 + +//}}}------------------------------------------------------------------- +//{{{ unique_resource + +template +class unique_resource { +public: + inline explicit unique_resource (R&& resource, D&& deleter, bool enabled = true) noexcept + : _resource(move(resource)), _deleter(move(deleter)),_enabled(enabled) {} + inline unique_resource (unique_resource&& r) noexcept + : _resource(move(r._resource)),_deleter(move(r._deleter)),_enabled(r._enabled) { r.release(); } + unique_resource (const unique_resource&) = delete; + inline ~unique_resource() noexcept(noexcept(declval>().reset())) + { reset(); } + inline const D& get_deleter (void) const noexcept { return _deleter; } + inline R const& get (void) const noexcept { return _resource; } + inline R const& release (void) noexcept { _enabled = false; return get(); } + inline void reset (void) noexcept (noexcept(declval())) { + if (_enabled) { + _enabled = false; + get_deleter()(_resource); + } + } + inline void reset (R&& r) noexcept (noexcept(reset())) { + reset(); + _resource = move(r); + _enabled = true; + } + unique_resource& operator= (const unique_resource&) = delete; + unique_resource& operator= (unique_resource &&r) noexcept(noexcept(reset())) { + reset(); + _deleter = move(r._deleter); + _resource = move(r._resource); + _enabled = r._enabled; + r.release(); + return *this; + } + inline operator R const& (void) const noexcept { return get(); } + inline R operator-> (void) const noexcept { return _resource; } + inline add_lvalue_reference_t> + operator* (void) const { return *_resource; } +private: + R _resource; + D _deleter; + bool _enabled; +}; + +#if HAVE_CPP14 + +template +auto make_unique_resource (R&& r, D&& d) noexcept + { return unique_resource>(move(r), forward>(d), true); } + +template +auto make_unique_resource_checked (R r, R invalid, D d) noexcept +{ + bool shouldrun = !(r == invalid); + return unique_resource(move(r), move(d), shouldrun); +} + +#endif // HAVE_CPP14 +#endif // HAVE_CPP11 + +//}}}------------------------------------------------------------------- +//{{{ construct and destroy + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template +inline void construct_at (T* p) + { new (p) T; } + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template +inline void construct_at (T* p, const T& value) + { new (p) T (value); } + +#if HAVE_CPP11 +/// Calls the move placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template +inline void construct_at (T* p, T&& value) + { new (p) T (move(value)); } +#endif + +template +inline void construct (T* p) + { construct_at(p); } + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template +inline void uninitialized_default_construct (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits::value_type value_type; +#if HAVE_CPP11 + if (is_pod::value) +#else + if (numeric_limits::is_integral) +#endif + memset (reinterpret_cast(first), 0, max(distance(first,last),0)*sizeof(value_type)); + else + for (--last; intptr_t(first) <= intptr_t(last); ++first) + construct_at (&*first); +} +template +inline void uninitialized_default_construct_n (ForwardIterator first, size_t n) + { uninitialized_default_construct (first, first+n); } +template +inline void construct (ForwardIterator first, ForwardIterator last) + { uninitialized_default_construct (first, last); } + +/// Calls the placement new on \p [first,last) with iterator_traits::value_type() +template +inline void uninitialized_value_construct (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits::value_type value_type; + for (--last; intptr_t(first) <= intptr_t(last); ++first) + construct_at (&*first, value_type()); +} +template +inline void uninitialized_value_construct_n (ForwardIterator first, size_t n) + { uninitialized_value_construct (first, first+n); } + +/// Calls the destructor of \p p without calling delete. +/// \ingroup RawStorageAlgorithms +/// +template +inline void destroy_at (T* p) noexcept + { p->~T(); } + +template +inline void destroy (T* p) noexcept + { destroy_at(p); } + +// Helper templates to not instantiate anything for integral types. +namespace { + +template +void dtors (T first, T last) noexcept + { for (--last; intptr_t(first) <= intptr_t(last); ++first) destroy_at (&*first); } +template +struct Sdtorsr { + inline void operator()(T first, T last) noexcept { dtors (first, last); } +}; +template +struct Sdtorsr { + inline void operator()(T, T) noexcept {} +}; +} // namespace + +/// Calls the destructor on elements in range [first, last) without calling delete. +/// \ingroup RawStorageAlgorithms +/// +template +inline void destroy (ForwardIterator first, ForwardIterator last) noexcept +{ + typedef typename iterator_traits::value_type value_type; +#if HAVE_CPP11 + Sdtorsr::value>()(first, last); +#else + Sdtorsr::is_integral>()(first, last); +#endif +} +template +inline void destroy_n (ForwardIterator first, size_t n) noexcept + { destroy (first, first+n); } + +//}}}------------------------------------------------------------------- +//{{{ Raw storage algorithms + +//}}}------------------------------------------------------------------- +//{{{ Raw storage algorithms + +template inline T* cast_to_type (void* p, const T*) { return reinterpret_cast(p); } + +/// \brief Creates a temporary buffer pair from \p p and \p n +/// This is intended to be used with alloca to create temporary buffers. +/// The size in the returned pair is set to 0 if the allocation is unsuccessful. +/// \ingroup RawStorageAlgorithms +/// +template +inline pair make_temporary_buffer (void* p, size_t n, const T* ptype) +{ + return make_pair (cast_to_type(p,ptype), ptrdiff_t(p ? n : 0)); +} + +#if HAVE_ALLOCA_H + /// \brief Allocates a temporary buffer, if possible. + /// \ingroup RawStorageAlgorithms + #define get_temporary_buffer(size, ptype) make_temporary_buffer (alloca(size_of_elements(size, ptype)), size, ptype) + #define return_temporary_buffer(p) +#else + #define get_temporary_buffer(size, ptype) make_temporary_buffer (malloc(size_of_elements(size, ptype)), size, ptype) + #define return_temporary_buffer(p) if (p) free (p), p = nullptr +#endif + +/// Copies [first, last) into result by calling copy constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template +ForwardIterator uninitialized_copy (InputIterator first, InputIterator last, ForwardIterator result) +{ + for (; first < last; ++result, ++first) + construct_at (&*result, *first); + return result; +} + +/// Copies [first, first + n) into result by calling copy constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template +ForwardIterator uninitialized_copy_n (InputIterator first, size_t n, ForwardIterator result) +{ + for (++n; --n; ++result, ++first) + construct_at (&*result, *first); + return result; +} + +/// Calls construct on all elements in [first, last) with value \p v. +/// \ingroup RawStorageAlgorithms +/// +template +void uninitialized_fill (ForwardIterator first, ForwardIterator last, const T& v) +{ + for (; first < last; ++first) + construct_at (&*first, v); +} + +/// Calls construct on all elements in [first, first + n) with value \p v. +/// \ingroup RawStorageAlgorithms +/// +template +ForwardIterator uninitialized_fill_n (ForwardIterator first, size_t n, const T& v) +{ + for (++n; --n; ++first) + construct_at (&*first, v); + return first; +} + +#if HAVE_CPP11 + +/// Moves [first, last) into result by calling move constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template +ForwardIterator uninitialized_move (InputIterator first, InputIterator last, ForwardIterator result) +{ + for (; first < last; ++result, ++first) + construct_at (&*result, move(*first)); + return result; +} + +/// Moves [first, first + n) into result by calling move constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template +ForwardIterator uninitialized_move_n (InputIterator first, size_t n, ForwardIterator result) +{ + for (++n; --n; ++result, ++first) + construct_at (&*result, move(*first)); + return result; +} + +#endif // HAVE_CPP11 + +} // namespace ustl + +//}}}------------------------------------------------------------------- +//{{{ initializer_list +#if HAVE_CPP11 && WITHOUT_LIBSTDCPP + +namespace std { // Internal stuff must be in std:: + +/// Internal class for compiler support of C++11 initializer lists +template +class initializer_list { +public: + typedef T value_type; + typedef size_t size_type; + typedef const T& const_reference; + typedef const_reference reference; + typedef const T* const_iterator; + typedef const_iterator iterator; +private: + /// This object is only constructed by the compiler when the {1,2,3} + /// syntax is used, so the constructor must be private + inline constexpr initializer_list (const_iterator p, size_type sz) noexcept : _data(p), _size(sz) {} +public: + inline constexpr initializer_list (void)noexcept : _data(nullptr), _size(0) {} + inline constexpr size_type size (void) const noexcept { return _size; } + inline constexpr const_iterator begin() const noexcept { return _data; } + inline constexpr const_iterator end() const noexcept { return begin()+size(); } +private: + iterator _data; + size_type _size; +}; + +template +inline constexpr const T* begin (initializer_list il) noexcept { return il.begin(); } +template +inline constexpr const T* end (initializer_list il) noexcept { return il.end(); } + +} // namespace std + +#endif // HAVE_CPP11 +//}}}------------------------------------------------------------------- diff --git a/pwn/flipper/dist/common/include/ustl/umultimap.h b/pwn/flipper/dist/common/include/ustl/umultimap.h new file mode 100644 index 0000000..1d93c06 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/umultimap.h @@ -0,0 +1,96 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "umap.h" + +namespace ustl { + +/// \class multimap umultimap.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief A sorted associative container that may container multiple entries for each key. +/// +template > +class multimap : public vector > { +public: + typedef K key_type; + typedef V data_type; + typedef const K& const_key_ref; + typedef const V& const_data_ref; + typedef const multimap& rcself_t; + typedef vector > base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair const_range_t; + typedef pair range_t; + typedef Comp key_compare; + typedef pair_compare_first value_compare; + typedef pair_compare_first_key value_key_compare; +public: + inline multimap (void) : base_class() {} + explicit inline multimap (size_type n) : base_class (n) {} + inline multimap (rcself_t v) : base_class (v) {} + inline multimap (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; } + inline key_compare key_comp (void) const { return key_compare(); } + inline value_compare value_comp (void) const { return value_compare(); } + inline size_type size (void) const { return base_class::size(); } + inline iterator begin (void) { return base_class::begin(); } + inline const_iterator begin (void) const { return base_class::begin(); } + inline iterator end (void) { return base_class::end(); } + inline const_iterator end (void) const { return base_class::end(); } + inline const_iterator find (const_key_ref k) const; + inline iterator find (const_key_ref k) { return const_cast (const_cast(*this).find (k)); } + const_iterator lower_bound (const_key_ref k) const { return ::ustl::lower_bound (begin(), end(), k, value_key_compare()); } + inline iterator lower_bound (const_key_ref k) { return const_cast(const_cast(*this).lower_bound (k)); } + const_iterator upper_bound (const_key_ref k) const { return ::ustl::upper_bound (begin(), end(), k, value_key_compare()); } + inline iterator upper_bound (const_key_ref k) { return const_cast(const_cast(*this).upper_bound (k)); } + const_range_t equal_range (const_key_ref k) const { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); } + inline range_t equal_range (const_key_ref k) { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); } + inline size_type count (const_key_ref v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline void push_back (const_reference v) { insert (v); } + inline iterator insert (const_reference v) { return base_class::insert (upper_bound (v.first), v); } + void insert (const_iterator i1, const_iterator i2) { for (; i1 != i2; ++i1) insert (*i1); } + inline void clear (void) { base_class::clear(); } + inline void erase (const_key_ref k) { erase (const_cast(lower_bound(k)), const_cast(upper_bound(k))); } + inline iterator erase (const_iterator ep) { return base_class::erase (ep); } + inline iterator erase (const_iterator ep1, const_iterator ep2) { return base_class::erase (ep1, ep2); } + inline void swap (multimap& v) { base_class::swap (v); } +#if HAVE_CPP11 + using initlist_t = std::initializer_list; + inline multimap (multimap&& v) : base_class (move(v)) {} + inline multimap (initlist_t v) : base_class() { insert (v.begin(), v.end()); } + inline multimap& operator= (multimap&& v) { base_class::operator= (move(v)); return *this; } + iterator insert (value_type&& v) { return base_class::insert (upper_bound (v.first), move(v)); } + inline iterator insert (const_iterator, value_type&& v) { return insert(move(v)); } + inline void insert (initlist_t v) { insert (v.begin(), v.end()); } + template + inline iterator emplace (Args&&... args) { return insert (value_type(forward(args)...)); } + template + inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, value_type(forward(args)...)); } + template + inline iterator emplace_back (Args&&... args) { return insert (value_type(forward(args)...)); } +#endif +}; + +/// Returns the pair where K = \p k. +template +inline typename multimap::const_iterator multimap::find (const_key_ref k) const +{ + const_iterator i = lower_bound (k); + return (i < end() && Comp()(k, i->first)) ? end() : i; +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/umultiset.h b/pwn/flipper/dist/common/include/ustl/umultiset.h new file mode 100644 index 0000000..b8e0272 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/umultiset.h @@ -0,0 +1,86 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" +#include "ualgo.h" + +namespace ustl { + +/// \class multiset umultiset.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief Multiple sorted container. +/// Unlike set, it may contain multiple copies of each element. +/// +template > +class multiset : public vector { +public: + typedef const multiset& rcself_t; + typedef vector base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair range_t; + typedef pair const_range_t; +public: + inline multiset (void) : base_class() {} + inline explicit multiset (size_type n) : base_class (n) {} + inline explicit multiset (rcself_t v) : base_class (v) {} + inline multiset (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; } + inline size_type size (void) const { return base_class::size(); } + inline iterator begin (void) { return base_class::begin(); } + inline const_iterator begin (void) const { return base_class::begin(); } + inline const_iterator cbegin (void) const { return base_class::cbegin(); } + inline iterator end (void) { return base_class::end(); } + inline const_iterator end (void) const { return base_class::end(); } + inline const_iterator cend (void) const { return base_class::cend(); } + inline Comp value_comp (void) const { return Comp(); } + inline Comp key_comp (void) const { return value_comp(); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline const_iterator find (const_reference v) const { const_iterator i = ::ustl::lower_bound (begin(), end(), v, Comp()); return (i != end() && *i == v) ? i : end(); } + inline iterator find (const_reference v) { return const_cast(const_cast(*this).find (v)); } + inline const_iterator lower_bound (const_reference v) const { return ::ustl::lower_bound (begin(), end(), v, Comp()); } + inline iterator lower_bound (const_reference v) { return const_cast(const_cast(*this).lower_bound (v)); } + inline const_iterator upper_bound (const_reference v) const { return ::ustl::upper_bound (begin(), end(), v, Comp()); } + inline iterator upper_bound (const_reference v) { return const_cast(const_cast(*this).upper_bound (v)); } + inline const_range_t equal_range (const_reference v) const { return ::ustl::equal_range (begin(), end(), v, Comp()); } + inline range_t equal_range (const_reference v) { return ::ustl::equal_range (begin(), end(), v, Comp()); } + inline size_type count (const_reference v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); } + inline void push_back (const_reference v) { insert (v); } + inline iterator insert (const_reference v) { return base_class::insert (upper_bound(v), v); } + inline iterator insert (const_iterator, const_reference v) { return insert(v); } + void insert (const_iterator i1, const_iterator i2) { for (; i1 < i2; ++i1) insert (*i1); } + inline iterator erase (const_iterator ep) { return base_class::erase (ep); } + inline iterator erase (const_iterator ep1, const_iterator ep2) { return base_class::erase (ep1, ep2); } + inline size_type erase (const_reference v) { range_t epr = equal_range (v); erase (epr.first, epr.second); return distance(epr.first, epr.second); } + inline void clear (void) { base_class::clear(); } + inline void swap (multiset& v) { base_class::swap (v); } +#if HAVE_CPP11 + using initlist_t = std::initializer_list; + inline explicit multiset (multiset&& v) : base_class (move(v)) {} + inline multiset (initlist_t v) : base_class() { insert (v.begin(), v.end()); } + inline multiset& operator= (multiset&& v) { base_class::operator= (move(v)); return *this; } + inline iterator insert (T&& v) { return base_class::insert (upper_bound(v), move(v)); } + inline iterator insert (const_iterator, T&& v) { return insert (move(v)); } + inline void insert (initlist_t v) { insert (v.begin(), v.end()); } + template + inline iterator emplace (Args&&... args) { return insert (T(forward(args)...)); } + template + inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, T(forward(args)...)); } + template + inline iterator emplace_back (Args&&... args) { return insert (T(forward(args)...)); } +#endif +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/unew.h b/pwn/flipper/dist/common/include/ustl/unew.h new file mode 100644 index 0000000..7ccd4b3 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/unew.h @@ -0,0 +1 @@ +#include diff --git a/pwn/flipper/dist/common/include/ustl/unumeric.h b/pwn/flipper/dist/common/include/ustl/unumeric.h new file mode 100644 index 0000000..dec0ae8 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/unumeric.h @@ -0,0 +1,151 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once + +namespace ustl { + +/// Returns the sum of all elements in [first, last) added to \p init. +/// \ingroup NumericAlgorithms +/// +template +inline T accumulate (InputIterator first, InputIterator last, T init) +{ + while (first < last) + init += *first++; + return init; +} + +/// Returns the sum of all elements in [first, last) via \p op, added to \p init. +/// \ingroup NumericAlgorithms +/// +template +inline T accumulate (InputIterator first, InputIterator last, T init, BinaryFunction binary_op) +{ + while (first < last) + init = binary_op (init, *first++); + return init; +} + +/// Assigns range [value, value + (last - first)) to [first, last) +/// \ingroup NumericAlgorithms +/// +template +inline void iota (ForwardIterator first, ForwardIterator last, T value) +{ + while (first < last) + *first++ = value++; +} + +/// Returns the sum of products of respective elements in the given ranges. +/// \ingroup NumericAlgorithms +/// +template +inline T inner_product (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) +{ + while (first1 < last1) + init += *first1++ * *first2++; + return init; +} + +/// Returns the sum of products of respective elements in the given ranges. +/// \ingroup NumericAlgorithms +/// +template +inline T inner_product +(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, + BinaryOperation1 sumOp, BinaryOperation2 productOp) +{ + while (first1 < last1) + init = sumOp (init, productOp (*first1++, *first2++)); + return init; +} + +/// Writes result such that result[i] = sum (first...first+i) +/// \ingroup NumericAlgorithms +/// +template +inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first < last) + *result = *first++; + while (first < last) + *++result = *first++ + *result; + return result; +} + +/// Writes result such that result[i] = sumOp (first...first+i) +/// \ingroup NumericAlgorithms +/// +template +inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation sumOp) +{ + if (first < last) + *result = *first++; + while (first < last) + *++result = sumOp (*first++, *result); + return result; +} + +/// Writes result such that result[i] = first[i] - first[i - 1] +/// \ingroup NumericAlgorithms +/// +template +inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first < last) + *result++ = *first++; + while (first < last) + *result++ = *first - *(first - 1); + return result; +} + +/// Writes result such that result[i] = differenceOp (first[i], first[i - 1]) +/// \ingroup NumericAlgorithms +/// +template +inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation differenceOp) +{ + if (first < last) + *result++ = *first++; + while (first < last) + *result++ = differenceOp (*first, *(first - 1)); + return result; +} + +/// \brief Returns x^n. +/// Donald Knuth's Russian Peasant algorithm. +/// \ingroup NumericAlgorithms +/// +template +inline T power (T x, unsigned n) +{ + T result (n % 2 ? x : 1); + while (n /= 2) { + x *= x; + if (n % 2) + result *= x; + } + return result; +} + +/// \brief Returns x^n, using \p op instead of multiplication. +/// Donald Knuth's Russian Peasant algorithm. +/// \ingroup NumericAlgorithms +/// +template +inline T power (T x, unsigned n, BinaryOperation op) +{ + T result (n % 2 ? x : 1); + while (n /= 2) { + x = op (x, x); + if (n % 2) + result = op (result, x); + } + return result; +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/upair.h b/pwn/flipper/dist/common/include/ustl/upair.h new file mode 100644 index 0000000..a61e240 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/upair.h @@ -0,0 +1,73 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ualgobase.h" + +namespace ustl { + +class istream; +class ostream; +class ostringstream; + +/// \class pair upair.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief Container for two values. +/// +template +class pair { +public: + typedef T1 first_type; + typedef T2 second_type; +public: + /// Default constructor. + inline constexpr pair (void) : first (T1()), second (T2()) {} + /// Initializes members with \p a, and \p b. + inline pair (const T1& a, const T2& b) : first (a), second (b) {} + template + inline pair (const pair& p2) : first (p2.first), second (p2.second) {} + inline pair& operator= (const pair& p2) { first = p2.first; second = p2.second; return *this; } + template + inline pair& operator= (const pair& p2) { first = p2.first; second = p2.second; return *this; } + inline bool operator== (const pair& v)const { return first == v.first && second == v.second; } + inline bool operator< (const pair& v) const { return first < v.first || (first == v.first && second < v.second); } + inline void swap (pair& v) { ::ustl::swap(first,v.first); ::ustl::swap(second,v.second); } + inline void read (istream& is); + inline void write (ostream& os) const; + void text_write (ostringstream& os) const; + inline size_t stream_size (void) const; +#if HAVE_CPP11 + pair (const pair&) = default; + pair (pair&&) = default; + template + inline pair (T3&& a, T4&& b) : first (forward(a)), second (forward(b)) {} + template + inline pair (pair&& p2) : first (forward(p2.first)), second (forward(p2.second)) {} + inline pair& operator= (pair&& p2) { first = move(p2.first); second = move(p2.second); return *this; } + template + inline pair& operator= (pair&& p2) { first = forward(p2.first); second = forward(p2.second); return *this; } + inline void swap (pair&& v) { ::ustl::swap(first,v.first); ::ustl::swap(second,v.second); } +#endif +public: + first_type first; + second_type second; +}; + +#if HAVE_CPP11 + +/// Returns a pair object with (a,b) +template +inline constexpr pair make_pair (T1&& a, T2&& b) + { return pair (forward(a), forward(b)); } + +#endif + +/// Returns a pair object with (a,b) +template +inline constexpr pair make_pair (const T1& a, const T2& b) + { return pair (a, b); } + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/upredalgo.h b/pwn/flipper/dist/common/include/ustl/upredalgo.h new file mode 100644 index 0000000..13b4ed4 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/upredalgo.h @@ -0,0 +1,585 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ualgo.h" + +namespace ustl { + +/// Copy_if copies elements from the range [first, last) to the range +/// [result, result + (last - first)) if pred(*i) returns true. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred) +{ + for (; first != last; ++first) { + if (pred(*first)) { + *result = *first; + ++ result; + } + } + return result; +} + +/// Returns the first iterator i in the range [first, last) such that +/// pred(*i) is true. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline InputIterator find_if (InputIterator first, InputIterator last, Predicate pred) +{ + while (first != last && !pred (*first)) + ++ first; + return first; +} + +/// Returns the first iterator such that p(*i, *(i + 1)) == true. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline ForwardIterator adjacent_find (ForwardIterator first, ForwardIterator last, BinaryPredicate p) +{ + if (first != last) + for (ForwardIterator prev = first; ++first != last; ++ prev) + if (p (*prev, *first)) + return prev; + return last; +} + +/// Returns the pointer to the first pair of unequal elements. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline pair +mismatch (InputIterator first1, InputIterator last1, InputIterator first2, BinaryPredicate comp) +{ + while (first1 != last1 && comp(*first1, *first2)) + ++ first1, ++ first2; + return make_pair (first1, first2); +} + +/// Returns true if two ranges are equal. +/// This is an extension, present in uSTL and SGI STL. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline bool equal (InputIterator first1, InputIterator last1, InputIterator first2, BinaryPredicate comp) +{ + return mismatch (first1, last1, first2, comp).first == last1; +} + +/// Count_if finds the number of elements in [first, last) that satisfy the +/// predicate pred. More precisely, the first version of count_if returns the +/// number of iterators i in [first, last) such that pred(*i) is true. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline size_t count_if (InputIterator first, InputIterator last, Predicate pred) +{ + size_t total = 0; + for (; first != last; ++first) + if (pred (*first)) + ++ total; + return total; +} + +/// Replace_if replaces every element in the range [first, last) for which +/// pred returns true with new_value. That is: for every iterator i, if +/// pred(*i) is true then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline void replace_if (ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value) +{ + for (; first != last; ++first) + if (pred (*first)) + *first = new_value; +} + +/// Replace_copy_if copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element for which pred is +/// true is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy_if performs the +/// assignment *(result+n) = new_value if pred(*(first+n)), +/// and *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator replace_copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred, const T& new_value) +{ + for (; first != last; ++result, ++first) + *result = pred(*first) ? new_value : *first; +} + +/// Remove_copy_if copies elements from the range [first, last) to a range +/// beginning at result, except that elements for which pred is true are not +/// copied. The return value is the end of the resulting range. This operation +/// is stable, meaning that the relative order of the elements that are copied +/// is the same as in the range [first, last). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline OutputIterator remove_copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred) +{ + for (; first != last; ++first) + if (!pred (*first)) + *result++ = *first; + return result; +} + +/// Remove_if removes from the range [first, last) every element x such that +/// pred(x) is true. That is, remove_if returns an iterator new_last such that +/// the range [first, new_last) contains no elements for which pred is true. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Remove_if is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline ForwardIterator remove_if (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + return remove_copy_if (first, last, first, pred); +} + +/// The reason there are two different versions of unique_copy is that there +/// are two different definitions of what it means for a consecutive group of +/// elements to be duplicates. In the first version, the test is simple +/// equality: the elements in a range [f, l) are duplicates if, for every +/// iterator i in the range, either i == f or else *i == *(i-1). In the second, +/// the test is an arbitrary Binary Predicate binary_pred: the elements in +/// [f, l) are duplicates if, for every iterator i in the range, either +/// i == f or else binary_pred(*i, *(i-1)) is true. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate binary_pred) +{ + if (first != last) { + *result = *first; + while (++first != last) + if (!binary_pred (*first, *result)) + *++result = *first; + ++ result; + } + return result; +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline ForwardIterator unique (ForwardIterator first, ForwardIterator last, BinaryPredicate binary_pred) +{ + return unique_copy (first, last, first, binary_pred); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), comp(*j, value) is true. +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, size_t(distance (first,last)) / 2); + if (comp (*mid, value)) + first = mid + 1; + else + last = mid; + } + return first; +} + +/// Performs a binary search inside the sorted range. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline bool binary_search (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator found = lower_bound (first, last, value, comp); + return found != last && !comp(*found, value); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), comp(value,*j) is false. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, size_t(distance (first,last)) / 2); + if (comp (value, *mid)) + last = mid; + else + first = mid + 1; + } + return last; +} + +/// Returns pair +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline pair equal_range (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + pair rv; + rv.second = rv.first = lower_bound (first, last, value, comp); + while (rv.second != last && !comp(value, *(rv.second))) + ++ rv.second; + return rv; +} + +/// \brief Puts \p nth element into its sorted position. +/// In this implementation, the entire array is sorted. The performance difference is +/// so small and the function use is so rare, there is no need to have code for it. +/// \ingroup SortingAlgorithms +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template +inline void nth_element (RandomAccessIterator first, RandomAccessIterator, RandomAccessIterator last, Compare comp) +{ + sort (first, last, comp); +} + +/// \brief Searches for the first subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate comp) +{ + const ForwardIterator1 slast = last1 - distance(first2, last2) + 1; + for (; first1 < slast; ++first1) { + ForwardIterator2 i = first2; + ForwardIterator1 j = first1; + for (; i != last2 && comp(*j, *i); ++i, ++j) ; + if (i == last2) + return first1; + } + return last1; +} + +/// \brief Searches for the last subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate comp) +{ + ForwardIterator1 s = last1 - distance(first2, last2); + for (; first1 < s; --s) { + ForwardIterator2 i = first2, j = s; + for (; i != last2 && comp(*j, *i); ++i, ++j) ; + if (i == last2) + return s; + } + return last1; +} + +/// \brief Searches for the first occurence of \p count \p values in [first, last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +Iterator search_n (Iterator first, Iterator last, size_t count, const T& value, BinaryPredicate comp) +{ + size_t n = 0; + for (; first != last; ++first) { + if (!comp (*first, value)) + n = 0; + else if (++n == count) + return first - --n; + } + return last; +} + +/// \brief Searches [first1,last1) for the first occurrence of an element from [first2,last2) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +InputIterator find_first_of (InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2, BinaryPredicate comp) +{ + for (; first1 != last1; ++first1) + for (ForwardIterator i = first2; i != last2; ++i) + if (comp (*first1, *i)) + return first1; + return first1; +} + +/// \brief Returns true if [first2,last2) is a subset of [first1,last1) +/// \ingroup ConditionAlgorithms +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template +bool includes (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, StrictWeakOrdering comp) +{ + for (; (first1 != last1) & (first2 != last2); ++first1) { + if (comp (*first2, *first1)) + return false; + first2 += !comp (*first1, *first2); + } + return first2 == last2; +} + +/// \brief Merges [first1,last1) with [first2,last2) +/// +/// Result will contain every element that is in either set. If duplicate +/// elements are present, max(n,m) is placed in the result. +/// +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template +OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + for (; (first1 != last1) & (first2 != last2); ++result) { + if (comp (*first2, *first1)) + *result = *first2++; + else { + first2 += !comp (*first1, *first2); + *result = *first1++; + } + } + return copy (first2, last2, copy (first1, last1, result)); +} + +/// \brief Creates a set containing elements shared by the given ranges. +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template +OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1ge2 = !comp (*first1, *first2), b2ge1 = !comp (*first2, *first1); + if (b1ge2 & b2ge1) + *result++ = *first1; + first1 += b2ge1; + first2 += b1ge2; + } + return result; +} + +/// \brief Removes from [first1,last1) elements present in [first2,last2) +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template +OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1ge2 = !comp (*first1, *first2), b2ge1 = !comp (*first2, *first1); + if (!b1ge2) + *result++ = *first1; + first1 += b2ge1; + first2 += b1ge2; + } + return copy (first1, last1, result); +} + +/// \brief Performs union of sets A-B and B-A. +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template +OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1l2 = comp (*first1, *first2), b2l1 = comp (*first2, *first1); + if (b1l2) + *result++ = *first1; + else if (b2l1) + *result++ = *first2; + first1 += !b2l1; + first2 += !b1l2; + } + return copy (first2, last2, copy (first1, last1, result)); +} + +/// \brief Returns true if the given range is sorted. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +template +bool is_sorted (ForwardIterator first, ForwardIterator last, StrictWeakOrdering comp) +{ + for (ForwardIterator i = first; ++i < last; ++first) + if (comp (*i, *first)) + return false; + return true; +} + +/// \brief Compares two given containers like strcmp compares strings. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +template +bool lexicographical_compare (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, BinaryPredicate comp) +{ + for (; (first1 != last1) & (first2 != last2); ++first1, ++first2) { + if (comp (*first1, *first2)) + return true; + if (comp (*first2, *first1)) + return false; + } + return (first1 == last1) & (first2 != last2); +} + +/// \brief Creates the next lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +template +bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering comp) +{ + if (distance (first, last) < 2) + return false; + BidirectionalIterator i = last; + for (--i; i != first; ) { + --i; + if (comp (i[0], i[1])) { + BidirectionalIterator j = last; + while (!comp (*i, *--j)) ; + iter_swap (i, j); + reverse (i + 1, last); + return true; + } + } + reverse (first, last); + return false; +} + +/// \brief Creates the previous lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +template +bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering comp) +{ + if (distance (first, last) < 2) + return false; + BidirectionalIterator i = last; + for (--i; i != first; ) { + --i; + if (comp(i[1], i[0])) { + BidirectionalIterator j = last; + while (!comp (*--j, *i)) ; + iter_swap (i, j); + reverse (i + 1, last); + return true; + } + } + reverse (first, last); + return false; +} + +/// \brief Returns iterator to the max element in [first,last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +inline ForwardIterator max_element (ForwardIterator first, ForwardIterator last, BinaryPredicate comp) +{ + ForwardIterator result = first; + for (; first != last; ++first) + if (comp (*result, *first)) + result = first; + return result; +} + +/// \brief Returns iterator to the min element in [first,last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template +inline ForwardIterator min_element (ForwardIterator first, ForwardIterator last, BinaryPredicate comp) +{ + ForwardIterator result = first; + for (; first != last; ++first) + if (comp (*first, *result)) + result = first; + return result; +} + +/// \brief Makes [first,middle) a part of the sorted array. +/// Contents of [middle,last) is undefined. This implementation just calls stable_sort. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template +inline void partial_sort (RandomAccessIterator first, RandomAccessIterator, RandomAccessIterator last, StrictWeakOrdering comp) +{ + stable_sort (first, last, comp); +} + +/// \brief Like partial_sort, but outputs to [result_first,result_last) +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template +RandomAccessIterator partial_sort_copy (InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last, StrictWeakOrdering comp) +{ + RandomAccessIterator rend = result_first; + for (; first != last; ++first) { + RandomAccessIterator i = result_first; + for (; i != rend && comp (*i, *first); ++i) ; + if (i == result_last) + continue; + rend += (rend < result_last); + copy_backward (i, rend - 1, rend); + *i = *first; + } + return rend; +} + +/// \brief Like partition, but preserves equal element order. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template +ForwardIterator stable_partition (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + if (first == last) + return first; + ForwardIterator l, r, m = advance (first, distance (first, last) / 2); + if (first == m) + return pred(*first) ? last : first; + l = stable_partition (first, m, pred); + r = stable_partition (m, last, pred); + rotate (l, m, r); + return advance (l, distance (m, r)); +} + +/// \brief Splits [first,last) in two by \p pred. +/// +/// Creates two ranges [first,middle) and [middle,last), where every element +/// in the former is less than every element in the latter. +/// The return value is middle. +/// +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template +inline ForwardIterator partition (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + return stable_partition (first, last, pred); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uqueue.h b/pwn/flipper/dist/common/include/ustl/uqueue.h new file mode 100644 index 0000000..655ced2 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uqueue.h @@ -0,0 +1,57 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" + +namespace ustl { + +/// \class queue uqueue.h ustl.h +/// \ingroup Sequences +/// +/// Queue adapter to uSTL containers. +/// +template > +class queue { +public: + typedef T value_type; + typedef Container container_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::difference_type difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; +public: + inline queue (void) : _storage(), _front (0) { } + explicit inline queue (const container_type& s) : _storage (s), _front (0) { } + explicit inline queue (const queue& s) : _storage (s._storage), _front (0) { } + inline size_type size (void) const { return _storage.size() - _front; } + inline bool empty (void) const { return !size(); } + inline reference front (void) { return _storage [_front]; } + inline const_reference front (void) const { return _storage [_front]; } + inline reference back (void) { return _storage.back(); } + inline const_reference back (void) const { return _storage.back(); } + inline void push (const_reference v) { _storage.push_back (v); } + void pop (void) { + if (++_front > _storage.size()/2) { + _storage.erase (_storage.begin(), _front); + _front = 0; + } + } + inline void swap (queue& v) { _storage.swap (v); swap (_front, v._front); } + inline bool operator== (const queue& s) const { return _storage == s._storage && _front == s._front; } + inline bool operator< (const queue& s) const { return size() < s.size(); } +#if HAVE_CPP11 + inline queue (queue&& v) : _storage(move(v._storage)),_front(v._front) { v._front = 0; } + inline queue (container_type&& s) : _storage(move(s)),_front(0) {} + inline queue& operator= (queue&& v) { swap (v); return *this; } + template + inline void emplace (Args&&... args) { _storage.emplace_back (forward(args)...); } +#endif +private: + container_type _storage; ///< Where the data actually is. + size_type _front; ///< Index of the element returned by next pop. +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uset.h b/pwn/flipper/dist/common/include/ustl/uset.h new file mode 100644 index 0000000..51220d4 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uset.h @@ -0,0 +1,112 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" + +namespace ustl { + +/// \class set uset.h ustl.h +/// \ingroup Sequences +/// +/// \brief Unique sorted container. Sorted vector with all values unique. +/// +template > +class set : public vector { +public: + typedef const set& rcself_t; + typedef vector base_class; + typedef typename base_class::value_type key_type; + typedef typename base_class::value_type data_type; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair insertrv_t; + typedef pair range_t; + typedef pair const_range_t; +public: + inline set (void) : base_class() { } + explicit inline set (size_type n) : base_class (n) { } + inline set (rcself_t v) : base_class (v) { } + inline set (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; } + inline size_type size (void) const { return base_class::size(); } + inline iterator begin (void) { return base_class::begin(); } + inline const_iterator begin (void) const { return base_class::begin(); } + inline const_iterator cbegin (void) const { return base_class::cbegin(); } + inline iterator end (void) { return base_class::end(); } + inline const_iterator end (void) const { return base_class::end(); } + inline const_iterator cend (void) const { return base_class::cend(); } + inline const_iterator find (const_reference v) const { const_iterator i = ::ustl::lower_bound (begin(), end(), v, Comp()); return (i != end() && *i == v) ? i : end(); } + inline iterator find (const_reference v) { return const_cast(const_cast(*this).find (v)); } + inline const_iterator lower_bound (const_reference v) const { return ::ustl::lower_bound (begin(), end(), v, Comp()); } + inline iterator lower_bound (const_reference v) { return const_cast(const_cast(*this).lower_bound (v)); } + inline const_iterator upper_bound (const_reference v) const { return ::ustl::upper_bound (begin(), end(), v, Comp()); } + inline iterator upper_bound (const_reference v) { return const_cast(const_cast(*this).upper_bound (v)); } + inline const_range_t equal_range (const_reference v) const { return ::ustl::equal_range (begin(), end(), v, Comp()); } + inline range_t equal_range (const_reference v) { return ::ustl::equal_range (begin(), end(), v, Comp()); } + inline size_type count (const_reference v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); } + inline Comp value_comp (void) const { return Comp(); } + inline Comp key_comp (void) const { return value_comp(); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline void push_back (const_reference v) { insert (v); } + insertrv_t insert (const_reference v); + inline iterator insert (const_iterator, const_reference v) { return insert(v).first; } + inline void insert (const_iterator i1, const_iterator i2) { for (; i1 < i2; ++i1) insert (*i1); } + inline void erase (const_reference v) { iterator ip = find (v); if (ip != end()) erase (ip); } + inline iterator erase (iterator ep) { return base_class::erase (ep); } + inline iterator erase (iterator ep1, iterator ep2) { return base_class::erase (ep1, ep2); } + inline void clear (void) { base_class::clear(); } + inline void swap (set& v) { base_class::swap (v); } +#if HAVE_CPP11 + using initlist_t = std::initializer_list; + inline set (set&& v) : base_class (move(v)) {} + inline set (initlist_t v) : base_class() { insert (v.begin(), v.end()); } + inline set& operator= (set&& v) { base_class::operator= (move(v)); return *this; } + insertrv_t insert (T&& v); + inline iterator insert (const_iterator, T&& v) { return insert (move(v)); } + inline void insert (initlist_t v) { insert (v.begin(), v.end()); } + template + inline insertrv_t emplace (Args&&... args) { return insert (T(forward(args)...)); } + template + inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, T(forward(args)...)); } + template + inline insertrv_t emplace_back (Args&&... args) { return insert (T(forward(args)...)); } +#endif +}; + +#if HAVE_CPP11 + +template +typename set::insertrv_t set::insert (T&& v) +{ + iterator ip = lower_bound (v); + bool bInserted = (ip == end() || Comp()(v,*ip)); + if (bInserted) + ip = base_class::insert (ip, move(v)); + return make_pair (ip, bInserted); +} + +#endif + +/// Inserts \p v into the container, maintaining the sort order. +template +typename set::insertrv_t set::insert (const_reference v) +{ + iterator ip = lower_bound (v); + bool bInserted = (ip == end() || Comp()(v,*ip)); + if (bInserted) + ip = base_class::insert (ip, v); + return make_pair (ip, bInserted); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uspecial.h b/pwn/flipper/dist/common/include/ustl/uspecial.h new file mode 100644 index 0000000..b24c5fe --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uspecial.h @@ -0,0 +1,237 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "uvector.h" +#include "ustring.h" +#include "uset.h" +#include "umultiset.h" +#include "ubitset.h" +#include "ulaalgo.h" +#include "uarray.h" +#include "uctralgo.h" +#include "ufunction.h" +#include "uctrstrm.h" +#include "sistream.h" +#include "uchrono.h" + +namespace ustl { + +//---------------------------------------------------------------------- +// Alogrithm specializations not in use by the library code. +//---------------------------------------------------------------------- + +template <> inline void swap (cmemlink& a, cmemlink& b) { a.swap (b); } +template <> inline void swap (memlink& a, memlink& b) { a.swap (b); } +template <> inline void swap (memblock& a, memblock& b) { a.swap (b); } +template <> inline void swap (string& a, string& b) { a.swap (b); } +#define TEMPLATE_SWAP_PSPEC(type, template_decl) \ +template_decl inline void swap (type& a, type& b) { a.swap (b); } +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (vector,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (set,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (multiset,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE2 (tuple,N,T), TEMPLATE_FULL_DECL2 (size_t,N,typename,T)) + +//---------------------------------------------------------------------- +// Streamable definitions. Not used in the library and require streams. +//---------------------------------------------------------------------- + +//----{ pair }---------------------------------------------------------- + +/// \brief Reads pair \p p from stream \p is. +template +void pair::read (istream& is) +{ + is >> first; + is.align (stream_align_of(second)); + is >> second; + is.align (stream_align_of(first)); +} + +/// Writes pair \p p to stream \p os. +template +void pair::write (ostream& os) const +{ + os << first; + os.align (stream_align_of(second)); + os << second; + os.align (stream_align_of(first)); +} + +/// Returns the written size of the object. +template +size_t pair::stream_size (void) const +{ + return Align (stream_size_of(first), stream_align_of(second)) + + Align (stream_size_of(second), stream_align_of(first)); +} + +/// Writes pair \p p to stream \p os. +template +void pair::text_write (ostringstream& os) const +{ + os << '(' << first << ',' << second << ')'; +} + +/// \brief Takes a pair and returns pair.first +/// This is an extension, available in uSTL and the SGI STL. +template struct select1st : public unary_function { + typedef typename Pair::first_type result_type; + inline const result_type& operator()(const Pair& a) const { return a.first; } + inline result_type& operator()(Pair& a) const { return a.first; } +}; + +/// \brief Takes a pair and returns pair.second +/// This is an extension, available in uSTL and the SGI STL. +template struct select2nd : public unary_function { + typedef typename Pair::second_type result_type; + inline const result_type& operator()(const Pair& a) const { return a.second; } + inline result_type& operator()(Pair& a) const { return a.second; } +}; + +/// \brief Converts a const_iterator pair into an iterator pair +/// Useful for converting pair ranges returned by equal_range, for instance. +/// This is an extension, available in uSTL. +template +inline pair +unconst (const pair& i, Container&) +{ + typedef pair unconst_pair_t; + return *noalias_cast(&i); +} + +//----{ vector }-------------------------------------------------------- + +template +inline size_t stream_align_of (const vector&) +{ + typedef typename vector::written_size_type written_size_type; + return stream_align_of (written_size_type()); +} + +//----{ bitset }-------------------------------------------------------- + +/// Writes bitset \p v into stream \p os. +template +void bitset::text_read (istringstream& is) +{ + char c; + for (int i = Size; --i >= 0 && (is >> c).good();) + set (i, c == '1'); +} + +//----{ tuple }--------------------------------------------------------- + +template +struct numeric_limits > { + typedef numeric_limits value_limits; + static inline tuple min (void) { tuple v; fill (v, value_limits::min()); return v; } + static inline tuple max (void) { tuple v; fill (v, value_limits::max()); return v; } + static const bool is_signed = value_limits::is_signed; + static const bool is_integer = value_limits::is_integer; + static const bool is_integral = value_limits::is_integral; +}; + +template +inline size_t stream_align_of (const tuple&) { return stream_align_of (NullValue()); } + +template +inline ostringstream& chartype_text_write (ostringstream& os, const T& v) +{ + os.format (_FmtPrtChr[!isprint(v)], v); + return os; +} + +template <> +inline ostringstream& container_element_text_write (ostringstream& os, const uint8_t& v) +{ return chartype_text_write (os, v); } +template <> +inline ostringstream& container_element_text_write (ostringstream& os, const int8_t& v) +{ return chartype_text_write (os, v); } + +//----{ matrix }-------------------------------------------------------- + +/// Writes matrix \p v into stream \p os. +template +void matrix::text_write (ostringstream& os) const +{ + os << '('; + for (uoff_t iRow = 0; iRow < NY; ++ iRow) { + os << '('; + for (uoff_t iColumn = 0; iColumn < NX; ++iColumn) + os << at(iRow)[iColumn] << ",)"[iColumn == NX-1]; + } + os << ')'; +} + +//----{ long4grain }---------------------------------------------------- + +#if SIZE_OF_LONG == 8 && HAVE_INT64_T +// Helper class for long4grain and ptr4grain wrappers. +class _long4grain { +public: + inline _long4grain (uint64_t v) : _v (v) {} +#if __x86_64__ + inline void read (istream& is) + { + assert (is.aligned(4)); + #if WANT_STREAM_BOUNDS_CHECKING + if (!is.verify_remaining ("read", "long4grain", sizeof(_v))) return; + #else + assert (is.remaining() >= sizeof(_v)); + #endif + _v = *reinterpret_cast(is.ipos()); + is.skip (sizeof(_v)); + } + inline void write (ostream& os) const + { + assert (os.aligned(4)); + #if WANT_STREAM_BOUNDS_CHECKING + if (!os.verify_remaining ("write", "long4grain", sizeof(_v))) return; + #else + assert (os.remaining() >= sizeof(_v)); + #endif + *reinterpret_cast(os.ipos()) = _v; + os.skip (sizeof(_v)); + } +#elif USTL_BYTE_ORDER == USTL_BIG_ENDIAN + inline void read (istream& is) { uint32_t vl, vh; is >> vh >> vl; _v = (uint64_t(vh) << 32) | uint64_t(vl); } + inline void write (ostream& os) const { os << uint32_t(_v >> 32) << uint32_t(_v); } +#else + inline void read (istream& is) { uint32_t vl, vh; is >> vl >> vh; _v = (uint64_t(vh) << 32) | uint64_t(vl); } + inline void write (ostream& os) const { os << uint32_t(_v) << uint32_t(_v >> 32); } +#endif + inline size_t stream_size (void) const { return stream_size_of(_v); } +private: + uint64_t _v; +}; + +/// Wrap long values to allow writing them on 4-grain even on 64bit platforms. +inline _long4grain& long4grain (unsigned long& v) { asm("":"+m"(v)); return *noalias_cast<_long4grain*>(&v); } +/// Wrap long values to allow writing them on 4-grain even on 64bit platforms. +inline const _long4grain long4grain (const unsigned long& v) { return _long4grain(v); } +/// Wrap pointer values to allow writing them on 4-grain even on 64bit platforms. +template +inline _long4grain& ptr4grain (T*& p) { asm("":"+m"(p)); return *noalias_cast<_long4grain*>(&p); } +/// Wrap pointer values to allow writing them on 4-grain even on 64bit platforms. +template +inline const _long4grain ptr4grain (const T* const& p) { return _long4grain(uintptr_t(p)); } +#else // if not SIZE_OF_LONG == 8 && HAVE_INT64_T +inline unsigned long& long4grain (unsigned long& v) { return v; } +inline const unsigned long& long4grain (const unsigned long& v) { return v; } +template inline T*& ptr4grain (T*& p) { return p; } +template inline const T* const& ptr4grain (const T* const& p) { return p; } +#endif // SIZE_OF_LONG == 8 + +//---------------------------------------------------------------------- + +} // namespace ustl + +ALIGNOF (_long4grain, 4) +ALIGNOF(ustl::CBacktrace, sizeof(void*)) +ALIGNOF (ustl::string, stream_align_of (string::value_type())) +// bool is a big type on some machines (like DEC Alpha), so it's written as a byte. +ALIGNOF(bool, sizeof(uint8_t)) +CAST_STREAMABLE(bool, uint8_t) diff --git a/pwn/flipper/dist/common/include/ustl/ustack.h b/pwn/flipper/dist/common/include/ustl/ustack.h new file mode 100644 index 0000000..0599842 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ustack.h @@ -0,0 +1,48 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once + +namespace ustl { + +/// \class stack ustack.h ustl.h +/// \ingroup Sequences +/// +/// Stack adapter to uSTL containers. +/// +template > +class stack { +public: + typedef T value_type; + typedef Container container_type; + typedef typename container_type::size_type size_type; + typedef typename container_type::difference_type difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; +public: + inline stack (void) : _storage () { } + explicit inline stack (const container_type& s) : _storage (s) { } + explicit inline stack (const stack& s) : _storage (s._storage) { } + inline bool empty (void) const { return _storage.empty(); } + inline size_type size (void) const { return _storage.size(); } + inline reference top (void) { return _storage.back(); } + inline const_reference top (void) const { return _storage.back(); } + inline void push (const_reference v) { _storage.push_back (v); } + inline void pop (void) { _storage.pop_back(); } + inline void swap (stack& v) { _storage.swap (v); } + inline bool operator== (const stack& s) const { return _storage == s._storage; } + inline bool operator< (const stack& s) const { return _storage.size() < s._storage.size(); } +#if HAVE_CPP11 + inline stack (stack&& v) : _storage(move(v._storage)) {} + inline stack (container_type&& s) : _storage(move(s)) {} + inline stack& operator= (stack&& v) { swap (v); return *this; } + template + inline void emplace (Args&&... args) { _storage.emplace_back (forward(args)...); } +#endif +private: + container_type _storage; ///< Where the data actually is. +}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ustl.h b/pwn/flipper/dist/common/include/ustl/ustl.h new file mode 100644 index 0000000..bec591b --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ustl.h @@ -0,0 +1,182 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "ustl/uspecial.h" +#include "ustl/umap.h" +#include "ustl/umultimap.h" +#include "ustl/ustack.h" +#include "ustl/uqueue.h" +#include "ustl/unumeric.h" +#include "ustl/ulist.h" +#include "ustl/uheap.h" + +/// \mainpage +/// +/// \section intro Introduction +/// +/// uSTL is a partial implementation of the STL specification intended to +/// reduce code size of the derivative programs. Usually, the STL containers +/// manage their own storage with new[] and delete[] operators, which create +/// strongly typed storage. That is the standard way of allocating C++ object +/// vectors, allowing appropriate constructors and destructors to be called on +/// the allocated storage and ensuring that objects are copied via their copy +/// operators. Although type safety is a good thing, placing memory management +/// code into a template necessitates its reinstantiation for every template +/// instance used by the derivative program. This produces substantial code +/// bloat, that is frequently derided by C developers and used by them as +/// an argument that C is better than C++. The uSTL implementation solves +/// this problem by factoring memory management code into a non-template base +/// class, ustl::memblock, which performs unstructured memory allocation. STL +/// containers are then implemented as template wrappers for memblock to +/// provide a measure of type safety. The result is that each template +/// instantiation contains less code, and although it does not completely +/// "disappear", due to the requirement for calling placement constructors +/// on the allocated memory, most of it does, being replaced by calls to +/// memblock methods. The base classes for unstructured storage management +/// (cmemlink - link to constant memory, memlink - link to mutable memory, +/// and memblock - owner of mutable memory) are, of course, also available +/// for use as data buffers wherever those are needed, and streams that +/// efficiently read and write binary data into them are also available. +// +/// \defgroup Containers Containers +/// Here you'll find all the containers for your objects and data. +// +/// \defgroup MemoryManagement Memory Management +/// \ingroup Containers +/// Classes that implement low-level memory management and form the base for +/// all containers in the library. Almost all functionality in the containers +/// is reduced to calls to these base classes through a great deal of inline +/// crunching by the compiler, and thus you end up storing all your data in +/// ustl::memblock objects with the container templates as mere syntactic sugar. +// +/// \defgroup Sequences Sequence Containers +/// \ingroup Containers +/// Containers containing sequences of objects. +// +/// \defgroup AssociativeContainers Associative Containers +/// \ingroup Containers +/// Containers containing associations of objects. +// +/// \defgroup Streams Streams +/// Streams convert objects into flat data. +// +/// \defgroup BinaryStreams Binary Streams +/// \ingroup Streams +/// Unlike the C++ standard library, +/// the default behaviour is very strongly biased toward binary streams. I +/// believe that text formats should be used very sparingly due to numerous +/// problems they cause, such as total lack of structure, buffer overflows, +/// the great multitude of formats and encodings for even the most +/// trivial of things like integers, and the utter lack of readability +/// despite ardent claims to the contrary. Binary formats are well-structured, +/// are simpler to define exhaustively, are aggregates of basic types which +/// are universal to all architectures (with the exception of two types of +/// byte ordering, which I hope to be an issue that will go away soon), and +/// are much more readable (through an appropriate formatting tool equipped +/// to read binary format specifications). +// +/// \defgroup BinaryStreamIterators Binary Stream Iterators +/// \ingroup BinaryStreams +/// \ingroup Iterators +/// Iterators for using STL algorithms with binary streams. +// +/// \defgroup TextStreams TextStreams +/// \ingroup Streams +/// Streams converting objects into streams of text. +// +/// \defgroup DeviceStreams Device Streams +/// \ingroup Streams +/// Standard cout, cerr, and cin implementations for reading +/// and writing text through standard file descriptors. +// +/// \defgroup Iterators Iterators +/// Generalizations of the pointer concept, allowing algorithms to treat +/// all containers in a unified fashion. +// +/// \defgroup IteratorAdaptors Iterator Adaptors +/// \ingroup Iterators +/// Iterators made out of other iterators. +// +/// \defgroup Algorithms Algorithms +/// STL algorithms are the heart of generic programming. The idea is to +/// separate algorithms from containers to take advantage of the fact that +/// there are fewer distinct algorithms than typed containers. This is +/// diametrically opposed to object oriented programming, where each object +/// must contain all functionality related to its internal data. You will +/// find, I think, that in practice, generic programming is not terribly +/// convenient because it prevents you from encapsulating all your data. +/// The best approach is to compromise and have raw data classes that will +/// be manipulated by algorithms and to treat the rest of the objects as +/// stateful data transformers. +// +/// \defgroup MutatingAlgorithms Mutating Algorithms +/// \ingroup Algorithms +/// Algorithms for modifying your data in some way. +// +/// \defgroup SortingAlgorithms Sorting Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for sorting containers. +// +/// \defgroup GeneratorAlgorithms Generator Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for generating data. +// +/// \defgroup NumericAlgorithms Numeric Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms generalizing mathematical operations. +// +/// \defgroup SetAlgorithms Set Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for working with sorted sets. +// +/// \defgroup HeapAlgorithms Heap Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for generating and manipulating heaps. +// +/// \defgroup SwapAlgorithms Swap Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for swapping elements. +// +/// \defgroup RawStorageAlgorithms Raw Storage Algorithms +/// \ingroup MutatingAlgorithms +/// Algorithms for manipulating unstructured memory. +// +/// \defgroup ConditionAlgorithms Condition Algorithms +/// \ingroup Algorithms +/// Algorithms for obtaining information about data. +// +/// \defgroup SearchingAlgorithms Searching Algorithms +/// \ingroup ConditionAlgorithms +/// Algorithms for searching through containers. +// +/// \defgroup PredicateAlgorithms Predicate Algorithms +/// \ingroup Algorithms +/// Algorithms that take a functor object. Avoid these if you can, +/// and carefully check the generated assembly if you can't. These +/// algorithms can and will generate prodigious amounts of bloat +/// if you are not very very careful about writing your functors. +// +/// \defgroup Functors Functors +/// Functors are inteded to be passed as arguments to \link PredicateAlgorithms +/// predicate algorithms\endlink. Ivory tower academics make much of this capability, +/// no doubt happy that C++ can now be made to look just like their precious lisp. +/// In practice, however, functors and predicate algorithms are mostly useless. +/// An iterative solution using \ref foreach is usually far simpler to write +/// and to maintain. Furthermore, functional programming in C++ often +/// generates much bloat and slowness, which is difficult to avoid with any +/// but the most primitive functors. Try them if you wish, now and then, but +/// compare with an iterative solution to see if the compiler really can see +/// through all your functional trickery. +// +/// \defgroup FunctorObjects Functor Objects +/// \ingroup Functors +/// Objects that wrap other functors to provide new functionality. +// +/// \defgroup FunctorAccessors Functor Object Accessors +/// \ingroup Functors +/// Because C++ is so very unsuited to functional programming, trying +/// to do so may require a lot of typing. These accessor functions +/// are somewhat helpful in making functional constructs more readable. diff --git a/pwn/flipper/dist/common/include/ustl/ustring.h b/pwn/flipper/dist/common/include/ustl/ustring.h new file mode 100644 index 0000000..5dbff94 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ustring.h @@ -0,0 +1,371 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "memblock.h" +#include "utf8.h" +#include + +namespace ustl { + +/// \class string ustring.h ustl.h +/// \ingroup Sequences +/// +/// \brief STL basic_string<char> equivalent. +/// +/// An STL container for text string manipulation. +/// Differences from C++ standard: +/// - string is a class, not a template. Wide characters are assumed to be +/// encoded with utf8 at all times except when rendering or editing, +/// where you would use a utf8 iterator. +/// - format member function - you can, of course use an \ref ostringstream, +/// which also have format functions, but most of the time this way +/// is more convenient. Because uSTL does not implement locales, +/// format is the only way to create localized strings. +/// - const char* cast operator. It is much clearer to use this than having +/// to type .c_str() every time. +/// - length returns the number of _characters_, not bytes. +/// This function is O(N), so use wisely. +/// +/// An additional note is in order regarding the use of indexes. All indexes +/// passed in as arguments or returned by find are byte offsets, not character +/// offsets. Likewise, sizes are specified in bytes, not characters. The +/// rationale is that there is no way for you to know what is in the string. +/// There is no way for you to know how many characters are needed to express +/// one thing or another. The only thing you can do to a localized string is +/// search for delimiters and modify text between them as opaque blocks. If you +/// do anything else, you are hardcoding yourself into a locale! So stop it! +/// +class string : public memblock { +public: + typedef char value_type; + typedef unsigned char uvalue_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef wchar_t wvalue_type; + typedef wvalue_type* wpointer; + typedef const wvalue_type* const_wpointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef value_type& reference; + typedef value_type const_reference; + typedef ::ustl::reverse_iterator reverse_iterator; + typedef ::ustl::reverse_iterator const_reverse_iterator; + typedef utf8in_iterator utf8_iterator; + typedef size_type pos_type; + static constexpr const pos_type npos = INT_MAX; ///< Value that means the end of string. +public: + inline string (void) noexcept : memblock () { relink ("",0); } + string (const string& s); + inline string (const string& s, pos_type o, size_type n = npos); + inline explicit string (const cmemlink& l); + string (const_pointer s) noexcept; + inline string (const_pointer s, size_type len); + inline string (const_pointer s1, const_pointer s2); + string (size_type n, value_type c); + inline ~string (void) noexcept { } + inline pointer data (void) { return string::pointer (memblock::data()); } + inline const_pointer data (void) const { return string::const_pointer (memblock::data()); } + inline const_pointer c_str (void) const { return string::const_pointer (memblock::cdata()); } + inline size_type max_size (void) const { size_type s (memblock::max_size()); return s - !!s; } + inline size_type capacity (void) const { size_type c (memblock::capacity()); return c - !!c; } + void resize (size_type n); + inline void resize (size_type n, value_type c); + inline void clear (void) { resize (0); } + inline iterator begin (void) { return iterator (memblock::begin()); } + inline const_iterator begin (void) const { return const_iterator (memblock::begin()); } + inline const_iterator cbegin (void) const { return begin(); } + inline iterator end (void) { return iterator (memblock::end()); } + inline const_iterator end (void) const { return const_iterator (memblock::end()); } + inline const_iterator cend (void) const { return end(); } + inline reverse_iterator rbegin (void) { return reverse_iterator (end()); } + inline const_reverse_iterator rbegin (void) const { return const_reverse_iterator (end()); } + inline const_reverse_iterator crbegin (void) const { return rbegin(); } + inline reverse_iterator rend (void) { return reverse_iterator (begin()); } + inline const_reverse_iterator rend (void) const { return const_reverse_iterator (begin()); } + inline const_reverse_iterator crend (void) const { return rend(); } + inline utf8_iterator utf8_begin (void) const { return utf8_iterator (begin()); } + inline utf8_iterator utf8_end (void) const { return utf8_iterator (end()); } + inline const_reference at (pos_type pos) const { assert (pos <= size() && begin()); return begin()[pos]; } + inline reference at (pos_type pos) { assert (pos <= size() && begin()); return begin()[pos]; } + inline const_iterator iat (pos_type pos) const { return begin() + (__builtin_constant_p(pos) && pos >= npos ? size() : min(size_type(pos),size())); } + inline iterator iat (pos_type pos) { return const_cast(const_cast(this)->iat(pos)); } + const_iterator wiat (pos_type i) const noexcept; + inline iterator wiat (pos_type i) { return const_cast(const_cast(this)->wiat(i)); } + inline const_reference front (void) const { return at(0); } + inline reference front (void) { return at(0); } + inline const_reference back (void) const { return at(size()-1); } + inline reference back (void) { return at(size()-1); } + inline size_type length (void) const { return distance (utf8_begin(), utf8_end()); } + inline string& append (const_iterator i1, const_iterator i2) { return append (i1, distance (i1, i2)); } + string& append (const_pointer s, size_type len); + string& append (const_pointer s); + string& append (size_type n, value_type c); + inline string& append (size_type n, wvalue_type c) { insert (size(), n, c); return *this; } + inline string& append (const_wpointer s1, const_wpointer s2) { insert (size(), s1, s2); return *this; } + inline string& append (const_wpointer s) { const_wpointer se (s); for (;se&&*se;++se) {} return append (s, se); } + inline string& append (const string& s) { return append (s.begin(), s.end()); } + inline string& append (const string& s,pos_type o,size_type n) { return append (s.iat(o), s.iat(o+n)); } + inline void push_back (value_type c) { resize(size()+1); end()[-1] = c; } + inline void push_back (wvalue_type c) { append (1, c); } + inline void pop_back (void) { resize (size()-1); } + inline string& assign (const_iterator i1, const_iterator i2) { return assign (i1, distance (i1, i2)); } + string& assign (const_pointer s, size_type len); + string& assign (const_pointer s); + inline string& assign (const_wpointer s1, const_wpointer s2) { clear(); return append (s1, s2); } + inline string& assign (const_wpointer s1) { clear(); return append (s1); } + inline string& assign (const string& s) { return assign (s.begin(), s.end()); } + inline string& assign (const string& s, pos_type o, size_type n) { return assign (s.iat(o), s.iat(o+n)); } + inline string& assign (size_type n, value_type c) { clear(); return append (n, c); } + inline string& assign (size_type n, wvalue_type c) { clear(); return append (n, c); } + size_type copy (pointer p, size_type n, pos_type pos = 0) const noexcept; + inline size_type copyto (pointer p, size_type n, pos_type pos = 0) const noexcept { size_type bc = copy(p,n-1,pos); p[bc]=0; return bc; } + inline int compare (const string& s) const { return compare (begin(), end(), s.begin(), s.end()); } + inline int compare (pos_type start, size_type len, const string& s) const { return compare (iat(start), iat(start+len), s.begin(), s.end()); } + inline int compare (pos_type s1, size_type l1, const string& s, pos_type s2, size_type l2) const { return compare (iat(s1), iat(s1+l1), s.iat(s2), s.iat(s2+l2)); } + inline int compare (const_pointer s) const { return compare (begin(), end(), s, s + strlen(s)); } + inline int compare (pos_type s1, size_type l1, const_pointer s, size_type l2) const { return compare (iat(s1), iat(s1+l1), s, s+l2); } + inline int compare (pos_type s1, size_type l1, const_pointer s) const { return compare (s1, l1, s, strlen(s)); } + static int compare (const_iterator first1, const_iterator last1, const_iterator first2, const_iterator last2) noexcept; + inline operator const value_type* (void) const; + inline operator value_type* (void); + inline const string& operator= (const string& s) { return assign (s.begin(), s.end()); } + inline const string& operator= (const_reference c) { return assign (&c, 1); } + inline const string& operator= (const_pointer s) { return assign (s); } + inline const string& operator= (const_wpointer s) { return assign (s); } + inline const string& operator+= (const string& s) { return append (s.begin(), s.size()); } + inline const string& operator+= (value_type c) { push_back(c); return *this; } + inline const string& operator+= (const_pointer s) { return append (s); } + inline const string& operator+= (wvalue_type c) { return append (1, c); } + inline const string& operator+= (uvalue_type c) { return operator+= (value_type(c)); } + inline const string& operator+= (const_wpointer s) { return append (s); } + inline string operator+ (const string& s) const; + inline bool operator== (const string& s) const { return memblock::operator== (s); } + bool operator== (const_pointer s) const noexcept; + inline bool operator== (value_type c) const { return size() == 1 && c == at(0); } + inline bool operator== (uvalue_type c) const { return operator== (value_type(c)); } + inline bool operator!= (const string& s) const { return !operator== (s); } + inline bool operator!= (const_pointer s) const { return !operator== (s); } + inline bool operator!= (value_type c) const { return !operator== (c); } + inline bool operator!= (uvalue_type c) const { return !operator== (c); } + inline bool operator< (const string& s) const { return 0 > compare (s); } + inline bool operator< (const_pointer s) const { return 0 > compare (s); } + inline bool operator< (value_type c) const { return 0 > compare (begin(), end(), &c, &c + 1); } + inline bool operator< (uvalue_type c) const { return operator< (value_type(c)); } + inline bool operator> (const_pointer s) const { return 0 < compare (s); } + inline string& insert (pos_type ip, size_type n, value_type c) { insert (iat(ip), n, c); return *this; } + inline string& insert (pos_type ip, const_pointer s) { insert (iat(ip), s, s + strlen(s)); return *this; } + inline string& insert (pos_type ip, const_pointer s, size_type nlen) { insert (iat(ip), s, s + nlen); return *this; } + inline string& insert (pos_type ip, const string& s) { insert (iat(ip), s.c_str(), s.size()); return *this; } + inline string& insert (pos_type ip, const string& s, size_type sp, size_type slen) { insert (iat(ip), s.iat(sp), s.iat(sp + slen)); return *this; } + string& insert (pos_type ip, size_type n, wvalue_type c); + string& insert (pos_type ip, const_wpointer first, const_wpointer last, size_type n = 1); + inline string& insert (int ip, size_type n, value_type c) { insert (pos_type(ip), n, c); return *this; } + inline string& insert (int ip, const_pointer s, size_type nlen) { insert (pos_type(ip), s, nlen); return *this; } + iterator insert (const_iterator start, size_type n, value_type c); + inline iterator insert (const_iterator start, value_type c) { return insert (start, 1u, c); } + iterator insert (const_iterator start, const_pointer s, size_type n); + iterator insert (const_iterator start, const_pointer first, const_iterator last, size_type n = 1); + iterator erase (const_iterator epo, size_type n = 1); + string& erase (pos_type epo = 0, size_type n = npos); + inline string& erase (int epo, size_type n = npos) { return erase (pos_type(epo), n); } + inline iterator erase (const_iterator first, const_iterator last) { return erase (first, size_type(distance(first,last))); } + inline iterator eraser (pos_type first, pos_type last) { return erase (iat(first), iat(last)); } + string& replace (const_iterator first, const_iterator last, const_pointer i1, const_pointer i2, size_type n); + template + string& replace (const_iterator first, const_iterator last, InputIt first2, InputIt last2) { return replace (first, last, first2, last2, 1); } + inline string& replace (const_iterator first, const_iterator last, const string& s) { return replace (first, last, s.begin(), s.end()); } + string& replace (const_iterator first, const_iterator last, const_pointer s); + inline string& replace (const_iterator first, const_iterator last, const_pointer s, size_type slen) { return replace (first, last, s, s + slen); } + inline string& replace (const_iterator first, const_iterator last, size_type n, value_type c) { return replace (first, last, &c, &c + 1, n); } + inline string& replace (pos_type rp, size_type n, const string& s) { return replace (iat(rp), iat(rp + n), s); } + inline string& replace (pos_type rp, size_type n, const string& s, uoff_t sp, size_type slen) { return replace (iat(rp), iat(rp + n), s.iat(sp), s.iat(sp + slen)); } + inline string& replace (pos_type rp, size_type n, const_pointer s, size_type slen) { return replace (iat(rp), iat(rp + n), s, s + slen); } + inline string& replace (pos_type rp, size_type n, const_pointer s) { return replace (iat(rp), iat(rp + n), string(s)); } + inline string& replace (pos_type rp, size_type n, size_type count, value_type c) { return replace (iat(rp), iat(rp + n), count, c); } + inline string substr (pos_type o = 0, size_type n = npos) const { return string (*this, o, n); } + inline void swap (string& v) { memblock::swap (v); } + pos_type find (value_type c, pos_type pos = 0) const noexcept; + pos_type find (const string& s, pos_type pos = 0) const noexcept; + inline pos_type find (uvalue_type c, pos_type pos = 0) const noexcept { return find (value_type(c), pos); } + inline pos_type find (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return find (sp, pos); } + pos_type rfind (value_type c, pos_type pos = npos) const noexcept; + pos_type rfind (const string& s, pos_type pos = npos) const noexcept; + inline pos_type rfind (uvalue_type c, pos_type pos = npos) const noexcept { return rfind (value_type(c), pos); } + inline pos_type rfind (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return rfind (sp, pos); } + pos_type find_first_of (const string& s, pos_type pos = 0) const noexcept; + inline pos_type find_first_of (value_type c, pos_type pos = 0) const { string sp (1, c); return find_first_of(sp,pos); } + inline pos_type find_first_of (uvalue_type c, pos_type pos = 0) const { return find_first_of (value_type(c), pos); } + inline pos_type find_first_of (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return find_first_of (sp, pos); } + pos_type find_first_not_of (const string& s, pos_type pos = 0) const noexcept; + inline pos_type find_first_not_of (value_type c, pos_type pos = 0) const { string sp (1, c); return find_first_not_of(sp,pos); } + inline pos_type find_first_not_of (uvalue_type c, pos_type pos = 0) const { return find_first_not_of (value_type(c), pos); } + inline pos_type find_first_not_of (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return find_first_not_of (sp, pos); } + pos_type find_last_of (const string& s, pos_type pos = npos) const noexcept; + inline pos_type find_last_of (value_type c, pos_type pos = npos) const { string sp (1, c); return find_last_of(sp,pos); } + inline pos_type find_last_of (uvalue_type c, pos_type pos = npos) const { return find_last_of (value_type(c), pos); } + inline pos_type find_last_of (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return find_last_of (sp, pos); } + pos_type find_last_not_of (const string& s, pos_type pos = npos) const noexcept; + inline pos_type find_last_not_of (value_type c, pos_type pos = npos) const { string sp (1, c); return find_last_not_of(sp,pos); } + inline pos_type find_last_not_of (uvalue_type c, pos_type pos = npos) const { return find_last_not_of (value_type(c), pos); } + inline pos_type find_last_not_of (const_pointer p, pos_type pos, size_type count) const { string sp; sp.link (p,count); return find_last_not_of (sp, pos); } + int vformat (const char* fmt, va_list args); + int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + void read (istream&); + void write (ostream& os) const; + size_t stream_size (void) const noexcept; + static hashvalue_t hash (const char* f1, const char* l1) noexcept; +#if HAVE_CPP11 + using initlist_t = std::initializer_list; + inline string (string&& v) : memblock (move(v)) {} + inline string (initlist_t v) : memblock() { assign (v.begin(), v.size()); } + inline string& assign (string&& v) { swap (v); return *this; } + inline string& assign (initlist_t v) { return assign (v.begin(), v.size()); } + inline string& append (initlist_t v) { return append (v.begin(), v.size()); } + inline string& operator+= (initlist_t v) { return append (v.begin(), v.size()); } + inline string& operator= (string&& v) { return assign (move(v)); } + inline string& operator= (initlist_t v) { return assign (v.begin(), v.size()); } + inline iterator insert (const_iterator ip, initlist_t v) { return insert (ip, v.begin(), v.end()); } + inline string& replace (const_iterator first, const_iterator last, initlist_t v) { return replace (first, last, v.begin(), v.end()); } +#endif +private: + virtual size_type minimumFreeCapacity (void) const noexcept final override __attribute__((const)); +}; + +//---------------------------------------------------------------------- + +/// Assigns itself the value of string \p s +inline string::string (const cmemlink& s) +: memblock () +{ + assign (const_iterator (s.begin()), s.size()); +} + +/// Assigns itself a [o,o+n) substring of \p s. +inline string::string (const string& s, pos_type o, size_type n) +: memblock() +{ + assign (s, o, n); +} + +/// Copies the value of \p s of length \p len into itself. +inline string::string (const_pointer s, size_type len) +: memblock () +{ + assign (s, len); +} + +/// Copies into itself the string data between \p s1 and \p s2 +inline string::string (const_pointer s1, const_pointer s2) +: memblock () +{ + assert (s1 <= s2 && "Negative ranges result in memory allocation errors."); + assign (s1, s2); +} + +/// Returns the pointer to the first character. +inline string::operator const string::value_type* (void) const +{ + assert ((!end() || !*end()) && "This string is linked to data that is not 0-terminated. This may cause serious security problems. Please assign the data instead of linking."); + return begin(); +} + +/// Returns the pointer to the first character. +inline string::operator string::value_type* (void) +{ + assert ((end() && !*end()) && "This string is linked to data that is not 0-terminated. This may cause serious security problems. Please assign the data instead of linking."); + return begin(); +} + +/// Concatenates itself with \p s +inline string string::operator+ (const string& s) const +{ + string result (*this); + result += s; + return result; +} + +/// Resize to \p n and fill new entries with \p c +inline void string::resize (size_type n, value_type c) +{ + const size_type oldn = size(); + resize (n); + fill_n (iat(oldn), max(ssize_t(n-oldn),0), c); +} + +//---------------------------------------------------------------------- +// Operators needed to avoid comparing pointer to pointer + +#define PTR_STRING_CMP(op, impl) \ +inline bool op (const char* s1, const string& s2) { return impl; } +PTR_STRING_CMP (operator==, (s2 == s1)) +PTR_STRING_CMP (operator!=, (s2 != s1)) +PTR_STRING_CMP (operator<, (s2 > s1)) +PTR_STRING_CMP (operator<=, (s2 >= s1)) +PTR_STRING_CMP (operator>, (s2 < s1)) +PTR_STRING_CMP (operator>=, (s2 <= s1)) +#undef PTR_STRING_CMP + +inline string operator+ (const char* cs, const string& ss) { string r; r.reserve (strlen(cs)+ss.size()); r += cs; r += ss; return r; } + +//---------------------------------------------------------------------- + +inline hashvalue_t hash_value (const char* first, const char* last) +{ return string::hash (first, last); } +inline hashvalue_t hash_value (const char* v) +{ return hash_value (v, v + strlen(v)); } + +//---------------------------------------------------------------------- +// String-number conversions + +#define STRING_TO_INT_CONVERTER(name,type,func) \ +inline type name (const string& str, size_t* idx = nullptr, int base = 10) \ +{ \ + const char* sp = str.c_str(); \ + char* endp = nullptr; \ + type r = func (sp, idx ? &endp : nullptr, base);\ + if (idx) \ + *idx = endp - sp; \ + return r; \ +} +/*STRING_TO_INT_CONVERTER(stoi,int,strtol) +STRING_TO_INT_CONVERTER(stol,long,strtol) +STRING_TO_INT_CONVERTER(stoul,unsigned long,strtoul) +#if HAVE_LONG_LONG +STRING_TO_INT_CONVERTER(stoll,long long,strtoll) +STRING_TO_INT_CONVERTER(stoull,unsigned long long,strtoull) +#endif*/ +#undef STRING_TO_INT_CONVERTER + +#define STRING_TO_FLOAT_CONVERTER(name,type,func) \ +inline type name (const string& str, size_t* idx = nullptr) \ +{ \ + const char* sp = str.c_str(); \ + char* endp = nullptr; \ + type r = func (sp, idx ? &endp : nullptr);\ + if (idx) \ + *idx = endp - sp; \ + return r; \ +} +/*STRING_TO_FLOAT_CONVERTER(stof,float,strtof) +STRING_TO_FLOAT_CONVERTER(stod,double,strtod) +STRING_TO_FLOAT_CONVERTER(stold,long double,strtold)*/ +#undef STRING_TO_FLOAT_CONVERTER + +#define NUMBER_TO_STRING_CONVERTER(type,fmts)\ + inline string to_string (type v) { string r; r.format(fmts,v); return r; } +NUMBER_TO_STRING_CONVERTER(int,"%d") +NUMBER_TO_STRING_CONVERTER(long,"%ld") +NUMBER_TO_STRING_CONVERTER(unsigned long,"%lu") +#if HAVE_LONG_LONG +NUMBER_TO_STRING_CONVERTER(long long,"%lld") +NUMBER_TO_STRING_CONVERTER(unsigned long long,"%llu") +#endif +/*NUMBER_TO_STRING_CONVERTER(float,"%f") +NUMBER_TO_STRING_CONVERTER(double,"%lf") +NUMBER_TO_STRING_CONVERTER(long double,"%Lf")*/ +#undef NUMBER_TO_STRING_CONVERTER + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/ustringformat.h b/pwn/flipper/dist/common/include/ustl/ustringformat.h new file mode 100644 index 0000000..c2b7f66 --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/ustringformat.h @@ -0,0 +1,36 @@ +#pragma once + +#include "utypes.h" +#include "stdarg.h" +#include "kstring.h" + +#define MAXNBUF 40 + +#define hex2ascii(hex) (hex2ascii_data[hex]) +#define hex2asciiupper(hex) (hex2ascii_data_upper[hex]) +char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +char const hex2ascii_data_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long u_long; +typedef unsigned int u_int; +/*typedef unsigned int size_t;*/ + +struct snprintf_arg { + char *str; + size_t remain; +}; + +extern int +vsnprintf(char *str, size_t size, const char *format, va_list ap); + +extern void +snprintf_func(int ch, void *arg); + +extern int +kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap); + +extern char * +ksprintn(char* nbuf, u_long ul, int base, int* lenp, int upper); + diff --git a/pwn/flipper/dist/common/include/ustl/utf8.h b/pwn/flipper/dist/common/include/ustl/utf8.h new file mode 100644 index 0000000..6f9316e --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/utf8.h @@ -0,0 +1,213 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. +// +// This file contains stream iterators that read and write UTF-8 encoded +// characters. The encoding is defined as follows: +// +// U-00000000 - U-0000007F: 0xxxxxxx +// U-00000080 - U-000007FF: 110xxxxx 10xxxxxx +// U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx +// U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-80000000 - U-FFFFFFFF: 11111110 100000xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + +#pragma once +#include "uiterator.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +typedef uint8_t utf8subchar_t; ///< Type for the encoding subcharacters. + +//---------------------------------------------------------------------- + +inline size_t Utf8Bytes (wchar_t v) __attribute__((const)); +inline size_t Utf8Bytes (const wchar_t* first, const wchar_t* last) __attribute__((pure)); +inline size_t Utf8SequenceBytes (wchar_t c) __attribute__((const)); + +//---------------------------------------------------------------------- + +/// Returns the number of bytes required to UTF-8 encode \p v. +inline size_t Utf8Bytes (wchar_t v) +{ + if (uint32_t(v) < 128) + return 1; + size_t n; + #if __x86__ + uint32_t r = 0; + asm ("bsr\t%2, %%eax\n\t" + "add\t$4, %0\n\t" + "div\t%3":"=a"(n),"+d"(r):"r"(v),"c"(5)); + #else + static const uint32_t c_Bounds[7] = { 0x0000007F, 0x000007FF, 0x0000FFFF, 0x001FFFFF, 0x03FFFFFF, 0x7FFFFFFF, 0xFFFFFFFF }; + for (n = 0; c_Bounds[n++] < uint32_t(v);); + #endif + return n; +} + +/// Measures the size of a wchar_t array in UTF-8 encoding. +inline size_t Utf8Bytes (const wchar_t* first, const wchar_t* last) +{ + size_t bc = 0; + for (; first < last; ++first) + bc += Utf8Bytes(*first); + return bc; +} + +/// Returns the number of bytes in a UTF-8 sequence that starts with \p c. +inline size_t Utf8SequenceBytes (wchar_t c) // a wchar_t to keep c in a full register +{ + // Count the leading bits. Header bits are 1 * nBytes followed by a 0. + // 0 - single byte character. Take 7 bits (0xFF >> 1) + // 1 - error, in the middle of the character. Take 6 bits (0xFF >> 2) + // so you will keep reading invalid entries until you hit the next character. + // >2 - multibyte character. Take remaining bits, and get the next bytes. + // All errors are ignored, since the user can not correct them. + // + wchar_t mask = 0x80; + size_t nBytes = 0; + for (; c & mask; ++nBytes) + mask >>= 1; + return nBytes ? nBytes : 1; // A sequence is always at least 1 byte. +} + +//---------------------------------------------------------------------- + +/// \class utf8in_iterator utf8.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief An iterator adaptor to character containers for reading UTF-8 encoded text. +/// +/// For example, you can copy from ustl::string to ustl::vector with +/// copy (utf8in (str.begin()), utf8in (str.end()), back_inserter(wvect)); +/// There is no error handling; if the reading frame slips you'll get extra +/// characters, one for every misaligned byte. Although it is possible to skip +/// to the start of the next character, that would result in omitting the +/// misformatted character and the one after it, making it very difficult to +/// detect by the user. It is better to write some strange characters and let +/// the user know his file is corrupted. Another problem is overflow on bad +/// encodings (like a 0xFF on the end of a string). This is checked through +/// the end-of-string nul character, which will always be there as long as +/// you are using the string class. +/// +template +class utf8in_iterator { +public: + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + typedef input_iterator_tag iterator_category; +public: + explicit utf8in_iterator (const Iterator& is) : _i (is), _v (0) { Read(); } + utf8in_iterator (const utf8in_iterator& i) : _i (i._i), _v (i._v) {} + inline const utf8in_iterator& operator= (const utf8in_iterator& i) { _i = i._i; _v = i._v; return *this; } + inline Iterator base (void) const { return _i - (Utf8Bytes(_v) - 1); } + /// Reads and returns the next value. + inline WChar operator* (void) const { return _v; } + inline utf8in_iterator& operator++ (void) { ++_i; Read(); return *this; } + inline utf8in_iterator operator++ (int) { utf8in_iterator old (*this); operator++(); return old; } + inline utf8in_iterator& operator+= (uoff_t n) { while (n--) operator++(); return *this; } + inline utf8in_iterator operator+ (uoff_t n) { utf8in_iterator v (*this); return v += n; } + inline bool operator== (const utf8in_iterator& i) const { return _i == i._i; } + inline bool operator< (const utf8in_iterator& i) const { return _i < i._i; } + difference_type operator- (const utf8in_iterator& i) const; +private: + void Read (void); +private: + Iterator _i; + WChar _v; +}; + +/// Steps to the next character and updates current returnable value. +template +void utf8in_iterator::Read (void) +{ + const utf8subchar_t c = *_i; + size_t nBytes = Utf8SequenceBytes (c); + _v = c & (0xFF >> nBytes); // First byte contains bits after the header. + while (--nBytes && *++_i) // Each subsequent byte has 6 bits. + _v = (_v << 6) | (*_i & 0x3F); +} + +/// Returns the distance in characters (as opposed to the distance in bytes). +template +typename utf8in_iterator::difference_type +utf8in_iterator::operator- (const utf8in_iterator& last) const +{ + difference_type dist = 0; + for (Iterator first (last._i); first < _i; ++dist) + first = advance (first, Utf8SequenceBytes (*first)); + return dist; +} + +//---------------------------------------------------------------------- + +/// \class utf8out_iterator utf8.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief An iterator adaptor to character containers for writing UTF-8 encoded text. +/// +template +class utf8out_iterator { +public: + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + typedef output_iterator_tag iterator_category; +public: + explicit utf8out_iterator (const Iterator& os) : _i (os) {} + utf8out_iterator (const utf8out_iterator& i) : _i (i._i) {} + inline const Iterator& base (void) const { return _i; } + /// Writes \p v into the stream. + utf8out_iterator& operator= (WChar v); + inline utf8out_iterator& operator* (void) { return *this; } + inline utf8out_iterator& operator++ (void) { return *this; } + inline utf8out_iterator& operator++ (int) { return *this; } + inline bool operator== (const utf8out_iterator& i) const { return _i == i._i; } + inline bool operator< (const utf8out_iterator& i) const { return _i < i._i; } +private: + Iterator _i; +}; + +/// Writes \p v into the stream. +template +utf8out_iterator& utf8out_iterator::operator= (WChar v) +{ + const size_t nBytes = Utf8Bytes (v); + if (nBytes > 1) { + // Write the bits 6 bits at a time, except for the first one, + // which may be less than 6 bits. + wchar_t shift = nBytes * 6; + *_i++ = ((v >> (shift -= 6)) & 0x3F) | (0xFF << (8 - nBytes)); + while (shift) + *_i++ = ((v >> (shift -= 6)) & 0x3F) | 0x80; + } else // If only one byte, there is no header. + *_i++ = v; + return *this; +} + +//---------------------------------------------------------------------- + +/// Returns a UTF-8 adaptor writing to \p i. Useful in conjuction with back_insert_iterator. +template +inline utf8out_iterator utf8out (Iterator i) +{ + return utf8out_iterator (i); +} + +/// Returns a UTF-8 adaptor reading from \p i. +template +inline utf8in_iterator utf8in (Iterator i) +{ + return utf8in_iterator (i); +} + +//---------------------------------------------------------------------- + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uttraits.h b/pwn/flipper/dist/common/include/ustl/uttraits.h new file mode 100644 index 0000000..e0e251a --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uttraits.h @@ -0,0 +1,506 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "utypes.h" + +#if HAVE_CPP11 +namespace ustl { + +//{{{ Helper templates and specs --------------------------------------- + +/// true or false templatized constant for metaprogramming +template +struct integral_constant { + using value_type = T; + using type = integral_constant; + static constexpr const T value = v; + constexpr operator value_type() const { return value; } + constexpr T operator()() const { return value; } +}; +template constexpr const T integral_constant::value; + +using true_type = integral_constant; +using false_type = integral_constant; + +/// Selects type = flag ? T : U +template struct conditional { using type = T; }; +template struct conditional { using type = U; }; +template using conditional_t = typename conditional::type; + +/// Selects bool = flag ? T : U +template struct t_if : public integral_constant {}; +template struct t_if : public integral_constant {}; + +template struct enable_if { }; +template struct enable_if { using type = T; }; +template using enable_if_t = typename enable_if::type; + +#define UNARY_TRAIT_DEFB(name,condition) \ +template struct name : public integral_constant {} +#define UNARY_TRAIT_DEFN(name) \ +template struct name : public false_type {} +#define UNARY_TRAIT_TRUE(name,type) \ +template <> struct name : public true_type {} + +//}}}------------------------------------------------------------------- +//{{{ Type modifications + +template struct remove_const { using type = T; }; +template struct remove_const { using type = T; }; +template using remove_const_t = typename remove_const::type; + +template struct remove_volatile { using type = T; }; +template struct remove_volatile{ using type = T; }; +template using remove_volatile_t = typename remove_volatile::type; + +template struct remove_cv { using type = remove_volatile_t>; }; +template using remove_cv_t = typename remove_cv::type; + +template struct add_const { using type = T const; }; +template struct add_const { using type = T const; }; +template using add_const_t = typename add_const::type; + +template constexpr add_const_t& as_const (T& v) { return v; } +template void as_const(const T&&) = delete; + +template struct add_volatile { using type = T volatile; }; +template struct add_volatile { using type = T volatile; }; +template using add_volatile_t = typename add_volatile::type; + +template struct add_cv { using type = add_volatile_t>; }; +template using add_cv_t = typename add_cv::type; + +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template struct remove_reference { using type = T; }; +template using remove_reference_t = typename remove_reference::type; + +template struct remove_pointer { using type = T; }; +template struct remove_pointer { using type = T; }; +template using remove_pointer_t = typename remove_pointer::type; + +template struct add_pointer { using type = T*; }; +template struct add_pointer { using type = T*; }; +template using add_pointer_t = typename add_pointer::type; + +template struct remove_extent { using type = T; }; +template struct remove_extent { using type = T; }; +template struct remove_extent { using type = T; }; +template using remove_extent_t = typename remove_extent::type; + +template struct remove_all_extents { using type = T; }; +template struct remove_all_extents { using type = typename remove_all_extents::type; }; +template struct remove_all_extents { using type = typename remove_all_extents::type; }; +template using remove_all_extents_t = typename remove_all_extents::type; + +template struct underlying_type { using type = __underlying_type(T); }; +template using underlying_type_t = typename underlying_type::type; + +#if HAVE_CPP14 +template using void_t = void; +#endif + +template struct make_signed { using type = T; }; +template <> struct make_signed { using type = signed char; }; +template <> struct make_signed { using type = signed char; }; +template <> struct make_signed { using type = signed short; }; +template <> struct make_signed { using type = signed int; }; +template <> struct make_signed { using type = signed long; }; +#if HAVE_LONG_LONG +template <> struct make_signed { using type = signed long long; }; +#endif +template using make_signed_t = typename make_signed::type; + +template struct make_unsigned { using type = T; }; +template <> struct make_unsigned { using type = unsigned char; }; +template <> struct make_unsigned { using type = unsigned char; }; +template <> struct make_unsigned { using type = unsigned short; }; +template <> struct make_unsigned { using type = unsigned int; }; +template <> struct make_unsigned { using type = unsigned long; }; +#if HAVE_LONG_LONG +template <> struct make_unsigned { using type = unsigned long long; }; +#endif +template using make_unsigned_t = typename make_unsigned::type; + +//}}}------------------------------------------------------------------- +//{{{ Primary type categories + +#if __clang__ // clang already has these __is_ helpers as builtins + +UNARY_TRAIT_DEFB (is_void, __is_void(remove_cv_t)); +UNARY_TRAIT_DEFB (is_integral, __is_integral(remove_cv_t)); +UNARY_TRAIT_DEFB (is_signed, __is_signed(remove_cv_t)); +UNARY_TRAIT_DEFB (is_floating_point, __is_floating_point(remove_cv_t)); +UNARY_TRAIT_DEFB (is_pointer, __is_pointer(remove_cv_t)); +UNARY_TRAIT_DEFB (is_member_pointer, __is_member_pointer(remove_cv_t)); +UNARY_TRAIT_DEFB (is_member_function_pointer, __is_member_function_pointer(remove_cv_t)); + +#else + +UNARY_TRAIT_DEFN (__is_void); +UNARY_TRAIT_TRUE (__is_void, void); +UNARY_TRAIT_DEFB (is_void, __is_void>::value); + +UNARY_TRAIT_DEFN (__is_integral); +UNARY_TRAIT_TRUE (__is_integral, char); +#if HAVE_THREE_CHAR_TYPES +UNARY_TRAIT_TRUE (__is_integral, signed char); +#endif +UNARY_TRAIT_TRUE (__is_integral, short); +UNARY_TRAIT_TRUE (__is_integral, int); +UNARY_TRAIT_TRUE (__is_integral, long); +UNARY_TRAIT_TRUE (__is_integral, unsigned char); +UNARY_TRAIT_TRUE (__is_integral, unsigned short); +UNARY_TRAIT_TRUE (__is_integral, unsigned int); +UNARY_TRAIT_TRUE (__is_integral, unsigned long); +#if HAVE_LONG_LONG +UNARY_TRAIT_TRUE (__is_integral, long long); +UNARY_TRAIT_TRUE (__is_integral, unsigned long long); +#endif +UNARY_TRAIT_TRUE (__is_integral, wchar_t); +UNARY_TRAIT_TRUE (__is_integral, bool); +UNARY_TRAIT_DEFB (is_integral, __is_integral>::value); + +UNARY_TRAIT_DEFN (__is_signed); +UNARY_TRAIT_TRUE (__is_signed, char); +UNARY_TRAIT_TRUE (__is_signed, wchar_t); +UNARY_TRAIT_TRUE (__is_signed, short); +UNARY_TRAIT_TRUE (__is_signed, int); +UNARY_TRAIT_TRUE (__is_signed, long); +UNARY_TRAIT_TRUE (__is_signed, long long); +UNARY_TRAIT_DEFB (is_signed, __is_signed>::value); + +UNARY_TRAIT_DEFN (__is_floating_point); +//UNARY_TRAIT_TRUE (__is_floating_point, float); +//UNARY_TRAIT_TRUE (__is_floating_point, double); +//UNARY_TRAIT_TRUE (__is_floating_point, long double); +UNARY_TRAIT_DEFB (is_floating_point, __is_floating_point>::value); + +template struct __is_pointer : public false_type {}; +template struct __is_pointer : public true_type {}; +template struct is_pointer : public __is_pointer> {}; + +UNARY_TRAIT_DEFN (__is_member_pointer); +template struct __is_member_pointer : public true_type {}; +UNARY_TRAIT_DEFB (is_member_pointer, __is_member_pointer>::value); + +UNARY_TRAIT_DEFN (__is_member_function_pointer); +template struct __is_member_function_pointer : public true_type {}; +template struct __is_member_function_pointer : public true_type {}; +template +struct __is_member_function_pointer : public true_type {}; +template +struct __is_member_function_pointer : public true_type {}; +UNARY_TRAIT_DEFB (is_member_function_pointer, __is_member_function_pointer>::value); + +#endif // __clang__ + +UNARY_TRAIT_DEFB (is_unsigned, !is_signed::value); +UNARY_TRAIT_DEFB (is_member_object_pointer, is_member_pointer::value && !is_member_function_pointer::value); + +UNARY_TRAIT_DEFN (is_array); +UNARY_TRAIT_DEFN (is_lvalue_reference); +template struct is_lvalue_reference : public true_type {}; +UNARY_TRAIT_DEFN (is_rvalue_reference); +template struct is_rvalue_reference : public true_type {}; + +UNARY_TRAIT_DEFB (is_reference, is_lvalue_reference::value || is_rvalue_reference::value); + +template struct is_array : public true_type {}; +template struct is_array : public true_type {}; + +UNARY_TRAIT_DEFB (is_union, __is_union(T)); +UNARY_TRAIT_DEFB (is_class, __is_class(T)); +UNARY_TRAIT_DEFB (is_enum, __is_enum(T)); + +UNARY_TRAIT_DEFN (is_function); +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; +template struct is_function : public true_type { }; + +UNARY_TRAIT_DEFB (is_object, !is_reference::value && !is_void::value && !is_function::value); +UNARY_TRAIT_DEFB (__is_referenceable, is_reference::value || is_object::value); +template +struct __is_referenceable : public true_type {}; +template +struct __is_referenceable : public true_type {}; + +//}}}------------------------------------------------------------------- +//{{{ Composite type categories + +UNARY_TRAIT_DEFB (is_arithmetic, is_integral::value || is_floating_point::value); +UNARY_TRAIT_DEFB (is_fundamental, is_arithmetic::value || is_void::value); +UNARY_TRAIT_DEFB (is_scalar, is_arithmetic::value || is_enum::value || is_pointer::value || is_member_pointer::value); +UNARY_TRAIT_DEFB (is_compound, !is_fundamental::value); + +template ::value> struct __add_lvalue_reference { using type = T; }; +template struct __add_lvalue_reference { using type = T&; }; +template struct add_lvalue_reference : public __add_lvalue_reference {}; +template using add_lvalue_reference_t = typename add_lvalue_reference::type; + +template ::value> struct __add_rvalue_reference { using type = T; }; +template struct __add_rvalue_reference { using type = T&&; }; +template struct add_rvalue_reference : public __add_rvalue_reference {}; +template using add_rvalue_reference_t = typename add_rvalue_reference::type; + +/// Unusable default value for T. Use with decltype. +template add_rvalue_reference_t declval (void) noexcept; + +//}}}------------------------------------------------------------------- +//{{{ Type properties + +UNARY_TRAIT_DEFN (is_const); +template struct is_const : public true_type {}; +UNARY_TRAIT_DEFN (is_volatile); +template struct is_volatile : public true_type {}; + +UNARY_TRAIT_DEFB (is_empty, __is_empty(T)); +UNARY_TRAIT_DEFB (is_abstract, __is_abstract(T)); +UNARY_TRAIT_DEFB (is_literal_type, __is_literal_type(T)); +UNARY_TRAIT_DEFB (is_polymorphic, __is_polymorphic(T)); +#if HAVE_CPP14 +UNARY_TRAIT_DEFB (is_final, __is_final(T)); +#endif +UNARY_TRAIT_DEFB (is_standard_layout, __is_standard_layout(T)); +UNARY_TRAIT_DEFB (is_pod, __is_pod(T) || is_scalar::value || (is_array::value && is_scalar>::value)); +UNARY_TRAIT_DEFB (has_unique_object_representations, is_pod::value); +UNARY_TRAIT_DEFB (is_trivial, is_pod::value || __is_trivial(T)); +UNARY_TRAIT_DEFB (is_swappable, is_trivial::value); +UNARY_TRAIT_DEFB (is_nothrow_swappable, is_trivial::value); +UNARY_TRAIT_DEFB (has_trivial_copy, is_pod::value || __has_trivial_copy(T)); +UNARY_TRAIT_DEFB (has_trivial_assign, is_pod::value || __has_trivial_assign(T)); +UNARY_TRAIT_DEFB (has_trivial_constructor, is_pod::value || __has_trivial_constructor(T)); +UNARY_TRAIT_DEFB (has_trivial_destructor, is_pod::value || __has_trivial_destructor(T)); +UNARY_TRAIT_DEFB (has_virtual_destructor, __has_virtual_destructor(T)); +UNARY_TRAIT_DEFB (has_nothrow_assign, __has_nothrow_assign(T)); +UNARY_TRAIT_DEFB (has_nothrow_copy, __has_nothrow_copy(T)); +UNARY_TRAIT_DEFB (has_nothrow_constructor, __has_nothrow_constructor(T)); + +template struct alignment_of : public integral_constant {}; + +template struct rank : public integral_constant {}; +template struct rank : public integral_constant::value> {}; +template struct rank : public integral_constant::value> {}; + +template struct extent { static constexpr const size_t value = 0; }; +template struct extent { static constexpr const size_t value = I ? extent::value : 0; }; +template struct extent { static constexpr const size_t value = I ? extent::value : N; }; + +template ::value, bool IsFunction = is_function::value> struct __decay; +template struct __decay { using type = remove_cv_t; }; +template struct __decay { using type = remove_extent_t*; }; +template struct __decay { using type = add_pointer_t; }; +template struct decay : public __decay> {}; +template using decay_t = typename decay::type; + +template struct common_type; +template struct common_type { using type = decay_t; }; +template using common_type_t = typename common_type::type; +template struct common_type + { using type = decay_t() : declval())>; }; +template +struct common_type + { using type = common_type_t, V...>; }; + +//}}}------------------------------------------------------------------- +//{{{ Constructability and destructability + +// All these use the standard SFINAE technique +struct __is_destructible { + template ().~T())> static true_type test (int); + template static false_type test (...); +}; +template struct is_destructible : public decltype(__is_destructible::test(0)) {}; + +struct __is_nothrow_destructible { + template static integral_constant().~T())> test (int); + template static false_type test (...); +}; +template +struct is_nothrow_destructible : public decltype(__is_nothrow_destructible::test(0)) {}; + +struct __is_default_constructible { + template static true_type test (int); + template static false_type test (...); +}; +template struct is_default_constructible : public decltype(__is_default_constructible::test(0)) {}; + +struct __is_nothrow_default_constructible { + template static integral_constant test (int); + template static false_type test (...); +}; +template struct is_nothrow_default_constructible : public decltype(__is_nothrow_default_constructible::test(0)) {}; + +template struct is_constructible : public is_default_constructible {}; +template struct is_nothrow_constructible : public is_nothrow_default_constructible {}; + +struct __is_copy_constructible { + template ()))> static true_type test (int); + template static false_type test (...); +}; +template struct is_copy_constructible : public decltype(__is_copy_constructible::test(0)) {}; + +struct __is_move_constructible { + template ()))> static true_type test (int); + template static false_type test (...); +}; +template struct is_move_constructible : public decltype(__is_move_constructible::test(0)) {}; + +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 9) || __GNUC__ >= 8 +template struct is_assignable : public integral_constant {}; +#else +struct __is_assignable { + template () = declval())> static true_type test (int); + template static false_type test (...); +}; +template struct is_assignable : public decltype(__is_assignable::test(0)) {}; +#endif + +template struct is_copy_assignable : public is_assignable {}; +template struct is_move_assignable : public is_assignable {}; + +// TODO: later +template struct is_nothrow_copy_constructible : public false_type {}; +template struct is_nothrow_move_constructible : public false_type {}; +template struct is_nothrow_assignable : public false_type {}; +template struct is_nothrow_copy_assignable : public false_type {}; +template struct is_nothrow_move_assignable : public false_type {}; + +#if __GNUC__ >= 5 +UNARY_TRAIT_DEFB (is_trivially_copyable, __is_trivially_copyable(T)); +template +struct is_trivially_constructible : public integral_constant {}; + +template +struct is_trivially_copy_constructible : public + integral_constant::value + && __is_trivially_constructible(T, const T&)> {}; + +template +struct is_trivially_move_constructible : public + integral_constant::value + && __is_trivially_constructible(T, T&&)> {}; + +template +struct is_trivially_assignable : public integral_constant {}; + +UNARY_TRAIT_DEFB (is_trivially_default_constructible, __is_trivially_constructible(T)); +UNARY_TRAIT_DEFB (is_trivially_copy_assignable, __is_trivially_assignable(T,const T&)); +UNARY_TRAIT_DEFB (is_trivially_move_assignable, __is_trivially_assignable(T,T&&)); +#else +UNARY_TRAIT_DEFB (is_trivially_copyable, __has_trivial_copy(T)); +UNARY_TRAIT_DEFB (is_trivially_default_constructible, __has_trivial_constructor(T)); +UNARY_TRAIT_DEFB (is_trivially_copy_assignable, __has_trivial_assign(T)); +UNARY_TRAIT_DEFB (is_trivially_move_assignable, false); +#endif + +UNARY_TRAIT_DEFB (is_trivially_destructible, __has_trivial_destructor(T)); +UNARY_TRAIT_DEFB (has_trivial_copy_constructor, __has_trivial_copy(T)); +UNARY_TRAIT_DEFB (has_trivial_copy_assign, __has_trivial_assign(T)); + +//}}}------------------------------------------------------------------- +//{{{ Type relations + +template struct is_same : public false_type {}; +template struct is_same : public true_type {}; + +#if __clang__ // clang has __is_convertible builtin + +template +struct is_convertible : public integral_constant {}; + +#else + +template ::value || is_function::value || is_array::value> +class __is_convertible : public integral_constant::value> {}; +template +class __is_convertible { + template static void __test_aux(TT); + template (declval()))> + static true_type __test(int); + template static false_type __test(...); +public: + using type = decltype(__test(0)); +}; +template +struct is_convertible : public __is_convertible::type {}; + +#endif + +template struct is_swappable_with + : public integral_constant::value && is_convertible::value> {}; +template struct is_nothrow_swappable_with + : public integral_constant::value && is_convertible::value> {}; + +/// Defines a has_member_function_name template where has_member_function_name::value is true when O::name exists +/// Example: HAS_MEMBER_FUNCTION(read, void (O::*)(istream&)); has_member_function_read>::value == true +#define HAS_MEMBER_FUNCTION(name, signature) \ +template \ +class __has_member_function_##name { \ + template struct test_for_##name {};\ + template static true_type found (test_for_##name*);\ + template static false_type found (...);\ +public: \ + using type = decltype(found(nullptr)); \ +}; \ +template \ +struct has_member_function_##name : public __has_member_function_##name::type {} + +/// Defines a has_static_member_variable template where has_static_member_variable_name::value is true when O::name exists +/// Example: HAS_STATIC_MEMBER_VARIABLE(int, _val); has_static_member_variable__val::value == true +#define HAS_STATIC_MEMBER_VARIABLE(varT,name) \ +template \ +class __has_static_member_variable_##name { \ + template > V> struct test_for_##name {};\ + template static true_type found (test_for_##name*);\ + template static false_type found (...);\ +public: \ + using type = decltype(found(nullptr)); \ +}; \ +template \ +struct has_static_member_variable_##name : public __has_static_member_variable_##name::type {} + +template struct is_base_of { + static constexpr const bool value = __is_base_of(T,U); +}; +template struct is_base_of : public false_type {}; +template struct is_base_of : public false_type {}; + +template struct aligned_storage + { struct type { alignas(Grain) unsigned char _data[Size]; }; }; + +//}}}------------------------------------------------------------------- +//{{{ Helper templates and specs +#undef UNARY_TRAIT_DEFN +#undef UNARY_TRAIT_DEFB +#define POD_CLASS(T) namespace ustl { UNARY_TRAIT_TRUE(is_pod,T); } +//}}} + +} // namespace ustl +#endif // HAVE_CPP11 diff --git a/pwn/flipper/dist/common/include/ustl/utypes.h b/pwn/flipper/dist/common/include/ustl/utypes.h new file mode 100644 index 0000000..018329f --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/utypes.h @@ -0,0 +1,134 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "config.h" + +/* +#define __STDC_LIMIT_MACROS // For WCHAR_MIN and WCHAR_MAX in stdint. +#define __STDC_CONSTANT_MACROS // For UINT??_C macros to avoid using L and UL suffixes on constants. +#include "config.h" +#if HAVE_STDINT_H + #include +#elif HAVE_INTTYPES_H + #include +#else + #error "Need standard integer types definitions, usually in stdint.h" +#endif +#if HAVE_SYS_TYPES_H + #include +#endif +#include // For ptrdiff_t, size_t +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_ALLOCA_H + #include +#endif +#ifndef WITHOUT_LIBSTDCPP + #include + #include + #include + #if HAVE_CPP11 + #include + #endif +#endif +*/ +#ifndef SIZE_MAX + #define SIZE_MAX UINT_MAX +#endif +#if sun || __sun // Solaris defines UINTPTR_MAX as empty. + #undef UINTPTR_MAX + #define UINTPTR_MAX ULONG_MAX +#endif +#ifndef WCHAR_MAX + #ifdef __WCHAR_MAX__ + #define WCHAR_MAX __WCHAR_MAX__ + #else + #define WCHAR_MAX CHAR_MAX + #endif +#endif +#if HAVE_LONG_LONG + #ifndef LLONG_MAX + #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) + #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) + #define LLONG_MIN ULLONG_MAX + #endif +#endif +#ifndef BYTE_ORDER + #define LITTLE_ENDIAN USTL_LITTLE_ENDIAN + #define BIG_ENDIAN USTL_BIG_ENDIAN + #define BYTE_ORDER USTL_BYTE_ORDER +#endif + +//sweb added +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CHAR_MIN +#define CHAR_MIN 0 +#endif + +#ifndef CHAR_MAX +#define CHAR_MAX 0xFF +#endif + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xFF +#endif + +#define CHAR_BIT 8 +#define DBL_MAX 0 +#define DBL_MIN 0 +#define FLT_MAX 0 +#define FLT_MIN 0 +#define INT_MAX 0xFFFFFFFF +#define INT_MIN 0 +#define LONG_MAX 0 +#define LONG_MIN 0 +#define UINTPTR_MAX 0xFFFFFFFF +#define SHRT_MAX 0 +#define SHRT_MIN 0 +#define LDBL_MAX 0 +#define LDBL_MIN 0 +#define UINT_MAX 0xFFFFFFFF +#define INT_MIN 0 +#define ULONG_MAX 0xFFFFFFFF +#define USHRT_MAX 0xFFFF + +#include "types.h" + +typedef uint64 uint64_t; +typedef int64 int64_t; +typedef uint32 uint32_t; +typedef int32 int32_t; +typedef uint16 uint16_t; +typedef int16 int16_t; +typedef uint8 uint8_t; +typedef int8 int8_t; +typedef ssize_t ptrdiff_t; +typedef ssize_t off_t; + +typedef size_t uoff_t; ///< A type for storing offsets into blocks measured by size_t. +typedef uint32_t hashvalue_t; ///< Value type returned by the hash functions. +typedef size_t streamsize; ///< Size of stream data +typedef uoff_t streamoff; ///< Offset into a stream + +typedef size_t uintptr_t; +typedef ssize_t intptr_t; +/* +#if !defined(UINTPTR_MAX) || !defined(UINT32_C) + #error "If you include stdint.h before ustl.h, define __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS first" +#endif*/ +#if WANT_ALWAYS_INLINE + #define inline INLINE inline +#endif diff --git a/pwn/flipper/dist/common/include/ustl/uutility.h b/pwn/flipper/dist/common/include/ustl/uutility.h new file mode 100644 index 0000000..3adf7db --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uutility.h @@ -0,0 +1,449 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. +// +/// \file uutility.h +/// \brief Utility templates. + +#pragma once +#include "utypes.h" +#include "ulimits.h" +#include "assert.h" + +namespace ustl { + +#if HAVE_CPP11 + using nullptr_t = decltype(nullptr); + using max_align_t = uintptr_t; +#endif + +#if __GNUC__ + /// Returns the number of elements in a static vector + #define VectorSize(v) (sizeof(v) / sizeof(*v)) +#else + // Old compilers will not be able to evaluate *v on an empty vector. + // The tradeoff here is that VectorSize will not be able to measure arrays of local structs. + #define VectorSize(v) (sizeof(v) / ustl::size_of_elements(1, v)) +#endif + +/// Returns the end() for a static vector +template inline constexpr T* VectorEnd (T(&a)[N]) { return &a[N]; } + +/// Expands into a ptr,size expression for the given static vector; useful as link arguments. +#define VectorBlock(v) &(v)[0], VectorSize(v) +/// Expands into a begin,end expression for the given static vector; useful for algorithm arguments. +#define VectorRange(v) &(v)[0], VectorEnd(v) + +/// Returns the number of bits in the given type +#define BitsInType(t) (sizeof(t) * CHAR_BIT) + +/// Returns the mask of type \p t with the lowest \p n bits set. +#define BitMask(t,n) (t(~t(0)) >> (BitsInType(t) - (n))) + +/// Argument that is used only in debug builds (as in an assert) +#ifndef NDEBUG + #define DebugArg(x) x +#else + #define DebugArg(x) +#endif + +/// Shorthand for container iteration. +#define foreach(type,i,ctr) for (type i = (ctr).begin(); i != (ctr).end(); ++ i) +/// Shorthand for container reverse iteration. +#define eachfor(type,i,ctr) for (type i = (ctr).rbegin(); i != (ctr).rend(); ++ i) + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +// Macro for passing template types as macro arguments. +// These are deprecated. Use metamac macros instead. Will remove by next release. +#define TEMPLATE_FULL_DECL1(d1,t1) template +#define TEMPLATE_FULL_DECL2(d1,t1,d2,t2) template +#define TEMPLATE_FULL_DECL3(d1,t1,d2,t2,d3,t3) template +#define TEMPLATE_DECL1(t1) TEMPLATE_FULL_DECL1(typename,t1) +#define TEMPLATE_DECL2(t1,t2) TEMPLATE_FULL_DECL2(typename,t1,typename,t2) +#define TEMPLATE_DECL3(t1,t2,t3) TEMPLATE_FULL_DECL3(typename,t1,typename,t2,typename,t3) +#define TEMPLATE_TYPE1(type,a1) type +#define TEMPLATE_TYPE2(type,a1,a2) type +#define TEMPLATE_TYPE3(type,a1,a2,a3) type +#endif + +/// Returns the minimum of \p a and \p b +template +inline constexpr T1 min (const T1& a, const T2& b) +{ + return a < b ? a : b; +} + +/// Returns the maximum of \p a and \p b +template +inline constexpr T1 max (const T1& a, const T2& b) +{ + return b < a ? a : b; +} + +/// Indexes into a static array with bounds limit +template +inline constexpr T& VectorElement (T(&v)[N], size_t i) { return v[min(i,N-1)]; } + +/// The alignment performed by default. +const size_t c_DefaultAlignment = __alignof__(void*); + +/// \brief Rounds \p n up to be divisible by \p grain +template +inline constexpr T AlignDown (T n, size_t grain = c_DefaultAlignment) + { return n - n % grain; } + +/// \brief Rounds \p n up to be divisible by \p grain +template +inline constexpr T Align (T n, size_t grain = c_DefaultAlignment) + { return AlignDown (n + grain - 1, grain); } + +/// Returns a nullptr pointer cast to T. +template +inline constexpr T* NullPointer (void) + { return nullptr; } + +/// \brief Returns a non-dereferentiable value reference. +/// This is useful for passing to stream_align_of or the like which need a value but +/// don't need to actually use it. +template +inline constexpr T& NullValue (void) + { return *NullPointer(); } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +// Offsets a pointer +template +inline T advance_ptr (T i, ptrdiff_t offset) + { return i + offset; } + +// Offsets a void pointer +template <> +inline const void* advance_ptr (const void* p, ptrdiff_t offset) +{ + assert (p || !offset); + return reinterpret_cast(p) + offset; +} + +// Offsets a void pointer +template <> +inline void* advance_ptr (void* p, ptrdiff_t offset) +{ + assert (p || !offset); + return reinterpret_cast(p) + offset; +} +#endif + +/// Offsets an iterator +template +inline T advance (T i, Distance offset) + { return advance_ptr (i, offset); } + +/// Returns the difference \p p1 - \p p2 +template +inline constexpr ptrdiff_t distance (T1 i1, T2 i2) +{ + return i2 - i1; +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#define UNVOID_DISTANCE(T1const,T2const) \ +template <> inline constexpr ptrdiff_t distance (T1const void* p1, T2const void* p2) \ +{ return static_cast(p2) - static_cast(p1); } +UNVOID_DISTANCE(,) +UNVOID_DISTANCE(const,const) +UNVOID_DISTANCE(,const) +UNVOID_DISTANCE(const,) +#undef UNVOID_DISTANCE +#endif + +template +T* addressof (T& v) + { return reinterpret_cast(&const_cast(reinterpret_cast(v))); } + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +// The compiler issues a warning if an unsigned type is compared to 0. +template struct __is_negative { inline constexpr bool operator()(const T& v) const { return v < 0; } }; +template struct __is_negative { inline constexpr bool operator()(const T&) const { return false; } }; +/// Warning-free way to check if \p v is negative, even if for unsigned types. +template inline constexpr bool is_negative (const T& v) { return __is_negative::is_signed>()(v); } +#endif + +/// \brief Returns the absolute value of \p v +/// Unlike the stdlib functions, this is inline and works with all types. +template +inline constexpr T absv (T v) +{ + return is_negative(v) ? -v : v; +} + +/// \brief Returns -1 for negative values, 1 for positive, and 0 for 0 +template +inline constexpr T sign (T v) +{ + return (0 < v) - is_negative(v); +} + +/// Returns the absolute value of the distance i1 and i2 +template +inline constexpr size_t abs_distance (T1 i1, T2 i2) +{ + return absv (distance(i1, i2)); +} + +/// Returns the size of \p n elements of size \p T +template +inline constexpr size_t size_of_elements (size_t n, const T*) +{ + return n * sizeof(T); +} + +/// Returns the greatest common divisor +template +constexpr T gcd (T a, T b) +{ + return b ? gcd(b,a%b) : absv(a); +} + +/// Returns the least common multiple +template +constexpr T lcm (T a, T b) +{ + return a/gcd(a,b)*b; +} + +// Defined in byteswap.h, which is usually unusable. +#undef bswap_16 +#undef bswap_32 +#undef bswap_64 + +inline uint16_t bswap_16 (uint16_t v) +{ +#if __x86__ + if (!__builtin_constant_p(v)) asm ("rorw $8, %0":"+r"(v)); else +#endif + v = v << 8 | v >> 8; + return v; +} +inline uint32_t bswap_32 (uint32_t v) +{ +#if __x86__ + if (!__builtin_constant_p(v)) asm ("bswap %0":"+r"(v)); else +#endif + v = v << 24 | (v & 0xFF00) << 8 | ((v >> 8) & 0xFF00) | v >> 24; + return v; +} +#if HAVE_INT64_T +inline uint64_t bswap_64 (uint64_t v) +{ +#if __x86_64__ + if (!__builtin_constant_p(v)) asm ("bswap %0":"+r"(v)); else +#endif + v = (uint64_t(bswap_32(v)) << 32) | bswap_32(v >> 32); + return v; +} +#endif + +/// \brief Swaps the byteorder of \p v. +template +inline T bswap (const T& v) +{ + switch (BitsInType(T)) { + default: return v; + case 16: return T (bswap_16 (uint16_t (v))); + case 32: return T (bswap_32 (uint32_t (v))); +#if HAVE_INT64_T + case 64: return T (bswap_64 (uint64_t (v))); +#endif + } +} + +#if BYTE_ORDER == BIG_ENDIAN +template inline T le_to_native (const T& v) { return bswap (v); } +template inline T be_to_native (const T& v) { return v; } +template inline T native_to_le (const T& v) { return bswap (v); } +template inline T native_to_be (const T& v) { return v; } +#elif BYTE_ORDER == LITTLE_ENDIAN +template inline T le_to_native (const T& v) { return v; } +template inline T be_to_native (const T& v) { return bswap (v); } +template inline T native_to_le (const T& v) { return v; } +template inline T native_to_be (const T& v) { return bswap (v); } +#endif // BYTE_ORDER + +/// Deletes \p p and sets it to nullptr +template +inline void Delete (T*& p) +{ + delete p; + p = nullptr; +} + +/// Deletes \p p as an array and sets it to nullptr +template +inline void DeleteVector (T*& p) +{ + delete [] p; + p = nullptr; +} + +/// Template of making != from ! and == +template +inline constexpr bool operator!= (const T& x, const T& y) + { return !(x == y); } + +/// Template of making > from < +template +inline constexpr bool operator> (const T& x, const T& y) + { return y < x; } + +/// Template of making <= from < and == +template +inline constexpr bool operator<= (const T& x, const T& y) + { return !(y < x); } + +/// Template of making >= from < and == +template +inline constexpr bool operator>= (const T& x, const T& y) + { return !(x < y); } + +/// Packs \p s multiple times into \p b. Useful for loop unrolling. +template +inline void pack_type (TSmall s, TBig& b) +{ + b = s; + for (unsigned h = BitsInType(TSmall); h < BitsInType(TBig); h *= 2) + b = (b << h)|b; +} + +/// \brief Divides \p n1 by \p n2 and rounds the result up. +/// This is in contrast to regular division, which rounds down. +template +inline T1 DivRU (T1 n1, T2 n2) +{ + T2 adj = n2 - 1; + if (is_negative (n1)) + adj = -adj; + return (n1 + adj) / n2; +} + +/// Sets the contents of \p pm to 1 and returns true if the previous value was 0. +inline bool TestAndSet (int* pm) +{ +#if __x86__ + int oldVal (1); + asm volatile ("xchgl %0, %1" : "=r"(oldVal), "=m"(*pm) : "0"(oldVal), "m"(*pm) : "memory"); + return !oldVal; +#elif __sparc32__ // This has not been tested + int rv; + asm volatile ("ldstub %1, %0" : "=r"(rv), "=m"(*pm) : "m"(pm)); + return !rv; +#else + const int oldVal (*pm); + *pm = 1; + return !oldVal; +#endif +} + +/// Returns the index of the first set bit in \p v or \p nbv if none. +inline uoff_t FirstBit (uint32_t v, uoff_t nbv) +{ + uoff_t n = nbv; +#if __x86__ + if (!__builtin_constant_p(v)) asm ("bsr\t%1, %k0":"+r,r"(n):"r,m"(v)); else +#endif +#if __GNUC__ + if (v) n = 31 - __builtin_clz(v); +#else + if (v) for (uint32_t m = uint32_t(1)<<(n=31); !(v & m); m >>= 1) --n; +#endif + return n; +} +/// Returns the index of the first set bit in \p v or \p nbv if none. +inline uoff_t FirstBit (uint64_t v, uoff_t nbv) +{ + uoff_t n = nbv; +#if __x86_64__ + if (!__builtin_constant_p(v)) asm ("bsr\t%1, %0":"+r,r"(n):"r,m"(v)); else +#endif +#if __GNUC__ && SIZE_OF_LONG >= 8 + if (v) n = 63 - __builtin_clzl(v); +#elif __GNUC__ && HAVE_LONG_LONG && SIZE_OF_LONG_LONG >= 8 + if (v) n = 63 - __builtin_clzll(v); +#else + if (v) for (uint64_t m = uint64_t(1)<<(n=63); !(v & m); m >>= 1) --n; +#endif + return n; +} + +/// Returns the next power of 2 >= \p v. +/// Values larger than UINT32_MAX/2 will return 2^0 +inline uint32_t NextPow2 (uint32_t v) +{ + uint32_t r = v-1; +#if __x86__ + if (!__builtin_constant_p(r)) asm("bsr\t%0, %0":"+r"(r)); else +#endif + { r = FirstBit(r,r); if (r >= BitsInType(r)-1) r = uint32_t(-1); } + return 1<<(1+r); +} + +/// Bitwise rotate value left +template +inline T Rol (T v, size_t n) +{ +#if __x86__ + if (!(__builtin_constant_p(v) && __builtin_constant_p(n))) asm("rol\t%b1, %0":"+r,r"(v):"i,c"(n)); else +#endif + v = (v << n) | (v >> (BitsInType(T)-n)); + return v; +} + +/// Bitwise rotate value right +template +inline T Ror (T v, size_t n) +{ +#if __x86__ + if (!(__builtin_constant_p(v) && __builtin_constant_p(n))) asm("ror\t%b1, %0":"+r,r"(v):"i,c"(n)); else +#endif + v = (v >> n) | (v << (BitsInType(T)-n)); + return v; +} + +/// \brief This template is to be used for dereferencing a type-punned pointer without a warning. +/// +/// When casting a local variable to an unrelated type through a pointer (for +/// example, casting a float to a uint32_t without conversion), the resulting +/// memory location can be accessed through either pointer, which violates the +/// strict aliasing rule. While -fno-strict-aliasing option can be given to +/// the compiler, eliminating this warning, inefficient code may result in +/// some instances, because aliasing inhibits some optimizations. By using +/// this template, and by ensuring the memory is accessed in one way only, +/// efficient code can be produced without the warning. For gcc 4.1.0+. +/// +template +inline DEST noalias (const DEST&, SRC* s) +{ + asm("":"+g"(s)::"memory"); + union UPun { SRC s; DEST d; }; + return reinterpret_cast(s)->d; +} + +template +inline DEST noalias_cast (SRC s) +{ + asm("":"+g"(s)::"memory"); + union { SRC s; DEST d; } u = {s}; + return u.d; +} + +namespace simd { + /// Call after you are done using SIMD algorithms for 64 bit tuples. + #define ALL_MMX_REGS_CHANGELIST "mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7","st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)" +#if __3DNOW__ + inline void reset_mmx (void) { asm ("femms":::ALL_MMX_REGS_CHANGELIST); } +#elif __MMX__ + inline void reset_mmx (void) { asm ("emms":::ALL_MMX_REGS_CHANGELIST); } +#else + inline void reset_mmx (void) {} +#endif +} // namespace simd +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/ustl/uvector.h b/pwn/flipper/dist/common/include/ustl/uvector.h new file mode 100644 index 0000000..cb88bbc --- /dev/null +++ b/pwn/flipper/dist/common/include/ustl/uvector.h @@ -0,0 +1,349 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#pragma once +#include "memblock.h" +#include "umemory.h" +#include "upredalgo.h" + +namespace ustl { + +/// \class vector uvector.h ustl.h +/// \ingroup Sequences +/// +/// \brief STL vector equivalent. +/// +/// Provides a typed array-like interface to a managed memory block, including +/// element access, iteration, modification, resizing, and serialization. In +/// this design elements frequently undergo bitwise move, so don't put it in +/// here if it doesn't support it. This mostly means having no self-pointers. +/// +template +class vector { +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef memblock::size_type size_type; + typedef memblock::written_size_type written_size_type; + typedef memblock::difference_type difference_type; + typedef ::ustl::reverse_iterator reverse_iterator; + typedef ::ustl::reverse_iterator const_reverse_iterator; +public: + inline vector (void); + inline explicit vector (size_type n); + vector (size_type n, const T& v); + vector (const vector& v); + vector (const_iterator i1, const_iterator i2); + inline ~vector (void) noexcept; + inline const vector& operator= (const vector& v); + inline bool operator== (const vector& v) const { return _data == v._data; } + inline operator cmemlink (void) const { return cmemlink (_data); } + inline operator cmemlink (void) { return cmemlink (_data); } + inline operator memlink (void) { return memlink (_data); } + inline void reserve (size_type n, bool bExact = false); + inline void resize (size_type n); + void resize (size_type n, const_reference v); + inline size_type capacity (void) const { return _data.capacity() / sizeof(T); } + inline size_type size (void) const { return _data.size() / sizeof(T); } + inline size_type max_size (void) const { return _data.max_size() / sizeof(T); } + inline bool empty (void) const { return _data.empty(); } + inline iterator begin (void) { return iterator (_data.begin()); } + inline const_iterator begin (void) const { return const_iterator (_data.begin()); } + inline iterator end (void) { return iterator (_data.end()); } + inline const_iterator end (void) const { return const_iterator (_data.end()); } + inline const_iterator cbegin (void) const { return begin(); } + inline const_iterator cend (void) const { return end(); } + inline reverse_iterator rbegin (void) { return reverse_iterator (end()); } + inline const_reverse_iterator rbegin (void) const { return const_reverse_iterator (end()); } + inline reverse_iterator rend (void) { return reverse_iterator (begin()); } + inline const_reverse_iterator rend (void) const { return const_reverse_iterator (begin()); } + inline const_reverse_iterator crbegin (void) const { return rbegin(); } + inline const_reverse_iterator crend (void) const { return rend(); } + inline pointer data (void) { return pointer (_data.data()); } + inline const_pointer data (void) const { return const_pointer (_data.data()); } + inline const_pointer cdata (void) const { return const_pointer (_data.cdata()); } + inline iterator iat (size_type i) { assert (i <= size()); return begin() + i; } + inline const_iterator iat (size_type i) const { assert (i <= size()); return begin() + i; } + inline reference at (size_type i) { assert (i < size()); return begin()[i]; } + inline const_reference at (size_type i) const { assert (i < size()); return begin()[i]; } + inline reference operator[] (size_type i) { return at (i); } + inline const_reference operator[] (size_type i) const { return at (i); } + inline reference front (void) { return at(0); } + inline const_reference front (void) const { return at(0); } + inline reference back (void) { assert (!empty()); return end()[-1]; } + inline const_reference back (void) const { assert (!empty()); return end()[-1]; } + inline void push_back (const T& v = T()); + inline void pop_back (void) { size_type nsz = _data.size()-sizeof(T); destroy (iterator(_data.begin()+nsz)); _data.memlink::resize (nsz); } + inline void clear (void) { destroy_all(); _data.clear(); } + inline void shrink_to_fit (void) { _data.shrink_to_fit(); } + inline void deallocate (void) noexcept; + inline void assign (const_iterator i1, const_iterator i2); + inline void assign (size_type n, const T& v); + inline void swap (vector& v) { _data.swap (v._data); } + inline iterator insert (const_iterator ip, const T& v); + inline iterator insert (const_iterator ip, size_type n, const T& v); + inline iterator insert (const_iterator ip, const_iterator i1, const_iterator i2); + inline iterator erase (const_iterator ep, size_type n = 1); + inline iterator erase (const_iterator ep1, const_iterator ep2); + inline void manage (pointer p, size_type n) { _data.manage (p, n * sizeof(T)); } + inline bool is_linked (void) const { return _data.is_linked(); } + inline void unlink (void) { _data.unlink(); } + inline void copy_link (void) { _data.copy_link(); } + inline void link (const_pointer p, size_type n) { _data.link (p, n * sizeof(T)); } + inline void link (pointer p, size_type n) { _data.link (p, n * sizeof(T)); } + inline void link (const vector& v) { _data.link (v); } + inline void link (vector& v) { _data.link (v); } + inline void link (const_pointer first, const_pointer last) { _data.link (first, last); } + inline void link (pointer first, pointer last) { _data.link (first, last); } + //inline void read (istream& is) { container_read (is, *this); } + //inline void write (ostream& os) const { container_write (os, *this); } + //inline void text_write (ostringstream& os) const { container_text_write (os, *this); } + inline size_t stream_size (void) const { return container_stream_size (*this); } +#if HAVE_CPP11 + inline vector (vector&& v) : _data(move(v._data)) {} + inline vector (std::initializer_list v) : _data() { uninitialized_copy_n (v.begin(), v.size(), append_hole(v.size())); } + inline vector& operator= (vector&& v) { swap (v); return *this; } + template + inline iterator emplace (const_iterator ip, Args&&... args); + template + inline void emplace_back (Args&&... args); + inline void push_back (T&& v) { emplace_back (move(v)); } + inline iterator insert (const_iterator ip, T&& v) { return emplace (ip, move(v)); } + inline iterator insert (const_iterator ip, std::initializer_list v) { return insert (ip, v.begin(), v.end()); } +#endif +protected: + inline iterator insert_space (const_iterator ip, size_type n); +private: + inline iterator insert_hole (const_iterator ip, size_type n); + inline iterator append_hole (size_type n); + void destroy_all (void) + { if (!is_linked()) destroy (begin(), end()); } +private: + memblock _data; ///< Raw element data, consecutively stored. +}; + +/// Allocates space for at least \p n elements. +template +inline void vector::reserve (size_type n, bool bExact) +{ + _data.reserve (n*sizeof(T), bExact); +} + +template +inline typename vector::iterator vector::append_hole (size_type n) +{ + size_type nsz = _data.size() + n*sizeof(T); + _data.reserve (nsz); + iterator hp = end(); + _data.memlink::resize (nsz); + return hp; +} + +/// Resizes the vector to contain \p n elements. +template +void vector::resize (size_type n) +{ + size_type nb = n*sizeof(T); + _data.reserve (nb); + iterator inewend = iterator(_data.begin()+nb); + if (nb < _data.size()) + destroy (inewend, end()); + else + uninitialized_default_construct (end(), inewend); + _data.memlink::resize (nb); +} + +/// Resizes the vector to contain \p n elements. +template +void vector::resize (size_type n, const_reference v) +{ + size_type nb = n*sizeof(T); + _data.reserve (nb); + iterator inewend = iterator(_data.begin()+nb); + if (nb < _data.size()) + destroy (inewend, end()); + else + uninitialized_fill (end(), inewend, v); + _data.memlink::resize (nb); +} + +/// Calls element destructors and frees storage. +template +inline void vector::deallocate (void) noexcept +{ + destroy_all(); + _data.deallocate(); +} + +/// Initializes empty vector. +template +inline vector::vector (void) +:_data() +{ +} + +/// Initializes a vector of size \p n. +template +inline vector::vector (size_type n) +:_data() +{ + resize (n); +} + +/// Copies \p n elements from \p v. +template +vector::vector (size_type n, const T& v) +:_data() +{ + uninitialized_fill_n (append_hole (n), n, v); +} + +/// Copies \p v. +template +vector::vector (const vector& v) +:_data() +{ + uninitialized_copy_n (v.begin(), v.size(), append_hole(v.size())); +} + +/// Copies range [\p i1, \p i2] +template +vector::vector (const_iterator i1, const_iterator i2) +:_data() +{ + uninitialized_copy (i1, i2, append_hole(distance(i1,i2))); +} + +/// Destructor +template +inline vector::~vector (void) noexcept +{ + destroy_all(); +} + +/// Copies the range [\p i1, \p i2] +template +inline void vector::assign (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + resize (distance (i1, i2)); + ::ustl::copy (i1, i2, begin()); +} + +/// Copies \p n elements with value \p v. +template +inline void vector::assign (size_type n, const T& v) +{ + resize (n); + ::ustl::fill (begin(), end(), v); +} + +/// Copies contents of \p v. +template +inline const vector& vector::operator= (const vector& v) +{ + assign (v.begin(), v.end()); + return *this; +} + +/// Inserts \p n uninitialized elements at \p ip. +template +inline typename vector::iterator vector::insert_hole (const_iterator ip, size_type n) +{ + const uoff_t ipmi = distance (_data.begin(), memblock::const_iterator(ip)); + reserve (size() + n); + return iterator (_data.insert (_data.iat(ipmi), n * sizeof(T))); +} + +/// Inserts \p n uninitialized elements at \p ip. +template +inline typename vector::iterator vector::insert_space (const_iterator ip, size_type n) +{ + iterator ih = insert_hole (ip, n); + uninitialized_default_construct_n (ih, n); + return ih; +} + +/// Inserts \p n elements with value \p v at offsets \p ip. +template +inline typename vector::iterator vector::insert (const_iterator ip, size_type n, const T& v) +{ + iterator d = insert_hole (ip, n); + uninitialized_fill_n (d, n, v); + return d; +} + +/// Inserts value \p v at offset \p ip. +template +inline typename vector::iterator vector::insert (const_iterator ip, const T& v) +{ + iterator d = insert_hole (ip, 1); + construct_at (d, v); + return d; +} + +/// Inserts range [\p i1, \p i2] at offset \p ip. +template +inline typename vector::iterator vector::insert (const_iterator ip, const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + iterator d = insert_hole (ip, distance (i1, i2)); + uninitialized_copy (i1, i2, d); + return d; +} + +/// Removes \p count elements at offset \p ep. +template +inline typename vector::iterator vector::erase (const_iterator ep, size_type n) +{ + iterator d = const_cast(ep); + destroy_n (d, n); + return iterator (_data.erase (memblock::iterator(d), n * sizeof(T))); +} + +/// Removes elements from \p ep1 to \p ep2. +template +inline typename vector::iterator vector::erase (const_iterator ep1, const_iterator ep2) +{ + assert (ep1 <= ep2); + return erase (ep1, distance(ep1, ep2)); +} + +/// Inserts value \p v at the end of the vector. +template +inline void vector::push_back (const T& v) +{ + construct_at (append_hole(1), v); +} + +#if HAVE_CPP11 + +/// Constructs value at \p ip +template +template +inline typename vector::iterator vector::emplace (const_iterator ip, Args&&... args) +{ + return new (insert_hole(ip,1)) T (forward(args)...); +} + +/// Constructs value at the end of the vector. +template +template +inline void vector::emplace_back (Args&&... args) +{ + new (append_hole(1)) T (forward(args)...); +} + +#endif + +/// Use with vector classes to allocate and link to stack space. \p n is in elements. +#define typed_alloca_link(m,T,n) (m).link ((T*) alloca ((n) * sizeof(T)), (n)) + +} // namespace ustl diff --git a/pwn/flipper/dist/common/include/util/Bitmap.h b/pwn/flipper/dist/common/include/util/Bitmap.h new file mode 100644 index 0000000..3ed5b3e --- /dev/null +++ b/pwn/flipper/dist/common/include/util/Bitmap.h @@ -0,0 +1,67 @@ +#pragma once + +#include "types.h" + +#define BITMAP_BYTE_COUNT(number_of_bits) (number_of_bits / Bitmap::bits_per_bitmap_atom_ + ((number_of_bits % Bitmap::bits_per_bitmap_atom_ > 0) ? 1 : 0)) + +class Bitmap +{ + public: + + static uint8 const bits_per_bitmap_atom_; + + Bitmap(size_t number_of_bits); + Bitmap(const Bitmap &bm); + ~Bitmap(); + + bool setBit(size_t bit_number); + static bool setBit(uint8* b, size_t& num_bits_set, size_t bit_number); + + bool getBit(size_t bit_number); + static bool getBit(uint8* b, size_t bit_number); + + bool unsetBit(size_t bit_number); + static bool unsetBit(uint8* b, size_t& num_bits_set, size_t bit_number); + + size_t getSize(); + + /** + * returns the number of bits set + * @return the number of bits set + */ + size_t getNumBitsSet(); + + /** + * returns the number of unset bits + * @return the number of unset bits + */ + size_t getNumFreeBits(); + + /** + * prints the bitmap using kprintfd + */ + void bmprint(); + static void bmprint(uint8* b, size_t n, size_t num_bits_set); + + /** + * sets a whole byte in the bitmap + * only use if you know what you are doing + * @param byte_number the number of the byte to set + * @param byte the byte to set + */ + void setByte(size_t byte_number, uint8 byte); + + /** + * returns a whole byte of a given number + * only use if you know what you are doing + * @param byte_number the number of the byte to return + * @return the byte + */ + uint8 getByte(size_t byte_number); + + private: + size_t size_; + size_t num_bits_set_; + uint8 *bitmap_; +}; + diff --git a/pwn/flipper/dist/common/include/util/FiFo.h b/pwn/flipper/dist/common/include/util/FiFo.h new file mode 100644 index 0000000..8df5ceb --- /dev/null +++ b/pwn/flipper/dist/common/include/util/FiFo.h @@ -0,0 +1,183 @@ +#pragma once + +#include "kprintf.h" +#include "new.h" +#include "Mutex.h" +#include "Condition.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __cplusplus +} +#endif + +#define FIFO_NOBLOCK_PUT 1 +#define FIFO_NOBLOCK_PUT_OVERWRITE_OLD 2 + +template +class FiFo +{ + public: + + /** + * Constructor + * @param inputb_size the buffer size (default 512) + * @param flags FIFO_NOBLOCK_PUT or FIFO_NOBLOCK_PUT_OVERWRITE_OLD (default none) + * @return + */ + FiFo(uint32 inputb_size = 512, uint8 flags = 0); + + ~FiFo(); + + /** + * Puts the given parameter in the fifo buffer. + * @param c the parameter to put + */ + void put(T c); + + /** + * Returns a element from the fifo buffer + * @return the element + */ + T get(); + + /** + * Returns if there is a next element in the buffer and stores it in the given parameter. + * @param c the paramter to store the element in + * @return true if there is a next element + */ + bool peekAhead(T &c); + + /** + * Returns the number of elements in the fifo buffer. + * @return the number of elements + */ + uint32 countElementsAhead(); + + void clear(); + + private: + Mutex input_buffer_lock_; + Condition something_to_read_; + Condition space_to_write_; + + uint32 input_buffer_size_; + T *input_buffer_; + uint32 ib_write_pos_; + uint32 ib_read_pos_; + + uint8 flags_; +}; + +template +FiFo::FiFo(uint32 inputb_size, uint8 flags) : + input_buffer_lock_("FiFo input_buffer_lock_"), something_to_read_(&input_buffer_lock_, "FiFo::something_to_read_"), + space_to_write_(&input_buffer_lock_, "FiFo::space_to_write_") +{ + if (inputb_size < 2) + input_buffer_size_ = 512; + else + input_buffer_size_ = inputb_size; + + input_buffer_ = new T[input_buffer_size_]; + ib_write_pos_ = 1; + ib_read_pos_ = 0; + flags_ = flags; +} + +template +FiFo::~FiFo() +{ + delete[] input_buffer_; +} + +//only put uses the fallback buffer -> so it doesn't need a lock +//input_buffer could be in use -> so if locked use fallback +template +void FiFo::put(T c) +{ + input_buffer_lock_.acquire(); + if (ib_write_pos_ == ib_read_pos_) + { + if (flags_ & FIFO_NOBLOCK_PUT) + { + if (flags_ & FIFO_NOBLOCK_PUT_OVERWRITE_OLD) + ib_read_pos_ = (ib_read_pos_ + 1) % input_buffer_size_; //move read pos ahead of us + else + { + input_buffer_lock_.release(); + return; + } + } + else + while (ib_write_pos_ == ib_read_pos_) + space_to_write_.wait(); + } + something_to_read_.signal(); + input_buffer_[ib_write_pos_++] = c; + ib_write_pos_ %= input_buffer_size_; + input_buffer_lock_.release(); +} + +template +void FiFo::clear(void) +{ + input_buffer_lock_.acquire(); + ib_write_pos_ = 1; + ib_read_pos_ = 0; + input_buffer_lock_.release(); +} + +//now this routine could get preempted +template +T FiFo::get() +{ + T ret = 0; + input_buffer_lock_.acquire(); + + while (ib_write_pos_ == ((ib_read_pos_ + 1) % input_buffer_size_)) //nothing new to read + something_to_read_.wait(); //this implicates release & acquire + + space_to_write_.signal(); + ib_read_pos_ = (ib_read_pos_ + 1) % input_buffer_size_; + ret = input_buffer_[ib_read_pos_]; + + input_buffer_lock_.release(); + return ret; +} + +//now this routine could get preempted +template +bool FiFo::peekAhead(T &ret) +{ + input_buffer_lock_.acquire(); + + if (ib_write_pos_ == ((ib_read_pos_ + 1) % input_buffer_size_)) //nothing new to read + { + input_buffer_lock_.release(); + return false; + } + + ret = input_buffer_[(ib_read_pos_ + 1) % input_buffer_size_]; + input_buffer_lock_.release(); + return true; +} + +template +uint32 FiFo::countElementsAhead() +{ + input_buffer_lock_.acquire(); + uint32 count = ib_write_pos_ - ib_read_pos_; + input_buffer_lock_.release(); + if (count == 0) + return input_buffer_size_; + else if (count > 0) + return (count - 1); + else + // count < 0 + return (input_buffer_size_ + count); +} + diff --git a/pwn/flipper/dist/common/include/util/RingBuffer.h b/pwn/flipper/dist/common/include/util/RingBuffer.h new file mode 100644 index 0000000..cb96557 --- /dev/null +++ b/pwn/flipper/dist/common/include/util/RingBuffer.h @@ -0,0 +1,79 @@ +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __cplusplus +} +#endif + +#include "new.h" +#include "ArchThreads.h" +#include "assert.h" + +template +class RingBuffer +{ + public: + RingBuffer ( uint32 size=128 ); + ~RingBuffer(); + bool get ( T &c ); + void put ( T c ); + void clear(); + + private: + + size_t buffer_size_; + T *buffer_; + size_t write_pos_; + size_t read_pos_; +}; + +template +RingBuffer::RingBuffer ( uint32 size ) +{ + assert ( size>1 ); + buffer_size_=size; + buffer_=new T[buffer_size_]; + write_pos_=1; + read_pos_=0; +} + +template +RingBuffer::~RingBuffer() +{ + delete[] buffer_; +} + +template +void RingBuffer::put ( T c ) +{ + size_t old_write_pos=write_pos_; + if ( old_write_pos == read_pos_ ) + return; + buffer_[old_write_pos]=c; + ArchThreads::testSetLock ( write_pos_, ( old_write_pos + 1 ) % buffer_size_ ); +} + +template +void RingBuffer::clear() +{ + ArchThreads::testSetLock ( write_pos_,1 ); + // assumed that there is only one reader who can't have called clear and get at the same time. + // here get would return garbage. + ArchThreads::testSetLock ( read_pos_,0 ); +} + +template +bool RingBuffer::get ( T &c ) +{ + uint32 new_read_pos = ( read_pos_ + 1 ) % buffer_size_; + if ( write_pos_ == new_read_pos ) //nothing new to read + return false; + c = buffer_[new_read_pos]; + ArchThreads::testSetLock ( read_pos_,new_read_pos ); + return true; +} + diff --git a/pwn/flipper/dist/common/include/util/SWEBDebugInfo.h b/pwn/flipper/dist/common/include/util/SWEBDebugInfo.h new file mode 100644 index 0000000..efaf156 --- /dev/null +++ b/pwn/flipper/dist/common/include/util/SWEBDebugInfo.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ustring.h" +#include "umap.h" +#include "Stabs2DebugInfo.h" + + +// The limit for function names, after that, they will get capped +#define CALL_FUNC_NAME_LIMIT 256 +#define CALL_FUNC_NAME_LIMIT_STR macroToString(CALL_FUNC_NAME_LIMIT) + +class SWEBDebugInfo : public Stabs2DebugInfo { +public: + + SWEBDebugInfo(char const *sweb_begin, char const *sweb_end); + + virtual ~SWEBDebugInfo(); + + virtual void getCallNameAndLine(pointer address, const char *&mangled_name, ssize_t &line) const; + + virtual void printCallInformation(pointer address) const; + +private: + ustl::map file_addrs_; + ustl::map function_defs_; + + virtual void initialiseSymbolTable(); + +}; diff --git a/pwn/flipper/dist/common/include/util/SerialManager.h b/pwn/flipper/dist/common/include/util/SerialManager.h new file mode 100644 index 0000000..1d4a53f --- /dev/null +++ b/pwn/flipper/dist/common/include/util/SerialManager.h @@ -0,0 +1,116 @@ +#pragma once + +#include "types.h" +#include "chardev.h" + +#define MAX_PORTS 16 + +class ArchSerialInfo; + +class SerialPort : public CharacterDevice +{ + public: + typedef enum _br + { + BR_9600, BR_14400, BR_19200, BR_38400, BR_55600, BR_115200 + } BAUD_RATE_E; + + typedef enum _par + { + ODD_PARITY, EVEN_PARITY, NO_PARITY + } PARITY_E; + + typedef enum _db + { + DATA_7, DATA_8 + } DATA_BITS_E; + + typedef enum _sb + { + STOP_ONE, STOP_TWO, STOP_ONEANDHALF + } STOP_BITS_E; + + typedef enum _sres + { + SR_OK, SR_ERROR // you might want to add elements for common errors that can appear + } SRESULT; + + SerialPort(char*, ArchSerialInfo port_info); + + ~SerialPort(); + + /** + * Opens a serial port for reading or writing + * @param baud_rate Speed @see BAUD_RATE_E + * @param data_bits Data bits @see DATA_BITS_E + * @param stop_bits Stop bits @see STOP_BITS_E + * @param parity Parity @see PARITY_E + * @return Result @see SERIAL_ERROR_E + */ + SRESULT setup_port(BAUD_RATE_E baud_rate, DATA_BITS_E data_bits, STOP_BITS_E stop_bits, PARITY_E parity); + + /** + * Writes size bytes to serial port + * @param offset Not used with serial ports + * @param size Number of bytes to be written + * @param buffer The data to be written + * @return Number of bytes actualy written or -1 in case of an error + */ + virtual int32 writeData(uint32 offset, uint32 size, const char*buffer); + + void irq_handler(); + + /** + * Returns the Architecture specific data for this serial port. + * The basic task of any operating system is to hide this ugly data. + * This function is mainly called from SerialManager and I do not think + * that it is needed anywhere else. Perhaps it could be protected and + * SerialManager declared as a friend class. + * @return @see ArchSerialInfo + */ + ArchSerialInfo get_info() + { + return port_info_; + } + ; + + private: + void write_UART(uint32 reg, uint8 what); + uint8 read_UART(uint32 reg); + + size_t WriteLock; + size_t SerialLock; + + private: + ArchSerialInfo port_info_; + +}; + +class SerialManager +{ + public: + static SerialManager *instance_; + + static SerialManager * getInstance() + { + if (!instance_) + instance_ = new SerialManager(); + + return instance_; + } + ; + + SerialManager(); + ~SerialManager(); + + SerialPort * serial_ports[ MAX_PORTS]; + + uint32 do_detection(uint32 is_paging_set_up); + uint32 get_num_ports(); + uint32 get_port_number(const uint8* friendly_name); + void service_irq(uint32 irq_num); + + private: + uint32 num_ports; +}; + diff --git a/pwn/flipper/dist/common/include/util/Stabs2DebugInfo.h b/pwn/flipper/dist/common/include/util/Stabs2DebugInfo.h new file mode 100644 index 0000000..191f6dd --- /dev/null +++ b/pwn/flipper/dist/common/include/util/Stabs2DebugInfo.h @@ -0,0 +1,39 @@ +#pragma once + +#include "umap.h" +#include "arch_backtrace.h" + +// The limit for function names, after that, they will get capped +#define CALL_FUNC_NAME_LIMIT 256 +#define CALL_FUNC_NAME_LIMIT_STR macroToString(CALL_FUNC_NAME_LIMIT) + +class StabEntry; +class Stabs2DebugInfo +{ +public: + + Stabs2DebugInfo(char const *stab_begin, char const *stab_end, char const *stab_str); + virtual ~Stabs2DebugInfo(); + + virtual void getCallNameAndLine(pointer address, const char*& mangled_name, ssize_t &line) const; + virtual void printCallInformation(pointer address) const; + +protected: + StabEntry const *stab_start_; + StabEntry const *stab_end_; + char const *stabstr_buffer_; + + ustl::map function_symbols_; + +private: + virtual void initialiseSymbolTable(); + + virtual pointer getFunctionName(pointer address, char function_name[], size_t size) const; + ssize_t getFunctionLine(pointer start, pointer offset) const; + bool tryPasteOoperator(const char *& input, char *& buffer, size_t& size) const; + int readNumber(const char *& input) const; + void pasteTypename(const char *& input, char *& buffer, size_t& size) const; + void pasteArguments(const char *& input, char *& buffer, char delimiter, size_t& size) const; + void demangleName(const char* name, char *buffer, size_t size) const; + size_t putChar2Buffer(char*& buffer, char c, size_t& size) const; +}; diff --git a/pwn/flipper/dist/common/include/util/backtrace.h b/pwn/flipper/dist/common/include/util/backtrace.h new file mode 100644 index 0000000..06ded2b --- /dev/null +++ b/pwn/flipper/dist/common/include/util/backtrace.h @@ -0,0 +1,15 @@ +#pragma once + +#include "arch_backtrace.h" + +/** + * Get the pointer where the current function has been called from. + * @param offset the call depth + * 0 ... the point where this function has been called + * 1 ... the point where the calling function has been called from + * x ... the point where the x'th function call happened + * @return the call pointer in case it could be resolved + * @return 0 in case the call could not be resolved + */ +pointer getCalledBefore(size_t offset); + diff --git a/pwn/flipper/dist/common/include/util/chardev.h b/pwn/flipper/dist/common/include/util/chardev.h new file mode 100644 index 0000000..266d45b --- /dev/null +++ b/pwn/flipper/dist/common/include/util/chardev.h @@ -0,0 +1,94 @@ +#pragma once + +#include "ustring.h" +#include "FiFo.h" + +class CharacterDevice +{ + public: + + /** + * Constructor + * @param name the device name + * @param super_block the superblock (0) + * @param inode_type the inode type (cahracter device) + */ + CharacterDevice(const char* name) : + in_buffer_(CD_BUFFER_SIZE, FIFO_NOBLOCK_PUT | FIFO_NOBLOCK_PUT_OVERWRITE_OLD), + out_buffer_(CD_BUFFER_SIZE, FIFO_NOBLOCK_PUT | FIFO_NOBLOCK_PUT_OVERWRITE_OLD), + name_(name) + { + } + + ~CharacterDevice() + { + } + + /** + * reads the data from the character device + * @param buffer is the buffer where the data is written to + * @param count is the number of bytes to read. + * @param offset is never to be used, because there is no offset + * in character devices, but it is defined in the Inode interface + */ + virtual int32 readData(uint32 offset, uint32 size, char *buffer) + { + if (offset) + return -1; // offset reading not supprted with char devices + + char *bptr = buffer; + do + { + *bptr++ = in_buffer_.get(); + } while ((bptr - buffer) < (int32) size); + + return (bptr - buffer); + } + + /** + * writes to the character device + * @param buffer is the buffer where the data is read from + * @param count is the number of bytes to write. + * @param offset is never to be used, because there is no offset + * in character devices, but it is defined in the Inode interface + */ + virtual int32 writeData(uint32 offset, uint32 size, const char*buffer) + { + if (offset) + return -1; // offset writing also not supp0rted + + const char *bptr = buffer; + do + { + out_buffer_.put(*bptr++); + } while ((bptr - buffer) < (int32) size); + + return (bptr - buffer); + } + + const char *getDeviceName() const + { + return name_.c_str(); + } + + protected: + static const uint32 CD_BUFFER_SIZE = 1024; + + FiFo in_buffer_; + FiFo out_buffer_; + + ustl::string name_; + + void processInBuffer() + { + in_buffer_.get(); + } + + void processOutBuffer() + { + out_buffer_.get(); + } + +}; + + diff --git a/pwn/flipper/dist/common/include/util/kstring.h b/pwn/flipper/dist/common/include/util/kstring.h new file mode 100644 index 0000000..8f39f34 --- /dev/null +++ b/pwn/flipper/dist/common/include/util/kstring.h @@ -0,0 +1,65 @@ +#pragma once + +#define STRING_SAVE + +#include "types.h" +#include "paging-definitions.h" + +/** + * Convert a define to a string. + * This macro is used to fi. resolve defined numbers within a constant string. + * @param _s the macro to convert to a string + * @return the string which is resolved by the macro + */ +#ifndef macroToString +#define _macroToString(_s) #_s +#define macroToString(_s) _macroToString(_s) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + size_t strlen(const char* str); + void *memcpy(void *dest, const void *src, size_t length); + void *memmove(void *dest, const void *src, size_t length); + void *memccpy(void *dest, const void *src, uint8 c, size_t length); + void *memset(void *block, uint8 c, size_t size); + char *strcpy(char *dest, const char* src); + char *strncpy(char *dest, const char* src, size_t size); + char *strdup(const char *src); + char *strcat(char *dest, const char*append); + char *strncat(char *dest, const char*append, size_t size); + size_t strlcat(char *dest, const char*append, size_t size); + int32 memcmp(const void *region1, const void *region2, size_t size); + int32 strcmp(const char *str1, const char *str2); + int32 strncmp(const char *str1, const char *str2, size_t n); + void *memnotchr(const void *block, uint8 c, size_t size); + void *memchr(const void *block, uint8 c, size_t size); + void *memrchr(const void *block, uint8 c, size_t size); + char *strchr(const char* str, char c); + char *strrchr(const char* str, char c); + char* strtok(char* str, const char* delimiters); + char* itoa(int value, char * str, int base); + + /** + * copy length bytes from src to dest, even if they overlap + */ + void bcopy(void *src, void* dest, size_t length); + + /** + * Compare size bytes of region1 and region2 + * @return the difference between the first differing bytes or zero on equality + */ + int32 bcmp(const void *region1, const void *region2, size_t size); + + /** + * Computes a CRC- like checksum + */ + uint32 checksum(uint32* src, uint32 nbytes); + +#ifdef __cplusplus +} +#endif + diff --git a/pwn/flipper/dist/common/include/util/libgcc.h b/pwn/flipper/dist/common/include/util/libgcc.h new file mode 100644 index 0000000..3a249b1 --- /dev/null +++ b/pwn/flipper/dist/common/include/util/libgcc.h @@ -0,0 +1,9 @@ +#pragma once + +#include "types.h" + +extern "C" int64 __divdi3(int64 num, int64 den); +extern "C" uint64 __udivdi3(uint64 num, uint64 den); +extern "C" uint64 __umoddi3(uint64 a, uint64 b); +extern "C" uint64 __udivmoddi4(uint64 num, uint64 den, uint64 *rem_p); + diff --git a/pwn/flipper/dist/common/include/util/qsort.h b/pwn/flipper/dist/common/include/util/qsort.h new file mode 100644 index 0000000..704fd8c --- /dev/null +++ b/pwn/flipper/dist/common/include/util/qsort.h @@ -0,0 +1,5 @@ +#pragma once + +#include "types.h" + +void qsort(void* base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); diff --git a/pwn/flipper/dist/common/include/util/stdarg.h b/pwn/flipper/dist/common/include/util/stdarg.h new file mode 100644 index 0000000..1c81fcb --- /dev/null +++ b/pwn/flipper/dist/common/include/util/stdarg.h @@ -0,0 +1,133 @@ +/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself cause + the resulting executable to be covered by the GNU General Public + License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General + Public License. */ + +/* + * ISO C Standard: 7.15 Variable arguments + */ + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#ifdef _SCO_DS +#define __VA_LIST +#endif +#endif /* _VA_LIST_ */ +#else /* not __svr4__ || _SCO_DS */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. +But on BSD NET2 we must not test or define or undef it. +(Note that the comments in NET 2's ansi.h +are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) +/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ +#ifndef _VA_LIST_DEFINED +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +/* The macro __va_list__ is used by BeOS. */ +#ifndef __va_list__ +typedef __gnuc_va_list va_list; +#endif /* not __va_list__ */ +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_DEFINED */ +#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) +#define _VA_LIST_ +#endif +#ifndef _VA_LIST +#define _VA_LIST +#endif +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED +#endif +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#endif +#ifndef __va_list__ +#define __va_list__ +#endif + +#endif /* not _VA_LIST_, except on certain systems */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ diff --git a/pwn/flipper/dist/common/source/.keep b/pwn/flipper/dist/common/source/.keep new file mode 100644 index 0000000..e69de29 diff --git a/pwn/flipper/dist/common/source/CMakeLists.txt b/pwn/flipper/dist/common/source/CMakeLists.txt new file mode 100644 index 0000000..f96a066 --- /dev/null +++ b/pwn/flipper/dist/common/source/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(fs) +add_subdirectory(kernel) +add_subdirectory(util) +add_subdirectory(ustl) diff --git a/pwn/flipper/dist/common/source/fs/BDManager.cpp b/pwn/flipper/dist/common/source/fs/BDManager.cpp new file mode 100644 index 0000000..2dd634e --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/BDManager.cpp @@ -0,0 +1,91 @@ +#include "BDDriver.h" +#include "BDManager.h" +#include "BDRequest.h" +#include "BDVirtualDevice.h" +#include "IDEDriver.h" +#include "kprintf.h" +#include "debug.h" +#include "kstring.h" + +BDManager *BDManager::getInstance() +{ + if (!instance_) + instance_ = new BDManager(); + return instance_; +} + + +BDManager::BDManager() : + probeIRQ(false) +{ +} + +void BDManager::doDeviceDetection(void) +{ + debug(BD_MANAGER, "doDeviceDetection: Detecting BD devices\n"); + IDEDriver id; + // insert other device detectors here + debug(BD_MANAGER, "doDeviceDetection:Detection done\n"); +} + +void BDManager::addRequest(BDRequest* bdr) +{ + if (bdr->getDevID() < getNumberOfDevices()) + getDeviceByNumber(bdr->getDevID())->addRequest(bdr); + else + bdr->setStatus(BDRequest::BD_ERROR); +} + +void BDManager::addVirtualDevice(BDVirtualDevice* dev) +{ + debug(BD_MANAGER, "addVirtualDevice:Adding device\n"); + dev->setDeviceNumber(device_list_.size()); + device_list_.push_back(dev); + debug(BD_MANAGER, "addVirtualDevice:Device added\n"); +} + +void BDManager::serviceIRQ(uint32 irq_num) +{ + debug(BD_MANAGER, "serviceIRQ:Servicing IRQ\n"); + probeIRQ = false; + + for (BDVirtualDevice* dev : device_list_) + if (dev->getDriver()->irq == irq_num) + { + dev->getDriver()->serviceIRQ(); + return; + } + + debug(BD_MANAGER, "serviceIRQ:End servicing IRQ\n"); +} + +BDVirtualDevice* BDManager::getDeviceByNumber(uint32 dev_num) +{ + return device_list_[dev_num]; +} + +BDVirtualDevice* BDManager::getDeviceByName(const char * dev_name) +{ + if(!dev_name) + { + return 0; + } + + debug(BD_MANAGER, "getDeviceByName: %s", dev_name); + for (BDVirtualDevice* dev : device_list_) + { + if (strcmp(dev->getName(), dev_name) == 0) + { + debug(BD_MANAGER, "getDeviceByName: %s with id: %d\n", dev->getName(), dev->getDeviceNumber()); + return dev; + } + } + return 0; +} + +uint32 BDManager::getNumberOfDevices(void) +{ + return device_list_.size(); +} + +BDManager* BDManager::instance_ = 0; diff --git a/pwn/flipper/dist/common/source/fs/BDVirtualDevice.cpp b/pwn/flipper/dist/common/source/fs/BDVirtualDevice.cpp new file mode 100644 index 0000000..2c78829 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/BDVirtualDevice.cpp @@ -0,0 +1,125 @@ +#include "ArchInterrupts.h" +#include "BDDriver.h" +#include "BDRequest.h" +#include "BDVirtualDevice.h" +#include "kstring.h" +#include "debug.h" +#include "kprintf.h" + +BDVirtualDevice::BDVirtualDevice(BDDriver * driver, uint32 offset, uint32 num_sectors, uint32 sector_size, + const char *name, bool writable) : + offset_(offset), num_sectors_(num_sectors), sector_size_(sector_size), block_size_(sector_size), + writable_(writable), driver_(driver), partition_type_(0), name_(name) +{ + + debug(BD_VIRT_DEVICE, "ctor: offset = %d, num_sectors = %d,\n sector_size = %d, " + "name = %s \n", + offset, num_sectors, sector_size, name); + dev_number_ = 0; +} + +void BDVirtualDevice::addRequest(BDRequest * command) +{ + command->setResult(5); + switch (command->getCmd()) + { + case BDRequest::BD_GET_BLK_SIZE: + command->setResult(block_size_); + command->setStatus(BDRequest::BD_DONE); + break; + case BDRequest::BD_GET_NUM_BLOCKS: + command->setResult(getNumBlocks()); + command->setStatus(BDRequest::BD_DONE); + break; + case BDRequest::BD_READ: + case BDRequest::BD_WRITE: + //start block and num blocks will be interpreted as start sector and num sectors + command->setStartBlock(command->getStartBlock() * (block_size_ / sector_size_) + offset_); + command->setNumBlocks(command->getNumBlocks() * (block_size_ / sector_size_)); + // fall-through + default: + command->setResult(driver_->addRequest(command)); + break; + } + return; +} + + +int32 BDVirtualDevice::readData(uint32 offset, uint32 size, char *buffer) +{ + assert(buffer); + assert(offset % block_size_ == 0 && "we can only read multiples of block_size_ from the device"); + assert(size % block_size_ == 0 && "we can only read multiples of block_size_ from the device"); + + assert((offset + size <= getNumBlocks() * block_size_) && "tried reading out of range"); + + debug(BD_VIRT_DEVICE, "readData\n"); + uint32 blocks2read = size / block_size_, jiffies = 0; + uint32 blockoffset = offset / block_size_; + + debug(BD_VIRT_DEVICE, "blocks2read %d\n", blocks2read); + BDRequest bd(dev_number_, BDRequest::BD_READ, blockoffset, blocks2read, buffer); + addRequest(&bd); + + if (driver_->irq != 0) + { + bool interrupt_context = ArchInterrupts::disableInterrupts(); + ArchInterrupts::enableInterrupts(); + + while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT) + ArchInterrupts::yieldIfIFSet(); + + if (!interrupt_context) + ArchInterrupts::disableInterrupts(); + } + + if (bd.getStatus() != BDRequest::BD_DONE) + { + return -1; + } + return size; +} + + +int32 BDVirtualDevice::writeData(uint32 offset, uint32 size, char *buffer) +{ + assert(offset % block_size_ == 0 && "we can only write multiples of block_size_ to the device"); + assert(size % block_size_ == 0 && "we can only write multiples of block_size_ to the device"); + + assert((offset + size <= getNumBlocks() * block_size_) && "tried writing out of range"); + + debug(BD_VIRT_DEVICE, "writeData\n"); + uint32 blocks2write = size / block_size_, jiffies = 0; + uint32 blockoffset = offset / block_size_; + + BDRequest bd(dev_number_, BDRequest::BD_WRITE, blockoffset, blocks2write, buffer); + addRequest(&bd); + + if (driver_->irq != 0) + { + bool interrupt_context = ArchInterrupts::disableInterrupts(); + ArchInterrupts::enableInterrupts(); + + while (bd.getStatus() == BDRequest::BD_QUEUED && jiffies++ < IO_TIMEOUT) + ArchInterrupts::yieldIfIFSet(); + + if (!interrupt_context) + ArchInterrupts::disableInterrupts(); + } + + if (bd.getStatus() != BDRequest::BD_DONE) + return -1; + else + return size; +} + + +void BDVirtualDevice::setPartitionType(uint8 part_type) +{ + partition_type_ = part_type; +} + +uint8 BDVirtualDevice::getPartitionType(void) const +{ + return partition_type_; +} diff --git a/pwn/flipper/dist/common/source/fs/CMakeLists.txt b/pwn/flipper/dist/common/source/fs/CMakeLists.txt new file mode 100644 index 0000000..d04432f --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/CMakeLists.txt @@ -0,0 +1,7 @@ +include_directories(../../include/fs) + +add_project_library(common_fs) + +add_subdirectory(devicefs) +add_subdirectory(minixfs) +add_subdirectory(ramfs) \ No newline at end of file diff --git a/pwn/flipper/dist/common/source/fs/Dentry.cpp b/pwn/flipper/dist/common/source/fs/Dentry.cpp new file mode 100644 index 0000000..6d849f8 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/Dentry.cpp @@ -0,0 +1,94 @@ +#include "Dentry.h" +#include "assert.h" +#include "Inode.h" + +#include "kprintf.h" + +Dentry::Dentry(Inode* inode) : + d_inode_(inode), d_parent_(this), d_mounts_(0), d_name_("/") +{ + debug(DENTRY, "Created root Dentry\n"); + inode->addDentry(this); +} + +Dentry::Dentry(Inode* inode, Dentry* parent, const ustl::string& name) : + d_inode_(inode), d_parent_(parent), d_mounts_(0), d_name_(name) +{ + debug(DENTRY, "created Dentry with Name %s\n", name.c_str()); + assert(name != ""); + parent->setChild(this); + inode->addDentry(this); +} + +Dentry::~Dentry() +{ + debug(DENTRY, "Deleting Dentry %s, d_parent_: %p, this: %p\n", d_name_.c_str(), d_parent_, this); + if (d_parent_ && (d_parent_ != this)) + { + d_parent_->childRemove(this); + } + for (Dentry* dentry : d_child_) + dentry->d_parent_ = 0; + + d_inode_->removeDentry(this); +} + +void Dentry::setInode(Inode *inode) +{ + d_inode_ = inode; +} + +void Dentry::childInsert(Dentry *child_dentry) +{ + assert(child_dentry != 0); + d_child_.push_back(child_dentry); +} + +int32 Dentry::childRemove(Dentry *child_dentry) +{ + debug(DENTRY, "Dentry childRemove d_child_ included: %d\n", + ustl::find(d_child_.begin(), d_child_.end(), child_dentry) != d_child_.end()); + assert(child_dentry != 0); + assert(child_dentry->d_parent_ == this); + d_child_.remove(child_dentry); + child_dentry->d_parent_ = 0; + return 0; +} + +const char* Dentry::getName() +{ + return d_name_.c_str(); +} + +int32 Dentry::setChild(Dentry *dentry) +{ + if (dentry == 0 || ustl::find(d_child_.begin(), d_child_.end(), dentry) != d_child_.end()) + return -1; + + d_child_.push_back(dentry); + + return 0; +} + +Dentry* Dentry::checkName(const char* name) +{ + for (Dentry* dentry : d_child_) + { + const char *tmp_name = dentry->getName(); + debug(DENTRY, "(checkname) name : %s\n", tmp_name); + if (strcmp(tmp_name, name) == 0) + return dentry; + } + + return 0; +} + +uint32 Dentry::getNumChild() +{ + return d_child_.size(); +} + +bool Dentry::emptyChild() +{ + return d_child_.empty(); +} diff --git a/pwn/flipper/dist/common/source/fs/File.cpp b/pwn/flipper/dist/common/source/fs/File.cpp new file mode 100644 index 0000000..2f0499c --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/File.cpp @@ -0,0 +1,79 @@ +#include "File.h" +#include "Inode.h" +#include "FileDescriptor.h" +#include "assert.h" +#include "Superblock.h" +#include "FileSystemType.h" + + +File::File(Inode* inode, Dentry* dentry, uint32 flag) : + uid(0), gid(0), version(0), f_superblock_(0), f_inode_(inode), f_dentry_(dentry), flag_(flag) +{ + f_inode_->incRefCount(); +} + +File::~File() +{ + debug(VFS_FILE, "Destroying file\n"); + + assert(f_fds_.empty() && "File to be destroyed still has open file descriptors"); + assert(f_inode_); + + if(!f_inode_->decRefCount()) + { + debug(VFS_FILE, "No more references to %s inode %p left after closing file, deleting\n", + f_inode_->getSuperblock()->getFSType()->getFSName(), f_inode_); + f_inode_->getSuperblock()->deleteInode(f_inode_); + } +} + +uint32 File::getSize() +{ + return f_inode_->getSize(); +} + +l_off_t File::lseek(l_off_t offset, uint8 origin) +{ + if (origin == SEEK_SET) + offset_ = offset; + else if (origin == SEEK_CUR) + offset_ += offset; + else if (origin == SEEK_END) + offset_ = f_inode_->getSize() + offset; + else + return -1; + + return offset_; +} + + + + +FileDescriptor* File::openFd() +{ + debug(VFS_FILE, "Open new file descriptor\n"); + FileDescriptor* fd = new FileDescriptor(this); + f_fds_.push_back(fd); + + debug(VFS_FILE, "New file descriptor num: %u\n", fd->getFd()); + return fd; +} + + +int File::closeFd(FileDescriptor* fd) +{ + debug(VFS_FILE, "Close file descriptor num %u\n", fd->getFd()); + assert(fd); + + f_fds_.remove(fd); + delete fd; + + // Release on last fd removed + if(f_fds_.empty()) + { + debug(VFS_FILE, "Releasing file\n"); + return getInode()->release(this); // Will delete this file object + } + + return 0; +} diff --git a/pwn/flipper/dist/common/source/fs/FileDescriptor.cpp b/pwn/flipper/dist/common/source/fs/FileDescriptor.cpp new file mode 100644 index 0000000..f3077cf --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/FileDescriptor.cpp @@ -0,0 +1,90 @@ +#include "FileDescriptor.h" +#include +#ifndef EXE2MINIXFS +#include "ArchThreads.h" +#endif +#include "kprintf.h" +#include "debug.h" +#include "assert.h" +#include "Mutex.h" +#include "MutexLock.h" +#include "File.h" + +FileDescriptorList global_fd_list; + +static size_t fd_num_ = 3; + +FileDescriptor::FileDescriptor(File* file) : + fd_(ArchThreads::atomic_add(fd_num_, 1)), + file_(file) +{ + debug(VFS_FILE, "Create file descriptor %u\n", getFd()); +} + +FileDescriptor::~FileDescriptor() +{ + assert(this); + debug(VFS_FILE, "Destroy file descriptor %p num %u\n", this, getFd()); +} + +FileDescriptorList::FileDescriptorList() : + fds_(), fd_lock_("File descriptor list lock") +{ +} + +FileDescriptorList::~FileDescriptorList() +{ + for(auto fd : fds_) + { + fd->getFile()->closeFd(fd); + } +} + +int FileDescriptorList::add(FileDescriptor* fd) +{ + debug(VFS_FILE, "FD list, add %p num %u\n", fd, fd->getFd()); + MutexLock l(fd_lock_); + + for(auto x : fds_) + { + if(x->getFd() == fd->getFd()) + { + return -1; + } + } + + fds_.push_back(fd); + + return 0; +} + +int FileDescriptorList::remove(FileDescriptor* fd) +{ + debug(VFS_FILE, "FD list, remove %p num %u\n", fd, fd->getFd()); + MutexLock l(fd_lock_); + for(auto it = fds_.begin(); it != fds_.end(); ++it) + { + if((*it)->getFd() == fd->getFd()) + { + fds_.erase(it); + return 0; + } + } + + return -1; +} + +FileDescriptor* FileDescriptorList::getFileDescriptor(uint32 fd_num) +{ + MutexLock l(fd_lock_); + for(auto fd : fds_) + { + if(fd->getFd() == fd_num) + { + assert(fd->getFile()); + return fd; + } + } + + return nullptr; +} diff --git a/pwn/flipper/dist/common/source/fs/FileSystemInfo.cpp b/pwn/flipper/dist/common/source/fs/FileSystemInfo.cpp new file mode 100644 index 0000000..2a4459b --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/FileSystemInfo.cpp @@ -0,0 +1,18 @@ +#include "FileSystemInfo.h" +#include "Dentry.h" +#include "kstring.h" +#include "assert.h" + +FileSystemInfo::FileSystemInfo() : + root_(), pwd_() +{ +} + +FileSystemInfo::FileSystemInfo(const FileSystemInfo& fsi) : + root_(fsi.root_),pwd_(fsi.pwd_) +{ +} + +FileSystemInfo::~FileSystemInfo() +{ +} diff --git a/pwn/flipper/dist/common/source/fs/FileSystemType.cpp b/pwn/flipper/dist/common/source/fs/FileSystemType.cpp new file mode 100644 index 0000000..acf43b8 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/FileSystemType.cpp @@ -0,0 +1,23 @@ +#include "FileSystemType.h" +#include "assert.h" + +FileSystemType::FileSystemType(const char *fs_name) : + fs_name_ ( fs_name ), + fs_flags_ ( 0 ) +{} + + +FileSystemType::~FileSystemType() +{} + + +const char* FileSystemType::getFSName() const +{ + return fs_name_; +} + + +int32 FileSystemType::getFSFlags() const +{ + return fs_flags_; +} diff --git a/pwn/flipper/dist/common/source/fs/Inode.cpp b/pwn/flipper/dist/common/source/fs/Inode.cpp new file mode 100644 index 0000000..a2ba0b7 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/Inode.cpp @@ -0,0 +1,237 @@ +#include "Inode.h" +#include "Superblock.h" +#include "FileSystemType.h" +#include "File.h" + +Inode::Inode(Superblock *superblock, uint32 inode_type) : + i_dentrys_(), + i_files_(), + i_nlink_(0), + i_refcount_(0), + superblock_(superblock), + i_size_(0), + i_type_(inode_type), + i_state_(I_UNUSED), + i_mode_((A_READABLE ^ A_WRITABLE) ^ A_EXECABLE) +{ +} + +Inode::~Inode() +{ + if(numRefs() != 0) + { + debug(INODE, "~Inode %s %p refcount: %u\n", getSuperblock()->getFSType()->getFSName(), this, numRefs()); + } + assert(numRefs() == 0); +} + +uint32 Inode::incRefCount() +{ + auto count = ++i_refcount_; + debug(INODE, "Increasing %s inode %p ref count to: %u\n", getSuperblock()->getFSType()->getFSName(), this, count); + return count; +} + +uint32 Inode::decRefCount() +{ + auto count = --i_refcount_; + debug(INODE, "Decreasing %s inode %p ref count to: %u\n", getSuperblock()->getFSType()->getFSName(), this, count); + return count; +} + +uint32 Inode::incLinkCount() +{ + auto count = ++i_nlink_; + debug(INODE, "Increasing %s inode %p link count to: %u\n", getSuperblock()->getFSType()->getFSName(), this, count); + return count; +} + +uint32 Inode::decLinkCount() +{ + auto count = --i_nlink_; + debug(INODE, "Decreasing %s inode %p link count to: %u\n", getSuperblock()->getFSType()->getFSName(), this, count); + return count; +} + +uint32 Inode::numRefs() +{ + return i_refcount_; +} + +uint32 Inode::numLinks() +{ + return i_nlink_; +} + + +bool Inode::hasDentry(Dentry* dentry) +{ + return ustl::find(i_dentrys_.begin(), i_dentrys_.end(), dentry) != i_dentrys_.end(); +} + +void Inode::addDentry(Dentry* dentry) +{ + assert(dentry); + assert(!hasDentry(dentry)); + + debug(INODE, "%s inode %p addDentry %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + incRefCount(); + + i_dentrys_.push_back(dentry); + dentry->setInode(this); +} + +void Inode::removeDentry(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + + debug(INODE, "%s inode %p removeDentry %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + i_dentrys_.remove(dentry); + assert(!hasDentry(dentry)); + + dentry->releaseInode(); + decRefCount(); +} + + + +// ######################## +// Default inode operations +// ######################## + +int32 Inode::mkfile(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + assert(getType() == I_FILE); + + debug(INODE, "%s inode %p mkfile %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + incLinkCount(); + return 0; +} + +int32 Inode::mkdir(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + assert(getType() == I_DIR); + + debug(INODE, "%s inode %p mkdir %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + incLinkCount(); + return 0; +} + +int32 Inode::mknod(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + assert((getType() != I_DIR) && (getType() != I_FILE)); + + debug(INODE, "%s inode %p mkdir %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + incLinkCount(); + return 0; +} + +int32 Inode::link(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + + if(getType() == I_DIR) + { + debug(INODE, "Hard links are not supported for directories\n"); + return -1; + } + + debug(INODE, "%s indode %p link %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + incLinkCount(); + return 0; +} + +int32 Inode::unlink(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + + debug(INODE, "%s inode %p unlink %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + if(!dentry->emptyChild()) + { + debug(INODE, "Error: %s inode %p has children, cannot unlink %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + return -1; + } + + decLinkCount(); + return 0; +} + +int32 Inode::rmdir(Dentry* dentry) +{ + assert(dentry); + assert(dentry->getInode() == this); + assert(hasDentry(dentry)); + assert(getType() == I_DIR); + + debug(INODE, "%s inode %p rmdir %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + + if(!dentry->emptyChild()) + { + debug(INODE, "Error: %s inode %p has children, cannot unlink %s\n", + getSuperblock()->getFSType()->getFSName(), this, dentry->getName()); + return -1; + } + + decLinkCount(); + return 0; +} + +Dentry* Inode::lookup(const char* name) +{ + if (name == 0) + { + // ERROR_DNE + return 0; + } + + debug(INODE, "%s inode %p lookup %s\n", getSuperblock()->getFSType()->getFSName(), this, name); + + if (i_type_ != I_DIR) + { + return 0; + } + + assert(i_dentrys_.size() >= 1); + return i_dentrys_.front()->checkName(name); +} + + +int32 Inode::release(File* file) +{ + debug(INODE, "%s inode %p release file\n", getSuperblock()->getFSType()->getFSName(), this); + i_files_.remove(file); + getSuperblock()->fileReleased(file); + delete file; + return 0; +} diff --git a/pwn/flipper/dist/common/source/fs/Path.cpp b/pwn/flipper/dist/common/source/fs/Path.cpp new file mode 100644 index 0000000..afb8bd9 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/Path.cpp @@ -0,0 +1,105 @@ +#include "Path.h" +#include "kprintf.h" +#include "debug.h" +#include "Dentry.h" +#include "VfsMount.h" +#include "Inode.h" +#include "assert.h" +#include "VirtualFileSystem.h" +#include "PathWalker.h" + +Path::Path(Dentry* dentry, VfsMount* mnt) : + dentry_(dentry), mnt_(mnt) +{ + +} + + +bool Path::operator==(const Path& other) const +{ + return ((dentry_ == other.dentry_) && (mnt_ == other.mnt_)); +} + + +Path Path::parent(const Path* global_root) const +{ + debug(PATHWALKER, "Walk up to parent dir\n"); + assert(dentry_ && mnt_); + + if(isGlobalRoot(global_root)) + { + debug(PATHWALKER, "Reached global file system root\n"); + return *this; + } + + if(isMountRoot()) + { + debug(PATHWALKER, "File system mount root reached, going up a mount to vfsmount %p, mountpoint %p %s\n", mnt_->getParent(), mnt_->getMountPoint(), mnt_->getMountPoint()->getName()); + + return Path(mnt_->getMountPoint()->getParent(), mnt_->getParent()); + } + + return Path(dentry_->getParent(), mnt_); +} + +int Path::child(const ustl::string& name, Path& out) const +{ // Warning: out parameter may refer to this object! + debug(PATHWALKER, "Walk down to child %s\n", name.c_str()); + assert(dentry_ && mnt_); + + VfsMount* child_mnt = mnt_; + Dentry *child_dentry = dentry_->getInode()->lookup(name.c_str()); + if(!child_dentry) + { + debug(PATHWALKER, "Error: No child dentry %s\n", name.c_str()); + out = Path(); + return PW_ENOTFOUND; + } + +#ifndef EXE2MINIXFS + VfsMount* vfs_mount = vfs.getVfsMount(child_dentry); + if (vfs_mount != 0) + { + debug(PATHWALKER, "Reached mountpoint at %s, going down to mounted file system\n", dentry_->getName()); + assert(child_dentry->getMountedRoot() == vfs_mount->getRoot()); + + child_dentry = vfs_mount->getRoot(); + child_mnt = vfs_mount; + } +#endif + + out = Path(child_dentry, child_mnt); + return PW_SUCCESS; +} + + +ustl::string Path::getAbsolutePath(const Path* global_root) const +{ + if(isGlobalRoot(global_root)) + { + return "/"; + } + else if(isMountRoot()) // If this is a mount root, we want the name of the mountpoint instead + { + return parent().getAbsolutePath() + mnt_->getMountPoint()->getName(); + } + else if(parent().isGlobalRoot()) // Avoid adding '/' twice + { + return parent().getAbsolutePath() + dentry_->getName(); + } + else + { + return parent().getAbsolutePath() + "/" + dentry_->getName(); + } +} + +bool Path::isGlobalRoot(const Path* global_root) const +{ + return (global_root && (*this == *global_root)) || + (isMountRoot() && mnt_->isRootMount()); +} + +bool Path::isMountRoot() const +{ + return dentry_->getParent() == dentry_; +} diff --git a/pwn/flipper/dist/common/source/fs/PathWalker.cpp b/pwn/flipper/dist/common/source/fs/PathWalker.cpp new file mode 100644 index 0000000..9c69a93 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/PathWalker.cpp @@ -0,0 +1,175 @@ +#include "PathWalker.h" +#include "Inode.h" +#include "Dentry.h" +#include "VfsMount.h" +#include "Superblock.h" +#include "assert.h" +#include "kstring.h" +#include "kprintf.h" +#include "FileSystemInfo.h" +#include "Path.h" +#ifndef EXE2MINIXFS +#include "Mutex.h" +#include "Thread.h" +#endif + +#define CHAR_DOT '.' +#define NULL_CHAR '\0' +#define CHAR_ROOT '/' +#define SEPARATOR '/' + + + +int32 PathWalker::pathWalk(const char* pathname, FileSystemInfo* fs_info, Path& out, Path* parent_dir) +{ + assert(fs_info); + return pathWalk(pathname, fs_info->getPwd(), fs_info->getRoot(), out, parent_dir); +} + +int32 PathWalker::pathWalk(const char* pathname, const Path& pwd, const Path& root, Path& out, Path* parent_dir) +{ + if ((pathname == 0) || (strlen(pathname) == 0)) + { + debug(PATHWALKER, "pathWalk> ERROR: Invalid path name\n"); + return PW_EINVALID; + } + + debug(PATHWALKER, "pathWalk> path: %s\n", pathname); + + if ((pwd.dentry_ == 0) || (pwd.mnt_ == 0) || + (root.dentry_ == 0) || (root.mnt_ == 0)) + { + debug(PATHWALKER, "pathWalk> Error: Invalid pwd/root\n"); + return PW_EINVALID; + } + + // Clear parent dir tracker + if(parent_dir) + { + *parent_dir = Path(); + } + + // Start at ROOT if path starts with '/', else start with PWD + out = (*pathname == CHAR_ROOT) ? root : pwd; + debug(PATHWALKER, "PathWalk> Start dentry: %p, vfs_mount: %p\n", out.dentry_, out.mnt_); + + + while (true) + { + while (*pathname == SEPARATOR) + pathname++; + + if (!*pathname) + { + debug(PATHWALKER, "pathWalk> Reached end of path\n"); + break; + } + + size_t segment_len = getNextPartLen(pathname); + + char segment[segment_len + 1]; + strncpy(segment, pathname, segment_len + 1); + segment[segment_len] = 0; + + pathname += segment_len; + + while (*pathname == SEPARATOR) + pathname++; + + + debug(PATHWALKER, "pathWalk> segment: %s\n", segment); + debug(PATHWALKER, "pathWalk> remaining: %s\n", pathname); + + switch(pathSegmentType(segment)) + { + case LAST_DOT: + { + debug(PATHWALKER, "pathWalk> follow last dot\n"); + break; + } + case LAST_DOTDOT: + { + debug(PATHWALKER, "pathWalk> follow last dotdot\n"); + out = out.parent(&root); + break; + } + case LAST_NORM: + { + debug(PATHWALKER, "pathWalk> follow last norm segment: %s\n", segment); + + Path child; + if(out.child(segment, child) != PW_SUCCESS) + { + debug(PATHWALKER, "pathWalk> dentry %s not found\n", segment); + if(!*pathname && parent_dir) // No further remaining segments -> parent directory exists + { + *parent_dir = out; + } + return PW_ENOTFOUND; + } + + out = child; + break; + } + default: + assert(false); + } + } + + if(parent_dir) + { + *parent_dir = out.parent(&root); + } + return PW_SUCCESS; +} + + +int PathWalker::pathSegmentType(const char* segment) +{ + return (strcmp(segment, ".") == 0) ? LAST_DOT : + (strcmp(segment, "..") == 0) ? LAST_DOTDOT : + LAST_NORM; +} + +size_t PathWalker::getNextPartLen(const char* path) +{ + const char* sep = strchr(path, SEPARATOR); + return sep ? sep - path : strlen(path); +} + + +ustl::string PathWalker::pathPrefix(const ustl::string& path) +{ + ssize_t prefix_len = path.find_last_of("/"); + if(prefix_len == -1) + { + debug(PATHWALKER, "pathPrefix: %s -> %s\n", path.c_str(), ""); + return ""; + } + + ustl::string retval = path.substr(0, prefix_len); + debug(PATHWALKER, "pathPrefix: %s -> %s\n", path.c_str(), retval.c_str()); + return retval; +} + +ustl::string PathWalker::lastPathSegment(const ustl::string& path, bool ignore_separator_at_end) +{ + if(path.length() == 0) + return path; + + if(!ignore_separator_at_end || path.back() != '/') + { + ssize_t prefix_len = path.find_last_of("/"); + ustl::string retval = path.substr(prefix_len+1, path.length() - prefix_len); + debug(PATHWALKER, "lastPathSegment: %s -> %s\n", path.c_str(), retval.c_str()); + return retval; + } + else + { + ustl::string tmp_path = path.substr(0, path.find_last_not_of("/") + 1); + ssize_t prefix_len = tmp_path.find_last_of("/"); + ustl::string retval = tmp_path.substr(prefix_len+1, tmp_path.length() - prefix_len); + debug(PATHWALKER, "lastPathSegment: %s -> %s\n", path.c_str(), retval.c_str()); + return retval; + } +} diff --git a/pwn/flipper/dist/common/source/fs/Superblock.cpp b/pwn/flipper/dist/common/source/fs/Superblock.cpp new file mode 100644 index 0000000..8690f33 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/Superblock.cpp @@ -0,0 +1,109 @@ +#include "Superblock.h" +#include "assert.h" +#include "Dentry.h" +#include "Inode.h" +#include "File.h" +#include "FileSystemType.h" + +Superblock::Superblock(FileSystemType* fs_type, size_t s_dev) : + s_magic_(0), s_type_(fs_type), s_dev_(s_dev), s_flags_(0), s_root_(0), s_mountpoint_(0) +{ + debug(SUPERBLOCK, "%s Superblock created\n", s_type_->getFSName()); +} + +Superblock::~Superblock() +{ + debug(SUPERBLOCK, "%s Superblock destroyed\n", s_type_->getFSName()); +} + +void Superblock::deleteInode(Inode* inode) +{ + assert(inode != 0); + dirty_inodes_.remove(inode); + used_inodes_.remove(inode); + all_inodes_.remove(inode); + delete inode; +} + +Dentry* Superblock::getRoot() +{ + return s_root_; +} + +Dentry* Superblock::getMountPoint() +{ + return s_mountpoint_; +} + +void Superblock::setMountPoint(Dentry* mountpoint) +{ + s_mountpoint_ = mountpoint; +} + +FileSystemType* Superblock::getFSType() +{ + return (FileSystemType*) s_type_; +} + + +int Superblock::fileOpened(File* file) +{ + Inode* inode = file->getInode(); + assert(inode->getSuperblock() == this); + + if(ustl::find(s_files_.begin(), s_files_.end(), file) != s_files_.end()) + { + return -1; + } + + s_files_.push_back(file); + used_inodes_.push_back(inode); + + return 0; +} + +int Superblock::fileReleased(File* file) +{ + Inode* inode = file->getInode(); + assert(inode->getSuperblock() == this); + + s_files_.remove(file); + + if (inode->getNumOpenedFile() == 0) + { + used_inodes_.remove(inode); + } + + return 0; +} + +void Superblock::releaseAllOpenFiles() +{ + debug(SUPERBLOCK, "Releasing all open files\n"); + while(!s_files_.empty()) + { + File* file = s_files_.front(); + file->getInode()->release(file); + } + + assert(s_files_.empty()); +} + +void Superblock::deleteAllInodes() +{ + for (Inode* inode : all_inodes_) + { + while(!inode->getDentrys().empty()) + { + delete inode->getDentrys().front(); + } + + debug(SUPERBLOCK, "~Superblock write inode to disc\n"); + writeInode(inode); + + debug(SUPERBLOCK, "~Superblock delete inode %p\n", inode); + delete inode; + } + + all_inodes_.clear(); +} diff --git a/pwn/flipper/dist/common/source/fs/VfsMount.cpp b/pwn/flipper/dist/common/source/fs/VfsMount.cpp new file mode 100644 index 0000000..f5179f6 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/VfsMount.cpp @@ -0,0 +1,77 @@ +#include "VfsMount.h" + + +VfsMount::VfsMount() : + mnt_parent_ ( 0 ), + mnt_mountpoint_ ( 0 ), + mnt_root_ ( 0 ), + mnt_sb_ ( 0 ), + mnt_flags_ ( 0 ) +{} + + +VfsMount::VfsMount ( VfsMount* parent, Dentry * mountpoint, Dentry* root, + Superblock* superblock, int32 flags ) : + mnt_parent_ ( parent ? parent : this), + mnt_mountpoint_ ( mountpoint ), + mnt_root_ ( root ), + mnt_sb_ ( superblock ), + mnt_flags_ ( flags ) +{} + + +VfsMount::~VfsMount() +{ + mnt_parent_ = 0; + mnt_mountpoint_ = 0; + mnt_root_ = 0; + mnt_sb_ = 0; + mnt_flags_ = 0; +} + + +VfsMount *VfsMount::getParent() const +{ + return mnt_parent_; +} + + +Dentry *VfsMount::getMountPoint() const +{ + return mnt_mountpoint_; +} + + +Dentry *VfsMount::getRoot() const +{ + return mnt_root_; +} + + +Superblock *VfsMount::getSuperblock() const +{ + return mnt_sb_; +} + + +int32 VfsMount::getFlags() const +{ + return mnt_flags_; +} + + +//NOTE: only used as workaround +void VfsMount::clear() +{ + mnt_parent_ = 0; + mnt_mountpoint_ = 0; + mnt_root_ = 0; + mnt_sb_ = 0; + mnt_flags_ = 0; +} + + +bool VfsMount::isRootMount() const +{ + return getParent() == this; +} diff --git a/pwn/flipper/dist/common/source/fs/VfsSyscall.cpp b/pwn/flipper/dist/common/source/fs/VfsSyscall.cpp new file mode 100644 index 0000000..b05d23c --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/VfsSyscall.cpp @@ -0,0 +1,462 @@ +#include "VfsSyscall.h" +#include "kstring.h" +#include "assert.h" +#include "Dirent.h" +#include "Inode.h" +#include "Dentry.h" +#include "Superblock.h" +#include "File.h" +#include "FileDescriptor.h" +#include "FileSystemType.h" +#include "FileSystemInfo.h" +#include "VirtualFileSystem.h" +#include "MinixFSType.h" +#include "PathWalker.h" +#include "VfsMount.h" +#include "kprintf.h" +#ifndef EXE2MINIXFS +#include "Thread.h" +#endif + +#define SEPARATOR '/' +#define CHAR_DOT '.' + +FileDescriptor* VfsSyscall::getFileDescriptor(uint32 fd) +{ + return global_fd_list.getFileDescriptor(fd); +} + + +int32 VfsSyscall::mkdir(const char* pathname, int32) +{ + debug(VFSSYSCALL, "(mkdir) Path: %s\n", pathname); + FileSystemInfo *fs_info = getcwd(); + + Path target_path; + Path parent_dir_path; + int32 path_walk_status = PathWalker::pathWalk(pathname, fs_info, target_path, &parent_dir_path); + + if((path_walk_status == PW_ENOTFOUND) && parent_dir_path.dentry_) + { + ustl::string new_dir_name = PathWalker::lastPathSegment(pathname, true); + + Inode* parent_dir_inode = parent_dir_path.dentry_->getInode(); + Superblock* parent_dir_sb = parent_dir_inode->getSuperblock(); + + if (parent_dir_inode->getType() != I_DIR) + { + debug(VFSSYSCALL, "(mkdir) Error: This path is not a directory\n"); + return -1; + } + + debug(VFSSYSCALL, "(mkdir) Creating new directory Inode in superblock %p of type %s\n", parent_dir_sb, parent_dir_sb->getFSType()->getFSName()); + Inode* new_dir_inode = parent_dir_sb->createInode(I_DIR); + + debug(VFSSYSCALL, "(mkdir) Creating new dentry: %s in parent dir %s\n", new_dir_name.c_str(), parent_dir_path.dentry_->getName()); + Dentry* new_dir_dentry = new Dentry(new_dir_inode, parent_dir_path.dentry_, new_dir_name); + new_dir_inode->mkdir(new_dir_dentry); + + return 0; + } + else if (path_walk_status == PW_SUCCESS) + { + debug(VFSSYSCALL, "(mkdir) Error: The pathname already exists\n"); + } + else if (path_walk_status == PW_EINVALID) + { + debug(VFSSYSCALL, "(mkdir) Error: Invalid pathname\n"); + } + else if ((path_walk_status == PW_ENOTFOUND) && !parent_dir_path.dentry_) + { + debug(VFSSYSCALL, "(mkdir) Error: Parent directory not found\n\n"); + } + + return -1; +} + +static const char* readdirPrefix(uint32 inode_type) +{ + switch (inode_type) + { + case I_DIR: + return "[D] "; + case I_FILE: + return "[F] "; + case I_LNK: + return "[L] "; + default: + return ""; + } +} + +Dirent* VfsSyscall::readdir(const char* pathname, char* buffer, size_t size) +{ + FileSystemInfo *fs_info = getcwd(); + + Path target_path; + if (PathWalker::pathWalk(pathname, fs_info, target_path) != PW_SUCCESS) + { + debug(VFSSYSCALL, "(readdir) ERROR: Path doesn't exist\n"); + kprintf("Error: %s not found\n", pathname); + return 0; + } + + if (target_path.dentry_->getInode()->getType() != I_DIR) + { + debug(VFSSYSCALL, "(readdir) ERROR: This path is not a directory\n"); + kprintf("Error: %s is not a directory\n", pathname); + return nullptr; + } + + debug(VFSSYSCALL, "(readdir) listing dir %s:\n", target_path.dentry_->getName()); + size_t it = 0; + for (Dentry* sub_dentry : target_path.dentry_->d_child_) + { + uint32 inode_type = sub_dentry->getInode()->getType(); + const char* prefix = readdirPrefix(inode_type); + const char* name = sub_dentry->getName(); + + if(buffer) + { + auto len_name = strlen(name); + if(it + len_name + 1 >= size) + { + debug(VFSSYSCALL, "Buffer is too small for all elements -> return it as it is\n"); + buffer[it] = 0; + return 0; + } + + memcpy(buffer + it, name, len_name); + it += len_name; + buffer[it++] = '\n'; + } + else + { + kprintf("%s%s\n", prefix, name); + } + } + + if(buffer) + { + buffer[it] = 0; + } + + return 0; +} + +int32 VfsSyscall::chdir(const char* pathname) +{ + debug(VFSSYSCALL, "(chdir) Changing working directory to: %s\n", pathname); + + FileSystemInfo *fs_info = getcwd(); + + Path target_path; + if (PathWalker::pathWalk(pathname, fs_info, target_path) != PW_SUCCESS) + { + debug(VFSSYSCALL, "(chdir) Error: The directory does not exist.\n"); + return -1; + } + + Inode* current_inode = target_path.dentry_->getInode(); + if (current_inode->getType() != I_DIR) + { + debug(VFSSYSCALL, "(chdir) Error: This path is not a directory\n"); + return -1; + } + + fs_info->setPwd(target_path); + + return 0; +} + +int32 VfsSyscall::rm(const char* pathname) +{ + debug(VFSSYSCALL, "(rm) Removing: %s\n", pathname); + + FileSystemInfo *fs_info = getcwd(); + + Path target_path; + if (PathWalker::pathWalk(pathname, fs_info, target_path) != PW_SUCCESS) + { + debug(VFSSYSCALL, "(rm) target file does not exist.\n"); + return -1; + } + debug(VFSSYSCALL, "(rm) current_dentry->getName(): %s \n", target_path.dentry_->getName()); + Inode* current_inode = target_path.dentry_->getInode(); + debug(VFSSYSCALL, "(rm) current_inode: %p\n", current_inode); + + if (current_inode->getType() != I_FILE) + { + debug(VFSSYSCALL, "(rm) Target is not a file\n"); + return -1; + } + + if (current_inode->unlink(target_path.dentry_)) + { + debug(VFSSYSCALL, "(rm) Error: File unlink failed\n"); + return -1; + } + + delete target_path.dentry_; + if (!current_inode->numRefs()) + { + Superblock* sb = current_inode->getSuperblock(); + debug(VFSSYSCALL, "(rm) No more references to inode left, remove inode %p from the list of sb: %p\n", current_inode, sb); + sb->deleteInode(current_inode); + } + + return 0; +} + +int32 VfsSyscall::rmdir(const char* pathname) +{ + FileSystemInfo *fs_info = getcwd(); + + Path target_dir; + Path parent_dir_path; + int32 path_walk_status = PathWalker::pathWalk(pathname, fs_info, target_dir, &parent_dir_path); + + if(path_walk_status != PW_SUCCESS) + { + debug(VFSSYSCALL, "(rmdir) Error: The directory does not exist.\n"); + return -1; + } + + Inode* current_inode = target_dir.dentry_->getInode(); + + //if directory is read from a real file system, + //it can't ever be empty, "." and ".." are still + //contained; this has to be checked in Inode::rmdir() + + if (current_inode->getType() != I_DIR) + { + debug(VFSSYSCALL, "(rmdir) Error: This is not a directory\n"); + return -1; + } + + if (current_inode->rmdir(target_dir.dentry_)) + { + debug(VFSSYSCALL, "(rmdir) Error: File system rmdir failed\n"); + return -1; + } + + delete target_dir.dentry_; + if (!current_inode->numRefs()) + { + Superblock* sb = current_inode->getSuperblock(); + debug(VFSSYSCALL, "(rmdir) No more references to inode left, remove inode %p from the list of sb: %p\n", current_inode, sb); + sb->deleteInode(current_inode); + } + + return 0; +} + +int32 VfsSyscall::close(uint32 fd) +{ + debug(VFSSYSCALL, "(close) Close fd num %u\n", fd); + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(close) Error: the fd does not exist.\n"); + return -1; + } + + assert(!global_fd_list.remove(file_descriptor)); + file_descriptor->getFile()->closeFd(file_descriptor); + + debug(VFSSYSCALL, "(close) File closed\n"); + return 0; +} + +int32 VfsSyscall::open(const char* pathname, uint32 flag) +{ + if(!pathname) + { + debug(VFSSYSCALL, "(open) Invalid pathname\n"); + return -1; + } + + debug(VFSSYSCALL, "(open) Opening file %s\n", pathname); + if (flag & ~(O_RDONLY | O_WRONLY | O_CREAT | O_RDWR | O_TRUNC | O_APPEND)) + { + debug(VFSSYSCALL, "(open) Invalid flag parameter\n"); + return -1; + } + if(flag & (O_APPEND | O_TRUNC)) + { + kprintfd("(open) ERROR: Flags not yet implemented\n"); // kprintfd instead of debug so it will be printed even if the debug flag is disabled + return -1; + } + + FileSystemInfo *fs_info = getcwd(); + + Path target_path; + Path parent_dir_path; + int32 path_walk_status = PathWalker::pathWalk(pathname, fs_info, target_path, &parent_dir_path); + + if (path_walk_status == PW_SUCCESS) + { + debug(VFSSYSCALL, "(open) Found target file: %s\n", target_path.dentry_->getName()); + Inode* target_inode = target_path.dentry_->getInode(); + + if (target_inode->getType() != I_FILE) + { + debug(VFSSYSCALL, "(open) Error: This path is not a file\n"); + return -1; + } + + File* file = target_inode->open(target_path.dentry_, flag); + FileDescriptor* fd = file->openFd(); + assert(!global_fd_list.add(fd)); + + debug(VFSSYSCALL, "(open) Fd for new open file: %d, flags: %x\n", fd->getFd(), flag); + return fd->getFd(); + } + else if ((path_walk_status == PW_ENOTFOUND) && (flag & O_CREAT)) + { + if (!parent_dir_path.dentry_) + { + debug(VFSSYSCALL, "(open) ERROR: unable to create file, directory does not exist\n"); + return -1; + } + + debug(VFSSYSCALL, "(open) target does not exist, creating new file\n"); + + ustl::string new_dentry_name = PathWalker::lastPathSegment(pathname); + if(new_dentry_name == "") // Path has trailing slashes + { + debug(VFSSYSCALL, "(open) Error: last path segment is empty (trailing '/')\n"); + return -1; + } + + debug(VFSSYSCALL, "(open) new file name: %s\n", new_dentry_name.c_str()); + + Inode* parent_dir_inode = parent_dir_path.dentry_->getInode(); + Superblock* parent_dir_sb = parent_dir_inode->getSuperblock(); + + if (parent_dir_inode->getType() != I_DIR) + { + debug(VFSSYSCALL, "(open) ERROR: This path is not a directory\n"); + return -1; + } + + debug(VFSSYSCALL, "(open) Creating new file Inode in superblock %p of type %s\n", parent_dir_sb, parent_dir_sb->getFSType()->getFSName()); + Inode* new_file_inode = parent_dir_sb->createInode(I_FILE); + if (!new_file_inode) + { + debug(VFSSYSCALL, "(open) ERROR: Unable to create inode for new file\n"); + return -1; + } + + debug(VFSSYSCALL, "(open) Creating new dentry: %s in parent dir %s\n", new_dentry_name.c_str(), parent_dir_path.dentry_->getName()); + Dentry* new_file_dentry = new Dentry(new_file_inode, parent_dir_path.dentry_, new_dentry_name); + new_file_inode->mkfile(new_file_dentry); + + File* file = new_file_inode->open(new_file_dentry, flag); + FileDescriptor* fd = file->openFd(); + assert(!global_fd_list.add(fd)); + + debug(VFSSYSCALL, "(open) Fd for new open file: %d, flags: %x\n", fd->getFd(), flag); + return fd->getFd(); + } + else if (path_walk_status == PW_EINVALID) + { + debug(VFSSYSCALL, "(open) Error: Invalid pathname\n"); + } + else + { + debug(VFSSYSCALL, "(open) Error: File not found\n"); + } + return -1; +} + +int32 VfsSyscall::read(uint32 fd, char* buffer, uint32 count) +{ + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(read) Error: the fd does not exist.\n"); + return -1; + } + + if (count == 0) + return 0; + + return file_descriptor->getFile()->read(buffer, count, 0); +} + +int32 VfsSyscall::write(uint32 fd, const char *buffer, uint32 count) +{ + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(write) Error: the fd does not exist.\n"); + return -1; + } + + if (count == 0) + return 0; + + return file_descriptor->getFile()->write(buffer, count, 0); +} + +l_off_t VfsSyscall::lseek(uint32 fd, l_off_t offset, uint8 origin) +{ + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(lseek) Error: the fd does not exist.\n"); + return -1; + } + + return file_descriptor->getFile()->lseek(offset, origin); +} + +int32 VfsSyscall::flush(uint32 fd) +{ + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(read) Error: the fd does not exist.\n"); + return -1; + } + + return file_descriptor->getFile()->flush(); +} + +#ifndef EXE2MINIXFS +int32 VfsSyscall::mount(const char *device_name, const char *dir_name, const char *file_system_name, int32 flag) +{ + FileSystemType* type = vfs.getFsType(file_system_name); + if (!type) + { + debug(VFSSYSCALL, "(mount) Unknown file system %s\n", file_system_name); + return -1; + } + + return vfs.mount(device_name, dir_name, file_system_name, flag); +} + +int32 VfsSyscall::umount(const char *dir_name, int32 flag) +{ + return vfs.umount(dir_name, flag); +} +#endif + +uint32 VfsSyscall::getFileSize(uint32 fd) +{ + FileDescriptor* file_descriptor = getFileDescriptor(fd); + + if (file_descriptor == 0) + { + debug(VFSSYSCALL, "(read) Error: the fd does not exist.\n"); + return -1; + } + + return file_descriptor->getFile()->getSize(); +} diff --git a/pwn/flipper/dist/common/source/fs/VirtualFileSystem.cpp b/pwn/flipper/dist/common/source/fs/VirtualFileSystem.cpp new file mode 100644 index 0000000..b56b004 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/VirtualFileSystem.cpp @@ -0,0 +1,259 @@ +#include "FileSystemType.h" +#include "FileSystemInfo.h" +#include "PathWalker.h" +#include "VirtualFileSystem.h" +#include "Dentry.h" +#include "Superblock.h" +#include "VfsMount.h" +#include "kstring.h" +#include "assert.h" +#include "BDManager.h" +#include "BDVirtualDevice.h" +#include "Thread.h" + +#include "console/kprintf.h" + +VirtualFileSystem vfs; + +void VirtualFileSystem::initialize() +{ + new (this) VirtualFileSystem(); +} + +VirtualFileSystem::VirtualFileSystem() +{ +} + +VirtualFileSystem::~VirtualFileSystem() +{ +} + +int32 VirtualFileSystem::registerFileSystem(FileSystemType *file_system_type) +{ + assert(file_system_type); + assert(file_system_type->getFSName()); + + // check whether a file system type with that name has already been + // registered + if (getFsType(file_system_type->getFSName())) + return -1; + file_system_types_.push_back(file_system_type); + return 0; +} + +int32 VirtualFileSystem::unregisterFileSystem(FileSystemType *file_system_type) +{ + assert(file_system_type != 0); + + const char *fs_name = file_system_type->getFSName(); + for (FileSystemType* fst : file_system_types_) + { + if (strcmp(fst->getFSName(), fs_name) == 0) + delete fst; + } + return 0; +} + +FileSystemType *VirtualFileSystem::getFsType(const char* fs_name) +{ + assert(fs_name); + + for (FileSystemType* fst : file_system_types_) + { + if (strcmp(fst->getFSName(), fs_name) == 0) + return fst; + } + return 0; +} + +VfsMount *VirtualFileSystem::getVfsMount(const Dentry* dentry, bool is_root) +{ + assert(dentry); + + if (is_root == false) + { + for (VfsMount* mnt : mounts_) + { + debug(VFS, "getVfsMount> mnt->getMountPoint()->getName() : %s\n", mnt->getMountPoint()->getName()); + if (!is_root && (mnt->getMountPoint()) == dentry) + return mnt; + else if (mnt->getRoot() == dentry) + return mnt; + } + } + return 0; +} + +FileSystemInfo *VirtualFileSystem::rootMount(const char *fs_name, uint32 /*flags*/) +{ + FileSystemType *fst = getFsType(fs_name); + if(!fst) + { + debug(VFS, "Unknown file system %s\n", fs_name); + return nullptr; + } + + if(fst->getFSFlags() & FS_REQUIRES_DEV) + { + debug(VFS, "Only file systems that do not require a device are currently supported as root file system\n"); + return nullptr; + } + + debug(VFS, "Create root %s superblock\n", fst->getFSName()); + Superblock *super = fst->createSuper(-1); + super = fst->readSuper(super, 0); + + Dentry *root = super->getRoot(); + + super->setMountPoint(root); + root->setMountedRoot(root); + + VfsMount *root_mount = new VfsMount(0, root, root, super, 0); + + mounts_.push_back(root_mount); + superblocks_.push_back(super); + + // fs_info initialize + FileSystemInfo *fs_info = new FileSystemInfo(); + Path root_path(root, root_mount); + fs_info->setRoot(root_path); + fs_info->setPwd(root_path); + + assert(root_mount->getParent() == root_mount); + assert(root_mount->getMountPoint() == root); + assert(root->getParent() == root); + assert(root->getMountedRoot() == root); + assert(super->getMountPoint() == super->getRoot()); + + return fs_info; +} + +int32 VirtualFileSystem::mount(const char* dev_name, const char* dir_name, const char* fs_name, uint32 /*flags*/) +{ + debug(VFS, "Mount fs %s at %s with device %s\n", fs_name, dir_name, dev_name ? dev_name : "(null)"); + + if ((!dir_name) || (!fs_name)) + return -1; + + FileSystemType *fst = getFsType(fs_name); + if (!fst) + return -1; + + if ((fst->getFSFlags() & FS_REQUIRES_DEV) && !dev_name) + return -1; + + FileSystemInfo *fs_info = currentThread->getWorkingDirInfo(); + assert(fs_info); + + uint32_t dev = -1; + if(fst->getFSFlags() & FS_REQUIRES_DEV) + { + BDVirtualDevice* bddev = BDManager::getInstance()->getDeviceByName(dev_name); + if (!bddev) + { + debug(VFS, "mount: device with name %s doesn't exist\n", dev_name); + return -1; + } + + dev = bddev->getDeviceNumber(); + debug(VFS, "mount: dev_nr: %d\n", dev); + } + + // Find mount point + Path mountpoint_path; + int32 success = PathWalker::pathWalk(dir_name, fs_info->getPwd(), fs_info->getRoot(), mountpoint_path); + + if (success != 0) + { + debug(VFS, "mount: Could not find mountpoint\n"); + return -1; + } + + // create a new superblock + debug(VFS, "Create %s superblock\n", fst->getFSName()); + Superblock *super = fst->createSuper(dev); + if (!super) + { + debug(VFS, "mount: Superblock creation failed\n"); + return -1; + } + + debug(VFS, "mount: Fill superblock\n"); + super = fst->readSuper(super, 0); //? + + Dentry *root = super->getRoot(); + assert(root->getParent() == root); + + super->setMountPoint(mountpoint_path.dentry_); // Set mountpoint for new superblock + mountpoint_path.dentry_->setMountedRoot(root); // Mountpoint mounts new superblock root + + // create a new vfs_mount + VfsMount* new_mount = new VfsMount(mountpoint_path.mnt_, mountpoint_path.dentry_, root, super, 0); + mounts_.push_back(new_mount); + superblocks_.push_back(super); + + assert(new_mount->getParent() == mountpoint_path.mnt_); + assert(new_mount->getMountPoint() == mountpoint_path.dentry_); + assert(new_mount->getSuperblock() == super); + assert(new_mount->getRoot() == root); + + return 0; +} + +int32 VirtualFileSystem::rootUmount() +{ + if (superblocks_.size() == 0) + { + return -1; + } + VfsMount *root_vfs_mount = mounts_.at(0); + delete root_vfs_mount; + + Superblock *root_sb = superblocks_.at(0); + delete root_sb; + return 0; +} + +int32 VirtualFileSystem::umount(const char* dir_name, uint32 /*flags*/) +{ + FileSystemInfo *fs_info = currentThread->getWorkingDirInfo(); + if (dir_name == 0) + return -1; + + Path mountpount_path; + int32 success = PathWalker::pathWalk(dir_name, fs_info->getPwd(), fs_info->getRoot(), mountpount_path); + + if (success != 0) + { + debug(VFS, "(umount) unable to find mountpoint\n"); + return -1; + } + + debug(VFS, "(umount) mountpoint found\n"); + assert(mountpount_path.mnt_); + + // in the case, the current-directory is in the local-root of the umounted + // filesystem + if (fs_info->getPwd().mnt_ == mountpount_path.mnt_) + { + if (fs_info->getPwd().dentry_ == mountpount_path.dentry_) + { + debug(VFS, "(umount) the mount point exchange\n"); + fs_info->setPwd(Path(mountpount_path.mnt_->getMountPoint(), mountpount_path.mnt_->getParent())); + } + else + { + debug(VFS, "(umount) set PWD NULL\n"); + fs_info->setPwd(Path()); + } + } + + Superblock *sb = mountpount_path.mnt_->getSuperblock(); + + mounts_.remove(mountpount_path.mnt_); + delete mountpount_path.mnt_; + delete sb; + + return 0; +} + diff --git a/pwn/flipper/dist/common/source/fs/devicefs/CMakeLists.txt b/pwn/flipper/dist/common/source/fs/devicefs/CMakeLists.txt new file mode 100644 index 0000000..0b1abab --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/devicefs/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(../../../include/fs/devicefs) + +add_project_library(common_fs_devicefs) \ No newline at end of file diff --git a/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSSuperblock.cpp b/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSSuperblock.cpp new file mode 100644 index 0000000..8843f2b --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSSuperblock.cpp @@ -0,0 +1,47 @@ +#include "fs/devicefs/DeviceFSSuperblock.h" +#include "fs/ramfs/RamFSInode.h" +#include "DeviceFSType.h" +#include "fs/Dentry.h" +#include "fs/Inode.h" +#include "fs/File.h" +#include "fs/FileDescriptor.h" + +#include "console/kprintf.h" + +#include "Console.h" + +class DeviceFSType; + +extern Console* main_console; + +const char DeviceFSSuperBlock::ROOT_NAME[] = "/"; +const char DeviceFSSuperBlock::DEVICE_ROOT_NAME[] = "dev"; + +DeviceFSSuperBlock* DeviceFSSuperBlock::instance_ = 0; + +DeviceFSSuperBlock::DeviceFSSuperBlock(DeviceFSType* fs_type, uint32 s_dev) : + RamFSSuperblock(fs_type, s_dev) +{ +} + +DeviceFSSuperBlock::~DeviceFSSuperBlock() +{ +} + +void DeviceFSSuperBlock::addDevice(Inode* device_inode, const char* node_name) +{ + // Devices are mounted at the devicefs root (s_root_) + device_inode->setSuperBlock(this); + + Dentry* fdntr = new Dentry(device_inode, s_root_, node_name); + + assert(device_inode->mknod(fdntr) == 0); + all_inodes_.push_back(device_inode); +} + +DeviceFSSuperBlock* DeviceFSSuperBlock::getInstance() +{ + if (!instance_) + instance_ = new DeviceFSSuperBlock(DeviceFSType::getInstance(), 0); + return instance_; +} diff --git a/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSType.cpp b/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSType.cpp new file mode 100644 index 0000000..3e07213 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/devicefs/DeviceFSType.cpp @@ -0,0 +1,32 @@ +#include "fs/devicefs/DeviceFSType.h" +#include "fs/devicefs/DeviceFSSuperblock.h" + +DeviceFSType* DeviceFSType::instance_ = nullptr; + +DeviceFSType::DeviceFSType() : + RamFSType() +{ + fs_name_ = "devicefs"; +} + +DeviceFSType::~DeviceFSType() +{ +} + +Superblock* DeviceFSType::readSuper(Superblock *superblock, void*) const +{ + return superblock; +} + +Superblock* DeviceFSType::createSuper(uint32 __attribute__((unused)) s_dev) +{ + Superblock *super = DeviceFSSuperBlock::getInstance(); + return super; +} + +DeviceFSType* DeviceFSType::getInstance() +{ + if (!instance_) + instance_ = new DeviceFSType(); + return instance_; +} diff --git a/pwn/flipper/dist/common/source/fs/minixfs/CMakeLists.txt b/pwn/flipper/dist/common/source/fs/minixfs/CMakeLists.txt new file mode 100644 index 0000000..3bc99ee --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(../../../include/fs/minixfs) + +add_project_library(common_fs_minixfs) \ No newline at end of file diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixFSFile.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSFile.cpp new file mode 100644 index 0000000..76940cc --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSFile.cpp @@ -0,0 +1,51 @@ +#include "MinixFSFile.h" +#include "MinixFSInode.h" +#include "Inode.h" + +MinixFSFile::MinixFSFile(Inode* inode, Dentry* dentry, uint32 flag) : + File(inode, dentry, flag) +{ + f_superblock_ = inode->getSuperblock(); + offset_ = 0; +} + +MinixFSFile::~MinixFSFile() +{ +} + +int32 MinixFSFile::read(char *buffer, size_t count, l_off_t offset) +{ + if (((flag_ & O_RDONLY) || (flag_ & O_RDWR)) && (f_inode_->getMode() & A_READABLE)) + { + int32 read_bytes = f_inode_->readData(offset_ + offset, count, buffer); + offset_ += read_bytes; + return read_bytes; + } + else + { + // ERROR_FF + return -1; + } +} + +int32 MinixFSFile::write(const char *buffer, size_t count, l_off_t offset) +{ + if (((flag_ & O_WRONLY) || (flag_ & O_RDWR)) && (f_inode_->getMode() & A_WRITABLE)) + { + int32 written = f_inode_->writeData(offset_ + offset, count, buffer); + offset_ += written; + return written; + } + else + { + // ERROR_FF + return -1; + } +} + +int32 MinixFSFile::flush() +{ + ((MinixFSInode *) f_inode_)->flush(); + return 0; +} + diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixFSInode.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSInode.cpp new file mode 100644 index 0000000..8852273 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSInode.cpp @@ -0,0 +1,394 @@ +#include "MinixFSInode.h" +#ifndef EXE2MINIXFS +#include "kstring.h" +#endif +#include +#include "MinixFSSuperblock.h" +#include "MinixFSFile.h" +#include "Dentry.h" + +MinixFSInode::MinixFSInode(Superblock *super_block, uint32 inode_type) : + Inode(super_block, inode_type), + i_zones_(0), + i_num_(0), + children_loaded_(false) +{ + debug(M_INODE, "Simple Constructor\n"); +} + +MinixFSInode::MinixFSInode(Superblock *super_block, uint16 i_mode, uint32 i_size, uint16 i_nlinks, uint32* i_zones, + uint32 i_num) : + Inode(super_block, 0), i_zones_(new MinixFSZone((MinixFSSuperblock*) super_block, i_zones)), i_num_(i_num), + children_loaded_(false) +{ + i_size_ = i_size; + i_nlink_ = i_nlinks; + i_state_ = I_UNUSED; + if (i_mode & 0x8000) + { + i_type_ = I_FILE; + } + else if (i_mode & 0x4000) + { + i_type_ = I_DIR; + } + else + { + debug(M_INODE, "i_mode = %x\n", i_mode); + assert(false); + } + // (hard/sym link/...) not handled! + + debug(M_INODE, "Constructor: size: %d\tnlink: %d\tnum zones: %d\tmode: %x\n", i_size_, numLinks(), + i_zones_->getNumZones(), i_mode); +} + +MinixFSInode::~MinixFSInode() +{ + debug(M_INODE, "Destructor\n"); + delete i_zones_; +} + +int32 MinixFSInode::readData(uint32 offset, uint32 size, char *buffer) +{ + assert(buffer); + debug(M_INODE, "readData: offset: %d, size; %d,i_size_: %d\n", offset, size, i_size_); + if ((size + offset) > i_size_) + { + if (i_size_ <= offset) + return 0; + else + size = i_size_ - offset; + } + uint32 start_zone = offset / ZONE_SIZE; + uint32 zone_offset = offset % ZONE_SIZE; + uint32 num_zones = (zone_offset + size) / ZONE_SIZE + 1; + char rbuffer[ZONE_SIZE]; + + uint32 index = 0; + debug(M_INODE, "readData: zone: %d, zone_offset %d, num_zones: %d\n", start_zone, zone_offset, num_zones); + for (uint32 zone = start_zone; zone < start_zone + num_zones; zone++) + { + memset(rbuffer, 0, sizeof(rbuffer)); + ((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), rbuffer); + uint32 count = size - index; + uint32 zone_diff = ZONE_SIZE - zone_offset; + count = count < zone_diff ? count : zone_diff; + memcpy(buffer + index, rbuffer + zone_offset, count); + index += count; + zone_offset = 0; + } + return size; +} + +int32 MinixFSInode::writeData(uint32 offset, uint32 size, const char *buffer) +{ + debug(M_INODE, "MinixFSInode writeData> offset: %d, size: %d, i_size_: %d\n", offset, size, i_size_); + uint32 zone = offset / ZONE_SIZE; + uint32 num_zones = (offset % ZONE_SIZE + size) / ZONE_SIZE + 1; + uint32 last_used_zone = i_size_ / ZONE_SIZE; + uint32 last_zone = last_used_zone; + if ((size + offset) > i_size_) + { + uint32 num_new_zones = (size + offset - i_size_) / ZONE_SIZE + 1; + for (uint32 new_zones = 0; new_zones < num_new_zones; new_zones++, last_zone++) + { + MinixFSSuperblock* sb = (MinixFSSuperblock*) superblock_; + debug(M_INODE, "writeData: allocating new Zone\n"); + uint16 new_zone = sb->allocateZone(); + i_zones_->setZone(i_zones_->getNumZones(), new_zone); + } + } + if (offset > i_size_) + { + debug(M_INODE, "writeData: have to clean memory\n"); + uint32 zone_size_offset = i_size_ % ZONE_SIZE; + char fill_buffer[ZONE_SIZE]; + memset(fill_buffer, 0, sizeof(fill_buffer)); + if (zone_size_offset) + { + readData(i_size_ - zone_size_offset, zone_size_offset, fill_buffer); + ((MinixFSSuperblock *) superblock_)->writeZone(last_used_zone, fill_buffer); + } + ++last_used_zone; + for (; last_used_zone <= offset / ZONE_SIZE; last_used_zone++) + { + memset(fill_buffer, 0, sizeof(fill_buffer)); + ((MinixFSSuperblock *) superblock_)->writeZone(last_used_zone, fill_buffer); + } + --last_used_zone; + i_size_ = offset; + } + uint32 zone_offset = offset % ZONE_SIZE; + char* wbuffer_array = new char[num_zones * ZONE_SIZE]; + char* wbuffer = wbuffer_array; + memset((void*) wbuffer, 0, num_zones * ZONE_SIZE); + debug(M_INODE, "writeData: reading data at the beginning of zone: offset-zone_offset: %d,zone_offset: %d\n", + offset - zone_offset, zone_offset); + readData(offset - zone_offset, num_zones * ZONE_SIZE, wbuffer); + for (uint32 index = 0, pos = zone_offset; index < size; pos++, index++) + { + wbuffer[pos] = buffer[index]; + } + for (uint32 zone_index = 0; zone_index < num_zones; zone_index++) + { + debug(M_INODE, "writeData: writing zone_index: %d, i_zones_->getZone(zone) : %d\n", zone_index, + i_zones_->getZone(zone)); + ((MinixFSSuperblock *) superblock_)->writeZone(i_zones_->getZone(zone_index + zone), wbuffer); + wbuffer += ZONE_SIZE; + } + if (i_size_ < offset + size) + { + i_size_ = offset + size; + } + delete[] wbuffer_array; + return size; +} + +int32 MinixFSInode::mknod(Dentry *dentry) +{ + Inode::mknod(dentry); + debug(M_INODE, "mknod: dentry: %p, i_type_: %x\n", dentry, i_type_); + + ((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName()); + return 0; +} + +int32 MinixFSInode::mkfile(Dentry *dentry) +{ + Inode::mkfile(dentry); + debug(M_INODE, "mkfile: dentry: %p (%s)\n", dentry, dentry->getName()); + + ((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName()); + return 0; +} + +int32 MinixFSInode::mkdir(Dentry *dentry) +{ + Inode::mkdir(dentry); + debug(M_INODE, "mkdir: dentry: %p (%s)\n", dentry, dentry->getName()); + + MinixFSInode* parent_inode = ((MinixFSInode *) dentry->getParent()->getInode()); + assert(parent_inode->getType() == I_DIR); + + parent_inode->writeDentry(0, i_num_, dentry->getName()); + // link count already increased once in Inode::mkdir(dentry); + + writeDentry(0, i_num_, "."); + incLinkCount(); + + writeDentry(0, parent_inode->i_num_, ".."); + parent_inode->incLinkCount(); + + return 0; +} + +int32 MinixFSInode::findDentry(uint32 i_num) +{ + debug(M_INODE, "findDentry: i_num: %d\n", i_num); + char dbuffer[ZONE_SIZE]; + for (uint32 zone = 0; zone < i_zones_->getNumZones(); zone++) + { + ((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), dbuffer); + for (uint32 curr_dentry = 0; curr_dentry < BLOCK_SIZE; curr_dentry += INODE_SIZE) + { + uint16 inode_index = *(uint16*) (dbuffer + curr_dentry); + if (inode_index == i_num) + { + debug(M_INODE, "findDentry: found pos: %d\n", (zone * ZONE_SIZE + curr_dentry)); + return (zone * ZONE_SIZE + curr_dentry); + } + } + } + debug(M_INODE, "findDentry: i_num: %d not found\n", i_num); + return -1; +} + +void MinixFSInode::writeDentry(uint32 dest_i_num, uint32 src_i_num, const char* name) +{ + debug(M_INODE, "writeDentry: dest_i_num : %d, src_i_num : %d, name : %s\n", dest_i_num, src_i_num, name); + assert(name); + int32 dentry_pos = findDentry(dest_i_num); + if (dentry_pos < 0 && dest_i_num == 0) + { + i_zones_->addZone(((MinixFSSuperblock *) superblock_)->allocateZone()); + dentry_pos = (i_zones_->getNumZones() - 1) * ZONE_SIZE; + } + char dbuffer[ZONE_SIZE]; + uint32 zone = i_zones_->getZone(dentry_pos / ZONE_SIZE); + ((MinixFSSuperblock *) superblock_)->readZone(zone, dbuffer); + *(uint16*) (dbuffer + (dentry_pos % ZONE_SIZE)) = src_i_num; + strncpy(dbuffer + dentry_pos % ZONE_SIZE + INODE_BYTES, name, MAX_NAME_LENGTH); + ((MinixFSSuperblock *) superblock_)->writeZone(zone, dbuffer); + + if (dest_i_num == 0 && i_size_ < (uint32) dentry_pos + INODE_SIZE) + i_size_ += INODE_SIZE; + +} + +File* MinixFSInode::open(Dentry* dentry, uint32 flag) +{ + debug(M_INODE, "Open file, flag: %x\n", flag); + assert(ustl::find(i_dentrys_.begin(), i_dentrys_.end(), dentry) != i_dentrys_.end()); + File* file = (File*) (new MinixFSFile(this, dentry, flag)); + i_files_.push_back(file); + getSuperblock()->fileOpened(file); + return file; +} + + +int32 MinixFSInode::link(Dentry* dentry) +{ + int32 link_status = Inode::link(dentry); + if(link_status) + { + return link_status; + } + + ((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(0, i_num_, dentry->getName()); + + return 0; +} + +int32 MinixFSInode::unlink(Dentry* dentry) +{ + int32 unlink_status = Inode::unlink(dentry); + if(unlink_status) + { + return unlink_status; + } + + ((MinixFSInode *) dentry->getParent()->getInode())->writeDentry(i_num_, 0, ""); + + return 0; +} + +int32 MinixFSInode::rmdir(Dentry* dentry) +{ + assert(dentry && (dentry->getInode() == this)); + assert(dentry->getParent() && (dentry->getParent()->getInode())); + assert(getType() == I_DIR); + + debug(M_INODE, "rmdir %s for inode %p\n", dentry->getName(), this); + + MinixFSInode* parent_inode = static_cast(dentry->getParent()->getInode()); + + //the "." and ".." dentries will be deleted in some inode-dtor + //("." in this inodes-dtor, ".." in the parent-dentry-inodes-dtor) + for (Dentry* child : dentry->d_child_) + { + if (strcmp(child->getName(), ".") != 0 && strcmp(child->getName(), "..") != 0) + { + //if directory contains other entries than "." or ".." + //-> directory not empty + debug(M_INODE, "Error: Cannot remove non-empty directory\n"); + return -1; + } + } + + writeDentry(i_num_, 0, ""); //this was the "."-entry + decLinkCount(); + + writeDentry(parent_inode->i_num_, 0, ""); //this was ".." + parent_inode->decLinkCount(); + + parent_inode->writeDentry(i_num_, 0, ""); + decLinkCount(); + + assert(i_nlink_ == 0); + + return 0; +} + +Dentry* MinixFSInode::lookup(const char* name) +{ + if(i_type_ != I_DIR) + { + return nullptr; + } + + assert(i_dentrys_.size() >= 1); + + debug(M_INODE, "lookup: name: %s this->i_dentry_->getName(): %s \n", name, i_dentrys_.front()->getName()); + if (name == 0) + { + // ERROR_DNE + return 0; + } + + Dentry* dentry_update = 0; + + dentry_update = i_dentrys_.front()->checkName(name); + if (dentry_update == 0) + { + // ERROR_NNE + return (Dentry*) 0; + } + else + { + debug(M_INODE, "lookup: dentry_update->getName(): %s\n", dentry_update->getName()); + if (((MinixFSInode *) dentry_update->getInode())->i_type_ == I_DIR) + { + ((MinixFSInode *) dentry_update->getInode())->loadChildren(); + } + return dentry_update; + } +} + +void MinixFSInode::loadChildren() +{ + if (children_loaded_) + { + debug(M_INODE, "loadChildren: Children allready loaded\n"); + return; + } + char dbuffer[ZONE_SIZE]; + for (uint32 zone = 0; zone < i_zones_->getNumZones(); zone++) + { + ((MinixFSSuperblock *) superblock_)->readZone(i_zones_->getZone(zone), dbuffer); + for (uint32 curr_dentry = 0; curr_dentry < BLOCK_SIZE; curr_dentry += INODE_SIZE) + { + uint16 inode_index = *(uint16*) (dbuffer + curr_dentry); + if (inode_index) + { + debug(M_INODE, "loadChildren: loading child %d\n", inode_index); + bool is_already_loaded = false; + + MinixFSInode* inode = ((MinixFSSuperblock *) superblock_)->getInode(inode_index, is_already_loaded); + + if (!inode) + { + kprintfd("MinixFSInode::loadChildren: inode nr. %d not set in bitmap, but occurs in directory-entry; " + "maybe filesystem was not properly unmounted last time\n", + inode_index); + char ch = 0; + writeDentry(inode_index, 0, &ch); + continue; + } + + char name[MAX_NAME_LENGTH + 1]; + strncpy(name, dbuffer + curr_dentry + INODE_BYTES, MAX_NAME_LENGTH); + + name[MAX_NAME_LENGTH] = 0; + + debug(M_INODE, "loadChildren: dentry name: %s\n", name); + assert(i_dentrys_.size() >= 1); + Dentry *new_dentry = new Dentry(inode, i_dentrys_.front(), name); + inode->i_dentrys_.push_back(new_dentry); + + if (!is_already_loaded) + { + ((MinixFSSuperblock *) superblock_)->all_inodes_add_inode(inode); + } + } + } + } + children_loaded_ = true; +} + +int32 MinixFSInode::flush() +{ + superblock_->writeInode(this); + debug(M_INODE, "flush: flushed\n"); + return 0; +} diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixFSSuperblock.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSSuperblock.cpp new file mode 100644 index 0000000..3700205 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSSuperblock.cpp @@ -0,0 +1,345 @@ +#include "FileDescriptor.h" +#include "MinixFSType.h" +#include "MinixFSSuperblock.h" +#include "MinixFSInode.h" +#include "MinixFSFile.h" +#include "Dentry.h" +#include "assert.h" +#include "kprintf.h" +#ifdef EXE2MINIXFS +#include +#else +#include "kstring.h" +#include "BDManager.h" +#include "BDVirtualDevice.h" +#endif + +#define ROOT_NAME "/" + +MinixFSSuperblock::MinixFSSuperblock(MinixFSType* fs_type, size_t s_dev, uint64 offset) : + Superblock(fs_type, s_dev), superblock_(this), offset_(offset) +{ + //read Superblock data from disc + readHeader(); + debug(M_SB, "s_num_inodes_ : %d\ns_zones_ : %d\ns_num_inode_bm_blocks_ : %d\ns_num_zone_bm_blocks_ : %d\n" + "s_1st_datazone_ : %d\ns_log_zone_size_ : %d\ns_max_file_size_ : %d\ns_block_size_ : %d\ns_magic_ : %llu\n", + s_num_inodes_, s_zones_, s_num_inode_bm_blocks_, s_num_zone_bm_blocks_, s_1st_datazone_, s_log_zone_size_, + s_max_file_size_, s_block_size_, (long long unsigned)s_magic_); + assert(s_log_zone_size_ == 0); + assert(s_block_size_ == 1024); + //create Storage Manager + uint32 bm_size = s_num_inode_bm_blocks_ + s_num_zone_bm_blocks_; + char* bm_buffer = new char[BLOCK_SIZE * bm_size]; + readBlocks(2, bm_size, bm_buffer); + debug(M_SB, "---creating Storage Manager\n"); + storage_manager_ = new MinixStorageManager(bm_buffer, s_num_inode_bm_blocks_, s_num_zone_bm_blocks_, s_num_inodes_, + s_zones_); + if (M_STORAGE_MANAGER & OUTPUT_ENABLED) + { + storage_manager_->printBitmap(); + } + delete[] bm_buffer; + + initInodes(); +} + +void MinixFSSuperblock::readHeader() +{ + char buffer[BLOCK_SIZE]; + readBlocks(1, 1, buffer); + s_magic_ = ((uint16*) buffer)[12]; + s_num_inodes_ = V3_ARRAY(buffer,0); + if (s_magic_ == MINIX_V3) + { + s_block_size_ = ((uint16*) buffer)[14]; + s_disk_version_ = buffer[30]; + s_zones_ = ((uint32*) buffer)[5]; + } + else + { + s_magic_ = ((uint16*) buffer)[8]; + s_zones_ = ((uint16*) buffer)[1]; + s_block_size_ = 1024; + } + s_num_inode_bm_blocks_ = ((uint16*) buffer)[2 + V3_OFFSET]; + s_num_zone_bm_blocks_ = ((uint16*) buffer)[3 + V3_OFFSET]; + s_1st_datazone_ = ((uint16*) buffer)[4 + V3_OFFSET]; + s_log_zone_size_ = ((uint16*) buffer)[5 + V3_OFFSET]; + s_max_file_size_ = ((uint32*) buffer)[3 + V3_OFFSET]; +} + +void MinixFSSuperblock::initInodes() +{ + debug(M_SB, "init Inodes\n"); + MinixFSInode *root_inode = getInode(1); + s_root_ = new Dentry(root_inode); + + all_inodes_add_inode(root_inode); + //read children from disc + debug(M_SB, "Load children of root inode\n"); + root_inode->loadChildren(); +} + +MinixFSInode* MinixFSSuperblock::getInode(uint16 i_num, bool &is_already_loaded) +{ + MinixFSInode* tmp = (MinixFSInode*) all_inodes_set_[i_num]; + if (tmp) + { + is_already_loaded = true; + return tmp; + } + tmp = getInode(i_num); + return tmp; +} + +MinixFSInode* MinixFSSuperblock::getInode(uint16 i_num) +{ + debug(M_SB, "getInode::called with i_num: %d\n", i_num); + + if (i_num >= storage_manager_->getNumUsedInodes()) + { + debug(M_SB, "getInode::bad inode number %d\n", i_num); + return 0; + } + + if (!storage_manager_->isInodeSet(i_num)) + { + if (i_num == 1) + assert(storage_manager_->isInodeSet(1)); + + return 0; + } + uint32 inodes_start = s_num_inode_bm_blocks_ + s_num_zone_bm_blocks_ + 2; + uint32 inode_block_num = inodes_start + (i_num - 1) / INODES_PER_BLOCK; + MinixFSInode *inode = 0; + char ibuffer_array[BLOCK_SIZE]; + char* ibuffer = ibuffer_array; + debug(M_SB, "getInode::reading block num: %d\n", inode_block_num); + readBlocks(inode_block_num, 1, ibuffer); + debug(M_SB, "getInode:: returned reading block num: %d\n", inode_block_num); + uint32 offset = ((i_num - 1) % INODES_PER_BLOCK) * INODE_SIZE; + debug(M_SB, "getInode:: setting offset: %d\n", offset); + ibuffer += offset; + uint32 i_zones[NUM_ZONES]; + for (uint32 num_zone = 0; num_zone < NUM_ZONES; num_zone++) + { + i_zones[num_zone] = V3_ARRAY(ibuffer, 7 - V3_OFFSET + num_zone); + } + debug(M_SB, "getInode:: calling creating Inode\n"); + inode = new MinixFSInode(this, ((uint16*) ibuffer)[0], ((uint32*) ibuffer)[1 + V3_OFFSET], + ((uint16*) ibuffer)[V3_OFFSET], i_zones, i_num); + debug(M_SB, "getInode:: returned creating Inode\n"); + return inode; +} + +MinixFSSuperblock::~MinixFSSuperblock() +{ + debug(M_SB, "~MinixSuperblock\n"); + assert(dirty_inodes_.empty() == true); + storage_manager_->flush(this); + + releaseAllOpenFiles(); + + debug(M_SB, "Open files released\n"); + if (M_SB & OUTPUT_ENABLED) + { + for (auto it : all_inodes_) + debug(M_SB, "Inode: %p\n", it); + } + + // Also writes back inodes to disk + deleteAllInodes(); + all_inodes_set_.clear(); + + delete storage_manager_; + + debug(M_SB, "~MinixSuperblock finished\n"); +} + +Inode* MinixFSSuperblock::createInode(uint32 type) +{ + uint16 mode = 0x01ff; + if (type == I_FILE) + mode |= 0x8000; + else if (type == I_DIR) + mode |= 0x4000; + //else link etc. + uint32 zones[NUM_ZONES]; + for (uint32 i = 0; i < NUM_ZONES; i++) + zones[i] = 0; + uint32 i_num = storage_manager_->allocInode(); + debug(M_SB, "createInode> acquired inode %d mode: %d\n", i_num, mode); + Inode *inode = new MinixFSInode(this, mode, 0, 0, zones, i_num); + debug(M_SB, "createInode> created Inode\n"); + all_inodes_add_inode(inode); + debug(M_SB, "createInode> calling write Inode to Disc\n"); + writeInode(inode); + debug(M_SB, "createInode> finished\n"); + return inode; +} + +int32 MinixFSSuperblock::readInode(Inode* inode) +{ + assert(inode); + MinixFSInode *minix_inode = (MinixFSInode *) inode; + assert(ustl::find(all_inodes_.begin(), all_inodes_.end(), inode) != all_inodes_.end()); + uint32 block = 2 + s_num_inode_bm_blocks_ + s_num_zone_bm_blocks_ + + ((minix_inode->i_num_ - 1) * INODE_SIZE / BLOCK_SIZE); + uint32 offset = ((minix_inode->i_num_ - 1) * INODE_SIZE) % BLOCK_SIZE; + char buffer[INODE_SIZE]; + readBytes(block, offset, INODE_SIZE, buffer); + uint32 *i_zones = new uint32[NUM_ZONES]; + for (uint32 num_zone = 0; num_zone < NUM_ZONES; num_zone++) + { + i_zones[num_zone] = V3_ARRAY(buffer, 7 - V3_OFFSET + num_zone); + } + MinixFSZone *to_delete_i_zones = minix_inode->i_zones_; + minix_inode->i_zones_ = new MinixFSZone(this, i_zones); + + if (s_magic_ == MINIX_V3) + minix_inode->i_nlink_ = ((uint16*)buffer)[1]; + else + minix_inode->i_nlink_ = buffer[13]; + minix_inode->i_size_ = ((uint32*)buffer)[1 + V3_OFFSET]; + delete to_delete_i_zones; + return 0; +} + +void MinixFSSuperblock::writeInode(Inode* inode) +{ + assert(inode); + assert(ustl::find(all_inodes_.begin(), all_inodes_.end(), inode) != all_inodes_.end()); + //flush zones + MinixFSInode *minix_inode = (MinixFSInode *) inode; + uint32 block = 2 + s_num_inode_bm_blocks_ + s_num_zone_bm_blocks_ + + ((minix_inode->i_num_ - 1) * INODE_SIZE / BLOCK_SIZE); + uint32 offset = ((minix_inode->i_num_ - 1) * INODE_SIZE) % BLOCK_SIZE; + char buffer[INODE_SIZE]; + memset((void*) buffer, 0, sizeof(buffer)); + debug(M_SB, "writeInode> reading block %d with offset %d from disc\n", block, offset); + readBytes(block, offset, INODE_SIZE, buffer); + debug(M_SB, "writeInode> read data from disc\n"); + debug(M_SB, "writeInode> the inode: i_type_: %d, i_nlink_: %d, i_size_: %d\n", minix_inode->i_type_, + minix_inode->numLinks(), minix_inode->i_size_); + if (minix_inode->i_type_ == I_FILE) + { + debug(M_SB, "writeInode> setting mode to file : %x\n", *(uint16*) buffer | 0x81FF); + *(uint16*) buffer |= 0x81FF; + } + else if (minix_inode->i_type_ == I_DIR) + { + debug(M_SB, "writeInode> setting mode to dir : %x\n", *(uint16*) buffer | 0x41FF); + *(uint16*) buffer |= 0x41FF; + } + else + { + // link etc. unhandled + } + ((uint32*)buffer)[1+V3_OFFSET] = minix_inode->i_size_; + debug(M_SB, "writeInode> write inode %p link count %u\n", inode, minix_inode->numLinks()); + if (s_magic_ == MINIX_V3) + ((uint16*)buffer)[1] = minix_inode->numLinks(); + else + buffer[13] = minix_inode->numLinks(); + debug(M_SB, "writeInode> writing bytes to disc on block %d with offset %d\n", block, offset); + writeBytes(block, offset, INODE_SIZE, buffer); + debug(M_SB, "writeInode> flushing zones of inode %p\n", inode); + minix_inode->i_zones_->flush(minix_inode->i_num_); +} + +void MinixFSSuperblock::all_inodes_add_inode(Inode* inode) +{ + all_inodes_.push_back(inode); + all_inodes_set_[((MinixFSInode*) inode)->i_num_] = inode; +} + +void MinixFSSuperblock::all_inodes_remove_inode(Inode* inode) +{ + all_inodes_.remove(inode); + all_inodes_set_.erase(((MinixFSInode*) inode)->i_num_); +} + +void MinixFSSuperblock::deleteInode(Inode* inode) +{ + assert(inode->getDentrys().size() == 0); + assert(ustl::find(used_inodes_.begin(), used_inodes_.end(), inode) == used_inodes_.end()); + dirty_inodes_.remove(inode); + MinixFSInode *minix_inode = (MinixFSInode *) inode; + all_inodes_remove_inode(minix_inode); + assert(minix_inode->i_files_.empty()); + minix_inode->i_zones_->freeZones(); + storage_manager_->freeInode(minix_inode->i_num_); + uint32 block = 2 + s_num_inode_bm_blocks_ + s_num_zone_bm_blocks_ + + ((minix_inode->i_num_ - 1) * INODE_SIZE / BLOCK_SIZE); + uint32 offset = ((minix_inode->i_num_ - 1) * INODE_SIZE) % BLOCK_SIZE; + char buffer[INODE_SIZE]; + memset((void*) buffer, 0, sizeof(buffer)); + writeBytes(block, offset, INODE_SIZE, buffer); + delete inode; +} + +uint16 MinixFSSuperblock::allocateZone() +{ + debug(M_ZONE, "MinixFSSuperblock allocateZone>\n"); + uint16 ret = (storage_manager_->allocZone() + s_1st_datazone_ - 1); // -1 because the zone nr 0 is set in the bitmap and should never be used! + debug(M_ZONE, "MinixFSSuperblock allocateZone> returning %d\n", ret); + return ret; +} + +void MinixFSSuperblock::readZone(uint16 zone, char* buffer) +{ + assert(buffer); + readBlocks(zone, ZONE_SIZE / BLOCK_SIZE, buffer); +} + +void MinixFSSuperblock::readBlocks(uint16 block, uint32 num_blocks, char* buffer) +{ + assert(buffer); +#ifdef EXE2MINIXFS + fseek((FILE*)s_dev_, offset_ + block * BLOCK_SIZE, SEEK_SET); + assert(fread(buffer, 1, BLOCK_SIZE * num_blocks, (FILE*)s_dev_) == BLOCK_SIZE * num_blocks); +#else + BDVirtualDevice* bdvd = BDManager::getInstance()->getDeviceByNumber(s_dev_); + bdvd->readData(block * bdvd->getBlockSize(), num_blocks * bdvd->getBlockSize(), buffer); +#endif +} + +void MinixFSSuperblock::writeZone(uint16 zone, char* buffer) +{ + writeBlocks(zone, ZONE_SIZE / BLOCK_SIZE, buffer); +} + +void MinixFSSuperblock::writeBlocks(uint16 block, uint32 num_blocks, char* buffer) +{ +#ifdef EXE2MINIXFS + fseek((FILE*)s_dev_, offset_ + block * BLOCK_SIZE, SEEK_SET); + assert(fwrite(buffer, 1, BLOCK_SIZE * num_blocks, (FILE*)s_dev_) == BLOCK_SIZE * num_blocks); +#else + BDVirtualDevice* bdvd = BDManager::getInstance()->getDeviceByNumber(s_dev_); + bdvd->writeData(block * bdvd->getBlockSize(), num_blocks * bdvd->getBlockSize(), buffer); +#endif +} + +int32 MinixFSSuperblock::readBytes(uint32 block, uint32 offset, uint32 size, char* buffer) +{ + assert(offset+size <= BLOCK_SIZE); + char rbuffer[BLOCK_SIZE]; + readBlocks(block, 1, rbuffer); + memcpy(rbuffer + offset, buffer, size); + return size; +} + +int32 MinixFSSuperblock::writeBytes(uint32 block, uint32 offset, uint32 size, char* buffer) +{ + assert(offset+size <= BLOCK_SIZE); + char wbuffer[BLOCK_SIZE]; + readBlocks(block, 1, wbuffer); + memcpy(wbuffer + offset, buffer, size); + writeBlocks(block, 1, wbuffer); + return size; +} + +void MinixFSSuperblock::freeZone(uint16 index) +{ + storage_manager_->freeZone(index - s_1st_datazone_ + 1); +} diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixFSType.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSType.cpp new file mode 100644 index 0000000..4eb48c5 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSType.cpp @@ -0,0 +1,31 @@ +#include "MinixFSType.h" +#include "MinixFSSuperblock.h" +#include "BDManager.h" +#include "BDVirtualDevice.h" + +MinixFSType::MinixFSType() : FileSystemType("minixfs") +{ + fs_flags_ |= FS_REQUIRES_DEV; +} + + +MinixFSType::~MinixFSType() +{ +} + + +Superblock *MinixFSType::readSuper(Superblock *superblock, void*) const +{ + return superblock; +} + + +Superblock *MinixFSType::createSuper(uint32 s_dev) +{ + if (s_dev == (uint32) -1) + return 0; + + BDManager::getInstance()->getDeviceByNumber(s_dev)->setBlockSize(BLOCK_SIZE); + Superblock *super = new MinixFSSuperblock(this, s_dev, 0); + return super; +} diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixFSZone.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSZone.cpp new file mode 100644 index 0000000..e8a0b5d --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixFSZone.cpp @@ -0,0 +1,248 @@ +#include "MinixFSZone.h" +#include "MinixFSSuperblock.h" +#ifndef EXE2MINIXFS +#include "kstring.h" +#endif +#include "kprintf.h" +#include +#include "minix_fs_consts.h" + +MinixFSZone::MinixFSZone(MinixFSSuperblock *superblock, uint32 *zones) +{ + superblock_ = superblock; + num_zones_ = 0; + for (uint32 i = 0; i < NUM_ZONES; i++) + { + direct_zones_[i] = zones[i]; + if (zones[i] && i < 7) + ++num_zones_; + debug(M_ZONE, "zone: %x\t", zones[i]); + } + char buffer[ZONE_SIZE]; + if (zones[7]) + { + indirect_zones_ = new uint32[NUM_ZONE_ADDRESSES]; + superblock_->readZone(zones[7], buffer); + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + { + indirect_zones_[i] = V3_ARRAY(buffer,i); + if (indirect_zones_[i]) + ++num_zones_; + } + } + else + { + indirect_zones_ = 0; + } + if (zones[8]) + { + double_indirect_zones_ = new uint32*[NUM_ZONE_ADDRESSES]; + double_indirect_linking_zone_ = new uint32[NUM_ZONE_ADDRESSES]; + superblock_->readZone(zones[8], buffer); + char ind_buffer[ZONE_SIZE]; + for (uint32 ind_zone = 0; ind_zone < NUM_ZONE_ADDRESSES; ind_zone++) + { + double_indirect_linking_zone_[ind_zone] = V3_ARRAY(buffer,ind_zone); + if (double_indirect_linking_zone_[ind_zone]) + { + superblock_->readZone(double_indirect_linking_zone_[ind_zone], ind_buffer); + double_indirect_zones_[ind_zone] = new uint32[NUM_ZONE_ADDRESSES]; + + for (uint32 d_ind_zone = 0; d_ind_zone < NUM_ZONE_ADDRESSES; d_ind_zone++) + { + double_indirect_zones_[ind_zone][d_ind_zone] = V3_ARRAY(ind_buffer,d_ind_zone); + if (double_indirect_zones_[ind_zone][d_ind_zone]) + ++num_zones_; + } + } + else + { + double_indirect_zones_[ind_zone] = 0; + } + } + } + else + { + double_indirect_zones_ = 0; + double_indirect_linking_zone_ = 0; + } + + if (M_ZONE & OUTPUT_ENABLED) + { + kprintfd("=========Zones:======%d=======\n", num_zones_); + kprintfd("====direct Zones:====\n"); + uint32 print_num_zones = 0; + for (uint32 i = 0; i < NUM_ZONES; i++, print_num_zones++) + { + kprintfd("====zone: %x\t", direct_zones_[i]); + } + kprintfd("===indirect Zones:===\n"); + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES && print_num_zones < num_zones_; i++, print_num_zones++) + { + kprintfd("===zone: %x\t", indirect_zones_[i]); + } + kprintfd("=dblindirect Zones:==\n"); + for (uint32 ind_zone = 0; ind_zone < NUM_ZONE_ADDRESSES && print_num_zones < num_zones_; + ind_zone++, print_num_zones++) + { + for (uint32 d_ind_zone = 0; d_ind_zone < NUM_ZONE_ADDRESSES && print_num_zones < num_zones_; + d_ind_zone++, print_num_zones++) + { + kprintfd("=zone: %x\t", double_indirect_zones_[ind_zone][d_ind_zone]); + } + } + } +} + +MinixFSZone::~MinixFSZone() +{ + if (double_indirect_zones_) + { + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + { + delete[] double_indirect_zones_[i]; + } + delete[] double_indirect_zones_; + delete[] double_indirect_linking_zone_; + } + + delete[] indirect_zones_; +} + +uint32 MinixFSZone::getZone(uint32 index) +{ + assert(index < num_zones_); + if (index < 7) + return direct_zones_[index]; + index -= 7; + if (index < NUM_ZONE_ADDRESSES) + return indirect_zones_[index]; + index -= NUM_ZONE_ADDRESSES; + return double_indirect_zones_[index / NUM_ZONE_ADDRESSES][index % NUM_ZONE_ADDRESSES]; +} + +void MinixFSZone::setZone(uint32 index, uint32 zone) +{ + debug(M_ZONE, "MinixFSZone::setZone> index: %d, zone: %d\n", index, zone); + if (index < 7) + { + direct_zones_[index] = zone; + ++num_zones_; + return; + } + index -= 7; + if (index < NUM_ZONE_ADDRESSES) + { + if (!indirect_zones_) + { + direct_zones_[7] = superblock_->allocateZone(); + indirect_zones_ = new uint32[NUM_ZONE_ADDRESSES]; + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + indirect_zones_[i] = 0; + } + indirect_zones_[index] = zone; + ++num_zones_; + return; + } + index -= NUM_ZONE_ADDRESSES; + if (!double_indirect_zones_) + { + direct_zones_[8] = superblock_->allocateZone(); + double_indirect_linking_zone_ = new uint32[NUM_ZONE_ADDRESSES]; + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + double_indirect_linking_zone_[i] = 0; + + double_indirect_zones_ = new uint32*[NUM_ZONE_ADDRESSES]; + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + double_indirect_zones_[i] = 0; + } + if (!double_indirect_zones_[index / NUM_ZONE_ADDRESSES]) + { + double_indirect_linking_zone_[index / NUM_ZONE_ADDRESSES] = superblock_->allocateZone(); + double_indirect_zones_[index / NUM_ZONE_ADDRESSES] = new uint32[NUM_ZONE_ADDRESSES]; + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + double_indirect_zones_[index / NUM_ZONE_ADDRESSES][i] = 0; + } + double_indirect_zones_[index / NUM_ZONE_ADDRESSES][index % NUM_ZONE_ADDRESSES] = zone; + + ++num_zones_; +} + +void MinixFSZone::addZone(uint32 zone) +{ + setZone(num_zones_, zone); +} + +void MinixFSZone::flush(uint32 i_num) +{ + debug(M_ZONE, "MinixFSZone::flush i_num : %d; %p\n", i_num, this); + char buffer[NUM_ZONES * INODE_BYTES]; + for (uint32 index = 0; index < NUM_ZONES; index++) + SET_V3_ARRAY(buffer,index,direct_zones_[index]); + uint32 block = 2 + superblock_->s_num_inode_bm_blocks_ + superblock_->s_num_zone_bm_blocks_ + + ((i_num - 1) * INODE_SIZE) / BLOCK_SIZE; + superblock_->writeBytes(block, ((i_num - 1) * INODE_SIZE) % BLOCK_SIZE + INODE_BYTES * (7 - V3_OFFSET), + NUM_ZONES * INODE_BYTES, buffer); + debug(M_ZONE, "MinixFSZone::flush direct written\n"); + if (direct_zones_[7]) + { + char ind_buffer[ZONE_SIZE]; + debug(M_ZONE, "MinixFSZone::flush writing indirect\n"); + assert(indirect_zones_); + memset((void*)ind_buffer, 0, sizeof(ind_buffer)); + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + SET_V3_ARRAY(ind_buffer,i,indirect_zones_[i]); + superblock_->writeZone(direct_zones_[7], ind_buffer); + } + + if (direct_zones_[8]) + { + char dbl_ind_buffer[ZONE_SIZE]; + assert(double_indirect_linking_zone_); + assert(double_indirect_zones_); + for (uint32 ind_zone = 0; ind_zone < NUM_ZONE_ADDRESSES; ind_zone++) + SET_V3_ARRAY(dbl_ind_buffer, ind_zone, double_indirect_linking_zone_[ind_zone]); + superblock_->writeZone(direct_zones_[8], dbl_ind_buffer); + for (uint32 ind_zone = 0; ind_zone < NUM_ZONE_ADDRESSES; ind_zone++) + { + if (double_indirect_linking_zone_[ind_zone]) + { + memset((void*)dbl_ind_buffer, 0, sizeof(dbl_ind_buffer)); + for (uint32 d_ind_zone = 0; d_ind_zone < NUM_ZONE_ADDRESSES; d_ind_zone++) + SET_V3_ARRAY(dbl_ind_buffer, d_ind_zone, double_indirect_zones_[ind_zone][d_ind_zone]); + superblock_->writeZone(double_indirect_linking_zone_[ind_zone], dbl_ind_buffer); + } + } + } +} + +void MinixFSZone::freeZones() +{ + for (uint32 i = 0; i < NUM_ZONES; i++) + if (direct_zones_[i]) + superblock_->freeZone(direct_zones_[i]); + + if (!indirect_zones_) + return; + + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + if (indirect_zones_[i]) + superblock_->freeZone(indirect_zones_[i]); + + if (!double_indirect_linking_zone_) + return; + + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + if (double_indirect_linking_zone_[i]) + superblock_->freeZone(double_indirect_linking_zone_[i]); + + if (!double_indirect_zones_) + return; + + for (uint32 i = 0; i < NUM_ZONE_ADDRESSES; i++) + if (double_indirect_zones_[i]) + for (uint32 j = 0; j < NUM_ZONE_ADDRESSES; j++) + if (double_indirect_zones_[i][j]) + superblock_->freeZone(double_indirect_zones_[i][j]); +} + diff --git a/pwn/flipper/dist/common/source/fs/minixfs/MinixStorageManager.cpp b/pwn/flipper/dist/common/source/fs/minixfs/MinixStorageManager.cpp new file mode 100644 index 0000000..0ee3169 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/MinixStorageManager.cpp @@ -0,0 +1,184 @@ +#include "MinixStorageManager.h" +#include "MinixFSSuperblock.h" +#include +#include "kprintf.h" + +MinixStorageManager::MinixStorageManager(char *bm_buffer, uint16 num_inode_bm_blocks, uint16 num_zone_bm_blocks, + uint16 num_inodes, uint16 num_zones) : + StorageManager(num_inodes, num_zones) +{ + debug(M_STORAGE_MANAGER, + "Constructor: num_inodes:%d\tnum_inode_bm_blocks:%d\tnum_zones:%d\tnum_zone_bm_blocks:%d\t\n", num_inodes, + num_inode_bm_blocks, num_zones, num_zone_bm_blocks); + + num_inode_bm_blocks_ = num_inode_bm_blocks; + num_zone_bm_blocks_ = num_zone_bm_blocks; + + uint32 i_byte = 0; + for (; i_byte < num_inodes / 8; i_byte++) + { + inode_bitmap_.setByte(i_byte, bm_buffer[i_byte]); + } + for (uint32 i_bit = 0; i_bit < num_inodes % 8; i_bit++) + { + uint8 byte = bm_buffer[i_byte]; + if ((byte >> i_bit) & 0x01) + inode_bitmap_.setBit(i_byte * 8 + i_bit); + } + //read zone bitmap + uint32 z_byte = num_inode_bm_blocks * BLOCK_SIZE; + uint32 z_bm_byte = 0; + for (; z_bm_byte < num_zones / 8; z_byte++, z_bm_byte++) + { + zone_bitmap_.setByte(z_bm_byte, bm_buffer[z_byte]); + } + for (uint32 z_bit = 0; z_bit < num_zones % 8; z_bit++) + { + uint8 byte = bm_buffer[z_byte]; + if ((byte >> z_bit) & 0x01) + zone_bitmap_.setBit(z_bm_byte * 8 + z_bit); + } + curr_inode_pos_ = 0; + curr_zone_pos_ = 0; +} + +MinixStorageManager::~MinixStorageManager() +{ + debug(M_STORAGE_MANAGER, "Destructor: destroyed\n"); +} + +bool MinixStorageManager::isInodeSet(size_t index) +{ + assert(index < inode_bitmap_.getSize() && "MinixStorageManager::isInodeSet called with bad index number"); + return inode_bitmap_.getBit(index); +} + +uint32 MinixStorageManager::getNumUsedInodes() +{ + return inode_bitmap_.getNumBitsSet(); +} + +size_t MinixStorageManager::allocZone() +{ + size_t pos = curr_zone_pos_ + 1; + for (; pos != curr_zone_pos_; ++pos) + { + if (pos >= zone_bitmap_.getSize()) + { + pos = 0; + if(pos == curr_zone_pos_) // Increment happens before check in for loop, which would lead to an infinite loop when curr_zone_pos_ = 0 + { + break; + } + } + if (!zone_bitmap_.getBit(pos)) + { + zone_bitmap_.setBit(pos); + curr_zone_pos_ = pos; + debug(M_STORAGE_MANAGER, "acquireZone: Zone %zu acquired\n", pos); + return pos; + } + } + debug(M_STORAGE_MANAGER, "acquireZone: NO FREE ZONE FOUND!\n"); + assert(false); // full memory should have been checked. + return 0; +} + +size_t MinixStorageManager::allocInode() +{ + size_t pos = curr_inode_pos_ + 1; + for (; pos != curr_inode_pos_; pos++) + { + if (pos >= inode_bitmap_.getSize()) + pos = 0; + if (!inode_bitmap_.getBit(pos)) + { + inode_bitmap_.setBit(pos); + curr_inode_pos_ = pos; + debug(M_STORAGE_MANAGER, "acquireInode: Inode %zu acquired\n", pos); + return pos; + } + } + kprintfd("acquireInode: NO FREE INODE FOUND!\n"); + assert(false); // full memory should have been checked. + return 0; +} + +void MinixStorageManager::freeZone(size_t index) +{ + zone_bitmap_.unsetBit(index); + debug(M_STORAGE_MANAGER, "freeZone: Zone %zu freed\n", index); +} + +void MinixStorageManager::freeInode(size_t index) +{ + inode_bitmap_.unsetBit(index); + debug(M_STORAGE_MANAGER, "freeInode: Inode %zu freed\n", index); +} + +void MinixStorageManager::flush(MinixFSSuperblock *superblock) +{ + debug(M_STORAGE_MANAGER, "flush: starting flushing\n"); + char* bm_buffer = new char[(num_inode_bm_blocks_ + num_zone_bm_blocks_) * BLOCK_SIZE]; + uint32 num_inodes = inode_bitmap_.getSize(); + uint32 i_byte = 0; + for (; i_byte < num_inodes / 8; i_byte++) + { + bm_buffer[i_byte] = inode_bitmap_.getByte(i_byte); + } + uint8 byte = 0; + for (uint32 i_bit = 0; i_bit < 8; i_bit++) + { + if (i_bit < num_inodes % 8) + { + if (inode_bitmap_.getBit(i_byte * 8 + i_bit)) + { + byte &= 0x01 << i_bit; + } + } + else + byte &= 0x01 << i_bit; + } + bm_buffer[i_byte] = byte; + ++i_byte; + for (; i_byte < num_inode_bm_blocks_ * BLOCK_SIZE; i_byte++) + { + bm_buffer[i_byte] = 0xff; + } + + uint32 num_zones = zone_bitmap_.getSize(); + uint32 z_byte = 0; + for (; z_byte < num_zones / 8; z_byte++, i_byte++) + { + bm_buffer[i_byte] = zone_bitmap_.getByte(z_byte); + } + byte = 0; + for (uint32 z_bit = 0; z_bit < 8; z_bit++) + { + if (z_bit < num_zones % 8) + { + if (zone_bitmap_.getBit(z_byte * 8 + z_bit)) + { + byte &= 0x01 << z_bit; + } + } + else + byte &= 0x01 << z_bit; + } + bm_buffer[i_byte] = byte; + ++z_byte; + ++i_byte; + for (; z_byte < num_zone_bm_blocks_ * BLOCK_SIZE; z_byte++, i_byte++) + { + bm_buffer[i_byte] = 0xff; + } + superblock->writeBlocks(2, num_inode_bm_blocks_ + num_zone_bm_blocks_, bm_buffer); + delete[] bm_buffer; + debug(M_STORAGE_MANAGER, "flush: flushing finished\n"); +} + +void MinixStorageManager::printBitmap() +{ + inode_bitmap_.bmprint(); + zone_bitmap_.bmprint(); +} diff --git a/pwn/flipper/dist/common/source/fs/minixfs/StorageManager.cpp b/pwn/flipper/dist/common/source/fs/minixfs/StorageManager.cpp new file mode 100644 index 0000000..8f53b30 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/minixfs/StorageManager.cpp @@ -0,0 +1,11 @@ +#include "StorageManager.h" + +StorageManager::StorageManager(uint16 num_inodes, uint16 num_zones) : + inode_bitmap_(num_inodes), zone_bitmap_(num_zones) +{ +} + +StorageManager::~StorageManager() +{ +} + diff --git a/pwn/flipper/dist/common/source/fs/ramfs/CMakeLists.txt b/pwn/flipper/dist/common/source/fs/ramfs/CMakeLists.txt new file mode 100644 index 0000000..dc3b9b4 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/ramfs/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(../../../include/fs/ramfs) + +add_project_library(common_fs_ramfs) \ No newline at end of file diff --git a/pwn/flipper/dist/common/source/fs/ramfs/RamFSFile.cpp b/pwn/flipper/dist/common/source/fs/ramfs/RamFSFile.cpp new file mode 100644 index 0000000..6d4cd08 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/ramfs/RamFSFile.cpp @@ -0,0 +1,64 @@ +#include "fs/ramfs/RamFSInode.h" +#include "fs/ramfs/RamFSFile.h" +#include "fs/ramfs/RamFSSuperblock.h" +#include "fs/Dentry.h" + +#define ERROR_FRO "ERROR: The flag muss be READONLY for several opened files" +#define ERROR_FF "ERROR: The flag does not allow this operation" +#define ERROR_FNO "ERROR: The file is not open." + +RamFSFile::RamFSFile(Inode* inode, Dentry* dentry, uint32 flag) : + File(inode, dentry, flag) +{ + f_superblock_ = inode->getSuperblock(); + offset_ = 0; +} + +RamFSFile::~RamFSFile() +{ +} + +int32 RamFSFile::read(char *buffer, size_t count, l_off_t offset) +{ + if (((flag_ & O_RDONLY) || (flag_ & O_RDWR)) && (f_inode_->getMode() & A_READABLE)) + { + int32 read_bytes = f_inode_->readData(offset_ + offset, count, buffer); + offset_ += read_bytes; + return read_bytes; + } + else + { + // ERROR_FF + return -1; + } +} + +int32 RamFSFile::write(const char *buffer, size_t count, l_off_t offset) +{ + if (((flag_ & O_WRONLY) || (flag_ & O_RDWR)) && (f_inode_->getMode() & A_WRITABLE)) + { + int32 written_bytes = f_inode_->writeData(offset_ + offset, count, buffer); + offset_ += written_bytes; + return written_bytes; + } + else + { + // ERROR_FF + return -1; + } +} + +int32 RamFSFile::open(uint32 __attribute__((unused)) flag) +{ + return 0; +} + +int32 RamFSFile::close() +{ + return 0; +} + +int32 RamFSFile::flush() +{ + return 0; +} diff --git a/pwn/flipper/dist/common/source/fs/ramfs/RamFSInode.cpp b/pwn/flipper/dist/common/source/fs/ramfs/RamFSInode.cpp new file mode 100644 index 0000000..0926bec --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/ramfs/RamFSInode.cpp @@ -0,0 +1,74 @@ +#include "fs/ramfs/RamFSInode.h" +#include "kstring.h" +#include "assert.h" +#include "fs/ramfs/RamFSSuperblock.h" +#include "fs/ramfs/RamFSFile.h" +#include "fs/Dentry.h" +#include "FileSystemType.h" + +#include "console/kprintf.h" + +#define BASIC_ALLOC 256 + +RamFSInode::RamFSInode(Superblock *super_block, uint32 inode_type) : + Inode(super_block, inode_type), + data_(0) +{ + debug(RAMFS, "New RamFSInode %p\n", this); + if (inode_type == I_FILE) + { + data_ = new char[BASIC_ALLOC](); + i_size_ = BASIC_ALLOC; + } +} + +RamFSInode::~RamFSInode() +{ + debug(RAMFS, "Destroying RamFSInode %p\n", this); + delete[] data_; +} + +int32 RamFSInode::readData(uint32 offset, uint32 size, char *buffer) +{ + if(offset >= getSize()) + { + return 0; + } + + uint32 read_size = Min(size, getSize() - offset); + + char *ptr_offset = data_ + offset; + memcpy(buffer, ptr_offset, read_size); + return read_size; +} + +int32 RamFSInode::writeData(uint32 offset, uint32 size, const char *buffer) +{ + assert(i_type_ == I_FILE); + + if(offset >= getSize()) + { + return 0; + } + + uint32 write_size = Min(size, getSize() - offset); + if(write_size != size) + { + debug(RAMFS, "WARNING: RamFS currently does not support expanding files via the write syscall\n"); + } + + char *ptr_offset = data_ + offset; + memcpy(ptr_offset, buffer, write_size); + return write_size; +} + +File* RamFSInode::open(Dentry* dentry, uint32 flag) +{ + debug(INODE, "%s Inode: Open file\n", getSuperblock()->getFSType()->getFSName()); + assert(ustl::find(i_dentrys_.begin(), i_dentrys_.end(), dentry) != i_dentrys_.end()); + + File* file = (File*) (new RamFSFile(this, dentry, flag)); + i_files_.push_back(file); + getSuperblock()->fileOpened(file); + return file; +} diff --git a/pwn/flipper/dist/common/source/fs/ramfs/RamFSSuperblock.cpp b/pwn/flipper/dist/common/source/fs/ramfs/RamFSSuperblock.cpp new file mode 100644 index 0000000..7fc7ab2 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/ramfs/RamFSSuperblock.cpp @@ -0,0 +1,64 @@ +#include "fs/FileDescriptor.h" +#include "fs/ramfs/RamFSSuperblock.h" +#include "fs/ramfs/RamFSInode.h" +#include "fs/ramfs/RamFSFile.h" +#include "fs/ramfs/RamFSType.h" +#include "fs/Dentry.h" +#include "assert.h" + +#include "console/kprintf.h" +#include "console/debug.h" +#define ROOT_NAME "/" + +RamFSSuperblock::RamFSSuperblock(RamFSType* fs_type, uint32 s_dev) : + Superblock(fs_type, s_dev) +{ + Inode *root_inode = createInode(I_DIR); + s_root_ = new Dentry(root_inode); + assert(root_inode->mkdir(s_root_) == 0); +} + +RamFSSuperblock::~RamFSSuperblock() +{ + assert(dirty_inodes_.empty() == true); + + releaseAllOpenFiles(); + + deleteAllInodes(); +} + +Inode* RamFSSuperblock::createInode(uint32 type) +{ + debug(RAMFS, "createInode, type: %x\n", type); + auto inode = new RamFSInode(this, type); + + all_inodes_.push_back(inode); + return inode; +} + +int32 RamFSSuperblock::readInode(Inode* inode) +{ + assert(inode); + + if (ustl::find(all_inodes_, inode) == all_inodes_.end()) + { + all_inodes_.push_back(inode); + } + return 0; +} + +void RamFSSuperblock::writeInode(Inode* inode) +{ + assert(inode); + + if (ustl::find(all_inodes_, inode) == all_inodes_.end()) + { + all_inodes_.push_back(inode); + } +} + +void RamFSSuperblock::deleteInode(Inode* inode) +{ + all_inodes_.remove(inode); + delete inode; +} diff --git a/pwn/flipper/dist/common/source/fs/ramfs/RamFSType.cpp b/pwn/flipper/dist/common/source/fs/ramfs/RamFSType.cpp new file mode 100644 index 0000000..4546976 --- /dev/null +++ b/pwn/flipper/dist/common/source/fs/ramfs/RamFSType.cpp @@ -0,0 +1,24 @@ +#include "fs/ramfs/RamFSType.h" +#include "fs/ramfs/RamFSSuperblock.h" + + +RamFSType::RamFSType() : FileSystemType("ramfs") +{ +} + + +RamFSType::~RamFSType() +{} + + +Superblock *RamFSType::readSuper(Superblock *superblock, void*) const +{ + return superblock; +} + + +Superblock *RamFSType::createSuper (uint32 s_dev) +{ + Superblock *super = new RamFSSuperblock(this, s_dev); + return super; +} diff --git a/pwn/flipper/dist/common/source/ustl/CMakeLists.txt b/pwn/flipper/dist/common/source/ustl/CMakeLists.txt new file mode 100644 index 0000000..73ad637 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(../../include/ustl) + +add_project_library(common_ustl) diff --git a/pwn/flipper/dist/common/source/ustl/LICENSE b/pwn/flipper/dist/common/source/ustl/LICENSE new file mode 100644 index 0000000..ad459b2 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/LICENSE @@ -0,0 +1,24 @@ +License for the USTL, forked from https://github.com/msharov/ustl + + + The MIT License + +Copyright (c) 2005 by Mike Sharov + +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. diff --git a/pwn/flipper/dist/common/source/ustl/cmemlink.cpp b/pwn/flipper/dist/common/source/ustl/cmemlink.cpp new file mode 100644 index 0000000..91dd8a3 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/cmemlink.cpp @@ -0,0 +1,68 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "cmemlink.h" +//#include "ofstream.h" +#include "strmsize.h" +#include "ualgo.h" +#include "panic.h" + +namespace ustl { + +/// \brief Attaches the object to pointer \p p of size \p n. +/// +/// If \p p is nullptr and \p n is non-zero, bad_alloc is thrown and current +/// state remains unchanged. +/// +void cmemlink::link (const void* p, size_type n) +{ + if (!p && n) + kpanict("bad_alloc"); + //throw bad_alloc (n); + unlink(); + relink (p, n); +} + +/// Writes the object to stream \p os +/*void cmemlink::write (ostream& os) const +{ + const written_size_type sz (size()); + assert (sz == size() && "No support for writing memblocks larger than 4G"); + os << sz; + os.write (cdata(), sz); + os.align (stream_align_of (sz)); +} + +/// Writes the object to stream \p os +void cmemlink::text_write (ostringstream& os) const +{ + os.write (begin(), readable_size()); +}*/ + +/// Returns the number of bytes required to write this object to a stream. +cmemlink::size_type cmemlink::stream_size (void) const noexcept +{ + const written_size_type sz (size()); + return Align (stream_size_of (sz) + sz, stream_align_of(sz)); +} + +/// Writes the data to file \p "filename". +/*void cmemlink::write_file (const char* filename, int mode) const +{ + fstream f; + f.exceptions (fstream::allbadbits); + f.open (filename, fstream::out | fstream::trunc, mode); + f.write (cdata(), readable_size()); + f.close(); +}*/ + +/// Compares to memory block pointed by l. Size is compared first. +bool cmemlink::operator== (const cmemlink& l) const noexcept +{ + return l._size == _size && + (l._data == _data || 0 == memcmp (l._data, _data, _size)); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/debugchecks.cpp b/pwn/flipper/dist/common/source/ustl/debugchecks.cpp new file mode 100644 index 0000000..2fb4d3e --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/debugchecks.cpp @@ -0,0 +1,24 @@ +#include "ArchInterrupts.h" +#include "Scheduler.h" +#include "kprintf.h" +#include "KernelMemoryManager.h" +#include "Thread.h" +#include "types.h" + +namespace ustl +{ + void checkKMMDeadlock() + { + if (unlikely (ArchInterrupts::testIFSet() == false || Scheduler::instance()->isSchedulingEnabled() == false)) + { + if (unlikely (KernelMemoryManager::instance()->KMMLockHeldBy() != 0)) + { + system_state = KPANIC; + kprintfd("(ERROR) checkKMMDeadlock: Using a not resize-safe ustl container method with IF=%d and SchedulingEnabled=%d ! This will fail!!!\n", + ArchInterrupts::testIFSet(), Scheduler::instance()->isSchedulingEnabled()); + currentThread->printBacktrace(true); + assert(false); + } + } + } +} diff --git a/pwn/flipper/dist/common/source/ustl/memblock.cpp b/pwn/flipper/dist/common/source/ustl/memblock.cpp new file mode 100644 index 0000000..0cc9589 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/memblock.cpp @@ -0,0 +1,163 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "mistream.h" +#include "memblock.h" +#include "ualgo.h" +#include "umemory.h" +//#include "fstream.h" +#include "kmalloc.h" +#include "panic.h" + +namespace ustl { + +memblock::memblock (void) noexcept : memlink(), _capacity (0) { } +memblock::memblock (const void* p, size_type n) : memlink(), _capacity (0) { assign (p, n); } +memblock::memblock (size_type n) : memlink(), _capacity (0) { resize (n); } +memblock::memblock (const cmemlink& b) : memlink(), _capacity (0) { assign (b); } +memblock::memblock (const memlink& b) : memlink(), _capacity (0) { assign (b); } +memblock::memblock (const memblock& b) : memlink(), _capacity (0) { assign (b); } +memblock::~memblock (void) noexcept { deallocate(); } + +void memblock::unlink (void) noexcept +{ + _capacity = 0; + memlink::unlink(); +} + +/// resizes the block to \p newSize bytes, reallocating if necessary. +void memblock::resize (size_type newSize, bool bExact) +{ + if (_capacity < newSize + minimumFreeCapacity()) + reserve (newSize, bExact); + memlink::resize (newSize); +} + +/// Frees internal data. +void memblock::deallocate (void) noexcept +{ + if (_capacity) { + assert (cdata() && "Internal error: space allocated, but the pointer is nullptr"); + assert (data() && "Internal error: read-only block is marked as allocated space"); + kfree (data()); + } + unlink(); +} + +/// Assumes control of the memory block \p p of size \p n. +/// The block assigned using this function will be freed in the destructor. +void memblock::manage (void* p, size_type n) noexcept +{ + assert (p || !n); + assert (!_capacity && "Already managing something. deallocate or unlink first."); + link (p, n); + _capacity = n; +} + +/// "Instantiate" a linked block by allocating and copying the linked data. +void memblock::copy_link (void) +{ + reserve (size()); +} + +/// Copies data from \p p, \p n. +void memblock::assign (const void* p, size_type n) +{ + assert ((static_cast(p) != cdata() || size() == n) && "Self-assignment can not resize"); + resize (n); + copy_n (const_pointer(p), n, begin()); +} + +/// \brief Reallocates internal block to hold at least \p newSize bytes. +/// +/// Additional memory may be allocated, but for efficiency it is a very +/// good idea to call reserve before doing byte-by-byte edit operations. +/// The block size as returned by size() is not altered. reserve will not +/// reduce allocated memory. If you think you are wasting space, call +/// deallocate and start over. To avoid wasting space, use the block for +/// only one purpose, and try to get that purpose to use similar amounts +/// of memory on each iteration. +/// +void memblock::reserve (size_type newSize, bool bExact) +{ + if ((newSize += minimumFreeCapacity()) <= _capacity) + return; + extern void checkKMMDeadlock(); + checkKMMDeadlock(); + pointer oldBlock (is_linked() ? nullptr : data()); + const size_t alignedSize (NextPow2 (newSize)); + if (!bExact) + newSize = alignedSize; + pointer newBlock = static_cast (krealloc (oldBlock, newSize)); + if (!newBlock) + kpanict("bad_alloc"); + if (!oldBlock & (cdata() != nullptr)) + copy_n (cdata(), min (size() + 1, newSize), newBlock); + link (newBlock, size()); + _capacity = newSize; +} + +/// Reduces capacity to match size +void memblock::shrink_to_fit (void) +{ + if (is_linked()) + return; + pointer newBlock = static_cast (krealloc (begin(), size())); + if (!newBlock && size()) + kpanict("bad_alloc"); + _capacity = size(); + memlink::relink (newBlock, size()); +} + +/// Shifts the data in the linked block from \p start to \p start + \p n. +memblock::iterator memblock::insert (const_iterator start, size_type n) +{ + const uoff_t ip = start - begin(); + assert (ip <= size()); + resize (size() + n, false); + memlink::insert (iat(ip), n); + return iat (ip); +} + +/// Shifts the data in the linked block from \p start + \p n to \p start. +memblock::iterator memblock::erase (const_iterator start, size_type n) +{ + const uoff_t ep = start - begin(); + assert (ep + n <= size()); + reserve (size()); // copy-on-write + iterator iep = iat(ep); + memlink::erase (iep, n); + memlink::resize (size() - n); + return iep; +} + +/// Reads the object from stream \p s +/*void memblock::read (istream& is) +{ + written_size_type n = 0; + is >> n; + if (!is.verify_remaining ("read", "ustl::memblock", n)) + return; + resize (n); + is.read (data(), writable_size()); + is.align (stream_align_of (n)); +} + +/// Reads the entire file \p "filename". +void memblock::read_file (const char* filename) +{ + fstream f; + f.exceptions (fstream::allbadbits); + f.open (filename, fstream::in); + const off_t fsize (f.size()); + reserve (fsize); + f.read (data(), fsize); + f.close(); + resize (fsize); +}*/ + +memblock::size_type memblock::minimumFreeCapacity (void) const noexcept { return 0; } + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/memlink.cpp b/pwn/flipper/dist/common/source/ustl/memlink.cpp new file mode 100644 index 0000000..e427b60 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/memlink.cpp @@ -0,0 +1,44 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "memlink.h" +//#include "mistream.h" +//#include "ustdxept.h" + +namespace ustl { + +/// Reads the object from stream \p s +/*void memlink::read (istream& is) +{ + written_size_type n = 0; + is >> n; + if (!is.verify_remaining ("read", "ustl::memlink", n)) + return; + if (n > size()) + throw length_error ("memlink can not increase the size of the linked storage for reading"); + resize (n); + is.read (data(), n); + is.align (stream_align_of (n)); +}*/ + +/// Fills the linked block with the given pattern. +/// \arg start Offset at which to start filling the linked block +/// \arg p Pointer to the pattern. +/// \arg elSize Size of the pattern. +/// \arg elCount Number of times to write the pattern. +/// Total number of bytes written is \p elSize * \p elCount. +/// +void memlink::fill (const_iterator cstart, const void* p, size_type elSize, size_type elCount) noexcept +{ + assert (data() || !elCount || !elSize); + assert (cstart >= begin() && cstart + elSize * elCount <= end()); + iterator start = const_cast(cstart); + if (elSize == 1) + fill_n (start, elCount, *reinterpret_cast(p)); + else while (elCount--) + start = copy_n (const_iterator(p), elSize, start); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/mistream.cpp b/pwn/flipper/dist/common/source/ustl/mistream.cpp new file mode 100644 index 0000000..700a336 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/mistream.cpp @@ -0,0 +1,130 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "mistream.h" +#include "sostream.h" +//#include "ustdxept.h" +#include "ustring.h" +#include "ualgo.h" +#include "kprintf.h" +#include "panic.h" + +namespace ustl { + +//-------------------------------------------------------------------- + +/// Checks that \p n bytes are available in the stream, or else throws. +void ios_base::overrun (__attribute__((unused)) const char* op, __attribute__((unused)) const char* type, __attribute__((unused)) uint32_t n, __attribute__((unused)) uint32_t pos, uint32_t rem) +{ + if (set_and_throw (rem ? failbit : (failbit | eofbit))) + /* throw stream_bounds_exception (op, type, pos, n, rem)*/{ kprintfd("ERROR stream_bounds_exception: %s:%d", __FILE__, __LINE__); kpanict("ERROR stream_bounds_exception " LOCATION); } +} + +//-------------------------------------------------------------------- + +/// Attaches to the block pointed to by source of size source.pos() +istream::istream (const ostream& source) noexcept +: cmemlink (source.begin(), source.pos()) +,_pos (0) +{ +} + +void istream::unlink (void) noexcept { cmemlink::unlink(); _pos = 0; } +void ostream::unlink (void) noexcept { memlink::unlink(); _pos = 0; } + +/// Writes all unread bytes into \p os. +void istream::write (ostream& os) const +{ + os.write (ipos(), remaining()); +} + +/// Writes the object to stream \p os. +/*void istream::text_write (ostringstream& os) const +{ + os.write (ipos(), remaining()); +}*/ + +/// Reads a null-terminated string into \p str. +void istream::read_strz (string& str) +{ + const_iterator zp = find (ipos(), end(), '\0'); + if (zp == end()) + zp = ipos(); + const size_type strl = distance (ipos(), zp); + str.assign (ipos(), strl); + _pos += strl + 1; +} + +/// Reads at most \p n bytes into \p s. +istream::size_type istream::readsome (void* s, size_type n) +{ + if (remaining() < n) + underflow (n); + const size_type ntr (min (n, remaining())); + read (s, ntr); + return ntr; +} + +streamsize istream::underflow (streamsize n) +{ + verify_remaining ("read", "byte", n); + return remaining(); +} + +//-------------------------------------------------------------------- + +/// Aligns the write pointer on \p grain. The skipped bytes are zeroed. +void ostream::align (size_type grain) +{ + assert (!((grain-1)&grain) && "grain must be a power of 2"); + iterator ip = ipos(); + iterator ipa = iterator((uintptr_t(ip) + (grain-1)) & ~(grain-1)); + size_t nb = distance (ip, ipa); +#if WANT_STREAM_BOUNDS_CHECKING + if (!verify_remaining ("align", "padding", nb)) + return; +#else + assert (remaining() >= nb && "Buffer overrun. Check your stream size calculations."); +#endif + memset (ip, '\x0', nb); + _pos += nb; +} + +/// Writes \p str as a null-terminated string. +void ostream::write_strz (const char* str) +{ + write (str, strlen(str)+1); +} + +/// Writes all available data from \p is. +void ostream::read (istream& is) +{ + write (is.ipos(), is.remaining()); + is.seek (is.size()); +} + +/// Writes all written data to \p os. +/*void ostream::text_write (ostringstream& os) const +{ + os.write (begin(), pos()); +}*/ + +/// Inserts an empty area of \p size, at \p start. +void ostream::insert (iterator start, size_type s) +{ + _pos += s; + memlink::insert (start, s); +} + +/// Erases an area of \p size, at \p start. +void ostream::erase (iterator start, size_type s) +{ + _pos -= s; + memlink::erase (start, s); +} + +//-------------------------------------------------------------------- + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/outerrstream.cpp b/pwn/flipper/dist/common/source/ustl/outerrstream.cpp new file mode 100644 index 0000000..4ed6e36 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/outerrstream.cpp @@ -0,0 +1,152 @@ +#include "outerrstream.h" +#include "ustringformat.h" // for vsnprintf (in string::format) + +namespace ustl +{ + +coutclass cout_obj; +coutclass cerr_obj; +coutclass& cout = cout_obj; +coutclass& cerr = cerr_obj; + +void coutclass::init() +{ + new (&cout_obj) coutclass(&kprintf); + new (&cerr_obj) coutclass(&kprintfd); +} + + +/// Creates an output string stream linked to the given memory area. +coutclass::coutclass (void* p __attribute__((unused)), size_t n __attribute__((unused))) +: ostream (), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2), + m_kprintf(&kprintf) +{ + exceptions (goodbit); +} +/// Creates an output string stream linked to the given memory area. +coutclass::coutclass (void* p __attribute__((unused)), size_t n __attribute__((unused)), void (*m_kprintf)(const char*, ...)) +: ostream (), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2), + m_kprintf(m_kprintf) +{ + exceptions (goodbit); +} + +/// Creates an output string stream, initializing the buffer with v. +coutclass::coutclass () +: ostream (), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2), + m_kprintf(&kprintf) +{ + exceptions (goodbit); +} + +/// Creates an output string stream, initializing the buffer with v. +coutclass::coutclass (void (*m_kprintf)(const char*, ...)) +: ostream (), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2), + m_kprintf(m_kprintf) +{ + exceptions (goodbit); +} + +/// Writes a single character into the stream. +void coutclass::iwrite (uint8_t v) +{ + //debug(SCHEDULER, "writing single character: %d\n", v); + m_kprintf("%c", v); +} + +/// Writes the contents of \p buffer of \p size into the stream. +coutclass& coutclass::write (const void* buffer, size_type sz) +{ + kprintf("%.*s",(int)sz,(const char*)buffer); + return (*this); +} + +/// Simple decimal encoding of \p n into \p fmt. +inline char* coutclass::encode_dec (char* fmt, uint32_t n) const +{ + do { + *fmt++ = '0' + n % 10; + } while (n /= 10); + return (fmt); +} + +/// Generates a sprintf format string for the given type. +void coutclass::fmtstring (char* fmt, const char* typestr, bool bInteger) const +{ + *fmt++ = '%'; + if (m_Width) + fmt = encode_dec (fmt, m_Width); + if (m_Flags & left) + *fmt++ = '-'; + if (!bInteger) { + *fmt++ = '.'; + fmt = encode_dec (fmt, m_Precision); + } + while (*typestr) + *fmt++ = *typestr++; + if (bInteger) { + if (m_Base == 16) + fmt[-1] = 'X'; + else if (m_Base == 8) + fmt[-1] = 'o'; + } else { + if (m_Flags & scientific) + fmt[-1] = 'E'; + } + *fmt = 0; +} + +/// Writes \p v into the stream as utf8 +void coutclass::iwrite (wchar_t v) +{ + char buffer [8]; + *utf8out(buffer) = v; + write (buffer, Utf8Bytes(v)); +} + +/// Writes value \p v into the stream as text. +void coutclass::iwrite (bool v) +{ + static const char tf[2][8] = { "false", "true" }; + write (tf[v], 5 - v); +} + +/// Equivalent to a sprintf on the string. +int coutclass::format (const char* fmt, ...) +{ + va_list args; + va_start (args, fmt); + m_kprintf(fmt, args); + va_end (args); + return (0); +} + +/// Links to string \p l as resizable. +void coutclass::link (void* p, size_type n) +{ + assert ((p || !n) && "The output string buffer must not be read-only"); +} + +/// Attempts to create more output space. Returns remaining(). +coutclass::size_type coutclass::overflow (size_type n __attribute__((unused))) +{ + return remaining(); +} + +} diff --git a/pwn/flipper/dist/common/source/ustl/sistream.cpp b/pwn/flipper/dist/common/source/ustl/sistream.cpp new file mode 100644 index 0000000..071eaf3 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/sistream.cpp @@ -0,0 +1,232 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "sistream.h" +#include "sostream.h" +#include "ustring.h" + +namespace ustl { + +#define DEFAULT_DELIMITERS " \t\n\r;:,.?" +const char ios_base::c_DefaultDelimiters [istringstream::c_MaxDelimiters] = DEFAULT_DELIMITERS; + +/// Default constructor. +istringstream::istringstream (void) noexcept +: istream() +,_flags (0) +,_gcount (0) +{ + exceptions (goodbit); + set_delimiters (DEFAULT_DELIMITERS); +} + +istringstream::istringstream (const void* p, size_type n) noexcept +: istream() +,_flags (0) +,_gcount (0) +{ + exceptions (goodbit); + relink (p, n); + set_delimiters (DEFAULT_DELIMITERS); +} + +istringstream::istringstream (const cmemlink& source) noexcept +: istream() +,_flags (0) +,_gcount (0) +{ + exceptions (goodbit); + relink (source); + set_delimiters (DEFAULT_DELIMITERS); +} + +bool istringstream::is_delimiter (char c) const noexcept +{ + return memchr (_delimiters, c, VectorSize(_delimiters)-1); +} + +char istringstream::skip_delimiters (void) +{ + char c = _delimiters[0]; + while (is_delimiter(c)) { + if (!remaining() && !underflow()) { + verify_remaining ("read", "", 1); + return 0; + } + istream::iread (c); + } + return c; +} +/* +//{{{ str_to_num +namespace { + +typedef istringstream::iterator issiter_t; +template +inline void str_to_num (issiter_t i, issiter_t* iend, unsigned base, T& v) + { v = strtol (i, const_cast(iend), base); } +template <> inline void str_to_num (issiter_t i, issiter_t* iend, unsigned, double& v) + { v = strtod (i, const_cast(iend)); } +#if HAVE_LONG_LONG && SIZE_OF_LONG_LONG > SIZE_OF_LONG +template <> inline void str_to_num (issiter_t i, issiter_t* iend, unsigned base, long long& v) + { v = strtoll (i, const_cast(iend), base); } +#endif + +} //}}} namespace + +template +inline void istringstream::read_number (T& v) +{ + v = 0; + if (!skip_delimiters()) + return; + ungetc(); + iterator ilast; + do { + str_to_num (ipos(), &ilast, (_flags & hex) ? 16 : (_flags & oct) ? 8 : 0, v); + skip (distance (ipos(), ilast)); + } while (ilast == end() && underflow()); +}*/ + +void istringstream::iread (int& v) { read_number (v); } +//void istringstream::iread (double& v) { read_number (v); } +void istringstream::iread (long& v) { read_number (v); } +#if HAVE_LONG_LONG +void istringstream::iread (long long& v) { read_number (v); } +#endif + +void istringstream::iread (wchar_t& v) +{ + if (!(v = skip_delimiters())) + return; + ungetc(); + size_t cs = Utf8SequenceBytes (v); + if (remaining() < cs && underflow(cs) < cs) + verify_remaining ("read", "wchar_t", cs); + else { + v = *utf8in (ipos()); + skip (cs); + } +} + +void istringstream::iread (bool& v) +{ + static const char tf[2][8] = { "false", "true" }; + char c = skip_delimiters(); + v = (c == 't' || c == '1'); + if (c != tf[v][0]) + return; + for (const char* tv = tf[v]; c == *tv && (remaining() || underflow()); ++tv) + istream::iread (c); + ungetc(); +} + +void istringstream::iread (string& v) +{ + v.clear(); + char prevc, quoteChar = 0, c = skip_delimiters(); + if (!c) + return; + if (c == '\"' || c == '\'') + quoteChar = c; + else + v += c; + while (remaining() || underflow()) { + prevc = c; + istream::iread (c); + if (!quoteChar && is_delimiter(c)) + break; + if (prevc == '\\') { + switch (c) { + case 't': c = '\t'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 'b': c = '\b'; break; + case 'E': c = 27; break; // ESC sequence + case '\"': c = '\"'; break; + case '\'': c = '\''; break; + case '\\': c = '\\'; break; + }; + v.end()[-1] = c; + } else { + if (c == quoteChar) + break; + v += c; + } + } +} + +istringstream& istringstream::read (void* buffer, size_type sz) +{ + if (remaining() < sz && underflow(sz) < sz) + verify_remaining ("read", "", sz); + else + istream::read (buffer, _gcount = sz); + return *this; +} + +/// Reads characters into \p p,n until \p delim is found (but not stored or extracted) +istringstream& istringstream::get (char* p, size_type n, char delim) +{ + _gcount = 0; + for (char c = 0, *pend = p+n-1; p < pend && (remaining() || underflow()); ++p, ++_gcount) { + istream::iread (c); + if (c == delim) { + ungetc(); + break; + } + *p = c; + } + *p = 0; + return *this; +} + +/// Reads characters into \p s until \p delim is found (but not stored or extracted) +istringstream& istringstream::get (string& v, char delim) +{ + _gcount = 0; + v.clear(); + while ((remaining() || underflow()) && ipos()[0] != delim) { + const_iterator p = ipos(); + size_type n = find (p, end(), delim) - p; + v.append (p, n); + skip (n); + _gcount += n; + } + return *this; +} + +/// Reads characters into \p s until \p delim is extracted (but not stored) +istringstream& istringstream::getline (string& s, char delim) +{ + get (s, delim); + if (remaining() && ipos()[0] == delim) { + skip (1); + ++_gcount; + } + return *this; +} + +/// Reads characters into \p p,n until \p delim is extracted (but not stored) +istringstream& istringstream::getline (char* p, size_type n, char delim) +{ + get (p, n, delim); + if (remaining() && ipos()[0] == delim) { + skip (1); + ++_gcount; + } + return *this; +} + +/// Extract until \p delim or \p n chars have been read. +istringstream& istringstream::ignore (size_type n, char delim) +{ + _gcount = n; + while (n-- && (remaining() || underflow()) && get() != delim) {} + _gcount -= n; + return *this; +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/sostream.cpp b/pwn/flipper/dist/common/source/ustl/sostream.cpp new file mode 100644 index 0000000..134bda6 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/sostream.cpp @@ -0,0 +1,174 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "mistream.h" // for istream_iterator, referenced in utf8.h +#include "sostream.h" +#include "ustring.h" +#include "ulimits.h" +#include "ustringformat.h" +//#include + +namespace ustl { + +/// Creates an output string stream linked to the given memory area. +ostringstream::ostringstream (void* p, size_t n) noexcept +: ostream() +,_buffer() +,_flags (0) +,_width (0) +,_precision (2) +,_fill (0) +{ + exceptions (goodbit); + link (p, n); +} + +/// Creates an output string stream, initializing the buffer with v. +ostringstream::ostringstream (const string& v) +: ostream() +,_buffer (v) +,_flags (0) +,_width (0) +,_precision (2) +,_fill (0) +{ + exceptions (goodbit); + ostream::link (_buffer); +} + +/// Copies \p s to the internal buffer. +void ostringstream::str (const string& s) +{ + _buffer = s; + ostream::link (_buffer); + SetPos (_buffer.size()); +} + +/// Writes a single character into the stream. +void ostringstream::iwrite (unsigned char v) +{ + if (remaining() >= 1 || overflow() >= 1) + ostream::iwrite (v); +} + +/// Writes the contents of \p buffer of \p size into the stream. +ostringstream& ostringstream::write (const void* buffer, size_type sz) +{ + const char* buf = static_cast(buffer); + for (size_type bw = 0; (bw = min(sz, remaining() ? remaining() : overflow(sz))); buf += bw, sz -= bw) + ostream::write (buf, bw); + return *this; +} + +/// Simple decimal encoding of \p n into \p fmt. +inline char* ostringstream::encode_dec (char* fmt, uint32_t n) const noexcept +{ + do { + *fmt++ = '0' + n % 10; + } while (n /= 10); + return fmt; +} + +/// Generates a sprintf format string for the given type. +void ostringstream::fmtstring (char* fmt, const char* typestr, bool bInteger) const +{ + *fmt++ = '%'; + if (_width) { + if (_fill == '0') + *fmt++ = '0'; + fmt = encode_dec (fmt, _width); + } + if (_flags.f & left) + *fmt++ = '-'; + if (bInteger) { + if (_flags.f & showpos) + *fmt++ = '+'; + if (_flags.f & showbase) + *fmt++ = '#'; + } else { + *fmt++ = '.'; + fmt = encode_dec (fmt, _precision); + } + while (*typestr) + *fmt++ = *typestr++; + if (bInteger) { + if (_flags.f & hex) + fmt[-1] = (_flags.f & uppercase) ? 'X' : 'x'; + else if (_flags.f & oct) + fmt[-1] = 'o'; + } else if (_flags.f & scientific) + fmt[-1] = 'E'; + *fmt = 0; +} + +/// Writes \p v into the stream as utf8 +void ostringstream::iwrite (wchar_t v) +{ + char buffer [8]; + *utf8out(buffer) = v; + write (buffer, Utf8Bytes(v)); +} + +/// Writes value \p v into the stream as text. +void ostringstream::iwrite (bool v) +{ + static const char tf[2][8] = { "false", "true" }; + write (tf[v], 5 - v); +} + +/// Equivalent to a vsprintf on the string. +int ostringstream::vformat (const char* fmt, va_list args) +{ +#if HAVE_VA_COPY + va_list args2; +#else + #define args2 args + #undef __va_copy + #define __va_copy(x,y) +#endif + int rv, space; + do { + space = remaining(); + __va_copy (args2, args); + if (0 > (rv = vsnprintf (ipos(), space, fmt, args2))) + return rv; + } while (rv >= space && rv < int(overflow(rv+1))); + SetPos (pos() + min (rv, space)); + return rv; +} + +/// Equivalent to a sprintf on the string. +int ostringstream::format (const char* fmt, ...) +{ + va_list args; + va_start (args, fmt); + const int rv = vformat (fmt, args); + va_end (args); + return rv; +} + +/// Links to string \p l as resizable. +void ostringstream::link (void* p, size_type n) noexcept +{ + assert ((p || !n) && "The output string buffer must not be read-only"); + ostream::link (p, n); + _buffer.link (p, n); +} + +/// Attempts to create more output space. Returns remaining(). +ostringstream::size_type ostringstream::overflow (size_type n) +{ + if (n > remaining() && (good() || n <= capacity() - pos())) { + const uoff_t oldPos (pos()); + _buffer.reserve (oldPos + n, false); + _buffer.resize (oldPos + n); + ostream::link (_buffer); + SetPos (oldPos); + } + verify_remaining ("write", "text", n); + return remaining(); +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/ualgobase.cpp b/pwn/flipper/dist/common/source/ustl/ualgobase.cpp new file mode 100644 index 0000000..73b2680 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/ualgobase.cpp @@ -0,0 +1,286 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#ifndef NDEBUG // Optimized code here. asserts slow it down, and are checked elsewhere. +#define NDEBUG +#endif + +#include "ualgo.h" + +namespace ustl { + +// Generic version for implementing fill_nX_fast on non-i386 architectures. +template static inline void stosv (T*& p, size_t n, T v) + { while (n--) *p++ = v; } + +#if __x86__ + +//---------------------------------------------------------------------- +// Copy functions +//---------------------------------------------------------------------- + +static inline void movsb_dir_up (void) { asm volatile ("cld"); } +static inline void movsb_dir_down (void) { asm volatile ("std"); } + +static inline void movsb (const void*& src, size_t nBytes, void*& dest) +{ + asm volatile ("rep;\n\tmovsb" + : "=&S"(src), "=&D"(dest), "=&c"(nBytes) + : "0"(src), "1"(dest), "2"(nBytes) + : "memory"); +} + +static inline void movsd (const void*& src, size_t nWords, void*& dest) +{ + asm volatile ("rep;\n\tmovsl" + : "=&S"(src), "=&D"(dest), "=&c"(nWords) + : "0"(src), "1"(dest), "2"(nWords) + : "memory"); +} + +#if __MMX__ +template <> inline void stosv (uint8_t*& p, size_t n, uint8_t v) +{ asm volatile ("rep;\n\tstosb" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } +#endif +template <> inline void stosv (uint16_t*& p, size_t n, uint16_t v) +{ asm volatile ("rep;\n\tstosw" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } +template <> inline void stosv (uint32_t*& p, size_t n, uint32_t v) +{ asm volatile ("rep;\n\tstosl" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } + +#if __MMX__ +#define MMX_ALIGN 16U // Data must be aligned on this grain +#define MMX_BS 32U // Assembly routines copy data this many bytes at a time. + +static inline void simd_block_copy (const void* src, void* dest) +{ + const char* csrc = static_cast(src); + char* cdest = static_cast(dest); + #if __SSE__ + asm ( + "movaps\t%2, %%xmm0 \n\t" + "movaps\t%3, %%xmm1 \n\t" + "movntps\t%%xmm0, %0 \n\t" + "movntps\t%%xmm1, %1" + : "=m"(cdest[0]), "=m"(cdest[16]) + : "m"(csrc[0]), "m"(csrc[16]) + : "xmm0", "xmm1", "memory"); + #else + asm ( + "movq %4, %%mm0 \n\t" + "movq %5, %%mm1 \n\t" + "movq %6, %%mm2 \n\t" + "movq %7, %%mm3 \n\t" + "movq %%mm0, %0 \n\t" + "movq %%mm1, %1 \n\t" + "movq %%mm2, %2 \n\t" + "movq %%mm3, %3" + : "=m"(cdest[0]), "=m"(cdest[8]), "=m"(cdest[16]), "=m"(cdest[24]) + : "m"(csrc[0]), "m"(csrc[8]), "m"(csrc[16]), "m"(csrc[24]) + : "mm0", "mm1", "mm2", "mm3", "st", "st(1)", "st(2)", "st(3)", "memory"); + #endif +} + +static inline void simd_block_store (uint8_t* dest) +{ + #if __SSE__ + asm volatile ( + "movntq %%mm0, %0\n\t" + "movntq %%mm0, %1\n\t" + "movntq %%mm0, %2\n\t" + "movntq %%mm0, %3" + : "=m"(dest[0]), "=m"(dest[8]), "=m"(dest[16]), "=m"(dest[24]) + :: "memory"); + #else + asm volatile ( + "movq %%mm0, %0 \n\t" + "movq %%mm0, %1 \n\t" + "movq %%mm0, %2 \n\t" + "movq %%mm0, %3" + : "=m"(dest[0]), "=m"(dest[8]), "=m"(dest[16]), "=m"(dest[24]) + :: "memory"); + #endif +} + +static inline void simd_block_cleanup (void) +{ + #if !__SSE__ + simd::reset_mmx(); + #endif + asm volatile ("sfence"); +} + +/// The fastest optimized raw memory copy. +void copy_n_fast (const void* src, size_t nBytes, void* dest) noexcept +{ + movsb_dir_up(); + size_t nHeadBytes = Align(uintptr_t(src), MMX_ALIGN) - uintptr_t(src); + nHeadBytes = min (nHeadBytes, nBytes); + movsb (src, nHeadBytes, dest); + nBytes -= nHeadBytes; + if (!(uintptr_t(dest) % MMX_ALIGN)) { + const size_t nMiddleBlocks = nBytes / MMX_BS; + for (uoff_t i = 0; i < nMiddleBlocks; ++ i) { + prefetch (advance (src, 512), 0, 0); + simd_block_copy (src, dest); + src = advance (src, MMX_BS); + dest = advance (dest, MMX_BS); + } + simd_block_cleanup(); + nBytes %= MMX_BS; + } + movsb (src, nBytes, dest); +} +#endif // __MMX__ + +/// The fastest optimized backwards raw memory copy. +void copy_backward_fast (const void* first, const void* last, void* result) noexcept +{ + prefetch (first, 0, 0); + prefetch (result, 1, 0); + size_t nBytes (distance (first, last)); + movsb_dir_down(); + size_t nHeadBytes = uintptr_t(last) % 4; + last = advance (last, -1); + result = advance (result, -1); + movsb (last, nHeadBytes, result); + nBytes -= nHeadBytes; + if (uintptr_t(result) % 4 == 3) { + const size_t nMiddleBlocks = nBytes / 4; + last = advance (last, -3); + result = advance (result, -3); + movsd (last, nMiddleBlocks, result); + nBytes %= 4; + } + movsb (last, nBytes, result); + movsb_dir_up(); +} +#endif // __x86__ + +//---------------------------------------------------------------------- +// Fill functions +//---------------------------------------------------------------------- + +#if __MMX__ +template static inline void build_block (T) {} +template <> inline void build_block (uint8_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpunpcklbw %%mm0, %%mm0\n\tpshufw $0, %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} +template <> inline void build_block (uint16_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpshufw $0, %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} +template <> inline void build_block (uint32_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpunpckldq %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} + +static inline void simd_block_fill_loop (uint8_t*& dest, size_t count) +{ + prefetch (advance (dest, 512), 1, 0); + for (const uint8_t* destEnd = dest + count * MMX_BS; dest < destEnd; dest += MMX_BS) + simd_block_store (dest); + simd_block_cleanup(); + simd::reset_mmx(); +} + +template +static inline void fill_n_fast (T* dest, size_t count, T v) +{ + size_t nHead = Align(uintptr_t(dest), MMX_ALIGN) - uintptr_t(dest) / sizeof(T); + nHead = min (nHead, count); + stosv (dest, nHead, v); + count -= nHead; + build_block (v); + uint8_t* bdest = reinterpret_cast(dest); + simd_block_fill_loop (bdest, count * sizeof(T) / MMX_BS); + count %= MMX_BS; + dest = reinterpret_cast(bdest); + stosv (dest, count, v); +} + +void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) noexcept + { fill_n_fast (dest, count, v); } +void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) noexcept + { fill_n_fast (dest, count, v); } +void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) noexcept + { fill_n_fast (dest, count, v); } +#else +void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) noexcept { memset (dest, v, count); } +void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) noexcept { stosv (dest, count, v); } +void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) noexcept { stosv (dest, count, v); } +#endif // __MMX__ + +/// Exchanges ranges [first, middle) and [middle, last) +void rotate_fast (void* first, void* middle, void* last) noexcept +{ +#if HAVE_ALLOCA_H + const size_t half1 (distance (first, middle)), half2 (distance (middle, last)); + const size_t hmin (min (half1, half2)); + if (!hmin) + return; + void* buf = alloca (hmin); + if (buf) { + if (half2 < half1) { + copy_n_fast (middle, half2, buf); + copy_backward_fast (first, middle, last); + copy_n_fast (buf, half2, first); + } else { + copy_n_fast (first, half1, buf); + copy_n_fast (middle, half2, first); + copy_n_fast (buf, half1, advance (first, half2)); + } + } else +#else + if (first == middle || middle == last) + return; +#endif + { + char* f = static_cast(first); + char* m = static_cast(middle); + char* l = static_cast(last); + reverse (f, m); + reverse (m, l); + while (f != m && m != l) + iter_swap (f++, --l); + reverse (f, (f == m ? l : m)); + } +} + +#if __GNUC__ < 4 +size_t popcount (uint32_t v) noexcept +{ + const uint32_t w = v - ((v >> 1) & 0x55555555); // Algorithm from AMD optimization guide + const uint32_t x = (w & 0x33333333) + ((w >> 2) & 0x33333333); + return ((x + (x >> 4) & 0x0F0F0F0F) * 0x01010101) >> 24; +} + +#if HAVE_INT64_T +/// \brief Returns the number of 1s in \p v in binary. +size_t popcount (uint64_t v) noexcept +{ + v -= (v >> 1) & UINT64_C(0x5555555555555555); // Algorithm from Wikipedia + v = (v & UINT64_C(0x3333333333333333)) + ((v >> 2) & UINT64_C(0x3333333333333333)); + v = (v + (v >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F); + return (v * UINT64_C(0x0101010101010101)) >> 56; +} +#endif // HAVE_INT64_T +#endif // !__GNUC__ + +//---------------------------------------------------------------------- +// Miscellaneous instantiated stuff from headers which don't have enough +// to warrant creation of a separate file.cc +//---------------------------------------------------------------------- + +// Used in uspecial to print printable characters +const char _FmtPrtChr[2][8]={"'%c'","%d"}; + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/ubitset.cpp b/pwn/flipper/dist/common/source/ustl/ubitset.cpp new file mode 100644 index 0000000..89ee6c1 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/ubitset.cpp @@ -0,0 +1,34 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "ubitset.h" + +namespace ustl { + +/// Copies bits from \p v of size \p n into \p buf as MSB "1011001..." LSB +/// If \p buf is too small, MSB bits will be truncated. +void convert_to_bitstring (const bitset_value_type* v, size_t n, string& buf) noexcept +{ + string::iterator stri = buf.end(); + for (size_t i = 0; i < n && stri > buf.begin(); ++ i) + for (bitset_value_type b = 1; b && stri > buf.begin(); b <<= 1) + *--stri = (v[i] & b) ? '1' : '0'; +} + +/// Copies bits from \p buf as MSB "1011001..." LSB into \p v of size \p n. +void convert_from_bitstring (const string& buf, bitset_value_type* v, size_t n) noexcept +{ + string::const_iterator stri = buf.end(); + for (size_t i = 0; i < n; ++ i) { + for (bitset_value_type b = 1; b; b <<= 1) { + if (stri == buf.begin() || *--stri == '0') + v[i] &= ~b; + else + v[i] |= b; + } + } +} + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/ustring.cpp b/pwn/flipper/dist/common/source/ustl/ustring.cpp new file mode 100644 index 0000000..a0c6871 --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/ustring.cpp @@ -0,0 +1,400 @@ +// This file is part of the uSTL library, an STL implementation. +// +// Copyright (c) 2005 by Mike Sharov +// This file is free software, distributed under the MIT License. + +#include "ustring.h" +#include "mistream.h" +#include "mostream.h" +#include "ualgo.h" +#include "ustringformat.h" // for vsnprintf (in string::format) + +extern char data_end_address; + +namespace ustl { + +//---------------------------------------------------------------------- + +constexpr const string::pos_type string::npos; + +//---------------------------------------------------------------------- + +/// Assigns itself the value of string \p s +string::string (const string& s) +: memblock ((s.size()+1) & (s.is_linked()-1)) // +1 because base ctor can't call virtuals of this class +{ +// if (s.is_linked()) +// relink (s.c_str(), s.size()); +// else { + copy_n (s.begin(), size(), begin()); + relink (begin(), size()-1); // --m_Size +// } +} + +/// Links to \p s +string::string (const_pointer s) noexcept +: memblock (strlen(s)+1) +{ + if (!s) s = ""; + copy_n (s, strlen(s)+1, begin()); + relink (begin(), size()-1); // --m_Size +} + +/// Creates a string of length \p n filled with character \p c. +string::string (size_type n, value_type c) +: memblock (n+1) // +1 because base ctor can't call virtuals of this class +{ + relink (begin(), size()-1); // --m_Size + fill_n (begin(), n, c); + at(n) = 0; +} + +/// Resize the string to \p n characters. New space contents is undefined. +void string::resize (size_type n) +{ + if (!(n | memblock::capacity())) + return relink ("",0); + memblock::resize (n); + at(n) = 0; +} + +/// Assigns itself the value of string \p s +string& string::assign (const_pointer s) +{ + if (!s) s = ""; + assign (s, strlen (s)); + return *this; +} + +/// Assigns itself the value of string \p s of length \p len. +string& string::assign (const_pointer s, size_type len) +{ + resize (len); + copy_n (s, len, begin()); + return *this; +} + +/// Appends to itself the value of string \p s of length \p len. +string& string::append (const_pointer s) +{ + if (!s) s = ""; + append (s, strlen (s)); + return *this; +} + +/// Appends to itself the value of string \p s of length \p len. +string& string::append (const_pointer s, size_type len) +{ + resize (size() + len); + copy_n (s, len, end() - len); + return *this; +} + +/// Appends to itself \p n characters of value \p c. +string& string::append (size_type n, value_type c) +{ + resize (size() + n); + fill_n (end() - n, n, c); + return *this; +} + +/// Copies [start,start+n) into [p,n). The result is not null terminated. +string::size_type string::copy (pointer p, size_type n, pos_type start) const noexcept +{ + assert (p && n && start <= size()); + const size_type btc = min(n, size()-start); + copy_n (iat(start), btc, p); + return btc; +} + +/// Returns comparison value regarding string \p s. +/// The return value is: +/// \li 1 if this string is greater (by value, not length) than string \p s +/// \li 0 if this string is equal to string \p s +/// \li -1 if this string is less than string \p s +/// +int string::compare (const_iterator first1, const_iterator last1, const_iterator first2, const_iterator last2) noexcept // static +{ + assert (first1 <= last1 && (first2 <= last2 || !last2) && "Negative ranges result in memory allocation errors."); + const size_type len1 = distance (first1, last1), len2 = distance (first2, last2); + const int rvbylen = sign (int(len1 - len2)); + int rv = memcmp (first1, first2, min (len1, len2)); + return rv ? rv : rvbylen; +} + +/// Returns true if this string is equal to string \p s. +bool string::operator== (const_pointer s) const noexcept +{ + if (!s) s = ""; + return size() == strlen(s) && 0 == memcmp (c_str(), s, size()); +} + +/// Returns the beginning of character \p i. +string::const_iterator string::wiat (pos_type i) const noexcept +{ + utf8in_iterator cfinder (begin()); + cfinder += i; + return cfinder.base(); +} + +/// Inserts wide character \p c at \p ipo \p n times as a UTF-8 string. +/// +/// \p ipo is a byte position, not a character position, and is intended +/// to be obtained from one of the find functions. Generally you are not +/// able to know the character position in a localized string; different +/// languages will have different character counts, so use find instead. +/// +string& string::insert (pos_type ipo, size_type n, wvalue_type c) +{ + iterator ip (iat(ipo)); + ip = iterator (memblock::insert (memblock::iterator(ip), n * Utf8Bytes(c))); + fill_n (utf8out (ip), n, c); + *end() = 0; + return *this; +} + +/// Inserts sequence of wide characters at \p ipo (byte position from a find call) +string& string::insert (pos_type ipo, const wvalue_type* first, const wvalue_type* last, const size_type n) +{ + iterator ip (iat(ipo)); + size_type nti = distance (first, last), bti = 0; + for (size_type i = 0; i < nti; ++ i) + bti += Utf8Bytes(first[i]); + ip = iterator (memblock::insert (memblock::iterator(ip), n * bti)); + utf8out_iterator uout (utf8out (ip)); + for (size_type j = 0; j < n; ++ j) + for (size_type k = 0; k < nti; ++ k, ++ uout) + *uout = first[k]; + *end() = 0; + return *this; +} + +/// Inserts character \p c into this string at \p start. +string::iterator string::insert (const_iterator start, size_type n, value_type c) +{ + memblock::iterator ip = memblock::insert (memblock::const_iterator(start), n); + fill_n (ip, n, c); + *end() = 0; + return iterator(ip); +} + +/// Inserts \p count instances of string \p s at offset \p start. +string::iterator string::insert (const_iterator start, const_pointer s, size_type n) +{ + if (!s) s = ""; + return insert (start, s, s + strlen(s), n); +} + +/// Inserts [first,last] \p n times. +string::iterator string::insert (const_iterator start, const_pointer first, const_pointer last, size_type n) +{ + assert (first <= last); + assert (begin() <= start && end() >= start); + assert ((first < begin() || first >= end() || size() + abs_distance(first,last) < capacity()) && "Insertion of self with autoresize is not supported"); + memblock::iterator ip = iterator (memblock::insert (memblock::const_iterator(start), distance(first, last) * n)); + fill (ip, first, distance(first, last), n); + *end() = 0; + return iterator(ip); +} + +/// Erases \p size bytes at \p ep. +string::iterator string::erase (const_iterator ep, size_type n) +{ + string::iterator rv = memblock::erase (memblock::const_iterator(ep), n); + *end() = 0; + return rv; +} + +/// Erases \p n bytes at byte offset \p epo. +string& string::erase (pos_type epo, size_type n) +{ + erase (iat(epo), min (n, size()-epo)); + return *this; +} + +/// Replaces range [\p start, \p start + \p len] with string \p s. +string& string::replace (const_iterator first, const_iterator last, const_pointer s) +{ + if (!s) s = ""; + replace (first, last, s, s + strlen(s)); + return *this; +} + +/// Replaces range [\p start, \p start + \p len] with \p count instances of string \p s. +string& string::replace (const_iterator first, const_iterator last, const_pointer i1, const_pointer i2, size_type n) +{ + assert (first <= last); + assert (n || distance(first, last)); + assert (first >= begin() && first <= end() && last >= first && last <= end()); + assert ((i1 < begin() || i1 >= end() || abs_distance(i1,i2) * n + size() < capacity()) && "Replacement by self can not autoresize"); + const size_type bte = distance(first, last), bti = distance(i1, i2) * n; + memblock::const_iterator rp = static_cast(first); + if (bti < bte) + rp = memblock::erase (rp, bte - bti); + else if (bte < bti) + rp = memblock::insert (rp, bti - bte); + fill (rp, i1, distance(i1, i2), n); + *end() = 0; + return *this; +} + +/// Returns the offset of the first occurence of \p c after \p pos. +string::pos_type string::find (value_type c, pos_type pos) const noexcept +{ + const_iterator found = ::ustl::find (iat(pos), end(), c); + return found < end() ? pos_type (distance(begin(),found)) : npos; +} + +/// Returns the offset of the first occurence of substring \p s of length \p n after \p pos. +string::pos_type string::find (const string& s, pos_type pos) const noexcept +{ + if (s.empty() || s.size() > size() - pos) + return npos; + pos_type endi = s.size() - 1; + value_type endchar = s[endi]; + pos_type lastPos = endi; + while (lastPos-- && s[lastPos] != endchar) ; + const size_type skip = endi - lastPos; + const_iterator i = iat(pos) + endi; + for (; i < end() && (i = ::ustl::find (i, end(), endchar)) < end(); i += skip) + if (memcmp (i - endi, s.c_str(), s.size()) == 0) + return distance (begin(), i) - endi; + return npos; +} + +/// Returns the offset of the last occurence of character \p c before \p pos. +string::pos_type string::rfind (value_type c, pos_type pos) const noexcept +{ + for (int i = min(pos,pos_type(size()-1)); i >= 0; --i) + if (at(i) == c) + return i; + return npos; +} + +/// Returns the offset of the last occurence of substring \p s of size \p n before \p pos. +string::pos_type string::rfind (const string& s, pos_type pos) const noexcept +{ + const_iterator d = iat(pos) - 1; + const_iterator sp = begin() + s.size() - 1; + const_iterator m = s.end() - 1; + for (long int i = 0; d > sp && size_type(i) < s.size(); -- d) + for (i = 0; size_type(i) < s.size(); ++ i) + if (m[-i] != d[-i]) + break; + return d > sp ? pos_type (distance (begin(), d + 2 - s.size())) : npos; +} + +/// Returns the offset of the first occurence of one of characters in \p s of size \p n after \p pos. +string::pos_type string::find_first_of (const string& s, pos_type pos) const noexcept +{ + for (size_type i = min(size_type(pos),size()); i < size(); ++ i) + if (s.find (at(i)) != npos) + return i; + return npos; +} + +/// Returns the offset of the first occurence of one of characters not in \p s of size \p n after \p pos. +string::pos_type string::find_first_not_of (const string& s, pos_type pos) const noexcept +{ + for (size_type i = min(size_type(pos),size()); i < size(); ++ i) + if (s.find (at(i)) == npos) + return i; + return npos; +} + +/// Returns the offset of the last occurence of one of characters in \p s of size \p n before \p pos. +string::pos_type string::find_last_of (const string& s, pos_type pos) const noexcept +{ + for (int i = min(size_type(pos),size()-1); i >= 0; -- i) + if (s.find (at(i)) != npos) + return i; + return npos; +} + +/// Returns the offset of the last occurence of one of characters not in \p s of size \p n before \p pos. +string::pos_type string::find_last_not_of (const string& s, pos_type pos) const noexcept +{ + for (int i = min(pos,pos_type(size()-1)); i >= 0; -- i) + if (s.find (at(i)) == npos) + return i; + return npos; +} + +/// Equivalent to a vsprintf on the string. +int string::vformat (const char* fmt, va_list args) +{ +#if HAVE_VA_COPY + va_list args2; +#else + #define args2 args + #undef __va_copy + #define __va_copy(x,y) +#endif + int rv = size(), wcap; + do { + __va_copy (args2, args); + rv = vsnprintf (data(), wcap = memblock::capacity(), fmt, args2); + resize (rv); + } while (rv >= wcap); + return rv; +} + +/// Equivalent to a sprintf on the string. +int string::format (const char* fmt, ...) +{ + va_list args; + va_start (args, fmt); + const int rv = vformat (fmt, args); + va_end (args); + return rv; +} + +/// Returns the number of bytes required to write this object to a stream. +size_t string::stream_size (void) const noexcept +{ + return Utf8Bytes(size()) + size(); +} + +/// Reads the object from stream \p os +/*void string::read (istream& is) +{ + char szbuf [8]; + is >> szbuf[0]; + size_t szsz (Utf8SequenceBytes (szbuf[0]) - 1), n = 0; + if (!is.verify_remaining ("read", "ustl::string", szsz)) return; + is.read (szbuf + 1, szsz); + n = *utf8in(szbuf); + if (!is.verify_remaining ("read", "ustl::string", n)) return; + resize (n); + is.read (data(), size()); +} + +/// Writes the object to stream \p os +void string::write (ostream& os) const +{ + const written_size_type sz (size()); + assert (sz == size() && "No support for writing strings larger than 4G"); + + char szbuf [8]; + utf8out_iterator szout (szbuf); + *szout = sz; + size_t szsz = distance (szbuf, szout.base()); + + if (!os.verify_remaining ("write", "ustl::string", szsz + sz)) return; + os.write (szbuf, szsz); + os.write (cdata(), sz); +}*/ + +/// Returns a hash value for [first, last) +hashvalue_t string::hash (const char* first, const char* last) noexcept // static +{ + hashvalue_t h = 0; + // This has the bits flowing into each other from both sides of the number + for (; first < last; ++ first) + h = *first + ((h << 7) | (h >> (BitsInType(hashvalue_t) - 7))); + return h; +} + +string::size_type string::minimumFreeCapacity (void) const noexcept { return 1; } + +} // namespace ustl diff --git a/pwn/flipper/dist/common/source/ustl/ustringformat.cpp b/pwn/flipper/dist/common/source/ustl/ustringformat.cpp new file mode 100644 index 0000000..83e57ac --- /dev/null +++ b/pwn/flipper/dist/common/source/ustl/ustringformat.cpp @@ -0,0 +1,416 @@ +#include "ustringformat.h" + +/* Blatantly stolen from FREEBSD. */ + +typedef uint64 uintmax_t; +typedef int64 intmax_t; +typedef uint64 u_quad_t; +typedef int64 quad_t; + +char* ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) +{ + char *p = nbuf; + *p = '\0'; + do + { + *++p = upper ? hex2asciiupper(num % base) : hex2ascii(num % base); + } while (num /= base); + if (lenp) + *lenp = p - nbuf; + return (p); +} + +int kvprintf(char const *fmt, void (*func)(int,void*), void *arg, int radix, va_list ap) +{ +#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; } + char nbuf[MAXNBUF]; + char *d; + const char *p, *percent, *q; + u_char *up; + int ch, n; + uintmax_t num; + int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; + int cflag, hflag, jflag, tflag, zflag; + int dwidth, upper; + char padc; + int stop = 0, retval = 0; + + num = 0; + if (!func) + d = (char *) arg; + else + d = NULL; + + if (fmt == NULL) + fmt = "(fmt null)\n"; + + if (radix < 2 || radix > 36) + radix = 10; + + for (;;) + { + padc = ' '; + width = 0; + while ((ch = (u_char) *fmt++) != '%' || stop) + { + if (ch == '\0') + return (retval); + PCHAR(ch); + } + percent = fmt - 1; + qflag = 0; + lflag = 0; + ladjust = 0; + sharpflag = 0; + neg = 0; + sign = 0; + dot = 0; + dwidth = 0; + upper = 0; + cflag = 0; + hflag = 0; + jflag = 0; + tflag = 0; + zflag = 0; + reswitch: switch (ch = (u_char) *fmt++) + { + case '.': + dot = 1; + goto reswitch; + case '#': + sharpflag = 1; + goto reswitch; + case '+': + sign = 1; + goto reswitch; + case '-': + ladjust = 1; + goto reswitch; + case '%': + PCHAR(ch) + ; + break; + case '*': + if (!dot) + { + width = va_arg(ap, int); + if (width < 0) + { + ladjust = !ladjust; + width = -width; + } + } + else + { + dwidth = va_arg(ap, int); + } + goto reswitch; + case '0': + if (!dot) + { + padc = '0'; + goto reswitch; + } + // fall-through + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + for (n = 0;; ++fmt) + { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') + break; + } + if (dot) + dwidth = n; + else + width = n; + goto reswitch; + case 'b': + num = (u_int) va_arg(ap, int); + p = va_arg(ap, char *); + for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) + PCHAR(*q--) + ; + + if (num == 0) + break; + + for (tmp = 0; *p;) + { + n = *p++; + if (num & (1 << (n - 1))) + { + PCHAR(tmp ? ',' : '<'); + for (; (n = *p) > ' '; ++p) + PCHAR(n); + tmp = 1; + } + else + for (; *p > ' '; ++p) + continue; + } + if (tmp) + PCHAR('>') + ; + break; + case 'c': + PCHAR(va_arg(ap, int)) + ; + break; + case 'D': + up = va_arg(ap, u_char *); + p = va_arg(ap, char *); + if (!width) + width = 16; + while (width--) + { + PCHAR(hex2ascii(*up >> 4)); + PCHAR(hex2ascii(*up & 0x0f)); + up++; + if (width) + for (q = p; *q; q++) + PCHAR(*q); + } + break; + case 'd': + case 'i': + base = 10; + sign = 1; + goto handle_sign; + case 'h': + if (hflag) + { + hflag = 0; + cflag = 1; + } + else + hflag = 1; + goto reswitch; + case 'j': + jflag = 1; + goto reswitch; + case 'l': + if (lflag) + { + lflag = 0; + qflag = 1; + } + else + lflag = 1; + goto reswitch; + case 'n': + if (jflag) + *(va_arg(ap, intmax_t *)) = retval; + else if (qflag) + *(va_arg(ap, quad_t *)) = retval; + else if (lflag) + *(va_arg(ap, long *)) = retval; + else if (zflag) + *(va_arg(ap, size_t *)) = retval; + else if (hflag) + *(va_arg(ap, short *)) = retval; + else if (cflag) + *(va_arg(ap, char *)) = retval; + else + *(va_arg(ap, int *)) = retval; + break; + case 'o': + base = 8; + goto handle_nosign; + case 'p': + base = 16; + sharpflag = (width == 0); + sign = 0; + num = (uintptr_t) va_arg(ap, void *); + goto number; + case 'q': + qflag = 1; + goto reswitch; + case 'r': + base = radix; + if (sign) + goto handle_sign; + goto handle_nosign; + case 's': + p = va_arg(ap, char *); + if (p == NULL) + p = "(null)"; + if (!dot) + n = strlen(p); + else + for (n = 0; n < dwidth && p[n]; n++) + continue; + + width -= n; + + if (!ladjust && width > 0) + while (width--) + PCHAR(padc) + ; + while (n--) + PCHAR(*p++) + ; + if (ladjust && width > 0) + while (width--) + PCHAR(padc) + ; + break; + case 't': + tflag = 1; + goto reswitch; + case 'u': + base = 10; + goto handle_nosign; + case 'X': + upper = 1; + // fall-through + case 'x': + sharpflag = 1; + base = 16; + goto handle_nosign; + case 'y': + base = 16; + sign = 1; + goto handle_sign; + case 'z': + zflag = 1; + goto reswitch; + handle_nosign: sign = 0; + if (jflag) + num = va_arg(ap, uintmax_t); + else if (qflag) + num = va_arg(ap, u_quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, u_long); + else if (zflag) + num = va_arg(ap, size_t); + else if (hflag) + num = (u_short) va_arg(ap, int); + else if (cflag) + num = (u_char) va_arg(ap, int); + else + num = va_arg(ap, u_int); + goto number; + handle_sign: if (jflag) + num = va_arg(ap, intmax_t); + else if (qflag) + num = va_arg(ap, quad_t); + else if (tflag) + num = va_arg(ap, ptrdiff_t); + else if (lflag) + num = va_arg(ap, long); + else if (zflag) + num = va_arg(ap, ssize_t); + else if (hflag) + num = (short) va_arg(ap, int); + else if (cflag) + num = (char) va_arg(ap, int); + else + num = va_arg(ap, int); + number: if (sign && (intmax_t) num < 0) + { + neg = 1; + num = -(intmax_t) num; + } + p = ksprintn(nbuf, num, base, &n, upper); + tmp = 0; + if (sharpflag && num != 0) + { + if (base == 8) + tmp++; + else if (base == 16) + tmp += 2; + } + if (neg) + tmp++; + + if (!ladjust && padc == '0') + dwidth = width - tmp; + width -= tmp + Max(dwidth, n); + dwidth -= n; + if (!ladjust) + while (width-- > 0) + PCHAR(' ') + ; + if (neg) + PCHAR('-') + ; + if (sharpflag && num != 0) + { + if (base == 8) + { + PCHAR('0'); + } + else if (base == 16) + { + PCHAR('0'); + PCHAR('x'); + } + } + while (dwidth-- > 0) + PCHAR('0') + ; + + while (*p) + PCHAR(*p--) + ; + + if (ladjust) + while (width-- > 0) + PCHAR(' ') + ; + + break; + default: + while (percent < fmt) + PCHAR(*percent++) + ; + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + stop = 1; + break; + } + } +#undef PCHAR +} + +void snprintf_func(int ch, void *arg) +{ + snprintf_arg * info = (snprintf_arg* ) arg; + + if (info->remain >= 2) + { + *info->str++ = ch; + info->remain--; + } +} + +/* + * Scaled down version of vsnprintf(3). + */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + snprintf_arg info; + int retval; + + info.str = str; + info.remain = size; + retval = kvprintf(format, snprintf_func, &info, 10, ap); + if (info.remain >= 1) + *info.str++ = '\0'; + return retval; +} diff --git a/pwn/flipper/dist/common/source/util/Bitmap.cpp b/pwn/flipper/dist/common/source/util/Bitmap.cpp new file mode 100644 index 0000000..7e1bb01 --- /dev/null +++ b/pwn/flipper/dist/common/source/util/Bitmap.cpp @@ -0,0 +1,140 @@ +#include "Bitmap.h" +#include "kprintf.h" +#include "assert.h" +#include "kstring.h" + +uint8 const Bitmap::bits_per_bitmap_atom_ = 8; + +static const uint8 BIT_COUNT[] = +{ +0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, +2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, +2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, +4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, +2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, +3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, +4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; + +Bitmap::Bitmap(size_t number_of_bits) : + size_(number_of_bits), + num_bits_set_(0) +{ + bitmap_ = new uint8[BITMAP_BYTE_COUNT(number_of_bits)]{}; +} + +Bitmap::Bitmap(const Bitmap &bm) + : size_(bm.size_) + , num_bits_set_(bm.num_bits_set_) +{ + const size_t bytes = BITMAP_BYTE_COUNT(size_); + bitmap_ = new uint8[bytes]{}; + memcpy(bitmap_, bm.bitmap_, bytes); +} + +Bitmap::~Bitmap() +{ + delete[] bitmap_; +} + +#define BYTE (b[bit_number / bits_per_bitmap_atom_]) +#define MASK (1 << (bit_number % bits_per_bitmap_atom_)) + +bool Bitmap::setBit(size_t bit_number) +{ + assert(bit_number < size_); + return setBit(bitmap_, num_bits_set_, bit_number); +} + +bool Bitmap::setBit(uint8* b, size_t& num_bits_set, size_t bit_number) +{ + //kprintfd("bitmap %p, %zu, %zu\n",b,num_bits_set, bit_number); + if (!(BYTE & MASK)) + { + BYTE |= MASK; + ++num_bits_set; + return true; + } + return false; +} + +bool Bitmap::getBit(size_t bit_number) +{ + assert(bit_number < size_); + return getBit(bitmap_, bit_number); +} + +bool Bitmap::getBit(uint8* b, size_t bit_number) +{ + return BYTE & MASK; +} + +bool Bitmap::unsetBit(size_t bit_number) +{ + assert(bit_number < size_); + return unsetBit(bitmap_, num_bits_set_, bit_number); +} + +bool Bitmap::unsetBit(uint8* b, size_t& num_bits_set, size_t bit_number) +{ + if (BYTE & MASK) + { + BYTE &= ~MASK; + --num_bits_set; + return true; + } + return false; +} + +void Bitmap::setByte(size_t byte_number, uint8 byte) +{ + assert(byte_number * bits_per_bitmap_atom_ < size_); + uint8& b = bitmap_[byte_number]; + + num_bits_set_ -= BIT_COUNT[b]; + num_bits_set_ += BIT_COUNT[byte]; + b = byte; +} + +uint8 Bitmap::getByte(size_t byte_number) +{ + assert(byte_number * bits_per_bitmap_atom_ < size_); + return bitmap_[byte_number]; +} + +void Bitmap::bmprint() +{ + bmprint(bitmap_, size_, num_bits_set_); +} + +void Bitmap::bmprint(uint8* b, size_t n, size_t num_bits_set) +{ + kprintfd("\n---------------------Bitmap: size=%zd, num_bits_set=%zd---------------------\n" + " 0x0 0x8 0x10 0x18 0x20 0x28 0x30 0x38\n", n, num_bits_set); + for (size_t i = 0; i < n; i++) + { + if (i % 64 == 0) + kprintfd("%05zx| ",i); + kprintfd("%d", getBit(b, i)); + if (i % 8 == 7) + kprintfd(" "); + if (i % 64 == 63) + kprintfd("\n"); + } + kprintfd("\n----------------------------------Bitmap:end----------------------------------\n"); +} + +size_t Bitmap::getSize() +{ + return size_; +} + +size_t Bitmap::getNumBitsSet() +{ + return num_bits_set_; +} + +size_t Bitmap::getNumFreeBits() +{ + return size_ - num_bits_set_; +} diff --git a/pwn/flipper/dist/common/source/util/CMakeLists.txt b/pwn/flipper/dist/common/source/util/CMakeLists.txt new file mode 100644 index 0000000..68d29e3 --- /dev/null +++ b/pwn/flipper/dist/common/source/util/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(../../include/util) + +add_project_library(common_util) \ No newline at end of file diff --git a/pwn/flipper/dist/common/source/util/SWEBDebugInfo.cpp b/pwn/flipper/dist/common/source/util/SWEBDebugInfo.cpp new file mode 100644 index 0000000..8db946c --- /dev/null +++ b/pwn/flipper/dist/common/source/util/SWEBDebugInfo.cpp @@ -0,0 +1,112 @@ +#include +#include "kprintf.h" +#include "SWEBDebugInfo.h" +#include "Stabs2DebugInfo.h" +#include "ArchCommon.h" +#include "ArchMemory.h" + + +struct FileHeader { + uint16_t functions; + uint8_t filename_len; +} __attribute__((packed)); + +struct FunctionHeader { + uint64_t offset; + uint16_t line_entries; + uint8_t name_len; +} __attribute__((packed)); + +struct LineHeader { + uint16_t offset; + uint16_t number; +} __attribute__((packed)); + + +SWEBDebugInfo::SWEBDebugInfo(char const *sweb_start, char const *sweb_end) : Stabs2DebugInfo(sweb_start, sweb_end, 0) { + if (sweb_start != 0 && sweb_end != 0) + initialiseSymbolTable(); +} + +SWEBDebugInfo::~SWEBDebugInfo() { +} + + +void SWEBDebugInfo::initialiseSymbolTable() { + function_defs_.reserve(256); + file_addrs_.reserve(256); + + char *data = (char *) stab_start_ + 8; + + char buffer[256]; + do { + FileHeader *fh = (FileHeader *) data; + data += sizeof(FileHeader); + strncpy(buffer, data, fh->filename_len); + buffer[fh->filename_len] = 0; + data += fh->filename_len; + ustl::string filename(buffer); + + for(int fn = 0; fn < fh->functions; fn++) { + FunctionHeader* fnh = (FunctionHeader*)data; + if(fn == 0) { + file_addrs_[fnh->offset] = filename; + } + function_defs_[fnh->offset] = data; + data += sizeof(FunctionHeader); + data += fnh->name_len; + data += fnh->line_entries * sizeof(LineHeader); + } + + } while(data != (char*)stab_end_); + + debug(USERTRACE, "found %zd sweb debug functions\n", function_defs_.size()); + +} + +void SWEBDebugInfo::getCallNameAndLine(pointer address, const char *&name, ssize_t &line) const { + name = "UNKNOWN FUNCTION"; + line = 0; + + if (!this || function_defs_.size() == 0) + return; + + FunctionHeader* fh = 0; + for(auto f : function_defs_) { + if (address >= f.first) + fh = (FunctionHeader*)f.second; + } + if (fh == 0) + return; + + name = ((char*)fh) + sizeof(FunctionHeader); + + LineHeader* lh = (LineHeader*)((char*)(fh + 1) + fh->name_len); + bool found = false; + for(int e = 0; e < fh->line_entries; e++) { + if(address < fh->offset + lh->offset) { + lh--; + found = true; + break; + } else if(address == fh->offset + lh->offset) { + found = true; + break; + } + lh++; + } + + line = found ? lh->number : -(int)(address - fh->offset); +} + + +void SWEBDebugInfo::printCallInformation(pointer address) const { + const char *name; + ssize_t line; + getCallNameAndLine(address, name, line); + if (line >= 0) { + kprintfd("%10zx: %." CALL_FUNC_NAME_LIMIT_STR "s:%zu \n", address, name, line ); + } + else { + kprintfd("%10zx: %." CALL_FUNC_NAME_LIMIT_STR "s+%zx\n", address, name, -line); + } +} diff --git a/pwn/flipper/dist/common/source/util/Stabs2DebugInfo.cpp b/pwn/flipper/dist/common/source/util/Stabs2DebugInfo.cpp new file mode 100644 index 0000000..93ac7b8 --- /dev/null +++ b/pwn/flipper/dist/common/source/util/Stabs2DebugInfo.cpp @@ -0,0 +1,380 @@ +#include "kprintf.h" +#include "Stabs2DebugInfo.h" +#include "ArchCommon.h" +#include "ArchMemory.h" + +#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,0 */ +#define N_FUN 0x24 /* procedure: name,,0,linenumber,address */ +#define N_SLINE 0x44 /* src line: 0,,0,linenumber,address */ +#define N_PSYM 0xa0 /* parameter: name,,0,type,offset */ + +struct StabEntry +{ + uint32 n_strx; + uint8 n_type; + uint8 n_other; + uint16 n_desc; + uint32 n_value; +}__attribute__((packed)); + +Stabs2DebugInfo::Stabs2DebugInfo(char const *stab_start, char const *stab_end, char const *stab_str) : + stab_start_(reinterpret_cast(stab_start)), + stab_end_(reinterpret_cast(stab_end)), stabstr_buffer_(stab_str) +{ + if (stabstr_buffer_) + initialiseSymbolTable(); +} + +Stabs2DebugInfo::~Stabs2DebugInfo() +{ + // we reinterpret casted this from normal character buffers + // so make sure we don't execute any potential dtors, no ctors were called anyway + operator delete[](reinterpret_cast(const_cast(stab_start_))); + operator delete[](reinterpret_cast(const_cast(stabstr_buffer_))); +} + +void Stabs2DebugInfo::initialiseSymbolTable() +{ + function_symbols_.reserve(256); + + // debug output for userspace symols + for (StabEntry const *current_stab = stab_start_; current_stab < stab_end_; ++current_stab) + { + if (ArchMemory::get_PPN_Of_VPN_In_KernelMapping((size_t)current_stab / PAGE_SIZE,0,0) && (current_stab->n_type == N_FUN || current_stab->n_type == N_FNAME)) + { + function_symbols_[current_stab->n_value] = current_stab; + } + } + debug(MAIN, "found %zd functions\n", function_symbols_.size()); + +} + +struct StabsOperator +{ + const char* mangled; + const char* demangled; +} operators[] = { + {"nw"," new"}, {"na"," new[]"}, {"dl"," delete"}, {"da"," delete[]"}, {"ps","+"}, {"ng","-"}, {"ad","&"}, {"de","*"}, + {"co","~"}, {"pl","+"}, {"mi","-"}, {"ml","*"}, {"dv","/"}, {"rm","%"}, {"an","&"}, {"or","|"}, {"eo","^"}, + {"aS","="}, {"pL","+="}, {"mI","-="}, {"mL","*="}, {"dV","/="}, {"rM","%="}, {"aN","&="}, {"oR","|="}, {"eO","^="}, + {"ls","<<"}, {"rs",">>"}, {"lS","<<="}, {"rS",">>="}, {"eq","=="}, {"ne","!="}, {"lt","<"}, {"gt",">"}, {"le","<="}, + {"ge",">="}, {"nt","!"}, {"aa","&&"}, {"oo","||"}, {"pp","++"}, {"mm","--"}, {"cm",","}, {"pm","->*"}, {"pt","->"}, + {"cl","()"}, {"ix","[]"}, {"qu","?"}, {"st","sizeof"}, {"sz","sizeof"} +}; + +bool Stabs2DebugInfo::tryPasteOoperator(const char *& input, char *& buffer, size_t& size) const +{ + if (!input || !buffer) + return false; + + const char* operator_name = 0; + + for (StabsOperator op : operators) + { + if (input[0] == op.mangled[0] && input[1] == op.mangled[1]) + { + operator_name = op.demangled; + break; + } + } + + if (operator_name == 0) + return false; + + size_t n = strlen(operator_name); + + const char* op_str = "operator"; + while (*op_str) + putChar2Buffer(buffer,*op_str++,size); + for (size_t i = 0; i < n; ++i) + putChar2Buffer(buffer,*operator_name++,size); + input += 2; + return true; +} + +ssize_t Stabs2DebugInfo::getFunctionLine(pointer start, pointer offset) const +{ + ssize_t line = -1; + ustl::map::const_iterator it = function_symbols_.find(start); + if (it != function_symbols_.end()) + { + StabEntry const *se = it->second + 1; + while (se->n_type == N_PSYM) + ++se; + while (se->n_type == N_SLINE) + { + if (offset < se->n_value) + return line; + else + line = se->n_desc; + ++se; + } + } + return line; +} + + +void Stabs2DebugInfo::getCallNameAndLine(pointer address, const char*& mangled_name, ssize_t &line) const +{ + mangled_name = 0; + line = 0; + + if (!this || function_symbols_.size() == 0 || + !(ADDRESS_BETWEEN(address, function_symbols_.begin()->first, ArchCommon::getKernelEndAddress()))) + return; + + ustl::map::const_iterator it; + for(it = function_symbols_.begin(); it != function_symbols_.end() && it->first <= address; ++it); + + if (it == function_symbols_.end()) + return; + + --it; + mangled_name = stabstr_buffer_ + it->second->n_strx; + size_t offset = address - it->first; + line = -offset; + + StabEntry const *se; + // run the iterator until it finds line informations + for(se = it->second + 1; se->n_type == N_PSYM; ++se) + ; + + for(; se->n_type == N_SLINE && offset >= se->n_value; ++se) + { + line = se->n_desc; + } +} + + + +void Stabs2DebugInfo::printCallInformation(pointer address) const +{ + const char* mangled_name; + ssize_t line; + getCallNameAndLine(address, mangled_name, line); + char name[CALL_FUNC_NAME_LIMIT] = "UNKNOWN FUNCTION"; + if(mangled_name) + { + demangleName(mangled_name, name, CALL_FUNC_NAME_LIMIT); + } + if(line >= 0) + { + kprintfd("%10zx: %." CALL_FUNC_NAME_LIMIT_STR "s:%zu \n", address, name, line ); + } + else + { + kprintfd("%10zx: %." CALL_FUNC_NAME_LIMIT_STR "s+%zx\n", address, name, -line); + } +} + +pointer Stabs2DebugInfo::getFunctionName(pointer address, char function_name[], size_t size) const +{ + if (function_symbols_.size() == 0 || !(ADDRESS_BETWEEN(address, function_symbols_.begin()->first, ArchCommon::getKernelEndAddress()))) + return 0; + + ustl::map::const_iterator it; + for(it = function_symbols_.begin(); it != function_symbols_.end() && it->first <= address; ++it) + { + } + + if (it != function_symbols_.end()) + { + --it; + demangleName(stabstr_buffer_ + it->second->n_strx, function_name, size); + return it->first; + } + + return 0; +} + +int Stabs2DebugInfo::readNumber(const char *& input) const +{ + if (!input) + return -1; + + int result = 0; + + while (*input >= '0' && *input <= '9') + { + result = 10 * result + (*input - '0'); + ++input; + } + + return result; +} + +struct StabsTypename +{ + const char mangled; + const char* demangled; +} typenames[] = { + {'v',""}, {'w',"wchar_t"}, {'b',"bool"}, {'c',"char"}, {'a',"signed char"}, {'h',"unsigned char"}, {'s',"short"}, + {'t',"unsigned short"}, {'i',"int"}, {'j',"unsigned int"}, {'l',"long"}, {'m',"unsigned long"}, {'x',"long long"}, + {'y',"unsigned long long"}, {'n',"__int128"}, {'o',"unsigned __int128"}, {'f',"float"}, {'d',"double"}, + {'e',"long double"}, {'g',"__float128"}, {'z',"ellipsis"} +}; + +void Stabs2DebugInfo::pasteTypename(const char *& input, char *& buffer, size_t& size) const +{ + bool is_reference = false, is_pointer = false; + size_t offset_input, count; + char const* src = ""; + + if (!input || !buffer) + return; + + if (*input == 'R') + { + ++input; + is_reference = true; + } + + if (*input == 'P') + { + ++input; + is_pointer = true; + } + + if (*input == 'K') + { + const char* const_str = "const"; + while (*const_str) + putChar2Buffer(buffer,*const_str++,size); + ++input; + } + + if (*input >= '0' && *input <= '9') + { + count = readNumber(input); + offset_input = count; + src = input; + } + else + { + src = ""; + for (StabsTypename t : typenames) + { + if (*input == t.mangled) + { + src = t.demangled; + break; + } + } + count = strlen(src); + offset_input = 1; + } + + for (size_t i = 0; i < count; ++i) + putChar2Buffer(buffer,*src++,size); + input += offset_input; + + if (is_pointer) + putChar2Buffer(buffer,'*',size); + + if (is_reference) + putChar2Buffer(buffer,'&',size); +} + +void Stabs2DebugInfo::pasteArguments(const char *& input, char *& buffer, char delimiter, size_t& size) const +{ + if (!input || !buffer) + return; + + int arg_nr = 0; + + while (*input != delimiter) + { + if (arg_nr++) + { + putChar2Buffer(buffer,',',size); + putChar2Buffer(buffer,' ',size); + } + + pasteTypename(input, buffer, size); + } +} + +size_t Stabs2DebugInfo::putChar2Buffer(char*& buffer, char c, size_t& size) const +{ + if (size <= 1) + return -1; + *buffer++ = c; + *buffer = 0; + --size; + return 0; +} + +void Stabs2DebugInfo::demangleName(const char* name, char *buffer, size_t size) const +{ + const char *p_data = name; + + if (!buffer || !p_data) + return; + + if (p_data[0] != '_' || p_data[1] != 'Z') // is the name mangled? + { + size_t length = strlen(name); + for (size_t i = 0; i < length; ++i) // copy unmangled name + { + if (*p_data == ':') + break; + + putChar2Buffer(buffer,*p_data++,size); + } + } + else + { + p_data += 2; // skip "_Z", which indicates a mangled name + + if (*p_data == 'N') // we've got a nested name + { + ++p_data; + int name_count = 0; + + uint32 repeat = 0; + while (*p_data != 'E') + { + if (name_count++ && *p_data != 'I') + { + putChar2Buffer(buffer,':',size); + putChar2Buffer(buffer,':',size); + } + + if (*p_data >= '0' && *p_data <= '9') // part of nested name + { + size_t Count = readNumber(p_data); + + for (size_t i = 0; i < Count; ++i) + putChar2Buffer(buffer,*p_data++,size); + } + else if (*p_data == 'I') // parse template params + { + putChar2Buffer(buffer,'<',size); + pasteArguments(++p_data, buffer, 'E', size); + putChar2Buffer(buffer,'>',size); + ++p_data; + } + else + tryPasteOoperator(p_data, buffer, size); + if (repeat >= 2) + break; + ++repeat; + } + ++p_data; + } + else + { + if (*p_data == 'L') // we've got a local name + ++p_data; + + size_t count = readNumber(p_data); + for (size_t i = 0; i < count; ++i) + putChar2Buffer(buffer,*p_data++,size); + } + + putChar2Buffer(buffer,'(',size); + pasteArguments(p_data, buffer, ':', size); + putChar2Buffer(buffer,')',size); + } +} + diff --git a/pwn/flipper/dist/common/source/util/backtrace.cpp b/pwn/flipper/dist/common/source/util/backtrace.cpp new file mode 100644 index 0000000..b1ef753 --- /dev/null +++ b/pwn/flipper/dist/common/source/util/backtrace.cpp @@ -0,0 +1,15 @@ +#include "backtrace.h" +#include "Thread.h" + +pointer getCalledBefore(size_t offset) +{ + // this function calls the backtrace function, so increase the backtrace depth + offset += 2; + pointer call_stack[offset]; + call_stack[offset-1] = 0; + if((size_t)backtrace(call_stack, offset, currentThread, false) == offset) + { + return call_stack[offset-1]; + } + return 0; +} diff --git a/pwn/flipper/dist/common/source/util/kstring.cpp b/pwn/flipper/dist/common/source/util/kstring.cpp new file mode 100644 index 0000000..1751755 --- /dev/null +++ b/pwn/flipper/dist/common/source/util/kstring.cpp @@ -0,0 +1,564 @@ +#include "kstring.h" +#include "kmalloc.h" +#include "assert.h" +#include "ArchMemory.h" + +extern "C" size_t strlen(const char *str) +{ + const char *pos = str; + + while (*pos) + { + ++pos; + } + + return (pos - str); +} + +extern "C" void *memcpy(void *dest, const void *src, size_t length) +{ + size_t i; + size_t* s = (size_t*) src; + size_t* d = (size_t*) dest; + size_t num_large_copies = length / sizeof(size_t); + size_t num_rest_copies = length % sizeof(size_t); + for (size_t i = 0; i < num_large_copies; ++i) + { + *d++ = *s++; + } + uint8* s8 = (uint8*) s; + uint8* d8 = (uint8*) d; + for (i = 0; i < num_rest_copies; ++i) + { + *d8++ = *s8++; + } + return dest; +} + +extern "C" void *memmove(void *dest, const void *src, size_t length) +{ + uint8* dest8 = (uint8*) dest; + const uint8* src8 = (const uint8*) src; + + if (length == 0 || src == dest) + { + return dest; + } + + if (src > dest) + { + // if src is _not_ before dest we can do a forward copy + while (length--) + { + *dest8++ = *src8++; + } + } + else + { + // if src is before dest we have to do a backward copy + src8 += length - 1; + dest8 += length - 1; + + while (length--) + { + *dest8-- = *src8--; + } + } + + return dest; +} + +void *memccpy(void *dest, const void *src, uint8 c, size_t length) +{ + uint8 *dest8 = (uint8*) dest; + const uint8 *src8 = (const uint8*) src; + + if (length == 0) + { + return (void*) 0; + } + + while (length--) + { + if ((*dest8++ = *src8++) == c) + { + return (void*) dest8; + } + } + + return (void *) 0; +} + +extern "C" void *memset(void *block, uint8 c, size_t size) +{ + if (size) + { + size_t i; + size_t* d = (size_t*) block; + size_t large_c = c; + for (i = 0; i < sizeof(size_t); i++) + { + large_c = (large_c << 8) | c; + } + size_t num_large_copies = size / sizeof(size_t); + size_t num_rest_copies = size % sizeof(size_t); + for (i = 0; i < num_large_copies; ++i) + { + *d++ = large_c; + } + uint8* d8 = (uint8*) d; + for (i = 0; i < num_rest_copies; ++i) + { + *d8++ = c; + } + } + return block; +} + +extern "C" char *strcpy(char *dest, const char* src) +{ + //assert("don't use strcpy" == 0); + + char *start = dest; + + for (; (*dest = *src); ++src, ++dest) + ; + + return start; +} + +extern "C" char *strncpy(char *dest, const char* src, size_t size) +{ + char *start = dest; + int8 fill = 0; + + while (size--) + { + if (fill) + { + *dest = 0; + } + else if ((*dest = *src) == 0) + { + fill = 1; + } + + src++; + dest++; + } + + return start; +} + +extern "C" char *strdup(const char *src) +{ + size_t size = strlen(src) + 1; + char *dest = 0; + + if ((dest = (char*) kmalloc((size) * sizeof(char))) == (char*) 0) + { + return (char*) 0; + } + + return (char*) memcpy(dest, src, size); +} + +extern "C" char *strcat(char *dest, const char*append) +{ + char *start = dest + strlen(dest); + strcpy(start, append); + return dest; +} + +extern "C" char *strncat(char *dest, const char*append, size_t size) +{ + char* save = dest; + + if (size == 0) + { + return save; + } + + while (*dest) + { + ++dest; + } + + while (size--) + { + if ((*dest = *append++) == '\0') + { + break; + } + ++dest; + } + + *dest = '\0'; + return save; +} + +extern "C" size_t strlcat(char *dest, const char*append, size_t size) +{ + size_t count = size; + const char*append_start = append; + size_t done = 0; + + while (count != 0 && *dest != '\0') + { + --count; + ++dest; + } + done = size - count; + + if (count == 0) + { + return done + strlen(append); + } + + while (count--) + { + if ((*dest++ = *append) == '\0') + { + break; + } + ++append; + } + + return done + (append - append_start) - 1; +} + +extern "C" void bcopy(void *src, void* dest, size_t length) +{ + uint8* dest8 = (uint8*) dest; + const uint8* src8 = (const uint8*) src; + + if (length == 0 || src == dest) + { + return; + } + + if (src < dest) + { + // if src is before dest we can do a forward copy + while (length--) + { + *dest8++ = *src8++; + } + } + else + { + // if src is _not_ before dest we can do a forward copy + src8 += length; + dest8 += length; + + while (length--) + { + *dest8-- = *src8--; + } + } + +} + +extern "C" int32 memcmp(const void *region1, const void *region2, size_t size) +{ + const uint8* b1 = (const uint8*)region1; + const uint8* b2 = (const uint8*)region2; + + if (size == 0) + { + return 0; + } + + while (size--) + { + if (*b1++ != *b2++) + { + return (*--b1 - *--b2); + } + } + + return 0; +} + +extern "C" int32 strcmp(const char *str1, const char *str2) +{ + assert(str1); + assert(str2); + + if (str1 == str2) + { + return 0; + } + + while ((*str1) && (*str2)) + { + if (*str1 != *str2) + { + break; + } + ++str1; + ++str2; + } + + return (*(uint8 *) str1 - *(uint8 *) str2); +} + +extern "C" int32 strncmp(const char *str1, const char *str2, size_t n) +{ + while (n && (*str1) && (*str2)) + { + if (*str1 != *str2) + { + break; + } + ++str1; + ++str2; + --n; + } + if (n == 0) + return 0; + else + return (*(uint8 *) str1 - *(uint8 *) str2); +} + +extern "C" int32 bcmp(const void *region1, const void *region2, size_t size) +{ + const uint8* b1 = (const uint8*)region1; + const uint8* b2 = (const uint8*)region2; + + if (size == 0) + { + return 0; + } + + while (size--) + { + if (*b1++ != *b2++) + { + return (*--b1 - *--b2); + } + } + + return 0; +} + +extern "C" void *memnotchr(const void *block, uint8 c, size_t size) +{ + const uint8 *b = (const uint8*) block; + + while (size--) + { + if (*b != c) + { + return (void *) b; + } + ++b; + } + + return (void *) 0; +} + +extern "C" void *memchr(const void *block, uint8 c, size_t size) +{ + const uint8 *b = (const uint8*) block; + + while (size--) + { + if (*b == c) + { + return (void *) b; + } + ++b; + } + + return (void *) 0; +} + +extern "C" void *memrchr(const void *block, uint8 c, size_t size) +{ + const uint8 *b = ((const uint8*) block + size - 1); + + while (size--) + { + if (*b == c) + { + return (void *) b; + } + --b; + } + + return (void *) 0; +} + +extern "C" char *strchr(const char* str, char c) +{ + do + { + if (*str == c) + { + return (char *) str; + } + } while (*++str); + + return (char *) 0; +} + +extern "C" char *strrchr(const char* str, char c) +{ + uint32 len = strlen(str); + const char *pos = str + len; // goes to '\0' + + do + { + if (*--pos == c) + { + return (char *) pos; + } + } while (--len); + + return (char *) 0; +} + +extern "C" char* strtok(char* str, const char* delimiters) +{ + static char* str_to_tok = 0; + if (str != 0) + str_to_tok = str; + + // no delimiters, so just return the rest-string + if (delimiters == 0) + return str_to_tok; + + if (str_to_tok == 0) + return 0; + + // determine token start and end + uint32 tok_start = 0; + uint32 tok_end = -1; + + // find first char which is not one of the delimiters + uint32 str_pos = 0; + for (str_pos = 0; str_to_tok[str_pos] != '\0'; str_pos++) + { + uint8 char_is_delimiter = 0; + + uint32 del_pos = 0; + for (del_pos = 0; delimiters[del_pos] != '\0'; del_pos++) + { + if (str_to_tok[str_pos] == delimiters[del_pos]) + { + char_is_delimiter = 1; + break; + } + } + + if (char_is_delimiter == 0) + { + // this is the start char of the token + tok_start = str_pos; + break; + } + } + + // find next delimiter in the string + for (str_pos = tok_start; str_to_tok[str_pos] != '\0'; str_pos++) + { + uint32 del_pos = 0; + for (; delimiters[del_pos] != '\0'; del_pos++) + { + if (str_to_tok[str_pos] == delimiters[del_pos]) + { + // delimiter found! + tok_end = str_pos; + break; + } + } + + if (tok_end != -1U) + break; + } + + // create and return token: + char* token = str_to_tok + tok_start; + + // update string + if (tok_end == -1U) + { + // finished, no next token + str_to_tok = 0; + } + else + { + str_to_tok[tok_end] = '\0'; + str_to_tok += tok_end + 1; + } + + return token; +} + +// converts a single digit into an +extern "C" char numToASCIIChar(uint8 number) +{ + if (number <= 9) + return 0x30 + number; + + if (number >= 0xa && number <= 0xf) + return 0x61 + number - 0xa; + + // default value + return '?'; +} + +extern "C" char* itoa(int value, char* str, int base) +{ + if (!str) + return 0; + + int div = value; + int mod; + unsigned int str_pos = 0; + + while (div >= base) + { + mod = div % base; + div /= base; + str[str_pos++] = numToASCIIChar(mod); + } + str[str_pos++] = numToASCIIChar(div); + if (value < 0) + str[str_pos++] = '-'; + str[str_pos] = '\0'; + + if (str_pos > 1) + { + uint32 str_len = strlen(str); + uint32 i = 0; + // switching the string + for (i = 0; i < str_len / 2; i++) + { + char temp = str[str_len - 1 - i]; + str[str_len - 1 - i] = str[i]; + str[i] = temp; + } + } + + return str; +} + +extern "C" uint32 checksum(uint32* src, uint32 nbytes) +{ + nbytes /= sizeof(uint32); + uint32 poly = 0xEDB88320; + int bit = 0, nbits = 32; + uint32 res = 0xFFFFFFFF; + + for (uint32 i = 0; i < nbytes; ++i) + for (bit = nbits - 1; bit >= 0; --bit) + if ((res & 1) != ((src[i] >> bit) & 1)) + res = (res >> 1) ^ poly; + else + res = (res >> 1) + 7; + + res ^= 0xFFFFFFFF; + return res; +} diff --git a/pwn/flipper/dist/common/source/util/libgcc.cpp b/pwn/flipper/dist/common/source/util/libgcc.cpp new file mode 100644 index 0000000..d8dbaae --- /dev/null +++ b/pwn/flipper/dist/common/source/util/libgcc.cpp @@ -0,0 +1,67 @@ +#include "libgcc.h" +#include "kprintf.h" +#include "assert.h" + +int64 __divdi3(int64 num, int64 den) +{ + int minus = 0; + int64 v; + + if ( num < 0 ) + { + num = -num; + minus = 1; + } + if ( den < 0 ) + { + den = -den; + minus ^= 1; + } + + v = __udivmoddi4(num, den, 0); + if ( minus ) + v = -v; + + return v; +} + + +uint64 __udivdi3(uint64 num, uint64 den) +{ + return __udivmoddi4(num, den, 0); +} + +uint64 __umoddi3(uint64 a, uint64 b) +{ + uint64 r; + __udivmoddi4(a, b, &r); + return r; +} + +uint64 __udivmoddi4(uint64 num, uint64 den, uint64 *rem_p) +{ + uint64 quot = 0, qbit = 1; + assert(den && "division by zero"); + + while ( (int64)den >= 0 ) + { + den <<= 1; + qbit <<= 1; + } + + while ( qbit ) + { + if ( den <= num ) + { + num -= den; + quot += qbit; + } + den >>= 1; + qbit >>= 1; + } + + if ( rem_p ) + *rem_p = num; + + return quot; +} diff --git a/pwn/flipper/dist/common/source/util/qsort.cpp b/pwn/flipper/dist/common/source/util/qsort.cpp new file mode 100644 index 0000000..3c3af6c --- /dev/null +++ b/pwn/flipper/dist/common/source/util/qsort.cpp @@ -0,0 +1,101 @@ +#include "types.h" +#include "assert.h" +#include "qsort.h" + +// Conversion from pointers to indices , to allow parent/child calculations +#define PTR_TO_INDEX(ptr) ((size_t) ((ptr) - (s_info->lo_)) / (s_info->size_)) +#define INDEX_TO_PTR(i) ((char*) ((i) * (s_info->size_) + (s_info->lo_))) + +// Macros for getting around in our tree +#define PARENT(ptr) INDEX_TO_PTR((size_t) ((PTR_TO_INDEX(ptr) - 1) / 2)) +#define L_CHILD(ptr) INDEX_TO_PTR(((PTR_TO_INDEX(ptr) * 2) + 1)) +#define R_CHILD(ptr) INDEX_TO_PTR(((PTR_TO_INDEX(ptr) * 2) + 2)) + +// Data about the area to sort +typedef struct { + char* lo_; + char* hi_; + size_t size_; + int (*compar_)(const void*, const void*); +} SortInfo; + +typedef struct { + char* lo_; + char* hi_; +} Range; + +static inline void swap_elements(char* a, char* b, const size_t size) +{ + if(a == b) return; + + for(size_t i = 0; i < size; i++) + { + char* a_c = (char*) a + i; + char* b_c = (char*) b + i; + + char tmp = *a_c; + *a_c = *b_c; + *b_c = tmp; + } +} + +// Re-Heaps a part of the heap +void siftDown(const SortInfo* const s_info, Range range) +{ + char* root = range.lo_; + + while (L_CHILD(root) <= range.hi_) + { + char* l_child = L_CHILD(root); + char* r_child = R_CHILD(root); + char* swap = root; + + if(s_info->compar_(swap, l_child) < 0) + swap = l_child; + + if(r_child <= range.hi_ && s_info->compar_(swap, r_child) < 0) + swap = r_child; + + if(root == swap) return; + + swap_elements(root, swap, s_info->size_); + root = swap; + } +} + +// Heapify the entire range +void heapify(const SortInfo* const s_info) +{ + char* start = PARENT(s_info->hi_); + + while(start >= s_info->lo_) + { + Range range = {start, s_info->hi_}; + siftDown(s_info, range); + start -= s_info->size_; + } +} + +// Simple heapsort +void heapsort(const SortInfo* const s_info) +{ + heapify(s_info); + + Range range = {s_info->lo_, s_info->hi_}; + while(range.hi_ > range.lo_) + { + swap_elements(range.hi_, range.lo_, s_info->size_); + range.hi_ -= s_info->size_; + siftDown(s_info, range); + } +} + +// Wrapper around heapsort +void qsort(void* ptr, size_t count, size_t size, int (*compar)(const void*, const void*)) +{ + if(count == 0) return; + if(size == 0) return; + + const SortInfo s_info = {(char*) ptr, ((char*) ptr) + (count - 1) * size, size, compar}; + heapsort(&s_info); +} diff --git a/pwn/flipper/dist/kernel.x b/pwn/flipper/dist/kernel.x new file mode 100755 index 0000000..8d2a425 Binary files /dev/null and b/pwn/flipper/dist/kernel.x differ diff --git a/pwn/flipper/dist/kernel64.x b/pwn/flipper/dist/kernel64.x new file mode 100755 index 0000000..d4b4059 Binary files /dev/null and b/pwn/flipper/dist/kernel64.x differ diff --git a/pwn/flipper/dist/setup_cmake.sh b/pwn/flipper/dist/setup_cmake.sh new file mode 100755 index 0000000..244cc28 --- /dev/null +++ b/pwn/flipper/dist/setup_cmake.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env sh + +# Use BUILD_DIR env var as path if provided, otherwise use default +DEFAULT_DIR="build" +BUILD_DIR="${BUILD_DIR:-${DEFAULT_DIR}}" + +# Create the build directory and initialize cmake pointing to this source folder +cmake -B"${BUILD_DIR}" -H. + +cd build +make -j diff --git a/pwn/flipper/dist/userspace/CMakeLists.txt b/pwn/flipper/dist/userspace/CMakeLists.txt new file mode 100644 index 0000000..d318f24 --- /dev/null +++ b/pwn/flipper/dist/userspace/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(libc) +add_subdirectory(tests) diff --git a/pwn/flipper/dist/userspace/data/README.txt b/pwn/flipper/dist/userspace/data/README.txt new file mode 100644 index 0000000..0017991 --- /dev/null +++ b/pwn/flipper/dist/userspace/data/README.txt @@ -0,0 +1,2 @@ +All files in this folder (userspace/data) are copied to the SWEB minix partition. + diff --git a/pwn/flipper/dist/userspace/libc/CMakeLists.txt b/pwn/flipper/dist/userspace/libc/CMakeLists.txt new file mode 100644 index 0000000..53c8bfa --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/CMakeLists.txt @@ -0,0 +1,7 @@ +target_include_directories(userspace_libc + PUBLIC + include + include/sys +) + +add_subdirectory(src) diff --git a/pwn/flipper/dist/userspace/libc/include/assert.h b/pwn/flipper/dist/userspace/libc/include/assert.h new file mode 100644 index 0000000..20e488f --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/assert.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +#define assert(X) do { if (!(X)) {\ + printf("Assertion failed: '%s', file %s, function %s, line %d\n", #X, __FILE__, __FUNCTION__, __LINE__); \ + exit(-1); } } while (0) + diff --git a/pwn/flipper/dist/userspace/libc/include/ctype.h b/pwn/flipper/dist/userspace/libc/include/ctype.h new file mode 100644 index 0000000..71652c2 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/ctype.h @@ -0,0 +1,61 @@ +#pragma once + +/* + * NOTE! This ctype does not handle EOF like the standard C + * library is required to. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static inline unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + + +#ifdef __cplusplus +} +#endif + diff --git a/pwn/flipper/dist/userspace/libc/include/fcntl.h b/pwn/flipper/dist/userspace/libc/include/fcntl.h new file mode 100644 index 0000000..a1e743d --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/fcntl.h @@ -0,0 +1,151 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +#include "unistd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The basic flags for files + */ +#ifndef O_RDONLY +#define O_RDONLY 0x0001 +#endif +#ifndef O_WRONLY +#define O_WRONLY 0x0002 +#endif +#ifndef O_RDWR +#define O_RDWR 0x0004 +#endif +#ifndef O_CREAT +#define O_CREAT 0x0008 +#endif +#ifndef O_APPEND +#define O_APPEND 0x0010 +#endif +#ifndef O_EXCL +#define O_EXCL 0x0020 +#endif +#ifndef O_NONBLOCK +#define O_NONBLOCK 0x0040 +#endif +#ifndef O_TRUNC +#define O_TRUNC 0x0080 +#endif +#ifndef O_SYNC +#define O_SYNC 0x0100 +#endif +#ifndef O_DSYNC +#define O_DSYNC 0x0200 +#endif +#ifndef O_RSYNC +#define O_RSYNC O_SYNC +#endif + +/** + * The basic access modes for files + */ +#define A_READABLE 0x0001 +#define A_WRITABLE 0x0002 +#define A_EXECABLE 0x0004 + + +/** + * Structure for describing a file lock + * + */ +struct flock +{ + + /** + * Type of lock + * F_RDLCK, F_WRLCK or F_UNLCK + * + */ + short l_type; + + /** + * Flag for starting offset + * + */ + short l_whence; + + /** + * Relative offset in bytes + * + */ + off_t l_start; + + /** + * Size, if 0 then until EOF + * + */ + off_t l_len; + + /** + * Process ID of the process holding the lock. + * + */ + pid_t l_pid; + +}; + +/** + * Equivalent to open() with flags equal to O_CREAT | O_WRONLY | O_TRUNC. + * + * @param path A pathname pointing to the file to open + * @param mode + * @return A valid file descriptor or -1 if an error occured + * + */ +extern int creat(const char *path, mode_t mode); + +/** + * Converts a pathname into a file descriptor which can be used in subsequent + * read and write operations. + * If successfull, the lowest file descriptor not currently open for the + * process will be returned. + * + * Possible values for the flags parameter are: + * - O_RDONLY Open for reading only + * - O_WRONLY Open for writing only + * - O_RDWR Open for reading and writing + * + * which can be bitwise combined (or'd) with: + * - O_APPEND Open in append mode + * - O_CREAT Create file if it does not exist + * - O_TRUNC Truncate file to 0 length if it already exists and is a + * regular file + * + * @param path A pathname pointing to the file to open + * @param flags Flags to specify how the file is opened + * @return A valid file descriptor or -1 if an error occured + * + */ +extern int open(const char *path, int flags, ...); + +#ifdef __cplusplus +} +#endif + + diff --git a/pwn/flipper/dist/userspace/libc/include/nonstd.h b/pwn/flipper/dist/userspace/libc/include/nonstd.h new file mode 100644 index 0000000..cc5dd69 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/nonstd.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../../../common/include/kernel/syscall-definitions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Creates a new process. + * + * @param path the path to the binary to open + * @param sleep whether the calling process should sleep until the other process terminated + * @return -1 if the path did not lead to an executable, 0 if the process was executed successfully + * + */ +extern int createprocess(const char* path, int sleep); +extern int flipBit(const void* address, int bit_num); +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/pthread.h b/pwn/flipper/dist/userspace/libc/include/pthread.h new file mode 100644 index 0000000..ca5aae8 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/pthread.h @@ -0,0 +1,63 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//pthread typedefs +typedef size_t pthread_t; +typedef unsigned int pthread_attr_t; + +//pthread mutex typedefs +typedef unsigned int pthread_mutex_t; +typedef unsigned int pthread_mutexattr_t; + +//pthread spinlock typedefs +typedef unsigned int pthread_spinlock_t; + +//pthread cond typedefs +typedef unsigned int pthread_cond_t; +typedef unsigned int pthread_condattr_t; + +extern int pthread_create(pthread_t *thread, + const pthread_attr_t *attr, void *(*start_routine)(void *), + void *arg); + +extern void pthread_exit(void *value_ptr); + +extern int pthread_cancel(pthread_t thread); + +extern int pthread_join(pthread_t thread, void **value_ptr); + +extern int pthread_detach(pthread_t thread); + +extern int pthread_mutex_init(pthread_mutex_t *mutex, + const pthread_mutexattr_t *attr); + +extern int pthread_mutex_destroy(pthread_mutex_t *mutex); + +extern int pthread_mutex_lock(pthread_mutex_t *mutex); + +extern int pthread_mutex_unlock(pthread_mutex_t *mutex); + +extern int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); + +extern int pthread_cond_destroy(pthread_cond_t *cond); + +extern int pthread_cond_signal(pthread_cond_t *cond); + +extern int pthread_cond_broadcast(pthread_cond_t *cond); + +extern int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); + +extern int pthread_setcancelstate(int state, int *oldstate); + +extern int pthread_setcanceltype(int type, int *oldtype); + +#ifdef __cplusplus +} +#endif + + diff --git a/pwn/flipper/dist/userspace/libc/include/sched.h b/pwn/flipper/dist/userspace/libc/include/sched.h new file mode 100644 index 0000000..836c872 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/sched.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../../common/include/kernel/syscall-definitions.h" + +extern int sched_yield(void); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/semaphore.h b/pwn/flipper/dist/userspace/libc/include/semaphore.h new file mode 100644 index 0000000..28e5f6b --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/semaphore.h @@ -0,0 +1,28 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +//semaphores typedefs +#ifndef SEM_T_DEFINED_ +#define SEM_T_DEFINED_ +typedef unsigned int sem_t; +#endif // SEM_T_DEFINED_ + +extern int sem_init(sem_t *sem, int pshared, unsigned value); + +extern int sem_wait(sem_t *sem); + +extern int sem_trywait(sem_t *sem); + +extern int sem_destroy(sem_t *sem); + +extern int sem_post(sem_t *sem); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/stdarg.h b/pwn/flipper/dist/userspace/libc/include/stdarg.h new file mode 100644 index 0000000..846e54e --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/stdarg.h @@ -0,0 +1,146 @@ +/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you include this header file into source + files compiled by GCC, this header file does not by itself cause + the resulting executable to be covered by the GNU General Public + License. This exception does not however invalidate any other + reasons why the executable file might be covered by the GNU General + Public License. */ + + + +/* + * ISO C Standard: 7.15 Variable arguments + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _STDARG_H +#ifndef _ANSI_STDARG_H_ +#ifndef __need___va_list +#define _STDARG_H +#define _ANSI_STDARG_H_ +#endif /* not __need___va_list */ +#undef __need___va_list + + + +/* Define __gnuc_va_list. */ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif + +/* Define the standard macros for the user, + if this invocation was from the user program. */ +#ifdef _STDARG_H + +#define va_start(v,l) __builtin_va_start(v,l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v,l) __builtin_va_arg(v,l) +#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L +#define va_copy(d,s) __builtin_va_copy(d,s) +#endif +#define __va_copy(d,s) __builtin_va_copy(d,s) + +/* Define va_list, if desired, from __gnuc_va_list. */ +/* We deliberately do not define va_list when called from + stdio.h, because ANSI C says that stdio.h is not supposed to define + va_list. stdio.h needs to have access to that data type, + but must not use that name. It should use the name __gnuc_va_list, + which is safe because it is reserved for the implementation. */ + +#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */ +#undef _VA_LIST +#endif + +#ifdef _BSD_VA_LIST +#undef _BSD_VA_LIST +#endif + +#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST)) +/* SVR4.2 uses _VA_LIST for an internal alias for va_list, + so we must avoid testing it and setting it here. + SVR4 uses _VA_LIST as a flag in stdarg.h, but we should + have no conflict with that. */ +#ifndef _VA_LIST_ +#define _VA_LIST_ +#ifdef __i860__ +#ifndef _VA_LIST +#define _VA_LIST va_list +#endif +#endif /* __i860__ */ +typedef __gnuc_va_list va_list; +#ifdef _SCO_DS +#define __VA_LIST +#endif +#endif /* _VA_LIST_ */ +#else /* not __svr4__ || _SCO_DS */ + +/* The macro _VA_LIST_ is the same thing used by this file in Ultrix. + But on BSD NET2 we must not test or define or undef it. + (Note that the comments in NET 2's ansi.h + are incorrect for _VA_LIST_--see stdio.h!) */ +#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT) +/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5 */ +#ifndef _VA_LIST_DEFINED +/* The macro _VA_LIST is used in SCO Unix 3.2. */ +#ifndef _VA_LIST +/* The macro _VA_LIST_T_H is used in the Bull dpx2 */ +#ifndef _VA_LIST_T_H +/* The macro __va_list__ is used by BeOS. */ +#ifndef __va_list__ +typedef __gnuc_va_list va_list; +#endif /* not __va_list__ */ +#endif /* not _VA_LIST_T_H */ +#endif /* not _VA_LIST */ +#endif /* not _VA_LIST_DEFINED */ +#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__)) +#define _VA_LIST_ +#endif +#ifndef _VA_LIST +#define _VA_LIST +#endif +#ifndef _VA_LIST_DEFINED +#define _VA_LIST_DEFINED +#endif +#ifndef _VA_LIST_T_H +#define _VA_LIST_T_H +#endif +#ifndef __va_list__ +#define __va_list__ +#endif + +#endif /* not _VA_LIST_, except on certain systems */ + +#endif /* not __svr4__ */ + +#endif /* _STDARG_H */ + +#endif /* not _ANSI_STDARG_H_ */ +#endif /* not _STDARG_H */ + +#ifdef __cplusplus +} +#endif + diff --git a/pwn/flipper/dist/userspace/libc/include/stdio.h b/pwn/flipper/dist/userspace/libc/include/stdio.h new file mode 100644 index 0000000..85bfc19 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/stdio.h @@ -0,0 +1,253 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +// stdarg.h is taken from gcc +#include + +#include "unistd.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Size of buffers + * + */ +#define BUFSIZ 4096 + + +/** + * Input/output fully buffered + * + */ +#define _IOFBF 0x0000 + +/** + * Input/output line buffered + * + */ +#define _IOLBF 0x0001 + +/** + * Input/output unbuffered + * + */ +#define _IONBF 0x0002 + + +/** + * Maximum size of character array to hold ctermid() output + * + */ +#define L_ctermid 64 + +/** + * Maximum size of character array to hold tmpnam() output + * + */ +#define L_tmpnam 64 + + +/** + * Set file offset to offset, defined for lseek() and fcntl() + * + */ +#define SEEK_SET 0x0000 + +/** + * Set file offset to current + offset, defined for lseek() and fcntl() + * + */ +#define SEEK_CUR 0x0001 + +/** + * Set file offset to EOF + offset, defined for lseek() and fcntl() + * + */ +#define SEEK_END 0x0002 + + +/** + * Maximum size in bytes of the longest filename string that the implementation + * guarantees can be opened. + * + */ +#define FILENAME_MAX 256 + +/** + * Number of streams which the implementation guarantees can be opened + * simultaneously. The value is at least eight. + * + */ +#define FOPEN_MAX 8 + +/** + * Minimum number of unique filenames generated by tmpnam(). Maximum number of + * times an application can call tmpnam() reliably. The value of TMP_MAX is at + * least 25. + * + */ +#define TMP_MAX 25 + + +/** + * End-of-file return value + * + */ +#define EOF -1 + +/** + * NULL pointer constant + * + */ +#define NULL 0 + + +/** + * Default directory prefix for tempnam() + * + */ +#define P_tmpdir /tmp + + +/** + * A non-array type containing all information needed to specify uniquely + * every position within a file. + * + */ +typedef off_t fpos_t; + +/** + * Renames a file, moving it between directories if required. + * + * @param old_path The old pathname + * @param new_path The new pathname + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int rename(const char *old_path, const char *new_path); + +/** + * Equivalent to getc(stdin). + * + * @return The read character on success, EOF otherwise and errno is set\ + appropriately + * + */ +extern int getchar(); + +/** + * Reads a line from stdin and stores it in the string pointed to by the + * argument. + * Reading is terminated by a newline, EOF which are both replaced by '\0' or + * when the buffer is full. + * + * @param input_buffer The buffer where the input is stored + * @param buffer_size The size of the buffer + * @return A pointer to the input_string on success, NULL otherwise + * + */ +extern char *gets(char *input_buffer, size_t buffer_size); + +extern char *fgets(char *str, int num, int fd); + +/** + * Equivalent to putc(character, stdout). + * + * @param character The character for writing + * @return The character written as unsigned char cast to int or EOF on error + * + */ +extern int putchar(int character); + +/** + * Writes the given string followed by a newline to stdout. + * + * @param output_string The string for writing + * @return A non-negative number on success or EOF on error + * + */ +extern int puts(const char *output_string); + + +/** + * Writes output to stdout. + * A detailed description of the format is given in the + * 'Linux Programmer's Manual'. + * + * @param format A string containing the output format, followed by an\ + argument list containing different variables for output + * @return The number of characters printed or the number of characters that\ + would have been printed if the output was truncated, a negative\ + value is returned on failure + * + */ +extern int printf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); + +/** + * Prints an error message on the standard error output describing the last + * error encountered during a call to a system or library function. + * This function first prints the given error message string, if it is not + * NULL and has a length greater zero, followed by a colon and a blank. + * After that the message corresponding to the last error is printed + * followed by a new-line. + * It is useful to include the name of the function that failed in the + * argument string. + * + * The last error number is stored in the external variable errno which + * indexes the global error list sys_errlist[]. By accessing this list with + * errno as index, the message for the error can be obtained. + * The largest index for sys_errlist[] is the value of the external variable + * sys_nerr - 1. + * + * The variable errno has undefined state if the call to a function succeeded. + * If a failing call is not immediately followed by a call to perror() then + * the value of errno should be saved. + * + * @param error_msg Additional error message + * + */ +extern void perror(const char *error_msg); + +/** + * Reads input from stdin according to the given format and + * assigns read values to the given variables. + * A detailed description of the format is given in the + * 'Linux Programmer's Manual'. + * + * @param format A string containing the input format, followed by an\ + argument list of variables for assignment + * @return The number of input items assigned, zero indicates that no input\ + items were assigned while input was available, EOF if failure (e.g.\ + end-of-file) occurs before any items have been read + * + */ +extern int scanf(const char *format, ...) __attribute__ ((format (scanf, 1, 2))); + +extern int sscanf(const char *buffer, const char *fmt, ...) __attribute__((format (scanf, 2, 3))); + +#ifdef __cplusplus +} +#endif + + diff --git a/pwn/flipper/dist/userspace/libc/include/stdlib.h b/pwn/flipper/dist/userspace/libc/include/stdlib.h new file mode 100644 index 0000000..4e6e260 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/stdlib.h @@ -0,0 +1,91 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * exit value constants + * + */ +#define EXIT_FAILURE -1 +#define EXIT_SUCCESS 0 + +/** + * NULL pointer constant + * + */ +#define NULL 0 + + +/** + * parses the given string and returns its value as integer + * @param string the string for parsing + * @return the parsed value + * + */ +extern int atoi(const char *string); + +/** + * parses the given string and returns its value as long + * @param string the string for parsing + * @return the parsed value + * + */ +extern long atol(const char *string); + +/** + * Terminates the program normally, functions registered by atexit() are called + * in reverse order of their registration, any open file descriptors belonging + * to the process are closed, any children of the process are inherited by + * process 1 (init) and the process's parent is sent a SIGCHLD signal. + * The status value is returned to the parent as exit status and can be + * collected using a wait call. + * @param status the exit status of the calling process, 0 or EXIT_SUCCESS for + * successfull termination, EXIT_FAILURE for unsuccessful termination + * + */ +extern void exit(int status); + +/** + * register a function to be called at normal process termination + * @param function the function to be called + * @return 0 if successful, other-wise non-zero + */ +extern int atexit(void (*function)(void)); + +extern void *malloc(size_t size); + +extern void *calloc(size_t nmemb, size_t size); + +extern void *realloc(void *ptr, size_t size); + +extern void free(void *ptr); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/string.h b/pwn/flipper/dist/userspace/libc/include/string.h new file mode 100644 index 0000000..839d5d3 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/string.h @@ -0,0 +1,99 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * NULL pointer constant + * + */ +#define NULL 0 + +/** + * Compares the given number of bytes of the memory areas started by the + * given pointers. + * The return value will be an integer less than zero, if the bytes at the + * first area are less than those of the second. It will be zero for equality, + * and a value greater zero if the bytes at the first area are greater than + * those of the second + * + * @param first_position Position of the first memory area + * @param second_position Position of the second memory area + * @param number_of_bytes Number of bytes to compare + * @return An integer indicating the found differences + * + */ +extern int memcmp(const void *first_position, const void *second_position, + size_t number_of_bytes); + +/** + * Copies the given number of bytes from memory area source to memory area + * destination. The memory areas should not overlap. + * + * @param destination Destination memory position + * @param source Source memory position + * @param number_of_bytes Number of bytes to copy + * @return A pointer to the destination + * + */ +extern void* memcpy(void *destination, const void *source, + size_t number_of_bytes); + +/** + * Fills the given number of bytes of the memory area pointed to by the given + * position with the given value. + * + * @param position Position of the memory area + * @param value Value to write + * @param number_of_bytes Number of bytes to write + * @return A pointer to the memory area + * + */ +extern void *memset(void *position, int value, size_t number_of_bytes); + +/** + * Gets the length of the null terminated string + * + * @param str String + * @return length of String + */ +extern size_t strlen(const char* str); + +/** + * Compares the 2 Strings, default implementation + */ +extern int strcmp (const char * l, const char * r); + +/** + * searches for needle in haystack + */ +extern char *strstr(const char *haystack, const char *needle); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/sys/mman.h b/pwn/flipper/dist/userspace/libc/include/sys/mman.h new file mode 100644 index 0000000..4997f90 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/sys/mman.h @@ -0,0 +1,33 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PROT_NONE 0x00000000 // 00..00 +#define PROT_READ 0x00000001 // ..0001 +#define PROT_WRITE 0x00000002 // ..0010 +#define PROT_EXEC 0x00000004 // ..0100 + +#define MAP_PRIVATE 0x20000000 // 0010.. +#define MAP_SHARED 0x40000000 // 0100.. +#define MAP_ANONYMOUS 0x80000000 // 1000.. + +extern void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); + +extern int munmap(void* start, size_t length); + +extern int shm_open(const char* name, int oflag, mode_t mode); + +extern int shm_unlink(const char* name); + +extern int mprotect(void *addr, size_t len, int prot); + +#ifdef __cplusplus +} +#endif + + diff --git a/pwn/flipper/dist/userspace/libc/include/sys/syscall.h b/pwn/flipper/dist/userspace/libc/include/sys/syscall.h new file mode 100644 index 0000000..ada0ee6 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/sys/syscall.h @@ -0,0 +1,44 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Low-level syscall function, takes 6 arguments where the first is the syscall + * number as defined in the kernel syscall definitions. + * Unused arguments can be filled up with 0x00s. + * e.g. __syscall(sc_exit, status, 0x00, 0x00, 0x00, 0x00); + * DO NOT CHANGE SIGNATURE. + */ +extern size_t __syscall(size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5, + size_t arg6); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/time.h b/pwn/flipper/dist/userspace/libc/include/time.h new file mode 100644 index 0000000..4442ac3 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/time.h @@ -0,0 +1,19 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define CLOCKS_PER_SEC 1000000 + +#ifndef CLOCK_T_DEFINED +#define CLOCK_T_DEFINED +typedef unsigned int clock_t; +#endif // CLOCK_T_DEFINED + +extern clock_t clock(void); + +#ifdef __cplusplus +} +#endif + diff --git a/pwn/flipper/dist/userspace/libc/include/types.h b/pwn/flipper/dist/userspace/libc/include/types.h new file mode 100644 index 0000000..9ddab75 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/types.h @@ -0,0 +1,22 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +typedef long unsigned int off_t; +typedef long unsigned int mode_t; +typedef long unsigned int uid_t; +typedef long unsigned int gid_t; +typedef long unsigned int size_t; +typedef long int ssize_t; + +#ifndef PID_T_DEFINED +#define PID_T_DEFINED +typedef long int pid_t; +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/pwn/flipper/dist/userspace/libc/include/unistd.h b/pwn/flipper/dist/userspace/libc/include/unistd.h new file mode 100644 index 0000000..feacf62 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/unistd.h @@ -0,0 +1,313 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#pragma once + +#include "../../../common/include/kernel/syscall-definitions.h" +#include "stdarg.h" +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * NULL pointer constant + * + */ +#define NULL 0 + + +/** + * Set file offset to offset, defined for lseek() and fcntl() + * + */ +#define SEEK_SET 0x0000 + +/** + * Set file offset to current + offset, defined for lseek() and fcntl() + * + */ +#define SEEK_CUR 0x0001 + +/** + * Set file offset to EOF + offset, defined for lseek() and fcntl() + * + */ +#define SEEK_END 0x0002 + + +/** + * Lock a section for exclusive use, defined for lockf() + * + */ +#define F_LOCK 0x0000 + +/** + * Unlock locked sections, defined for lockf() + * + */ +#define F_ULOCK 0x0001 + +/** + * Test section for locks by other processes, defined for lockf() + * + */ +#define F_TEST 0x0002 + +/** + * Test and lock a section for exclusive use, defined for lockf() + * + */ +#define F_TLOCK 0x0004 + + +/** + * File number of stdin + * + */ +#define STDIN_FILENO fd_stdin + +/** + * File number of stdin + * + */ +#define STDOUT_FILENO fd_stdout + +/** + * File number of stdin + * + */ +#define STDERR_FILENO fd_stderr + +/** + * Time in microseconds + * + */ +typedef long unsigned int useconds_t; + +/** + * Signed integral type large enough to hold any pointer + * + */ +typedef long int intptr_t; + + +/** + * Creates a child process. + * The new process will be nearly identical to the callee except for its + * PID and PPID. + * Resource utilizations are set to zero, file locks are not inherited. + * + */ +extern pid_t fork(); + +/** + * Terminates the calling process. Any open file descriptors belonging to the + * process are closed, any children of the process are inherited by process + * 1, init, and the process's parent is sent a SIGCHLD signal. + * The value status is returned to the parent process as the process's exit + * status and can be collected using a wait call. + * This function does NOT call any functions registered with atexit(), nor any + * registered signal handlers. + * + * @param status exit status of the process + * + */ +extern void _exit(int status); + +/** + * Creates a new hard link to an existing file. + * If new_path exists it will not be overwritten. + * + * @param old_path Path to file for linking + * @param new_path Path to the link to create + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int link(const char *old_path, const char *new_path); + +/** + * Deletes a name from the filesystem. + * If that name was the last link to a file and no processes have the file + * open the file is deleted. + * If a process has the file opened when the last link to it is deleted, the + * file will be deleted after the last file descriptor referring to it is + * closed. + * + * @param path the pathname to delete from the filesystem + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int unlink(const char *path); + +/** + * Deletes the given directory. + * The given directory must be empty. + * + * @param path the path to the directory to delete + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int rmdir(const char *path); + +/** + * Closes the given file descriptor, so that it no longer refers to any file + * and may be reused. + * Any locks held on the file it was associated with, and owned by the process, + * are removed. + * If file_descriptor is the last copy of a particular file descriptor the + * the resources associated with it are freed; if the descriptor was the last + * reference to a file which has been removed using unlink() the file is + * deleted. + * + * @param file_descriptor the file descriptor which should be closed + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int close(int file_descriptor); + +/** + * Creates a copy of the given file descriptor using the lowest-numbered + * unused descriptor. + * The copy shares locks, file position pointers and flags with the original + * file descriptor but not the close-on-exec flag. + * + * @param file_descriptor the descriptor to copy + * @return the new descriptor or -1 if an error occured (errno is as usually\ + set appropriately) + * + */ +extern int dup(int file_descriptor); + +/** + * Creates a copy of the given file descriptor using the given new descriptor + * and closing it first if necessary. + * The copy shares locks, file position pointers and flags with the original + * file descriptor but not the close-on-exec flag. + * + * @param old_file_descriptor the descriptor to copy + * @param new_file_descriptor the descriptor which should be the copy + * @return the new descriptor or -1 if an error occured (errno is as usually\ + set appropriately) + * + */ +extern int dup2(int old_file_descriptor, int new_file_descriptor); + +/** + * Creates a pipe. + * A pair of file descriptors pointing to a pipe inode is created and placed + * in an array pointed to by the given array parameter. + * The first element in the array is for reading and the second for writing. + * + * @param file_descriptor_array An array into which the two file descriptors\ + for the new pipe will be written + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +extern int pipe(int file_descriptor_array[2]); + +/** + * Repositions the read/write file offset to the given offset value according + * to the directive whence. + * + * Possible values for whence: + * - SEEK_SET Set offset to the given offset + * - SEEK_CUR Set offset to current position + given offset bytes + * - SEEK_END Set offset to the end-of-file position + given offset bytes + * + * If data is written after the end of the file, the data in the gap between + * the original end-of-file and the new data is returned as zero on reads. + * + * @param file_descriptor file descriptor referencing the file for operation + * @param offset the offset to set + * @param whence the directive how the offset will be set + * @return the resulting offset location as measured in bytes from the\ + beginning of the file, or (off_t)-1 if an error occurs (errno will be set in\ + this case) + * + */ +extern off_t lseek(int file_descriptor, off_t offset, int whence); + +/** + * Reads from a file descriptor. + * The provided buffer is filled with data from the given file. The count + * variable specifies the number of bytes to read. + * + * If the given file is capable of seeking, the read will start at the file + * position associated with the descriptor. This offset is incremented by + * the number of bytes actually read. + * + * @param file_descriptor file descriptor referencing the file to read + * @param buffer the buffer where the read data will be placed + * @param count the number of bytes to read + * @return the number of bytes read on success, 0 if count is zero or the \ + offset for reading is after the end-of-file, and -1 if an error occured + * + */ +extern ssize_t read(int file_descriptor, void *buffer, size_t count); + +/** + * Writes to a file descriptor. + * Up to count bytes from the provided buffer are written to the given file. + * + * If the given file is capable of seeking, the write will start at the file + * position associated with the descriptor. This offset is incremented by + * the number of bytes actually written. + * + * @param file_descriptor file descriptor referencing the file to write + * @param buffer the buffer where the write data will be placed + * @param count the number of bytes to write + * @param offset the absolute offset where the write operation starts + * @return the number of bytes written on success, 0 if count is zero or\ + nothing was written, and -1 if an error occured + * + */ +extern ssize_t write(int file_descriptor, const void *buffer, size_t count); + +extern int ftruncate(int fildes, off_t length); + +extern int brk(void *end_data_segment); + +extern void* sbrk(intptr_t increment); + +extern unsigned int sleep(unsigned int seconds); + +/** + * Replaces the current process image with a new one. + * The values provided with the argv array are the arguments for the new + * image starting with the filename of the file to be executed (by convention). + * This pointer array must be terminated by a NULL pointer (which has to be + * of type char *. + * If this function returns, an error has occured. + * + * @param path path to the file to execute + * @param argv an array containing the arguments + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int execv(const char *path __attribute__((unused)), char *const argv[] __attribute__((unused))); + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/include/wait.h b/pwn/flipper/dist/userspace/libc/include/wait.h new file mode 100644 index 0000000..0259803 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/include/wait.h @@ -0,0 +1,25 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEXITED 4 + +//pid typedefs +#ifndef PID_T_DEFINED +#define PID_T_DEFINED +typedef ssize_t pid_t; +#endif // PID_T_DEFINED + +extern pid_t waitpid(pid_t pid, int *status, int options); + + +#ifdef __cplusplus +} +#endif + + + diff --git a/pwn/flipper/dist/userspace/libc/src/CMakeLists.txt b/pwn/flipper/dist/userspace/libc/src/CMakeLists.txt new file mode 100644 index 0000000..07c5172 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/CMakeLists.txt @@ -0,0 +1,5 @@ +FILE(GLOB userspace_libc_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.c) + +target_sources(userspace_libc + PRIVATE + ${userspace_libc_SOURCES}) diff --git a/pwn/flipper/dist/userspace/libc/src/atoi.c b/pwn/flipper/dist/userspace/libc/src/atoi.c new file mode 100644 index 0000000..0f721c1 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/atoi.c @@ -0,0 +1,90 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "stdlib.h" + +/** + * parses the given string and returns its value as integer + * @param string the string for parsing + * @return the parsed value + * + */ +int atoi(const char *string) +{ + // taken from kprintf.cpp + int number = 0; + int base = 10; + int negative = 0; + + if(*string == '-') + { + negative = 1; + ++string; + } + else + if(*string == '+') + ++string; + + while(*string >= '0' && *string <= '9') + { + number *= base; + number += *string - '0'; + ++string; + } + + if(negative) + number *= -1; + + return number; +} + +/** + * parses the given string and returns its value as long + * @param string the string for parsing + * @return the parsed value + * + */ +long atol(const char *string) +{ + // taken from kprintf.cpp + long number = 0; + long base = 10; + int negative = 0; + + if(*string == '-') + { + negative = 1; + ++string; + } + else + if(*string == '+') + ++string; + + while(*string >= '0' && *string <= '9') + { + number *= base; + number += *string - '0'; + ++string; + } + + if(negative) + number *= -1; + + return number; +} diff --git a/pwn/flipper/dist/userspace/libc/src/ctype.c b/pwn/flipper/dist/userspace/libc/src/ctype.c new file mode 100644 index 0000000..8a60a5d --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/ctype.c @@ -0,0 +1,34 @@ +/* + * linux/lib/ctype.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include "ctype.h" + +unsigned char _ctype[] = { +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + diff --git a/pwn/flipper/dist/userspace/libc/src/exec.c b/pwn/flipper/dist/userspace/libc/src/exec.c new file mode 100644 index 0000000..7316ef7 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/exec.c @@ -0,0 +1,76 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "unistd.h" +#include "../../../common/include/kernel/syscall-definitions.h" +#include "sys/syscall.h" +#include "stdarg.h" +#include "stdlib.h" + +/** + * Creates a child process. + * The new process will be nearly identical to the callee except for its + * PID and PPID. + * Resource utilizations are set to zero, file locks are not inherited. + * + */ +pid_t fork() +{ + return __syscall(sc_fork, 0x00, 0x00, 0x00, 0x00, 0x00); +} + +/** + * Replaces the current process image with a new one. + * The values provided with the argv array are the arguments for the new + * image starting with the filename of the file to be executed (by convention). + * This pointer array must be terminated by a NULL pointer (which has to be + * of type char *. + * If this function returns, an error has occured. + * + * @param path path to the file to execute + * @param argv an array containing the arguments + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int execv(const char *path __attribute__((unused)), char *const argv[] __attribute__((unused))) +{ + + return 0; +} + +/** + * Terminates the calling process. Any open file descriptors belonging to the + * process are closed, any children of the process are inherited by process + * 1, init, and the process's parent is sent a SIGCHLD signal. + * The value status is returned to the parent process as the process's exit + * status and can be collected using a wait call. + * This function does NOT call any functions registered with atexit(), nor any + * registered signal handlers. + * + * @param status exit status of the process + * + */ +void _exit(int status) +{ + __syscall(sc_exit, status, 0x00, 0x00, 0x00, 0x00); +} +void exit(int status) +{ + __syscall(sc_exit, status, 0x00, 0x00, 0x00, 0x00); +} diff --git a/pwn/flipper/dist/userspace/libc/src/file_alloc.c b/pwn/flipper/dist/userspace/libc/src/file_alloc.c new file mode 100644 index 0000000..0479aac --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/file_alloc.c @@ -0,0 +1,179 @@ +#include "unistd.h" +#include "fcntl.h" +#include "stdarg.h" +#include "sys/syscall.h" +#include "../../../common/include/kernel/syscall-definitions.h" + + +/** + * Creates a new hard link to an existing file. + * If new_path exists it will not be overwritten. + * + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int link(const char *old_path, const char *new_path) +{ + return -1; +} + + +/** + * Deletes a name from the filesystem. + * If that name was the last link to a file and no processes have the file + * open the file is deleted. + * If a process has the file opened when the last link to it is deleted, the + * file will be deleted after the last file descriptor referring to it is + * closed. + * + * @param path the pathname to delete from the filesystem + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int unlink(const char *path) +{ + return -1; +} + + +/** + * Closes the given file descriptor, so that it no longer refers to any file + * and may be reused. + * Any locks held on the file it was associated with, and owned by the process, + * are removed. + * If file_descriptor is the last copy of a particular file descriptor the + * the resources associated with it are freed; if the descriptor was the last + * reference to a file which has been removed using unlink() the file is + * deleted. + * + * @param file_descriptor the file descriptor which should be closed + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int close(int file_descriptor) +{ + return __syscall(sc_close, file_descriptor, 0x00, 0x00, 0x00, 0x00); +} + + +/** + * Converts a pathname into a file descriptor which can be used in subsequent + * read and write operations. + * If successfull, the lowest file descriptor not currently open for the + * process will be returned. + * + * Possible values for the flags parameter are: + * - O_RDONLY Open for reading only + * - O_WRONLY Open for writing only + * - O_RDWR Open for reading and writing + * + * which can be bitwise combined (or'd) with: + * - O_APPEND Open in append mode + * - O_CREAT Create file if it does not exist + * - O_TRUNC Truncate file to 0 length if it already exists and is a + * regular file + * + * The mode argument specifies the permissions to use in case a new file is + * created. The effective permissions are (mode & ~umask). + * + * @param path A pathname pointing to the file to open + * @param flags Flags to specify how the file is opened + * @param mode Access permissions on file creation, ignored otherwise + * @return A valid file descriptor or -1 if an error occured + * + */ +int open(const char *path, int flags, ...) +{ + // taken from the uClibc open() + mode_t mode = 0; + + if(flags & O_CREAT) + { + va_list args; + + va_start(args, flags); + mode = va_arg(args, mode_t); + va_end(args); + } + + return __syscall(sc_open, (long) path, flags, mode, 0x00, 0x00); +} + +/** + * Equivalent to open() with flags equal to O_CREAT | O_WRONLY | O_TRUNC. + * + * @param path A pathname pointing to the file to open + * @param mode + * @return A valid file descriptor or -1 if an error occured + * + */ +int creat(const char *path, mode_t mode) +{ + return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode); +} + + +/** + * Creates a pipe. + * A pair of file descriptors pointing to a pipe inode is created and placed + * in an array pointed to by the given array parameter. + * The first element in the array is for reading and the second for writing. + * + * @param file_descriptor_array An array into which the two file descriptors\ + for the new pipe will be written + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int pipe(int file_descriptor_array[2]) +{ + return -1; +} + + +/** + * Creates a copy of the given file descriptor using the lowest-numbered + * unused descriptor. + * The copy shares locks, file position pointers and flags with the original + * file descriptor but not the close-on-exec flag. + * + * @param file_descriptor the descriptor to copy + * @return the new descriptor or -1 if an error occured (errno is as usually\ + set appropriately) + * + */ +int dup(int file_descriptor) +{ + return -1; +} + + +/** + * Creates a copy of the given file descriptor using the given new descriptor + * and closing it first if necessary. + * The copy shares locks, file position pointers and flags with the original + * file descriptor but not the close-on-exec flag. + * + * @param old_file_descriptor the descriptor to copy + * @param new_file_descriptor the descriptor which should be the copy + * @return the new descriptor or -1 if an error occured (errno is as usually\ + set appropriately) + * + */ +int dup2(int old_file_descriptor, int new_file_descriptor) +{ + return -1; +} + + +/** + * Renames a file, moving it between directories if required. + * + * @param old_path The old pathname + * @param new_path The new pathname + * @return 0 on success, -1 otherwise and errno is set appropriately + * + */ +int rename(const char *old_path, const char *new_path) +{ + return -1; +} diff --git a/pwn/flipper/dist/userspace/libc/src/mman.c b/pwn/flipper/dist/userspace/libc/src/mman.c new file mode 100644 index 0000000..6b17c54 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/mman.c @@ -0,0 +1,48 @@ +#include "sys/mman.h" + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +void* mmap(void* start, size_t length, int prot, int flags, int fd, + off_t offset) +{ + return 0; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int munmap(void* start, size_t length) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int shm_open(const char* name, int oflag, mode_t mode) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int shm_unlink(const char* name) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int mprotect(void *addr, size_t len, int prot) +{ + return -1; +} + diff --git a/pwn/flipper/dist/userspace/libc/src/nonstd.c b/pwn/flipper/dist/userspace/libc/src/nonstd.c new file mode 100644 index 0000000..043a246 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/nonstd.c @@ -0,0 +1,22 @@ +#include "nonstd.h" +#include "sys/syscall.h" +#include "../../../common/include/kernel/syscall-definitions.h" +#include "stdlib.h" + +int createprocess(const char* path, int sleep) +{ + return __syscall(sc_createprocess, (long) path, sleep, 0x00, 0x00, 0x00); +} + +int flipBit(const void* address, int bit_num) +{ + return __syscall(sc_flip_bit, (long) address, bit_num, 0, 0, 0); +} + + +extern int main(); + +void _start() +{ + exit(main()); +} diff --git a/pwn/flipper/dist/userspace/libc/src/printf.c b/pwn/flipper/dist/userspace/libc/src/printf.c new file mode 100644 index 0000000..4bfe097 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/printf.c @@ -0,0 +1,722 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "unistd.h" +#include "stdio.h" +#include "stdlib.h" +#include "stdarg.h" +#include "string.h" + +/** + * structure containing useful variables describing a string stored in a + * character array + * + */ +typedef struct c_string +{ + // start pointer + char *start; + + // working pointer + char *ptr; + + // length of the string + size_t length; + + // actual allocated size for the string + size_t size; + +} c_string; + +unsigned char const ZEROPAD = 1; /* pad with zero */ +unsigned char const SIGN = 2; /* unsigned/signed long */ +unsigned char const PLUS = 4; /* show plus */ +unsigned char const SPACE = 8; /* space if plus */ +unsigned char const LEFT = 16; /* left justified */ +unsigned char const SPECIAL = 32; /* 0x */ +unsigned char const LARGE = 64; /* use 'ABCDEF' instead of 'abcdef' */ +unsigned char const LONG = 128; /* sizeof(number) == sizeof(size_t) */ + +/** + * Resizes the string in the given c_string structure.. + * + * @param str structure containing information for the string to resize + * @param new_size the value for resizing the string + * + */ +#ifdef STATIC_MEMORY__ +void resizeString(c_string *str, unsigned int new_size) +{ + c_string old_string; + unsigned int copy_count = 0; + + old_string.start = str->start; + old_string.ptr = str->start; + old_string.size = str->size; + + str->size = new_size; + str->start = str->ptr = (char *) malloc(str->size * sizeof(char)); + + if(new_size > old_string.size) + new_size = old_string.size; + + for(; copy_count < new_size; ++copy_count) + *str->ptr++ = *old_string.ptr++; + + free(old_string.start); +} +#endif // STATIC_MEMORY__ + + +/** + * Writes a number of fill chars into a string + */ +void writeFillChars(c_string *output_string, int size, char fill ) +{ + while( size-- > 0 ) + { + *output_string->ptr++ = fill; + ++output_string->length; + } +} + +/** + * Writes a number into a string using the given parameters. + * + * @param output_string Structure containing information for the output string + * @param number The number for writing + * @param base The base of the number + * @param size The size (in digits) for output + * @param precision Precision for output + * @param type Output type + * + */ +void writeNumber(c_string *output_string, size_t number, + unsigned int base, unsigned int size, + unsigned int precision, unsigned char type) +{ + // code taken from kprintf's output_number() + char c; + char sign,tmp[70]; + const char *digits; + static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + unsigned int i; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + { + type &= ~ZEROPAD; + size = 0; //no padding then + } + if (base < 2 || base > 36) + return; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if ((type & LONG) && ((ssize_t)number) < 0) { + sign = '-'; + number = - (ssize_t) number; + } else if (!(type & LONG) && ((int)number) < 0) { + sign = '-'; + number = - (int) number; + } else if (type & PLUS) { + sign = '+'; + } else if (type & SPACE) { + sign = ' '; + } + } + i = 0; + if (number == 0) + tmp[i++]='0'; + else while (number != 0) + { + tmp[i++] = digits[number%base]; + number /= base; + } + //size -= precision; + //~ if (!(type&(ZEROPAD+LEFT))) { + //~ while(size-- >0) { + //~ console->write(' '); + //~ } + //~ } + if (sign) { + tmp[i++] = sign; + } + if (type & SPECIAL) { + precision = 0; //no precision with special for now + if (base==8) { + tmp[i++] = '0'; + } else if (base==16) { + tmp[i++] = digits[33]; + tmp[i++] = '0'; + } + } + + if (precision > size) + precision = size; + + while (size-- - precision > i) + { + *output_string->ptr++ = c; + ++output_string->length; + } + + while (precision-- > i) + { + *output_string->ptr++ = '0'; + ++output_string->length; + } + + while (i-- > 0) + { + *output_string->ptr++ = tmp[i]; + ++output_string->length; + } + + + //~ while (size-- > 0) { + //~ if (buf <= end) + //~ *buf = ' '; + //~ ++buf; + //~ } +} + +/** + * Calculates the integer logarithm of base 10. + * + * @param n Value of which the logarithm should be calculated + * + */ +int _log10(double n) +{ + int log = 0; + while(n >= 10) + { + n /= 10.0; + log++; + } + return log; +} + +/** + * Calculates 10.0^x for integer x. + * + * @param p Exponent, can be positive and negative + * + */ +double _pow10(int p) +{ + double res = 1; + while(p > 0) + { + res *= 10.0; + p--; + } + while(p < 0) + { + res /= 10.0; + p++; + } + return res; +} + +/** + * Writes a floating point number into a string using the given precision. + * Based on http://stackoverflow.com/a/7097567/5259559 + * + * @param s Structure containing information for the output string + * @param n The floating point number for writing + * @param precision Precision for output + * + */ +void writeFloat(c_string *output_string, double n, unsigned int width, unsigned int prec, unsigned char flags) +{ + c_string s; + int character_count = 70; + s.size = character_count; + char buffer[character_count]; + s.start = (char *) &buffer; + s.ptr = s.start; + s.length = 0; + double precision = _pow10(-prec); + + // special cases + if (__builtin_isnan(n)) + { + if(flags & LARGE) + { + *s.ptr++ = 'N'; *s.ptr++ = 'A'; *s.ptr++ = 'N'; + } else { + *s.ptr++ = 'n'; *s.ptr++ = 'a'; *s.ptr++ = 'n'; + } + s.length += 3; + } + else if (__builtin_isinf(n)) + { + if(flags & LARGE) + { + *s.ptr++ = 'I'; *s.ptr++ = 'N'; *s.ptr++ = 'F'; + } else { + *s.ptr++ = 'i'; *s.ptr++ = 'n'; *s.ptr++ = 'f'; + } + s.length += 3; + } + else if (n == 0.0) + { + *(s.ptr++) = '0'; + s.length++; + } + else + { + int digit, m, m1; + int neg = (n < 0); + if (neg) + n = -n; + // calculate magnitude + m = _log10(n); + int useExp = (m >= 14 || (neg && m >= 9) || m <= -9); + if (neg) + { + *(s.ptr++) = '-'; + s.length++; + } + // set up for scientific notation + if (useExp) + { + if (m < 0) + m -= 1.0; + n = n / _pow10(m); + m1 = m; + m = 0; + } + if (m < 1.0) + { + m = 0; + } + // convert the number + while (n > precision || m >= 0) + { + double weight = _pow10(m); + if (weight > 0 && !__builtin_isinf(weight)) + { + digit = (int)(n / weight); + n -= (digit * weight); + *(s.ptr++) = '0' + digit; + s.length++; + } + if (m == 0 && n > 0) + { + *(s.ptr++) = '.'; + s.length++; + } + m--; + } + if (useExp) + { + // convert the exponent + int i, j; + *(s.ptr++) = 'e'; + s.length++; + if (m1 > 0) + { + *(s.ptr++) = '+'; + s.length++; + } + else + { + *(s.ptr++) = '-'; + s.length++; + m1 = -m1; + } + m = 0; + while (m1 > 0) + { + *(s.ptr++) = '0' + m1 % 10; + s.length++; + m1 /= 10; + m++; + } + s.ptr -= m; + char tmp; + for (i = 0, j = m-1; i s.length) { + for(i = 0; i < width - s.length; i++) { + if(flags & ZEROPAD) *output_string->ptr++ = '0'; + else *output_string->ptr++ = ' '; + output_string->length++; + } + } + for(i = 0; i < s.length; i++) { + *output_string->ptr++ = *start++; + } + output_string->length += s.length; + +} + +/** + * Writes output to stdout. + * A detailed description of the format is given in the + * 'Linux Programmer's Manual'. + * + * @param format A string containing the output format, followed by an\ + argument list containing different variables for output + * @return The number of characters printed or the number of characters that\ + would have been printed if the output was truncated, a negative\ + value is returned on failure + * + */ +extern int printf(const char *format, ...) +{ +// no dynamic memory allocation available yet +#define STATIC_MEMORY__ + + c_string output_string; + int character_count = 256; + output_string.size = character_count; + +#ifdef STATIC_MEMORY__ + char buffer[character_count]; + + output_string.start = (char *) &buffer; +#else + output_string.start = (char *) malloc(output_string.size * sizeof(char)); +#endif // STATIC_MEMORY__ + + output_string.ptr = output_string.start; + output_string.length = 0; + + + va_list args; + + va_start(args, format); + + // format handling taken from vkprintf + while (format && *format) + { + if(!character_count) + { +#ifdef STATIC_MEMORY__ + break; +#else + // resize output string if necessary + character_count = output_string.size; + resizeString(&output_string, output_string.size * 2); +#endif // STATIC_MEMORY__ + } + + if (*format == '%') + { + int width = 0; + int precision = 14; + unsigned char flag = 0; + ++format; + while (1) + { + switch (*format) // prefix specifiers (there might be multiple) + { + case '-': + flag |= LEFT; + ++format; + continue; + case '+': + flag |= PLUS; + ++format; + continue; + case '0': + flag |= ZEROPAD; + ++format; + continue; + case 'z': + case 'l': + flag |= LONG; + ++format; + continue; + default: + break; + } + if (width) + break; // only look for width specifier if we didn't have one yet + + size_t c = 0; + char num[4]; + for(; *format >= (c ? '0' : '1') && *format <= '9'; ++format, ++c) + if( c < 4 ) + num[c] = *format; + num[c < 4 ? c : 3] = 0; + if( c ) + { + width = atoi(num); + +#ifdef STATIC_MEMORY__ + if(character_count < width) + width = character_count; +#else + while(character_count < width) + { + character_count = output_string.size; + resizeString(&output_string, output_string.size * 2); + } +#endif // STATIC_MEMORY__ + + continue; // there might be another prefix character after this... + } + + break; // prefix is done + } + + if(*format == '.') { + ++format; + char num[4]; + size_t c = 0; + for(; *format >= (c ? '0' : '1') && *format <= '9'; ++format, ++c) + if( c < 4 ) + num[c] = *format; + num[c < 4 ? c : 3] = 0; + if( c ) + { + precision = atoi(num); + } + } + + //handle diouxXfeEgGcs + switch (*format) + { + case '%': + *output_string.ptr++ = *format; + + --character_count; + ++output_string.length; + break; + + case 's': + { + char const *string_arg = va_arg(args, char const*); + int len = strlen(string_arg); + + // we should align right -> fill with spaces + if( !(flag & LEFT) && (len < width) ) + { + character_count -= width - len; + if( character_count < 0 ) + { +#ifdef STATIC_MEMORY__ + break; +#else + // resize output string if necessary + character_count = output_string.size; + resizeString(&output_string, output_string.size * 2); +#endif // STATIC_MEMORY__ + } + + writeFillChars(&output_string, width - len, ' '); + } + + // now print the string + while(string_arg && *string_arg) + { + if(!character_count) + { +#ifdef STATIC_MEMORY__ + break; +#else + // resize output string if necessary + character_count = output_string.size; + resizeString(&output_string, output_string.size * 2); +#endif // STATIC_MEMORY__ + } + + + *output_string.ptr++ = *string_arg++; + --character_count; + ++output_string.length; + } + + // and some fillchars if aligned on the left + if( flag & LEFT && len < width ) + { + character_count -= width - len; + if( character_count < 0 ) + { +#ifdef STATIC_MEMORY__ + break; +#else + // resize output string if necessary + character_count = output_string.size; + resizeString(&output_string, output_string.size * 2); +#endif // STATIC_MEMORY__ + } + + writeFillChars(&output_string, width - len, ' '); + } + + break; + } + + //signed decimal + case 'd': + writeNumber(&output_string,(size_t) va_arg(args,size_t),10,width, 0, flag | SIGN); + break; + + //we don't do i until I see what it actually should do + //case 'i': + // break; + + //octal + case 'o': + writeNumber(&output_string,(size_t) va_arg(args,size_t),8,width, 0, flag | SPECIAL); + break; + + //unsigned + case 'u': + writeNumber(&output_string,(size_t) va_arg(args,size_t),10,width, 0, flag ); + break; + + case 'p': + case 'x': + writeNumber(&output_string,(size_t) va_arg(args,size_t),16,width, 0, flag | SPECIAL); + break; + + case 'X': + writeNumber(&output_string,(size_t) va_arg(args,size_t), 16, width, 0, flag | SPECIAL | LARGE); + break; + + //float + case 'f': + writeFloat(&output_string,(double) va_arg(args,double), width, precision, flag); + break; + + case 'F': + writeFloat(&output_string,(double) va_arg(args,double), width, precision, flag | LARGE); + break; + + //no scientific notation (yet) + //case 'e': + // break; + + //case 'E': + // break; + + //no floating point yet + //case 'g': + // break; + + //case 'G': + // break; + + //we don't do unicode (yet) + case 'c': + *output_string.ptr++ = (char) va_arg(args,unsigned int); + ++output_string.length; + break; + + default: + //jump over unknown arg + //++args; + *output_string.ptr++ = '%'; + ++output_string.length; + break; + } + + } + else + { + *output_string.ptr++ = *format; + --character_count; + ++output_string.length; + } + + ++format; + } + + va_end(args); + + character_count = write(STDOUT_FILENO, + (void*) output_string.start, output_string.length); + +#ifndef STATIC_MEMORY__ + free(output_string.start); +#endif // STATIC_MEMORY__ + + return (int) character_count; +} + + +/** + * Writes the given character to stdout. + * The character is casted to unsigned char. + * + * @param character The character for writing + * @return The character written as unsigned char cast to int or EOF on error + * + */ +int putchar(int character) +{ + unsigned char output_char = (unsigned char) character; + int characters_written = write(STDOUT_FILENO, (void*) &output_char, 1); + + if(!characters_written || (characters_written == -1)) + return EOF; + + return (int) output_char; +} + +/** + * Writes the given string followed by a newline to stdout. + * + * @param output_string The string for writing + * @return A non-negative number on success or EOF on error + * + */ +int puts(const char *output_string) +{ + unsigned char newline = '\n'; + const char *string_ptr = output_string; + size_t string_length = 0; + int characters_written = 0; + + while(string_ptr && *string_ptr++) + ++string_length; + + if(string_length) + { + characters_written = write(STDOUT_FILENO, (void*) output_string, string_length); + if(!characters_written || (characters_written == -1)) + return EOF; + } + + characters_written = write(STDOUT_FILENO, (void*) &newline, 1); + + if(!characters_written || (characters_written == -1)) + return EOF; + + return 0; +} + diff --git a/pwn/flipper/dist/userspace/libc/src/pthread.c b/pwn/flipper/dist/userspace/libc/src/pthread.c new file mode 100644 index 0000000..ded6eee --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/pthread.c @@ -0,0 +1,191 @@ +#include "pthread.h" + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +void pthread_exit(void *value_ptr) +{ +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cancel(pthread_t thread) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_join(pthread_t thread, void **value_ptr) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_detach(pthread_t thread) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_mutex_lock(pthread_mutex_t *mutex) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cond_destroy(pthread_cond_t *cond) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cond_signal(pthread_cond_t *cond) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cond_broadcast(pthread_cond_t *cond) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_spin_destroy(pthread_spinlock_t *lock) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_spin_init(pthread_spinlock_t *lock, int pshared) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_spin_lock(pthread_spinlock_t *lock) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_spin_trylock(pthread_spinlock_t *lock) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_spin_unlock(pthread_spinlock_t *lock) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_setcancelstate(int state, int *oldstate) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int pthread_setcanceltype(int type, int *oldtype) +{ + return -1; +} + diff --git a/pwn/flipper/dist/userspace/libc/src/read.c b/pwn/flipper/dist/userspace/libc/src/read.c new file mode 100644 index 0000000..c8c4f27 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/read.c @@ -0,0 +1,70 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "unistd.h" +#include "sys/syscall.h" +#include "../../../common/include/kernel/syscall-definitions.h" + +/** + * Repositions the read/write file offset to the given offset value according + * to the directive whence. + * + * Possible values for whence: + * - SEEK_SET Set offset to the given offset + * - SEEK_CUR Set offset to current position + given offset bytes + * - SEEK_END Set offset to the end-of-file position + given offset bytes + * + * If data is written after the end of the file, the data in the gap between + * the original end-of-file and the new data is returned as zero on reads. + * + * @param file_descriptor file descriptor referencing the file for operation + * @param offset the offset to set + * @param whence the directive how the offset will be set + * @return the resulting offset location as measured in bytes from the\ + beginning of the file, or (off_t)-1 if an error occurs (errno will be set in\ + this case) + * + */ +off_t lseek(int file_descriptor, off_t offset, int whence) +{ + return __syscall(sc_lseek, file_descriptor, offset, whence, 0x00, 0x00); +} + +/** + * Reads from a file descriptor. + * The provided buffer is filled with data from the given file. The count + * variable specifies the number of bytes to read. + * + * If the given file is capable of seeking, the read will start at the file + * position associated with the descriptor. This offset is incremented by + * the number of bytes actually read. + * + * @param file_descriptor file descriptor referencing the file to read + * @param buffer the buffer where the read data will be placed + * @param count the number of bytes to read + * @return the number of bytes read on success, 0 if count is zero or the \ + offset for reading is after the end-of-file, and -1 if an error occured + * + */ +ssize_t read(int file_descriptor, void *buffer, size_t count) +{ + return __syscall(sc_read, file_descriptor, (long) buffer, count, 0x00, 0x00); +} + + diff --git a/pwn/flipper/dist/userspace/libc/src/scanf.c b/pwn/flipper/dist/userspace/libc/src/scanf.c new file mode 100644 index 0000000..4be2a5a --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/scanf.c @@ -0,0 +1,531 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "unistd.h" +#include "stdio.h" +#include "stdlib.h" +#include "stdarg.h" +#include "ctype.h" + + +#define unlikely(arg) arg + +// The following functions defined before scanf are taken from the linux +// kernel (v.2.6.13) file lib/vsprintf.c + +/** + * Maximum integer value + * + */ +#define INT_MAX ((int)(~0U>>1)) + + +/** + * simple_strtoul - convert a string to an unsigned long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } else if (base == 16) { + if (cp[0] == '0' && toupper(cp[1]) == 'X') + cp += 2; + } + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + + +/** + * simple_strtol - convert a string to a signed long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + + +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) +{ + unsigned long long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } else if (base == 16) { + if (cp[0] == '0' && toupper(cp[1]) == 'X') + cp += 2; + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + + +/** + * simple_strtoll - convert a string to a signed long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long long simple_strtoll(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoull(cp+1,endp,base); + return simple_strtoull(cp,endp,base); +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + + +/** + * vsscanf - Unformat a buffer into a list of arguments + * @buf: input buffer + * @fmt: format of buffer + * @args: arguments + */ +int vsscanf(const char * buf, const char * fmt, va_list args) +{ + const char *str = buf; + char *next; + char digit; + int num = 0; + int qualifier; + int base; + int field_width; + int is_sign = 0; + + while(*fmt && *str) { + /* skip any white space in format */ + /* white space in format matchs any amount of + * white space, including none, in the input. + */ + if (isspace(*fmt)) { + while (isspace(*fmt)) + ++fmt; + while (isspace(*str)) + ++str; + } + + /* anything that is not a conversion must match exactly */ + if (*fmt != '%' && *fmt) { + if (*fmt++ != *str++) + break; + continue; + } + + if (!*fmt) + break; + ++fmt; + + /* skip this conversion. + * advance both strings to next white space + */ + if (*fmt == '*') { + while (!isspace(*fmt) && *fmt) + fmt++; + while (!isspace(*str) && *str) + str++; + continue; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + + /* get conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt == 'Z' || *fmt == 'z') { + qualifier = *fmt++; + if (unlikely(qualifier == *fmt)) { + if (qualifier == 'h') { + qualifier = 'H'; + fmt++; + } else if (qualifier == 'l') { + qualifier = 'L'; + fmt++; + } + } + } + base = 10; + is_sign = 0; + + if (!*fmt || !*str) + break; + + switch(*fmt++) { + case 'c': + { + char *s = (char *) va_arg(args,char*); + if (field_width == -1) + field_width = 1; + do { + *s++ = *str++; + } while (--field_width > 0 && *str); + num++; + } + continue; + case 's': + { + char *s = (char *) va_arg(args, char *); + if(field_width == -1) + field_width = INT_MAX; + /* first, skip leading white space in buffer */ + while (isspace(*str)) + str++; + + /* now copy until next white space */ + while (*str && !isspace(*str) && field_width--) { + *s++ = *str++; + } + *s = '\0'; + num++; + } + continue; + case 'n': + /* return number of characters read so far */ + { + int *i = (int *)va_arg(args,int*); + *i = str - buf; + } + continue; + case 'o': + base = 8; + break; + case 'x': + case 'X': + base = 16; + break; + case 'i': + base = 0; + // fall through + case 'd': + is_sign = 1; + case 'u': + break; + case '%': + /* looking for '%' in str */ + if (*str++ != '%') + return num; + continue; + default: + /* invalid format; stop here */ + return num; + } + + /* have some sort of integer conversion. + * first, skip white space in buffer. + */ + while (isspace(*str)) + str++; + + digit = *str; + if (is_sign && digit == '-') + digit = *(str + 1); + + if (!digit + || (base == 16 && !isxdigit(digit)) + || (base == 10 && !isdigit(digit)) + || (base == 8 && (!isdigit(digit) || digit > '7')) + || (base == 0 && !isdigit(digit))) + break; + + switch(qualifier) { + case 'H': /* that's 'hh' in format */ + if (is_sign) { + signed char *s = (signed char *) va_arg(args,signed char *); + *s = (signed char) simple_strtol(str,&next,base); + } else { + unsigned char *s = (unsigned char *) va_arg(args, unsigned char *); + *s = (unsigned char) simple_strtoul(str, &next, base); + } + break; + case 'h': + if (is_sign) { + short *s = (short *) va_arg(args,short *); + *s = (short) simple_strtol(str,&next,base); + } else { + unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); + *s = (unsigned short) simple_strtoul(str, &next, base); + } + break; + case 'l': + if (is_sign) { + long *l = (long *) va_arg(args,long *); + *l = simple_strtol(str,&next,base); + } else { + unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); + *l = simple_strtoul(str,&next,base); + } + break; + case 'L': + if (is_sign) { + long long *l = (long long*) va_arg(args,long long *); + *l = simple_strtoll(str,&next,base); + } else { + unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); + *l = simple_strtoull(str,&next,base); + } + break; + case 'Z': + case 'z': + { + size_t *s = (size_t*) va_arg(args,size_t*); + *s = (size_t) simple_strtoul(str,&next,base); + } + break; + default: + if (is_sign) { + int *i = (int *) va_arg(args, int*); + *i = (int) simple_strtol(str,&next,base); + } else { + unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); + *i = (unsigned int) simple_strtoul(str,&next,base); + } + break; + } + num++; + + if (!next) + break; + str = next; + } + return num; +} + + +/** + * Size of the static input buffer for scanf + * + */ +#define INPUT_BUFFER_SIZE 256 + +/** + * Reads input from stdin according to the given format and + * assigns read values to the given variables. + * A detailed description of the format is given in the + * 'Linux Programmer's Manual'. + * + * @param format A string containing the input format, followed by an\ + argument list of variables for assignment + * @return The number of input items assigned, zero indicates that no input\ + items were assigned while input was available, EOF if failure (e.g.\ + end-of-file) occurs before any items have been read + * + */ +int scanf(const char *fmt, ...) +{ + va_list args; + int return_val = 0; + + char input_buffer_array[INPUT_BUFFER_SIZE]; + char *buffer = (char*) &input_buffer_array; + + if(gets(buffer, INPUT_BUFFER_SIZE) == NULL) + return return_val; + + va_start(args, fmt); + + return_val = vsscanf(buffer, fmt, args); + + va_end(args); + + return return_val; +} + + +int sscanf(const char *buffer, const char *fmt, ...) +{ + va_list args; + int return_val = 0; + + va_start(args, fmt); + + return_val = vsscanf(buffer, fmt, args); + + va_end(args); + + return return_val; +} + + +/** + * Reads the next character from stdin. + * The read value will be returned as unsigned char cast to an int + * + * @return The read character on success, EOF otherwise and errno is set\ + appropriately + * + */ +int getchar() +{ + char character = 0; + int characters_read = read(STDIN_FILENO, (void*) &character, 1); + + if(!characters_read || (characters_read == -1)) + return EOF; + + return (int) character; +} + +/** + * Reads a line from stdin and stores it in the string pointed to by the + * argument. + * Reading is terminated by a newline, EOF which are both replaced by '\0' or + * when the buffer is full. + * + * @param input_buffer The buffer where the input is stored + * @param buffer_size The size of the buffer + * @return A pointer to the input_string on success, NULL otherwise + * + */ +char *gets(char *input_buffer, size_t buffer_size) +{ + unsigned int counter = 0; + if (!buffer_size) + return input_buffer; + + int cchar = 0; + + while((cchar = getchar()) != EOF) + { + + if(cchar == '\r' || cchar == '\n' || (counter + 1) >= buffer_size) // there must be one space left for the \0 at end + { + *(input_buffer + counter) = '\0'; + break; + } + else + { + *(input_buffer + counter) = (char)cchar; + } + + if (cchar == '\b') + { + if (counter > 0) + counter--; + } + else + { + counter++; + } + + } + + return input_buffer; +} + + +char *fgets(char *str, int num, int fd) +{ + unsigned int counter = 0; + ssize_t readCount = 0; + char buffer[128]; + off_t oldOffset = lseek(fd, 0, SEEK_CUR); + + if (!num) + return str; + + do + { + readCount = read(fd, buffer, 128); + for (ssize_t i = 0; i < readCount; i++) + { + if (buffer[i] == '\r' || buffer[i] == '\n' || (counter+1) >= num) + { + *(str + counter) = '\0'; + lseek(fd, oldOffset+counter+1, SEEK_SET); + return str; + } + else + { + *(str + counter) = buffer[i]; + } + + if (buffer[i] == '\b') + { + if (counter > 0) + counter--; + } + else + { + counter++; + } + } + } while (readCount > 0); + + if (num - counter) + str[counter] = '\0'; + + if (counter == 0) + return 0; + + return str; +} diff --git a/pwn/flipper/dist/userspace/libc/src/sched.c b/pwn/flipper/dist/userspace/libc/src/sched.c new file mode 100644 index 0000000..b7f14f5 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/sched.c @@ -0,0 +1,12 @@ +#include "sched.h" +#include "sys/syscall.h" +#include "../../../common/include/kernel/syscall-definitions.h" + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sched_yield(void) +{ + return __syscall(sc_sched_yield, 0x00, 0x00, 0x00, 0x00, 0x00); +} diff --git a/pwn/flipper/dist/userspace/libc/src/semaphore.c b/pwn/flipper/dist/userspace/libc/src/semaphore.c new file mode 100644 index 0000000..71ba1d1 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/semaphore.c @@ -0,0 +1,49 @@ +#include "semaphore.h" + + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sem_wait(sem_t *sem) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sem_trywait(sem_t *sem) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sem_init(sem_t *sem, int pshared, unsigned value) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sem_destroy(sem_t *sem) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int sem_post(sem_t *sem) +{ + return -1; +} + + diff --git a/pwn/flipper/dist/userspace/libc/src/stdlib.c b/pwn/flipper/dist/userspace/libc/src/stdlib.c new file mode 100644 index 0000000..5f07407 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/stdlib.c @@ -0,0 +1,25 @@ +#include "stdlib.h" + +void *malloc(size_t size) +{ + return 0; +} + +void free(void *ptr) +{ +} + +int atexit(void (*function)(void)) +{ + return -1; +} + +void *calloc(size_t nmemb, size_t size) +{ + return 0; +} + +void *realloc(void *ptr, size_t size) +{ + return 0; +} diff --git a/pwn/flipper/dist/userspace/libc/src/string.c b/pwn/flipper/dist/userspace/libc/src/string.c new file mode 100644 index 0000000..b69bbbe --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/string.c @@ -0,0 +1,150 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "string.h" + +/** + * Compares the given number of bytes of the memory areas started by the + * given pointers. + * The return value will be an integer less than zero, if the bytes at the + * first area are less than those of the second. It will be zero for equality, + * and a value greater zero if the bytes at the first area are greater than + * those of the second + * + * @param first_position Position of the first memory area + * @param second_position Position of the second memory area + * @param number_of_bytes Number of bytes to compare + * @return An integer indicating the found differences + * + */ +int memcmp(const void *first_position, const void *second_position, + size_t number_of_bytes) +{ + const char *b1 = first_position; + const char *b2 = second_position; + + if(number_of_bytes == 0) + return 0; + + while(number_of_bytes--) + { + if(*b1++ != *b2++) + return (*--b1 - *--b2); + } + + return 0; +} + +/** + * Copies the given number of bytes from memory area source to memory area + * destination. The memory areas should not overlap. + * + * @param destination Destination memory position + * @param source Source memory position + * @param number_of_bytes Number of bytes to copy + * @return A pointer to the destination + * + */ +void* memcpy(void *destination, const void *source, size_t number_of_bytes) +{ + char *byte_destination = (char*) destination; + const char *byte_source = (const char*) source; + + // The areas must not overlap! + if(((byte_source < (byte_destination + number_of_bytes)) && + (byte_source > byte_destination)) || + ((byte_destination < (byte_source + number_of_bytes)) && + (byte_destination > byte_source))) + return destination; + + if(number_of_bytes == 0 || source == destination) + return destination; + + while(number_of_bytes--) + *byte_destination++ = *byte_source++; + + return destination; +} + +/** + * Fills the given number of bytes of the memory area pointed to by the given + * position with the given value. + * + * @param position Position of the memory area + * @param value Value to write + * @param number_of_bytes Number of bytes to write + * @return A pointer to the memory area + * + */ +void *memset(void *position, int value, size_t number_of_bytes) +{ + char *byte_block = (char *) position; + + if(number_of_bytes) + { + while(number_of_bytes--) + *byte_block++ = (char) value; + } + + return position; +} + +/** + * Gets the length of the null terminated string + * + * @param str String + * @return length of String + */ +size_t strlen(const char* str) +{ + size_t count=0; + while(str[count] != '\0') + count++; + return count; +} + +/** + * Compares the 2 Strings, default implementation + */ +int strcmp (const char * l, const char * r) +{ + + for(; *l == *r; ++l, ++r) + if(*l == 0) + return 0; + return *(unsigned char *)l < *(unsigned char *)r ? -1 : 1; +} + + +char *strstr(const char *haystack, const char *needle) +{ + if(*needle == '\0') + return (char*)haystack; + + for(int i = 0; haystack[i] != '\0'; i++) + { + int j; + for(j = 0; needle[j] != '\0' && haystack[i + j] == needle[j]; j++) + ; + if(needle[j] == '\0') + return (char*)(haystack + i); + } + + return NULL; +} \ No newline at end of file diff --git a/pwn/flipper/dist/userspace/libc/src/time.c b/pwn/flipper/dist/userspace/libc/src/time.c new file mode 100644 index 0000000..ddca93d --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/time.c @@ -0,0 +1,11 @@ +#include "time.h" + + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +clock_t clock(void) +{ + return (clock_t) -1U; +} diff --git a/pwn/flipper/dist/userspace/libc/src/unistd.c b/pwn/flipper/dist/userspace/libc/src/unistd.c new file mode 100644 index 0000000..7467120 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/unistd.c @@ -0,0 +1,40 @@ +#include "unistd.h" + + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int brk(void *end_data_segment) +{ + return -1; +} + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +void* sbrk(intptr_t increment) +{ + return (void*) -1; +} + + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +unsigned int sleep(unsigned int seconds) +{ + return -1U; +} + + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +int ftruncate(int fildes, off_t length) +{ + return -1; +} diff --git a/pwn/flipper/dist/userspace/libc/src/wait.c b/pwn/flipper/dist/userspace/libc/src/wait.c new file mode 100644 index 0000000..db2cb8e --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/wait.c @@ -0,0 +1,12 @@ +#include "wait.h" + +/** + * function stub + * posix compatible signature - do not change the signature! + */ +pid_t waitpid(pid_t pid, int *status, int options) +{ + return -1; +} + + diff --git a/pwn/flipper/dist/userspace/libc/src/write.c b/pwn/flipper/dist/userspace/libc/src/write.c new file mode 100644 index 0000000..28f1ed4 --- /dev/null +++ b/pwn/flipper/dist/userspace/libc/src/write.c @@ -0,0 +1,44 @@ +// Projectname: SWEB +// Simple operating system for educational purposes +// +// Copyright (C) 2005 Andreas Niederl +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "unistd.h" +#include "sys/syscall.h" +#include "../../../common/include/kernel/syscall-definitions.h" + +/** + * Writes to a file descriptor. + * Up to count bytes from the provided buffer are written to the given file. + * + * If the given file is capable of seeking, the write will start at the file + * position associated with the descriptor. This offset is incremented by + * the number of bytes actually written. + * + * @param file_descriptor file descriptor referencing the file to write + * @param buffer the buffer where the write data will be placed + * @param count the number of bytes to write + * @param offset the absolute offset where the write operation starts + * @return the number of bytes written on success, 0 if count is zero or\ + nothing was written, and -1 if an error occured + * + */ +ssize_t write(int file_descriptor, const void *buffer, size_t count) +{ + return __syscall(sc_write, file_descriptor, (long) buffer, count, 0x00, + 0x00); +} diff --git a/pwn/flipper/dist/userspace/tests/CMakeLists.txt b/pwn/flipper/dist/userspace/tests/CMakeLists.txt new file mode 100644 index 0000000..9df0d6d --- /dev/null +++ b/pwn/flipper/dist/userspace/tests/CMakeLists.txt @@ -0,0 +1,48 @@ +project(userspace_tests) +include(../../arch/${ARCH}/CMakeLists.userspace) + +# Put userspace libraries and executables in seperated paths +set(LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH}/userspace") +set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/userspace") + +# Reset userspace program names +set($ENV{USERSPACE_NAMES} "") + +set(USERSPACE_TESTS_COMPILE_OPTIONS) +set(USERSPACE_TESTS_LINKER_OPTIONS -Wl,-Ttext=0x8000000 -Wl,--build-id=none -Wl,-whole-archive) + +set(FINAL_USERSPACE_TESTS_COMPILE_OPTIONS ${ARCH_USERSPACE_COMPILE_OPTIONS} ${USERSPACE_TESTS_COMPILE_OPTIONS}) +set(FINAL_USERSPACE_TESTS_LINKER_OPTIONS ${ARCH_LD_ARGUMENTS} ${ARCH_USERSPACE_LINKER_OPTIONS} ${USERSPACE_TESTS_LINKER_OPTIONS}) + +file(GLOB userspace_tests_SOURCES ${SOURCE_WILDCARDS}) + +# Create own executable for every .c file and link with libc +foreach(curFile ${userspace_tests_SOURCES}) + get_filename_component(curName ${curFile} NAME_WE) + + add_executable(${curName}.sweb ${curFile}) + target_link_libraries(${curName}.sweb ${FINAL_USERSPACE_TESTS_LINKER_OPTIONS} userspace_libc ${ARCH_APPEND_LD_ARGUMENTS}) + + ADD_DEBUG_INFO(${curName}.sweb) + + # Remember the userspace program names for dependency checking in the root CMakeLists + set(ENV{USERSPACE_NAMES} "$ENV{USERSPACE_NAMES};${curName}.sweb") + set(ENV{USERSPACE_NAMES_EXE2MINIX} "$ENV{USERSPACE_NAMES_EXE2MINIX};${EXECUTABLE_OUTPUT_PATH}/${curName}.sweb;${curName}.sweb") +endforeach(curFile) + +file(GLOB userspace_tests_PROJECTS */) + +foreach(curProject ${userspace_tests_PROJECTS}) +file(GLOB curProject_SOURCES ${curProject}/*.c) + + if(curProject_SOURCES) + get_filename_component(exename ${curProject} NAME) + add_executable(${exename}.sweb ${curProject_SOURCES}) + target_link_libraries(${exename}.sweb ${FINAL_USERSPACE_TESTS_LINKER_OPTIONS} "-Wl,-whole-archive" userspace_libc ${ARCH_APPEND_LD_ARGUMENTS}) + + ADD_DEBUG_INFO(${curName}.sweb) + + set(ENV{USERSPACE_NAMES} "$ENV{USERSPACE_NAMES};${exename}.sweb") + set(ENV{USERSPACE_NAMES_EXE2MINIX} "$ENV{USERSPACE_NAMES_EXE2MINIX};${EXECUTABLE_OUTPUT_PATH}/${exename}.sweb;${exename}.sweb") + endif(curProject_SOURCES) +endforeach(curProject) diff --git a/pwn/flipper/dist/userspace/tests/exploit.c b/pwn/flipper/dist/userspace/tests/exploit.c new file mode 100644 index 0000000..ac130e4 --- /dev/null +++ b/pwn/flipper/dist/userspace/tests/exploit.c @@ -0,0 +1,9 @@ +#include "stdio.h" +#include "nonstd.h" +#include "sched.h" + +int main(int argc, char** argv) +{ + // On the server, only this file will be executed. + printf("Your exploit here\n"); +} \ No newline at end of file diff --git a/pwn/flipper/dist/userspace/tests/mult.c b/pwn/flipper/dist/userspace/tests/mult.c new file mode 100644 index 0000000..9bcf19e --- /dev/null +++ b/pwn/flipper/dist/userspace/tests/mult.c @@ -0,0 +1,54 @@ +#include "../../common/include/kernel/syscall-definitions.h" + + +/* the result should be 1237619379 for size of 100 */ +#define ARRAY_SIZE 100 +#define POS(x,y) (x*ARRAY_SIZE+y) + +typedef unsigned int uint32; + + +uint32 axa[ARRAY_SIZE][ARRAY_SIZE]; +uint32 bxb[ARRAY_SIZE][ARRAY_SIZE]; +uint32 cxc[ARRAY_SIZE][ARRAY_SIZE]; +uint32 prime = 5000011; +uint32 rand = 31337; +uint32 expos = 1; +uint32 sum = 0; + +uint32 getRandom() +{ + expos = expos * prime; + rand = rand + expos; + rand = rand % 100003; + return rand; +} + +int main(int argc, char** argv) +{ + int x, y, a = 0; + + + for (x = 0; x < ARRAY_SIZE; ++x) + { + for (y = 0; y < ARRAY_SIZE; ++y) + { + axa[x][y]= getRandom(); + bxb[x][y] = getRandom(); + + } + } + for (x=0;x +#include +#include +#include +#include +#include +#include + +using namespace std; + +/* + * Debug File Format + * + * Name Len (bytes) + * ----------------------------------------- + * id 8 + * + * - For each source file that has symbol infos in the binary: + * + * functions 2 + * filename_len 1 + * filename filename_len + * + * - For each function of the source file: + * + * offset 8 + * line_entries 2 + * functionname_len 1 + * functionname functionname_len + * + * - For each line of the source file: + * + * line_offset 2 + * line_number 2 + * + */ + +struct MatchPathSeparator { + bool operator()(char ch) const { return ch == '\\' || ch == '/'; } +}; + +string basename(string const &pathname) { + return string( + find_if(pathname.rbegin(), pathname.rend(), MatchPathSeparator()).base(), + pathname.end()); +} + +struct Function { + uint64_t start, end; + string name; + + Function(uint64_t s, uint64_t e, string n) : start(s), end(e), name(n) {} + + Function() : start(0), end(0), name("") {} +}; + +#define WRITE_FIX(x, type, offset) do {*(type*) debug = (x); debug += sizeof(type) - (offset);} while(0); +#define WRITE(x, type) WRITE_FIX(x, type, 0); +#define TELL(type) (type*)debug + +struct FileHeader { + uint16_t functions; + uint8_t filename_len; + char filename[255]; +} __attribute__((packed)); + +struct FunctionHeader { + uint64_t offset; + uint16_t line_entries; + uint8_t name_len; + char name[255]; +} __attribute__((packed)); + +struct LineHeader { + uint16_t offset; + uint16_t number; +} __attribute__((packed)); + + +int main(int argc, char **argv) { + if (argc != 3) { + fprintf(stderr, "usage: %s elf-file dbg-file\n", argv[0]); + return 2; + } + + int fd = open(argv[1], O_RDONLY); + if (fd < 0) { + fprintf(stderr, "%s: %s\n", argv[1], strerror(errno)); + return 0; + } + FILE *d = fopen(argv[2], "wb"); + if (!d) return 0; + + char *debug = (char *) malloc(1024 * 1024); + char *debug_start = debug; + + memcpy(debug, "SWEBDBG1", 8); + debug += 8; + + map > line_info; + + try { + elf::elf ef(elf::create_mmap_loader(fd)); + dwarf::dwarf dw(dwarf::elf::create_loader(ef)); + + for (auto cu : dw.compilation_units()) { + const dwarf::line_table < = cu.get_line_table(); + + // count entries + uint32_t lines = 0; + for (auto &line : lt) { + (void) line; + lines++; + } + if (!lines || lt.begin() == lt.end() || (begin(lt)->file) == 0) + continue; + + string file(basename(begin(lt)->file->path)); + + // get lines + for (auto &line : lt) { + if (!line.end_sequence) { + line_info[file][line.address] = line.line; + } + } + } + + // look for symbol table + for (auto &sec : ef.sections()) { + if (sec.get_hdr().type != elf::sht::symtab && sec.get_hdr().type != elf::sht::dynsym) + continue; + + // extract and demangle functions + map fncs; + map fnc_written; + for (auto sym : sec.as_symtab()) { + auto &d = sym.get_data(); + if (d.type() != elf::stt::func) continue; + + int status; + char *realname = abi::__cxa_demangle(sym.get_name().c_str(), 0, 0, &status); + string name; + + if (status == -2) { + name = sym.get_name(); + realname = NULL; + } else { + name = string(realname); + } + + fncs[(uint64_t) d.value] = Function((uint64_t) d.value, + (uint64_t) d.value + (int) d.size, string(name)); + fnc_written[(uint64_t) d.value] = false; + free(realname); + } + + // get line infos for functions + for (auto &info : line_info) { + // write fileheader + FileHeader fh; + fh.functions = 0; + fh.filename_len = info.first.size() <= 255 ? info.first.size() : 255; + strncpy(fh.filename, info.first.c_str(), 255); + FileHeader *fh_orig = TELL(FileHeader); + WRITE_FIX(fh, FileHeader, 255 - fh.filename_len); + + int functions = 0; + for (auto &f : fncs) { + Function &func = f.second; + + bool found = false; + map offsets; + for (auto &it : info.second) { + if (func.start <= it.first && func.end > it.first) { + offsets[(int) (it.first - func.start)] = it.second; + found = true; + } + } + + if (found) { + // write function name + offset + entries + functions++; + FunctionHeader fnh; + fnh.offset = func.start; + fnh.line_entries = (uint16_t) offsets.size(); + fnh.name_len = func.name.size() <= 254 ? func.name.size() + 1 : 255; + strncpy(fnh.name, func.name.c_str(), 255); + fnh.name[fnh.name_len] = 0; + WRITE_FIX(fnh, FunctionHeader, 255 - fnh.name_len); + + // write line infos + for (auto &it : offsets) { + LineHeader lh; + lh.offset = (uint16_t) it.first; + lh.number = (uint16_t) it.second; + WRITE(lh, LineHeader); + } + + fnc_written[f.first] = true; + } + } + fh_orig->functions = functions; + + } + + // functions where we couldn't get a file name + map unwritten; + for (auto &f : fncs) { + if (!fnc_written[f.first]) unwritten[f.first] = f.second; + } + + // write zero fileheader + FileHeader fh; + fh.functions = unwritten.size(); + fh.filename_len = 0; + WRITE_FIX(fh, FileHeader, 255); + + // write functions without line information + for (auto &u : unwritten) { + FunctionHeader fnh; + fnh.offset = u.second.start; + fnh.line_entries = 0; + fnh.name_len = u.second.name.size() <= 254 ? u.second.name.size() + 1 : 255; + strncpy(fnh.name, u.second.name.c_str(), 255); + fnh.name[fnh.name_len] = 0; + WRITE_FIX(fnh, FunctionHeader, 255 - fnh.name_len); + } + + fncs.clear(); + } + + //printf("Got %d bytes of debug info\n", (int) (debug - debug_start)); + fwrite(debug_start, debug - debug_start, 1, d); + + } catch (...) { + printf("No debug infos for '%s' available (binary too small).\n",argv[1]); + } + + fclose(d); + return 0; +} diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/.gitignore b/pwn/flipper/dist/utils/add-debug/dwarf/.gitignore new file mode 100644 index 0000000..6b2f7c1 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/.gitignore @@ -0,0 +1,5 @@ +*.o +to_string.cc +libdwarf++.a +libdwarf++.pc +/doc/ diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/CMakeLists.txt b/pwn/flipper/dist/utils/add-debug/dwarf/CMakeLists.txt new file mode 100644 index 0000000..f32dc4f --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/CMakeLists.txt @@ -0,0 +1,25 @@ +# Attention: This CMakeLists.txt implements the bare minimum of what is +# required by SWEB. + +cmake_minimum_required(VERSION 3.1.0) + +set(CMAKE_CXX_STANDARD 11) + +add_custom_command( + OUTPUT to_string.cc + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen_to_string.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/to_string.cc + DEPENDS ../elf/enum-print.py dwarf++.hh data.hh internal.hh +) + +add_library(dwarf++ STATIC + dwarf.cc cursor.cc die.cc value.cc abbrev.cc + expr.cc rangelist.cc line.cc attrs.cc + die_str_map.cc elf.cc to_string.cc +) + +# This is needed for the out-of-source generated to_string.cc +target_include_directories(dwarf++ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") + +if(${CMAKE_VERSION} VERSION_GREATER "3.6.0" OR ${CMAKE_VERSION} VERSION_EQUAL "3.6.0") + target_compile_features(dwarf++ INTERFACE cxx_range_for cxx_generalized_initializers cxx_defaulted_functions cxx_attributes) +endif() \ No newline at end of file diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/abbrev.cc b/pwn/flipper/dist/utils/add-debug/dwarf/abbrev.cc new file mode 100644 index 0000000..9ab1abb --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/abbrev.cc @@ -0,0 +1,168 @@ +#include "internal.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +static value::type +resolve_type(DW_AT name, DW_FORM form) +{ + switch (form) { + case DW_FORM::addr: + return value::type::address; + + case DW_FORM::block: + case DW_FORM::block1: + case DW_FORM::block2: + case DW_FORM::block4: + // Prior to DWARF 4, exprlocs didn't have their own + // form and were represented as blocks. + // XXX Should this be predicated on version? + switch (name) { + case DW_AT::location: + case DW_AT::byte_size: + case DW_AT::bit_offset: + case DW_AT::bit_size: + case DW_AT::string_length: + case DW_AT::lower_bound: + case DW_AT::return_addr: + case DW_AT::bit_stride: + case DW_AT::upper_bound: + case DW_AT::count: + case DW_AT::data_member_location: + case DW_AT::frame_base: + case DW_AT::segment: + case DW_AT::static_link: + case DW_AT::use_location: + case DW_AT::vtable_elem_location: + case DW_AT::allocated: + case DW_AT::associated: + case DW_AT::data_location: + case DW_AT::byte_stride: + return value::type::exprloc; + default: + return value::type::block; + } + + case DW_FORM::data4: + case DW_FORM::data8: + // Prior to DWARF 4, section offsets didn't have their + // own form and were represented as data4 or data8. + // DWARF 3 clarified that types that accepted both + // constants and section offsets were to treat data4 + // and data8 as section offsets and other constant + // forms as constants. + // XXX Should this be predicated on version? + switch (name) { + case DW_AT::location: + case DW_AT::stmt_list: + case DW_AT::string_length: + case DW_AT::return_addr: + case DW_AT::start_scope: + case DW_AT::data_member_location: + case DW_AT::frame_base: + case DW_AT::macro_info: + case DW_AT::segment: + case DW_AT::static_link: + case DW_AT::use_location: + case DW_AT::vtable_elem_location: + case DW_AT::ranges: + goto sec_offset; + default: + // fallthrough + break; + } // fallthrough + case DW_FORM::data1: + case DW_FORM::data2: + return value::type::constant; + case DW_FORM::udata: + return value::type::uconstant; + case DW_FORM::sdata: + return value::type::sconstant; + + case DW_FORM::exprloc: + return value::type::exprloc; + + case DW_FORM::flag: + case DW_FORM::flag_present: + return value::type::flag; + + case DW_FORM::ref1: + case DW_FORM::ref2: + case DW_FORM::ref4: + case DW_FORM::ref8: + case DW_FORM::ref_addr: + case DW_FORM::ref_sig8: + case DW_FORM::ref_udata: + return value::type::reference; + + case DW_FORM::string: + case DW_FORM::strp: + return value::type::string; + + case DW_FORM::indirect: + // There's nothing meaningful we can do + return value::type::invalid; + + case DW_FORM::sec_offset: + sec_offset: + // The type of this form depends on the attribute + switch (name) { + case DW_AT::stmt_list: + return value::type::line; + + case DW_AT::location: + case DW_AT::string_length: + case DW_AT::return_addr: + case DW_AT::data_member_location: + case DW_AT::frame_base: + case DW_AT::segment: + case DW_AT::static_link: + case DW_AT::use_location: + case DW_AT::vtable_elem_location: + return value::type::loclist; + + case DW_AT::macro_info: + return value::type::mac; + + case DW_AT::start_scope: + case DW_AT::ranges: + return value::type::rangelist; + + default: + throw format_error("DW_FORM_sec_offset not expected for attribute " + + to_string(name)); + } + } + throw format_error("unknown attribute form " + to_string(form)); +} + +attribute_spec::attribute_spec(DW_AT name, DW_FORM form) + : name(name), form(form), type(resolve_type(name, form)) +{ +} + +bool +abbrev_entry::read(cursor *cur) +{ + attributes.clear(); + + // Section 7.5.3 + code = cur->uleb128(); + if (!code) + return false; + + tag = (DW_TAG)cur->uleb128(); + children = cur->fixed() == DW_CHILDREN::yes; + while (1) { + DW_AT name = (DW_AT)cur->uleb128(); + DW_FORM form = (DW_FORM)cur->uleb128(); + if (name == (DW_AT)0 && form == (DW_FORM)0) + break; + attributes.push_back(attribute_spec(name, form)); + } + attributes.shrink_to_fit(); + return true; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/attrs.cc b/pwn/flipper/dist/utils/add-debug/dwarf/attrs.cc new file mode 100644 index 0000000..0651b1c --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/attrs.cc @@ -0,0 +1,263 @@ +#include "dwarf++.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +#define AT_ANY(name) \ + value at_##name(const die &d) \ + { \ + return d[DW_AT::name]; \ + } \ + static_assert(true, "") + +#define AT_ADDRESS(name) \ + taddr at_##name(const die &d) \ + { \ + return d[DW_AT::name].as_address(); \ + } \ + static_assert(true, "") + +#define AT_ENUM(name, type) \ + type at_##name(const die &d) \ + { \ + return (type)d[DW_AT::name].as_uconstant(); \ + } \ + static_assert(true, "") + +#define AT_FLAG(name) \ + bool at_##name(const die &d) \ + { \ + return d[DW_AT::name].as_flag(); \ + } \ + static_assert(true, "") + +#define AT_FLAG_(name) \ + bool at_##name(const die &d) \ + { \ + return d[DW_AT::name##_].as_flag(); \ + } \ + static_assert(true, "") + +#define AT_REFERENCE(name) \ + die at_##name(const die &d) \ + { \ + return d[DW_AT::name].as_reference(); \ + } \ + static_assert(true, "") + +#define AT_STRING(name) \ + string at_##name(const die &d) \ + { \ + return d[DW_AT::name].as_string(); \ + } \ + static_assert(true, "") + +#define AT_UDYNAMIC(name) \ + uint64_t at_##name(const die &d, expr_context *ctx) \ + { \ + return _at_udynamic(DW_AT::name, d, ctx); \ + } \ + static_assert(true, "") + +static uint64_t _at_udynamic(DW_AT attr, const die &d, expr_context *ctx, int depth = 0) +{ + // DWARF4 section 2.19 + if (depth > 16) + throw format_error("reference depth exceeded for " + to_string(attr)); + + value v(d[attr]); + switch (v.get_type()) { + case value::type::constant: + case value::type::uconstant: + return v.as_uconstant(); + case value::type::reference: + return _at_udynamic(attr, v.as_reference(), ctx, depth + 1); + case value::type::exprloc: + return v.as_exprloc().evaluate(ctx).value; + default: + throw format_error(to_string(attr) + " has unexpected type " + + to_string(v.get_type())); + } +} + +////////////////////////////////////////////////////////////////// +// 0x0X +// + +AT_REFERENCE(sibling); +// XXX location +AT_STRING(name); +AT_ENUM(ordering, DW_ORD); +AT_UDYNAMIC(byte_size); +AT_UDYNAMIC(bit_offset); +AT_UDYNAMIC(bit_size); + +////////////////////////////////////////////////////////////////// +// 0x1X +// + +// XXX stmt_list +AT_ADDRESS(low_pc); +taddr +at_high_pc(const die &d) +{ + value v(d[DW_AT::high_pc]); + switch (v.get_type()) { + case value::type::address: + return v.as_address(); + case value::type::constant: + case value::type::uconstant: + return at_low_pc(d) + v.as_uconstant(); + default: + throw format_error(to_string(DW_AT::high_pc) + " has unexpected type " + + to_string(v.get_type())); + } +} +AT_ENUM(language, DW_LANG); +AT_REFERENCE(discr); +AT_ANY(discr_value); // XXX Signed or unsigned +AT_ENUM(visibility, DW_VIS); +AT_REFERENCE(import); +// XXX string_length +AT_REFERENCE(common_reference); +AT_STRING(comp_dir); +AT_ANY(const_value); +AT_REFERENCE(containing_type); +// XXX default_value + +////////////////////////////////////////////////////////////////// +// 0x2X +// + +DW_INL at_inline(const die &d) +{ + // XXX Missing attribute is equivalent to DW_INL_not_inlined + // (DWARF4 section 3.3.8) + return (DW_INL)d[DW_AT::inline_].as_uconstant(); +} +AT_FLAG(is_optional); +AT_UDYNAMIC(lower_bound); // XXX Language-based default? +AT_STRING(producer); +AT_FLAG(prototyped); +// XXX return_addr +// XXX start_scope +AT_UDYNAMIC(bit_stride); +AT_UDYNAMIC(upper_bound); + +////////////////////////////////////////////////////////////////// +// 0x3X +// + +AT_REFERENCE(abstract_origin); +AT_ENUM(accessibility, DW_ACCESS); +// XXX const address_class +AT_FLAG(artificial); +// XXX base_types +AT_ENUM(calling_convention, DW_CC); +AT_UDYNAMIC(count); +expr_result +at_data_member_location(const die &d, expr_context *ctx, taddr base, [[gnu::unused]] taddr pc) +{ + value v(d[DW_AT::data_member_location]); + switch (v.get_type()) { + case value::type::constant: + case value::type::uconstant: + return {expr_result::type::address, base + v.as_uconstant(), nullptr, 0}; + case value::type::exprloc: + return v.as_exprloc().evaluate(ctx, base); + case value::type::loclist: + // XXX + throw std::runtime_error("not implemented"); + default: + throw format_error("DW_AT_data_member_location has unexpected type " + + to_string(v.get_type())); + } +} +// XXX decl_column decl_file decl_line +AT_FLAG(declaration); +// XXX discr_list +AT_ENUM(encoding, DW_ATE); +AT_FLAG(external); + +////////////////////////////////////////////////////////////////// +// 0x4X +// + +// XXX frame_base +die at_friend(const die &d) +{ + return d[DW_AT::friend_].as_reference(); +} +AT_ENUM(identifier_case, DW_ID); +// XXX macro_info +AT_REFERENCE(namelist_item); +AT_REFERENCE(priority); // XXX Computed might be useful +// XXX segment +AT_REFERENCE(specification); +// XXX static_link +AT_REFERENCE(type); +// XXX use_location +AT_FLAG(variable_parameter); +// XXX 7.11 The value DW_VIRTUALITY_none is equivalent to the absence +// of the DW_AT_virtuality attribute. +AT_ENUM(virtuality, DW_VIRTUALITY); +// XXX vtable_elem_location +AT_UDYNAMIC(allocated); +AT_UDYNAMIC(associated); + +////////////////////////////////////////////////////////////////// +// 0x5X +// + +// XXX data_location +AT_UDYNAMIC(byte_stride); +AT_ADDRESS(entry_pc); +AT_FLAG(use_UTF8); +AT_REFERENCE(extension); +rangelist +at_ranges(const die &d) +{ + return d[DW_AT::ranges].as_rangelist(); +} +// XXX trampoline +// XXX const call_column, call_file, call_line +AT_STRING(description); +// XXX const binary_scale +// XXX const decimal_scale +AT_REFERENCE(small); +// XXX const decimal_sign +// XXX const digit_count + +////////////////////////////////////////////////////////////////// +// 0x6X +// + +AT_STRING(picture_string); +AT_FLAG_(mutable); +AT_FLAG(threads_scaled); +AT_FLAG_(explicit); +AT_REFERENCE(object_pointer); +AT_ENUM(endianity, DW_END); +AT_FLAG(elemental); +AT_FLAG(pure); +AT_FLAG(recursive); +AT_REFERENCE(signature); // XXX Computed might be useful +AT_FLAG(main_subprogram); +// XXX const data_bit_offset +AT_FLAG(const_expr); +AT_FLAG(enum_class); +AT_STRING(linkage_name); + +rangelist +die_pc_range(const die &d) +{ + // DWARF4 section 2.17 + if (d.has(DW_AT::ranges)) + return at_ranges(d); + taddr low = at_low_pc(d); + taddr high = d.has(DW_AT::high_pc) ? at_high_pc(d) : (low + 1); + return rangelist({{low, high}}); +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/cursor.cc b/pwn/flipper/dist/utils/add-debug/dwarf/cursor.cc new file mode 100644 index 0000000..1c78268 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/cursor.cc @@ -0,0 +1,198 @@ +#include "internal.hh" + +#include +#include + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +int64_t +cursor::sleb128() +{ + // Appendix C + uint64_t result = 0; + unsigned shift = 0; + while (pos < sec->end) { + uint8_t byte = *(uint8_t*)(pos++); + result |= (uint64_t)(byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) { + if (shift < sizeof(result)*8 && (byte & 0x40)) + result |= -((uint64_t)1 << shift); + return result; + } + } + underflow(); + return 0; +} + +shared_ptr
+cursor::subsection() +{ + // Section 7.4 + const char *begin = pos; + section_length length = fixed(); + format fmt; + if (length < 0xfffffff0) { + fmt = format::dwarf32; + length += sizeof(uword); + } else if (length == 0xffffffff) { + length = fixed(); + fmt = format::dwarf64; + length += sizeof(uword) + sizeof(uint64_t); + } else { + throw format_error("initial length has reserved value"); + } + pos = begin + length; + return make_shared
(sec->type, begin, length, fmt); +} + +void +cursor::skip_initial_length() +{ + switch (sec->fmt) { + case format::dwarf32: + pos += sizeof(uword); + break; + case format::dwarf64: + pos += sizeof(uword) + sizeof(uint64_t); + break; + default: + throw logic_error("cannot skip initial length with unknown format"); + } +} + +section_offset +cursor::offset() +{ + switch (sec->fmt) { + case format::dwarf32: + return fixed(); + case format::dwarf64: + return fixed(); + default: + throw logic_error("cannot read offset with unknown format"); + } +} + +void +cursor::string(std::string &out) +{ + size_t size; + const char *p = this->cstr(&size); + out.resize(size); + if (out.size() != 0) + memmove(&out.front(), p, size); +} + +const char * +cursor::cstr(size_t *size_out) +{ + // Scan string size + const char *p = pos; + while (pos < sec->end && *pos) + pos++; + if (pos == sec->end) + throw format_error("unterminated string"); + if (size_out) + *size_out = pos - p; + pos++; + return p; +} + +void +cursor::skip_form(DW_FORM form) +{ + section_offset tmp; + + // Section 7.5.4 + switch (form) { + case DW_FORM::addr: + pos += sec->addr_size; + break; + case DW_FORM::sec_offset: + case DW_FORM::ref_addr: + case DW_FORM::strp: + switch (sec->fmt) { + case format::dwarf32: + pos += 4; + break; + case format::dwarf64: + pos += 8; + break; + case format::unknown: + throw logic_error("cannot read form with unknown format"); + } + break; + + // size+data forms + case DW_FORM::block1: + tmp = fixed(); + pos += tmp; + break; + case DW_FORM::block2: + tmp = fixed(); + pos += tmp; + break; + case DW_FORM::block4: + tmp = fixed(); + pos += tmp; + break; + case DW_FORM::block: + case DW_FORM::exprloc: + tmp = uleb128(); + pos += tmp; + break; + + // fixed-length forms + case DW_FORM::flag_present: + break; + case DW_FORM::flag: + case DW_FORM::data1: + case DW_FORM::ref1: + pos += 1; + break; + case DW_FORM::data2: + case DW_FORM::ref2: + pos += 2; + break; + case DW_FORM::data4: + case DW_FORM::ref4: + pos += 4; + break; + case DW_FORM::data8: + case DW_FORM::ref_sig8: + pos += 8; + break; + + // variable-length forms + case DW_FORM::sdata: + case DW_FORM::udata: + case DW_FORM::ref_udata: + while (pos < sec->end && (*(uint8_t*)pos & 0x80)) + pos++; + pos++; + break; + case DW_FORM::string: + while (pos < sec->end && *pos) + pos++; + pos++; + break; + + case DW_FORM::indirect: + skip_form((DW_FORM)uleb128()); + break; + + default: + throw format_error("unknown form " + to_string(form)); + } +} + +void +cursor::underflow() +{ + throw underflow_error("cannot read past end of DWARF section"); +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/data.hh b/pwn/flipper/dist/utils/add-debug/dwarf/data.hh new file mode 100644 index 0000000..8fc0a24 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/data.hh @@ -0,0 +1,561 @@ +#ifndef _DWARFPP_DW_HH_ +#define _DWARFPP_DW_HH_ + +#include +#include + +DWARFPP_BEGIN_NAMESPACE + +// Integer representations (Section 7.26) +typedef std::int8_t sbyte; +typedef std::uint8_t ubyte; +typedef std::uint16_t uhalf; +typedef std::uint32_t uword; + +// Section offsets and lengths +typedef std::uint64_t section_offset; +typedef std::uint64_t section_length; + +// A target machine address. Targets may use smaller addresses; this +// represents the largest supported address type. +typedef std::uint64_t taddr; + +// DIE tags (Section 7, figure 18). typedef, friend, and namespace +// have a trailing underscore because they are reserved words. +enum class DW_TAG +{ + array_type = 0x01, + class_type = 0x02, + entry_point = 0x03, + enumeration_type = 0x04, + formal_parameter = 0x05, + imported_declaration = 0x08, + label = 0x0a, + lexical_block = 0x0b, + member = 0x0d, + pointer_type = 0x0f, + reference_type = 0x10, + compile_unit = 0x11, + string_type = 0x12, + structure_type = 0x13, + subroutine_type = 0x15, + typedef_ = 0x16, + + union_type = 0x17, + unspecified_parameters = 0x18, + variant = 0x19, + common_block = 0x1a, + common_inclusion = 0x1b, + inheritance = 0x1c, + inlined_subroutine = 0x1d, + module = 0x1e, + ptr_to_member_type = 0x1f, + set_type = 0x20, + subrange_type = 0x21, + with_stmt = 0x22, + access_declaration = 0x23, + base_type = 0x24, + catch_block = 0x25, + const_type = 0x26, + constant = 0x27, + enumerator = 0x28, + file_type = 0x29, + friend_ = 0x2a, + + namelist = 0x2b, + namelist_item = 0x2c, + packed_type = 0x2d, + subprogram = 0x2e, + template_type_parameter = 0x2f, + template_value_parameter = 0x30, + thrown_type = 0x31, + try_block = 0x32, + variant_part = 0x33, + variable = 0x34, + volatile_type = 0x35, + dwarf_procedure = 0x36, + restrict_type = 0x37, + interface_type = 0x38, + namespace_ = 0x39, + imported_module = 0x3a, + unspecified_type = 0x3b, + partial_unit = 0x3c, + imported_unit = 0x3d, + condition = 0x3f, + + shared_type = 0x40, + type_unit = 0x41, + rvalue_reference_type = 0x42, + template_alias = 0x43, + lo_user = 0x4080, + hi_user = 0xffff, +}; + +std::string +to_string(DW_TAG v); + +// Child determination (Section 7, figure 19). +enum class DW_CHILDREN : ubyte +{ + no = 0x00, + yes = 0x01, +}; + +std::string +to_string(DW_CHILDREN v); + +// Attribute names (Section 7, figure 20). inline, friend, mutable, +// and explicit have a trailing underscore because they are reserved +// words. +enum class DW_AT +{ + sibling = 0x01, // reference + location = 0x02, // exprloc, loclistptr + name = 0x03, // string + ordering = 0x09, // constant + byte_size = 0x0b, // constant, exprloc, reference + bit_offset = 0x0c, // constant, exprloc, reference + bit_size = 0x0d, // constant, exprloc, reference + stmt_list = 0x10, // lineptr + low_pc = 0x11, // address + high_pc = 0x12, // address, constant + language = 0x13, // constant + discr = 0x15, // reference + discr_value = 0x16, // constant + visibility = 0x17, // constant + import = 0x18, // reference + string_length = 0x19, // exprloc, loclistptr + common_reference = 0x1a, // reference + comp_dir = 0x1b, // string + const_value = 0x1c, // block, constant, string + + containing_type = 0x1d, // reference + default_value = 0x1e, // reference + inline_ = 0x20, // constant + is_optional = 0x21, // flag + lower_bound = 0x22, // constant, exprloc, reference + producer = 0x25, // string + prototyped = 0x27, // flag + return_addr = 0x2a, // exprloc, loclistptr + start_scope = 0x2c, // constant, rangelistptr + bit_stride = 0x2e, // constant, exprloc, reference + upper_bound = 0x2f, // constant, exprloc, reference + abstract_origin = 0x31, // reference + accessibility = 0x32, // constant + address_class = 0x33, // constant + artificial = 0x34, // flag + base_types = 0x35, // reference + calling_convention = 0x36, // constant + count = 0x37, // constant, exprloc, reference + data_member_location = 0x38, // constant, exprloc, loclistptr + decl_column = 0x39, // constant + + decl_file = 0x3a, // constant + decl_line = 0x3b, // constant + declaration = 0x3c, // flag + discr_list = 0x3d, // block + encoding = 0x3e, // constant + external = 0x3f, // flag + frame_base = 0x40, // exprloc, loclistptr + friend_ = 0x41, // reference + identifier_case = 0x42, // constant + macro_info = 0x43, // macptr + namelist_item = 0x44, // reference + priority = 0x45, // reference + segment = 0x46, // exprloc, loclistptr + specification = 0x47, // reference + static_link = 0x48, // exprloc, loclistptr + type = 0x49, // reference + use_location = 0x4a, // exprloc, loclistptr + variable_parameter = 0x4b, // flag + virtuality = 0x4c, // constant + vtable_elem_location = 0x4d, // exprloc, loclistptr + + // DWARF 3 + allocated = 0x4e, // constant, exprloc, reference + associated = 0x4f, // constant, exprloc, reference + data_location = 0x50, // exprloc + byte_stride = 0x51, // constant, exprloc, reference + entry_pc = 0x52, // address + use_UTF8 = 0x53, // flag + extension = 0x54, // reference + ranges = 0x55, // rangelistptr + trampoline = 0x56, // address, flag, reference, string + call_column = 0x57, // constant + call_file = 0x58, // constant + call_line = 0x59, // constant + description = 0x5a, // string + binary_scale = 0x5b, // constant + decimal_scale = 0x5c, // constant + small = 0x5d, // reference + decimal_sign = 0x5e, // constant + digit_count = 0x5f, // constant + picture_string = 0x60, // string + mutable_ = 0x61, // flag + + threads_scaled = 0x62, // flag + explicit_ = 0x63, // flag + object_pointer = 0x64, // reference + endianity = 0x65, // constant + elemental = 0x66, // flag + pure = 0x67, // flag + recursive = 0x68, // flag + + // DWARF 4 + signature = 0x69, // reference + main_subprogram = 0x6a, // flag + data_bit_offset = 0x6b, // constant + const_expr = 0x6c, // flag + enum_class = 0x6d, // flag + linkage_name = 0x6e, // string + + lo_user = 0x2000, + hi_user = 0x3fff, +}; + +std::string +to_string(DW_AT v); + +// Attribute form encodings (Section 7, figure 21) +enum class DW_FORM +{ + addr = 0x01, // address + block2 = 0x03, // block + block4 = 0x04, // block + data2 = 0x05, // constant + data4 = 0x06, // constant + data8 = 0x07, // constant + string = 0x08, // string + block = 0x09, // block + block1 = 0x0a, // block + data1 = 0x0b, // constant + flag = 0x0c, // flag + sdata = 0x0d, // constant + strp = 0x0e, // string + udata = 0x0f, // constant + ref_addr = 0x10, // reference + ref1 = 0x11, // reference + ref2 = 0x12, // reference + ref4 = 0x13, // reference + ref8 = 0x14, // reference + + ref_udata = 0x15, // reference + indirect = 0x16, // (Section 7.5.3) + + // DWARF 4 + sec_offset = 0x17, // lineptr, loclistptr, macptr, rangelistptr + exprloc = 0x18, // exprloc + flag_present = 0x19, // flag + ref_sig8 = 0x20, // reference +}; + +std::string +to_string(DW_FORM v); + +// DWARF operation encodings (Section 7.7.1 and figure 24) +enum class DW_OP : ubyte +{ + addr = 0x03, // [constant address (size target specific)] + deref = 0x06, + + const1u = 0x08, // [1-byte constant] + const1s = 0x09, // [1-byte constant] + const2u = 0x0a, // [2-byte constant] + const2s = 0x0b, // [2-byte constant] + const4u = 0x0c, // [4-byte constant] + const4s = 0x0d, // [4-byte constant] + const8u = 0x0e, // [8-byte constant] + const8s = 0x0f, // [8-byte constant] + constu = 0x10, // [ULEB128 constant] + consts = 0x11, // [SLEB128 constant] + dup = 0x12, + drop = 0x13, + over = 0x14, + pick = 0x15, // [1-byte stack index] + swap = 0x16, + rot = 0x17, + xderef = 0x18, + abs = 0x19, + and_ = 0x1a, + div = 0x1b, + + minus = 0x1c, + mod = 0x1d, + mul = 0x1e, + neg = 0x1f, + not_ = 0x20, + or_ = 0x21, + plus = 0x22, + plus_uconst = 0x23, // [ULEB128 addend] + shl = 0x24, + shr = 0x25, + shra = 0x26, + xor_ = 0x27, + skip = 0x2f, // [signed 2-byte constant] + bra = 0x28, // [signed 2-byte constant] + eq = 0x29, + ge = 0x2a, + gt = 0x2b, + le = 0x2c, + lt = 0x2d, + ne = 0x2e, + + // Literals 0..31 = (lit0 + literal) + lit0 = 0x30, + lit31 = 0x4f, + + // Registers 0..31 = (reg0 + regnum) + reg0 = 0x50, + reg31 = 0x6f, + + // Base register 0..31 = (breg0 + regnum) + breg0 = 0x70, // [SLEB128 offset] + breg31 = 0x8f, // [SLEB128 offset] + + regx = 0x90, // [ULEB128 register] + fbreg = 0x91, // [SLEB128 offset] + bregx = 0x92, // [ULEB128 register, SLEB128 offset] + piece = 0x93, // [ULEB128 size of piece addressed] + deref_size = 0x94, // [1-byte size of data retrieved] + xderef_size = 0x95, // [1-byte size of data retrieved] + nop = 0x96, + + // DWARF 3 + push_object_address = 0x97, + call2 = 0x98, // [2-byte offset of DIE] + call4 = 0x99, // [4-byte offset of DIE] + call_ref = 0x9a, // [4- or 8-byte offset of DIE] + form_tls_address = 0x9b, + call_frame_cfa = 0x9c, + bit_piece = 0x9d, // [ULEB128 size, ULEB128 offset] + + // DWARF 4 + implicit_value = 0x9e, // [ULEB128 size, block of that size] + stack_value = 0x9f, + + lo_user = 0xe0, + hi_user = 0xff, +}; + +std::string +to_string(DW_OP v); + +// DW_AT::encoding constants (DWARF4 section 7.8 figure 25) +enum class DW_ATE +{ + address = 0x01, + boolean = 0x02, + complex_float = 0x03, + float_ = 0x04, + signed_ = 0x05, + signed_char = 0x06, + unsigned_ = 0x07, + unsigned_char = 0x08, + imaginary_float = 0x09, + packed_decimal = 0x0a, + numeric_string = 0x0b, + edited = 0x0c, + signed_fixed = 0x0d, + unsigned_fixed = 0x0e, + decimal_float = 0x0f, + + // DWARF 4 + UTF = 0x10, + + lo_user = 0x80, + hi_user = 0xff, +}; + +std::string +to_string(DW_ATE v); + +// DW_AT::decimal_sign constants (DWARF4 section 7.8 figure 26) +enum class DW_DS +{ + unsigned_ = 0x01, + leading_overpunch = 0x02, + trailing_overpunch = 0x03, + leading_separate = 0x04, + trailing_separate = 0x05, +}; + +std::string +to_string(DW_DS v); + +// DW_AT::endianity constants (DWARF4 section 7.8 figure 27) +enum class DW_END +{ + default_ = 0x00, + big = 0x01, + little = 0x02, + lo_user = 0x40, + hi_user = 0xff, +}; + +std::string +to_string(DW_END v); + +// DW_AT::accessibility constants (DWARF4 section 7.9 figure 28) +enum class DW_ACCESS +{ + public_ = 0x01, + protected_ = 0x02, + private_ = 0x03, +}; + +std::string +to_string(DW_ACCESS v); + +// DW_AT::visibility constants (DWARF4 section 7.10 figure 29) +enum class DW_VIS +{ + local = 0x01, + exported = 0x02, + qualified = 0x03, +}; + +std::string +to_string(DW_VIS v); + +// DW_AT::virtuality constants (DWARF4 section 7.11 figure 30) +enum class DW_VIRTUALITY +{ + none = 0x00, + virtual_ = 0x01, + pure_virtual = 0x02, +}; + +std::string +to_string(DW_VIRTUALITY v); + +// DW_AT::language constants (DWARF4 section 7.12 figure 31) +enum class DW_LANG +{ + C89 = 0x0001, // Lower bound 0 + C = 0x0002, // Lower bound 0 + Ada83 = 0x0003, // Lower bound 1 + C_plus_plus = 0x0004, // Lower bound 0 + Cobol74 = 0x0005, // Lower bound 1 + Cobol85 = 0x0006, // Lower bound 1 + Fortran77 = 0x0007, // Lower bound 1 + Fortran90 = 0x0008, // Lower bound 1 + Pascal83 = 0x0009, // Lower bound 1 + Modula2 = 0x000a, // Lower bound 1 + Java = 0x000b, // Lower bound 0 + C99 = 0x000c, // Lower bound 0 + Ada95 = 0x000d, // Lower bound 1 + Fortran95 = 0x000e, // Lower bound 1 + PLI = 0x000f, // Lower bound 1 + + ObjC = 0x0010, // Lower bound 0 + ObjC_plus_plus = 0x0011, // Lower bound 0 + UPC = 0x0012, // Lower bound 0 + D = 0x0013, // Lower bound 0 + Python = 0x0014, // Lower bound 0 + lo_user = 0x8000, + hi_user = 0xffff, +}; + +std::string +to_string(DW_LANG v); + +// DW_AT::identifier_case constants (DWARF4 section 7.14 figure 32) +enum class DW_ID +{ + case_sensitive = 0x00, + up_case = 0x01, + down_case = 0x02, + case_insensitive = 0x03, +}; + +std::string +to_string(DW_ID v); + +// DW_AT::calling_convention constants (DWARF4 section 7.15 figure 33) +enum class DW_CC +{ + normal = 0x01, + program = 0x02, + nocall = 0x03, + lo_user = 0x40, + hi_user = 0xff, +}; + +std::string +to_string(DW_CC v); + +// DW_AT::inline constants (DWARF4 section 7.16 figure 34) +enum class DW_INL +{ + not_inlined = 0x00, + inlined = 0x01, + declared_not_inlined = 0x02, + declared_inlined = 0x03, +}; + +std::string +to_string(DW_INL v); + +// DW_AT::ordering constants (DWARF4 section 7.17 figure 35) +enum class DW_ORD +{ + row_major = 0x00, + col_major = 0x01, +}; + +std::string +to_string(DW_ORD v); + +// DW_AT::discr_list constants (DWARF4 section 7.18 figure 36) +enum class DW_DSC +{ + label = 0x00, + range = 0x01, +}; + +std::string +to_string(DW_DSC v); + +// Line number standard opcodes (DWARF4 section 7.21 figure 37) +enum class DW_LNS +{ + copy = 0x01, + advance_pc = 0x02, + advance_line = 0x03, + set_file = 0x04, + set_column = 0x05, + negate_stmt = 0x06, + set_basic_block = 0x07, + const_add_pc = 0x08, + fixed_advance_pc = 0x09, + + // DWARF 3 + set_prologue_end = 0x0a, + set_epilogue_begin = 0x0b, + set_isa = 0x0c, +}; + +std::string +to_string(DW_LNS v); + +// Line number extended opcodes (DWARF4 section 7.21 figure 38) +enum class DW_LNE +{ + end_sequence = 0x01, + set_address = 0x02, + define_file = 0x03, + + // DWARF 4 + set_discriminator = 0x04, + + // DWARF 3 + lo_user = 0x80, + hi_user = 0xff, +}; + +std::string +to_string(DW_LNE v); + +DWARFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/die.cc b/pwn/flipper/dist/utils/add-debug/dwarf/die.cc new file mode 100644 index 0000000..22e3843 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/die.cc @@ -0,0 +1,198 @@ +#include "internal.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +die::die(const unit *cu) + : cu(cu), abbrev(nullptr) +{ +} + +const unit & +die::get_unit() const +{ + return *cu; +} + +section_offset +die::get_section_offset() const +{ + return cu->get_section_offset() + offset; +} + +void +die::read(section_offset off) +{ + cursor cur(cu->data(), off); + + offset = off; + + abbrev_code acode = cur.uleb128(); + if (acode == 0) { + abbrev = nullptr; + next = cur.get_section_offset(); + return; + } + abbrev = &cu->get_abbrev(acode); + + tag = abbrev->tag; + + // XXX We can pre-compute almost all of this work in the + // abbrev_entry. + attrs.clear(); + attrs.reserve(abbrev->attributes.size()); + for (auto &attr : abbrev->attributes) { + attrs.push_back(cur.get_section_offset()); + cur.skip_form(attr.form); + } + next = cur.get_section_offset(); +} + +bool +die::has(DW_AT attr) const +{ + if (!abbrev) + return false; + // XXX Totally lame + for (auto &a : abbrev->attributes) + if (a.name == attr) + return true; + return false; +} + +value +die::operator[](DW_AT attr) const +{ + // XXX We can pre-compute almost all of this work in the + // abbrev_entry. + if (abbrev) { + int i = 0; + for (auto &a : abbrev->attributes) { + if (a.name == attr) + return value(cu, a.name, a.form, a.type, attrs[i]); + i++; + } + } + throw out_of_range("DIE does not have attribute " + to_string(attr)); +} + +value +die::resolve(DW_AT attr) const +{ + // DWARF4 section 2.13, DWARF4 section 3.3.8 + + // DWARF4 is unclear about what to do when there's both a + // DW_AT::specification and a DW_AT::abstract_origin. + // Conceptually, though, a concrete inlined instance cannot + // itself complete an external function that wasn't first + // completed by its abstract instance, so we first try to + // resolve abstract_origin, then we resolve specification. + + // XXX This traverses the abbrevs at least twice and + // potentially several more times + + if (has(attr)) + return (*this)[attr]; + + if (has(DW_AT::abstract_origin)) { + die ao = (*this)[DW_AT::abstract_origin].as_reference(); + if (ao.has(attr)) + return ao[attr]; + if (ao.has(DW_AT::specification)) { + die s = ao[DW_AT::specification].as_reference(); + if (s.has(attr)) + return s[attr]; + } + } else if (has(DW_AT::specification)) { + die s = (*this)[DW_AT::specification].as_reference(); + if (s.has(attr)) + return s[attr]; + } + + return value(); +} + +die::iterator +die::begin() const +{ + if (!abbrev || !abbrev->children) + return end(); + return iterator(cu, next); +} + +die::iterator::iterator(const unit *cu, section_offset off) + : d(cu) +{ + d.read(off); +} + +die::iterator & +die::iterator::operator++() +{ + if (!d.abbrev) + return *this; + + if (!d.abbrev->children) { + // The DIE has no children, so its successor follows + // immediately + d.read(d.next); + } else if (d.has(DW_AT::sibling)) { + // They made it easy on us. Follow the sibling + // pointer. XXX Probably worth optimizing + d = d[DW_AT::sibling].as_reference(); + } else { + // It's a hard-knock life. We have to iterate through + // the children to find the next DIE. + // XXX Particularly unfortunate if the user is doing a + // DFS, since this will result in N^2 behavior. Maybe + // a small cache of terminator locations in the CU? + iterator sub(d.cu, d.next); + while (sub->abbrev) + ++sub; + d.read(sub->next); + } + + return *this; +} + +const vector > +die::attributes() const +{ + vector > res; + + if (!abbrev) + return res; + + // XXX Quite slow, especially when using this to traverse an + // entire DIE tree since each DIE will produce a new vector + // (whereas other vectors get reused). Might be worth a + // custom iterator. + int i = 0; + for (auto &a : abbrev->attributes) { + res.push_back(make_pair(a.name, value(cu, a.name, a.form, a.type, attrs[i]))); + i++; + } + return res; +} + +bool +die::operator==(const die &o) const +{ + return cu == o.cu && offset == o.offset; +} + +bool +die::operator!=(const die &o) const +{ + return !(*this == o); +} + +DWARFPP_END_NAMESPACE + +size_t +std::hash::operator()(const dwarf::die &a) const +{ + return hash()(a.cu) ^ + hash()(a.get_unit_offset()); +} diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/die_str_map.cc b/pwn/flipper/dist/utils/add-debug/dwarf/die_str_map.cc new file mode 100644 index 0000000..a74b5bf --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/die_str_map.cc @@ -0,0 +1,114 @@ +#include "internal.hh" + +#include +#include + +using namespace std; + +// XXX Make this more readily available? +namespace std { + template<> + struct hash + { + typedef size_t result_type; + typedef dwarf::DW_TAG argument_type; + result_type operator()(argument_type a) const + { + return (result_type)a; + } + }; +} + +DWARFPP_BEGIN_NAMESPACE + +struct string_hash +{ + typedef size_t result_type; + typedef const char *argument_type; + result_type operator()(const char *s) const + { + result_type h = 0; + for (; *s; ++s) + h += 33 * h + *s; + return h; + } +}; + +struct string_eq +{ + typedef bool result_type; + typedef const char *first_argument_type; + typedef const char *second_argument_type; + bool operator()(const char *x, const char *y) const + { + return strcmp(x, y) == 0; + } +}; + +struct die_str_map::impl +{ + impl(const die &parent, DW_AT attr, + const initializer_list &accept) + : attr(attr), accept(accept.begin(), accept.end()), + pos(parent.begin()), end(parent.end()) { } + + unordered_map str_map; + DW_AT attr; + unordered_set accept; + die::iterator pos, end; + die invalid; +}; + +die_str_map::die_str_map(const die &parent, DW_AT attr, + const initializer_list &accept) + : m(make_shared(parent, attr, accept)) +{ +} + +die_str_map +die_str_map::from_type_names(const die &parent) +{ + return die_str_map + (parent, DW_AT::name, + // All DWARF type tags (this is everything that ends + // with _type except thrown_type). + {DW_TAG::array_type, DW_TAG::class_type, + DW_TAG::enumeration_type, DW_TAG::pointer_type, + DW_TAG::reference_type, DW_TAG::string_type, + DW_TAG::structure_type, DW_TAG::subroutine_type, + DW_TAG::union_type, DW_TAG::ptr_to_member_type, + DW_TAG::set_type, DW_TAG::subrange_type, + DW_TAG::base_type, DW_TAG::const_type, + DW_TAG::file_type, DW_TAG::packed_type, + DW_TAG::volatile_type, DW_TAG::restrict_type, + DW_TAG::interface_type, DW_TAG::unspecified_type, + DW_TAG::shared_type, DW_TAG::rvalue_reference_type}); +} + +const die & +die_str_map::operator[](const char *val) const +{ + // Do we have this value? + auto it = m->str_map.find(val); + if (it != m->str_map.end()) + return it->second; + // Read more until we find the value or the end + while (m->pos != m->end) { + const die &d = *m->pos; + ++m->pos; + + if (!m->accept.count(d.tag) || !d.has(m->attr)) + continue; + value dval(d[m->attr]); + if (dval.get_type() != value::type::string) + continue; + const char *dstr = dval.as_cstr(); + m->str_map[dstr] = d; + if (strcmp(val, dstr) == 0) + return m->str_map[dstr]; + } + // Not found + return m->invalid; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/dwarf++.hh b/pwn/flipper/dist/utils/add-debug/dwarf/dwarf++.hh new file mode 100644 index 0000000..732f1b4 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/dwarf++.hh @@ -0,0 +1,1556 @@ +#ifndef _DWARFPP_HH_ +#define _DWARFPP_HH_ + +#ifndef DWARFPP_BEGIN_NAMESPACE +#define DWARFPP_BEGIN_NAMESPACE namespace dwarf { +#define DWARFPP_END_NAMESPACE } +#endif + +#include "data.hh" +#include "small_vector.hh" + +#include +#include +#include +#include +#include +#include + +DWARFPP_BEGIN_NAMESPACE + +// Forward declarations +class dwarf; +class loader; +class compilation_unit; +class type_unit; +class die; +class value; +class expr; +class expr_context; +class expr_result; +class rangelist; +class line_table; + +// Internal type forward-declarations +struct section; +struct abbrev_entry; +struct cursor; + +// XXX Audit for binary-compatibility + +// XXX Might be able to reduce private coupling by making class +// section public (and clean it up and maybe rename it slice) and +// provide methods to get the backing data of things. +// +// XXX Make slice generic, without formatting information? Still want +// lightweight cursors, so maybe the cursor methods that need the +// format should take a const reference to a format stored in the +// compilation unit? + +// XXX operator==/!= and hash functions + +// XXX Support non-native byte order + +// XXX Indicate DWARF4 in all spec references + +// XXX Big missing support: .debug_aranges, .debug_frame, loclists, +// macros + +////////////////////////////////////////////////////////////////// +// DWARF files +// + +/** + * An exception indicating malformed DWARF data. + */ +class format_error : public std::runtime_error +{ +public: + explicit format_error(const std::string &what_arg) + : std::runtime_error(what_arg) { } + explicit format_error(const char *what_arg) + : std::runtime_error(what_arg) { } +}; + +/** + * DWARF section types. These correspond to the names of ELF + * sections, though DWARF can be embedded in other formats. + */ +enum class section_type +{ + abbrev, + aranges, + frame, + info, + line, + loc, + macinfo, + pubnames, + pubtypes, + ranges, + str, + types, +}; + +std::string +to_string(section_type v); + +/** + * A DWARF file. This class is internally reference counted and can + * be efficiently copied. + * + * Objects retrieved from this object may depend on it; the caller is + * responsible for keeping this object live as long as any retrieved + * object may be in use. + */ +class dwarf +{ +public: + /** + * Construct a DWARF file that is backed by sections read from + * the given loader. + */ + explicit dwarf(const std::shared_ptr &l); + + /** + * Construct a DWARF file that is initially not valid. + */ + dwarf() = default; + dwarf(const dwarf&) = default; + dwarf(dwarf&&) = default; + ~dwarf(); + + dwarf& operator=(const dwarf &o) = default; + dwarf& operator=(dwarf &&o) = default; + + bool operator==(const dwarf &o) const + { + return m == o.m; + } + + bool operator!=(const dwarf &o) const + { + return m != o.m; + } + + /** + * Return true if this object represents a DWARF file. + * Default constructed dwarf objects are not valid. + */ + bool valid() const + { + return !!m; + } + + // XXX This allows the compilation units to be modified and + // ties us to a vector. Probably should return an opaque + // iterable collection over const references. + /** + * Return the list of compilation units in this DWARF file. + */ + const std::vector &compilation_units() const; + + /** + * Return the type unit with the given signature. If the + * signature does not correspond to a type unit, throws + * out_of_range. + */ + const type_unit &get_type_unit(uint64_t type_signature) const; + + /** + * \internal Retrieve the specified section from this file. + * If the section does not exist, throws format_error. + */ + std::shared_ptr
get_section(section_type type) const; + +private: + struct impl; + std::shared_ptr m; +}; + +/** + * An interface for lazily loading DWARF sections. + */ +class loader +{ +public: + virtual ~loader() { } + + /** + * Load the requested DWARF section into memory and return a + * pointer to the beginning of it. This memory must remain + * valid and unchanged until the loader is destroyed. If the + * requested section does not exist, this should return + * nullptr. If the section exists but cannot be loaded for + * any reason, this should throw an exception. + */ + virtual const void *load(section_type section, size_t *size_out) = 0; +}; + +/** + * The base class for a compilation unit or type unit within a DWARF + * file. A unit consists of a rooted tree of DIEs, plus additional + * metadata that depends on the type of unit. + */ +class unit +{ +public: + virtual ~unit() = 0; + + bool operator==(const unit &o) const + { + return m == o.m; + } + + bool operator!=(const unit &o) const + { + return m != o.m; + } + + /** + * Return true if this object is valid. Default constructed + * unit objects are not valid. + */ + bool valid() const + { + return !!m; + } + + /** + * Return the dwarf file this unit is in. + */ + const dwarf &get_dwarf() const; + + /** + * Return the byte offset of this unit's header in its + * section (.debug_info or .debug_types). + */ + section_offset get_section_offset() const; + + /** + * Return the root DIE of this unit. For a compilation unit, + * this should be a DW_TAG::compilation_unit or + * DW_TAG::partial_unit. + */ + const die &root() const; + + /** + * \internal Return the data for this unit. + */ + const std::shared_ptr
&data() const; + + /** + * \internal Return the abbrev for the specified abbrev + * code. + */ + const abbrev_entry &get_abbrev(std::uint64_t acode) const; + +protected: + friend struct ::std::hash; + struct impl; + std::shared_ptr m; +}; + +/** + * A compilation unit within a DWARF file. Most of the information + * in a DWARF file is divided up by compilation unit. This class is + * internally reference counted and can be efficiently copied. + */ +class compilation_unit : public unit +{ +public: + compilation_unit() = default; + compilation_unit(const compilation_unit &o) = default; + compilation_unit(compilation_unit &&o) = default; + + compilation_unit& operator=(const compilation_unit &o) = default; + compilation_unit& operator=(compilation_unit &&o) = default; + + /** + * \internal Construct a compilation unit whose header begins + * offset bytes into the .debug_info section of file. + */ + compilation_unit(const dwarf &file, section_offset offset); + + /** + * Return the line number table of this compilation unit. + * Returns an invalid line table if this unit has no line + * table. + */ + const line_table &get_line_table() const; +}; + +/** + * A type unit. Type units allow complex type information to be + * shared between compilation units. + */ +class type_unit : public unit +{ +public: + type_unit() = default; + type_unit(const type_unit &o) = default; + type_unit(type_unit &&o) = default; + + type_unit &operator=(const type_unit &o) = default; + type_unit &operator=(type_unit &&o) = default; + + /** + * \internal Construct a type unit whose header begins offset + * bytes into the .debug_types section of file. + */ + type_unit(const dwarf &file, section_offset offset); + + /** + * Return the 64-bit unique signature that identifies this + * type unit. This is how DIEs from other units refer to type + * described by this unit. + */ + uint64_t get_type_signature() const; + + // XXX Can a type unit contain more than one top-level DIE? + // The description of type_offset makes it sound like it + // might. + + /** + * Return the DIE of the type described by this type unit. + * This may not be the root DIE of this unit if the type is + * nested in namespaces or other structures. + */ + const die &type() const; +}; + +////////////////////////////////////////////////////////////////// +// Debugging information entries (DIEs) +// + +/** + * A Debugging Information Entry, or DIE. The basic unit of + * information in a DWARF file. + */ +class die +{ + // XXX Make this class better for use in maps. Currently dies + // are fairly big and expensive to copy, but most of that + // information can be constructed lazily. This is also bad + // for use in caches since it will keep the DWARF file alive. + // OTOH, maybe caches need eviction anyway. +public: + DW_TAG tag; + + die() : cu(nullptr), abbrev(nullptr) { } + die(const die &o) = default; + die(die &&o) = default; + + die& operator=(const die &o) = default; + die& operator=(die &&o) = default; + + /** + * Return true if this object represents a DIE in a DWARF + * file. Default constructed objects are not valid and some + * methods return invalid DIEs to indicate failures. + */ + bool valid() const + { + return abbrev != nullptr; + } + + /** + * Return the unit containing this DIE. + */ + const unit &get_unit() const; + + /** + * Return this DIE's byte offset within its compilation unit. + */ + section_offset get_unit_offset() const + { + return offset; + } + + /** + * Return this DIE's byte offset within its section. + */ + section_offset get_section_offset() const; + + /** + * Return true if this DIE has the requested attribute. + */ + bool has(DW_AT attr) const; + + /** + * Return the value of attr. Throws out_of_range if this DIE + * does not have the specified attribute. It is generally + * better to use the type-safe attribute getters (the global + * functions beginning with at_*) when possible. + */ + value operator[](DW_AT attr) const; + + /** + * Return the value of attr after resolving specification and + * abstract origin references. If the attribute cannot be + * resolved, returns an invalid value. Declaration DIEs can + * "complete" a previous non-defining declaration DIE and + * similarly inherit the non-defining declaration's attributes + * (DWARF4 section 2.13) Likewise, any DIE that is a child of + * a concrete inlined instance can specify another DIE as its + * "abstract origin" and the original DIE will inherit the + * attributes of its abstract origin (DWARF4 section 3.3.8.2). + */ + value resolve(DW_AT attr) const; + + class iterator; + + /** + * Return an iterator over the children of this DIE. Note + * that the DIEs returned by this iterator are temporary, so + * if you need to store a DIE for more than one loop + * iteration, you must copy it. + */ + iterator begin() const; + iterator end() const; + + /** + * Return a vector of the attributes of this DIE. + */ + const std::vector > attributes() const; + + bool operator==(const die &o) const; + bool operator!=(const die &o) const; + +private: + friend class unit; + friend class type_unit; + friend class value; + // XXX If we can get the CU, we don't need this + friend struct ::std::hash; + + const unit *cu; + // The abbrev of this DIE. By convention, if this DIE + // represents a sibling list terminator, this is null. This + // object is kept live by the CU. + const abbrev_entry *abbrev; + // The beginning of this DIE, relative to the CU. + section_offset offset; + // Offsets of attributes, relative to cu's subsection. The + // vast majority of DIEs tend to have six or fewer attributes, + // so we reserve space in the DIE itself for six attributes. + small_vector attrs; + // The offset of the next DIE, relative to cu'd subsection. + // This is set even for sibling list terminators. + section_offset next; + + die(const unit *cu); + + /** + * Read this DIE from the given offset in cu. + */ + void read(section_offset off); +}; + +/** + * An iterator over a sequence of sibling DIEs. + */ +class die::iterator +{ +public: + iterator() = default; + iterator(const iterator &o) = default; + iterator(iterator &&o) = default; + + iterator& operator=(const iterator &o) = default; + iterator& operator=(iterator &&o) = default; + + const die &operator*() const + { + return d; + } + + const die *operator->() const + { + return &d; + } + + // XXX Make this less confusing by implementing operator== instead + bool operator!=(const iterator &o) const + { + // Quick test of abbrevs. In particular, this weeds + // out non-end against end, which is a common + // comparison while iterating, though it also weeds + // out many other things. + if (d.abbrev != o.d.abbrev) + return true; + + // Same, possibly NULL abbrev. If abbrev is NULL, + // then next's are uncomparable, so we need to stop + // now. We consider all ends to be the same, without + // comparing cu's. + if (d.abbrev == nullptr) + return false; + + // Comparing two non-end abbrevs. + return d.next != o.d.next || d.cu != o.d.cu; + } + + iterator &operator++(); + +private: + friend class die; + + iterator(const unit *cu, section_offset off); + + die d; +}; + +inline die::iterator +die::end() const +{ + return iterator(); +} + +/** + * An exception indicating that a value is not of the requested type. + */ +class value_type_mismatch : public std::logic_error +{ +public: + explicit value_type_mismatch(const std::string &what_arg) + : std::logic_error(what_arg) { } + explicit value_type_mismatch(const char *what_arg) + : std::logic_error(what_arg) { } +}; + +/** + * The value of a DIE attribute. + * + * This is logically a union of many different types. Each type has a + * corresponding as_* methods that will return the value as that type + * or throw value_type_mismatch if the attribute is not of the + * requested type. + * + * Values of "constant" type are somewhat ambiguous and + * context-dependent. Constant forms with specified signed-ness have + * type "uconstant" or "sconstant", while other constant forms have + * type "constant". If the value's type is "constant", it can be + * retrieved using either as_uconstant or as_sconstant. + * + * Some other types can also be coerced. These are documented on the + * individual as_* methods. + * + * There is no as_line; while there is an attribute for line tables, + * line tables are really associated with compilation units (and + * require additional context from the compilation unit). Use + * compilation_unit::get_line_table instead. + */ +class value +{ +public: + enum class type + { + invalid, + address, + block, + constant, + uconstant, + sconstant, + exprloc, + flag, + line, + loclist, + mac, + rangelist, + reference, + string + }; + + /** + * Construct a value with type `type::invalid`. + */ + value() : cu(nullptr), typ(type::invalid) { } + + value(const value &o) = default; + value(value &&o) = default; + + value& operator=(const value &o) = default; + value& operator=(value &&o) = default; + + /** + * Return true if this object represents a valid value. + * Default constructed line tables are not valid. + */ + bool valid() const + { + return typ != type::invalid; + } + + /** + * Return this value's byte offset within its compilation + * unit. + */ + section_offset get_unit_offset() const + { + return offset; + } + + /** + * Return this value's byte offset within its section. + */ + section_offset get_section_offset() const; + + type get_type() const + { + return typ; + } + + /** + * Return this value's attribute encoding. This automatically + * resolves indirect encodings, so this will never return + * DW_FORM::indirect. Note that the mapping from forms to + * types is non-trivial and often depends on the attribute + * (especially prior to DWARF 4). + */ + DW_FORM get_form() const + { + return form; + } + + /** + * Return this value as a target machine address. + */ + taddr as_address() const; + + /** + * Return this value as a block. The returned pointer points + * directly into the section data, so the caller must ensure + * that remains valid as long as the data is in use. + * *size_out is set to the length of the returned block, in + * bytes. + * + * This automatically coerces "exprloc" type values by + * returning the raw bytes of the encoded expression. + */ + const void *as_block(size_t *size_out) const; + + /** + * Return this value as an unsigned constant. This + * automatically coerces "constant" type values by + * interpreting their bytes as unsigned. + */ + uint64_t as_uconstant() const; + + /** + * Return this value as a signed constant. This automatically + * coerces "constant" type values by interpreting their bytes + * as twos-complement signed values. + */ + int64_t as_sconstant() const; + + /** + * Return this value as an expression. This automatically + * coerces "block" type values by interpreting the bytes in + * the block as an expression (prior to DWARF 4, exprlocs were + * always encoded as blocks, though the library automatically + * distinguishes these types based on context). + */ + expr as_exprloc() const; + + /** + * Return this value as a boolean flag. + */ + bool as_flag() const; + + // XXX loclistptr, macptr + + /** + * Return this value as a rangelist. + */ + rangelist as_rangelist() const; + + /** + * For a reference type value, return the referenced DIE. + * This DIE may be in a different compilation unit or could + * be a DIE in a type unit. + */ + die as_reference() const; + + /** + * Return this value as a string. + */ + std::string as_string() const; + + /** + * Fill the given string buffer with the string value of this + * value. This is useful to minimize allocation when reading + * several string-type values. + */ + void as_string(std::string &buf) const; + + /** + * Return this value as a NUL-terminated character string. + * The returned pointer points directly into the section data, + * so the caller must ensure that remains valid as long as the + * data is in use. *size_out, if not NULL, is set to the + * length of the returned string without the NUL-terminator. + */ + const char *as_cstr(size_t *size_out = nullptr) const; + + /** + * Return this value as a section offset. This is applicable + * to lineptr, loclistptr, macptr, and rangelistptr. + */ + section_offset as_sec_offset() const; + +private: + friend class die; + + value(const unit *cu, + DW_AT name, DW_FORM form, type typ, section_offset offset); + + void resolve_indirect(DW_AT name); + + const unit *cu; + DW_FORM form; + type typ; + section_offset offset; +}; + +std::string +to_string(value::type v); + +std::string +to_string(const value &v); + +////////////////////////////////////////////////////////////////// +// Expressions and location descriptions +// + +/** + * An exception during expression evaluation. + */ +class expr_error : public std::runtime_error +{ +public: + explicit expr_error(const std::string &what_arg) + : std::runtime_error(what_arg) { } + explicit expr_error(const char *what_arg) + : std::runtime_error(what_arg) { } +}; + +/** + * A DWARF expression or location description. + */ +class expr +{ +public: + /** + * Short-hand for evaluate(ctx, {}). + */ + expr_result evaluate(expr_context *ctx) const; + + /** + * Short-hand for evaluate(ctx, {argument}). + */ + expr_result evaluate(expr_context *ctx, taddr argument) const; + + /** + * Return the result of evaluating this expression using the + * specified expression context. The expression stack will be + * initialized with the given arguments such that the first + * arguments is at the top of the stack and the last argument + * at the bottom of the stack. + * + * Throws expr_error if there is an error evaluating the + * expression (such as an unknown operation, stack underflow, + * bounds error, etc.) + */ + expr_result evaluate(expr_context *ctx, const std::initializer_list &arguments) const; + +private: + // XXX This will need more information for some operations + expr(const unit *cu, + section_offset offset, section_length len); + + friend class value; + + const unit *cu; + section_offset offset; + section_length len; +}; + +/** + * An interface that provides contextual information for expression + * evaluation. Callers of expr::evaluate are expected to subclass + * this in order to provide this information to the expression + * evaluation engine. The default implementation throws expr_error + * for all methods. + */ +class expr_context +{ +public: + virtual ~expr_context() { } + + /** + * Return the value stored in register regnum. This is used + * to implement DW_OP_breg* operations. + */ + virtual taddr reg([[gnu::unused]] unsigned regnum) + { + throw expr_error("DW_OP_breg* operations not supported"); + } + + /** + * Implement DW_OP_deref_size. + */ + virtual taddr deref_size([[gnu::unused]] taddr address, [[gnu::unused]] unsigned size) + { + throw expr_error("DW_OP_deref_size operations not supported"); + } + + /** + * Implement DW_OP_xderef_size. + */ + virtual taddr xderef_size([[gnu::unused]] taddr address, [[gnu::unused]] taddr asid, [[gnu::unused]] unsigned size) + { + throw expr_error("DW_OP_xderef_size operations not supported"); + } + + /** + * Implement DW_OP_form_tls_address. + */ + virtual taddr form_tls_address([[gnu::unused]] taddr address) + { + throw expr_error("DW_OP_form_tls_address operations not supported"); + } +}; + +/** + * An instance of expr_context that throws expr_error for all methods. + * This is equivalent to the default construction of expr_context, but + * often more convenient to use. + */ +extern expr_context no_expr_context; + +// XXX Provide methods to check type and fetch value? +/** + * The result of evaluating a DWARF expression or location + * description. + */ +class expr_result +{ +public: + enum class type { + /** + * value specifies the address in memory of an object. + * This is also the result type used for general + * expressions that do not refer to object locations. + */ + address, + /** + * value specifies a register storing an object. + */ + reg, + /** + * The object does not have a location. value is the + * value of the object. + */ + literal, + /** + * The object does not have a location. Its value is + * pointed to by the 'implicit' field. + */ + implicit, + /** + * The object is present in the source, but not in the + * object code, and hence does not have a location or + * a value. + */ + empty, + }; + + /** + * For location descriptions, the type of location this result + * describes. + */ + type location_type; + + /** + * For general-purpose expressions, the result of expression. + * For address location descriptions, the address in memory of + * the object. For register location descriptions, the + * register storing the object. For literal location + * descriptions, the value of the object. + */ + taddr value; + + /** + * For implicit location descriptions, a pointer to a block + * representing the value in the memory representation of the + * target machine. + */ + const char *implicit; + size_t implicit_len; + + // XXX Composite locations +}; + +std::string +to_string(expr_result::type v); + +////////////////////////////////////////////////////////////////// +// Range lists +// + +/** + * A DWARF range list describing a set of possibly non-contiguous + * addresses. + */ +class rangelist +{ +public: + /** + * \internal Construct a range list whose data begins at the + * given offset in sec. cu_addr_size is the address size of + * the associated compilation unit. cu_low_pc is the + * DW_AT::low_pc attribute of the compilation unit containing + * the referring DIE or 0 (this is used as the base address of + * the range list). + */ + rangelist(const std::shared_ptr
&sec, section_offset off, + unsigned cu_addr_size, taddr cu_low_pc); + + /** + * Construct a range list from a sequence of {low, high} + * pairs. + */ + rangelist(const std::initializer_list > &ranges); + + /** + * Construct an empty range list. + */ + rangelist() = default; + + /** Copy constructor */ + rangelist(const rangelist &o) = default; + /** Move constructor */ + rangelist(rangelist &&o) = default; + + rangelist& operator=(const rangelist &o) = default; + rangelist& operator=(rangelist &&o) = default; + + class entry; + typedef entry value_type; + + class iterator; + + /** + * Return an iterator over the entries in this range list. + * The ranges returned by this iterator are temporary, so if + * you need to store a range for more than one loop iteration, + * you must copy it. + */ + iterator begin() const; + + /** + * Return an iterator to one past the last entry in this range + * list. + */ + iterator end() const; + + /** + * Return true if this range list contains the given address. + */ + bool contains(taddr addr) const; + +private: + std::vector synthetic; + std::shared_ptr
sec; + taddr base_addr; +}; + +/** + * An entry in a range list. The range spans addresses [low, high). + */ +class rangelist::entry +{ +public: + taddr low, high; + + /** + * Return true if addr is within this entry's bounds. + */ + bool contains(taddr addr) const + { + return low <= addr && addr < high; + } +}; + +/** + * An iterator over a sequence of ranges in a range list. + */ +class rangelist::iterator +{ +public: + /** + * \internal Construct an end iterator. + */ + iterator() : sec(nullptr), base_addr(0), pos(0) { } + + /** + * \internal Construct an iterator that reads rangelist data + * from the beginning of the given section and starts with the + * given base address. + */ + iterator(const std::shared_ptr
&sec, taddr base_addr); + + /** Copy constructor */ + iterator(const iterator &o) = default; + /** Move constructor */ + iterator(iterator &&o) = default; + + iterator& operator=(const iterator &o) = default; + iterator& operator=(iterator &&o) = default; + + /** + * Return the current range list entry. This entry is reused + * internally, so the caller should copy it if it needs to + * persist past the next increment. + */ + const rangelist::entry &operator*() const + { + return entry; + } + + /** Dereference operator */ + const rangelist::entry *operator->() const + { + return &entry; + } + + /** Equality operator */ + bool operator==(const iterator &o) const + { + return sec == o.sec && pos == o.pos; + } + + /** Inequality operator */ + bool operator!=(const iterator &o) const + { + return !(*this == o); + } + + /** + * Increment this iterator to point to the next range list + * entry. + */ + iterator &operator++(); + +private: + std::shared_ptr
sec; + taddr base_addr; + section_offset pos; + rangelist::entry entry; +}; + +////////////////////////////////////////////////////////////////// +// Line number tables +// + +/** + * A DWARF line number table. A line number table is a list of line + * table entries, broken up into "sequences". Within a sequence, + * entries are in order of increasing program counter ("address") and + * an entry provides information for all program counters between the + * entry's address and the address of the next entry. Each sequence + * is terminated by a special entry with its + * line_table::entry::end_sequence flag set. The line number table + * also records the set of source files for a given compilation unit, + * which can be referred to from other DIE attributes. + */ +class line_table +{ +public: + /** + * \internal Construct a line number table whose header begins + * at the given offset in sec. cu_addr_size is the address + * size of the associated compilation unit. cu_comp_dir and + * cu_name give the DW_AT::comp_dir and DW_AT::name attributes + * of the associated compilation unit. + */ + line_table(const std::shared_ptr
&sec, section_offset offset, + unsigned cu_addr_size, const std::string &cu_comp_dir, + const std::string &cu_name); + + /** + * Construct an invalid, empty line table. + */ + line_table() = default; + + /** Copy constructor */ + line_table(const line_table &o) = default; + /** Move constructor */ + line_table(line_table &&o) = default; + + line_table &operator=(const line_table &o) = default; + line_table &operator=(line_table &&o) = default; + + /** + * Return true if this object represents an initialized line + * table. Default constructed line tables are not valid. + */ + bool valid() const + { + return !!m; + } + + class file; + class entry; + typedef entry value_type; + + class iterator; + + /** + * Return an iterator to the beginning of this line number + * table. If called on an invalid line table, this will + * return an iterator equal to end(). + */ + iterator begin() const; + + /** + * Return an iterator to one past the last entry in this line + * number table. + */ + iterator end() const; + + /** + * Return an iterator to the line table entry containing addr + * (roughly, the entry with the highest address less than or + * equal to addr, but accounting for end_sequence entries). + * Returns end() if there is no such entry. + */ + iterator find_address(taddr addr) const; + + /** + * Return the index'th file in the line table. These indexes + * are typically used by declaration and call coordinates. If + * index is out of range, throws out_of_range. + */ + const file *get_file(unsigned index) const; + +private: + friend class iterator; + + struct impl; + std::shared_ptr m; +}; + +/** + * A source file in a line table. + */ +class line_table::file +{ +public: + /** + * The absolute path of this source file. + */ + std::string path; + + /** + * The last modification time of this source file in an + * implementation-defined encoding or 0 if unknown. + */ + uint64_t mtime; + + /** + * The size in bytes of this source file or 0 if unknown. + */ + uint64_t length; + + /** + * Construct a source file object. + */ + file(std::string path = "", uint64_t mtime = 0, uint64_t length = 0); +}; + +/** + * An entry in the line table. + */ +class line_table::entry +{ +public: + /** + * The program counter value corresponding to a machine + * instruction generated by the compiler. + */ + taddr address; + + /** + * The index of an operation within a VLIW instruction. The + * index of the first operation is 0. For non-VLIW + * architectures, this will always be 0. + */ + unsigned op_index; + + /** + * The source file containing this instruction. + */ + const line_table::file *file; + + /** + * The index of the source file containing this instruction. + */ + unsigned file_index; + + /** + * The source line number of this instruction, starting at 1. + * This may be 0 if this instruction cannot be attributed to + * any source line. + */ + unsigned line; + + /** + * The column number within this source line, starting at 1. + * The value 0 indicates that a statement begins at the "left + * edge" of the line, whatever that means. + */ + unsigned column; + + /** + * True if this instruction is a recommended breakpoint + * location. Typically this is the beginning of a statement. + */ + bool is_stmt; + + /** + * True if this instruction is the beginning of a basic block. + */ + bool basic_block; + + /** + * True if this address is the first byte after the end of a + * sequence of target machine instructions. In this case, all + * other fields besides address are not meaningful. + */ + bool end_sequence; + + /** + * True if this address is one where execution should be + * suspended for an entry breakpoint of a function. + */ + bool prologue_end; + + /** + * True if this address is one where execution should be + * suspended for an exit breakpoint of a function. + */ + bool epilogue_begin; + + /** + * The instruction set architecture of this instruction. The + * meaning of this field is generally defined by an + * architecture's ABI. + */ + unsigned isa; + + /** + * A number that identifies the block containing the current + * instruction if multiple blocks are associated with the same + * source file, line, and column. + */ + unsigned discriminator; + + /** + * Reset this line info object to the default initial values + * for all fields. is_stmt has no default value, so the + * caller must provide it. + */ + void reset(bool is_stmt); + + /** + * Return a descriptive string of the form + * "filename[:line[:column]]". + */ + std::string get_description() const; +}; + +/** + * An iterator over the entries in a line table. + */ +class line_table::iterator +{ +public: + /** + * \internal Construct an iterator for the given line table + * starting pos bytes into the table's section. + */ + iterator(const line_table *table, section_offset pos); + + /** Copy constructor */ + iterator(const iterator &o) = default; + /** Move constructor */ + iterator(iterator &&o) = default; + + iterator &operator=(const iterator &o) = default; + iterator &operator=(iterator &&o) = default; + + /** + * Return the current line table entry. This entry is reused + * internally, so the caller should copy it if it needs to + * persist past the next increment. + */ + const line_table::entry &operator*() const + { + return entry; + } + + /** Dereference operator */ + const line_table::entry *operator->() const + { + return &entry; + } + + /** Equality operator */ + bool operator==(const iterator &o) const + { + return o.pos == pos && o.table == table; + } + + /** Inequality operator */ + bool operator!=(const iterator &o) const + { + return !(*this == o); + } + + /** + * Increment this iterator to point to the next line table + * entry. + */ + iterator &operator++(); + + /** Post-increment operator */ + iterator operator++(int) + { + iterator tmp(*this); + ++(*this); + return tmp; + } + +private: + const line_table *table; + line_table::entry entry, regs; + section_offset pos; + + /** + * Process the next opcode. If the opcode "adds a row to the + * table", update entry to reflect the row and return true. + */ + bool step(cursor *cur); +}; + +////////////////////////////////////////////////////////////////// +// Type-safe attribute getters +// + +// XXX More + +die at_abstract_origin(const die &d); +DW_ACCESS at_accessibility(const die &d); +uint64_t at_allocated(const die &d, expr_context *ctx); +bool at_artificial(const die &d); +uint64_t at_associated(const die &d, expr_context *ctx); +uint64_t at_bit_offset(const die &d, expr_context *ctx); +uint64_t at_bit_size(const die &d, expr_context *ctx); +uint64_t at_bit_stride(const die &d, expr_context *ctx); +uint64_t at_byte_size(const die &d, expr_context *ctx); +uint64_t at_byte_stride(const die &d, expr_context *ctx); +DW_CC at_calling_convention(const die &d); +die at_common_reference(const die &d); +std::string at_comp_dir(const die &d); +value at_const_value(const die &d); +bool at_const_expr(const die &d); +die at_containing_type(const die &d); +uint64_t at_count(const die &d, expr_context *ctx); +expr_result at_data_member_location(const die &d, expr_context *ctx, taddr base, taddr pc); +bool at_declaration(const die &d); +std::string at_description(const die &d); +die at_discr(const die &d); +value at_discr_value(const die &d); +bool at_elemental(const die &d); +DW_ATE at_encoding(const die &d); +DW_END at_endianity(const die &d); +taddr at_entry_pc(const die &d); +bool at_enum_class(const die &d); +bool at_explicit(const die &d); +die at_extension(const die &d); +bool at_external(const die &d); +die at_friend(const die &d); +taddr at_high_pc(const die &d); +DW_ID at_identifier_case(const die &d); +die at_import(const die &d); +DW_INL at_inline(const die &d); +bool at_is_optional(const die &d); +DW_LANG at_language(const die &d); +std::string at_linkage_name(const die &d); +taddr at_low_pc(const die &d); +uint64_t at_lower_bound(const die &d, expr_context *ctx); +bool at_main_subprogram(const die &d); +bool at_mutable(const die &d); +std::string at_name(const die &d); +die at_namelist_item(const die &d); +die at_object_pointer(const die &d); +DW_ORD at_ordering(const die &d); +std::string at_picture_string(const die &d); +die at_priority(const die &d); +std::string at_producer(const die &d); +bool at_prototyped(const die &d); +bool at_pure(const die &d); +rangelist at_ranges(const die &d); +bool at_recursive(const die &d); +die at_sibling(const die &d); +die at_signature(const die &d); +die at_small(const die &d); +die at_specification(const die &d); +bool at_threads_scaled(const die &d); +die at_type(const die &d); +uint64_t at_upper_bound(const die &d, expr_context *ctx); +bool at_use_UTF8(const die &d); +bool at_variable_parameter(const die &d); +DW_VIRTUALITY at_virtuality(const die &d); +DW_VIS at_visibility(const die &d); + +/** + * Return the PC range spanned by the code of a DIE. The DIE must + * either have DW_AT::ranges or DW_AT::low_pc. It may optionally have + * DW_AT::high_pc. + */ +rangelist die_pc_range(const die &d); + +////////////////////////////////////////////////////////////////// +// Utilities +// + +/** + * An index of sibling DIEs by some string attribute. This index is + * lazily constructed and space-efficient. + */ +class die_str_map +{ +public: + /** + * Construct the index of the attr attribute of all immediate + * children of parent whose tags are in accept. + */ + die_str_map(const die &parent, DW_AT attr, + const std::initializer_list &accept); + + die_str_map() = default; + die_str_map(const die_str_map &o) = default; + die_str_map(die_str_map &&o) = default; + + die_str_map& operator=(const die_str_map &o) = default; + die_str_map& operator=(die_str_map &&o) = default; + + /** + * Construct a string map for the type names of parent's + * immediate children. + * + * XXX This should use .debug_pubtypes if parent is a compile + * unit's root DIE, but it currently does not. + */ + static die_str_map from_type_names(const die &parent); + + /** + * Return the DIE whose attribute matches val. If no such DIE + * exists, return an invalid die object. + */ + const die &operator[](const char *val) const; + + /** + * Short-hand for [value.c_str()]. + */ + const die &operator[](const std::string &val) const + { + return (*this)[val.c_str()]; + } + +private: + struct impl; + std::shared_ptr m; +}; + +////////////////////////////////////////////////////////////////// +// ELF support +// + +namespace elf +{ + /** + * Translate an ELF section name info a DWARF section type. + * If the section is a valid DWARF section name, sets *out to + * the type and returns true. If not, returns false. + */ + bool section_name_to_type(const char *name, section_type *out); + + /** + * Translate a DWARF section type into an ELF section name. + */ + const char *section_type_to_name(section_type type); + + template + class elf_loader : public loader + { + Elf f; + + public: + elf_loader(const Elf &file) : f(file) { } + + const void *load(section_type section, size_t *size_out) + { + auto sec = f.get_section(section_type_to_name(section)); + if (!sec.valid()) + return nullptr; + *size_out = sec.size(); + return sec.data(); + } + }; + + /** + * Create a DWARF section loader backed by the given ELF + * file. This is templatized to eliminate a static dependency + * between the libelf++ and libdwarf++, though it can only + * reasonably be used with elf::elf from libelf++. + */ + template + std::shared_ptr > create_loader(const Elf &f) + { + return std::make_shared >(f); + } +}; + +DWARFPP_END_NAMESPACE + +////////////////////////////////////////////////////////////////// +// Hash specializations +// + +namespace std +{ + template<> + struct hash + { + typedef size_t result_type; + typedef const dwarf::unit &argument_type; + result_type operator()(argument_type a) const + { + return hash()(a.m); + } + }; + + template<> + struct hash + { + typedef size_t result_type; + typedef const dwarf::die &argument_type; + result_type operator()(argument_type a) const; + }; +} + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/dwarf.cc b/pwn/flipper/dist/utils/add-debug/dwarf/dwarf.cc new file mode 100644 index 0000000..9c5454d --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/dwarf.cc @@ -0,0 +1,336 @@ +#include "internal.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +////////////////////////////////////////////////////////////////// +// class dwarf +// + +struct dwarf::impl +{ + impl(const std::shared_ptr &l) + : l(l), have_type_units(false) { } + + std::shared_ptr l; + + std::shared_ptr
sec_info; + std::shared_ptr
sec_abbrev; + + std::vector compilation_units; + + std::unordered_map type_units; + bool have_type_units; + + std::map > sections; +}; + +dwarf::dwarf(const std::shared_ptr &l) + : m(make_shared(l)) +{ + const void *data; + size_t size; + + // Get required sections + data = l->load(section_type::info, &size); + if (!data) + throw format_error("required .debug_info section missing"); + m->sec_info = make_shared
(section_type::info, data, size); + + data = l->load(section_type::abbrev, &size); + if (!data) + throw format_error("required .debug_abbrev section missing"); + m->sec_abbrev = make_shared
(section_type::abbrev, data, size); + + // Get compilation units. Everything derives from these, so + // there's no point in doing it lazily. + cursor infocur(m->sec_info); + while (!infocur.end()) { + // XXX Circular reference. Given that we now require + // the dwarf object to stick around for DIEs, maybe we + // might as well require that for units, too. + m->compilation_units.emplace_back( + *this, infocur.get_section_offset()); + infocur.subsection(); + } +} + +dwarf::~dwarf() +{ +} + +const std::vector & +dwarf::compilation_units() const +{ + static std::vector empty; + if (!m) + return empty; + return m->compilation_units; +} + +const type_unit & +dwarf::get_type_unit(uint64_t type_signature) const +{ + if (!m->have_type_units) { + cursor tucur(get_section(section_type::types)); + while (!tucur.end()) { + // XXX Circular reference + type_unit tu(*this, tucur.get_section_offset()); + m->type_units[tu.get_type_signature()] = tu; + tucur.subsection(); + } + m->have_type_units = true; + } + if (!m->type_units.count(type_signature)) + throw out_of_range("type signature 0x" + to_hex(type_signature)); + return m->type_units[type_signature]; +} + +std::shared_ptr
+dwarf::get_section(section_type type) const +{ + if (type == section_type::info) + return m->sec_info; + if (type == section_type::abbrev) + return m->sec_abbrev; + + auto it = m->sections.find(type); + if (it != m->sections.end()) + return it->second; + + size_t size; + const void *data = m->l->load(type, &size); + if (!data) + throw format_error(std::string(elf::section_type_to_name(type)) + + " section missing"); + m->sections[type] = std::make_shared
(section_type::str, data, size); + return m->sections[type]; +} + +////////////////////////////////////////////////////////////////// +// class unit +// + +/** + * Implementation of a unit. + */ +struct unit::impl +{ + const dwarf file; + const section_offset offset; + const std::shared_ptr
subsec; + const section_offset debug_abbrev_offset; + const section_offset root_offset; + + // Type unit-only values + const uint64_t type_signature; + const section_offset type_offset; + + // Lazily constructed root and type DIEs + die root, type; + + // Lazily constructed line table + line_table lt; + + // Map from abbrev code to abbrev. If the map is dense, it + // will be stored in the vector; otherwise it will be stored + // in the map. + bool have_abbrevs; + std::vector abbrevs_vec; + std::unordered_map abbrevs_map; + + impl(const dwarf &file, section_offset offset, + const std::shared_ptr
&subsec, + section_offset debug_abbrev_offset, section_offset root_offset, + uint64_t type_signature = 0, section_offset type_offset = 0) + : file(file), offset(offset), subsec(subsec), + debug_abbrev_offset(debug_abbrev_offset), + root_offset(root_offset), type_signature(type_signature), + type_offset(type_offset), have_abbrevs(false) { } + + void force_abbrevs(); +}; + +unit::~unit() +{ +} + +const dwarf & +unit::get_dwarf() const +{ + return m->file; +} + +section_offset +unit::get_section_offset() const +{ + return m->offset; +} + +const die& +unit::root() const +{ + if (!m->root.valid()) { + m->force_abbrevs(); + m->root = die(this); + m->root.read(m->root_offset); + } + return m->root; +} + +const std::shared_ptr
& +unit::data() const +{ + return m->subsec; +} + +const abbrev_entry & +unit::get_abbrev(abbrev_code acode) const +{ + if (!m->have_abbrevs) + m->force_abbrevs(); + + if (!m->abbrevs_vec.empty()) { + if (acode >= m->abbrevs_vec.size()) + goto unknown; + const abbrev_entry &entry = m->abbrevs_vec[acode]; + if (entry.code == 0) + goto unknown; + return entry; + } else { + auto it = m->abbrevs_map.find(acode); + if (it == m->abbrevs_map.end()) + goto unknown; + return it->second; + } + +unknown: + throw format_error("unknown abbrev code 0x" + to_hex(acode)); +} + +void +unit::impl::force_abbrevs() +{ + // XXX Compilation units can share abbrevs. Parse each table + // at most once. + if (have_abbrevs) + return; + + // Section 7.5.3 + cursor c(file.get_section(section_type::abbrev), + debug_abbrev_offset); + abbrev_entry entry; + abbrev_code highest = 0; + while (entry.read(&c)) { + abbrevs_map[entry.code] = entry; + if (entry.code > highest) + highest = entry.code; + } + + // Typically, abbrev codes are assigned linearly, so it's more + // space efficient and time efficient to store the table in a + // vector. Convert to a vector if it's dense enough, by some + // rough estimate of "enough". + if (highest * 10 < abbrevs_map.size() * 15) { + // Move the map into the vector + abbrevs_vec.resize(highest + 1); + for (auto &entry : abbrevs_map) + abbrevs_vec[entry.first] = move(entry.second); + abbrevs_map.clear(); + } + + have_abbrevs = true; +} + +////////////////////////////////////////////////////////////////// +// class compilation_unit +// + +compilation_unit::compilation_unit(const dwarf &file, section_offset offset) +{ + // Read the CU header (DWARF4 section 7.5.1.1) + cursor cur(file.get_section(section_type::info), offset); + std::shared_ptr
subsec = cur.subsection(); + cursor sub(subsec); + sub.skip_initial_length(); + uhalf version = sub.fixed(); + if (version < 2 || version > 4) + throw format_error("unknown compilation unit version " + std::to_string(version)); + // .debug_abbrev-relative offset of this unit's abbrevs + section_offset debug_abbrev_offset = sub.offset(); + ubyte address_size = sub.fixed(); + subsec->addr_size = address_size; + + m = make_shared(file, offset, subsec, debug_abbrev_offset, + sub.get_section_offset()); +} + +const line_table & +compilation_unit::get_line_table() const +{ + if (!m->lt.valid()) { + const die &d = root(); + if (!d.has(DW_AT::stmt_list) || !d.has(DW_AT::name) || + !d.has(DW_AT::comp_dir)) + goto done; + + shared_ptr
sec; + try { + sec = m->file.get_section(section_type::line); + } catch (format_error &e) { + goto done; + } + + m->lt = line_table(sec, d[DW_AT::stmt_list].as_sec_offset(), + m->subsec->addr_size, at_comp_dir(d), + at_name(d)); + } +done: + return m->lt; +} + +////////////////////////////////////////////////////////////////// +// class type_unit +// + +type_unit::type_unit(const dwarf &file, section_offset offset) +{ + // Read the type unit header (DWARF4 section 7.5.1.2) + cursor cur(file.get_section(section_type::types), offset); + std::shared_ptr
subsec = cur.subsection(); + cursor sub(subsec); + sub.skip_initial_length(); + uhalf version = sub.fixed(); + if (version != 4) + throw format_error("unknown type unit version " + std::to_string(version)); + // .debug_abbrev-relative offset of this unit's abbrevs + section_offset debug_abbrev_offset = sub.offset(); + ubyte address_size = sub.fixed(); + subsec->addr_size = address_size; + uint64_t type_signature = sub.fixed(); + section_offset type_offset = sub.offset(); + + m = make_shared(file, offset, subsec, debug_abbrev_offset, + sub.get_section_offset(), type_signature, + type_offset); +} + +uint64_t +type_unit::get_type_signature() const +{ + return m->type_signature; +} + +const die & +type_unit::type() const +{ + if (!m->type.valid()) { + m->force_abbrevs(); + m->type = die(this); + m->type.read(m->type_offset); + } + return m->type; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/elf.cc b/pwn/flipper/dist/utils/add-debug/dwarf/elf.cc new file mode 100644 index 0000000..8c637f7 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/elf.cc @@ -0,0 +1,50 @@ +#include "dwarf++.hh" + +#include + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +static const struct +{ + const char *name; + section_type type; +} sections[] = { + {".debug_abbrev", section_type::abbrev}, + {".debug_aranges", section_type::aranges}, + {".debug_frame", section_type::frame}, + {".debug_info", section_type::info}, + {".debug_line", section_type::line}, + {".debug_loc", section_type::loc}, + {".debug_macinfo", section_type::macinfo}, + {".debug_pubnames", section_type::pubnames}, + {".debug_pubtypes", section_type::pubtypes}, + {".debug_ranges", section_type::ranges}, + {".debug_str", section_type::str}, + {".debug_types", section_type::types}, +}; + +bool +elf::section_name_to_type(const char *name, section_type *out) +{ + for (auto &sec : sections) { + if (strcmp(sec.name, name) == 0) { + *out = sec.type; + return true; + } + } + return false; +} + +const char * +elf::section_type_to_name(section_type type) +{ + for (auto &sec : sections) { + if (sec.type == type) + return sec.name; + } + return nullptr; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/expr.cc b/pwn/flipper/dist/utils/add-debug/dwarf/expr.cc new file mode 100644 index 0000000..ed90a2f --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/expr.cc @@ -0,0 +1,418 @@ +#include "internal.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +expr_context no_expr_context; + +expr::expr(const unit *cu, + section_offset offset, section_length len) + : cu(cu), offset(offset), len(len) +{ +} + +expr_result +expr::evaluate(expr_context *ctx) const +{ + return evaluate(ctx, {}); +} + +expr_result +expr::evaluate(expr_context *ctx, taddr argument) const +{ + return evaluate(ctx, {argument}); +} + +expr_result +expr::evaluate(expr_context *ctx, const std::initializer_list &arguments) const +{ + // The stack machine's stack. The top of the stack is + // stack.back(). + // XXX This stack must be in target machine representation, + // since I see both (DW_OP_breg0 (eax): -28; DW_OP_stack_value) + // and (DW_OP_lit1; DW_OP_stack_value). + small_vector stack; + + // Create the initial stack. arguments are in reverse order + // (that is, element 0 is TOS), so reverse it. + stack.reserve(arguments.size()); + for (const taddr *elt = arguments.end() - 1; + elt >= arguments.begin(); elt--) + stack.push_back(*elt); + + // Create a subsection for just this expression so we can + // easily detect the end (including premature end). + auto cusec = cu->data(); + shared_ptr
subsec + (make_shared
(cusec->type, + cusec->begin + offset, len, + cusec->fmt, cusec->addr_size)); + cursor cur(subsec); + + // Prepare the expression result. Some location descriptions + // create the result directly, rather than using the top of + // stack. + expr_result result; + + // 2.6.1.1.4 Empty location descriptions + if (cur.end()) { + result.location_type = expr_result::type::empty; + result.value = 0; + return result; + } + + // Assume the result is an address for now and should be + // grabbed from the top of stack at the end. + result.location_type = expr_result::type::address; + + // Execute! + while (!cur.end()) { +#define CHECK() do { if (stack.empty()) goto underflow; } while (0) +#define CHECKN(n) do { if (stack.size() < n) goto underflow; } while (0) + union + { + uint64_t u; + int64_t s; + } tmp1, tmp2, tmp3; + static_assert(sizeof(tmp1) == sizeof(taddr), "taddr is not 64 bits"); + + // Tell GCC to warn us about missing switch cases, + // even though we have a default case. +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wswitch-enum" + DW_OP op = (DW_OP)cur.fixed(); + switch (op) { + // 2.5.1.1 Literal encodings + case DW_OP::lit0...DW_OP::lit31: + stack.push_back((unsigned)op - (unsigned)DW_OP::lit0); + break; + case DW_OP::addr: + stack.push_back(cur.address()); + break; + case DW_OP::const1u: + stack.push_back(cur.fixed()); + break; + case DW_OP::const2u: + stack.push_back(cur.fixed()); + break; + case DW_OP::const4u: + stack.push_back(cur.fixed()); + break; + case DW_OP::const8u: + stack.push_back(cur.fixed()); + break; + case DW_OP::const1s: + stack.push_back(cur.fixed()); + break; + case DW_OP::const2s: + stack.push_back(cur.fixed()); + break; + case DW_OP::const4s: + stack.push_back(cur.fixed()); + break; + case DW_OP::const8s: + stack.push_back(cur.fixed()); + break; + case DW_OP::constu: + stack.push_back(cur.uleb128()); + break; + case DW_OP::consts: + stack.push_back(cur.sleb128()); + break; + + // 2.5.1.2 Register based addressing + case DW_OP::fbreg: + // XXX + throw runtime_error("DW_OP_fbreg not implemented"); + case DW_OP::breg0...DW_OP::breg31: + tmp1.u = (unsigned)op - (unsigned)DW_OP::breg0; + tmp2.s = cur.sleb128(); + stack.push_back((int64_t)ctx->reg(tmp1.u) + tmp2.s); + break; + case DW_OP::bregx: + tmp1.u = cur.uleb128(); + tmp2.s = cur.sleb128(); + stack.push_back((int64_t)ctx->reg(tmp1.u) + tmp2.s); + break; + + // 2.5.1.3 Stack operations + case DW_OP::dup: + CHECK(); + stack.push_back(stack.back()); + break; + case DW_OP::drop: + CHECK(); + stack.pop_back(); + break; + case DW_OP::pick: + tmp1.u = cur.fixed(); + CHECKN(tmp1.u); + stack.push_back(stack.revat(tmp1.u)); + break; + case DW_OP::over: + CHECKN(2); + stack.push_back(stack.revat(1)); + break; + case DW_OP::swap: + CHECKN(2); + tmp1.u = stack.back(); + stack.back() = stack.revat(1); + stack.revat(1) = tmp1.u; + break; + case DW_OP::rot: + CHECKN(3); + tmp1.u = stack.back(); + stack.back() = stack.revat(1); + stack.revat(1) = stack.revat(2); + stack.revat(2) = tmp1.u; + break; + case DW_OP::deref: + tmp1.u = subsec->addr_size; + goto deref_common; + case DW_OP::deref_size: + tmp1.u = cur.fixed(); + if (tmp1.u > subsec->addr_size) + throw expr_error("DW_OP_deref_size operand exceeds address size"); + deref_common: + CHECK(); + stack.back() = ctx->deref_size(stack.back(), tmp1.u); + break; + case DW_OP::xderef: + tmp1.u = subsec->addr_size; + goto xderef_common; + case DW_OP::xderef_size: + tmp1.u = cur.fixed(); + if (tmp1.u > subsec->addr_size) + throw expr_error("DW_OP_xderef_size operand exceeds address size"); + xderef_common: + CHECKN(2); + tmp2.u = stack.back(); + stack.pop_back(); + stack.back() = ctx->xderef_size(tmp2.u, stack.back(), tmp1.u); + break; + case DW_OP::push_object_address: + // XXX + throw runtime_error("DW_OP_push_object_address not implemented"); + case DW_OP::form_tls_address: + CHECK(); + stack.back() = ctx->form_tls_address(stack.back()); + break; + case DW_OP::call_frame_cfa: + // XXX + throw runtime_error("DW_OP_call_frame_cfa not implemented"); + + // 2.5.1.4 Arithmetic and logical operations +#define UBINOP(binop) \ + do { \ + CHECKN(2); \ + tmp1.u = stack.back(); \ + stack.pop_back(); \ + tmp2.u = stack.back(); \ + stack.back() = tmp2.u binop tmp1.u; \ + } while (0) + case DW_OP::abs: + CHECK(); + tmp1.u = stack.back(); + if (tmp1.s < 0) + tmp1.s = -tmp1.s; + stack.back() = tmp1.u; + break; + case DW_OP::and_: + UBINOP(&); + break; + case DW_OP::div: + CHECKN(2); + tmp1.u = stack.back(); + stack.pop_back(); + tmp2.u = stack.back(); + tmp3.s = tmp1.s / tmp2.s; + stack.back() = tmp3.u; + break; + case DW_OP::minus: + UBINOP(-); + break; + case DW_OP::mod: + UBINOP(%); + break; + case DW_OP::mul: + UBINOP(*); + break; + case DW_OP::neg: + CHECK(); + tmp1.u = stack.back(); + tmp1.s = -tmp1.s; + stack.back() = tmp1.u; + break; + case DW_OP::not_: + CHECK(); + stack.back() = ~stack.back(); + break; + case DW_OP::or_: + UBINOP(|); + break; + case DW_OP::plus: + UBINOP(+); + break; + case DW_OP::plus_uconst: + tmp1.u = cur.uleb128(); + CHECK(); + stack.back() += tmp1.u; + break; + case DW_OP::shl: + CHECKN(2); + tmp1.u = stack.back(); + stack.pop_back(); + tmp2.u = stack.back(); + // C++ does not define what happens if you + // shift by more bits than the width of the + // type, so we handle this case specially + if (tmp1.u < sizeof(tmp2.u)*8) + stack.back() = tmp2.u << tmp1.u; + else + stack.back() = 0; + break; + case DW_OP::shr: + CHECKN(2); + tmp1.u = stack.back(); + stack.pop_back(); + tmp2.u = stack.back(); + // Same as above + if (tmp1.u < sizeof(tmp2.u)*8) + stack.back() = tmp2.u >> tmp1.u; + else + stack.back() = 0; + break; + case DW_OP::shra: + CHECKN(2); + tmp1.u = stack.back(); + stack.pop_back(); + tmp2.u = stack.back(); + // Shifting a negative number is + // implementation-defined in C++. + tmp3.u = (tmp2.s < 0); + if (tmp3.u) + tmp2.s = -tmp2.s; + if (tmp1.u < sizeof(tmp2.u)*8) + tmp2.u >>= tmp1.u; + else + tmp2.u = 0; + // DWARF implies that over-shifting a negative + // number should result in 0, not ~0. + if (tmp3.u) + tmp2.s = -tmp2.s; + stack.back() = tmp2.u; + break; + case DW_OP::xor_: + UBINOP(^); + break; +#undef UBINOP + + // 2.5.1.5 Control flow operations +#define SRELOP(relop) \ + do { \ + CHECKN(2); \ + tmp1.u = stack.back(); \ + stack.pop_back(); \ + tmp2.u = stack.back(); \ + stack.back() = (tmp2.s <= tmp1.s) ? 1 : 0; \ + } while (0) + case DW_OP::le: + SRELOP(<=); + break; + case DW_OP::ge: + SRELOP(>=); + break; + case DW_OP::eq: + SRELOP(==); + break; + case DW_OP::lt: + SRELOP(<); + break; + case DW_OP::gt: + SRELOP(>); + break; + case DW_OP::ne: + SRELOP(!=); + break; + case DW_OP::skip: + tmp1.s = cur.fixed(); + goto skip_common; + case DW_OP::bra: + tmp1.s = cur.fixed(); + CHECK(); + tmp2.u = stack.back(); + stack.pop_back(); + if (tmp2.u == 0) + break; + skip_common: + cur = cursor(subsec, (int64_t)cur.get_section_offset() + tmp1.s); + break; + case DW_OP::call2: + case DW_OP::call4: + case DW_OP::call_ref: + // XXX + throw runtime_error(to_string(op) + " not implemented"); +#undef SRELOP + + // 2.5.1.6 Special operations + case DW_OP::nop: + break; + + // 2.6.1.1.2 Register location descriptions + case DW_OP::reg0...DW_OP::reg31: + result.location_type = expr_result::type::reg; + result.value = (unsigned)op - (unsigned)DW_OP::reg0; + break; + case DW_OP::regx: + result.location_type = expr_result::type::reg; + result.value = cur.uleb128(); + break; + + // 2.6.1.1.3 Implicit location descriptions + case DW_OP::implicit_value: + result.location_type = expr_result::type::implicit; + result.implicit_len = cur.uleb128(); + cur.ensure(result.implicit_len); + result.implicit = cur.pos; + break; + case DW_OP::stack_value: + CHECK(); + result.location_type = expr_result::type::literal; + result.value = stack.back(); + break; + + // 2.6.1.2 Composite location descriptions + case DW_OP::piece: + case DW_OP::bit_piece: + // XXX + throw runtime_error(to_string(op) + " not implemented"); + + case DW_OP::lo_user...DW_OP::hi_user: + // XXX We could let the context evaluate this, + // but it would need access to the cursor. + throw expr_error("unknown user op " + to_string(op)); + + default: + throw expr_error("bad operation " + to_string(op)); + } +#pragma GCC diagnostic pop +#undef CHECK +#undef CHECKN + } + + if (result.location_type == expr_result::type::address) { + // The result type is still and address, so we should + // fetch it from the top of stack. + if (stack.empty()) + throw expr_error("final stack is empty; no result given"); + result.value = stack.back(); + } + + return result; + +underflow: + throw expr_error("stack underflow evaluating DWARF expression"); +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/gen_to_string.sh b/pwn/flipper/dist/utils/add-debug/dwarf/gen_to_string.sh new file mode 100755 index 0000000..19d2f32 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/gen_to_string.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +SOURCE_DIR="$1" +OUTPUT_FILE="$2" + +generate () { + echo "// Automatically generated by gen_to_string.sh at $(date)" + echo "// DO NOT EDIT" + echo + echo '#include "internal.hh"' + echo + echo 'DWARFPP_BEGIN_NAMESPACE' + echo + PYTHON=python + command -v $PYTHON > /dev/null 2>&1 + if [ $? -ne 0 ]; then + PYTHON=python3 + fi + $PYTHON "$SOURCE_DIR"/../elf/enum-print.py < "$SOURCE_DIR"/dwarf++.hh + $PYTHON "$SOURCE_DIR"/../elf/enum-print.py -s _ -u --hex -x hi_user -x lo_user < "$SOURCE_DIR"/data.hh + echo 'DWARFPP_END_NAMESPACE' +} + +generate > "$OUTPUT_FILE" diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/internal.hh b/pwn/flipper/dist/utils/add-debug/dwarf/internal.hh new file mode 100644 index 0000000..e1bca44 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/internal.hh @@ -0,0 +1,260 @@ +#ifndef _DWARFPP_INTERNAL_HH_ +#define _DWARFPP_INTERNAL_HH_ + +#include "dwarf++.hh" +#include "../elf/to_hex.hh" + +#include +#include +#include +#include + +DWARFPP_BEGIN_NAMESPACE + +enum class format +{ + unknown, + dwarf32, + dwarf64 +}; + +/** + * A single DWARF section or a slice of a section. This also tracks + * dynamic information necessary to decode values in this section. + */ +struct section +{ + section_type type; + const char *begin, *end; + const format fmt; + unsigned addr_size; + + section(section_type type, const void *begin, + section_length length, format fmt = format::unknown, + unsigned addr_size = 0) + : type(type), begin((char*)begin), end((char*)begin + length), + fmt(fmt), addr_size(addr_size) { } + + section(const section &o) = default; + + std::shared_ptr
slice(section_offset start, section_length len, + format fmt = format::unknown, + unsigned addr_size = 0) + { + if (fmt == format::unknown) + fmt = this->fmt; + if (addr_size == 0) + addr_size = this->addr_size; + + return std::make_shared
( + type, begin+start, + std::min(len, (section_length)(end-begin)), + fmt, addr_size); + } + + size_t size() const + { + return end - begin; + } +}; + +/** + * A cursor pointing into a DWARF section. Provides deserialization + * operations and bounds checking. + */ +struct cursor +{ + // XXX There's probably a lot of overhead to maintaining the + // shared pointer to the section from this. Perhaps the rule + // should be that all objects keep the dwarf::impl alive + // (directly or indirectly) and that keeps the loader alive, + // so a cursor just needs a regular section*. + + std::shared_ptr
sec; + const char *pos; + + cursor() + : pos(nullptr) { } + cursor(const std::shared_ptr
sec, section_offset offset = 0) + : sec(sec), pos(sec->begin + offset) { } + + /** + * Read a subsection. The cursor must be at an initial + * length. After, the cursor will point just past the end of + * the subsection. The returned section has the appropriate + * DWARF format and begins at the current location of the + * cursor (so this is usually followed by a + * skip_initial_length). + */ + std::shared_ptr
subsection(); + std::int64_t sleb128(); + section_offset offset(); + void string(std::string &out); + const char *cstr(size_t *size_out = nullptr); + + void + ensure(section_offset bytes) + { + if ((section_offset)(sec->end - pos) < bytes || pos >= sec->end) + underflow(); + } + + template + T fixed() + { + ensure(sizeof(T)); + T val = *(T*)pos; + pos += sizeof(T); + return val; + } + + std::uint64_t uleb128() + { + // Appendix C + // XXX Pre-compute all two byte ULEB's + std::uint64_t result = 0; + int shift = 0; + while (pos < sec->end) { + uint8_t byte = *(uint8_t*)(pos++); + result |= (uint64_t)(byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + return result; + shift += 7; + } + underflow(); + return 0; + } + + taddr address() + { + switch (sec->addr_size) { + case 1: + return fixed(); + case 2: + return fixed(); + case 4: + return fixed(); + case 8: + return fixed(); + default: + throw std::runtime_error("address size " + std::to_string(sec->addr_size) + " not supported"); + } + } + + void skip_initial_length(); + void skip_form(DW_FORM form); + + cursor &operator+=(section_offset offset) + { + pos += offset; + return *this; + } + + cursor operator+(section_offset offset) const + { + return cursor(sec, pos + offset); + } + + bool operator<(const cursor &o) const + { + return pos < o.pos; + } + + bool end() const + { + return pos >= sec->end; + } + + bool valid() const + { + return !!pos; + } + + section_offset get_section_offset() const + { + return pos - sec->begin; + } + +private: + cursor(const std::shared_ptr
sec, const char *pos) + : sec(sec), pos(pos) { } + + void underflow(); +}; + +/** + * An attribute specification in an abbrev. + */ +struct attribute_spec +{ + DW_AT name; + DW_FORM form; + + // Computed information + value::type type; + + attribute_spec(DW_AT name, DW_FORM form); +}; + +typedef std::uint64_t abbrev_code; + +/** + * An entry in .debug_abbrev. + */ +struct abbrev_entry +{ + abbrev_code code; + DW_TAG tag; + bool children; + std::vector attributes; + + abbrev_entry() : code(0) { } + + bool read(cursor *cur); +}; + +/** + * A section header in .debug_pubnames or .debug_pubtypes. + */ +struct name_unit +{ + uhalf version; + section_offset debug_info_offset; + section_length debug_info_length; + // Cursor to the first name_entry in this unit. This cursor's + // section is limited to this unit. + cursor entries; + + void read(cursor *cur) + { + // Section 7.19 + std::shared_ptr
subsec = cur->subsection(); + cursor sub(subsec); + sub.skip_initial_length(); + version = sub.fixed(); + if (version != 2) + throw format_error("unknown name unit version " + std::to_string(version)); + debug_info_offset = sub.offset(); + debug_info_length = sub.offset(); + entries = sub; + } +}; + +/** + * An entry in a .debug_pubnames or .debug_pubtypes unit. + */ +struct name_entry +{ + section_offset offset; + std::string name; + + void read(cursor *cur) + { + offset = cur->offset(); + cur->string(name); + } +}; + +DWARFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/line.cc b/pwn/flipper/dist/utils/add-debug/dwarf/line.cc new file mode 100644 index 0000000..ca9ff1e --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/line.cc @@ -0,0 +1,434 @@ +#include "internal.hh" + +#include + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +// The expected number of arguments for standard opcodes. This is +// used to check the opcode_lengths header field for compatibility. +static const int opcode_lengths[] = { + 0, + // DW_LNS::copy + 0, 1, 1, 1, 1, + // DW_LNS::negate_stmt + 0, 0, 0, 1, 0, + // DW_LNS::set_epilogue_begin + 0, 1 +}; + +struct line_table::impl +{ + shared_ptr
sec; + + // Header information + section_offset program_offset; + ubyte minimum_instruction_length; + ubyte maximum_operations_per_instruction; + bool default_is_stmt; + sbyte line_base; + ubyte line_range; + ubyte opcode_base; + vector standard_opcode_lengths; + vector include_directories; + vector file_names; + + // The offset in sec following the last read file name entry. + // File name entries can appear both in the line table header + // and in the line number program itself. Since we can + // iterate over the line number program repeatedly, this keeps + // track of how far we've gotten so we don't add the same + // entry twice. + section_offset last_file_name_end; + // If an iterator has traversed the entire program, then we + // know we've gathered all file names. + bool file_names_complete; + + impl() : last_file_name_end(0), file_names_complete(false) {}; + + bool read_file_entry(cursor *cur, bool in_header); +}; + +line_table::line_table(const shared_ptr
&sec, section_offset offset, + unsigned cu_addr_size, const string &cu_comp_dir, + const string &cu_name) + : m(make_shared()) +{ + // XXX DWARF2 and 3 give a weird specification for DW_AT_comp_dir + + string comp_dir, abs_path; + if (cu_comp_dir.empty() || cu_comp_dir.back() == '/') + comp_dir = cu_comp_dir; + else + comp_dir = cu_comp_dir + '/'; + + // Read the line table header (DWARF2 section 6.2.4, DWARF3 + // section 6.2.4, DWARF4 section 6.2.3) + cursor cur(sec, offset); + m->sec = cur.subsection(); + cur = cursor(m->sec); + cur.skip_initial_length(); + m->sec->addr_size = cu_addr_size; + + // Basic header information + uhalf version = cur.fixed(); + if (version < 2 || version > 4) + throw format_error("unknown line number table version " + + std::to_string(version)); + section_length header_length = cur.offset(); + m->program_offset = cur.get_section_offset() + header_length; + m->minimum_instruction_length = cur.fixed(); + m->maximum_operations_per_instruction = 1; + if (version == 4) + m->maximum_operations_per_instruction = cur.fixed(); + if (m->maximum_operations_per_instruction == 0) + throw format_error("maximum_operations_per_instruction cannot" + " be 0 in line number table"); + m->default_is_stmt = cur.fixed(); + m->line_base = cur.fixed(); + m->line_range = cur.fixed(); + if (m->line_range == 0) + throw format_error("line_range cannot be 0 in line number table"); + m->opcode_base = cur.fixed(); + + static_assert(sizeof(opcode_lengths) / sizeof(opcode_lengths[0]) == 13, + "opcode_lengths table has wrong length"); + + // Opcode length table + m->standard_opcode_lengths.resize(m->opcode_base); + m->standard_opcode_lengths[0] = 0; + for (unsigned i = 1; i < m->opcode_base; i++) { + ubyte length = cur.fixed(); + if (length != opcode_lengths[i]) + // The spec never says what to do if the + // opcode length of a standard opcode doesn't + // match the header. Do the safe thing. + throw format_error( + "expected " + + std::to_string(opcode_lengths[i]) + + " arguments for line number opcode " + + std::to_string(i) + ", got " + + std::to_string(length)); + m->standard_opcode_lengths[i] = length; + } + + // Include directories list + string incdir; + // Include directory 0 is implicitly the compilation unit + // current directory + m->include_directories.push_back(comp_dir); + while (true) { + cur.string(incdir); + if (incdir.empty()) + break; + if (incdir.back() != '/') + incdir += '/'; + if (incdir[0] == '/') + m->include_directories.push_back(move(incdir)); + else + m->include_directories.push_back(comp_dir + incdir); + } + + // File name list + string file_name; + // File name 0 is implicitly the compilation unit file name. + // cu_name can be relative to comp_dir or absolute. + if (!cu_name.empty() && cu_name[0] == '/') + m->file_names.emplace_back(cu_name); + else + m->file_names.emplace_back(comp_dir + cu_name); + while (m->read_file_entry(&cur, true)); +} + +line_table::iterator +line_table::begin() const +{ + if (!valid()) + return iterator(nullptr, 0); + return iterator(this, m->program_offset); +} + +line_table::iterator +line_table::end() const +{ + if (!valid()) + return iterator(nullptr, 0); + return iterator(this, m->sec->size()); +} + +line_table::iterator +line_table::find_address(taddr addr) const +{ + iterator prev = begin(), e = end(); + if (prev == e) + return prev; + + iterator it = prev; + for (++it; it != e; prev = it++) { + if (prev->address <= addr && it->address > addr && + !prev->end_sequence) + return prev; + } + prev = e; + return prev; +} + +const line_table::file * +line_table::get_file(unsigned index) const +{ + if (index >= m->file_names.size()) { + // It could be declared in the line table program. + // This is unlikely, so we don't have to be + // super-efficient about this. Just force our way + // through the whole line table program. + if (!m->file_names_complete) { + for (auto &ent : *this) + (void)ent; + } + if (index >= m->file_names.size()) + throw out_of_range + ("file name index " + std::to_string(index) + + " exceeds file table size of " + + std::to_string(m->file_names.size())); + } + return &m->file_names[index]; +} + +bool +line_table::impl::read_file_entry(cursor *cur, bool in_header) +{ + assert(cur->sec == sec); + + string file_name; + cur->string(file_name); + if (in_header && file_name.empty()) + return false; + uint64_t dir_index = cur->uleb128(); + uint64_t mtime = cur->uleb128(); + uint64_t length = cur->uleb128(); + + // Have we already processed this file entry? + if (cur->get_section_offset() <= last_file_name_end) + return true; + last_file_name_end = cur->get_section_offset(); + + if (file_name[0] == '/') + file_names.emplace_back(move(file_name), mtime, length); + else if (dir_index < include_directories.size()) + file_names.emplace_back( + include_directories[dir_index] + file_name, + mtime, length); + else + throw format_error("file name directory index out of range: " + + std::to_string(dir_index)); + + return true; +} + +line_table::file::file(string path, uint64_t mtime, uint64_t length) + : path(path), mtime(mtime), length(length) +{ +} + +void +line_table::entry::reset(bool is_stmt) +{ + address = op_index = 0; + file = nullptr; + file_index = line = 1; + column = 0; + this->is_stmt = is_stmt; + basic_block = end_sequence = prologue_end = epilogue_begin = false; + isa = discriminator = 0; +} + +string +line_table::entry::get_description() const +{ + string res = file->path; + if (line) { + res.append(":").append(std::to_string(line)); + if (column) + res.append(":").append(std::to_string(column)); + } + return res; +} + +line_table::iterator::iterator(const line_table *table, section_offset pos) + : table(table), pos(pos) +{ + if (table) { + regs.reset(table->m->default_is_stmt); + ++(*this); + } +} + +line_table::iterator & +line_table::iterator::operator++() +{ + cursor cur(table->m->sec, pos); + + // Execute opcodes until we reach the end of the stream or an + // opcode emits a line table row + bool stepped = false, output = false; + while (!cur.end() && !output) { + output = step(&cur); + stepped = true; + } + if (stepped && !output) + throw format_error("unexpected end of line table"); + if (stepped && cur.end()) { + // Record that all file names must be known now + table->m->file_names_complete = true; + } + if (output) { + // Resolve file name of entry + if (entry.file_index < table->m->file_names.size()) + entry.file = &table->m->file_names[entry.file_index]; + else + throw format_error("bad file index " + + std::to_string(entry.file_index) + + " in line table"); + } + + pos = cur.get_section_offset(); + return *this; +} + +bool +line_table::iterator::step(cursor *cur) +{ + struct line_table::impl *m = table->m.get(); + + // Read the opcode (DWARF4 section 6.2.3) + ubyte opcode = cur->fixed(); + if (opcode >= m->opcode_base) { + // Special opcode (DWARF4 section 6.2.5.1) + ubyte adjusted_opcode = opcode - m->opcode_base; + unsigned op_advance = adjusted_opcode / m->line_range; + signed line_inc = m->line_base + (signed)adjusted_opcode % m->line_range; + + regs.line += line_inc; + regs.address += m->minimum_instruction_length * + ((regs.op_index + op_advance) + / m->maximum_operations_per_instruction); + regs.op_index = (regs.op_index + op_advance) + % m->maximum_operations_per_instruction; + entry = regs; + + regs.basic_block = regs.prologue_end = + regs.epilogue_begin = false; + regs.discriminator = 0; + + return true; + } else if (opcode != 0) { + // Standard opcode (DWARF4 sections 6.2.3 and 6.2.5.2) + // + // According to the standard, any opcode between the + // highest defined opcode for a given DWARF version + // and opcode_base should be treated as a + // vendor-specific opcode. However, the de facto + // standard seems to be to process these as standard + // opcodes even if they're from a later version of the + // standard than the line table header claims. + uint64_t uarg; +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wswitch-enum" + switch ((DW_LNS)opcode) { + case DW_LNS::copy: + entry = regs; + regs.basic_block = regs.prologue_end = + regs.epilogue_begin = false; + regs.discriminator = 0; + break; + case DW_LNS::advance_pc: + // Opcode advance (as for special opcodes) + uarg = cur->uleb128(); + advance_pc: + regs.address += m->minimum_instruction_length * + ((regs.op_index + uarg) + / m->maximum_operations_per_instruction); + regs.op_index = (regs.op_index + uarg) + % m->maximum_operations_per_instruction; + break; + case DW_LNS::advance_line: + regs.line = (signed)regs.line + cur->sleb128(); + break; + case DW_LNS::set_file: + regs.file_index = cur->uleb128(); + break; + case DW_LNS::set_column: + regs.column = cur->uleb128(); + break; + case DW_LNS::negate_stmt: + regs.is_stmt = !regs.is_stmt; + break; + case DW_LNS::set_basic_block: + regs.basic_block = true; + break; + case DW_LNS::const_add_pc: + uarg = (255 - m->opcode_base) / m->line_range; + goto advance_pc; + case DW_LNS::fixed_advance_pc: + regs.address += cur->fixed(); + regs.op_index = 0; + break; + case DW_LNS::set_prologue_end: + regs.prologue_end = true; + break; + case DW_LNS::set_epilogue_begin: + regs.epilogue_begin = true; + break; + case DW_LNS::set_isa: + regs.isa = cur->uleb128(); + break; + default: + // XXX Vendor extensions + throw format_error("unknown line number opcode " + + to_string((DW_LNS)opcode)); + } + return ((DW_LNS)opcode == DW_LNS::copy); + } else { // opcode == 0 + // Extended opcode (DWARF4 sections 6.2.3 and 6.2.5.3) + assert(opcode == 0); + uint64_t length = cur->uleb128(); + section_offset end = cur->get_section_offset() + length; + opcode = cur->fixed(); + switch ((DW_LNE)opcode) { + case DW_LNE::end_sequence: + regs.end_sequence = true; + entry = regs; + regs.reset(m->default_is_stmt); + break; + case DW_LNE::set_address: + regs.address = cur->address(); + regs.op_index = 0; + break; + case DW_LNE::define_file: + m->read_file_entry(cur, false); + break; + case DW_LNE::set_discriminator: + // XXX Only DWARF4 + regs.discriminator = cur->uleb128(); + break; + case DW_LNE::lo_user...DW_LNE::hi_user: + // XXX Vendor extensions + throw runtime_error("vendor line number opcode " + + to_string((DW_LNE)opcode) + + " not implemented"); + default: + // XXX Prior to DWARF4, any opcode number + // could be a vendor extension + throw format_error("unknown line number opcode " + + to_string((DW_LNE)opcode)); + } +#pragma GCC diagnostic pop + if (cur->get_section_offset() > end) + throw format_error("extended line number opcode exceeded its size"); + cur += end - cur->get_section_offset(); + return ((DW_LNE)opcode == DW_LNE::end_sequence); + } +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/rangelist.cc b/pwn/flipper/dist/utils/add-debug/dwarf/rangelist.cc new file mode 100644 index 0000000..1ad1553 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/rangelist.cc @@ -0,0 +1,99 @@ +#include "internal.hh" + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +rangelist::rangelist(const std::shared_ptr
&sec, section_offset off, + unsigned cu_addr_size, taddr cu_low_pc) + : sec(sec->slice(off, ~0, format::unknown, cu_addr_size)), + base_addr(cu_low_pc) +{ +} + +rangelist::rangelist(const initializer_list > &ranges) +{ + synthetic.reserve(ranges.size() * 2 + 2); + for (auto &range : ranges) { + synthetic.push_back(range.first); + synthetic.push_back(range.second); + } + synthetic.push_back(0); + synthetic.push_back(0); + + sec = make_shared
( + section_type::ranges, (const char*)synthetic.data(), + synthetic.size() * sizeof(taddr), format::unknown, + sizeof(taddr)); + + base_addr = 0; +} + +rangelist::iterator +rangelist::begin() const +{ + if (sec) + return iterator(sec, base_addr); + return end(); +} + +rangelist::iterator +rangelist::end() const +{ + return iterator(); +} + +bool +rangelist::contains(taddr addr) const +{ + for (auto ent : *this) + if (ent.contains(addr)) + return true; + return false; +} + +rangelist::iterator::iterator(const std::shared_ptr
&sec, taddr base_addr) + : sec(sec), base_addr(base_addr), pos(0) +{ + // Read in the first entry + ++(*this); +} + +rangelist::iterator & +rangelist::iterator::operator++() +{ + // DWARF4 section 2.17.3 + taddr largest_offset = ~(taddr)0; + if (sec->addr_size < sizeof(taddr)) + largest_offset += 1 << (8 * sec->addr_size); + + // Read in entries until we reach a regular entry of an + // end-of-list. Note that pos points to the beginning of the + // entry *following* the current entry, so that's where we + // start. + cursor cur(sec, pos); + while (true) { + entry.low = cur.address(); + entry.high = cur.address(); + + if (entry.low == 0 && entry.high == 0) { + // End of list + sec.reset(); + pos = 0; + break; + } else if (entry.low == largest_offset) { + // Base address change + base_addr = entry.high; + } else { + // Regular entry. Adjust by base address. + entry.low += base_addr; + entry.high += base_addr; + pos = cur.get_section_offset(); + break; + } + } + + return *this; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/small_vector.hh b/pwn/flipper/dist/utils/add-debug/dwarf/small_vector.hh new file mode 100644 index 0000000..d96d910 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/small_vector.hh @@ -0,0 +1,195 @@ +#ifndef _DWARFPP_SMALL_VECTOR_HH_ +#define _DWARFPP_SMALL_VECTOR_HH_ + +DWARFPP_BEGIN_NAMESPACE + +/** + * A vector-like class that only heap allocates above a specified + * size. + */ +template +class small_vector +{ +public: + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + small_vector() + : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) + { + } + + small_vector(const small_vector &o) + : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) + { + *this = o; + } + + small_vector(small_vector &&o) + : base((T*)buf), end(base), cap((T*)&buf[sizeof(T[Min])]) + { + if ((char*)o.base == o.buf) { + // Elements are inline; have to copy them + base = (T*)buf; + end = base; + cap = (T*)&buf[sizeof(T[Min])]; + + *this = o; + o.clear(); + } else { + // Elements are external; swap pointers + base = o.base; + end = o.end; + cap = o.cap; + + o.base = (T*)o.buf; + o.end = o.base; + o.cap = (T*)&o.buf[sizeof(T[Min])]; + } + } + + ~small_vector() + { + clear(); + if ((char*)base != buf) + delete[] (char*)base; + } + + small_vector &operator=(const small_vector &o) + { + size_type osize = o.size(); + clear(); + reserve(osize); + for (size_type i = 0; i < osize; i++) + new (&base[i]) T(o[i]); + end = base + osize; + return *this; + } + + size_type size() const + { + return end - base; + } + + bool empty() const + { + return base == end; + } + + void reserve(size_type n) + { + if (n <= (size_type)(cap - base)) + return; + + size_type target = cap - base; + if (target == 0) + target = 1; + while (target < n) + target <<= 1; + + char *newbuf = new char[sizeof(T[target])]; + T *src = base, *dest = (T*)newbuf; + for (; src < end; src++, dest++) { + new(dest) T(*src); + dest->~T(); + } + if ((char*)base != buf) + delete[] (char*)base; + base = (T*)newbuf; + end = dest; + cap = base + target; + } + + reference operator[](size_type n) + { + return base[n]; + } + + const_reference operator[](size_type n) const + { + return base[n]; + } + + reference at(size_type n) + { + return base[n]; + } + + const_reference at(size_type n) const + { + return base[n]; + } + + /** + * "Reverse at". revat(0) is equivalent to back(). revat(1) + * is the element before back. Etc. + */ + reference revat(size_type n) + { + return *(end - 1 - n); + } + + const_reference revat(size_type n) const + { + return *(end - 1 - n); + } + + reference front() + { + assert(base.size() >= 1); + return base[0]; + } + + const_reference front() const + { + assert(base.size() >= 1); + return base[0]; + } + + reference back() + { + return *(end-1); + } + + const_reference back() const + { + return *(end-1); + } + + void push_back(const T& x) + { + reserve(size() + 1); + new (end) T(x); + end++; + } + + void push_back(T&& x) + { + reserve(size() + 1); + new (end) T(std::move(x)); + end++; + } + + void pop_back() + { + end--; + end->~T(); + } + + void clear() + { + for (T* p = base; p < end; ++p) + p->~T(); + end = base; + } + +private: + char buf[sizeof(T[Min])]; + T *base, *end, *cap; +}; + +DWARFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/dwarf/value.cc b/pwn/flipper/dist/utils/add-debug/dwarf/value.cc new file mode 100644 index 0000000..829e8d4 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/dwarf/value.cc @@ -0,0 +1,332 @@ +#include "internal.hh" + +#include + +using namespace std; + +DWARFPP_BEGIN_NAMESPACE + +value::value(const unit *cu, + DW_AT name, DW_FORM form, type typ, section_offset offset) + : cu(cu), form(form), typ(typ), offset(offset) { + if (form == DW_FORM::indirect) + resolve_indirect(name); +} + +section_offset +value::get_section_offset() const +{ + return cu->get_section_offset() + offset; +} + +taddr +value::as_address() const +{ + if (form != DW_FORM::addr) + throw value_type_mismatch("cannot read " + to_string(typ) + " as address"); + + cursor cur(cu->data(), offset); + return cur.address(); +} + +const void * +value::as_block(size_t *size_out) const +{ + // XXX Blocks can contain all sorts of things, including + // references, which couldn't be resolved by callers in the + // current minimal API. + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::block1: + *size_out = cur.fixed(); + break; + case DW_FORM::block2: + *size_out = cur.fixed(); + break; + case DW_FORM::block4: + *size_out = cur.fixed(); + break; + case DW_FORM::block: + case DW_FORM::exprloc: + *size_out = cur.uleb128(); + break; + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as block"); + } + cur.ensure(*size_out); + return cur.pos; +} + +uint64_t +value::as_uconstant() const +{ + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::data1: + return cur.fixed(); + case DW_FORM::data2: + return cur.fixed(); + case DW_FORM::data4: + return cur.fixed(); + case DW_FORM::data8: + return cur.fixed(); + case DW_FORM::udata: + return cur.uleb128(); + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as uconstant"); + } +} + +int64_t +value::as_sconstant() const +{ + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::data1: + return cur.fixed(); + case DW_FORM::data2: + return cur.fixed(); + case DW_FORM::data4: + return cur.fixed(); + case DW_FORM::data8: + return cur.fixed(); + case DW_FORM::sdata: + return cur.sleb128(); + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as sconstant"); + } +} + +expr +value::as_exprloc() const +{ + cursor cur(cu->data(), offset); + size_t size; + // Prior to DWARF 4, exprlocs were encoded as blocks. + switch (form) { + case DW_FORM::exprloc: + case DW_FORM::block: + size = cur.uleb128(); + break; + case DW_FORM::block1: + size = cur.fixed(); + break; + case DW_FORM::block2: + size = cur.fixed(); + break; + case DW_FORM::block4: + size = cur.fixed(); + break; + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as exprloc"); + } + return expr(cu, cur.get_section_offset(), size); +} + +bool +value::as_flag() const +{ + switch (form) { + case DW_FORM::flag: { + cursor cur(cu->data(), offset); + return cur.fixed() != 0; + } + case DW_FORM::flag_present: + return true; + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as flag"); + } +} + +rangelist +value::as_rangelist() const +{ + section_offset off = as_sec_offset(); + + // The compilation unit may not have a base address. In this + // case, the first entry in the range list must be a base + // address entry, but we'll just assume 0 for the initial base + // address. + die cudie = cu->root(); + taddr cu_low_pc = cudie.has(DW_AT::low_pc) ? at_low_pc(cudie) : 0; + auto sec = cu->get_dwarf().get_section(section_type::ranges); + auto cusec = cu->data(); + return rangelist(sec, off, cusec->addr_size, cu_low_pc); +} + +die +value::as_reference() const +{ + section_offset off; + // XXX Would be nice if we could avoid this. The cursor is + // all overhead here. + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::ref1: + off = cur.fixed(); + break; + case DW_FORM::ref2: + off = cur.fixed(); + break; + case DW_FORM::ref4: + off = cur.fixed(); + break; + case DW_FORM::ref8: + off = cur.fixed(); + break; + case DW_FORM::ref_udata: + off = cur.uleb128(); + break; + + case DW_FORM::ref_addr: { + off = cur.offset(); + // These seem to be extremely rare in practice (I + // haven't been able to get gcc to produce a + // ref_addr), so it's not worth caching this lookup. + const compilation_unit *base_cu = nullptr; + for (auto &file_cu : cu->get_dwarf().compilation_units()) { + if (file_cu.get_section_offset() > off) + break; + base_cu = &file_cu; + } + die d(base_cu); + d.read(off - base_cu->get_section_offset()); + return d; + } + + case DW_FORM::ref_sig8: { + uint64_t sig = cur.fixed(); + try { + return cu->get_dwarf().get_type_unit(sig).type(); + } catch (std::out_of_range &e) { + throw format_error("unknown type signature 0x" + to_hex(sig)); + } + } + + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as reference"); + } + + die d(cu); + d.read(off); + return d; +} + +void +value::as_string(string &buf) const +{ + size_t size; + const char *p = as_cstr(&size); + buf.resize(size); + memmove(&buf.front(), p, size); +} + +string +value::as_string() const +{ + size_t size; + const char *s = as_cstr(&size); + return string(s, size); +} + +const char * +value::as_cstr(size_t *size_out) const +{ + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::string: + return cur.cstr(size_out); + case DW_FORM::strp: { + section_offset off = cur.offset(); + cursor scur(cu->get_dwarf().get_section(section_type::str), off); + return scur.cstr(size_out); + } + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as string"); + } +} + +section_offset +value::as_sec_offset() const +{ + // Prior to DWARF 4, sec_offsets were encoded as data4 or + // data8. + cursor cur(cu->data(), offset); + switch (form) { + case DW_FORM::data4: + return cur.fixed(); + case DW_FORM::data8: + return cur.fixed(); + case DW_FORM::sec_offset: + return cur.offset(); + default: + throw value_type_mismatch("cannot read " + to_string(typ) + " as sec_offset"); + } +} + +void +value::resolve_indirect(DW_AT name) +{ + if (form != DW_FORM::indirect) + return; + + cursor c(cu->data(), offset); + DW_FORM form; + do { + form = (DW_FORM)c.uleb128(); + } while (form == DW_FORM::indirect); + typ = attribute_spec(name, form).type; + offset = c.get_section_offset(); +} + +string +to_string(const value &v) +{ + switch (v.get_type()) { + case value::type::invalid: + return ""; + case value::type::address: + return "0x" + to_hex(v.as_address()); + case value::type::block: { + size_t size; + const char *b = (const char*)v.as_block(&size); + string res = ::to_string(size) + " byte block:"; + for (size_t pos = 0; pos < size; ++pos) { + res += ' '; + res += to_hex(b[pos]); + } + return res; + } + case value::type::constant: + return "0x" + to_hex(v.as_uconstant()); + case value::type::uconstant: + return ::to_string(v.as_uconstant()); + case value::type::sconstant: + return ::to_string(v.as_sconstant()); + case value::type::exprloc: + // XXX + return ""; + case value::type::flag: + return v.as_flag() ? "true" : "false"; + case value::type::line: + return ""; + case value::type::loclist: + return ""; + case value::type::mac: + return ""; + case value::type::rangelist: + return ""; + case value::type::reference: { + die d = v.as_reference(); + auto tu = dynamic_cast(&d.get_unit()); + if (tu) + return "<.debug_types+0x" + to_hex(d.get_section_offset()) + ">"; + return "<0x" + to_hex(d.get_section_offset()) + ">"; + } + case value::type::string: + return v.as_string(); + } + return ""; +} + +DWARFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/elf/.gitignore b/pwn/flipper/dist/utils/add-debug/elf/.gitignore new file mode 100644 index 0000000..0d225b9 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/.gitignore @@ -0,0 +1,4 @@ +*.o +to_string.cc +libelf++.a +libelf++.pc diff --git a/pwn/flipper/dist/utils/add-debug/elf/CMakeLists.txt b/pwn/flipper/dist/utils/add-debug/elf/CMakeLists.txt new file mode 100644 index 0000000..87200f0 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/CMakeLists.txt @@ -0,0 +1,20 @@ +# Attention: This CMakeLists.txt implements the bare minimum of what is +# required by SWEB. +cmake_minimum_required(VERSION 3.1.0) + +set(CMAKE_CXX_STANDARD 11) + +add_custom_command( + OUTPUT to_string.cc + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen_to_string.sh ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/to_string.cc + DEPENDS enum-print.py data.hh to_hex.hh +) + +add_library(elf++ STATIC elf.cc mmap_loader.cc to_string.cc) + +# This is needed for the out-of-source generated to_string.cc +target_include_directories(elf++ PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") + +if(${CMAKE_VERSION} VERSION_GREATER "3.6.0" OR ${CMAKE_VERSION} VERSION_EQUAL "3.6.0") + target_compile_features(elf++ INTERFACE cxx_range_for cxx_generalized_initializers cxx_defaulted_functions) +endif() diff --git a/pwn/flipper/dist/utils/add-debug/elf/common.hh b/pwn/flipper/dist/utils/add-debug/elf/common.hh new file mode 100644 index 0000000..9347c2e --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/common.hh @@ -0,0 +1,75 @@ +#ifndef _ELFPP_COMMON_HH_ +#define _ELFPP_COMMON_HH_ + +#define ELFPP_BEGIN_NAMESPACE namespace elf { +#define ELFPP_END_NAMESPACE } + +#include + +ELFPP_BEGIN_NAMESPACE + +/** + * A byte ordering. + */ +enum class byte_order +{ + native, + lsb, + msb +}; + +/** + * Return either byte_order::lsb or byte_order::msb. If the argument + * is byte_order::native, it will be resolved to whatever the native + * byte order is. + */ +static inline byte_order +resolve_order(byte_order o) +{ + static const union + { + int i; + char c[sizeof(int)]; + } test = {1}; + + if (o == byte_order::native) + return test.c[0] == 1 ? byte_order::lsb : byte_order::msb; + return o; +} + +/** + * Return v converted from one byte order to another. + */ +template +T +swizzle(T v, byte_order from, byte_order to) +{ + static_assert(sizeof(T) == 1 || + sizeof(T) == 2 || + sizeof(T) == 4 || + sizeof(T) == 8, + "cannot swizzle type"); + + from = resolve_order(from); + to = resolve_order(to); + + if (from == to) + return v; + + switch (sizeof(T)) { + case 1: + return v; + case 2: { + std::uint16_t x = (std::uint16_t)v; + return (T)(((x&0xFF) << 8) | (x >> 8)); + } + case 4: + return (T)__builtin_bswap32((std::uint32_t)v); + case 8: + return (T)__builtin_bswap64((std::uint64_t)v); + } +} + +ELFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/elf/data.hh b/pwn/flipper/dist/utils/add-debug/elf/data.hh new file mode 100644 index 0000000..ba5b7b3 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/data.hh @@ -0,0 +1,565 @@ +#ifndef _ELFPP_DATA_HH_ +#define _ELFPP_DATA_HH_ + +#include "common.hh" + +#include +#include +#include + +ELFPP_BEGIN_NAMESPACE + +// Object file classes (ELF64 table 3) +enum class elfclass : unsigned char +{ + _32 = 1, // 32-bit objects + _64 = 2, // 64-bit objects +}; + +std::string +to_string(elfclass v); + +// Common basic data types +struct ElfTypes +{ + typedef std::uint16_t Half; + typedef std::uint32_t Word; + typedef std::int32_t Sword; +}; + +struct Elf32 : public ElfTypes +{ + // ELF class + static const elfclass cls = elfclass::_32; + + // Basic data types (ELF32 figure 1-2) + typedef std::uint32_t Addr; + typedef std::uint32_t Off; + + // Predicated types + typedef Word Word32_Xword64; + + template + struct pick + { + typedef t32 t; + }; +}; + +struct Elf64 : ElfTypes +{ + // ELF class + static const elfclass cls = elfclass::_64; + + // Basic data types (ELF64 table 1) + typedef std::uint64_t Addr; + typedef std::uint64_t Off; + typedef std::uint64_t Xword; + typedef std::int64_t Sxword; + + // Predicated types + typedef Xword Word32_Xword64; + + template + struct pick + { + typedef t64 t; + }; +}; + +// Data encodings (ELF64 table 4) +enum class elfdata : unsigned char +{ + lsb = 1, + msb = 2, +}; + +std::string +to_string(elfdata v); + +// Operating system and ABI identifiers (ELF64 table 5) +enum class elfosabi : unsigned char +{ + sysv = 0, + hpux = 1, + standalone = 255, +}; + +std::string +to_string(elfosabi v); + +// Object file types (ELF64 table 6) +enum class et : ElfTypes::Half +{ + none = 0, // No file type + rel = 1, // Relocatable object file + exec = 2, // Executable file + dyn = 3, // Shared object file + core = 4, // Core file + loos = 0xfe00, // Environment-specific use + hios = 0xfeff, + loproc = 0xff00, // Processor-specific use + hiproc = 0xffff, +}; + +std::string +to_string(et v); + +// ELF header (ELF32 figure 1-3, ELF64 figure 2) +template +struct Ehdr +{ + typedef E types; + static const byte_order order = Order; + + // ELF identification + unsigned char ei_magic[4]; + elfclass ei_class; + elfdata ei_data; + unsigned char ei_version; + elfosabi ei_osabi; + unsigned char ei_abiversion; + unsigned char ei_pad[7]; + + et type; // Object file type + typename E::Half machine; // Machine type + typename E::Word version; // Object file version + typename E::Addr entry; // Entry point address + typename E::Off phoff; // Program header offset + typename E::Off shoff; // Section header offset + typename E::Word flags; // Processor-specific flags + typename E::Half ehsize; // ELF header size + typename E::Half phentsize; // Size of program header entry + typename E::Half phnum; // Number of program header entries + typename E::Half shentsize; // Size of section header entry + typename E::Half shnum; // Number of section header entries + typename E::Half shstrndx; // Section name string table index + + template + void from(const E2 &o) + { + std::memcpy(ei_magic, o.ei_magic, sizeof(ei_magic)); + ei_class = swizzle(o.ei_class, o.order, order); + ei_data = swizzle(o.ei_data, o.order, order); + ei_version = swizzle(o.ei_version, o.order, order); + ei_osabi = swizzle(o.ei_osabi, o.order, order); + ei_abiversion = swizzle(o.ei_abiversion, o.order, order); + std::memcpy(ei_pad, o.ei_pad, sizeof(ei_pad)); + + type = swizzle(o.type, o.order, order); + machine = swizzle(o.machine, o.order, order); + version = swizzle(o.version, o.order, order); + entry = swizzle(o.entry, o.order, order); + phoff = swizzle(o.phoff, o.order, order); + shoff = swizzle(o.shoff, o.order, order); + flags = swizzle(o.flags, o.order, order); + ehsize = swizzle(o.ehsize, o.order, order); + phentsize = swizzle(o.phentsize, o.order, order); + phnum = swizzle(o.phnum, o.order, order); + shentsize = swizzle(o.shentsize, o.order, order); + shnum = swizzle(o.shnum, o.order, order); + shstrndx = swizzle(o.shstrndx, o.order, order); + } +}; + +// Special section indices (ELF32 figure 1-7, ELF64 table 7) +// +// This is an integer with a few special values, so this is a regular +// enum, rather than a type-safe enum. However, this is declared in a +// namespace and then used to avoid polluting the elf:: namespace. +namespace enums { +enum shn : ElfTypes::Half +{ + undef = 0, // Undefined or meaningless + + loproc = 0xff00, // Processor-specific use + hiproc = 0xff1f, + loos = 0xff20, // Environment-specific use + hios = 0xff3f, + + abs = 0xfff1, // Reference is an absolute value + common = 0xfff2, // Symbol declared as a common block +}; + +std::string +to_string(shn v); +} + +using enums::shn; + +// Section types (ELF64 table 8) +enum class sht : ElfTypes::Word +{ + null = 0, // Marks an unseen section header + progbits = 1, // Contains information defined by the program + symtab = 2, // Contains a linker symbol table + strtab = 3, // Contains a string table + rela = 4, // Contains "Rela" type relocation entries + hash = 5, // Contains a symbol hash table + dynamic = 6, // Contains dynamic linking tables + note = 7, // Contains note information + nobits = 8, // Contains uninitialized space; + // does not occupy any space in the file + rel = 9, // Contains "Rel" type relocation entries + shlib = 10, // Reserved + dynsym = 11, // Contains a dynamic loader symbol table + loos = 0x60000000, // Environment-specific use + hios = 0x6FFFFFFF, + loproc = 0x70000000, // Processor-specific use + hiproc = 0x7FFFFFFF, +}; + +std::string +to_string(sht v); + +// Section attributes (ELF64 table 9). Note: This is an Elf32_Word in +// ELF32. We use the larger ELF64 type for the canonical +// representation and switch it out for a plain Elf32_Word in the +// ELF32 format. +enum class shf : Elf64::Xword +{ + write = 0x1, // Section contains writable data + alloc = 0x2, // Section is allocated in memory image of program + execinstr = 0x4, // Section contains executable instructions + maskos = 0x0F000000, // Environment-specific use + maskproc = 0xF0000000, // Processor-specific use +}; + +std::string +to_string(shf v); + +static inline constexpr shf operator&(shf a, shf b) +{ + return (shf)((std::uint64_t)a & (std::uint64_t)b); +} + +static inline constexpr shf operator|(shf a, shf b) +{ + return (shf)((std::uint64_t)a | (std::uint64_t)b); +} + +static inline constexpr shf operator^(shf a, shf b) +{ + return (shf)((std::uint64_t)a ^ (std::uint64_t)b); +} + +static inline constexpr shf operator~(shf a) +{ + return (shf)~((std::uint64_t)a); +} + +static inline shf& operator&=(shf &a, shf b) +{ + a = a & b; + return a; +} + +static inline shf& operator|=(shf &a, shf b) +{ + a = a | b; + return a; +} + +static inline shf& operator^=(shf &a, shf b) +{ + a = a ^ b; + return a; +} + +// Section header (ELF32 figure 1-8, ELF64 figure 3) +template +struct Shdr +{ + typedef E types; + static const byte_order order = Order; + + typename E::Word name; // Section name + sht type; // Section type + typename E::template pick::t flags; // Section attributes + typename E::Addr addr; // Virtual address in memory + typename E::Off offset; // Offset in file + typename E::Word32_Xword64 size; // Size of section + shn link; // Link to other section + typename E::Word info; // Miscellaneous information + typename E::Word32_Xword64 addralign; // Address alignment boundary + typename E::Word32_Xword64 entsize; // Size of entries, if section has table + + template + void from(const E2 &o) + { + name = swizzle(o.name, o.order, order); + type = swizzle(o.type, o.order, order); + flags = (decltype(flags))swizzle(o.flags, o.order, order); + addr = swizzle(o.addr, o.order, order); + offset = swizzle(o.offset, o.order, order); + size = swizzle(o.size, o.order, order); + link = swizzle(o.link, o.order, order); + info = swizzle(o.info, o.order, order); + addralign = swizzle(o.addralign, o.order, order); + entsize = swizzle(o.entsize, o.order, order); + } +}; + +// Segment types (ELF64 table 16) +enum class pt : ElfTypes::Word +{ + null = 0, // Unused entry + load = 1, // Loadable segment + dynamic = 2, // Dynamic linking tables + interp = 3, // Program interpreter path name + note = 4, // Note sections + shlib = 5, // Reserved + phdr = 6, // Program header table + loos = 0x60000000, // Environment-specific use + hios = 0x6FFFFFFF, + loproc = 0x70000000, // Processor-specific use + hiproc = 0x7FFFFFFF, +}; + +std::string +to_string(pt v); + +// Segment attributes +enum class pf : ElfTypes::Word +{ + x = 0x1, // Execute permission + w = 0x2, // Write permission + r = 0x4, // Read permission + maskos = 0x00FF0000, // Environment-specific use + maskproc = 0xFF000000, // Processor-specific use +}; + +std::string +to_string(pf v); + +static inline constexpr pf operator&(pf a, pf b) +{ + return (pf)((std::uint64_t)a & (std::uint64_t)b); +} + +static inline constexpr pf operator|(pf a, pf b) +{ + return (pf)((std::uint64_t)a | (std::uint64_t)b); +} + +static inline constexpr pf operator^(pf a, pf b) +{ + return (pf)((std::uint64_t)a ^ (std::uint64_t)b); +} + +static inline constexpr pf operator~(pf a) +{ + return (pf)~((std::uint64_t)a); +} + +static inline pf& operator&=(pf &a, pf b) +{ + a = a & b; + return a; +} + +static inline pf& operator|=(pf &a, pf b) +{ + a = a | b; + return a; +} + +static inline pf& operator^=(pf &a, pf b) +{ + a = a ^ b; + return a; +} + +// Program header (ELF32 figure 2-1, ELF64 figure 6) +template +struct Phdr; + +template +struct Phdr +{ + typedef Elf32 types; + static const byte_order order = Order; + + pt type; // Type of segment + Elf32::Off offset; // Offset in file + Elf32::Addr vaddr; // Virtual address in memory + Elf32::Addr paddr; // Reserved + Elf32::Word filesz; // Size of segment in file + Elf32::Word memsz; // Size of segment in memory + pf flags; // Segment attributes + Elf32::Word align; // Alignment of segment + + template + void from(const E2 &o) + { + type = swizzle(o.type, o.order, order); + offset = swizzle(o.offset, o.order, order); + vaddr = swizzle(o.vaddr, o.order, order); + paddr = swizzle(o.paddr, o.order, order); + filesz = swizzle(o.filesz, o.order, order); + memsz = swizzle(o.memsz, o.order, order); + flags = swizzle(o.flags, o.order, order); + align = swizzle(o.align, o.order, order); + } +}; + +template +struct Phdr +{ + typedef Elf64 types; + static const byte_order order = Order; + + pt type; // Type of segment + pf flags; // Segment attributes + Elf64::Off offset; // Offset in file + Elf64::Addr vaddr; // Virtual address in memory + Elf64::Addr paddr; // Reserved + Elf64::Xword filesz; // Size of segment in file + Elf64::Xword memsz; // Size of segment in memory + Elf64::Xword align; // Alignment of segment + + template + void from(const E2 &o) + { + type = swizzle(o.type, o.order, order); + offset = swizzle(o.offset, o.order, order); + vaddr = swizzle(o.vaddr, o.order, order); + paddr = swizzle(o.paddr, o.order, order); + filesz = swizzle(o.filesz, o.order, order); + memsz = swizzle(o.memsz, o.order, order); + flags = swizzle(o.flags, o.order, order); + align = swizzle(o.align, o.order, order); + } +}; + +// Symbol bindings (ELF32 figure 1-16, ELF64 table 14) +enum class stb : unsigned char +{ + local = 0, // Not visible outside the object file + global = 1, // Global symbol + weak = 2, // Global scope, but with lower + // precedence than global symbols + loos = 10, // Environment-specific use + hios = 12, + loproc = 13, // Processor-specific use + hiproc = 15, +}; + +std::string +to_string(stb v); + +// Symbol types (ELF32 figure 1-17, ELF64 table 15) +enum class stt : unsigned char +{ + notype = 0, // No type (e.g., absolute symbol) + object = 1, // Data object + func = 2, // Function entry point + section = 3, // Symbol is associated with a section + file = 4, // Source file associated with the + // object file + loos = 10, // Environment-specific use + hios = 12, + loproc = 13, // Processor-specific use + hiproc = 15, +}; + +std::string +to_string(stt v); + +// Symbol table (ELF32 figure 1-15, ELF64 figure 4) +template +struct Sym; + +template +struct Sym +{ + typedef Elf32 types; + static const byte_order order = Order; + + Elf32::Word name; // Symbol name (strtab offset) + Elf32::Addr value; // Symbol value (address) + Elf32::Word size; // Size of object + unsigned char info; // Type and binding attributes + unsigned char other; // Reserved + shn shnxd; // Section table index + + template + void from(const E2 &o) + { + name = swizzle(o.name, o.order, order); + value = swizzle(o.value, o.order, order); + size = swizzle(o.size, o.order, order); + info = o.info; + other = o.other; + shnxd = swizzle(o.shnxd, o.order, order); + } + + stb binding() const + { + return (stb)(info >> 4); + } + + void set_binding(stb v) + { + info = (info & 0x0F) | ((unsigned char)v << 4); + } + + stt type() const + { + return (stt)(info & 0xF); + } + + void set_type(stt v) + { + info = (info & 0xF0) | (unsigned char)v; + } +}; + +template +struct Sym +{ + typedef Elf64 types; + static const byte_order order = Order; + + Elf64::Word name; // Symbol name (strtab offset) + unsigned char info; // Type and binding attributes + unsigned char other; // Reserved + shn shnxd; // Section table index + Elf64::Addr value; // Symbol value (address) + Elf64::Xword size; // Size of object + + template + void from(const E2 &o) + { + name = swizzle(o.name, o.order, order); + value = swizzle(o.value, o.order, order); + size = swizzle(o.size, o.order, order); + info = o.info; + other = o.other; + shnxd = swizzle(o.shnxd, o.order, order); + } + + stb binding() const + { + return (stb)(info >> 4); + } + + void set_binding(stb v) const + { + info = (info & 0xF) | ((unsigned char)v << 4); + } + + stt type() const + { + return (stt)(info & 0xF); + } + + void set_type(stt v) + { + info = (info & 0xF0) | (unsigned char)v; + } +}; + +ELFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/elf/elf++.hh b/pwn/flipper/dist/utils/add-debug/elf/elf++.hh new file mode 100644 index 0000000..a61e5c6 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/elf++.hh @@ -0,0 +1,382 @@ +#ifndef _ELFPP_HH_ +#define _ELFPP_HH_ + +#include "common.hh" +#include "data.hh" + +#include +#include +#include +#include + +ELFPP_BEGIN_NAMESPACE + +class elf; +class loader; +class section; +class strtab; +class symtab; + +// XXX Audit for binary compatibility + +// XXX Segments, other section types + +/** + * An exception indicating malformed ELF data. + */ +class format_error : public std::runtime_error +{ +public: + explicit format_error(const std::string &what_arg) + : std::runtime_error(what_arg) { } + explicit format_error(const char *what_arg) + : std::runtime_error(what_arg) { } +}; + +/** + * An ELF file. + * + * This class is internally reference counted and efficiently + * copyable. + * + * Raw pointers to ELF data returned by any method of this object or + * any object derived from this object point directly into loaded + * section data. Hence, callers must ensure that the loader passed to + * this file remains live as long as any such pointer is in use. + * Keeping any object that can return such a pointer live is + * sufficieint to keep the loader live. + */ +class elf +{ +public: + /** + * Construct an ELF file that is backed by data read from the + * given loader. + */ + explicit elf(const std::shared_ptr &l); + + /** + * Construct an ELF file that is initially not valid. Calling + * methods other than operator= and valid on this results in + * undefined behavior. + */ + elf() = default; + elf(const elf &o) = default; + elf(elf &&o) = default; + + elf& operator=(const elf &o) = default; + + bool valid() const + { + return !!m; + } + + /** + * Return the ELF file header in canonical form (ELF64 in + * native byte order). + */ + const Ehdr<> &get_hdr() const; + + /** + * Return the loader used by this file. + */ + std::shared_ptr get_loader() const; + + /** + * Return the sections in this file. + */ + const std::vector
§ions() const; + + /** + * Return the section with the specified name. If no such + * section is found, return an invalid section. + */ + const section &get_section(const std::string &name) const; + + /** + * Return the section at the given index. If no such section + * is found, return an invalid section. + */ + const section &get_section(unsigned index) const; + +private: + struct impl; + std::shared_ptr m; +}; + +/** + * An interface for loading sections of an ELF file. + */ +class loader +{ +public: + virtual ~loader() { } + + /** + * Load the requested file section into memory and return a + * pointer to the beginning of it. This memory must remain + * valid and unchanged until the loader is destroyed. If the + * loader cannot satisfy the full request for any reason + * (including a premature EOF), it must throw an exception. + */ + virtual const void *load(off_t offset, size_t size) = 0; +}; + +/** + * An mmap-based loader that maps requested sections on demand. This + * will close fd when done, so the caller should dup the file + * descriptor if it intends to continue using it. + */ +std::shared_ptr create_mmap_loader(int fd); + +/** + * An exception indicating that a section is not of the requested type. + */ +class section_type_mismatch : public std::logic_error +{ +public: + explicit section_type_mismatch(const std::string &what_arg) + : std::logic_error(what_arg) { } + explicit section_type_mismatch(const char *what_arg) + : std::logic_error(what_arg) { } +}; + +/** + * An ELF section. + * + * This class is internally reference counted and efficiently + * copyable. + */ +class section +{ +public: + /** + * Construct a section that is initially not valid. Calling + * methods other than operator= and valid on this results in + * undefined behavior. + */ + section() { } + + section(const elf &f, const void *hdr); + section(const section &o) = default; + section(section &&o) = default; + + /** + * Return true if this section is valid and corresponds to a + * section in the ELF file. + */ + bool valid() const + { + return !!m; + } + + /** + * Return the ELF section header in canonical form (ELF64 in + * native byte order). + */ + const Shdr<> &get_hdr() const; + + /** + * Return this section's name. + */ + const char *get_name(size_t *len_out) const; + /** + * Return this section's name. The returned string copies its + * data, so loader liveness requirements don't apply. + */ + std::string get_name() const; + + /** + * Return this section's data. If this is a NOBITS section, + * return nullptr. + */ + const void *data() const; + /** + * Return the size of this section in bytes. + */ + size_t size() const; + + /** + * Return this section as a strtab. Throws + * section_type_mismatch if this section is not a string + * table. + */ + strtab as_strtab() const; + + /** + * Return this section as a symtab. Throws + * section_type_mismatch if this section is not a symbol + * table. + */ + symtab as_symtab() const; + +private: + struct impl; + std::shared_ptr m; +}; + +/** + * A string table. + * + * This class is internally reference counted and efficiently + * copyable. + */ +class strtab +{ +public: + /** + * Construct a strtab that is initially not valid. Calling + * methods other than operator= and valid on this results in + * undefined behavior. + */ + strtab() = default; + strtab(elf f, const void *data, size_t size); + + bool valid() const + { + return !!m; + } + + /** + * Return the string at the given offset in this string table. + * If the offset is out of bounds, throws std::range_error. + * This is very efficient since the returned pointer points + * directly into the loaded section, though this still + * verifies that the returned string is NUL-terminated. + */ + const char *get(Elf64::Off offset, size_t *len_out) const; + /** + * Return the string at the given offset in this string table. + */ + std::string get(Elf64::Off offset) const; + +private: + struct impl; + std::shared_ptr m; +}; + +/** + * A symbol from a symbol table. + */ +class sym +{ + const strtab strs; + Sym<> data; + +public: + sym(elf f, const void *data, strtab strs); + + /** + * Return this symbol's raw data. + */ + const Sym<> &get_data() const + { + return data; + } + + /** + * Return this symbol's name. + * + * This returns a pointer into the string table and, as such, + * is very efficient. If len_out is non-nullptr, *len_out + * will be set the length of the returned string. + */ + const char *get_name(size_t *len_out) const; + + /** + * Return this symbol's name as a string. + */ + std::string get_name() const; +}; + +/** + * A symbol table. + * + * This class is internally reference counted and efficiently + * copyable. + */ +class symtab +{ +public: + /** + * Construct a symtab that is initially not valid. Calling + * methods other than operator= and valid on this results in + * undefined behavior. + */ + symtab() = default; + symtab(elf f, const void *data, size_t size, strtab strs); + + bool valid() const + { + return !!m; + } + + class iterator + { + const elf f; + const strtab strs; + const char *pos; + size_t stride; + + iterator(const symtab &tab, const char *pos); + friend class symtab; + + public: + sym operator*() const + { + return sym(f, pos, strs); + } + + iterator& operator++() + { + return *this += 1; + } + + iterator operator++(int) + { + iterator cur(*this); + *this += 1; + return cur; + } + + iterator& operator+=(std::ptrdiff_t x) + { + pos += x * stride; + return *this; + } + + iterator& operator-=(std::ptrdiff_t x) + { + pos -= x * stride; + return *this; + } + + bool operator==(iterator &o) const + { + return pos == o.pos; + } + + bool operator!=(iterator &o) const + { + return pos != o.pos; + } + }; + + /** + * Return an iterator to the first symbol. + */ + iterator begin() const; + + /** + * Return an iterator just past the last symbol. + */ + iterator end() const; + +private: + struct impl; + std::shared_ptr m; +}; + +ELFPP_END_NAMESPACE + +#endif diff --git a/pwn/flipper/dist/utils/add-debug/elf/elf.cc b/pwn/flipper/dist/utils/add-debug/elf/elf.cc new file mode 100644 index 0000000..3adf33d --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/elf.cc @@ -0,0 +1,334 @@ +#include "elf++.hh" + +#include + +using namespace std; + +ELFPP_BEGIN_NAMESPACE + +template class Hdr> +void canon_hdr(Hdr *out, const void *data, + elfclass ei_class, elfdata ei_data) +{ + switch (ei_class) { + case elfclass::_32: + switch (ei_data) { + case elfdata::lsb: + out->from(*(Hdr*)data); + break; + case elfdata::msb: + out->from(*(Hdr*)data); + break; + } // fallthrough + case elfclass::_64: + switch (ei_data) { + case elfdata::lsb: + out->from(*(Hdr*)data); + break; + case elfdata::msb: + out->from(*(Hdr*)data); + return; + } // fallthrough + } +} + +////////////////////////////////////////////////////////////////// +// class elf +// + +struct elf::impl +{ + impl(const shared_ptr &l) + : l(l) { } + + const shared_ptr l; + Ehdr<> hdr; + vector
sections; + //vector segments; + + section invalid_section; +}; + +elf::elf(const std::shared_ptr &l) + : m(make_shared(l)) +{ + // Read the first six bytes to check the magic number, ELF + // class, and byte order. + struct core_hdr + { + char ei_magic[4]; + elfclass ei_class; + elfdata ei_data; + unsigned char ei_version; + } *core_hdr = (struct core_hdr*)l->load(0, sizeof *core_hdr); + + // Check basic header + if (strncmp(core_hdr->ei_magic, "\x7f" "ELF", 4) != 0) + throw format_error("bad ELF magic number"); + if (core_hdr->ei_version != 1) + throw format_error("unknown ELF version"); + if (core_hdr->ei_class != elfclass::_32 && + core_hdr->ei_class != elfclass::_64) + throw format_error("bad ELF class"); + if (core_hdr->ei_data != elfdata::lsb && + core_hdr->ei_data != elfdata::msb) + throw format_error("bad ELF data order"); + + // Read in the real header and canonicalize it + size_t hdr_size = (core_hdr->ei_class == elfclass::_32 ? + sizeof(Ehdr) : sizeof(Ehdr)); + const void *hdr = l->load(0, hdr_size); + canon_hdr(&m->hdr, hdr, core_hdr->ei_class, core_hdr->ei_data); + + // More checks + if (m->hdr.version != 1) + throw format_error("bad section ELF version"); + if (m->hdr.shnum && m->hdr.shstrndx >= m->hdr.shnum) + throw format_error("bad section name string table index"); + + // Load sections + const void *sec_data = l->load(m->hdr.shoff, + m->hdr.shentsize * m->hdr.shnum); + for (unsigned i = 0; i < m->hdr.shnum; i++) { + const void *sec = ((const char*)sec_data) + i * m->hdr.shentsize; + // XXX Circular reference. Maybe this should be + // constructed on the fly? Canonicalizing the header + // isn't super-cheap. + m->sections.push_back(section(*this, sec)); + } +} + +const Ehdr<> & +elf::get_hdr() const +{ + return m->hdr; +} + +shared_ptr +elf::get_loader() const +{ + return m->l; +} + +const std::vector
& +elf::sections() const +{ + return m->sections; +} + +const section & +elf::get_section(const std::string &name) const +{ + for (auto &sec : sections()) + if (name == sec.get_name(nullptr)) + return sec; + return m->invalid_section; +} + +const section & +elf::get_section(unsigned index) const +{ + if (index >= sections().size()) + return m->invalid_section; + return sections().at(index); +} + +////////////////////////////////////////////////////////////////// +// class section +// + +std::string +enums::to_string(shn v) +{ + if (v == shn::undef) + return "undef"; + if (v == shn::abs) + return "abs"; + if (v == shn::common) + return "common"; + return std::to_string(v); +} + +struct section::impl +{ + impl(const elf &f) + : f(f), name(nullptr), data(nullptr) { } + + const elf f; + Shdr<> hdr; + const char *name; + size_t name_len; + const void *data; +}; + +section::section(const elf &f, const void *hdr) + : m(make_shared(f)) +{ + canon_hdr(&m->hdr, hdr, f.get_hdr().ei_class, f.get_hdr().ei_data); +} + +const Shdr<> & +section::get_hdr() const +{ + return m->hdr; +} + +const char * +section::get_name(size_t *len_out) const +{ + // XXX Should the section name strtab be cached? + if (!m->name) + m->name = m->f.get_section(m->f.get_hdr().shstrndx) + .as_strtab().get(m->hdr.name, &m->name_len); + if (len_out) + *len_out = m->name_len; + return m->name; +} + +string +section::get_name() const +{ + return get_name(nullptr); +} + +const void * +section::data() const +{ + if (m->hdr.type == sht::nobits) + return nullptr; + if (!m->data) + m->data = m->f.get_loader()->load(m->hdr.offset, m->hdr.size); + return m->data; +} + +size_t +section::size() const +{ + return m->hdr.size; +} + +strtab +section::as_strtab() const +{ + if (m->hdr.type != sht::strtab) + throw section_type_mismatch("cannot use section as strtab"); + return strtab(m->f, data(), size()); +} + +symtab +section::as_symtab() const +{ + if (m->hdr.type != sht::symtab && m->hdr.type != sht::dynsym) + throw section_type_mismatch("cannot use section as symtab"); + return symtab(m->f, data(), size(), + m->f.get_section(get_hdr().link).as_strtab()); +} + +////////////////////////////////////////////////////////////////// +// class strtab +// + +struct strtab::impl +{ + impl(const elf &f, const char *data, const char *end) + : f(f), data(data), end(end) { } + + const elf f; + const char *data, *end; +}; + +strtab::strtab(elf f, const void *data, size_t size) + : m(make_shared(f, (const char*)data, (const char *)data + size)) +{ +} + +const char * +strtab::get(Elf64::Off offset, size_t *len_out) const +{ + const char *start = m->data + offset; + + if (start >= m->end) + throw range_error("string offset " + std::to_string(offset) + " exceeds section size"); + + // Find the null terminator + const char *p = start; + while (p < m->end && *p) + p++; + if (p == m->end) + throw format_error("unterminated string"); + + if (len_out) + *len_out = p - start; + return start; +} + +std::string +strtab::get(Elf64::Off offset) const +{ + return get(offset, nullptr); +} + +////////////////////////////////////////////////////////////////// +// class sym +// + +sym::sym(elf f, const void *data, strtab strs) + : strs(strs) +{ + canon_hdr(&this->data, data, f.get_hdr().ei_class, f.get_hdr().ei_data); +} + +const char * +sym::get_name(size_t *len_out) const +{ + return strs.get(get_data().name, len_out); +} + +std::string +sym::get_name() const +{ + return strs.get(get_data().name); +} + +////////////////////////////////////////////////////////////////// +// class symtab +// + +struct symtab::impl +{ + impl(const elf &f, const char *data, const char *end, strtab strs) + : f(f), data(data), end(end), strs(strs) { } + + const elf f; + const char *data, *end; + const strtab strs; +}; + +symtab::symtab(elf f, const void *data, size_t size, strtab strs) + : m(make_shared(f, (const char*)data, (const char *)data + size, + strs)) +{ +} + +symtab::iterator::iterator(const symtab &tab, const char *pos) + : f(tab.m->f), strs(tab.m->strs), pos(pos) +{ + if (f.get_hdr().ei_class == elfclass::_32) + stride = sizeof(Sym); + else + stride = sizeof(Sym); +} + +symtab::iterator +symtab::begin() const +{ + return iterator(*this, m->data); +} + +symtab::iterator +symtab::end() const +{ + return iterator(*this, m->end); +} + +ELFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/elf/enum-print.py b/pwn/flipper/dist/utils/add-debug/elf/enum-print.py new file mode 100644 index 0000000..7553e48 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/enum-print.py @@ -0,0 +1,159 @@ +import sys, re +from optparse import OptionParser + +def read_toks(): + data = sys.stdin.read() + while data: + data = data.lstrip() + if data.startswith("//") or data.startswith("#"): + data = data.split("\n",1)[1] + elif data.startswith("/*"): + data = data.split("*/",1)[1] + elif data.startswith("\"") or data.startswith("'"): + c = data[0] + m = re.match(r'%s([^\\%s]|\\.)*%s' % (c,c,c), data) + yield m.group(0) + data = data[m.end():] + else: + m = re.match(r"[_a-zA-Z0-9]+|[{}();]|[^_a-zA-Z0-9 \n\t\f]+", data) + yield m.group(0) + data = data[m.end():] + +enums = {} + +def do_top_level(toks, ns=[]): + while toks: + tok = toks.pop(0) + if tok == "enum" and toks[0] == "class": + toks.pop(0) + name = toks.pop(0) + # Get to the first token in the body + while toks.pop(0) != "{": + pass + # Consume body and close brace + do_enum_body("::".join(ns + [name]), toks) + elif tok == "class": + name = do_qname(toks) + # Find the class body, if there is one + while toks[0] != "{" and toks[0] != ";": + toks.pop(0) + # Enter the class's namespace + if toks[0] == "{": + toks.pop(0) + do_top_level(toks, ns + [name]) + elif tok == "{": + # Enter an unknown namespace + do_top_level(toks, ns + [None]) + elif tok == "}": + # Exit the namespace + assert len(ns) + return + elif not ns and tok == "string" and toks[:2] == ["to_string", "("]: + # Get the argument type and name + toks.pop(0) + toks.pop(0) + typ = do_qname(toks) + if typ not in enums: + continue + arg = toks.pop(0) + assert toks[0] == ")" + + if typ in options.mask: + make_to_string_mask(typ, arg) + else: + make_to_string(typ, arg) + +def fmt_value(typ, key): + if options.no_type: + val = key + else: + val = "%s%s%s" % (typ, options.separator, key) + if options.strip_underscore: + val = val.strip("_") + return val + +def expr_remainder(typ, arg): + if options.hex: + return "\"(%s)0x\" + to_hex((int)%s)" % (typ, arg) + else: + return "\"(%s)\" + std::to_string((int)%s)" % (typ, arg) + +def make_to_string(typ, arg): + print("std::string") + print("to_string(%s %s)" % (typ, arg)) + print("{") + print(" switch (%s) {" % arg) + for key in enums[typ]: + if key in options.exclude: + print(" case %s::%s: break;" % (typ, key)) + continue + print(" case %s::%s: return \"%s\";" % \ + (typ, key, fmt_value(typ, key))) + print(" }") + print(" return %s;" % expr_remainder(typ, arg)) + print("}") + print + +def make_to_string_mask(typ, arg): + print("std::string") + print("to_string(%s %s)" % (typ, arg)) + print("{") + print(" std::string res;") + for key in enums[typ]: + if key in options.exclude: + continue + print(" if ((%s & %s::%s) == %s::%s) { res += \"%s|\"; %s &= ~%s::%s; }" % \ + (arg, typ, key, typ, key, fmt_value(typ, key), arg, typ, key)) + print(" if (res.empty() || %s != (%s)0) res += %s;" % \ + (arg, typ, expr_remainder(typ, arg))) + print(" else res.pop_back();") + print(" return res;") + print("}") + print + +def do_enum_body(name, toks): + keys = [] + while True: + key = toks.pop(0) + if key == "}": + assert toks.pop(0) == ";" + enums[name] = keys + return + keys.append(key) + if toks[0] == "=": + toks.pop(0) + toks.pop(0) + if toks[0] == ",": + toks.pop(0) + else: + assert toks[0] == "}" + +def do_qname(toks): + # Get a nested-name-specifier followed by an identifier + res = [] + while True: + res.append(toks.pop(0)) + if toks[0] != "::": + return "::".join(res) + toks.pop(0) + +parser = OptionParser() +parser.add_option("-x", "--exclude", dest="exclude", action="append", + help="exclude FIELD", metavar="FIELD", default=[]) +parser.add_option("-u", "--strip-underscore", dest="strip_underscore", + action="store_true", + help="strip leading and trailing underscores") +parser.add_option("-s", "--separator", dest="separator", + help="use SEP between type and field", metavar="SEP", + default="::") +parser.add_option("--hex", dest="hex", action="store_true", + help="return unknown values in hex", default=False) +parser.add_option("--no-type", dest="no_type", action="store_true", + help="omit type") +parser.add_option("--mask", dest="mask", action="append", + help="treat TYPE as a bit-mask", metavar="TYPE", default=[]) +(options, args) = parser.parse_args() +if args: + parser.error("expected 0 arguments") + +do_top_level(list(read_toks())) diff --git a/pwn/flipper/dist/utils/add-debug/elf/gen_to_string.sh b/pwn/flipper/dist/utils/add-debug/elf/gen_to_string.sh new file mode 100755 index 0000000..25dfd8d --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/gen_to_string.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +SOURCE_DIR="$1" +OUTPUT_FILE="$2" + +generate () { + echo "// Automatically generated by gen_to_string.sh at $(date)" + echo "// DO NOT EDIT" + echo + echo '#include "data.hh"' + echo '#include "to_hex.hh"' + echo + echo 'ELFPP_BEGIN_NAMESPACE' + echo + PYTHON=python + command -v $PYTHON > /dev/null 2>&1 + if [ $? -ne 0 ]; then + PYTHON=python3 + fi + + $PYTHON "$SOURCE_DIR"/enum-print.py -u --hex --no-type --mask shf --mask pf \ + -x loos -x hios -x loproc -x hiproc < "$SOURCE_DIR"/data.hh + echo 'ELFPP_END_NAMESPACE' +} + +generate > "$OUTPUT_FILE" diff --git a/pwn/flipper/dist/utils/add-debug/elf/mmap_loader.cc b/pwn/flipper/dist/utils/add-debug/elf/mmap_loader.cc new file mode 100644 index 0000000..9ae7b4f --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/mmap_loader.cc @@ -0,0 +1,55 @@ +#include "elf++.hh" + +#include + +#include +#include +#include +#include +#include + +using namespace std; + +ELFPP_BEGIN_NAMESPACE + +class mmap_loader : public loader +{ + void *base; + size_t lim; + +public: + mmap_loader(int fd) + { + off_t end = lseek(fd, 0, SEEK_END); + if (end == (off_t)-1) + throw system_error(errno, system_category(), + "finding file length"); + lim = end; + + base = mmap(nullptr, lim, PROT_READ, MAP_SHARED, fd, 0); + if (base == MAP_FAILED) + throw system_error(errno, system_category(), + "mmap'ing file"); + close(fd); + } + + ~mmap_loader() + { + munmap(base, lim); + } + + const void *load(off_t offset, size_t size) + { + if (offset + size > lim) + throw range_error("offset exceeds file size"); + return (const char*)base + offset; + } +}; + +std::shared_ptr +create_mmap_loader(int fd) +{ + return make_shared(fd); +} + +ELFPP_END_NAMESPACE diff --git a/pwn/flipper/dist/utils/add-debug/elf/to_hex.hh b/pwn/flipper/dist/utils/add-debug/elf/to_hex.hh new file mode 100644 index 0000000..82031a8 --- /dev/null +++ b/pwn/flipper/dist/utils/add-debug/elf/to_hex.hh @@ -0,0 +1,30 @@ +#ifndef _ELFPP_TO_HEX_HH_ +#define _ELFPP_TO_HEX_HH_ + +#include +#include + +template +std::string +to_hex(T v) +{ + static_assert(std::is_integral::value, + "to_hex applied to non-integral type"); + if (v == 0) + return std::string("0"); + char buf[sizeof(T)*2 + 1]; + char *pos = &buf[sizeof(buf)-1]; + *pos-- = '\0'; + while (v && pos >= buf) { + int digit = v & 0xf; + if (digit < 10) + *pos = '0' + digit; + else + *pos = 'a' + (digit - 10); + pos--; + v >>= 4; + } + return std::string(pos + 1); +} + +#endif // _ELFPP_TO_HEX_HH_ diff --git a/pwn/flipper/dist/utils/bochsrc b/pwn/flipper/dist/utils/bochsrc new file mode 100644 index 0000000..1395d4c --- /dev/null +++ b/pwn/flipper/dist/utils/bochsrc @@ -0,0 +1,1123 @@ +# You may now use double quotes around pathnames, in case +# your pathname includes spaces. + +#======================================================================= +# PLUGIN_CTRL: +# Controls the presence of optional device plugins. These plugins are loaded +# directly with this option and some of them install a config option that is +# only available when the plugin device is loaded. The value "1" means to load +# the plugin and "0" will unload it (if loaded before). +# +# These plugins will be loaded by default (if present): 'biosdev', 'extfpuirq', +# 'gameport', 'iodebug','parallel', 'serial', 'speaker' and 'unmapped'. +# +# These plugins are also supported, but they are usually loaded directly with +# their bochsrc option: 'e1000', 'es1370', 'ne2k', 'pcidev', 'pcipnic', 'sb16', +# 'usb_ohci', 'usb_uhci' and 'usb_xhci'. +# +# This plugin currently must be loaded with plugin_ctrl: 'voodoo'. +#======================================================================= +#plugin_ctrl: unmapped=0, e1000=1 # unload 'unmapped' and load 'e1000' + +#======================================================================= +# CONFIG_INTERFACE +# +# The configuration interface is a series of menus or dialog boxes that +# allows you to change all the settings that control Bochs's behavior. +# Depending on the platform there are up to 3 choices of configuration +# interface: a text mode version called "textconfig" and two graphical versions +# called "win32config" and "wx". The text mode version uses stdin/stdout and +# is always compiled in, unless Bochs is compiled for wx only. The choice +# "win32config" is only available on win32 and it is the default there. +# The choice "wx" is only available when you use "--with-wx" on the configure +# command. If you do not write a config_interface line, Bochs will +# choose a default for you. +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +#======================================================================= +#config_interface: textconfig +#config_interface: win32config +#config_interface: wx + +#======================================================================= +# DISPLAY_LIBRARY +# +# The display library is the code that displays the Bochs VGA screen. Bochs +# has a selection of about 10 different display library implementations for +# different platforms. If you run configure with multiple --with-* options, +# the display_library command lets you choose which one you want to run with. +# If you do not write a display_library line, Bochs will choose a default for +# you. +# +# The choices are: +# x use X windows interface, cross platform +# win32 use native win32 libraries +# carbon use Carbon library (for MacOS X) +# macintosh use MacOS pre-10 +# amigaos use native AmigaOS libraries +# sdl use SDL library, cross platform +# svga use SVGALIB library for Linux, allows graphics without X11 +# term text only, uses curses/ncurses library, cross platform +# rfb provides an interface to AT&T's VNC viewer, cross platform +# wx use wxWidgets library, cross platform +# nogui no display at all +# +# NOTE: if you use the "wx" configuration interface, you must also use +# the "wx" display library. +# +# Specific options: +# Some display libraries now support specific options to control their +# behaviour. These options are supported by more than one display library: +# +# "gui_debug" - use GTK debugger gui (sdl, x) / Win32 debugger gui (sdl, win32) +# "hideIPS" - disable IPS output in status bar (rfb, sdl, win32, wx, x) +# "nokeyrepeat" - turn off host keyboard repeat (sdl, win32, x) +# +# See the examples below for other currently supported options. +#======================================================================= +#display_library: amigaos +#display_library: carbon +#display_library: macintosh +#display_library: nogui +#display_library: rfb, options="timeout=60" # time to wait for client +#display_library: sdl, options="fullscreen" # startup in fullscreen mode +#display_library: term +#display_library: win32 +#display_library: wx +#display_library: x + +#======================================================================= +# ROMIMAGE: +# The ROM BIOS controls what the PC does when it first powers on. +# Normally, you can use a precompiled BIOS in the source or binary +# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded +# starting at address 0xf0000, and it is exactly 64k long. Another option +# is 128k BIOS which is loaded at address 0xe0000. +# You can also use the environment variable $BXSHARE to specify the +# location of the BIOS. +# The usage of external large BIOS images (up to 512k) at memory top is +# now supported, but we still recommend to use the BIOS distributed with +# Bochs. The start address optional, since it can be calculated from image size. +#======================================================================= +romimage: file=$BXSHARE/BIOS-bochs-latest +#romimage: file=bios/seabios-1.6.3.bin +#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top + +#======================================================================= +# CPU: +# This defines cpu-related parameters inside Bochs: +# +# MODEL: +# Selects CPU configuration to emulate from pre-defined list of all +# supported configurations. When this option is used, the CPUID option +# has no effect anymore. +# +# CPU configurations that can be selected: +# ----------------------------------------------------------------- +# pentium_mmx Intel Pentium MMX +# amd_k6_2_chomper AMD-K6(tm) 3D processor (Chomper) +# p2_klamath Intel Pentium II (Klamath) +# p3_katmai Intel Pentium III (Katmai) +# p4_willamette Intel(R) Pentium(R) 4 (Willamette) +# core_duo_t2400_yonah Intel(R) Core(TM) Duo CPU T2400 (Yonah) +# atom_n270 Intel(R) Atom(TM) CPU N270 +# athlon64_clawhammer AMD Athlon(tm) 64 Processor 2800+ (Clawhammer) +# athlon64_venice AMD Athlon(tm) 64 Processor 3000+ (Venice) +# turion64_tyler AMD Turion(tm) 64 X2 Mobile TL-60 (Tyler) +# phenom_8650_toliman AMD Phenom X3 8650 (Toliman) +# p4_prescott_celeron_336 Intel(R) Celeron(R) 336 (Prescott) +# core2_penryn_t9600 Intel Mobile Core 2 Duo T9600 (Penryn) +# corei5_lynnfield_750 Intel(R) Core(TM) i5 750 (Lynnfield) +# corei5_arrandale_m520 Intel(R) Core(TM) i5 M 520 (Arrandale) +# corei7_sandy_bridge_2600k Intel(R) Core(TM) i7-2600K (Sandy Bridge) +# corei7_ivy_bridge_3770k Intel(R) Core(TM) i7-3770K CPU (Ivy Bridge) +# +# COUNT: +# Set the number of processors:cores per processor:threads per core +# when Bochs is compiled for SMP emulation. +# Bochs currently supports up to 8 threads running simultaniosly. +# If Bochs is compiled without SMP support, it won't accept values +# different from 1. +# +# QUANTUM: +# Maximum amount of instructions allowed to execute by processor before +# returning control to another cpu. This option exists only in Bochs +# binary compiled with SMP support. +# +# RESET_ON_TRIPLE_FAULT: +# Reset the CPU when triple fault occur (highly recommended) rather than +# PANIC. Remember that if you trying to continue after triple fault the +# simulation will be completely bogus ! +# +# CPUID_LIMIT_WINNT: +# Determine whether to limit maximum CPUID function to 2. This mode is +# required to workaround WinNT installation and boot issues. +# +# MSRS: +# Define path to user CPU Model Specific Registers (MSRs) specification. +# See example in msrs.def. +# +# IGNORE_BAD_MSRS: +# Ignore MSR references that Bochs does not understand; print a warning +# message instead of generating #GP exception. This option is enabled +# by default but will not be avaiable if configurable MSRs are enabled. +# +# MWAIT_IS_NOP: +# When this option is enabled MWAIT will not put the CPU into a sleep state. +# This option exists only if Bochs compiled with --enable-monitor-mwait. +# +# IPS: +# Emulated Instructions Per Second. This is the number of IPS that bochs +# is capable of running on your machine. You can recompile Bochs with +# --enable-show-ips option enabled, to find your host's capability. +# Measured IPS value will then be logged into your log file or shown +# in the status bar (if supported by the gui). +# +# IPS is used to calibrate many time-dependent events within the bochs +# simulation. For example, changing IPS affects the frequency of VGA +# updates, the duration of time before a key starts to autorepeat, and +# the measurement of BogoMips and other benchmarks. +# +# Examples: +# +# Bochs Machine/Compiler Mips +# ______________________________________________________________________ +# 2.4.6 3.4Ghz Intel Core i7 2600 with Win7x64/g++ 4.5.2 85 to 95 Mips +# 2.3.7 3.2Ghz Intel Core 2 Q9770 with WinXP/g++ 3.4 50 to 55 Mips +# 2.3.7 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4 38 to 43 Mips +# 2.2.6 2.6Ghz Intel Core 2 Duo with WinXP/g++ 3.4 21 to 25 Mips +# 2.2.6 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4 12 to 15 Mips +#======================================================================= +#cpu: model=core2_penryn_t9600, ips=10000 + +#======================================================================= +# CPUID: +# +# This defines features and functionality supported by Bochs emulated CPU. +# The option has no offect if CPU model was selected in CPU option. +# +# MMX: +# Select MMX instruction set support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5. +# +# APIC: +# Select APIC configuration (LEGACY/XAPIC/XAPIC_EXT/X2APIC). +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 5. +# +# SEP: +# Select SYSENTER/SYSEXIT instruction set support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# SSE: +# Select SSE instruction set support. +# Any of NONE/SSE/SSE2/SSE3/SSSE3/SSE4_1/SSE4_2 could be selected. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# SSE4A: +# Select AMD SSE4A instructions support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# MISALIGNED_SSE: +# Select AMD Misaligned SSE mode support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# AES: +# Select AES instruction set support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# MOVBE: +# Select MOVBE Intel(R) Atom instruction support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# ADX: +# Select ADCX/ADOX instructions support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# XSAVE: +# Select XSAVE extensions support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# XSAVEOPT: +# Select XSAVEOPT instruction support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# AVX: +# Select AVX/AVX2 instruction set support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# AVX_F16C: +# Select AVX float16 convert instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# AVX_FMA: +# Select AVX fused multiply add (FMA) instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# BMI: +# Select BMI1/BMI2 instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# XOP: +# Select AMD XOP instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# FMA4: +# Select AMD four operand FMA instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# TBM: +# Select AMD Trailing Bit Manipulation (TBM) instructions support. +# This option exists only if Bochs compiled with --enable-avx option. +# +# X86-64: +# Enable x86-64 and long mode support. +# This option exists only if Bochs compiled with x86-64 support. +# +# 1G_PAGES: +# Enable 1G page size support in long mode. +# This option exists only if Bochs compiled with x86-64 support. +# +# PCID: +# Enable Process-Context Identifiers (PCID) support in long mode. +# This option exists only if Bochs compiled with x86-64 support. +# +# FSGSBASE: +# Enable GS/GS BASE access instructions support in long mode. +# This option exists only if Bochs compiled with x86-64 support. +# +# SMEP: +# Enable Supervisor Mode Execution Protection (SMEP) support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# SMAP: +# Enable Supervisor Mode Access Protection (SMAP) support. +# This option exists only if Bochs compiled with BX_CPU_LEVEL >= 6. +# +# MWAIT: +# Select MONITOR/MWAIT instructions support. +# This option exists only if Bochs compiled with --enable-monitor-mwait. +# +# VMX: +# Select VMX extensions emulation support. +# This option exists only if Bochs compiled with --enable-vmx option. +# +# SVM: +# Select AMD SVM (Secure Virtual Machine) extensions emulation support. +# This option exists only if Bochs compiled with --enable-svm option. +# +# VENDOR_STRING: +# Set the CPUID vendor string returned by CPUID(0x0). This should be a +# twelve-character ASCII string. +# +# BRAND_STRING: +# Set the CPUID vendor string returned by CPUID(0x80000002 .. 0x80000004). +# This should be at most a forty-eight-character ASCII string. +# +# FAMILY: +# Set model information returned by CPUID. Default family value determined +# by configure option --enable-cpu-level. +# +# MODEL: +# Set model information returned by CPUID. Default model value is 3. +# +# STEPPING: +# Set stepping information returned by CPUID. Default stepping value is 3. +#======================================================================= +#cpuid: x86_64=1, mmx=1, sep=1, sse=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1 +#cpuid: family=6, model=0x1a, stepping=5 + +#======================================================================= +# MEMORY +# Set the amount of physical memory you want to emulate. +# +# GUEST: +# Set amount of guest physical memory to emulate. The default is 32MB, +# the maximum amount limited only by physical address space limitations. +# +# HOST: +# Set amount of host memory you want to allocate for guest RAM emulation. +# It is possible to allocate less memory than you want to emulate in guest +# system. This will fake guest to see the non-existing memory. Once guest +# system touches new memory block it will be dynamically taken from the +# memory pool. You will be warned (by FATAL PANIC) in case guest already +# used all allocated host memory and wants more. +# +#======================================================================= +memory: guest=8, host=8 + +#======================================================================= +# OPTROMIMAGE[1-4]: +# You may now load up to 4 optional ROM images. Be sure to use a +# read-only area, typically between C8000 and EFFFF. These optional +# ROM images should not overwrite the rombios (located at +# F0000-FFFFF) and the videobios (located at C0000-C7FFF). +# Those ROM images will be initialized by the bios if they contain +# the right signature (0x55AA) and a valid checksum. +# It can also be a convenient way to upload some arbitrary code/data +# in the simulation, that can be retrieved by the boot loader +#======================================================================= +#optromimage1: file=optionalrom.bin, address=0xd0000 +#optromimage2: file=optionalrom.bin, address=0xd1000 +#optromimage3: file=optionalrom.bin, address=0xd2000 +#optromimage4: file=optionalrom.bin, address=0xd3000 + +#optramimage1: file=/path/file1.img, address=0x0010000 +#optramimage2: file=/path/file2.img, address=0x0020000 +#optramimage3: file=/path/file3.img, address=0x0030000 +#optramimage4: file=/path/file4.img, address=0x0040000 + +#======================================================================= +# VGAROMIMAGE +# You now need to load a VGA ROM BIOS into C0000. +#======================================================================= +#vgaromimage: file=bios/VGABIOS-elpin-2.40 +vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest +#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus + +#======================================================================= +# VGA: +# This defines parameters related to the VGA display +# +# EXTENSION +# Here you can specify the display extension to be used. With the value +# 'none' you can use standard VGA with no extension. Other supported +# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support. +# +# UPDATE_FREQ +# The VGA update frequency is based on the emulated clock and the default +# value is 5. Keep in mind that you must tweak the 'cpu: ips=N' directive +# to be as close to the number of emulated instructions-per-second your +# workstation can do, for this to be accurate. If the realtime sync is +# enabled with the 'clock' option, the value is based on the real time. +# This parameter can be changed at runtime. +# +# Examples: +# vga: extension=cirrus, update_freq=10 +#======================================================================= +#vga: extension=vbe, update_freq=5 + +#======================================================================= +# FLOPPYA: +# Point this to pathname of floppy image file or device +# This should be of a bootable floppy(image/device) if you're +# booting from 'a' (or 'floppy'). +# +# You can set the initial status of the media to 'ejected' or 'inserted'. +# floppya: 2_88=path, status=ejected (2.88M 3.5" media) +# floppya: 1_44=path, status=inserted (1.44M 3.5" media) +# floppya: 1_2=path, status=ejected (1.2M 5.25" media) +# floppya: 720k=path, status=inserted (720K 3.5" media) +# floppya: 360k=path, status=inserted (360K 5.25" media) +# floppya: 320k=path, status=inserted (320K 5.25" media) +# floppya: 180k=path, status=inserted (180K 5.25" media) +# floppya: 160k=path, status=inserted (160K 5.25" media) +# floppya: image=path, status=inserted (guess media type from image size) +# floppya: 1_44=vvfat:path, status=inserted (use directory as VFAT media) +# floppya: type=1_44 (1.44M 3.5" floppy drive, no media) +# +# The path should be the name of a disk image file. On Unix, you can use a raw +# device name such as /dev/fd0 on Linux. On win32 platforms, use drive letters +# such as a: or b: as the path. The parameter 'image' works with image files +# only. In that case the size must match one of the supported types. +# The parameter 'type' can be used to enable the floppy drive without media +# and status specified. Usually the drive type is set up based on the media type. +# The optional parameter 'write_protected' can be used to control the media +# write protect switch. By default it is turned off. +#======================================================================= +floppya: 1_44=/dev/fd0, status=inserted +#floppya: image=../1.44, status=inserted +#floppya: 1_44=/dev/fd0H1440, status=inserted +#floppya: 1_2=../1_2, status=inserted +#floppya: 1_44=a:, status=inserted +#floppya: 1_44=a.img, status=inserted, write_protected=1 +#floppya: 1_44=/dev/rfd0a, status=inserted + +#======================================================================= +# FLOPPYB: +# See FLOPPYA above for syntax +#======================================================================= +#floppyb: 1_44=b:, status=inserted +#floppyb: 1_44=b.img, status=inserted + +#======================================================================= +# ATA0, ATA1, ATA2, ATA3 +# ATA controller for hard disks and cdroms +# +# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number +# +# These options enables up to 4 ata channels. For each channel +# the two base io addresses and the irq must be specified. +# +# ata0 and ata1 are enabled by default with the values shown below +# +# Examples: +# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9 +#======================================================================= +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9 + +#======================================================================= +# ATA[0-3]-MASTER, ATA[0-3]-SLAVE +# +# This defines the type and characteristics of all attached ata devices: +# type= type of attached device [disk|cdrom] +# mode= only valid for disks [flat|concat|external|dll|sparse|vmware3] +# [vmware4|undoable|growing|volatile|vpc|vvfat] +# path= path of the image / directory +# cylinders= only valid for disks +# heads= only valid for disks +# spt= only valid for disks +# status= only valid for cdroms [inserted|ejected] +# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos] +# translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto] +# model= string returned by identify device command +# journal= optional filename of the redolog for undoable, volatile and vvfat disks +# +# Point this at a hard disk image file, cdrom iso file, or physical cdrom +# device. To create a hard disk image, try running bximage. It will help you +# choose the size and then suggest a line that works with it. +# +# In UNIX it may be possible to use a raw device as a Bochs hard disk, +# but WE DON'T RECOMMEND IT. In Windows there is no easy way. +# +# In windows, the drive letter + colon notation should be used for cdroms. +# Depending on versions of windows and drivers, you may only be able to +# access the "first" cdrom in the system. On MacOSX, use path="drive" +# to access the physical drive. +# +# The path is mandatory for hard disks. Disk geometry autodetection works with +# images created by bximage if CHS is set to 0/0/0 (cylinders are calculated +# using heads=16 and spt=63). For other hard disk images and modes the +# cylinders, heads, and spt are mandatory. In all cases the disk size reported +# from the image must be exactly C*H*S*512. +# +# Default values are: +# mode=flat, biosdetect=auto, translation=auto, model="Generic 1234" +# +# The biosdetect option has currently no effect on the bios +# +# Examples: +# ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17 +# ata0-slave: type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17 +# ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17 +# ata1-slave: type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17 +# ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17 +# ata2-slave: type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17 +# ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63 +# ata3-slave: type=cdrom, path=iso.sample, status=inserted +#======================================================================= +ata0-master: type=disk, mode=flat, path="SWEB-flat.vmdk" +#ata0-master: type=disk, mode=flat, path="30M.sample", cylinders=615, heads=6, spt=17 +#ata0-master: type=disk, mode=flat, path="c.img", cylinders=0 # autodetect +#ata0-slave: type=disk, mode=vvfat, path=/bochs/images/vvfat, journal=vvfat.redolog +#ata0-slave: type=cdrom, path=D:, status=inserted +#ata0-slave: type=cdrom, path=/dev/cdrom, status=inserted +#ata0-slave: type=cdrom, path="drive", status=inserted +#ata0-slave: type=cdrom, path=/dev/rcd0d, status=inserted + +#======================================================================= +# BOOT: +# This defines the boot sequence. Now you can specify up to 3 boot drives, +# which can be 'floppy', 'disk', 'cdrom' or 'network' (boot ROM). +# Legacy 'a' and 'c' are also supported. +# Examples: +# boot: floppy +# boot: cdrom, disk +# boot: network, disk +# boot: cdrom, floppy, disk +#======================================================================= +#boot: floppy +boot: disk + +#======================================================================= +# CLOCK: +# This defines the parameters of the clock inside Bochs: +# +# SYNC: +# This defines the method how to synchronize the Bochs internal time +# with realtime. With the value 'none' the Bochs time relies on the IPS +# value and no host time synchronization is used. The 'slowdown' method +# sacrifices performance to preserve reproducibility while allowing host +# time correlation. The 'realtime' method sacrifices reproducibility to +# preserve performance and host-time correlation. +# It is possible to enable both synchronization methods. +# +# RTC_SYNC: +# If this option is enabled together with the realtime synchronization, +# the RTC runs at realtime speed. This feature is disabled by default. +# +# TIME0: +# Specifies the start (boot) time of the virtual machine. Use a time +# value as returned by the time(2) system call. If no time0 value is +# set or if time0 equal to 1 (special case) or if time0 equal 'local', +# the simulation will be started at the current local host time. +# If time0 equal to 2 (special case) or if time0 equal 'utc', +# the simulation will be started at the current utc time. +# +# Syntax: +# clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc] +# +# Example: +# clock: sync=none, time0=local # Now (localtime) +# clock: sync=slowdown, time0=315529200 # Tue Jan 1 00:00:00 1980 +# clock: sync=none, time0=631148400 # Mon Jan 1 00:00:00 1990 +# clock: sync=realtime, time0=938581955 # Wed Sep 29 07:12:35 1999 +# clock: sync=realtime, time0=946681200 # Sat Jan 1 00:00:00 2000 +# clock: sync=none, time0=1 # Now (localtime) +# clock: sync=none, time0=utc # Now (utc/gmt) +# +# Default value are sync=none, time0=local +#======================================================================= +#clock: sync=none, time0=local + + +#======================================================================= +# FLOPPY_BOOTSIG_CHECK: disabled=[0|1] +# Enables or disables the 0xaa55 signature check on boot floppies +# Defaults to disabled=0 +# Examples: +# floppy_bootsig_check: disabled=0 +# floppy_bootsig_check: disabled=1 +#======================================================================= +floppy_bootsig_check: disabled=0 + +#======================================================================= +# LOG: +# Give the path of the log file you'd like Bochs debug and misc. verbiage +# to be written to. If you don't use this option or set the filename to +# '-' the output is written to the console. If you really don't want it, +# make it "/dev/null" (Unix) or "nul" (win32). :^( +# +# Examples: +# log: ./bochs.out +# log: /dev/tty +#======================================================================= +log: /dev/null +#log: bochsout.txt + +#======================================================================= +# LOGPREFIX: +# This handles the format of the string prepended to each log line. +# You may use those special tokens : +# %t : 11 decimal digits timer tick +# %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration) +# %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror) +# %d : 5 characters string of the device, between brackets +# +# Default : %t%e%d +# Examples: +# logprefix: %t-%e-@%i-%d +# logprefix: %i%e%d +#======================================================================= +#logprefix: %t%e%d + +#======================================================================= +# LOG CONTROLS +# +# Bochs has four severity levels for event logging. +# panic: cannot proceed. If you choose to continue after a panic, +# don't be surprised if you get strange behavior or crashes. +# error: something went wrong, but it is probably safe to continue the +# simulation. +# info: interesting or useful messages. +# debug: messages useful only when debugging the code. This may +# spit out thousands per second. +# +# For events of each level, you can choose to exit Bochs ('fatal'), 'report' +# or 'ignore'. On some guis you have the additional choice 'ask'. A gui dialog +# appears asks how to proceed. +# +# It is also possible to specify the 'action' to do for each Bochs facility +# separately (e.g. crash on panics from everything except the cdrom, and only +# report those). See the 'log function' module list in the user documentation. +# +# If you are experiencing many panics, it can be helpful to change +# the panic action to report instead of fatal. However, be aware +# that anything executed after a panic is uncharted territory and can +# cause bochs to become unstable. The panic is a "graceful exit," so +# if you disable it you may get a spectacular disaster instead. +#======================================================================= +panic: action=ask +error: action=ignore +info: action=ignore +#debug: action=ignore # report BX_DEBUG from module 'pci' + +#======================================================================= +# DEBUGGER_LOG: +# Give the path of the log file you'd like Bochs to log debugger output. +# If you really don't want it, make it /dev/null or '-'. :^( +# +# Examples: +# debugger_log: ./debugger.out +#======================================================================= +debugger_log: /dev/null +#debugger_log: debugger.out +#debugger_log: - + +#======================================================================= +# COM1, COM2, COM3, COM4: +# This defines a serial port (UART type 16550A). In the 'term' mode you can +# specify a device to use as com1. This can be a real serial line, or a pty. +# To use a pty (under X/Unix), create two windows (xterms, usually). One of +# them will run bochs, and the other will act as com1. Find out the tty the com1 +# window using the `tty' command, and use that as the `dev' parameter. +# Then do `sleep 1000000' in the com1 window to keep the shell from +# messing with things, and run bochs in the other window. Serial I/O to +# com1 (port 0x3f8) will all go to the other window. +# In socket* and pipe* (win32 only) modes Bochs becomes either socket/named pipe +# client or server. In client mode it connects to an already running server (if +# connection fails Bochs treats com port as not connected). In server mode it +# opens socket/named pipe and waits until a client application connects to it +# before starting simulation. This mode is useful for remote debugging (e.g. +# with gdb's "target remote host:port" command or windbg's command line option +# -k com:pipe,port=\\.\pipe\pipename). Socket modes use simple TCP communication, +# pipe modes use duplex byte mode pipes. +# Other serial modes are 'null' (no input/output), 'file' (output to a file +# specified as the 'dev' parameter), 'raw' (use the real serial port - under +# construction for win32), 'mouse' (standard serial mouse - requires +# mouse option setting 'type=serial', 'type=serial_wheel' or 'type=serial_msys'). +# +# Examples: +# com1: enabled=1, mode=null +# com1: enabled=1, mode=mouse +# com2: enabled=1, mode=file, dev=serial.out +# com3: enabled=1, mode=raw, dev=com1 +# com3: enabled=1, mode=socket-client, dev=localhost:8888 +# com3: enabled=1, mode=socket-server, dev=localhost:8888 +# com4: enabled=1, mode=pipe-client, dev=\\.\pipe\mypipe +# com4: enabled=1, mode=pipe-server, dev=\\.\pipe\mypipe +#======================================================================= +#com1: enabled=1, mode=term, dev=/dev/ttyp9 + + +#======================================================================= +# PARPORT1, PARPORT2: +# This defines a parallel (printer) port. When turned on and an output file is +# defined the emulated printer port sends characters printed by the guest OS +# into the output file. On some platforms a device filename can be used to +# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on +# win32 platforms). +# +# Examples: +# parport1: enabled=1, file="parport.out" +# parport2: enabled=1, file="/dev/lp0" +# parport1: enabled=0 +#======================================================================= +parport1: enabled=1, file="parport.out" + +#======================================================================= +# SB16: +# This defines the SB16 sound emulation. It can have several of the +# following properties. +# All properties are in the format sb16: property=value +# enabled: +# This optional property controls the presence of the SB16 emulation. +# The emulation is turned on unless this property is used and set to 0. +# midi: The filename is where the midi data is sent. This can be a +# device or just a file if you want to record the midi data. +# midimode: +# 0=no data +# 1=output to device (system dependent. midi denotes the device driver) +# 2=SMF file output, including headers +# 3=output the midi data stream to the file (no midi headers and no +# delta times, just command and data bytes) +# wave: This is the device/file where wave output is stored +# wavemode: +# 0=no data +# 1=output to device (system dependent. wave denotes the device driver) +# 2=VOC file output, incl. headers +# 3=output the raw wave stream to the file +# log: The file to write the sb16 emulator messages to. +# loglevel: +# 0=no log +# 1=resource changes, midi program and bank changes +# 2=severe errors +# 3=all errors +# 4=all errors plus all port accesses +# 5=all errors and port accesses plus a lot of extra info +# dmatimer: +# microseconds per second for a DMA cycle. Make it smaller to fix +# non-continuous sound. 750000 is usually a good value. This needs a +# reasonably correct setting for the IPS parameter of the CPU option. +# +# Examples for output devices: +# sb16: midimode=1, midi="", wavemode=1, wave="" # win32 +# sb16: midimode=1, midi=alsa:128:0, wavemode=1, wave=alsa # Linux with ALSA +# sb16: wavemode=1, wave=sdl # use SDL audio (if present) for output +#======================================================================= +#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000 + +#======================================================================= +# ES1370: +# This defines the ES1370 sound emulation. The parameter 'enabled' controls the +# presence of the device. The 'wavedev' parameter is similar to the 'wave' +# parameter of the SB16 soundcard. The emulation supports recording and playback +# (except DAC1+DAC2 output at the same time). +# +# Examples: +# es1370: enabled=1, wavedev="" # win32 +# es1370: enabled=1, wavedev=alsa # Linux with ALSA +# es1370: enabled=1, wavedev=sdl # use SDL audio (if present) for output +#======================================================================= +#es1370: enabled=1, wavedev=alsa + +#======================================================================= +# KEYBOARD: +# This defines parameters related to the emulated keyboard +# +# TYPE: +# Type of keyboard return by a "identify keyboard" command to the +# keyboard controller. It must be one of "xt", "at" or "mf". +# Defaults to "mf". It should be ok for almost everybody. A known +# exception is french macs, that do have a "at"-like keyboard. +# +# SERIAL_DELAY: +# Approximate time in microseconds that it takes one character to +# be transferred from the keyboard to controller over the serial path. +# +# PASTE_DELAY: +# Approximate time in microseconds between attempts to paste +# characters to the keyboard controller. This leaves time for the +# guest os to deal with the flow of characters. The ideal setting +# depends on how your operating system processes characters. The +# default of 100000 usec (.1 seconds) was chosen because it works +# consistently in Windows. +# If your OS is losing characters during a paste, increase the paste +# delay until it stops losing characters. +# +# KEYMAP: +# This enables a remap of a physical localized keyboard to a +# virtualized us keyboard, as the PC architecture expects. +# +# USER_SHORTCUT: +# This defines the keyboard shortcut to be sent when you press the "user" +# button in the headerbar. The shortcut string is a combination of maximum +# 3 key names (listed below) separated with a '-' character. +# Valid key names: +# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc", +# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup", +# "plus", "right", "shift", "space", "tab", "up", "win", "print" and "power". + +# Examples: +# keyboard: type=mf, serial_delay=200, paste_delay=100000 +# keyboard: keymap=gui/keymaps/x11-pc-de.map +# keyboard: user_shortcut=ctrl-alt-del +#======================================================================= +#keyboard: type=mf, serial_delay=250 + +#======================================================================= +# MOUSE: +# This defines parameters for the emulated mouse type, the initial status +# of the mouse capture and the runtime method to toggle it. +# +# TYPE: +# With the mouse type option you can select the type of mouse to emulate. +# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse +# on PS/2), 'serial', 'serial_wheel' and 'serial_msys' (one com port requires +# setting 'mode=mouse'). To connect a mouse to an USB port, see the 'usb_uhci', +# 'usb_ohci' or 'usb_xhci' options (requires PCI and USB support). +# +# ENABLED: +# The Bochs gui creates mouse "events" unless the 'enabled' option is +# set to 0. The hardware emulation itself is not disabled by this. +# Unless you have a particular reason for enabling the mouse by default, +# it is recommended that you leave it off. You can also toggle the mouse +# usage at runtime (RFB, SDL, Win32, wxWidgets and X11 - see below). +# +# TOGGLE: +# The default method to toggle the mouse capture at runtime is to press the +# CTRL key and the middle mouse button ('ctrl+mbutton'). This option allows +# to change the method to 'ctrl+f10' (like DOSBox), 'ctrl+alt' (like QEMU) +# or 'f12' (replaces win32 'legacyF12' option). +# +# Examples: +# mouse: enabled=1 +# mouse: type=imps2, enabled=1 +# mouse: type=serial, enabled=1 +# mouse: enabled=0, toggle=ctrl+f10 +#======================================================================= +mouse: enabled=0 + +#======================================================================= +# private_colormap: Request that the GUI create and use it's own +# non-shared colormap. This colormap will be used +# when in the bochs window. If not enabled, a +# shared colormap scheme may be used. Not implemented +# on all GUI's. +# +# Examples: +# private_colormap: enabled=1 +# private_colormap: enabled=0 +#======================================================================= +private_colormap: enabled=0 + +#======================================================================= +# fullscreen: ONLY IMPLEMENTED ON AMIGA +# Request that Bochs occupy the entire screen instead of a +# window. +# +# Examples: +# fullscreen: enabled=0 +# fullscreen: enabled=1 +#======================================================================= +#fullscreen: enabled=0 +#screenmode: name="sample" + +#======================================================================= +# ne2k: NE2000 compatible ethernet adapter +# +# Format: +# ne2k: enabled=1, ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, +# ethdev=DEVICE, script=SCRIPT, bootrom=BOOTROM +# +# IOADDR, IRQ: You probably won't need to change ioaddr and irq, unless there +# are IRQ conflicts. These arguments are ignored when assign the ne2k to a +# PCI slot. +# +# MAC: The MAC address MUST NOT match the address of any machine on the net. +# Also, the first byte must be an even number (bit 0 set means a multicast +# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast +# address. For the ethertap module, you must use fe:fd:00:00:00:01. There may +# be other restrictions too. To be safe, just use the b0:c4... address. +# +# ETHDEV: The ethdev value is the name of the network interface on your host +# platform. On UNIX machines, you can get the name by running ifconfig. On +# Windows machines, you must run niclist to get the name of the ethdev. +# Niclist source code is in misc/niclist.c and it is included in Windows +# binary releases. +# +# SCRIPT: The script value is optional, and is the name of a script that +# is executed after bochs initialize the network interface. You can use +# this script to configure this network interface, or enable masquerading. +# This is mainly useful for the tun/tap devices that only exist during +# Bochs execution. The network interface name is supplied to the script +# as first parameter. +# +# BOOTROM: The bootrom value is optional, and is the name of the ROM image +# to load. Note that this feature is only implemented for the PCI version of +# the NE2000. +# +# If you don't want to make connections to any physical networks, +# you can use the following 'ethmod's to simulate a virtual network. +# null: All packets are discarded, but logged to a few files. +# vde: Virtual Distributed Ethernet +# vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated. +# The virtual host uses 192.168.10.1. +# DHCP assigns 192.168.10.2 to the guest. +# TFTP uses the 'ethdev' value for the root directory and doesn't +# overwrite files. +# +#======================================================================= +# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0 +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0 +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD +# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0 +# ne2k: ioaddr=0x300, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0 +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl" +# ne2k: ioaddr=0x300, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp" +# ne2k: mac=b0:c4:20:00:00:01, ethmod=slirp, script=/usr/local/bin/slirp, bootrom=ne2k_pci.rom + +#======================================================================= +# pcipnic: Bochs/Etherboot pseudo-NIC +# +# Format: +# pcipnic: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT, +# bootrom=BOOTROM +# +# The pseudo-NIC accepts the same syntax (for mac, ethmod, ethdev, script, +# bootrom) and supports the same networking modules as the NE2000 adapter. +#======================================================================= +#pcipnic: enabled=1, mac=b0:c4:20:00:00:00, ethmod=vnet + +#======================================================================= +# e1000: Intel(R) 82540EM Gigabit Ethernet adapter +# +# Format: +# e1000: enabled=1, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT +# bootrom=BOOTROM +# +# The E1000 accepts the same syntax (for mac, ethmod, ethdev, script, bootrom) +# and supports the same networking modules as the NE2000 adapter. +#======================================================================= +#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=/usr/local/bin/slirp + +#======================================================================= +# PCI: +# This option controls the presence of a PCI chipset in Bochs. Currently it only +# supports the i440FX chipset. You can also specify the devices connected to +# PCI slots. Up to 5 slots are available. For these combined PCI/ISA devices +# assigning to slot is mandatory if you want to emulate the PCI model: cirrus, +# ne2k and pcivga. These PCI-only devices are also supported, but they are +# auto-assigned if you don't use the slot configuration: e1000, es1370, pcidev, +# pcipnic, usb_ohci and usb_xhci. +# +# Example: +# pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k +#======================================================================= +#pci: enabled=1, chipset=i440fx + +#======================================================================= +# USB_UHCI: +# This option controls the presence of the USB root hub which is a part +# of the i440FX PCI chipset. With the portX parameter you can connect devices +# to the hub (currently supported: 'mouse', 'tablet', 'keypad', 'disk', 'cdrom' +# 'hub' and 'printer'). +# +# The optionsX parameter can be used to assign specific options to the device +# connected to the corresponding USB port. Currently this feature is only used +# to set the speed reported by device and by the 'disk' device to specify +# an alternative redolog file of some image modes. +# +# If you connect the mouse or tablet to one of the ports, Bochs forwards the +# mouse movement data to the USB device instead of the selected mouse type. +# When connecting the keypad to one of the ports, Bochs forwards the input of +# the numeric keypad to the USB device instead of the PS/2 keyboard. +# +# To connect a 'flat' mode image as an USB hardisk you can use the 'disk' device +# with the path to the image separated with a colon. To use other disk image modes +# similar to ATA disks the syntax 'disk:mode:filename' must be used (see below). +# +# To emulate an USB cdrom you can use the 'cdrom' device name and the path to +# an ISO image or raw device name also separated with a colon. An option to +# insert/eject media is available in the runtime configuration. +# +# The device name 'hub' connects an external hub with max. 8 ports (default: 4) +# to the root hub. To specify the number of ports you have to add the value +# separated with a colon. Connecting devices to the external hub ports is only +# available in the runtime configuration. +# +# The device 'printer' emulates the HP Deskjet 920C printer. The PCL data is +# sent to a file specified in bochsrc.txt. The current code appends the PCL +# code to the file if the file already existed. It would probably be nice to +# overwrite the file instead, asking user first. +#======================================================================= +#usb_uhci: enabled=1 +#usb_uhci: enabled=1, port1=mouse, port2=disk:usbstick.img +#usb_uhci: enabled=1, port1=hub:7, port2=disk:growing:usbdisk.img +#usb_uhci: enabled=1, port2=disk:undoable:usbdisk.img, options1=journal:redo.log +#usb_uhci: enabled=1, port1=printer:printdata.bin, port2=cdrom:image.iso + +#======================================================================= +# USB_OHCI: +# This option controls the presence of the USB OHCI host controller with a +# 2-port hub. The portX option accepts the same device types with the same +# syntax as the UHCI controller (see above). +#======================================================================= +#usb_ohci: enabled=1 +#usb_ohci: enabled=1, port1=printer:usbprinter.bin + +#======================================================================= +# USB_XHCI: +# This option controls the presence of the experimental USB xHCI host controller +# with a 4-port hub. The portX option accepts the same device types with the +# same syntax as the UHCI controller (see above). +#======================================================================= +#usb_xhci: enabled=1 + +#======================================================================= +# CMOSIMAGE: +# This defines image file that can be loaded into the CMOS RAM at startup. +# The rtc_init parameter controls whether initialize the RTC with values stored +# in the image. By default the time0 argument given to the clock option is used. +# With 'rtc_init=image' the image is the source for the initial time. +# +# Example: +# cmosimage: file=cmos.img, rtc_init=image +#======================================================================= +#cmosimage: file=cmos.img, rtc_init=time0 + +#======================================================================= +# MAGIC_BREAK: +# This enables the "magic breakpoint" feature when using the debugger. +# The useless cpu instruction XCHG BX, BX causes Bochs to enter the +# debugger mode. This might be useful for software development. +# +# Example: +# magic_break: enabled=1 +#======================================================================= +#magic_break: enabled=1 + +#======================================================================= +# PORT_E9_HACK: +# The 0xE9 port doesn't exists in normal ISA architecture. However, we +# define a convention here, to display on the console of the system running +# Bochs anything that is written to it. The idea is to provide debug output +# very early when writing BIOS or OS code for example, without having to +# bother with setting up a serial port or etc. Reading from port 0xE9 will +# will return 0xe9 to let you know if the feature is available. +# Leave this 0 unless you have a reason to use it. +# +# Example: +# port_e9_hack: enabled=1 +#======================================================================= +port_e9_hack: enabled=1 + +#======================================================================= +# DEBUG_SYMBOLS: +# This loads symbols from the specified file for use in Bochs' internal +# debugger. Symbols are loaded into global context. This is equivalent to +# issuing ldsym debugger command at start up. +# +# Example: +# debug_symbols: file="kernel.sym" +# debug_symbols: file="kernel.sym", offset=0x80000000 +#======================================================================= +#debug_symbols: file="kernel.sym" + +#======================================================================= +# other stuff +#======================================================================= +#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log +#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img +#print_timestamps: enabled=1 + +#------------------------- +# PCI host device mapping +#------------------------- +#pcidev: vendor=0x1234, device=0x5678 + +#======================================================================= +# GDBSTUB: +# Enable GDB stub. See user documentation for details. +# Default value is enabled=0. +#======================================================================= +#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0 + +#======================================================================= +# USER_PLUGIN: +# Load user-defined plugin. This option is available only if Bochs is +# compiled with plugin support. Maximum 8 different plugins are supported. +# See the example in the Bochs sources how to write a plugin device. +#======================================================================= +#user_plugin: name=testdev + +#======================================================================= +# for Macintosh, use the style of pathnames in the following +# examples. +# +# vgaromimage: :bios:VGABIOS-elpin-2.40 +# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000 +# floppya: 1_44=[fd:], status=inserted +#======================================================================= + +#======================================================================= +# MEGS +# Set the number of Megabytes of physical memory you want to emulate. +# The default is 32MB, most OS's won't need more than that. +# The maximum amount of memory supported is 2048Mb. +# The 'MEGS' option is deprecated. Use 'MEMORY' option instead. +#======================================================================= +#megs: 256 +#megs: 128 +#megs: 64 +#megs: 32 +#megs: 16 +#megs: 8 diff --git a/pwn/flipper/dist/utils/emu.txt b/pwn/flipper/dist/utils/emu.txt new file mode 100644 index 0000000..f40d899 --- /dev/null +++ b/pwn/flipper/dist/utils/emu.txt @@ -0,0 +1,43 @@ + /-/-=/-= + // ZX " + / /XZXZX(o) ---, + / XZXZXZXZX _____`\ + /ZXZXZXZX + / ;,ZXZ + / :ZX%\ + /% : X\ + :/: %:X: + /%:% %\\ + /:%: % \ + / :% : \ + / :% :%\ + /% % \ + /%: %: %\ + //% : %\ + %%%%%%%%%% %% %% / / : : + %%%%%%%% %% % %%%% \: + %%%%%% : \ + %%%% :%:\ + % % % \ + % %% \ + % %%% %%%%%% \ + % %%%%%%%% %%%\ + % %% %%%%%% %\ + % %%%%%%%%%%%%% %%%%\\ + %%%%/%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% %%% %%\ + / %%%%%%%%% % %% % %%% % %%%%% %%%\ + (_____)%%(_____)%%%%%%\ + ((_____) ((____) + (___) (___) + (__) (__) + (__) (__) + (__) (__) + (__) (__) + ( ) ( ) V@V + ( ) ( ) | + ( ) ( ) \ | / / + (__ | (___ | \ | / + ___( / \ \____ \ |--- \\|// + <(____/ \_____(>\_____(> -===-= + + -==--=-- -= -=-=- -==-=-=- -=-==- =-=-=- -=-=- diff --git a/pwn/flipper/dist/utils/exe2minixfs/CMakeLists.txt b/pwn/flipper/dist/utils/exe2minixfs/CMakeLists.txt new file mode 100644 index 0000000..b2f0cd1 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.1.0) + +file(GLOB util_exe2minixfs_SOURCES *.cpp + ../../common/source/util/Bitmap.cpp + ../../common/source/fs/Inode.cpp + ../../common/source/fs/Dentry.cpp + ../../common/source/fs/FileDescriptor.cpp + ../../common/source/fs/FileSystemInfo.cpp + ../../common/source/fs/FileSystemType.cpp + ../../common/source/fs/Superblock.cpp + ../../common/source/fs/File.cpp + ../../common/source/fs/PathWalker.cpp + ../../common/source/fs/Path.cpp + ../../common/source/fs/VfsMount.cpp + ../../common/source/fs/VfsSyscall.cpp + ../../common/source/fs/minixfs/MinixFSFile.cpp + ../../common/source/fs/minixfs/MinixFSInode.cpp + ../../common/source/fs/minixfs/MinixFSSuperblock.cpp + ../../common/source/fs/minixfs/MinixFSZone.cpp + ../../common/source/fs/minixfs/MinixStorageManager.cpp + ../../common/source/fs/minixfs/StorageManager.cpp) + +add_executable(exe2minixfs ${util_exe2minixfs_SOURCES}) + +target_include_directories(exe2minixfs + PRIVATE + . + ustl + ../../common/include/util + ../../common/include/fs + ../../common/include/fs/minixfs + ../../common/include/console +) + +target_compile_definitions(exe2minixfs PRIVATE EXE2MINIXFS=1) diff --git a/pwn/flipper/dist/utils/exe2minixfs/MinixFSType.h b/pwn/flipper/dist/utils/exe2minixfs/MinixFSType.h new file mode 100644 index 0000000..09f378d --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/MinixFSType.h @@ -0,0 +1,29 @@ +#pragma once + +#include "FileSystemType.h" +#include "assert.h" + +class MinixFSType : public FileSystemType +{ +public: + MinixFSType() : + FileSystemType("minixfs") + { + + } + + virtual ~MinixFSType() + { + + } + + virtual Superblock *readSuper(Superblock *, void *) const + { + assert(0 && "Not implemented in exe2minixfs"); + } + + virtual Superblock *createSuper(uint32) + { + assert(0 && "Not implemented in exe2minixfs"); + } +}; diff --git a/pwn/flipper/dist/utils/exe2minixfs/Mutex.h b/pwn/flipper/dist/utils/exe2minixfs/Mutex.h new file mode 100644 index 0000000..cde72c2 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/Mutex.h @@ -0,0 +1,22 @@ +// WARNING: You are looking for a different Mutex.h - this one is just for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once + +class Mutex +{ +public: + + Mutex(const char*){}; + + Mutex(Mutex const &) = delete; + Mutex &operator=(Mutex const&) = delete; + + bool acquireNonBlocking(pointer = 0){return true;}; + + void acquire(pointer = 0){}; + void release(pointer = 0){}; + + bool isFree(){ return true; }; +}; + +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/MutexLock.h b/pwn/flipper/dist/utils/exe2minixfs/MutexLock.h new file mode 100644 index 0000000..ab74773 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/MutexLock.h @@ -0,0 +1,17 @@ +// WARNING: You are looking for a different MutexLock.h - this one is just for the exe2minixfs tool! + +#ifdef EXE2MINIXFS +#pragma once + +class Mutex; + +class MutexLock +{ +public: + MutexLock(Mutex &){}; + MutexLock(Mutex &, bool){}; + + MutexLock(MutexLock const&) = delete; + MutexLock &operator=(MutexLock const&) = delete; +}; +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/exe2minixfs.cpp b/pwn/flipper/dist/utils/exe2minixfs/exe2minixfs.cpp new file mode 100644 index 0000000..f42d44f --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/exe2minixfs.cpp @@ -0,0 +1,117 @@ +#ifdef EXE2MINIXFS +#include "types.h" +#include +#include +#include +#include +#include + +#include "Dentry.h" +#include "FileSystemInfo.h" +#include "Superblock.h" +#include "MinixFSType.h" +#include "MinixFSSuperblock.h" +#include "VfsSyscall.h" +#include "VfsMount.h" + +Superblock* superblock_; +FileSystemInfo* default_working_dir; + + +FileSystemInfo* getcwd() { return default_working_dir; } + +// obviously NOT atomic, we need this for compatability in single threaded host code +size_t atomic_add(size_t& x,size_t y) +{ + x += y; + return x-y; +} + +int main(int argc, char *argv[]) +{ + if (argc < 3 || argc % 2 == 0) + { + printf("Syntax: %s [file1-src file1-dest [file2-src file2-dest [....]]]\n", + argv[0]); + return -1; + } + + FILE* image_fd = fopen(argv[1], "r+b"); + + if (image_fd == 0) + { + printf("exe2minixfs: Error opening %s\n", argv[1]); + return -1; + } + + char* end; + size_t offset = strtoul(argv[2],&end,10); + if (strlen(end) != 0) + { + fclose(image_fd); + printf("exe2minixfs: disk offset has to be a number!\n"); + return -1; + } + + MinixFSType* minixfs_type = new MinixFSType(); + + superblock_ = (Superblock*) new MinixFSSuperblock(minixfs_type, (size_t)image_fd, offset); + Dentry *root = superblock_->getRoot(); + superblock_->setMountPoint(root); + Dentry *mount_point = superblock_->getMountPoint(); + mount_point->setMountedRoot(mount_point); + + VfsMount vfs_dummy_(nullptr, mount_point, root, superblock_, 0); + + + default_working_dir = new FileSystemInfo(); + Path root_path(root, &vfs_dummy_); + default_working_dir->setRoot(root_path); + default_working_dir->setPwd(root_path); + + for (int32 i = 2; i <= argc / 2; i++) + { + FILE* src_file = fopen(argv[2 * i - 1], "rb"); + + if (src_file == 0) + { + printf("exe2minixfs: Failed to open host file %s\n", argv[2 * i - 1]); + break; + } + + fseek(src_file, 0, SEEK_END); + size_t size = ftell(src_file); + + char *buf = new char[size]; + + fseek(src_file, 0, SEEK_SET); + assert(fread(buf, 1, size, src_file) == size && "exe2minixfs: fread was not able to read all bytes of the file"); + fclose(src_file); + + VfsSyscall::rm(argv[2 * i]); + int32 fd = VfsSyscall::open(argv[2 * i], 4 | 8); // i.e. O_RDWR | O_CREAT + if (fd < 0) + { + printf("exe2minixfs: Failed to open SWEB file %s\n", argv[2 * i]); + delete[] buf; + continue; + } + int32 write_status = VfsSyscall::write(fd, buf, size); + if((size_t)write_status != size) + { + printf("exe2minixfs: Writing %s failed with retval %d (expected %zu)\n", argv[2 * i], write_status, size); + } + VfsSyscall::close(fd); + + delete[] buf; + } + + delete default_working_dir; + delete superblock_; + delete minixfs_type; + fclose(image_fd); + + return 0; +} + +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/kprintf.h b/pwn/flipper/dist/utils/exe2minixfs/kprintf.h new file mode 100644 index 0000000..163a988 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/kprintf.h @@ -0,0 +1,10 @@ +// WARNING: You are looking for the other kprintf.h - this one is just for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include + +#define kprintfd(fmt,args...) do { printf(fmt, ## args); } while (0) +#define kprintf(fmt,args...) do { printf(fmt, ## args); } while (0) +#define debug(flag,fmt,args...) do { if (flag & 0x80000000) { printf(fmt,## args); } } while(0) +#define isDebugEnabled(flag) (flag & 0x80000000) +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/kstring.h b/pwn/flipper/dist/utils/exe2minixfs/kstring.h new file mode 100644 index 0000000..edfb60b --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/kstring.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/types.h b/pwn/flipper/dist/utils/exe2minixfs/types.h new file mode 100644 index 0000000..6db2c41 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/types.h @@ -0,0 +1,35 @@ +// WARNING: You are looking for a different types.h - this one is just for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once + +#define ArchThreads + +#include +#include +#include + +#define ustl std + +#include "../../common/include/console/debug.h" + +typedef int8_t int8; +typedef uint8_t uint8; + +typedef int16_t int16; +typedef uint16_t uint16; + +typedef int32_t int32; +typedef uint32_t uint32; + +typedef uint64_t uint64; +typedef int64_t int64; + +typedef void* pointer; + +typedef uint64_t l_off_t; + +class FileSystemInfo; + +size_t atomic_add(size_t& x,size_t y); + +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/sistream.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/sistream.h new file mode 100644 index 0000000..7e3240c --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/sistream.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/ualgo.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/ualgo.h new file mode 100644 index 0000000..02cae17 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/ualgo.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/uatomic.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/uatomic.h new file mode 100644 index 0000000..7439849 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/uatomic.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/ulist.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/ulist.h new file mode 100644 index 0000000..fae33a1 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/ulist.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/umap.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/umap.h new file mode 100644 index 0000000..10f9350 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/umap.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/exe2minixfs/ustl/ustring.h b/pwn/flipper/dist/utils/exe2minixfs/ustl/ustring.h new file mode 100644 index 0000000..860f5a1 --- /dev/null +++ b/pwn/flipper/dist/utils/exe2minixfs/ustl/ustring.h @@ -0,0 +1,5 @@ +// WARNING: This is only a dummy header for the exe2minixfs tool! +#ifdef EXE2MINIXFS +#pragma once +#include +#endif diff --git a/pwn/flipper/dist/utils/gdbinit b/pwn/flipper/dist/utils/gdbinit new file mode 100644 index 0000000..b7c3459 --- /dev/null +++ b/pwn/flipper/dist/utils/gdbinit @@ -0,0 +1,28 @@ +define stop_on_pagefault + handle SIGSEGV stop print pass + echo Now stopping on every pagefault\n +end +document stop_on_pagefault + Tells GDB to stop on every pagefault (default) +end + +define continue_on_pagefault + handle SIGSEGV nostop noprint nopass + echo Now continuing on every pagefault\n +end +document continue_on_pagefault + Tells GDB to ignore pagefaults +end + +set architecture i386:x86-64 + +# Connect to Bochs' gdbstub +target remote 127.0.0.1:1234 + +# Welcome message +echo \n\n +echo You can now set trace and breakpoints.\n +echo Enter 'continue' (or 'c') when you're done.\n + +break sweb_assert +break startup diff --git a/pwn/flipper/dist/utils/images/CMakeLists.txt b/pwn/flipper/dist/utils/images/CMakeLists.txt new file mode 100644 index 0000000..d7ba2de --- /dev/null +++ b/pwn/flipper/dist/utils/images/CMakeLists.txt @@ -0,0 +1,13 @@ + +set(HDD_IMAGE_FILE_SRC "${CMAKE_CURRENT_LIST_DIR}/SWEB-flat.vmdk.tar.gz") +set(HDD_IMAGE_FILE ${PROJECT_BINARY_DIR}/SWEB-flat.vmdk) + +#Custom Command: Outputs empty ext2 disk image +add_custom_command (OUTPUT ${HDD_IMAGE_FILE} + COMMAND ${CMAKE_COMMAND} -E tar xzf "${HDD_IMAGE_FILE_SRC}" + DEPENDS "${HDD_IMAGE_FILE_SRC}" + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Unpacking disk image..." + ) + +add_custom_target(blank_hdd_image DEPENDS ${HDD_IMAGE_FILE}) diff --git a/pwn/flipper/dist/utils/images/SWEB-flat.vmdk.tar.gz b/pwn/flipper/dist/utils/images/SWEB-flat.vmdk.tar.gz new file mode 100644 index 0000000..0beb9d5 Binary files /dev/null and b/pwn/flipper/dist/utils/images/SWEB-flat.vmdk.tar.gz differ diff --git a/pwn/flipper/dist/utils/images/menu.lst b/pwn/flipper/dist/utils/images/menu.lst new file mode 100644 index 0000000..066b8f1 --- /dev/null +++ b/pwn/flipper/dist/utils/images/menu.lst @@ -0,0 +1,39 @@ + +default 0 +timeout 0 + + +title = Sweb +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg + +title = Sweb - SVGA - 640x480x16 +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg +vbematch 640 480 16 + +title = Sweb - SVGA - 800x600x16 +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg +vbematch 800 600 16 + +title = Sweb - SVGA - 1024x768x16 +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg +vbematch 1024 768 16 + +title = Sweb - SVGA - 1280x1024x16 +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg +vbematch 1280 1024 16 + +title = Sweb - SVGA - 1600x1200x16 +root (hd0,0) +kernel = /boot/kernel.x +modulenounzip = /boot/kernel.dbg +vbematch 1600 1200 16 diff --git a/pwn/flipper/dist/utils/mount.sh b/pwn/flipper/dist/utils/mount.sh new file mode 100755 index 0000000..01bc4f8 --- /dev/null +++ b/pwn/flipper/dist/utils/mount.sh @@ -0,0 +1,13 @@ +# +# mount.sh +# mounts the SWEB-flat.vmdk image file to linux +# +mkdir /mnt/sweb +mkdir /mnt/sweb/part0 +mkdir /mnt/sweb/part1 +mkdir /mnt/sweb/part2 +mkdir /mnt/sweb/part3 +losetup /dev/loop4 ../sweb-bin/SWEB-flat.vmdk +losetup -o 10321920 /dev/loop5 /dev/loop4 +mount /dev/loop5 /mnt/sweb/part1 + diff --git a/pwn/flipper/dist/utils/netinit.sh b/pwn/flipper/dist/utils/netinit.sh new file mode 100755 index 0000000..412678e --- /dev/null +++ b/pwn/flipper/dist/utils/netinit.sh @@ -0,0 +1,133 @@ +#!/bin/sh +# +# Copyright IBM, Corp. 2010 +# +# Authors: +# Anthony Liguori +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. + + +# TODO's: +# Please make sure to install bridge-utils before using this script +# Please make also sure that you added 'allow br0' to your etc/qemu/bridge.conf + +# Set to the name of your bridge +BRIDGE=br0 + +# Network information +NETWORK=10.0.0.0 +NETMASK=255.255.255.0 +GATEWAY=10.0.0.1 + +# Optionally parameters to enable PXE support +TFTPROOT= +BOOTP= + +do_brctl() { + brctl "$@" +} + +do_ifconfig() { + ifconfig "$@" +} + +do_dd() { + dd "$@" +} + +do_iptables_restore() { + iptables-restore "$@" +} + +do_dnsmasq() { + dnsmasq "$@" +} + +check_bridge() { + if do_brctl show | grep "^$1" > /dev/null 2> /dev/null; then + return 1 + else + return 0 + fi +} + +create_bridge() { + do_brctl addbr "$1" + do_brctl stp "$1" off + do_brctl setfd "$1" 0 + do_ifconfig "$1" "$GATEWAY" netmask "$NETMASK" up +} + +enable_ip_forward() { + echo 1 | do_dd of=/proc/sys/net/ipv4/ip_forward > /dev/null +} + +add_filter_rules() { +do_iptables_restore < /dev/null 2> /dev/null & +fi +if [[ "$1" == "x86_32" ]] || [[ "$1" == "x86_32_pae" ]]; +then + qemu-system-i386 -m 8M -drive file=${HDD_IMAGE},index=0,media=disk -cpu qemu64 -debugcon file:/tmp/out.log -monitor pipe:/tmp/qemu -nographic -display none > /dev/null 2> /dev/null & +fi +if [[ "$1" == "arm_rpi2" ]]; +then + exit 0 # not supported in the travis qemu + qemu-system-arm -kernel kernel.x -cpu arm1176 -m 512 -M raspi2 -no-reboot -drive if=sd,file=${HDD_IMAGE} -serial file:/tmp/out.log -d guest_errors,unimp -monitor pipe:/tmp/qemu -nographic -display none > /dev/null 2> /dev/null & + sleep 2 +fi +if [[ "$1" == "arm_icp" ]]; +then + qemu-system-arm -M integratorcp -m 8M -kernel kernel.x -sd ${HDD_IMAGE} -no-reboot -serial file:/tmp/out.log -d guest_errors,unimp -monitor pipe:/tmp/qemu -nographic -display none > /dev/null 2> /dev/null & +fi +if [[ "$1" == "armv8_rpi3" ]]; +then + if [[ $(qemu-system-aarch64 -machine help | grep raspi3 | wc -l) != "0" ]]; then + qemu-system-aarch64 -M raspi3 -cpu cortex-a53 -m 1024 -drive file=SWEB-flat.vmdk,if=sd,format=raw -no-reboot -kernel kernel.x -serial file:/tmp/out.log -d guest_errors,unimp -monitor pipe:/tmp/qemu -nographic -display none > /dev/null 2> /dev/null & + sleep 10 + else + echo "QEMU version is too old to support the raspberry pi 3" + exit 0 + fi +fi + + +sleep 2 +echo "sendkey kp_enter" > /tmp/qemu.in +sleep 3 +echo "sendkey h" > /tmp/qemu.in +echo "sendkey e" > /tmp/qemu.in +echo "sendkey l" > /tmp/qemu.in +echo "sendkey p" > /tmp/qemu.in +echo "sendkey kp_enter" > /tmp/qemu.in +sleep 2 +echo "quit" > /tmp/qemu.in + +HAS_SHELL=$(grep -c "SWEB: />" /tmp/out.log) +HAS_HELP=$(grep -c "Command Help" /tmp/out.log) + +if [[ $HAS_SHELL > 0 ]] && [[ $HAS_HELP > 0 ]]; +then + echo "SWEB boots and has a (working) shell" + exit 0 +fi + +if [[ $HAS_SHELL > 0 ]] && [[ $HAS_HELP == 0 ]]; +then + echo "SWEB boots but has no working shell" + exit 0 +fi + +if [[ $HAS_SHELL == 0 ]]; +then + echo "SWEB does not boot to a shell" + exit 1 +fi diff --git a/pwn/flipper/dist/utils/umount.sh b/pwn/flipper/dist/utils/umount.sh new file mode 100755 index 0000000..e2cf183 --- /dev/null +++ b/pwn/flipper/dist/utils/umount.sh @@ -0,0 +1,8 @@ +# +# umount.sh +# unmounts the SWEB-flat.vmdk image file from linux +# +umount /mnt/sweb/part1 +losetup -d /dev/loop5 +losetup -d /dev/loop4 + diff --git a/pwn/fun-channel/README.md b/pwn/fun-channel/README.md new file mode 100644 index 0000000..1b261e2 --- /dev/null +++ b/pwn/fun-channel/README.md @@ -0,0 +1,6 @@ +"Good luck getting my secret password hehe. (Note: There are a lot of files in the current directory. The flag file has an arbitrary name, is the only file that ends with .txt and consists only of numbers 0-9 and letters. a-zA-Z)" + +author: Xer0 +``` +nc chall.glacierctf.com 13383 +``` \ No newline at end of file diff --git a/pwn/fun-channel/vuln b/pwn/fun-channel/vuln new file mode 100644 index 0000000..0f28436 Binary files /dev/null and b/pwn/fun-channel/vuln differ diff --git a/pwn/glacier-rating/README.md b/pwn/glacier-rating/README.md new file mode 100644 index 0000000..2689928 --- /dev/null +++ b/pwn/glacier-rating/README.md @@ -0,0 +1,6 @@ +I love C++. No malloc and free, so I can't mess up my heap management, right? + +author: n4nika +``` +nc chall.glacierctf.com 13373 +``` \ No newline at end of file diff --git a/pwn/glacier-rating/app b/pwn/glacier-rating/app new file mode 100755 index 0000000..747a1e6 Binary files /dev/null and b/pwn/glacier-rating/app differ diff --git a/pwn/glacier-rating/glacier_rating.tar.gz b/pwn/glacier-rating/glacier_rating.tar.gz new file mode 100644 index 0000000..fe84565 Binary files /dev/null and b/pwn/glacier-rating/glacier_rating.tar.gz differ diff --git a/pwn/glacier-rating/ld-linux-x86-64.so.2 b/pwn/glacier-rating/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..ccd8c34 Binary files /dev/null and b/pwn/glacier-rating/ld-linux-x86-64.so.2 differ diff --git a/pwn/glacier-rating/libc.so.6 b/pwn/glacier-rating/libc.so.6 new file mode 100755 index 0000000..4731458 Binary files /dev/null and b/pwn/glacier-rating/libc.so.6 differ diff --git a/pwn/glacier-rating/libm.so.6 b/pwn/glacier-rating/libm.so.6 new file mode 100755 index 0000000..2409d16 Binary files /dev/null and b/pwn/glacier-rating/libm.so.6 differ diff --git a/pwn/glacier-rating/libstdc++.so.6 b/pwn/glacier-rating/libstdc++.so.6 new file mode 100755 index 0000000..6978bfe Binary files /dev/null and b/pwn/glacier-rating/libstdc++.so.6 differ diff --git a/pwn/glacier-rating/main.cpp b/pwn/glacier-rating/main.cpp new file mode 100644 index 0000000..6637e1e --- /dev/null +++ b/pwn/glacier-rating/main.cpp @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include "user.hpp" + + +void buffering() +{ + setbuf(stdin, NULL); + setbuf(stdout, NULL); + setbuf(stderr, NULL); +} + + +void welcome() +{ + std::cout << "Welcome to 'Glacier rating'!\nYour trusted and secure site to rate mountains." << std::endl; +} + +User *authenticateUser() +{ + std::string username; + std::string password; + + std::cout << "Enter username: "; + std::getline(std::cin, username); + std::cout << "\nEnter password: "; + std::getline(std::cin, password); + + std::cout << std::endl; + + return new User(username, password, Perms::USER); +} + + +int getChoice() +{ + + while (true) + { + int choice = 0; + std::cout << "1. Create a rating" << std::endl; + std::cout << "2. Delete a rating" << std::endl; + std::cout << "3. Show a rating" << std::endl; + std::cout << "4. Scream into the mountains" << std::endl; + std::cout << "5. Do admin stuff" << std::endl; + std::cout << "6. Exit" << std::endl; + + std::cout << "> "; + scanf("%d", &choice); + getchar(); + if (choice < 1 | choice > 5) + { + std::cout << "Invalid choice" << std::endl << std::endl; + } + else + return choice; + } +} + +void writeRating(User *user) +{ + char *buffer = new char[24]; + + std::cout << "Give me your rating" << std::endl; + std::cout << "> "; + fgets(buffer, 24, stdin); + user->insertRating(buffer); + return; +} + +void deleteRating(User *user) +{ + size_t index = 0; + std::cout << "Which rating do you want to remove?" << std::endl; + std::cout << "> "; + scanf("%zd", &index); + getchar(); + user->removeRating(index); + return; +} + +void showRatings(User *user) +{ + user->showRatings(); + return; +} + +void scream(User *user) +{ + std::cout << "Now scream to your hearts content!" << std::endl; + std::string line; + std::vector lines; + while (line != "quit") + { + std::getline(std::cin, line); + lines.push_back(line); + } + return; +} + +void doAdminStuff(User *user) +{ + if (user->getUserLevel() != Perms::ADMIN) + { + std::cout << "You are not an admin!" << std::endl; + exit(1); + } + else if (user->getUserLevel() == Perms::ADMIN) + { + std::ifstream flag_stream("./flag.txt"); + std::string flag; + std::getline(flag_stream, flag); + flag_stream.close(); + std::cout << "Verified permissions" << std::endl; + std::cout << "Here is your flag: " << flag << std::endl; + exit(0); + } +} + + +int main() +{ + buffering(); + + int choice = 0; + welcome(); + + User *user = authenticateUser(); + + std::cout << "Greetings, " << user->getUsername() << std::endl; + std::cout << "What do you want to do?" << std::endl; + + + while (true) + { + choice = getChoice(); + + switch (choice) + { + case 1: + writeRating(user); + break; + case 2: + deleteRating(user); + break; + case 3: + showRatings(user); + break; + case 4: + scream(user); + break; + case 5: + doAdminStuff(user); + break; + default: + exit(0); + } + std::cout << std::endl; + } + return 0; +} diff --git a/pwn/glacier-rating/test.cpp b/pwn/glacier-rating/test.cpp new file mode 100644 index 0000000..ac7b68a --- /dev/null +++ b/pwn/glacier-rating/test.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + + +int main() +{ + std::string test_string; + std::vector vec; + std::getline(std::cin, test_string); + + vec.push_back(test_string); + + vec.erase(0); + + + + puts("aa\n"); + puts("aa\n"); + puts("aa\n"); + puts("aa\n"); + puts("aa\n"); + puts("aa\n"); + puts("aa\n"); + return 0; + +} \ No newline at end of file diff --git a/pwn/glacier-rating/user.cpp b/pwn/glacier-rating/user.cpp new file mode 100644 index 0000000..7635765 --- /dev/null +++ b/pwn/glacier-rating/user.cpp @@ -0,0 +1,60 @@ +#include "user.hpp" + +User::User(std::string username, std::string password, Perms user_level) : +username_(username), password_(password), user_level_(user_level) +{} + +std::string User::getUsername() +{ + return username_; +} + +Perms User::getUserLevel() +{ + return user_level_; +} + +void User::insertRating(char *rating) +{ + if (ratings_.size() >= 3) + { + std::cout << "Maximum amount of ratings reached!" << std::endl; + return; + } + else + { + ratings_.insert({ratings_.size() + 1, rating}); + std::cout << "Successfully added rating" << std::endl; + return; + } +} + +void User::removeRating(size_t index) +{ + if (ratings_.empty()) + { + std::cout << "No ratings to delete" << std::endl; + return; + } + else if (index >= ratings_.size() + 1 | index < 1) + { + std::cout << "Invalid Index" << std::endl; + return; + } + else + { + delete ratings_.at(index); + std::cout << "Removed rating " << index << std::endl; + return; + } +} + +void User::showRatings() +{ + std::cout << "Your ratings: " << std::endl; + for (auto rating : ratings_) + { + std::cout << rating.first << ": " << rating.second << std::endl; + } + return; +} \ No newline at end of file diff --git a/pwn/glacier-rating/user.hpp b/pwn/glacier-rating/user.hpp new file mode 100644 index 0000000..670270b --- /dev/null +++ b/pwn/glacier-rating/user.hpp @@ -0,0 +1,33 @@ +#ifndef USER_HPP +#define USER_HPP + +#include +#include +#include + +enum class Perms +{ + ADMIN = 0, + USER = 1000, +}; + +class User +{ + private: + std::string username_; + std::string password_; + std::map ratings_; + Perms user_level_; + + public: + User(std::string username, std::string password, Perms user_level); + ~User() = default; + User(const User ©) = delete; + std::string getUsername(); + Perms getUserLevel(); + void insertRating(char *rating); + void removeRating(size_t index); + void showRatings(); +}; + +#endif \ No newline at end of file diff --git a/pwn/secure-password-storage/README.md b/pwn/secure-password-storage/README.md new file mode 100644 index 0000000..0e7e71a --- /dev/null +++ b/pwn/secure-password-storage/README.md @@ -0,0 +1,6 @@ +I built a super secure application to hash and store your passwords, surely there are no flaws since i write insanely good code. Or so. + +author: n4nika +``` +nc chall.glacierctf.com 13390 +``` \ No newline at end of file diff --git a/pwn/secure-password-storage/challenge.tar.gz b/pwn/secure-password-storage/challenge.tar.gz new file mode 100644 index 0000000..cfb6b68 Binary files /dev/null and b/pwn/secure-password-storage/challenge.tar.gz differ diff --git a/pwn/secure-password-storage/ld-linux-x86-64.so.2 b/pwn/secure-password-storage/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..1cf2d3e Binary files /dev/null and b/pwn/secure-password-storage/ld-linux-x86-64.so.2 differ diff --git a/pwn/secure-password-storage/libc.so.6 b/pwn/secure-password-storage/libc.so.6 new file mode 100755 index 0000000..f022213 Binary files /dev/null and b/pwn/secure-password-storage/libc.so.6 differ diff --git a/pwn/secure-password-storage/libcrypto.so.3 b/pwn/secure-password-storage/libcrypto.so.3 new file mode 100755 index 0000000..650f530 Binary files /dev/null and b/pwn/secure-password-storage/libcrypto.so.3 differ diff --git a/pwn/secure-password-storage/vuln b/pwn/secure-password-storage/vuln new file mode 100755 index 0000000..46673b3 Binary files /dev/null and b/pwn/secure-password-storage/vuln differ diff --git a/pwn/write-byte-where/README.md b/pwn/write-byte-where/README.md new file mode 100644 index 0000000..e04c2c4 --- /dev/null +++ b/pwn/write-byte-where/README.md @@ -0,0 +1,5 @@ +One byte to rule them all + +``` +nc chall.glacierctf.com 13374 +``` \ No newline at end of file diff --git a/pwn/write-byte-where/ld-linux-x86-64.so.2 b/pwn/write-byte-where/ld-linux-x86-64.so.2 new file mode 100644 index 0000000..ccd8c34 Binary files /dev/null and b/pwn/write-byte-where/ld-linux-x86-64.so.2 differ diff --git a/pwn/write-byte-where/libc.so.6 b/pwn/write-byte-where/libc.so.6 new file mode 100644 index 0000000..4731458 Binary files /dev/null and b/pwn/write-byte-where/libc.so.6 differ diff --git a/pwn/write-byte-where/vuln b/pwn/write-byte-where/vuln new file mode 100644 index 0000000..813f2b7 Binary files /dev/null and b/pwn/write-byte-where/vuln differ